Version 0.5.12.0
svn merge -r 23167:23342 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
git-svn-id: http://dart.googlecode.com/svn/trunk@23346 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/dart.gyp b/dart.gyp
index c4b0ddc..0be9a49 100644
--- a/dart.gyp
+++ b/dart.gyp
@@ -38,9 +38,15 @@
'runtime/dart-runtime.gyp:dart_no_snapshot',
'runtime/dart-runtime.gyp:run_vm_tests',
'runtime/dart-runtime.gyp:process_test',
- 'runtime/dart-runtime.gyp:test_extension',
'packages',
],
+ 'conditions': [
+ ['OS!="android"', {
+ 'dependencies': [
+ 'runtime/dart-runtime.gyp:test_extension',
+ ],
+ }],
+ ],
},
{
# Build the SDK. This target is separate from upload_sdk as the
diff --git a/pkg/analyzer_experimental/example/resolver_driver.dart b/pkg/analyzer_experimental/example/resolver_driver.dart
index c3a9ef7..883816e 100644
--- a/pkg/analyzer_experimental/example/resolver_driver.dart
+++ b/pkg/analyzer_experimental/example/resolver_driver.dart
@@ -28,7 +28,7 @@
AnalysisContext context = AnalysisEngine.instance.createAnalysisContext();
context.sourceFactory = new SourceFactory.con2([new DartUriResolver(sdk), new FileUriResolver()]);
- Source source = new FileBasedSource.con1(context.sourceFactory, new JavaFile(args[1]));
+ Source source = new FileBasedSource.con1(context.sourceFactory.contentCache, new JavaFile(args[1]));
//
ChangeSet changeSet = new ChangeSet();
changeSet.added(source);
diff --git a/pkg/analyzer_experimental/lib/options.dart b/pkg/analyzer_experimental/lib/options.dart
index d26060b..c6fd30d 100644
--- a/pkg/analyzer_experimental/lib/options.dart
+++ b/pkg/analyzer_experimental/lib/options.dart
@@ -37,6 +37,9 @@
/** The path to the dart SDK */
final String dartSdkPath;
+ /** The path to the package root */
+ final String packageRootPath;
+
/** The source files to analyze */
final List<String> sourceFiles;
@@ -45,12 +48,13 @@
*/
CommandLineOptions._fromArgs(ArgResults args)
: shouldBatch = args['batch'],
- machineFormat = args['machine_format'],
- ignoreUnrecognizedFlags = args['ignore_unrecognized_flags'],
- showPackageWarnings = args['show_package_warnings'],
- showSdkWarnings = args['show_sdk_warnings'],
- warningsAreFatal = args['fatal_warnings'],
- dartSdkPath = args['dart_sdk'],
+ machineFormat = args['machine-format'],
+ ignoreUnrecognizedFlags = args['ignore-unrecognized-flags'],
+ showPackageWarnings = args['show-package-warnings'],
+ showSdkWarnings = args['show-sdk-warnings'],
+ warningsAreFatal = args['fatal-warnings'],
+ dartSdkPath = args['dart-sdk'],
+ packageRootPath = args['package-root'],
sourceFiles = args.rest;
/**
@@ -81,18 +85,19 @@
var parser = new _CommandLineParser()
..addFlag('batch', abbr: 'b', help: 'Run in batch mode',
defaultsTo: false, negatable: false)
- ..addOption('dart_sdk', help: 'Specify path to the Dart sdk')
- ..addFlag('machine_format', help: 'Specify whether errors '
+ ..addOption('dart-sdk', help: 'The path to the Dart SDK')
+ ..addOption('package-root', help: 'The path to the package root')
+ ..addFlag('machine-format', help: 'Specify whether errors '
'should be in machine format',
defaultsTo: false, negatable: false)
- ..addFlag('ignore_unrecognized_flags',
+ ..addFlag('ignore-unrecognized-flags',
help: 'Ignore unrecognized command line flags',
defaultsTo: false, negatable: false)
- ..addFlag('fatal_warnings', help: 'Treat non-type warnings as fatal',
+ ..addFlag('fatal-warnings', help: 'Treat non-type warnings as fatal',
defaultsTo: false, negatable: false)
- ..addFlag('show_package_warnings', help: 'Show warnings from package: imports',
+ ..addFlag('show-package-warnings', help: 'Show warnings from package: imports',
defaultsTo: false, negatable: false)
- ..addFlag('show_sdk_warnings', help: 'Show warnings from SDK imports',
+ ..addFlag('show-sdk-warnings', help: 'Show warnings from SDK imports',
defaultsTo: false, negatable: false)
..addFlag('help', abbr: 'h', help: 'Display this help message',
defaultsTo: false, negatable: false);
diff --git a/pkg/analyzer_experimental/lib/src/analyzer_impl.dart b/pkg/analyzer_experimental/lib/src/analyzer_impl.dart
index 40b8deb..84cfb8d 100644
--- a/pkg/analyzer_experimental/lib/src/analyzer_impl.dart
+++ b/pkg/analyzer_experimental/lib/src/analyzer_impl.dart
@@ -71,7 +71,12 @@
List<UriResolver> resolvers = [new DartUriResolver(sdk), new FileUriResolver()];
// may be add package resolver
{
- var packageDirectory = getPackageDirectoryFor(sourceFile);
+ JavaFile packageDirectory;
+ if (options.packageRootPath != null) {
+ packageDirectory = new JavaFile(options.packageRootPath);
+ } else {
+ packageDirectory = getPackageDirectoryFor(sourceFile);
+ }
if (packageDirectory != null) {
resolvers.add(new PackageUriResolver([packageDirectory]));
}
@@ -138,11 +143,18 @@
}
static JavaFile getPackageDirectoryFor(JavaFile sourceFile) {
- JavaFile sourceFolder = sourceFile.getParentFile();
- JavaFile packagesFolder = new JavaFile.relative(sourceFolder, "packages");
- if (packagesFolder.exists()) {
- return packagesFolder;
+ // we are going to ask parent file, so get absolute path
+ sourceFile = sourceFile.getAbsoluteFile();
+ // look in the containing directories
+ JavaFile dir = sourceFile.getParentFile();
+ while (dir != null) {
+ JavaFile packagesDir = new JavaFile.relative(dir, "packages");
+ if (packagesDir.exists()) {
+ return packagesDir;
+ }
+ dir = dir.getParentFile();
}
+ // not found
return null;
}
}
diff --git a/pkg/analyzer_experimental/lib/src/error.dart b/pkg/analyzer_experimental/lib/src/error.dart
index 5485a0f..d3df0e1 100644
--- a/pkg/analyzer_experimental/lib/src/error.dart
+++ b/pkg/analyzer_experimental/lib/src/error.dart
@@ -98,8 +98,8 @@
String get result => _buffer.toString();
- void accept1(CharBuffer contents, _) =>
- _buffer.write(contents.subSequence(0, contents.length));
+ void accept(CharBuffer contents, _) =>
+ _buffer.write(contents.subSequence(0, contents.length()));
void accept2(String contents, _) => _buffer.write(contents);
}
diff --git a/pkg/analyzer_experimental/lib/src/generated/engine.dart b/pkg/analyzer_experimental/lib/src/generated/engine.dart
index fca4fef..e9390f7 100644
--- a/pkg/analyzer_experimental/lib/src/generated/engine.dart
+++ b/pkg/analyzer_experimental/lib/src/generated/engine.dart
@@ -4,7 +4,6 @@
library engine;
import 'dart:collection' show HasNextIterator;
-import 'dart:uri' show Uri;
import 'java_core.dart';
import 'java_engine.dart';
import 'instrumentation.dart';
@@ -2828,7 +2827,7 @@
for (XmlAttributeNode attribute in node.attributes) {
if (javaStringEqualsIgnoreCase(attribute.name.lexeme, AnalysisContextImpl._ATTRIBUTE_SRC)) {
try {
- Uri uri = new Uri.fromComponents(path: attribute.text);
+ Uri uri = new Uri(path: attribute.text);
String fileName = uri.path;
if (AnalysisEngine.isDartFileName(fileName)) {
Source librarySource = AnalysisContextImpl_this._sourceFactory.resolveUri(htmlSource, fileName);
diff --git a/pkg/analyzer_experimental/lib/src/generated/error.dart b/pkg/analyzer_experimental/lib/src/generated/error.dart
index 1f684c9..152ea76 100644
--- a/pkg/analyzer_experimental/lib/src/generated/error.dart
+++ b/pkg/analyzer_experimental/lib/src/generated/error.dart
@@ -1395,7 +1395,7 @@
/**
* An error listener that ignores errors that are reported to it.
*/
- AnalysisErrorListener _NULL_LISTENER = new AnalysisErrorListener_4();
+ static AnalysisErrorListener _NULL_LISTENER = new AnalysisErrorListener_4();
/**
* This method is invoked when an error has been found by the analysis engine.
* @param error the error that was just found (not {@code null})
diff --git a/pkg/analyzer_experimental/lib/src/generated/java_core.dart b/pkg/analyzer_experimental/lib/src/generated/java_core.dart
index 3bf99ccc..445d6d7 100644
--- a/pkg/analyzer_experimental/lib/src/generated/java_core.dart
+++ b/pkg/analyzer_experimental/lib/src/generated/java_core.dart
@@ -1,7 +1,6 @@
library java.core;
import "dart:math" as math;
-import "dart:uri";
import "dart:collection" show ListBase;
class JavaSystem {
@@ -319,7 +318,7 @@
}
void setAll(int index, Iterable<E> iterable) {
- elements.setAll(iterable);
+ elements.setAll(index, iterable);
}
void sort([int compare(E a, E b)]) {
@@ -462,11 +461,13 @@
class JavaStringBuilder {
StringBuffer sb = new StringBuffer();
String toString() => sb.toString();
- void append(x) {
+ JavaStringBuilder append(x) {
sb.write(x);
+ return this;
}
- void appendChar(int c) {
+ JavaStringBuilder appendChar(int c) {
sb.writeCharCode(c);
+ return this;
}
int get length => sb.length;
void set length(int newLength) {
diff --git a/pkg/analyzer_experimental/lib/src/generated/java_io.dart b/pkg/analyzer_experimental/lib/src/generated/java_io.dart
index b5ac6d9..f818d57 100644
--- a/pkg/analyzer_experimental/lib/src/generated/java_io.dart
+++ b/pkg/analyzer_experimental/lib/src/generated/java_io.dart
@@ -1,7 +1,6 @@
library java.io;
import "dart:io";
-import "dart:uri";
class JavaSystemIO {
static Map<String, String> _properties = new Map();
@@ -84,7 +83,7 @@
bool isDirectory() {
return _newDirectory().existsSync();
}
- Uri toURI() => new Uri.fromComponents(path: _path.toString());
+ Uri toURI() => new Uri(path: _path.toString());
String readAsStringSync() => _newFile().readAsStringSync();
int lastModified() => _newFile().lastModifiedSync().millisecondsSinceEpoch;
File _newFile() => new File.fromPath(_path);
diff --git a/pkg/analyzer_experimental/lib/src/generated/resolver.dart b/pkg/analyzer_experimental/lib/src/generated/resolver.dart
index fc7b84d..42147fa 100644
--- a/pkg/analyzer_experimental/lib/src/generated/resolver.dart
+++ b/pkg/analyzer_experimental/lib/src/generated/resolver.dart
@@ -4,7 +4,6 @@
library engine.resolver;
import 'dart:collection';
-import 'dart:uri' show Uri;
import 'java_core.dart';
import 'java_engine.dart';
import 'instrumentation.dart';
@@ -880,7 +879,7 @@
ExternalHtmlScriptElementImpl script = new ExternalHtmlScriptElementImpl(node);
if (scriptSourcePath != null) {
try {
- new Uri(scriptSourcePath);
+ Uri.parse(scriptSourcePath);
Source scriptSource = _context.sourceFactory.resolveUri(htmlSource, scriptSourcePath);
script.scriptSource = scriptSource;
if (!scriptSource.exists()) {
@@ -1994,7 +1993,7 @@
} else if (identifier.inGetterContext()) {
_resolver.reportError(StaticWarningCode.UNDEFINED_GETTER, identifier, [identifier.name, targetType.name]);
} else {
- System.out.println("two ${identifier.name}");
+ print("two ${identifier.name}");
_resolver.reportError(StaticWarningCode.UNDEFINED_IDENTIFIER, identifier, [identifier.name]);
}
}
@@ -8417,4 +8416,4 @@
bool needsRecompilation() => true;
int compareTo(ResolverErrorCode other) => __ordinal - other.__ordinal;
String toString() => __name;
-}
\ No newline at end of file
+}
diff --git a/pkg/analyzer_experimental/lib/src/generated/sdk.dart b/pkg/analyzer_experimental/lib/src/generated/sdk.dart
index 64bc958..9825059 100644
--- a/pkg/analyzer_experimental/lib/src/generated/sdk.dart
+++ b/pkg/analyzer_experimental/lib/src/generated/sdk.dart
@@ -3,7 +3,6 @@
library engine.sdk;
-import 'dart:uri';
import 'java_core.dart';
import 'java_engine.dart';
import 'source.dart' show ContentCache, Source, UriKind;
diff --git a/pkg/analyzer_experimental/lib/src/generated/sdk_io.dart b/pkg/analyzer_experimental/lib/src/generated/sdk_io.dart
index cb9c473..47abce7 100644
--- a/pkg/analyzer_experimental/lib/src/generated/sdk_io.dart
+++ b/pkg/analyzer_experimental/lib/src/generated/sdk_io.dart
@@ -4,7 +4,6 @@
library engine.sdk.io;
import 'dart:io';
-import 'dart:uri';
import 'java_core.dart';
import 'java_io.dart';
import 'java_engine.dart';
diff --git a/pkg/analyzer_experimental/lib/src/generated/source.dart b/pkg/analyzer_experimental/lib/src/generated/source.dart
index 83c24d0..1be6594 100644
--- a/pkg/analyzer_experimental/lib/src/generated/source.dart
+++ b/pkg/analyzer_experimental/lib/src/generated/source.dart
@@ -3,7 +3,6 @@
library engine.source;
-import 'dart:uri';
import 'java_core.dart';
import 'sdk.dart' show DartSdk;
import 'engine.dart' show AnalysisContext;
@@ -55,7 +54,7 @@
*/
Source forUri(String absoluteUri) {
try {
- Uri uri = new Uri(absoluteUri);
+ Uri uri = Uri.parse(absoluteUri);
if (uri.isAbsolute) {
return resolveUri2(null, uri);
}
@@ -79,7 +78,7 @@
throw new IllegalArgumentException("Invalid source kind in encoding: ${kind}");
}
try {
- Uri uri = new Uri(encoding.substring(1));
+ Uri uri = Uri.parse(encoding.substring(1));
for (UriResolver resolver in _resolvers) {
Source result = resolver.fromEncoding(_contentCache, kind, uri);
if (result != null) {
@@ -126,7 +125,7 @@
*/
Source resolveUri(Source containingSource, String containedUri) {
try {
- return resolveUri2(containingSource, new Uri(containedUri));
+ return resolveUri2(containingSource, Uri.parse(containedUri));
} on URISyntaxException catch (exception) {
return null;
}
@@ -729,4 +728,4 @@
_stampMap[source] = JavaSystem.currentTimeMillis();
}
}
-}
\ No newline at end of file
+}
diff --git a/pkg/analyzer_experimental/lib/src/generated/source_io.dart b/pkg/analyzer_experimental/lib/src/generated/source_io.dart
index f016564..5d5a49f 100644
--- a/pkg/analyzer_experimental/lib/src/generated/source_io.dart
+++ b/pkg/analyzer_experimental/lib/src/generated/source_io.dart
@@ -5,7 +5,6 @@
import 'source.dart';
import 'dart:io';
-import 'dart:uri';
import 'java_core.dart';
import 'java_io.dart';
import 'sdk.dart' show DartSdk;
@@ -195,7 +194,7 @@
} on IOException catch (e) {
AnalysisEngine.instance.logger.logError2("Canonical failed: ${pkgDir}", e);
}
- return new JavaFile.relative(pkgDir, relPath.replaceAll(0x2F, JavaFile.separatorChar));
+ return new JavaFile.relative(pkgDir, relPath.replaceAll('/', JavaFile.separatorChar));
}
}
/**
diff --git a/pkg/analyzer_experimental/lib/src/utils.dart b/pkg/analyzer_experimental/lib/src/utils.dart
index 4ff702f..2b5053e 100644
--- a/pkg/analyzer_experimental/lib/src/utils.dart
+++ b/pkg/analyzer_experimental/lib/src/utils.dart
@@ -4,7 +4,6 @@
library utils;
import 'dart:io';
-import 'dart:uri';
import 'package:pathos/path.dart' as pathos;
diff --git a/pkg/analyzer_experimental/test/generated/resolver_test.dart b/pkg/analyzer_experimental/test/generated/resolver_test.dart
index 829f7ff..fd28a66 100644
--- a/pkg/analyzer_experimental/test/generated/resolver_test.dart
+++ b/pkg/analyzer_experimental/test/generated/resolver_test.dart
@@ -2230,7 +2230,7 @@
verify([source]);
}
void fail_prefixCollidesWithTopLevelMembers() {
- Source source = addSource(EngineTestCase.createSource(["import 'dart:uri' as uri;", "var uri = null;"]));
+ Source source = addSource(EngineTestCase.createSource(["import 'dart:uft' as utf;", "var utf = null;"]));
resolve(source, []);
assertErrors([CompileTimeErrorCode.PREFIX_COLLIDES_WITH_TOP_LEVEL_MEMBER]);
verify([source]);
@@ -6765,4 +6765,4 @@
// StaticTypeWarningCodeTest.dartSuite();
// StaticWarningCodeTest.dartSuite();
// TypePropagationTest.dartSuite();
-}
\ No newline at end of file
+}
diff --git a/pkg/analyzer_experimental/test/generated/test_support.dart b/pkg/analyzer_experimental/test/generated/test_support.dart
index c666db1..df7f862 100644
--- a/pkg/analyzer_experimental/test/generated/test_support.dart
+++ b/pkg/analyzer_experimental/test/generated/test_support.dart
@@ -4,7 +4,6 @@
library engine.test_support;
import 'dart:collection';
-import 'dart:uri';
import 'package:analyzer_experimental/src/generated/java_core.dart';
import 'package:analyzer_experimental/src/generated/java_engine.dart';
import 'package:analyzer_experimental/src/generated/java_junit.dart';
@@ -669,6 +668,9 @@
Source resolveRelative(Uri uri) {
throw new UnsupportedOperationException();
}
+ UriKind get uriKind {
+ throw new UnsupportedOperationException();
+ }
}
/**
diff --git a/pkg/args/example/test_runner.dart b/pkg/args/example/test_runner.dart
index d0a6ed8..74750ae 100644
--- a/pkg/args/example/test_runner.dart
+++ b/pkg/args/example/test_runner.dart
@@ -40,8 +40,9 @@
allowedHelp: {
'vm': 'Run Dart code on the standalone dart vm.',
'd8': 'Run JavaScript from the command line using v8.',
+ // TODO(antonm): rename flag.
'drt': 'Run Dart or JavaScript in the headless version of Chrome,\n'
- 'DumpRenderTree.',
+ 'content shell.',
'dartium': 'Run Dart or JavaScript in Dartium.',
'ff': 'Run JavaScript in Firefox',
'chrome': 'Run JavaScript in Chrome',
@@ -116,7 +117,8 @@
defaultsTo: false);
parser.addOption('dart', help: 'Path to dart executable');
- parser.addOption('drt', help: 'Path to DumpRenderTree executable');
+ // TODO(antonm): rename the option.
+ parser.addOption('drt', help: 'Path to content shell executable');
parser.addOption('dartium', help: 'Path to Dartium Chrome executable');
parser.addFlag('batch', abbr: 'b',
diff --git a/sdk/lib/crypto/crypto.dart b/pkg/crypto/lib/crypto.dart
similarity index 96%
rename from sdk/lib/crypto/crypto.dart
rename to pkg/crypto/lib/crypto.dart
index a34ce53..1b764ae 100644
--- a/sdk/lib/crypto/crypto.dart
+++ b/pkg/crypto/lib/crypto.dart
@@ -6,12 +6,12 @@
import 'dart:math';
-part 'crypto_utils.dart';
-part 'hash_utils.dart';
-part 'hmac.dart';
-part 'md5.dart';
-part 'sha1.dart';
-part 'sha256.dart';
+part 'src/crypto_utils.dart';
+part 'src/hash_utils.dart';
+part 'src/hmac.dart';
+part 'src/md5.dart';
+part 'src/sha1.dart';
+part 'src/sha256.dart';
/**
* Interface for cryptographic hash functions.
diff --git a/sdk/lib/crypto/crypto_utils.dart b/pkg/crypto/lib/src/crypto_utils.dart
similarity index 100%
rename from sdk/lib/crypto/crypto_utils.dart
rename to pkg/crypto/lib/src/crypto_utils.dart
diff --git a/sdk/lib/crypto/hash_utils.dart b/pkg/crypto/lib/src/hash_utils.dart
similarity index 100%
rename from sdk/lib/crypto/hash_utils.dart
rename to pkg/crypto/lib/src/hash_utils.dart
diff --git a/sdk/lib/crypto/hmac.dart b/pkg/crypto/lib/src/hmac.dart
similarity index 100%
rename from sdk/lib/crypto/hmac.dart
rename to pkg/crypto/lib/src/hmac.dart
diff --git a/sdk/lib/crypto/md5.dart b/pkg/crypto/lib/src/md5.dart
similarity index 100%
rename from sdk/lib/crypto/md5.dart
rename to pkg/crypto/lib/src/md5.dart
diff --git a/sdk/lib/crypto/sha1.dart b/pkg/crypto/lib/src/sha1.dart
similarity index 100%
rename from sdk/lib/crypto/sha1.dart
rename to pkg/crypto/lib/src/sha1.dart
diff --git a/sdk/lib/crypto/sha256.dart b/pkg/crypto/lib/src/sha256.dart
similarity index 100%
rename from sdk/lib/crypto/sha256.dart
rename to pkg/crypto/lib/src/sha256.dart
diff --git a/pkg/crypto/pubspec.yaml b/pkg/crypto/pubspec.yaml
new file mode 100644
index 0000000..cc3c47d
--- /dev/null
+++ b/pkg/crypto/pubspec.yaml
@@ -0,0 +1,5 @@
+name: crypto
+author: "Dart Team <misc@dartlang.org>"
+homepage: http://www.dartlang.org
+description: >
+ Library of cryptographic functions.
diff --git a/pkg/http/lib/http.dart b/pkg/http/lib/http.dart
index dda24f24..752a53b 100644
--- a/pkg/http/lib/http.dart
+++ b/pkg/http/lib/http.dart
@@ -69,7 +69,6 @@
import 'dart:async';
import 'dart:typed_data';
-import 'dart:uri';
import 'src/client.dart';
import 'src/response.dart';
diff --git a/pkg/http/lib/src/base_client.dart b/pkg/http/lib/src/base_client.dart
index df6e730..2526a62 100644
--- a/pkg/http/lib/src/base_client.dart
+++ b/pkg/http/lib/src/base_client.dart
@@ -7,7 +7,6 @@
import 'dart:async';
import 'dart:io';
import 'dart:typed_data';
-import 'dart:uri';
import 'base_request.dart';
import 'client.dart';
diff --git a/pkg/http/lib/src/base_request.dart b/pkg/http/lib/src/base_request.dart
index ffff471..415e27a 100644
--- a/pkg/http/lib/src/base_request.dart
+++ b/pkg/http/lib/src/base_request.dart
@@ -7,7 +7,6 @@
import 'dart:async';
import 'dart:io';
import 'dart:isolate';
-import 'dart:uri';
import 'byte_stream.dart';
import 'client.dart';
diff --git a/pkg/http/lib/src/multipart_request.dart b/pkg/http/lib/src/multipart_request.dart
index ab66bbd..6d8f03b 100644
--- a/pkg/http/lib/src/multipart_request.dart
+++ b/pkg/http/lib/src/multipart_request.dart
@@ -7,7 +7,6 @@
import 'dart:async';
import 'dart:io';
import 'dart:math';
-import 'dart:uri';
import 'dart:utf';
import 'base_request.dart';
@@ -138,7 +137,8 @@
// http://tools.ietf.org/html/rfc2388 mandates some complex encodings for
// field names and file names, but in practice user agents seem to just
// URL-encode them so we do the same.
- var header = 'content-disposition: form-data; name="${encodeUri(name)}"';
+ var header =
+ 'content-disposition: form-data; name="${Uri.encodeFull(name)}"';
if (!isPlainAscii(value)) {
header = '$header\r\ncontent-type: text/plain; charset=utf-8';
}
@@ -149,10 +149,10 @@
/// contain only ASCII characters.
String _headerForFile(MultipartFile file) {
var header = 'content-type: ${file.contentType}\r\n'
- 'content-disposition: form-data; name="${encodeUri(file.field)}"';
+ 'content-disposition: form-data; name="${Uri.encodeFull(file.field)}"';
if (file.filename != null) {
- header = '$header; filename="${encodeUri(file.filename)}"';
+ header = '$header; filename="${Uri.encodeFull(file.filename)}"';
}
return '$header\r\n\r\n';
}
diff --git a/pkg/http/lib/src/request.dart b/pkg/http/lib/src/request.dart
index 2520b2a..982d2fb 100644
--- a/pkg/http/lib/src/request.dart
+++ b/pkg/http/lib/src/request.dart
@@ -7,7 +7,6 @@
import 'dart:async';
import 'dart:io';
import 'dart:typed_data';
-import 'dart:uri';
import 'base_request.dart';
import 'byte_stream.dart';
diff --git a/pkg/http/lib/src/streamed_request.dart b/pkg/http/lib/src/streamed_request.dart
index eb20758..1b72eab 100644
--- a/pkg/http/lib/src/streamed_request.dart
+++ b/pkg/http/lib/src/streamed_request.dart
@@ -6,7 +6,6 @@
import 'dart:async';
import 'dart:io';
-import 'dart:uri';
import 'byte_stream.dart';
import 'base_request.dart';
diff --git a/pkg/http/lib/src/utils.dart b/pkg/http/lib/src/utils.dart
index ba5c968..4a3b84c 100644
--- a/pkg/http/lib/src/utils.dart
+++ b/pkg/http/lib/src/utils.dart
@@ -5,12 +5,12 @@
library utils;
import 'dart:async';
-import 'dart:crypto';
import 'dart:io';
import 'dart:typed_data';
-import 'dart:uri';
import 'dart:utf';
+import "package:crypto/crypto.dart";
+
import 'byte_stream.dart';
/// Converts a URL query string (or `application/x-www-form-urlencoded` body)
@@ -37,7 +37,8 @@
String mapToQuery(Map<String, String> map) {
var pairs = <List<String>>[];
map.forEach((key, value) =>
- pairs.add([encodeUriComponent(key), encodeUriComponent(value)]));
+ pairs.add([Uri.encodeQueryComponent(key),
+ Uri.encodeQueryComponent(value)]));
return pairs.map((pair) => "${pair[0]}=${pair[1]}").join("&");
}
@@ -50,10 +51,10 @@
void mapAddAll(Map destination, Map source) =>
source.forEach((key, value) => destination[key] = value);
-/// Decodes a URL-encoded string. Unlike [decodeUriComponent], this includes
+/// Decodes a URL-encoded string. Unlike [Uri.decodeComponent], this includes
/// replacing `+` with ` `.
String urlDecode(String encoded) =>
- decodeUriComponent(encoded.replaceAll("+", " "));
+ Uri.decodeComponent(encoded.replaceAll("+", " "));
/// Like [String.split], but only splits on the first occurrence of the pattern.
/// This will always return an array of two elements or fewer.
diff --git a/pkg/http/test/client_test.dart b/pkg/http/test/client_test.dart
index e898426..aa7781f 100644
--- a/pkg/http/test/client_test.dart
+++ b/pkg/http/test/client_test.dart
@@ -5,7 +5,6 @@
library client_test;
import 'dart:io';
-import 'dart:uri';
import 'package:http/http.dart' as http;
import 'package:http/src/utils.dart';
diff --git a/pkg/http/test/mock_client_test.dart b/pkg/http/test/mock_client_test.dart
index a77d965..8e46ccc 100644
--- a/pkg/http/test/mock_client_test.dart
+++ b/pkg/http/test/mock_client_test.dart
@@ -7,7 +7,6 @@
import 'dart:async';
import 'dart:io';
import 'dart:json' as json;
-import 'dart:uri';
import 'package:http/http.dart' as http;
import 'package:http/src/utils.dart';
diff --git a/pkg/http/test/safe_http_server.dart b/pkg/http/test/safe_http_server.dart
index 25d57ee..c9885f1 100644
--- a/pkg/http/test/safe_http_server.dart
+++ b/pkg/http/test/safe_http_server.dart
@@ -6,7 +6,6 @@
import 'dart:async';
import 'dart:io';
-import 'dart:uri';
// TODO(nweiz): remove this when issue 9140 is fixed.
/// A wrapper around [HttpServer] that swallows errors caused by requests
diff --git a/pkg/http/test/utils.dart b/pkg/http/test/utils.dart
index 25bb92e..786bb84 100644
--- a/pkg/http/test/utils.dart
+++ b/pkg/http/test/utils.dart
@@ -7,7 +7,6 @@
import 'dart:async';
import 'dart:io';
import 'dart:json' as json;
-import 'dart:uri';
import 'package:http/http.dart' as http;
import 'package:http/src/byte_stream.dart';
diff --git a/pkg/intl/lib/src/lazy_locale_data.dart b/pkg/intl/lib/src/lazy_locale_data.dart
index a7ec331..90ff3a1 100644
--- a/pkg/intl/lib/src/lazy_locale_data.dart
+++ b/pkg/intl/lib/src/lazy_locale_data.dart
@@ -10,7 +10,6 @@
library lazy_locale_data;
import 'dart:async';
-import 'dart:uri';
import 'intl_helpers.dart';
import 'dart:json' as json;
diff --git a/pkg/mdv_observe/lib/src/observable_list.dart b/pkg/mdv_observe/lib/src/observable_list.dart
index c3ae880..66ca771 100644
--- a/pkg/mdv_observe/lib/src/observable_list.dart
+++ b/pkg/mdv_observe/lib/src/observable_list.dart
@@ -70,7 +70,8 @@
void operator []=(int index, E value) {
var oldValue = _list[index];
if (hasObservers) {
- _recordChange(new ListChangeRecord(index, addedCount: 1, removedCount: 1));
+ _recordChange(new ListChangeRecord(index, addedCount: 1,
+ removedCount: 1));
}
_list[index] = value;
}
diff --git a/pkg/mdv_observe/lib/src/observable_map.dart b/pkg/mdv_observe/lib/src/observable_map.dart
index 009d692..ce1e48f 100644
--- a/pkg/mdv_observe/lib/src/observable_map.dart
+++ b/pkg/mdv_observe/lib/src/observable_map.dart
@@ -92,6 +92,8 @@
bool get isEmpty => length == 0;
+ bool get isNotEmpty => !isEmpty;
+
bool containsValue(V value) => _map.containsValue(value);
bool containsKey(K key) => _map.containsKey(key);
diff --git a/pkg/oauth2/lib/oauth2.dart b/pkg/oauth2/lib/oauth2.dart
index 592589d..96bffcf 100644
--- a/pkg/oauth2/lib/oauth2.dart
+++ b/pkg/oauth2/lib/oauth2.dart
@@ -34,7 +34,6 @@
/// that the library is being used by a server-side application.
///
/// import 'dart:io'
-/// import 'dart:uri'
/// import 'package:oauth2/oauth2.dart' as oauth2;
///
/// // These URLs are endpoints that are provided by the authorization
diff --git a/pkg/oauth2/lib/src/authorization_code_grant.dart b/pkg/oauth2/lib/src/authorization_code_grant.dart
index 900dfc5..266812e 100644
--- a/pkg/oauth2/lib/src/authorization_code_grant.dart
+++ b/pkg/oauth2/lib/src/authorization_code_grant.dart
@@ -5,7 +5,6 @@
library authorization_code_grant;
import 'dart:async';
-import 'dart:uri';
import 'package:http/http.dart' as http;
diff --git a/pkg/oauth2/lib/src/authorization_exception.dart b/pkg/oauth2/lib/src/authorization_exception.dart
index 1062aa9..d48c3b1 100644
--- a/pkg/oauth2/lib/src/authorization_exception.dart
+++ b/pkg/oauth2/lib/src/authorization_exception.dart
@@ -5,7 +5,6 @@
library authorization_exception;
import 'dart:io';
-import 'dart:uri';
/// An exception raised when OAuth2 authorization fails.
class AuthorizationException implements Exception {
diff --git a/pkg/oauth2/lib/src/client.dart b/pkg/oauth2/lib/src/client.dart
index 62e2288..d473be19 100644
--- a/pkg/oauth2/lib/src/client.dart
+++ b/pkg/oauth2/lib/src/client.dart
@@ -5,7 +5,6 @@
library oauth2_client;
import 'dart:async';
-import 'dart:uri';
import 'package:http/http.dart' as http;
diff --git a/pkg/oauth2/lib/src/credentials.dart b/pkg/oauth2/lib/src/credentials.dart
index 420dc49..b02f470 100644
--- a/pkg/oauth2/lib/src/credentials.dart
+++ b/pkg/oauth2/lib/src/credentials.dart
@@ -6,7 +6,6 @@
import 'dart:async';
import 'dart:json' as JSON;
-import 'dart:uri';
import 'package:http/http.dart' as http;
diff --git a/pkg/oauth2/lib/src/handle_access_token_response.dart b/pkg/oauth2/lib/src/handle_access_token_response.dart
index c82c818..5e5f6e2 100644
--- a/pkg/oauth2/lib/src/handle_access_token_response.dart
+++ b/pkg/oauth2/lib/src/handle_access_token_response.dart
@@ -6,7 +6,6 @@
import 'dart:io';
import 'dart:json' as JSON;
-import 'dart:uri';
import 'package:http/http.dart' as http;
diff --git a/pkg/oauth2/lib/src/utils.dart b/pkg/oauth2/lib/src/utils.dart
index f69ac8b..d0e5f11 100644
--- a/pkg/oauth2/lib/src/utils.dart
+++ b/pkg/oauth2/lib/src/utils.dart
@@ -5,9 +5,9 @@
library utils;
import 'dart:async';
-import 'dart:uri';
import 'dart:isolate';
-import 'dart:crypto';
+
+import "package:crypto/crypto.dart";
/// Adds additional query parameters to [url], overwriting the original
/// parameters if a name conflict occurs.
@@ -35,8 +35,10 @@
String mapToQuery(Map<String, String> map) {
var pairs = <List<String>>[];
map.forEach((key, value) {
- key = encodeUriComponent(key);
- value = (value == null || value.isEmpty) ? null : encodeUriComponent(value);
+ key = Uri.encodeQueryComponent(key);
+ value = (value == null || value.isEmpty)
+ ? null
+ : Uri.encodeQueryComponent(value);
pairs.add([key, value]);
});
return pairs.map((pair) {
@@ -50,10 +52,10 @@
void mapAddAll(Map destination, Map source) =>
source.forEach((key, value) => destination[key] = value);
-/// Decode a URL-encoded string. Unlike [decodeUriComponent], this includes
+/// Decode a URL-encoded string. Unlike [Uri.decodeComponent], this includes
/// replacing `+` with ` `.
String urlDecode(String encoded) =>
- decodeUriComponent(encoded.replaceAll("+", " "));
+ Uri.decodeComponent(encoded.replaceAll("+", " "));
/// Like [String.split], but only splits on the first occurrence of the pattern.
/// This will always return a list of two elements or fewer.
diff --git a/pkg/oauth2/test/authorization_code_grant_test.dart b/pkg/oauth2/test/authorization_code_grant_test.dart
index 22be3cfa7..0d4a5fc 100644
--- a/pkg/oauth2/test/authorization_code_grant_test.dart
+++ b/pkg/oauth2/test/authorization_code_grant_test.dart
@@ -7,7 +7,6 @@
import 'dart:async';
import 'dart:io';
import 'dart:json' as JSON;
-import 'dart:uri';
import 'package:unittest/unittest.dart';
import 'package:http/http.dart' as http;
diff --git a/pkg/oauth2/test/client_test.dart b/pkg/oauth2/test/client_test.dart
index 7a05e99..d55eef7 100644
--- a/pkg/oauth2/test/client_test.dart
+++ b/pkg/oauth2/test/client_test.dart
@@ -7,7 +7,6 @@
import 'dart:async';
import 'dart:io';
import 'dart:json' as JSON;
-import 'dart:uri';
import 'package:http/http.dart' as http;
import 'package:oauth2/oauth2.dart' as oauth2;
diff --git a/pkg/oauth2/test/credentials_test.dart b/pkg/oauth2/test/credentials_test.dart
index 652d394..768b85a 100644
--- a/pkg/oauth2/test/credentials_test.dart
+++ b/pkg/oauth2/test/credentials_test.dart
@@ -7,7 +7,6 @@
import 'dart:async';
import 'dart:io';
import 'dart:json' as JSON;
-import 'dart:uri';
import 'package:http/http.dart' as http;
import 'package:oauth2/oauth2.dart' as oauth2;
diff --git a/pkg/oauth2/test/handle_access_token_response_test.dart b/pkg/oauth2/test/handle_access_token_response_test.dart
index 772f263..45860ab 100644
--- a/pkg/oauth2/test/handle_access_token_response_test.dart
+++ b/pkg/oauth2/test/handle_access_token_response_test.dart
@@ -6,7 +6,6 @@
import 'dart:io';
import 'dart:json' as JSON;
-import 'dart:uri';
import 'package:http/http.dart' as http;
import 'package:oauth2/oauth2.dart' as oauth2;
diff --git a/pkg/pkg.status b/pkg/pkg.status
index c752bfb..161a54b 100644
--- a/pkg/pkg.status
+++ b/pkg/pkg.status
@@ -119,6 +119,9 @@
[ $compiler == dart2js ]
unittest/test/instance_test: Skip
+[ $compiler == dart2js && $csp ]
+unittest/test/unittest_test: Pass, Crash # Issue 10935
+
[ $compiler == dart2js && $minified ]
# The unittest package relies on getting the original (non-minified) method
# names in Invocation. You can't get that when minifying.
@@ -140,9 +143,6 @@
[ $compiler == none && $runtime == drt ]
dartdoc/test/dartdoc_test: Skip # See dartbug.com/4541.
-[ $arch == arm ]
-*: Skip
-
[ $arch == simarm ]
*: Skip
diff --git a/pkg/scheduled_test/lib/scheduled_process.dart b/pkg/scheduled_test/lib/scheduled_process.dart
index 75891a9..3ff903c 100644
--- a/pkg/scheduled_test/lib/scheduled_process.dart
+++ b/pkg/scheduled_test/lib/scheduled_process.dart
@@ -39,7 +39,7 @@
Stream<String> _stdoutLog;
/// A line-by-line view of the standard output stream of the process.
- Stream<String> _stdout;
+ StreamIterator<String> _stdout;
/// A canceller that controls both [_stdout] and [_stdoutLog].
StreamCanceller _stdoutCanceller;
@@ -49,7 +49,7 @@
Stream<String> _stderrLog;
/// A line-by-line view of the standard error stream of the process.
- Stream<String> _stderr;
+ StreamIterator<String> _stderr;
/// A canceller that controls both [_stderr] and [_stderrLog].
StreamCanceller _stderrCanceller;
@@ -103,8 +103,8 @@
_stderrCanceller = stderrWithCanceller.last;
_stderrLog = stderrWithCanceller.first;
- _stdout = stdoutStream();
- _stderr = stderrStream();
+ _stdout = new StreamIterator<String>(stdoutStream());
+ _stderr = new StreamIterator<String>(stderrStream());
}
/// Updates [_description] to reflect [executable] and [arguments], which are
@@ -151,8 +151,7 @@
arguments,
workingDirectory: workingDirectory,
environment: environment).then((process) {
- // TODO(nweiz): enable this when issue 9020 is fixed.
- // process.stdin.encoding = Encoding.UTF_8;
+ process.stdin.encoding = Encoding.UTF_8;
return process;
});
});
@@ -249,11 +248,11 @@
}
/// Reads the next line of stdout from the process.
- Future<String> nextLine() => schedule(() => streamFirst(_stdout),
+ Future<String> nextLine() => schedule(() => streamIteratorFirst(_stdout),
"reading the next stdout line from process '$description'");
/// Reads the next line of stderr from the process.
- Future<String> nextErrLine() => schedule(() => streamFirst(_stderr),
+ Future<String> nextErrLine() => schedule(() => streamIteratorFirst(_stderr),
"reading the next stderr line from process '$description'");
/// Reads the remaining stdout from the process. This should only be called
@@ -263,8 +262,7 @@
throw new StateError("remainingStdout() should only be called after "
"kill() or shouldExit().");
}
-
- return schedule(() => _stdout.toList().then((lines) => lines.join("\n")),
+ return schedule(() => concatRest(_stdout),
"reading the remaining stdout from process '$description'");
}
@@ -276,7 +274,7 @@
"kill() or shouldExit().");
}
- return schedule(() => _stderr.toList().then((lines) => lines.join("\n")),
+ return schedule(() => concatRest(_stderr),
"reading the remaining stderr from process '$description'");
}
diff --git a/pkg/scheduled_test/lib/scheduled_server.dart b/pkg/scheduled_test/lib/scheduled_server.dart
index 1e4e633..293545b 100644
--- a/pkg/scheduled_test/lib/scheduled_server.dart
+++ b/pkg/scheduled_test/lib/scheduled_server.dart
@@ -7,7 +7,6 @@
import 'dart:async';
import 'dart:collection';
import 'dart:io';
-import 'dart:uri';
import 'scheduled_test.dart';
import 'src/utils.dart';
diff --git a/pkg/scheduled_test/lib/src/mock_clock.dart b/pkg/scheduled_test/lib/src/mock_clock.dart
index 6abe81f..0d77e5a 100644
--- a/pkg/scheduled_test/lib/src/mock_clock.dart
+++ b/pkg/scheduled_test/lib/src/mock_clock.dart
@@ -44,27 +44,25 @@
int get time => _time;
int _time = 0;
- /// The stream of millisecond ticks of the clock.
- Stream<int> get onTick {
- if (_onTickControllerStream == null) {
- _onTickControllerStream = _onTickController.stream.asBroadcastStream();
- }
- return _onTickControllerStream;
- }
-
- final _onTickController = new StreamController<int>();
- Stream<int> _onTickControllerStream;
+ /// Controller providing streams for listening.
+ StreamController<int> _multiplexController =
+ new StreamController<int>.broadcast();
Clock._();
+ /// The stream of millisecond ticks of the clock.
+ Stream<int> get onTick => _multiplexController.stream;
+
/// Advances the clock forward by [milliseconds]. This works like synchronous
/// code that takes [milliseconds] to execute; any [Timer]s that are scheduled
/// to fire during the interval will do so asynchronously once control returns
/// to the event loop.
- void tick([int milliseconds=1]) {
+ void tick([int milliseconds = 1]) {
for (var i = 0; i < milliseconds; i++) {
var tickTime = ++_time;
- new Future.value().then((_) => _onTickController.add(tickTime));
+ runAsync(() {
+ _multiplexController.add(tickTime);
+ });
}
}
@@ -74,7 +72,7 @@
/// code runs before the next tick.
void run() {
pumpEventQueue().then((_) {
- if (!_onTickController.hasListener) return;
+ if (!_multiplexController.hasListener) return;
tick();
return run();
});
diff --git a/pkg/scheduled_test/lib/src/scheduled_server/safe_http_server.dart b/pkg/scheduled_test/lib/src/scheduled_server/safe_http_server.dart
index 25d57ee..c9885f1 100644
--- a/pkg/scheduled_test/lib/src/scheduled_server/safe_http_server.dart
+++ b/pkg/scheduled_test/lib/src/scheduled_server/safe_http_server.dart
@@ -6,7 +6,6 @@
import 'dart:async';
import 'dart:io';
-import 'dart:uri';
// TODO(nweiz): remove this when issue 9140 is fixed.
/// A wrapper around [HttpServer] that swallows errors caused by requests
diff --git a/pkg/scheduled_test/lib/src/utils.dart b/pkg/scheduled_test/lib/src/utils.dart
index d686ef9..62461a6 100644
--- a/pkg/scheduled_test/lib/src/utils.dart
+++ b/pkg/scheduled_test/lib/src/utils.dart
@@ -94,27 +94,38 @@
return controller.stream;
}
-// TODO(nweiz): remove this when issue 7964 is fixed.
-/// Returns a [Future] that will complete to the first element of [stream].
-/// Unlike [Stream.first], this is safe to use with single-subscription streams.
-Future streamFirst(Stream stream) {
- var stackTrace;
- try {
- throw '';
- } catch (_, thrownStackTrace) {
- stackTrace = thrownStackTrace;
- }
+/// Returns the first element of a [StreamIterator].
+///
+/// If the [StreamIterator] has no elements, the result is a state error.
+Future<String> streamIteratorFirst(StreamIterator<String> streamIterator) {
+ StackTrace stackTrace = new Trace.current();
+ return streamIterator.moveNext().then((hasNext) {
+ if (hasNext) {
+ return streamIterator.current;
+ } else {
+ return new Future.error(new StateError("No elements"), stackTrace);
+ }
+ });
+}
- var completer = new Completer();
- var subscription;
- subscription = stream.listen((value) {
- subscription.cancel();
- completer.complete(value);
- }, onError: (e) {
- completer.completeError(e);
- }, onDone: () {
- completer.completeError(new StateError("No elements"), stackTrace);
- }, cancelOnError: true);
+/// Collects all remaining lines from a [StreamIterator] of lines.
+///
+/// Returns the concatenation of the collected lines joined by newlines.
+Future<String> concatRest(StreamIterator<String> streamIterator) {
+ var completer = new Completer<String>();
+ var buffer = new StringBuffer();
+ void collectAll() {
+ streamIterator.moveNext().then((hasNext) {
+ if (hasNext) {
+ if (!buffer.isEmpty) buffer.write('\n');
+ buffer.write(streamIterator.current);
+ collectAll();
+ } else {
+ completer.complete(buffer.toString());
+ }
+ }, onError: completer.completeError);
+ }
+ collectAll();
return completer.future;
}
diff --git a/pkg/serialization/lib/serialization.dart b/pkg/serialization/lib/serialization.dart
index a95ee3f..522a7d1 100644
--- a/pkg/serialization/lib/serialization.dart
+++ b/pkg/serialization/lib/serialization.dart
@@ -210,7 +210,6 @@
import 'dart:async';
import 'dart:json' as json;
import 'dart:collection';
-import 'dart:uri';
part 'src/reader_writer.dart';
part 'src/serialization_rule.dart';
diff --git a/pkg/serialization/lib/src/serialization_helpers.dart b/pkg/serialization/lib/src/serialization_helpers.dart
index 9568c24..1f86a97 100644
--- a/pkg/serialization/lib/src/serialization_helpers.dart
+++ b/pkg/serialization/lib/src/serialization_helpers.dart
@@ -248,6 +248,7 @@
values.clear();
}
bool get isEmpty => keys.isEmpty;
+ bool get isNotEmpty => !isEmpty;
// Note that this is doing an equality comparison.
bool containsValue(x) => values.contains(x);
diff --git a/pkg/serialization/lib/src/serialization_rule.dart b/pkg/serialization/lib/src/serialization_rule.dart
index 4ffe966..aad0aaf 100644
--- a/pkg/serialization/lib/src/serialization_rule.dart
+++ b/pkg/serialization/lib/src/serialization_rule.dart
@@ -408,7 +408,7 @@
// So follow one or the other path depending if it has a colon, which we
// assume is in any URI and can't be in a Symbol.
if (name.contains(":")) {
- var uri = new Uri(name);
+ var uri = Uri.parse(name);
var libMirror = currentMirrorSystem().libraries[uri];
return libMirror.classes[new Symbol(type)];
} else {
@@ -529,6 +529,7 @@
int get length => _raw.length;
bool get isEmpty => _raw.isEmpty;
+ bool get isNotEmpty => _raw.isNotEmpty;
Iterable get keys => _raw.keys;
bool containsKey(x) => _raw.containsKey(x);
diff --git a/pkg/stack_trace/lib/src/frame.dart b/pkg/stack_trace/lib/src/frame.dart
index cb7d656..335bfba 100644
--- a/pkg/stack_trace/lib/src/frame.dart
+++ b/pkg/stack_trace/lib/src/frame.dart
@@ -4,7 +4,6 @@
library frame;
-import 'dart:uri';
import 'package:pathos/path.dart' as path;
diff --git a/pkg/stack_trace/lib/src/trace.dart b/pkg/stack_trace/lib/src/trace.dart
index ffea498..4ed1563 100644
--- a/pkg/stack_trace/lib/src/trace.dart
+++ b/pkg/stack_trace/lib/src/trace.dart
@@ -5,7 +5,6 @@
library trace;
import 'dart:collection';
-import 'dart:uri';
import 'dart:math' as math;
import 'frame.dart';
diff --git a/pkg/stack_trace/lib/src/utils.dart b/pkg/stack_trace/lib/src/utils.dart
index 50ccab3..30a43bcc 100644
--- a/pkg/stack_trace/lib/src/utils.dart
+++ b/pkg/stack_trace/lib/src/utils.dart
@@ -5,7 +5,6 @@
library utils;
import 'dart:io';
-import 'dart:uri';
import 'package:pathos/path.dart' as path;
diff --git a/pkg/stack_trace/test/frame_test.dart b/pkg/stack_trace/test/frame_test.dart
index 826bad7..512f6d0 100644
--- a/pkg/stack_trace/test/frame_test.dart
+++ b/pkg/stack_trace/test/frame_test.dart
@@ -5,7 +5,6 @@
library frame_test;
import 'dart:io';
-import 'dart:uri';
import 'package:pathos/path.dart' as path;
import 'package:stack_trace/src/utils.dart';
@@ -42,7 +41,7 @@
// TODO(nweiz): use URL-style paths when such a thing exists.
var builder = new path.Builder(style: path.Style.posix);
expect(builder.basename(frame.uri.path), equals('frame_test.dart'));
- expect(frame.line, equals(17));
+ expect(frame.line, equals(16));
expect(frame.column, equals(5));
expect(frame.member, equals('getStackFrame'));
});
diff --git a/pkg/stack_trace/test/trace_test.dart b/pkg/stack_trace/test/trace_test.dart
index d3fa56e..afd5700 100644
--- a/pkg/stack_trace/test/trace_test.dart
+++ b/pkg/stack_trace/test/trace_test.dart
@@ -5,7 +5,6 @@
library trace_test;
import 'dart:io';
-import 'dart:uri';
import 'package:pathos/path.dart' as path;
import 'package:stack_trace/src/utils.dart';
diff --git a/pkg/unittest/lib/coverage_controller.js b/pkg/unittest/lib/coverage_controller.js
index 78ddb9d..1cf21ae 100644
--- a/pkg/unittest/lib/coverage_controller.js
+++ b/pkg/unittest/lib/coverage_controller.js
@@ -4,7 +4,7 @@
/**
* Coverage controller logic - used by coverage test harness to embed tests in
- * DumpRenderTree and extract coverage information.
+ * content shell and extract coverage information.
*/
var LONG_LINE = 60000;
@@ -13,7 +13,7 @@
if (e.data == 'unittest-suite-done') {
var s = JSON.stringify(top._$jscoverage);
var res = '';
- // DumpRenderTree has a bug on lines longer than 2^16, so we split them
+ // conent shell has a bug on lines longer than 2^16, so we split them
while (s.length > LONG_LINE) {
res += s.substr(0, LONG_LINE) + '<br>\n';
s = s.substr(LONG_LINE);
diff --git a/pkg/unittest/lib/test_controller.js b/pkg/unittest/lib/test_controller.js
index dd9bba3..d8ef908 100644
--- a/pkg/unittest/lib/test_controller.js
+++ b/pkg/unittest/lib/test_controller.js
@@ -4,7 +4,7 @@
/**
* Test controller logic - used by unit test harness to embed tests in
- * DumpRenderTree.
+ * conent shell.
*/
// Clear the console before every test run - this is Firebug specific code.
@@ -27,7 +27,7 @@
navigator.webkitStartDart();
}
-// testRunner is provided by DRT or WebKit's layout tests.
+// testRunner is provided by content shell.
// It is not available in selenium tests.
var testRunner = window.testRunner || window.layoutTestController;
diff --git a/pkg/webdriver/lib/webdriver.dart b/pkg/webdriver/lib/webdriver.dart
index e257bd6..0119c68 100644
--- a/pkg/webdriver/lib/webdriver.dart
+++ b/pkg/webdriver/lib/webdriver.dart
@@ -7,7 +7,6 @@
import 'dart:async';
import 'dart:io';
import 'dart:json' as json;
-import 'dart:uri';
part 'src/base64decoder.dart';
diff --git a/pkg/yaml/lib/src/yaml_map.dart b/pkg/yaml/lib/src/yaml_map.dart
index 29fec75..303d8ed 100644
--- a/pkg/yaml/lib/src/yaml_map.dart
+++ b/pkg/yaml/lib/src/yaml_map.dart
@@ -36,6 +36,7 @@
Iterable get values => _map.values;
int get length => _map.length;
bool get isEmpty => _map.isEmpty;
+ bool get isNotEmpty => map.isNotEmpty;
String toString() => _map.toString();
int get hashCode => hashCodeFor(_map);
diff --git a/runtime/bin/bin.gypi b/runtime/bin/bin.gypi
index 8cc5866..033539e 100644
--- a/runtime/bin/bin.gypi
+++ b/runtime/bin/bin.gypi
@@ -180,6 +180,7 @@
{
'target_name': 'libdart_io',
'type': 'static_library',
+ 'toolsets':['target', 'host'],
'include_dirs': [
'..',
],
@@ -187,14 +188,19 @@
'io_natives.h',
'io_natives.cc',
],
- 'includes': [
- 'io_impl_sources.gypi',
- ],
'conditions': [
[ 'dart_io_support==1', {
'dependencies': [
'bin/net/ssl.gyp:libssl_dart',
],
+ 'includes': [
+ 'io_impl_sources.gypi',
+ ],
+ },
+ {
+ 'includes': [
+ 'io_impl_sources_no_nss.gypi',
+ ],
}],
['OS=="win"', {
# TODO(antonm): fix the implementation.
@@ -336,6 +342,7 @@
{
'target_name': 'generate_resources_cc_file',
'type': 'none',
+ 'toolsets':['target', 'host'],
'includes': [
'vmstats_sources.gypi',
],
@@ -364,12 +371,13 @@
# dart binary with a snapshot of corelibs built in.
'target_name': 'dart',
'type': 'executable',
+ 'toolsets':['target'],
'dependencies': [
'libdart',
'libdart_builtin',
'libdart_io',
'generate_snapshot_file#host',
- 'generate_resources_cc_file',
+ 'generate_resources_cc_file#host',
],
'include_dirs': [
'..',
@@ -411,17 +419,34 @@
'-rdynamic',
],
}],
+ ['OS=="android"', {
+ 'link_settings': {
+ 'ldflags': [
+ '-z',
+ 'muldefs',
+ ],
+ 'ldflags!': [
+ '-Wl,--exclude-libs=ALL,-shared',
+ ],
+ 'libraries': [
+ '-llog',
+ '-lc',
+ '-lz',
+ ],
+ },
+ }],
],
},
{
# dart binary without any snapshot built in.
'target_name': 'dart_no_snapshot',
'type': 'executable',
+ 'toolsets':['target'],
'dependencies': [
'libdart_withcore',
'libdart_builtin',
'libdart_io',
- 'generate_resources_cc_file',
+ 'generate_resources_cc_file#host',
],
'include_dirs': [
'..',
@@ -467,6 +492,23 @@
'-rdynamic',
],
}],
+
+ ['OS=="android"', {
+ 'link_settings': {
+ 'ldflags': [
+ '-z',
+ 'muldefs',
+ ],
+ 'ldflags!': [
+ '-Wl,--exclude-libs=ALL,-shared',
+ ],
+ 'libraries': [
+ '-llog',
+ '-lc',
+ '-lz',
+ ],
+ },
+ }],
],
},
{
@@ -479,6 +521,78 @@
{
'target_name': 'run_vm_tests',
'type': 'executable',
+ 'toolsets':['target'],
+ 'dependencies': [
+ 'libdart_withcore',
+ 'libdart_builtin',
+ 'libdart_io',
+ 'generate_snapshot_file#host',
+ 'generate_snapshot_test_dat_file',
+ ],
+ 'include_dirs': [
+ '..',
+ '<(gen_source_dir)',
+ ],
+ 'sources': [
+ 'run_vm_tests.cc',
+ 'builtin_natives.cc',
+ 'builtin_nolib.cc',
+ 'builtin.h',
+ 'io_natives.h',
+ # Include generated source files.
+ '<(snapshot_cc_file)',
+ '<(builtin_cc_file)',
+ '<(io_cc_file)',
+ '<(io_patch_cc_file)',
+ ],
+ 'includes': [
+ 'builtin_impl_sources.gypi',
+ '../platform/platform_sources.gypi',
+ '../vm/vm_sources.gypi',
+ ],
+ 'defines': [
+ 'TESTING',
+ ],
+ # Only include _test.[cc|h] files.
+ 'sources/': [
+ ['exclude', '\\.(cc|h)$'],
+ ['include', 'run_vm_tests.cc'],
+ ['include', 'builtin_nolib.cc'],
+ ['include', 'builtin_natives.cc'],
+ ['include', '_gen\\.cc$'],
+ ['include', '_test\\.(cc|h)$'],
+ ],
+ 'conditions': [
+ ['OS=="win"', {
+ 'link_settings': {
+ 'libraries': [ '-lws2_32.lib', '-lRpcrt4.lib', '-lwinmm.lib' ],
+ },
+ }],
+ ['OS=="android"', {
+
+ 'link_settings': {
+ 'ldflags': [
+ '-z',
+ 'muldefs',
+ ],
+ 'ldflags!': [
+ '-Wl,--exclude-libs=ALL,-shared',
+ ],
+ 'libraries': [
+ '-Wl,--start-group',
+ '-Wl,--end-group',
+ '-llog',
+ '-lc',
+ '-lz',
+ ],
+ },
+ }],
+ ],
+ },
+ {
+ 'target_name': 'run_vm_tests.host',
+ 'type': 'executable',
+ 'toolsets':['host'],
'dependencies': [
'libdart_withcore',
'libdart_builtin',
@@ -527,44 +641,50 @@
}],
],
},
- {
- 'target_name': 'test_extension',
- 'type': 'shared_library',
- 'dependencies': [
- 'dart',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- 'test_extension.cc',
- 'test_extension_dllmain_win.cc',
- ],
- 'defines': [
- # The only effect of DART_SHARED_LIB is to export the Dart API entries.
- 'DART_SHARED_LIB',
- ],
- 'conditions': [
- ['OS=="win"', {
- 'msvs_settings': {
- 'VCLinkerTool': {
- 'AdditionalDependencies': [ 'dart.lib' ],
- 'AdditionalLibraryDirectories': [ '<(PRODUCT_DIR)' ],
- },
- },
- }],
- ['OS=="mac"', {
- 'xcode_settings': {
- 'OTHER_LDFLAGS': [ '-undefined', 'dynamic_lookup' ],
- },
- }],
- ['OS=="linux"', {
- 'cflags': [
- '-fPIC',
+ ],
+ 'conditions': [
+ ['OS!="android"', {
+ 'targets': [
+ {
+ 'target_name': 'test_extension',
+ 'type': 'shared_library',
+ 'dependencies': [
+ 'dart',
],
- }],
+ 'include_dirs': [
+ '..',
+ ],
+ 'sources': [
+ 'test_extension.cc',
+ 'test_extension_dllmain_win.cc',
+ ],
+ 'defines': [
+ # The only effect of DART_SHARED_LIB is to export the Dart API.
+ 'DART_SHARED_LIB',
+ ],
+ 'conditions': [
+ ['OS=="win"', {
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'AdditionalDependencies': [ 'dart.lib' ],
+ 'AdditionalLibraryDirectories': [ '<(PRODUCT_DIR)' ],
+ },
+ },
+ }],
+ ['OS=="mac"', {
+ 'xcode_settings': {
+ 'OTHER_LDFLAGS': [ '-undefined', 'dynamic_lookup' ],
+ },
+ }],
+ ['OS=="linux"', {
+ 'cflags': [
+ '-fPIC',
+ ],
+ }],
+ ],
+ },
],
- },
+ }],
],
}
diff --git a/runtime/bin/builtin.dart b/runtime/bin/builtin.dart
index 5eb32ad..808124a 100644
--- a/runtime/bin/builtin.dart
+++ b/runtime/bin/builtin.dart
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
library builtin;
-import 'dart:uri';
// Corelib 'print' implementation.
void _print(arg) {
@@ -58,9 +57,8 @@
_logResolution("## scriptName: $scriptName");
}
var base =
- new Uri.fromComponents(
- scheme: "file",
- path: cwd.endsWith("/") ? cwd : "$cwd/");
+ new Uri(scheme: "file",
+ path: cwd.endsWith("/") ? cwd : "$cwd/");
_entrypoint = base.resolve(scriptName);
_logResolution("# Resolved script to: $_entrypoint");
@@ -84,7 +82,7 @@
// package URI path part.
path = _filePathFromPackageUri(resolved);
}
- resolved = new Uri.fromComponents(scheme: "dart-ext", path: path);
+ resolved = new Uri(scheme: "dart-ext", path: path);
} else {
resolved = baseUri.resolve(userString);
}
@@ -127,8 +125,8 @@
}
String _filePathFromFileUri(Uri uri) {
- if (uri.domain != '') {
- throw "URIs using the 'file:' scheme may not contain a domain.";
+ if (!uri.host.isEmpty) {
+ throw "URIs using the 'file:' scheme may not contain a host.";
}
_logResolution("# Path: ${uri.path}");
@@ -136,8 +134,8 @@
}
String _filePathFromOtherUri(Uri uri) {
- if (uri.domain != '') {
- throw "URIs whose paths are used as file paths may not contain a domain.";
+ if (!uri.host.isEmpty) {
+ throw "URIs whose paths are used as file paths may not contain a host.";
}
_logResolution("# Path: ${uri.path}");
@@ -145,8 +143,8 @@
}
String _filePathFromPackageUri(Uri uri) {
- if (uri.domain != '') {
- var path = (uri.path != '') ? '${uri.domain}${uri.path}' : uri.domain;
+ if (!uri.host.isEmpty) {
+ var path = (uri.path != '') ? '${uri.host}${uri.path}' : uri.host;
var right = 'package:$path';
var wrong = 'package://$path';
diff --git a/runtime/bin/dartutils.cc b/runtime/bin/dartutils.cc
index e113927..89a84c4 100644
--- a/runtime/bin/dartutils.cc
+++ b/runtime/bin/dartutils.cc
@@ -26,7 +26,6 @@
const char* DartUtils::kCoreLibURL = "dart:core";
const char* DartUtils::kIOLibURL = "dart:io";
const char* DartUtils::kIOLibPatchURL = "dart:io-patch";
-const char* DartUtils::kUriLibURL = "dart:uri";
const char* DartUtils::kIdFieldName = "_id";
diff --git a/runtime/bin/dbg_message.cc b/runtime/bin/dbg_message.cc
index 5713657..caec295 100644
--- a/runtime/bin/dbg_message.cc
+++ b/runtime/bin/dbg_message.cc
@@ -1053,7 +1053,7 @@
DbgMsgQueue* DbgMsgQueueList::list_ = NULL;
-dart::Mutex DbgMsgQueueList::msg_queue_list_lock_;
+dart::Mutex* DbgMsgQueueList::msg_queue_list_lock_ = new dart::Mutex();
void DbgMsgQueueList::Initialize() {
@@ -1085,7 +1085,7 @@
const char* start,
const char* end,
int debug_fd) {
- MutexLocker ml(&msg_queue_list_lock_);
+ MutexLocker ml(msg_queue_list_lock_);
DbgMsgQueue* queue = DbgMsgQueueList::GetIsolateMsgQueueLocked(isolate_id);
if (queue != NULL) {
queue->AddMessage(cmd_idx, start, end, debug_fd);
@@ -1096,7 +1096,7 @@
bool DbgMsgQueueList::InterruptIsolate(Dart_IsolateId isolate_id) {
- MutexLocker ml(&msg_queue_list_lock_);
+ MutexLocker ml(msg_queue_list_lock_);
DbgMsgQueue* queue = DbgMsgQueueList::GetIsolateMsgQueueLocked(isolate_id);
if (queue != NULL) {
queue->InterruptIsolate();
@@ -1107,7 +1107,7 @@
DbgMsgQueue* DbgMsgQueueList::AddIsolateMsgQueue(Dart_IsolateId isolate_id) {
- MutexLocker ml(&msg_queue_list_lock_);
+ MutexLocker ml(msg_queue_list_lock_);
DbgMsgQueue* queue = new DbgMsgQueue(isolate_id, list_);
ASSERT(queue != NULL);
@@ -1117,7 +1117,7 @@
DbgMsgQueue* DbgMsgQueueList::GetIsolateMsgQueue(Dart_IsolateId isolate_id) {
- MutexLocker ml(&msg_queue_list_lock_);
+ MutexLocker ml(msg_queue_list_lock_);
ASSERT(Dart_GetIsolate(isolate_id) == Dart_CurrentIsolate());
return GetIsolateMsgQueueLocked(isolate_id);
}
@@ -1138,7 +1138,7 @@
void DbgMsgQueueList::RemoveIsolateMsgQueue(Dart_IsolateId isolate_id) {
- MutexLocker ml(&msg_queue_list_lock_);
+ MutexLocker ml(msg_queue_list_lock_);
if (list_ == NULL) {
return; // No items in the list.
}
@@ -1165,7 +1165,7 @@
void DbgMsgQueueList::ListIsolateIds(dart::TextBuffer* msg) {
- MutexLocker ml(&msg_queue_list_lock_);
+ MutexLocker ml(msg_queue_list_lock_);
if (list_ == NULL) {
return; // No items in the list.
}
diff --git a/runtime/bin/dbg_message.h b/runtime/bin/dbg_message.h
index 85be1a5..ca05255 100644
--- a/runtime/bin/dbg_message.h
+++ b/runtime/bin/dbg_message.h
@@ -255,7 +255,7 @@
static DbgMsgQueue* GetIsolateMsgQueueLocked(Dart_IsolateId isolate_id);
static DbgMsgQueue* list_;
- static dart::Mutex msg_queue_list_lock_;
+ static dart::Mutex* msg_queue_list_lock_;
DISALLOW_ALLOCATION();
DISALLOW_IMPLICIT_CONSTRUCTORS(DbgMsgQueueList);
diff --git a/runtime/bin/directory_android.cc b/runtime/bin/directory_android.cc
index f3ea9e6..dc5bad2 100644
--- a/runtime/bin/directory_android.cc
+++ b/runtime/bin/directory_android.cc
@@ -478,7 +478,7 @@
if (stat(ANDROID_TEMP_DIR, &st) != 0) {
mkdir(ANDROID_TEMP_DIR, 0777);
}
- path.Add(ANDROID_TEMP_DIR "/tmp/temp_dir1_");
+ path.Add(ANDROID_TEMP_DIR "/temp_dir1_");
} else if ((path.data)[path.length - 1] == '/') {
path.Add("temp_dir_");
}
diff --git a/runtime/bin/file_android.cc b/runtime/bin/file_android.cc
index e8a1fa9..b166aad 100644
--- a/runtime/bin/file_android.cc
+++ b/runtime/bin/file_android.cc
@@ -265,10 +265,17 @@
char* File::GetCanonicalPath(const char* pathname) {
char* abs_path = NULL;
if (pathname != NULL) {
+ // A null second argument to realpath crashes Android. Fixed in Mar 2013,
+ // but not in earlier releases of Android.
+ char* resolved = reinterpret_cast<char*>(malloc(PATH_MAX));
+ if (resolved == NULL) return NULL;
do {
- abs_path = realpath(pathname, NULL);
+ abs_path = realpath(pathname, resolved);
} while (abs_path == NULL && errno == EINTR);
ASSERT(abs_path == NULL || IsAbsolutePath(abs_path));
+ if (abs_path != resolved) {
+ free(resolved);
+ }
}
return abs_path;
}
diff --git a/runtime/bin/filter_dummy.cc b/runtime/bin/filter_dummy.cc
new file mode 100644
index 0000000..617e1c9
--- /dev/null
+++ b/runtime/bin/filter_dummy.cc
@@ -0,0 +1,44 @@
+// 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 "bin/builtin.h"
+#include "bin/dartutils.h"
+
+#include "include/dart_api.h"
+
+
+namespace dart {
+namespace bin {
+
+void FUNCTION_NAME(Filter_CreateZLibInflate)(Dart_NativeArguments args) {
+ Dart_EnterScope();
+ Dart_ThrowException(DartUtils::NewInternalError(
+ "ZLibInflater and Deflater not supported on this platform"));
+ Dart_ExitScope();
+}
+
+void FUNCTION_NAME(Filter_CreateZLibDeflate)(Dart_NativeArguments args) {
+ Dart_EnterScope();
+ Dart_ExitScope();
+}
+
+void FUNCTION_NAME(Filter_Process)(Dart_NativeArguments args) {
+ Dart_EnterScope();
+ Dart_ExitScope();
+}
+
+
+void FUNCTION_NAME(Filter_Processed)(Dart_NativeArguments args) {
+ Dart_EnterScope();
+ Dart_ExitScope();
+}
+
+
+void FUNCTION_NAME(Filter_End)(Dart_NativeArguments args) {
+ Dart_EnterScope();
+ Dart_ExitScope();
+}
+
+} // namespace bin
+} // namespace dart
diff --git a/runtime/bin/io_impl_sources_no_nss.gypi b/runtime/bin/io_impl_sources_no_nss.gypi
new file mode 100644
index 0000000..3222272
--- /dev/null
+++ b/runtime/bin/io_impl_sources_no_nss.gypi
@@ -0,0 +1,45 @@
+# 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.
+
+# This file contains some C++ sources for the dart:io library. The other
+# implementation files are in builtin_impl_sources.gypi.
+{
+ 'sources': [
+ 'common.cc',
+ 'crypto.cc',
+ 'crypto_android.cc',
+ 'crypto_linux.cc',
+ 'crypto_macos.cc',
+ 'crypto_win.cc',
+ 'eventhandler.cc',
+ 'eventhandler.h',
+ 'eventhandler_android.cc',
+ 'eventhandler_linux.cc',
+ 'eventhandler_linux.h',
+ 'eventhandler_macos.cc',
+ 'eventhandler_macos.h',
+ 'eventhandler_win.cc',
+ 'eventhandler_win.h',
+ 'filter_dummy.cc',
+ 'platform.cc',
+ 'platform.h',
+ 'platform_android.cc',
+ 'platform_linux.cc',
+ 'platform_macos.cc',
+ 'platform_win.cc',
+ 'process.cc',
+ 'process.h',
+ 'process_android.cc',
+ 'process_linux.cc',
+ 'process_macos.cc',
+ 'process_win.cc',
+ 'socket.cc',
+ 'socket.h',
+ 'socket_android.cc',
+ 'socket_linux.cc',
+ 'socket_macos.cc',
+ 'socket_win.cc',
+ 'secure_socket_dummy.cc',
+ ],
+}
diff --git a/runtime/bin/main.cc b/runtime/bin/main.cc
index 5bfc079..6f139b7 100644
--- a/runtime/bin/main.cc
+++ b/runtime/bin/main.cc
@@ -454,9 +454,6 @@
// Prepare builtin and its dependent libraries for use to resolve URIs.
// The builtin library is part of the core snapshot and would already be
// available here in the case of script snapshot loading.
- Dart_Handle uri_url = DartUtils::NewString(DartUtils::kUriLibURL);
- Dart_Handle uri_lib = Dart_LookupLibrary(uri_url);
- CHECK_RESULT(uri_lib);
Dart_Handle builtin_lib =
Builtin::LoadAndCheckLibrary(Builtin::kBuiltinLibrary);
CHECK_RESULT(builtin_lib);
diff --git a/runtime/bin/net/nss.gyp b/runtime/bin/net/nss.gyp
index 53d3d6f..e1c64e1 100644
--- a/runtime/bin/net/nss.gyp
+++ b/runtime/bin/net/nss.gyp
@@ -91,6 +91,7 @@
'target_name': 'nspr_dart', # Added by Dart (the _dart postfix)
'product_name': 'crnspr',
'type': '<(component)',
+ 'toolsets':['host','target'],
# Changed by Dart: '<(nss_directory)/' added to all paths.
'sources': [
# Added by Dart.
@@ -458,6 +459,7 @@
'target_name': 'nss_dart', # Added by Dart (the _dart postfix)
'product_name': 'crnss',
'type': '<(component)',
+ 'toolsets':['host','target'],
'dependencies': [
'nss_static_dart', # Added by Dart (the _dart postfix)
],
@@ -509,6 +511,7 @@
'target_name': 'nssckbi_dart', # Added by Dart (the _dart postfix)
'product_name': 'crnssckbi',
'type': 'static_library',
+ 'toolsets':['host','target'],
# This target is an implementation detail - the public dependencies
# should be on 'nss'.
'suppress_wildcard': 1,
@@ -571,6 +574,7 @@
{
'target_name': 'nss_static_dart', # Added by Dart (the _dart postfix)
'type': 'static_library',
+ 'toolsets':['host','target'],
# This target is an implementation detail - the public dependencies
# should be on 'nss'.
'suppress_wildcard': 1,
diff --git a/runtime/bin/net/sqlite.gyp b/runtime/bin/net/sqlite.gyp
index 14dedb2..f194bdc 100644
--- a/runtime/bin/net/sqlite.gyp
+++ b/runtime/bin/net/sqlite.gyp
@@ -39,6 +39,7 @@
'targets': [
{
'target_name': 'sqlite_dart', # Added by Dart (the _dart postfix)
+ 'toolsets':['host','target'],
'conditions': [
[ 'chromeos==1' , {
'defines': [
diff --git a/runtime/bin/net/ssl.gyp b/runtime/bin/net/ssl.gyp
index b8fbf8f..a7744df 100644
--- a/runtime/bin/net/ssl.gyp
+++ b/runtime/bin/net/ssl.gyp
@@ -44,6 +44,7 @@
{
'target_name': 'libssl_dart', # Added by Dart (the _dart postfix)
'type': 'static_library',
+ 'toolsets':['host','target'],
# Changed by Dart: '<(ssl_directory)/' added to all paths.
'sources': [
'<(ssl_directory)/ssl/authcert.c',
diff --git a/runtime/bin/net/zlib.gyp b/runtime/bin/net/zlib.gyp
index 41c5c62..f3e7bca 100644
--- a/runtime/bin/net/zlib.gyp
+++ b/runtime/bin/net/zlib.gyp
@@ -24,6 +24,7 @@
{
'target_name': 'zlib_dart', # Added by Dart (the _dart postfix)
'type': 'static_library',
+ 'toolsets':['host','target'],
# Changed by Dart: '<(zlib_directory)/' added to all paths.
'sources': [
'<(zlib_path)/adler32.c',
diff --git a/runtime/bin/secure_socket_dummy.cc b/runtime/bin/secure_socket_dummy.cc
new file mode 100644
index 0000000..a571c85
--- /dev/null
+++ b/runtime/bin/secure_socket_dummy.cc
@@ -0,0 +1,90 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#include "bin/builtin.h"
+#include "bin/dartutils.h"
+
+#include "include/dart_api.h"
+
+
+namespace dart {
+namespace bin {
+
+void FUNCTION_NAME(SecureSocket_Init)(Dart_NativeArguments args) {
+ Dart_EnterScope();
+ Dart_ThrowException(DartUtils::NewDartArgumentError(
+ "Secure Sockets unsupported on this platform"));
+ Dart_ExitScope();
+}
+
+
+void FUNCTION_NAME(SecureSocket_Connect)(Dart_NativeArguments args) {
+ Dart_EnterScope();
+ Dart_ThrowException(DartUtils::NewDartArgumentError(
+ "Secure Sockets unsupported on this platform"));
+ Dart_ExitScope();
+}
+
+
+void FUNCTION_NAME(SecureSocket_Destroy)(Dart_NativeArguments args) {
+ Dart_EnterScope();
+ Dart_ThrowException(DartUtils::NewDartArgumentError(
+ "Secure Sockets unsupported on this platform"));
+ Dart_ExitScope();
+}
+
+
+void FUNCTION_NAME(SecureSocket_Handshake)(Dart_NativeArguments args) {
+ Dart_EnterScope();
+ Dart_ThrowException(DartUtils::NewDartArgumentError(
+ "Secure Sockets unsupported on this platform"));
+ Dart_ExitScope();
+}
+
+
+void FUNCTION_NAME(SecureSocket_RegisterHandshakeCompleteCallback)(
+ Dart_NativeArguments args) {
+ Dart_EnterScope();
+ Dart_ThrowException(DartUtils::NewDartArgumentError(
+ "Secure Sockets unsupported on this platform"));
+ Dart_ExitScope();
+}
+
+
+void FUNCTION_NAME(SecureSocket_RegisterBadCertificateCallback)(
+ Dart_NativeArguments args) {
+ Dart_EnterScope();
+ Dart_ThrowException(DartUtils::NewDartArgumentError(
+ "Secure Sockets unsupported on this platform"));
+ Dart_ExitScope();
+}
+
+
+void FUNCTION_NAME(SecureSocket_ProcessBuffer)(Dart_NativeArguments args) {
+ Dart_EnterScope();
+ Dart_ThrowException(DartUtils::NewDartArgumentError(
+ "Secure Sockets unsupported on this platform"));
+ Dart_ExitScope();
+}
+
+
+void FUNCTION_NAME(SecureSocket_InitializeLibrary)
+ (Dart_NativeArguments args) {
+ Dart_EnterScope();
+ Dart_ThrowException(DartUtils::NewDartArgumentError(
+ "Secure Sockets unsupported on this platform"));
+ Dart_ExitScope();
+}
+
+
+void FUNCTION_NAME(SecureSocket_PeerCertificate)
+ (Dart_NativeArguments args) {
+ Dart_EnterScope();
+ Dart_ThrowException(DartUtils::NewDartArgumentError(
+ "Secure Sockets unsupported on this platform"));
+ Dart_ExitScope();
+}
+
+} // namespace bin
+} // namespace dart
diff --git a/runtime/bin/socket_android.cc b/runtime/bin/socket_android.cc
index 8bb8f07..20715a3 100644
--- a/runtime/bin/socket_android.cc
+++ b/runtime/bin/socket_android.cc
@@ -9,12 +9,14 @@
#include <stdio.h> // NOLINT
#include <stdlib.h> // NOLINT
#include <string.h> // NOLINT
+#include <sys/stat.h> // NOLINT
#include <unistd.h> // NOLINT
#include <netinet/tcp.h> // NOLINT
-#include "bin/socket.h"
#include "bin/fdutils.h"
+#include "bin/file.h"
#include "bin/log.h"
+#include "bin/socket.h"
namespace dart {
@@ -152,6 +154,17 @@
}
+int Socket::GetType(intptr_t fd) {
+ struct stat buf;
+ int result = fstat(fd, &buf);
+ if (result == -1) return -1;
+ if (S_ISCHR(buf.st_mode)) return File::kTerminal;
+ if (S_ISFIFO(buf.st_mode)) return File::kPipe;
+ if (S_ISREG(buf.st_mode)) return File::kFile;
+ return File::kOther;
+}
+
+
intptr_t Socket::GetStdioHandle(int num) {
return static_cast<intptr_t>(num);
}
diff --git a/runtime/bin/socket_patch.dart b/runtime/bin/socket_patch.dart
index f233a98..d86a17c 100644
--- a/runtime/bin/socket_patch.dart
+++ b/runtime/bin/socket_patch.dart
@@ -837,11 +837,6 @@
if (offset < buffer.length) {
if (!paused) {
paused = true;
- // TODO(ajohnsen): It would be nice to avoid this check.
- // Some info: socket._write can emit an event, if it fails to write.
- // If the user closes the socket in that event, stop() will be called
- // before we get a change to pause.
- if (subscription == null) return;
subscription.pause();
}
socket._enableWriteEvent();
@@ -874,6 +869,7 @@
if (subscription == null) return;
subscription.cancel();
subscription = null;
+ paused = false;
socket._disableWriteEvent();
}
}
diff --git a/runtime/lib/array.dart b/runtime/lib/array.dart
index b26f098..cfb640b 100644
--- a/runtime/lib/array.dart
+++ b/runtime/lib/array.dart
@@ -194,6 +194,8 @@
return this.length == 0;
}
+ bool get isNotEmpty => !isEmpty;
+
Iterable<E> get reversed => IterableMixinWorkaround.reversedList(this);
void sort([int compare(E a, E b)]) {
@@ -445,6 +447,8 @@
return this.length == 0;
}
+ bool get isNotEmpty => !isEmpty;
+
Iterable<E> get reversed => IterableMixinWorkaround.reversedList(this);
void sort([int compare(E a, E b)]) {
diff --git a/runtime/lib/collection_patch.dart b/runtime/lib/collection_patch.dart
index 1ddd5d9..6479ba2 100644
--- a/runtime/lib/collection_patch.dart
+++ b/runtime/lib/collection_patch.dart
@@ -109,6 +109,8 @@
/* patch */ int get length => _hashTable._elementCount;
/* patch */ bool get isEmpty => _hashTable._elementCount == 0;
+
+ /* patch */ bool get isNotEmpty => !isEmpty;
}
patch class HashSet<E> {
@@ -130,6 +132,8 @@
/* patch */ bool get isEmpty => _table._elementCount == 0;
+ /* patch */ bool get isNotEmpty => !isEmpty;
+
/* patch */ bool contains(Object object) => _table._get(object) >= 0;
// Collection.
@@ -300,6 +304,8 @@
/* patch */ int get length => _hashTable._elementCount;
/* patch */ bool get isEmpty => _hashTable._elementCount == 0;
+
+ /* patch */ bool get isNotEmpty => !isEmpty;
}
patch class LinkedHashSet<E> extends _HashSetBase<E> {
@@ -320,6 +326,8 @@
/* patch */ bool get isEmpty => _table._elementCount == 0;
+ /* patch */ bool get isNotEmpty => !isEmpty;
+
/* patch */ bool contains(Object object) => _table._get(object) >= 0;
/* patch */ void forEach(void action(E element)) {
diff --git a/runtime/lib/growable_array.dart b/runtime/lib/growable_array.dart
index 1e69b65..6dfb6f6 100644
--- a/runtime/lib/growable_array.dart
+++ b/runtime/lib/growable_array.dart
@@ -324,6 +324,8 @@
return this.length == 0;
}
+ bool get isNotEmpty => !isEmpty;
+
void clear() {
this.length = 0;
}
diff --git a/runtime/lib/immutable_map.dart b/runtime/lib/immutable_map.dart
index 3ca9ed5..3c5c72e 100644
--- a/runtime/lib/immutable_map.dart
+++ b/runtime/lib/immutable_map.dart
@@ -25,6 +25,8 @@
return kvPairs_.length == 0;
}
+ bool get isNotEmpty => !isEmpty;
+
int get length {
return kvPairs_.length ~/ 2;
}
diff --git a/runtime/lib/integers_patch.dart b/runtime/lib/integers_patch.dart
index 05d47cf..fb749d7 100644
--- a/runtime/lib/integers_patch.dart
+++ b/runtime/lib/integers_patch.dart
@@ -13,6 +13,8 @@
((9 <= codePoint) && (codePoint <= 13)); // CR, LF, TAB, etc.
}
+ static bool is64Bit() => 1 << 32 is _Smi;
+
static int _tryParseSmi(String str) {
if (str.isEmpty) return null;
var ix = 0;
@@ -40,7 +42,8 @@
return null; // Empty.
}
}
- if ((endIx - ix) >= 9) {
+ int smiLimit = is64Bit() ? 18 : 9;
+ if ((endIx - ix) >= smiLimit) {
return null; // May not fit into a Smi.
}
var result = 0;
diff --git a/runtime/lib/math_patch.dart b/runtime/lib/math_patch.dart
index c279c19..d5110da 100644
--- a/runtime/lib/math_patch.dart
+++ b/runtime/lib/math_patch.dart
@@ -49,7 +49,11 @@
do {
seed = (seed + 0x5A17) & _Random._MASK_64;
} while (seed == 0);
- return new _Random._internal(seed);
+ // Crank a couple of times to distribute the seed bits a bit further.
+ return new _Random._internal(seed).._nextState()
+ .._nextState()
+ .._nextState()
+ .._nextState();
}
}
diff --git a/runtime/lib/string_patch.dart b/runtime/lib/string_patch.dart
index dbe8dc0..0707a5f 100644
--- a/runtime/lib/string_patch.dart
+++ b/runtime/lib/string_patch.dart
@@ -70,6 +70,8 @@
return this.length == 0;
}
+ bool get isNotEmpty => !isEmpty;
+
String operator +(String other) native "String_concat";
String concat(String other) => this + other;
diff --git a/runtime/lib/typed_data.dart b/runtime/lib/typed_data.dart
index 8e5bcaa..8cf462f 100644
--- a/runtime/lib/typed_data.dart
+++ b/runtime/lib/typed_data.dart
@@ -358,6 +358,7 @@
return this.length == 0;
}
+ bool get isNotEmpty => !isEmpty;
// Method(s) implementing the List interface.
diff --git a/runtime/tests/vm/dart/isolate_mirror_local_test.dart b/runtime/tests/vm/dart/isolate_mirror_local_test.dart
index e7927c2..39f5948 100644
--- a/runtime/tests/vm/dart/isolate_mirror_local_test.dart
+++ b/runtime/tests/vm/dart/isolate_mirror_local_test.dart
@@ -13,7 +13,6 @@
import 'dart:async';
import 'dart:isolate';
import 'dart:mirrors';
-import 'dart:uri';
ReceivePort exit_port;
Set expectedTests;
diff --git a/runtime/tests/vm/vm.status b/runtime/tests/vm/vm.status
index 63e214c..4fe49fc 100644
--- a/runtime/tests/vm/vm.status
+++ b/runtime/tests/vm/vm.status
@@ -54,9 +54,6 @@
# Skip until we stabilize language tests.
*: Skip
-[ $arch == arm ]
-*: Skip
-
[ $arch == simarm ]
# Tests missing code generation support.
cc/Dart2JSCompileAll: Skip
@@ -65,11 +62,6 @@
dart/byte_array_test: Skip
dart/byte_array_optimized_test: Skip
-# Bug in optimized code generation.
-cc/ExternalStringDeoptimize: Skip
-dart/inline_stack_frame_test: Skip
-dart/isolate_mirror_local_test: Skip
-
[ $arch == mips ]
*: Skip
@@ -82,6 +74,11 @@
dart/byte_array_optimized_test: Skip
dart/inline_stack_frame_test: Skip
+# Bug in optimized code generation.
+cc/ExternalStringDeoptimize: Skip
+dart/inline_stack_frame_test: Skip
+dart/isolate_mirror_local_test: Skip
+
# TODO(ajohnsen): Fix this as part of library changes.
[ $compiler == none ]
cc/CustomIsolates: Skip # Bug 6890
diff --git a/runtime/tools/create_snapshot_bin.py b/runtime/tools/create_snapshot_bin.py
index c80df4d..db948a1 100755
--- a/runtime/tools/create_snapshot_bin.py
+++ b/runtime/tools/create_snapshot_bin.py
@@ -59,83 +59,6 @@
return True
-def RunAdb(device, command):
- """Run a raw adb command."""
- return utils.RunCommand(["adb", "-s", device] + command)
-
-
-def RunAdbShell(device, command):
- RunAdb(device, ['shell'] + command)
-
-
-def RunOnAndroid(options):
- outputBin = options.output_bin
-
- android_workspace = os.getenv("ANDROID_DART", "/data/local/dart")
- android_outputBin = join(android_workspace, basename(outputBin))
-
- executable = options.executable
- android_executable = join(android_workspace, basename(executable))
-
- filesToPush = [] # (src, dest)
- filesToPull = [] # (src, dest)
-
- # Setup arguments to the snapshot generator binary.
- script_args = [android_executable]
-
- # First setup the snapshot output filename.
- filesToPull.append((android_outputBin, outputBin))
- script_args.append(''.join([ "--snapshot=", android_outputBin]))
-
- # We don't know what source files are needed to fully satisfy a dart script,
- # so we can't support the general case of url mapping or script inclusion.
- if options.url_mapping:
- raise Exception("--url_mapping is not supported when building for Android")
-
- if options.script:
- raise Exception("--script is not supported when building for Android")
-
- filesToPush.append((executable, android_executable))
-
- abi = options.abi or 'x86'
- # We know we're run in the runtime directory, and we know the relative path
- # to the tools we want to execute:
- command = ["tools/android_finder.py", "--bootstrap", "--abi", abi]
- if VERBOSE:
- command += ['--verbose']
- device = utils.RunCommand(command, errStream=sys.stderr)
-
- if device == None:
- raise Exception("Could not find Android device for abi %s" % abi)
-
- device = device.strip()
-
- if VERBOSE:
- sys.write.stderr('Using Android device %s for abi %s' % (device, abi))
-
- RunAdbShell(device, ["mkdir", android_workspace])
-
- try:
- if VERBOSE:
- sys.write.stderr('pushing files to %s' % device)
- for src, dest in filesToPush:
- RunAdb(device, ["push", src, dest])
- if VERBOSE:
- sys.write.stderr('running snapshot generator')
- RunAdbShell(device, script_args)
- if VERBOSE:
- sys.write.stderr('retrieving snapshot')
- for src, dest in filesToPull:
- RunAdb(device, ["pull", src, dest])
- finally:
- if VERBOSE:
- sys.write.stderr('cleaning intermediate files')
- for src, dest in filesToPush:
- RunAdbShell(device, ["rm", dest])
- for src, dest in filesToPull:
- RunAdbShell(device, ["rm", src])
-
-
def Main():
# Parse options.
parser = BuildOptions()
@@ -165,15 +88,12 @@
script_args.append(options.script)
# Construct command line to execute the snapshot generator binary and invoke.
- if options.target_os == 'android':
- RunOnAndroid(options)
- else:
- command = [ options.executable ] + script_args
- try:
- utils.RunCommand(command, outStream=sys.stderr, errStream=sys.stderr,
- verbose=options.verbose, printErrorInfo=True)
- except Exception as e:
- return -1
+ command = [ options.executable ] + script_args
+ try:
+ utils.RunCommand(command, outStream=sys.stderr, errStream=sys.stderr,
+ verbose=options.verbose, printErrorInfo=True)
+ except Exception as e:
+ return -1
return 0
diff --git a/runtime/tools/gyp/runtime_configurations_android.gypi b/runtime/tools/gyp/runtime_configurations_android.gypi
index 15eafa5..6de2aee 100644
--- a/runtime/tools/gyp/runtime_configurations_android.gypi
+++ b/runtime/tools/gyp/runtime_configurations_android.gypi
@@ -7,6 +7,9 @@
# http://src.chromium.org/viewvc/chrome/trunk/src/build/common.gypi
{
+ 'variables': {
+ 'dart_io_support': 0,
+ },
'target_defaults': {
'cflags': [
'-Wno-abi',
diff --git a/runtime/vm/assembler_arm.cc b/runtime/vm/assembler_arm.cc
index dffa50b..b84ff57 100644
--- a/runtime/vm/assembler_arm.cc
+++ b/runtime/vm/assembler_arm.cc
@@ -18,7 +18,7 @@
namespace dart {
DEFINE_FLAG(bool, print_stop_message, true, "Print stop message.");
-
+DECLARE_FLAG(bool, inline_alloc);
bool CPUFeatures::integer_division_supported_ = false;
#if defined(DEBUG)
@@ -414,6 +414,12 @@
}
+void Assembler::bics(Register rd, Register rn, ShifterOperand so,
+ Condition cond) {
+ EmitType01(cond, so.type(), BIC, 1, rn, rd, so);
+}
+
+
void Assembler::mvn(Register rd, ShifterOperand so, Condition cond) {
EmitType01(cond, so.type(), MVN, 0, R0, rd, so);
}
@@ -517,6 +523,13 @@
}
+void Assembler::smlal(Register rd_lo, Register rd_hi,
+ Register rn, Register rm, Condition cond) {
+ // Assembler registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs.
+ EmitMulOp(cond, B23 | B22 | B21, rd_lo, rd_hi, rn, rm);
+}
+
+
void Assembler::EmitDivOp(Condition cond, int32_t opcode,
Register rd, Register rn, Register rm) {
ASSERT(CPUFeatures::integer_division_supported());
@@ -2060,9 +2073,39 @@
void Assembler::TryAllocate(const Class& cls,
Label* failure,
- bool near_jump,
Register instance_reg) {
- UNIMPLEMENTED();
+ ASSERT(failure != NULL);
+ if (FLAG_inline_alloc) {
+ Heap* heap = Isolate::Current()->heap();
+ const intptr_t instance_size = cls.instance_size();
+ LoadImmediate(instance_reg, heap->TopAddress());
+ ldr(instance_reg, Address(instance_reg, 0));
+ AddImmediate(instance_reg, instance_size);
+
+ // instance_reg: potential next object start.
+ LoadImmediate(TMP, heap->EndAddress());
+ ldr(TMP, Address(TMP, 0));
+ cmp(TMP, ShifterOperand(instance_reg));
+ // fail if heap end unsigned less than or equal to instance_reg.
+ b(failure, LS);
+
+ // Successfully allocated the object, now update top to point to
+ // next object start and store the class in the class field of object.
+ LoadImmediate(TMP, heap->TopAddress());
+ str(instance_reg, Address(TMP, 0));
+
+ ASSERT(instance_size >= kHeapObjectTag);
+ AddImmediate(instance_reg, -instance_size + kHeapObjectTag);
+
+ uword tags = 0;
+ tags = RawObject::SizeTag::update(instance_size, tags);
+ ASSERT(cls.id() != kIllegalCid);
+ tags = RawObject::ClassIdTag::update(cls.id(), tags);
+ LoadImmediate(TMP, tags);
+ str(TMP, FieldAddress(instance_reg, Object::tags_offset()));
+ } else {
+ b(failure);
+ }
}
diff --git a/runtime/vm/assembler_arm.h b/runtime/vm/assembler_arm.h
index 6195664..4ee373b 100644
--- a/runtime/vm/assembler_arm.h
+++ b/runtime/vm/assembler_arm.h
@@ -382,6 +382,7 @@
void movs(Register rd, ShifterOperand so, Condition cond = AL);
void bic(Register rd, Register rn, ShifterOperand so, Condition cond = AL);
+ void bics(Register rd, Register rn, ShifterOperand so, Condition cond = AL);
void mvn(Register rd, ShifterOperand so, Condition cond = AL);
void mvns(Register rd, ShifterOperand so, Condition cond = AL);
@@ -402,6 +403,8 @@
Condition cond = AL);
void umull(Register rd_lo, Register rd_hi, Register rn, Register rm,
Condition cond = AL);
+ void smlal(Register rd_lo, Register rd_hi, Register rn, Register rm,
+ Condition cond = AL);
// Division instructions.
void sdiv(Register rd, Register rn, Register rm, Condition cond = AL);
@@ -668,7 +671,6 @@
// Only the tags field of the object is initialized.
void TryAllocate(const Class& cls,
Label* failure,
- bool near_jump,
Register instance_reg);
// Emit data (e.g encoded instruction or immediate) in instruction stream.
diff --git a/runtime/vm/assembler_arm_test.cc b/runtime/vm/assembler_arm_test.cc
index 52de670..838bb69 100644
--- a/runtime/vm/assembler_arm_test.cc
+++ b/runtime/vm/assembler_arm_test.cc
@@ -17,7 +17,7 @@
ASSEMBLER_TEST_GENERATE(Simple, assembler) {
__ mov(R0, ShifterOperand(42));
- __ mov(PC, ShifterOperand(LR));
+ __ bx(LR);
}
@@ -29,7 +29,7 @@
ASSEMBLER_TEST_GENERATE(MoveNegated, assembler) {
__ mvn(R0, ShifterOperand(42));
- __ mov(PC, ShifterOperand(LR));
+ __ bx(LR);
}
@@ -46,7 +46,7 @@
__ mov(R0, shifter_op);
EXPECT(ShifterOperand::CanHold(0x30000003, &shifter_op));
__ add(R0, R0, shifter_op);
- __ mov(PC, ShifterOperand(LR));
+ __ bx(LR);
}
@@ -60,7 +60,7 @@
ASSEMBLER_TEST_GENERATE(MovImm16, assembler) {
__ movw(R0, 0x5678);
__ movt(R0, 0x1234);
- __ mov(PC, ShifterOperand(LR));
+ __ bx(LR);
}
@@ -76,7 +76,7 @@
__ cmp(R0, ShifterOperand(0));
__ LoadImmediate(R0, 0x12345678, EQ);
__ LoadImmediate(R0, 0x87654321, NE);
- __ mov(PC, ShifterOperand(LR));
+ __ bx(LR);
}
@@ -99,7 +99,7 @@
__ vmovsr(S7, R1); // S7 = R1, S6:S7 == 41:43
__ vmovrrd(R0, R1, D3); // R0:R1 = D3, R0:R1 == 41:43
__ sub(R0, R1, ShifterOperand(R0)); // 43-41
- __ mov(PC, ShifterOperand(LR));
+ __ bx(LR);
}
@@ -118,7 +118,7 @@
__ vadds(S0, S0, S0);
__ vstrs(S0, Address(R2, (-kWordSize * 30)));
__ ldr(R0, Address(SP, (kWordSize * 30), Address::PostIndex));
- __ mov(PC, ShifterOperand(LR));
+ __ bx(LR);
}
@@ -143,7 +143,7 @@
// Expressing __ldr(R0, Address(SP, (kWordSize * 32), Address::PostIndex));
// as:
__ ldr(R0, Address(SP, R1, LSL, 5, Address::PostIndex));
- __ mov(PC, ShifterOperand(LR));
+ __ bx(LR);
}
@@ -167,7 +167,7 @@
__ vstrd(D0, Address(R2, (-kWordSize * 30)));
__ ldr(R1, Address(R2, (-kWordSize * 29)));
__ ldr(R0, Address(SP, (kWordSize * 30), Address::PostIndex));
- __ mov(PC, ShifterOperand(LR));
+ __ bx(LR);
}
@@ -190,7 +190,7 @@
__ vdivs(S0, S0, S1); // 14.7f
__ vsqrts(S0, S0); // 3.8340579f
__ vmovrs(R0, S0);
- __ mov(PC, ShifterOperand(LR));
+ __ bx(LR);
}
@@ -213,7 +213,7 @@
__ vdivd(D0, D0, D1); // 14.7
__ vsqrtd(D0, D0); // 3.8340579
__ vmovrrd(R0, R1, D0);
- __ mov(PC, ShifterOperand(LR));
+ __ bx(LR);
}
@@ -225,12 +225,31 @@
}
+ASSEMBLER_TEST_GENERATE(DoubleSqrtNeg, assembler) {
+ // Check that sqrt of a negative double gives NaN.
+ __ LoadDImmediate(D1, -1.0, R0);
+ __ vsqrtd(D0, D1);
+ __ vcmpd(D0, D0);
+ __ vmstat();
+ __ mov(R0, ShifterOperand(1), VS);
+ __ mov(R0, ShifterOperand(0), VC);
+ __ Ret();
+}
+
+
+ASSEMBLER_TEST_RUN(DoubleSqrtNeg, test) {
+ EXPECT(test != NULL);
+ typedef double (*DoubleFPOperations)();
+ EXPECT_EQ(1, EXECUTE_TEST_CODE_INT32(DoubleFPOperations, test->entry()));
+}
+
+
ASSEMBLER_TEST_GENERATE(IntToDoubleConversion, assembler) {
__ mov(R3, ShifterOperand(6));
__ vmovsr(S3, R3);
__ vcvtdi(D1, S3);
__ vmovrrd(R0, R1, D1);
- __ mov(PC, ShifterOperand(LR));
+ __ bx(LR);
}
@@ -254,7 +273,7 @@
__ LoadDImmediate(D2, 1.0 * (1LL << 32), R0);
__ vmlad(D0, D1, D2);
__ vmovrrd(R0, R1, D0);
- __ mov(PC, ShifterOperand(LR));
+ __ bx(LR);
}
@@ -272,7 +291,7 @@
__ vmovsr(S3, R3);
__ vcvtsi(S1, S3);
__ vmovrs(R0, S1);
- __ mov(PC, ShifterOperand(LR));
+ __ bx(LR);
}
@@ -288,7 +307,7 @@
__ vmovsr(S1, R0);
__ vcvtis(S0, S1);
__ vmovrs(R0, S0);
- __ mov(PC, ShifterOperand(LR));
+ __ bx(LR);
}
@@ -311,7 +330,7 @@
__ vmovdrr(D1, R0, R1);
__ vcvtid(S0, D1);
__ vmovrs(R0, S0);
- __ mov(PC, ShifterOperand(LR));
+ __ bx(LR);
}
@@ -334,7 +353,7 @@
__ LoadSImmediate(S1, 12.8f);
__ vcvtds(D2, S1);
__ vmovrrd(R0, R1, D2);
- __ mov(PC, ShifterOperand(LR));
+ __ bx(LR);
}
@@ -351,7 +370,7 @@
__ LoadDImmediate(D1, 12.8, R0);
__ vcvtsd(S3, D1);
__ vmovrs(R0, S3);
- __ mov(PC, ShifterOperand(LR));
+ __ bx(LR);
}
@@ -387,7 +406,7 @@
__ add(R0, R0, ShifterOperand(16), VC); // Error if not unordered (not Nan).
// R0 is 0 if all tests passed.
- __ mov(PC, ShifterOperand(LR));
+ __ bx(LR);
}
@@ -421,7 +440,7 @@
__ add(R0, R0, ShifterOperand(16), VC); // Error if not unordered (not Nan).
// R0 is 0 if all tests passed.
- __ mov(PC, ShifterOperand(LR));
+ __ bx(LR);
}
@@ -440,7 +459,7 @@
__ mov(R0, ShifterOperand(R0, LSL, 1));
__ movs(R1, ShifterOperand(R1, LSR, 1));
__ b(&loop_entry, NE);
- __ mov(PC, ShifterOperand(LR));
+ __ bx(LR);
}
@@ -457,7 +476,7 @@
__ b(&skip);
__ mov(R0, ShifterOperand(11));
__ Bind(&skip);
- __ mov(PC, ShifterOperand(LR));
+ __ bx(LR);
}
@@ -472,7 +491,7 @@
__ mov(R1, ShifterOperand(123));
__ Push(R1);
__ Pop(R0);
- __ mov(PC, ShifterOperand(LR));
+ __ bx(LR);
}
@@ -489,7 +508,7 @@
__ add(R0, R1, ShifterOperand(4));
__ rsbs(R0, R0, ShifterOperand(100));
__ rsc(R0, R0, ShifterOperand(100));
- __ mov(PC, ShifterOperand(LR));
+ __ bx(LR);
}
@@ -511,7 +530,7 @@
__ tst(IP, ShifterOperand(0));
__ b(&retry, NE); // NE if context switch occurred between ldrex and strex.
__ Pop(R0); // 42
- __ mov(PC, ShifterOperand(LR));
+ __ bx(LR);
}
@@ -531,7 +550,7 @@
__ strex(IP, R1, SP); // IP == 1, failure
__ Pop(R0); // 40
__ add(R0, R0, ShifterOperand(IP));
- __ mov(PC, ShifterOperand(LR));
+ __ bx(LR);
}
@@ -548,7 +567,7 @@
__ and_(R1, R2, ShifterOperand(R1));
__ mov(R3, ShifterOperand(42));
__ orr(R0, R1, ShifterOperand(R3));
- __ mov(PC, ShifterOperand(LR));
+ __ bx(LR);
}
@@ -563,11 +582,11 @@
__ mov(R0, ShifterOperand(0));
__ tst(R0, ShifterOperand(R1)); // Set zero-flag.
__ orrs(R0, R0, ShifterOperand(1)); // Clear zero-flag.
- __ mov(PC, ShifterOperand(LR), EQ);
+ __ bx(LR, EQ);
__ mov(R0, ShifterOperand(42));
- __ mov(PC, ShifterOperand(LR), NE); // Only this return should fire.
+ __ bx(LR, NE); // Only this return should fire.
__ mov(R0, ShifterOperand(2));
- __ mov(PC, ShifterOperand(LR));
+ __ bx(LR);
}
@@ -583,7 +602,7 @@
__ mov(R2, ShifterOperand(40));
__ mul(R3, R2, R1);
__ mov(R0, ShifterOperand(R3));
- __ mov(PC, ShifterOperand(LR));
+ __ bx(LR);
}
@@ -603,7 +622,7 @@
__ vcvtid(S0, D0);
__ vmovrs(R1, S0); // r1 = r0/r2
__ mls(R0, R1, R2, R0); // r0 = r0 - r1*r2
- __ mov(PC, ShifterOperand(LR));
+ __ bx(LR);
}
@@ -624,7 +643,7 @@
__ mla(R2, IP, R3, R4);
__ add(R1, R2, ShifterOperand(R1));
__ Pop(R4);
- __ mov(PC, ShifterOperand(LR));
+ __ bx(LR);
}
@@ -638,7 +657,7 @@
ASSEMBLER_TEST_GENERATE(Multiply32To64, assembler) {
__ smull(R0, R1, R0, R2);
- __ mov(PC, ShifterOperand(LR));
+ __ bx(LR);
}
@@ -650,6 +669,20 @@
}
+ASSEMBLER_TEST_GENERATE(MultiplyAccum32To64, assembler) {
+ __ smlal(R0, R1, R0, R2);
+ __ bx(LR);
+}
+
+
+ASSEMBLER_TEST_RUN(MultiplyAccum32To64, test) {
+ EXPECT(test != NULL);
+ typedef int64_t (*Multiply32To64)(int64_t operand0, int64_t operand1);
+ EXPECT_EQ(3,
+ EXECUTE_TEST_CODE_INT64_LL(Multiply32To64, test->entry(), -3, -2));
+}
+
+
ASSEMBLER_TEST_GENERATE(Clz, assembler) {
Label error;
@@ -670,10 +703,10 @@
__ cmp(R1, ShifterOperand(3));
__ b(&error, NE);
__ mov(R0, ShifterOperand(0));
- __ mov(PC, ShifterOperand(LR));
+ __ bx(LR);
__ Bind(&error);
__ mov(R0, ShifterOperand(1));
- __ mov(PC, ShifterOperand(LR));
+ __ bx(LR);
}
@@ -693,7 +726,7 @@
__ b(&skip, NE);
__ mov(R0, ShifterOperand(0));
__ Bind(&skip);
- __ mov(PC, ShifterOperand(LR));
+ __ bx(LR);
}
@@ -711,7 +744,7 @@
__ mov(R0, ShifterOperand(R0, LSL, 1));
__ mov(R1, ShifterOperand(1));
__ mov(R0, ShifterOperand(R0, LSL, R1));
- __ mov(PC, ShifterOperand(LR));
+ __ bx(LR);
}
@@ -729,7 +762,7 @@
__ mov(R0, ShifterOperand(R0, LSR, 1));
__ mov(R1, ShifterOperand(1));
__ mov(R0, ShifterOperand(R0, LSR, R1));
- __ mov(PC, ShifterOperand(LR));
+ __ bx(LR);
}
@@ -746,7 +779,7 @@
__ mov(R0, ShifterOperand(1));
__ Lsl(R0, R0, 31);
__ Lsr(R0, R0, 31);
- __ mov(PC, ShifterOperand(LR));
+ __ bx(LR);
}
@@ -763,7 +796,7 @@
__ mov(R0, ShifterOperand(1));
__ Lsl(R0, R0, 31);
__ Asr(R0, R0, 31);
- __ mov(PC, ShifterOperand(LR));
+ __ bx(LR);
}
@@ -777,7 +810,7 @@
ASSEMBLER_TEST_GENERATE(Rsb, assembler) {
__ mov(R3, ShifterOperand(10));
__ rsb(R0, R3, ShifterOperand(42));
- __ mov(PC, ShifterOperand(LR));
+ __ bx(LR);
}
@@ -823,7 +856,7 @@
__ mov(R0, ShifterOperand(0));
__ Bind(&Done);
__ ldr(R1, Address(SP, (kWordSize * 30), Address::PostIndex));
- __ mov(PC, ShifterOperand(LR));
+ __ bx(LR);
}
@@ -840,7 +873,7 @@
__ str(R1, Address(SP, (-kWordSize * 30), Address::PreIndex));
__ ldrsb(R0, Address(R2, (-kWordSize * 30)));
__ ldr(R1, Address(SP, (kWordSize * 30), Address::PostIndex));
- __ mov(PC, ShifterOperand(LR));
+ __ bx(LR);
}
@@ -857,7 +890,7 @@
__ str(R1, Address(SP, (-kWordSize * 30), Address::PreIndex));
__ ldrb(R0, Address(R2, (-kWordSize * 30)));
__ ldr(R1, Address(SP, (kWordSize * 30), Address::PostIndex));
- __ mov(PC, ShifterOperand(LR));
+ __ bx(LR);
}
@@ -874,7 +907,7 @@
__ str(R1, Address(SP, (-kWordSize * 30), Address::PreIndex));
__ ldrsh(R0, Address(R2, (-kWordSize * 30)));
__ ldr(R1, Address(SP, (kWordSize * 30), Address::PostIndex));
- __ mov(PC, ShifterOperand(LR));
+ __ bx(LR);
}
@@ -891,7 +924,7 @@
__ str(R1, Address(SP, (-kWordSize * 30), Address::PreIndex));
__ ldrh(R0, Address(R2, (-kWordSize * 30)));
__ ldr(R1, Address(SP, (kWordSize * 30), Address::PostIndex));
- __ mov(PC, ShifterOperand(LR));
+ __ bx(LR);
}
@@ -910,7 +943,7 @@
__ ldrd(R0, Address(SP, (kWordSize * 30), Address::PostIndex));
__ sub(R0, R0, ShifterOperand(R2));
__ add(R1, R1, ShifterOperand(R3));
- __ mov(PC, ShifterOperand(LR));
+ __ bx(LR);
}
@@ -954,7 +987,7 @@
__ Pop(R5); // Restore R5.
__ Pop(R5); // Restore R5.
__ Pop(R5); // Restore R5.
- __ mov(PC, ShifterOperand(LR));
+ __ bx(LR);
}
@@ -970,7 +1003,7 @@
__ mov(R1, ShifterOperand(kWordSize));
__ str(R2, Address(SP, R1, LSL, 1, Address::NegOffset));
__ ldr(R0, Address(SP, (-kWordSize * 2), Address::Offset));
- __ mov(PC, ShifterOperand(LR));
+ __ bx(LR);
}
@@ -986,7 +1019,7 @@
__ mov(R1, ShifterOperand(kWordSize));
__ str(R2, Address(SP, (-kWordSize * 32), Address::Offset));
__ ldr(R0, Address(SP, R1, LSL, 5, Address::NegOffset));
- __ mov(PC, ShifterOperand(LR));
+ __ bx(LR);
}
@@ -1002,7 +1035,7 @@
__ mov(R1, ShifterOperand(kWordSize * 2));
__ str(R2, Address(SP, R1, LSR, 1, Address::NegOffset));
__ ldr(R0, Address(SP, -kWordSize, Address::Offset));
- __ mov(PC, ShifterOperand(LR));
+ __ bx(LR);
}
@@ -1018,7 +1051,7 @@
__ mov(R1, ShifterOperand(kWordSize * 2));
__ str(R2, Address(SP, -kWordSize, Address::Offset));
__ ldr(R0, Address(SP, R1, LSR, 1, Address::NegOffset));
- __ mov(PC, ShifterOperand(LR));
+ __ bx(LR);
}
@@ -1036,7 +1069,7 @@
__ str(R2, Address(SP, R1, LSL, 5, Address::NegPreIndex));
__ ldr(R0, Address(R3, (-kWordSize * 32), Address::Offset));
__ mov(SP, ShifterOperand(R3));
- __ mov(PC, ShifterOperand(LR));
+ __ bx(LR);
}
@@ -1052,7 +1085,7 @@
__ mov(R1, ShifterOperand(kWordSize));
__ str(R2, Address(SP, (-kWordSize * 32), Address::PreIndex));
__ ldr(R0, Address(SP, R1, LSL, 5, Address::PostIndex));
- __ mov(PC, ShifterOperand(LR));
+ __ bx(LR);
}
@@ -1106,7 +1139,7 @@
__ vmstat();
__ mov(R0, ShifterOperand(0), NE); // Put failure into R0 if NE
- __ mov(PC, ShifterOperand(LR));
+ __ bx(LR);
}
@@ -1159,7 +1192,7 @@
__ vmstat();
__ mov(R0, ShifterOperand(0), NE); // Put failure value into R0 if NE
- __ mov(PC, ShifterOperand(LR));
+ __ bx(LR);
}
@@ -1211,7 +1244,7 @@
__ vmstat();
__ mov(R0, ShifterOperand(0), NE); // Put failure into R0 if NE
- __ mov(PC, ShifterOperand(LR));
+ __ bx(LR);
}
@@ -1262,7 +1295,7 @@
__ vmstat();
__ mov(R0, ShifterOperand(0), NE); // Put failure value into R0 if NE
- __ mov(PC, ShifterOperand(LR));
+ __ bx(LR);
}
@@ -1319,7 +1352,7 @@
__ vmstat();
__ mov(R0, ShifterOperand(0), NE); // Put failure into R0 if NE
- __ mov(PC, ShifterOperand(LR));
+ __ bx(LR);
}
@@ -1374,7 +1407,7 @@
__ vmstat();
__ mov(R0, ShifterOperand(0), NE); // Put failure value into R0 if NE
- __ mov(PC, ShifterOperand(LR));
+ __ bx(LR);
}
@@ -1395,7 +1428,7 @@
// available both in Thumb and in the ARM instruction set.
__ Lsr(R0, R0, 24);
__ and_(R0, R0, ShifterOperand(0xf));
- __ mov(PC, ShifterOperand(LR));
+ __ bx(LR);
}
@@ -1413,7 +1446,7 @@
__ mrc(R0, 15, 0, 0, 2, 0);
__ Lsr(R0, R0, 24);
__ and_(R0, R0, ShifterOperand(0xf));
- __ mov(PC, ShifterOperand(LR));
+ __ bx(LR);
}
@@ -1431,7 +1464,7 @@
__ mrc(R0, 15, 0, 0, 2, 0);
__ Lsr(R0, R0, 24);
__ and_(R0, R0, ShifterOperand(0xf));
- __ mov(PC, ShifterOperand(LR));
+ __ bx(LR);
}
@@ -1458,7 +1491,7 @@
} else {
__ mov(R0, ShifterOperand(3));
}
- __ mov(PC, ShifterOperand(LR));
+ __ bx(LR);
}
@@ -1478,7 +1511,7 @@
} else {
__ LoadImmediate(R0, -3);
}
- __ mov(PC, ShifterOperand(LR));
+ __ bx(LR);
}
@@ -1498,7 +1531,7 @@
} else {
__ LoadImmediate(R0, 0);
}
- __ mov(PC, ShifterOperand(LR));
+ __ bx(LR);
}
@@ -1518,7 +1551,7 @@
} else {
__ LoadImmediate(R0, 0);
}
- __ mov(PC, ShifterOperand(LR));
+ __ bx(LR);
}
@@ -1538,7 +1571,7 @@
} else {
__ LoadImmediate(R0, 0);
}
- __ mov(PC, ShifterOperand(LR));
+ __ bx(LR);
}
@@ -1558,7 +1591,7 @@
} else {
__ LoadImmediate(R0, 0x80000000);
}
- __ mov(PC, ShifterOperand(LR));
+ __ bx(LR);
}
@@ -1575,7 +1608,7 @@
__ LoadImmediate(R1, -9);
__ muls(R2, R0, R1);
__ mov(R0, ShifterOperand(42), MI);
- __ mov(PC, ShifterOperand(LR));
+ __ bx(LR);
}
diff --git a/runtime/vm/assembler_ia32.cc b/runtime/vm/assembler_ia32.cc
index 7442edc..3b35560 100644
--- a/runtime/vm/assembler_ia32.cc
+++ b/runtime/vm/assembler_ia32.cc
@@ -1271,6 +1271,13 @@
}
+void Assembler::andl(Register dst, const Address& address) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x23);
+ EmitOperand(dst, address);
+}
+
+
void Assembler::orl(Register dst, Register src) {
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitUint8(0x0B);
@@ -1284,6 +1291,13 @@
}
+void Assembler::orl(Register dst, const Address& address) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x0B);
+ EmitOperand(dst, address);
+}
+
+
void Assembler::xorl(Register dst, Register src) {
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitUint8(0x33);
@@ -1297,6 +1311,13 @@
}
+void Assembler::xorl(Register dst, const Address& address) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x33);
+ EmitOperand(dst, address);
+}
+
+
void Assembler::addl(Register reg, const Immediate& imm) {
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitComplex(0, Operand(reg), imm);
diff --git a/runtime/vm/assembler_ia32.h b/runtime/vm/assembler_ia32.h
index e9c6148..7ed62a8 100644
--- a/runtime/vm/assembler_ia32.h
+++ b/runtime/vm/assembler_ia32.h
@@ -514,12 +514,15 @@
void andl(Register dst, const Immediate& imm);
void andl(Register dst, Register src);
+ void andl(Register dst, const Address& address);
void orl(Register dst, const Immediate& imm);
void orl(Register dst, Register src);
+ void orl(Register dst, const Address& address);
void xorl(Register dst, const Immediate& imm);
void xorl(Register dst, Register src);
+ void xorl(Register dst, const Address& address);
void addl(Register dst, Register src);
void addl(Register reg, const Immediate& imm);
diff --git a/runtime/vm/assembler_ia32_test.cc b/runtime/vm/assembler_ia32_test.cc
index bada450..cfc7981 100644
--- a/runtime/vm/assembler_ia32_test.cc
+++ b/runtime/vm/assembler_ia32_test.cc
@@ -340,14 +340,23 @@
ASSEMBLER_TEST_GENERATE(Bitwise, assembler) {
__ movl(ECX, Immediate(42));
__ xorl(ECX, ECX);
- __ orl(ECX, Immediate(256));
- __ movl(EAX, Immediate(4));
- __ orl(ECX, EAX);
+ __ orl(ECX, Immediate(0x100));
+ __ movl(EAX, Immediate(0x648));
+ __ orl(ECX, EAX); // 0x748.
__ movl(EAX, Immediate(0xfff0));
- __ andl(ECX, EAX);
+ __ andl(ECX, EAX); // 0x740.
+ __ pushl(Immediate(0xF6FF));
+ __ andl(ECX, Address(ESP, 0)); // 0x640.
+ __ popl(EAX); // Discard.
__ movl(EAX, Immediate(1));
- __ orl(ECX, EAX);
- __ xorl(ECX, Immediate(0));
+ __ orl(ECX, EAX); // 0x641.
+ __ pushl(Immediate(0x7));
+ __ orl(ECX, Address(ESP, 0)); // 0x647.
+ __ popl(EAX); // Discard.
+ __ xorl(ECX, Immediate(0)); // 0x647.
+ __ pushl(Immediate(0x1C));
+ __ xorl(ECX, Address(ESP, 0)); // 0x65B.
+ __ popl(EAX); // Discard.
__ movl(EAX, ECX);
__ ret();
}
@@ -355,7 +364,7 @@
ASSEMBLER_TEST_RUN(Bitwise, test) {
typedef int (*Bitwise)();
- EXPECT_EQ(256 + 1, reinterpret_cast<Bitwise>(test->entry())());
+ EXPECT_EQ(0x65B, reinterpret_cast<Bitwise>(test->entry())());
}
diff --git a/runtime/vm/assembler_mips.cc b/runtime/vm/assembler_mips.cc
index 3f496db..200e777 100644
--- a/runtime/vm/assembler_mips.cc
+++ b/runtime/vm/assembler_mips.cc
@@ -204,10 +204,14 @@
}
-void Assembler::CompareObject(Register rd, Register rn, const Object& object) {
+void Assembler::CompareObject(Register rd1, Register rd2,
+ Register rn, const Object& object) {
ASSERT(rn != TMP1);
+ ASSERT(rd1 != TMP1);
+ ASSERT(rd1 != rd2);
LoadObject(TMP1, object);
- subu(rd, rn, TMP1);
+ slt(rd1, rn, TMP1);
+ slt(rd2, TMP1, rn);
}
diff --git a/runtime/vm/assembler_mips.h b/runtime/vm/assembler_mips.h
index d496837..c48f1bd 100644
--- a/runtime/vm/assembler_mips.h
+++ b/runtime/vm/assembler_mips.h
@@ -230,10 +230,11 @@
}
// CPU instructions in alphabetical order.
- void addd(FRegister fd, FRegister fs, FRegister ft) {
- ASSERT(EvenFPURegister(fd));
- ASSERT(EvenFPURegister(fs));
- ASSERT(EvenFPURegister(ft));
+ void addd(DRegister dd, DRegister ds, DRegister dt) {
+ // DRegisters start at the even FRegisters.
+ FRegister fd = static_cast<FRegister>(dd * 2);
+ FRegister fs = static_cast<FRegister>(ds * 2);
+ FRegister ft = static_cast<FRegister>(dt * 2);
EmitFpuRType(COP1, FMT_D, ft, fs, fd, COP1_ADD);
}
@@ -378,58 +379,58 @@
}
// FPU compare, always false.
- void cfd(FRegister fs, FRegister ft) {
- ASSERT(EvenFPURegister(fs));
- ASSERT(EvenFPURegister(ft));
+ void cfd(DRegister ds, DRegister dt) {
+ FRegister fs = static_cast<FRegister>(ds * 2);
+ FRegister ft = static_cast<FRegister>(dt * 2);
EmitFpuRType(COP1, FMT_D, ft, fs, F0, COP1_C_F);
}
// FPU compare, true if unordered, i.e. one is NaN.
- void cund(FRegister fs, FRegister ft) {
- ASSERT(EvenFPURegister(fs));
- ASSERT(EvenFPURegister(ft));
+ void cund(DRegister ds, DRegister dt) {
+ FRegister fs = static_cast<FRegister>(ds * 2);
+ FRegister ft = static_cast<FRegister>(dt * 2);
EmitFpuRType(COP1, FMT_D, ft, fs, F0, COP1_C_UN);
}
// FPU compare, true if equal.
- void ceqd(FRegister fs, FRegister ft) {
- ASSERT(EvenFPURegister(fs));
- ASSERT(EvenFPURegister(ft));
+ void ceqd(DRegister ds, DRegister dt) {
+ FRegister fs = static_cast<FRegister>(ds * 2);
+ FRegister ft = static_cast<FRegister>(dt * 2);
EmitFpuRType(COP1, FMT_D, ft, fs, F0, COP1_C_EQ);
}
// FPU compare, true if unordered or equal.
- void cueqd(FRegister fs, FRegister ft) {
- ASSERT(EvenFPURegister(fs));
- ASSERT(EvenFPURegister(ft));
+ void cueqd(DRegister ds, DRegister dt) {
+ FRegister fs = static_cast<FRegister>(ds * 2);
+ FRegister ft = static_cast<FRegister>(dt * 2);
EmitFpuRType(COP1, FMT_D, ft, fs, F0, COP1_C_UEQ);
}
// FPU compare, true if less than.
- void coltd(FRegister fs, FRegister ft) {
- ASSERT(EvenFPURegister(fs));
- ASSERT(EvenFPURegister(ft));
+ void coltd(DRegister ds, DRegister dt) {
+ FRegister fs = static_cast<FRegister>(ds * 2);
+ FRegister ft = static_cast<FRegister>(dt * 2);
EmitFpuRType(COP1, FMT_D, ft, fs, F0, COP1_C_OLT);
}
// FPU compare, true if unordered or less than.
- void cultd(FRegister fs, FRegister ft) {
- ASSERT(EvenFPURegister(fs));
- ASSERT(EvenFPURegister(ft));
+ void cultd(DRegister ds, DRegister dt) {
+ FRegister fs = static_cast<FRegister>(ds * 2);
+ FRegister ft = static_cast<FRegister>(dt * 2);
EmitFpuRType(COP1, FMT_D, ft, fs, F0, COP1_C_ULT);
}
// FPU compare, true if less or equal.
- void coled(FRegister fs, FRegister ft) {
- ASSERT(EvenFPURegister(fs));
- ASSERT(EvenFPURegister(ft));
+ void coled(DRegister ds, DRegister dt) {
+ FRegister fs = static_cast<FRegister>(ds * 2);
+ FRegister ft = static_cast<FRegister>(dt * 2);
EmitFpuRType(COP1, FMT_D, ft, fs, F0, COP1_C_OLE);
}
// FPU compare, true if unordered or less or equal.
- void culed(FRegister fs, FRegister ft) {
- ASSERT(EvenFPURegister(fs));
- ASSERT(EvenFPURegister(ft));
+ void culed(DRegister ds, DRegister dt) {
+ FRegister fs = static_cast<FRegister>(ds * 2);
+ FRegister ft = static_cast<FRegister>(dt * 2);
EmitFpuRType(COP1, FMT_D, ft, fs, F0, COP1_C_ULE);
}
@@ -442,21 +443,20 @@
}
// Converts a 32-bit signed int in fs to a double in fd.
- void cvtdw(FRegister fd, FRegister fs) {
- ASSERT(EvenFPURegister(fd));
+ void cvtdw(DRegister dd, FRegister fs) {
+ FRegister fd = static_cast<FRegister>(dd * 2);
EmitFpuRType(COP1, FMT_W, F0, fs, fd, COP1_CVT_D);
}
// Converts a 64-bit signed int in fs to a double in fd.
- void cvtdl(FRegister fd, FRegister fs) {
- ASSERT(EvenFPURegister(fs));
- ASSERT(EvenFPURegister(fd));
+ void cvtdl(DRegister dd, DRegister ds) {
+ FRegister fs = static_cast<FRegister>(ds * 2);
+ FRegister fd = static_cast<FRegister>(dd * 2);
EmitFpuRType(COP1, FMT_L, F0, fs, fd, COP1_CVT_D);
}
- void cvtwd(FRegister fd, FRegister fs) {
- ASSERT(EvenFPURegister(fs));
- ASSERT(EvenFPURegister(fd));
+ void cvtwd(FRegister fd, DRegister ds) {
+ FRegister fs = static_cast<FRegister>(ds * 2);
EmitFpuRType(COP1, FMT_D, F0, fs, fd, COP1_CVT_W);
}
@@ -464,10 +464,10 @@
EmitRType(SPECIAL, rs, rt, R0, 0, DIV);
}
- void divd(FRegister fd, FRegister fs, FRegister ft) {
- ASSERT(EvenFPURegister(fd));
- ASSERT(EvenFPURegister(fs));
- ASSERT(EvenFPURegister(ft));
+ void divd(DRegister dd, DRegister ds, DRegister dt) {
+ FRegister fd = static_cast<FRegister>(dd * 2);
+ FRegister fs = static_cast<FRegister>(ds * 2);
+ FRegister ft = static_cast<FRegister>(dt * 2);
EmitFpuRType(COP1, FMT_D, ft, fs, fd, COP1_DIV);
}
@@ -496,8 +496,8 @@
EmitLoadStore(LBU, rt, addr);
}
- void ldc1(FRegister ft, const Address& addr) {
- ASSERT(EvenFPURegister(ft));
+ void ldc1(DRegister dt, const Address& addr) {
+ FRegister ft = static_cast<FRegister>(dt * 2);
EmitFpuLoadStore(LDC1, ft, addr);
}
@@ -542,9 +542,9 @@
or_(rd, rs, ZR);
}
- void movd(FRegister fd, FRegister fs) {
- ASSERT(EvenFPURegister(fd));
- ASSERT(EvenFPURegister(fs));
+ void movd(DRegister dd, DRegister ds) {
+ FRegister fd = static_cast<FRegister>(dd * 2);
+ FRegister fs = static_cast<FRegister>(ds * 2);
EmitFpuRType(COP1, FMT_D, F0, fs, fd, COP1_MOV);
}
@@ -567,10 +567,10 @@
fs << kFsShift);
}
- void muld(FRegister fd, FRegister fs, FRegister ft) {
- ASSERT(EvenFPURegister(fd));
- ASSERT(EvenFPURegister(fs));
- ASSERT(EvenFPURegister(ft));
+ void muld(DRegister dd, DRegister ds, DRegister dt) {
+ FRegister fd = static_cast<FRegister>(dd * 2);
+ FRegister fs = static_cast<FRegister>(ds * 2);
+ FRegister ft = static_cast<FRegister>(dt * 2);
EmitFpuRType(COP1, FMT_D, ft, fs, fd, COP1_MUL);
}
@@ -604,8 +604,8 @@
EmitLoadStore(SB, rt, addr);
}
- void sdc1(FRegister ft, const Address& addr) {
- ASSERT(EvenFPURegister(ft));
+ void sdc1(DRegister dt, const Address& addr) {
+ FRegister ft = static_cast<FRegister>(dt * 2);
EmitFpuLoadStore(SDC1, ft, addr);
}
@@ -625,13 +625,25 @@
EmitRType(SPECIAL, rs, rt, rd, 0, SLT);
}
+ void slti(Register rt, Register rs, const Immediate& imm) {
+ ASSERT(Utils::IsInt(kImmBits, imm.value()));
+ int16_t imm_value = static_cast<int16_t>(imm.value());
+ EmitIType(SLTI, rs, rt, imm_value);
+ }
+
+ void sltiu(Register rt, Register rs, const Immediate& imm) {
+ ASSERT(Utils::IsUint(kImmBits, imm.value()));
+ uint16_t imm_value = static_cast<uint16_t>(imm.value());
+ EmitIType(SLTIU, rs, rt, imm_value);
+ }
+
void sltu(Register rd, Register rs, Register rt) {
EmitRType(SPECIAL, rs, rt, rd, 0, SLTU);
}
- void sqrtd(FRegister fd, FRegister fs) {
- ASSERT(EvenFPURegister(fd));
- ASSERT(EvenFPURegister(fs));
+ void sqrtd(DRegister dd, DRegister ds) {
+ FRegister fd = static_cast<FRegister>(dd * 2);
+ FRegister fs = static_cast<FRegister>(ds * 2);
EmitFpuRType(COP1, FMT_D, F0, fs, fd, COP1_SQRT);
}
@@ -651,10 +663,10 @@
EmitRType(SPECIAL, rs, rt, rd, 0, SRLV);
}
- void subd(FRegister fd, FRegister fs, FRegister ft) {
- ASSERT(EvenFPURegister(fd));
- ASSERT(EvenFPURegister(fs));
- ASSERT(EvenFPURegister(ft));
+ void subd(DRegister dd, DRegister ds, DRegister dt) {
+ FRegister fd = static_cast<FRegister>(dd * 2);
+ FRegister fs = static_cast<FRegister>(ds * 2);
+ FRegister ft = static_cast<FRegister>(dt * 2);
EmitFpuRType(COP1, FMT_D, ft, fs, fd, COP1_SUB);
}
@@ -760,23 +772,23 @@
}
}
- void LoadImmediate(FRegister rd, double value) {
- ASSERT(EvenFPURegister(rd));
+ void LoadImmediate(DRegister rd, double value) {
+ FRegister frd = static_cast<FRegister>(rd * 2);
const int64_t ival = bit_cast<uint64_t, double>(value);
const int32_t low = Utils::Low32Bits(ival);
const int32_t high = Utils::High32Bits(ival);
if (low != 0) {
LoadImmediate(TMP1, low);
- mtc1(TMP1, rd);
+ mtc1(TMP1, frd);
} else {
- mtc1(ZR, rd);
+ mtc1(ZR, frd);
}
if (high != 0) {
LoadImmediate(TMP1, high);
- mtc1(TMP1, static_cast<FRegister>(rd + 1));
+ mtc1(TMP1, static_cast<FRegister>(frd + 1));
} else {
- mtc1(ZR, static_cast<FRegister>(rd + 1));
+ mtc1(ZR, static_cast<FRegister>(frd + 1));
}
}
@@ -853,8 +865,13 @@
}
void BranchSignedGreaterEqual(Register rd, int32_t value, Label* l) {
- LoadImmediate(CMPRES, value);
- BranchSignedGreaterEqual(rd, CMPRES, l);
+ if (Utils::IsInt(kImmBits, value)) {
+ slti(CMPRES, rd, Immediate(value));
+ beq(CMPRES, ZR, l);
+ } else {
+ LoadImmediate(CMPRES, value);
+ BranchSignedGreaterEqual(rd, CMPRES, l);
+ }
}
void BranchUnsignedGreaterEqual(Register rd, Register rs, Label* l) {
@@ -863,8 +880,13 @@
}
void BranchUnsignedGreaterEqual(Register rd, int32_t value, Label* l) {
- LoadImmediate(CMPRES, value);
- BranchUnsignedGreaterEqual(rd, CMPRES, l);
+ if (Utils::IsUint(kImmBits, value)) {
+ sltiu(CMPRES, rd, Immediate(value));
+ beq(CMPRES, ZR, l);
+ } else {
+ LoadImmediate(CMPRES, value);
+ BranchUnsignedGreaterEqual(rd, CMPRES, l);
+ }
}
void BranchSignedLess(Register rd, Register rs, Label* l) {
@@ -872,8 +894,13 @@
}
void BranchSignedLess(Register rd, int32_t value, Label* l) {
- LoadImmediate(CMPRES, value);
- BranchSignedGreater(CMPRES, rd, l);
+ if (Utils::IsInt(kImmBits, value)) {
+ slti(CMPRES, rd, Immediate(value));
+ bne(CMPRES, ZR, l);
+ } else {
+ LoadImmediate(CMPRES, value);
+ BranchSignedGreater(CMPRES, rd, l);
+ }
}
void BranchUnsignedLess(Register rd, Register rs, Label* l) {
@@ -881,8 +908,13 @@
}
void BranchUnsignedLess(Register rd, int32_t value, Label* l) {
- LoadImmediate(CMPRES, value);
- BranchUnsignedGreater(CMPRES, rd, l);
+ if (Utils::IsUint(kImmBits, value)) {
+ sltiu(CMPRES, rd, Immediate(value));
+ bne(CMPRES, ZR, l);
+ } else {
+ LoadImmediate(CMPRES, value);
+ BranchUnsignedGreater(CMPRES, rd, l);
+ }
}
void BranchSignedLessEqual(Register rd, Register rs, Label* l) {
@@ -937,9 +969,11 @@
void LoadObject(Register rd, const Object& object);
void PushObject(const Object& object);
- // Sets register rd to zero if the object is equal to register rn,
- // sets it to non-zero otherwise.
- void CompareObject(Register rd, Register rn, const Object& object);
+ // Compares rn with the object. Returns results in rd1 and rd2.
+ // rd1 is 1 if rn < object. rd2 is 1 if object < rn. Since both cannot be
+ // 1, rd1 == rd2 (== 0) iff rn == object.
+ void CompareObject(Register rd1, Register rd2,
+ Register rn, const Object& object);
void LoadClassId(Register result, Register object);
void LoadClassById(Register result, Register class_id);
@@ -993,10 +1027,6 @@
GrowableArray<CodeComment*> comments_;
- bool EvenFPURegister(FRegister reg) {
- return (static_cast<int>(reg) & 1) == 0;
- }
-
void Emit(int32_t value) {
// Emitting an instruction clears the delay slot state.
in_delay_slot_ = false;
diff --git a/runtime/vm/assembler_mips_test.cc b/runtime/vm/assembler_mips_test.cc
index 1dc7d33..445ab8e 100644
--- a/runtime/vm/assembler_mips_test.cc
+++ b/runtime/vm/assembler_mips_test.cc
@@ -1186,9 +1186,9 @@
ASSEMBLER_TEST_GENERATE(Addd, assembler) {
- __ LoadImmediate(F0, 1.0);
- __ LoadImmediate(F2, 2.0);
- __ addd(F4, F0, F2);
+ __ LoadImmediate(D0, 1.0);
+ __ LoadImmediate(D1, 2.0);
+ __ addd(D2, D0, D1);
__ mfc1(V0, F4);
__ mfc1(V1, F5);
__ Ret();
@@ -1204,8 +1204,8 @@
ASSEMBLER_TEST_GENERATE(Movd, assembler) {
- __ LoadImmediate(F0, 1.0);
- __ movd(F2, F0);
+ __ LoadImmediate(D0, 1.0);
+ __ movd(D1, D0);
__ mfc1(V0, F2);
__ mfc1(V1, F3);
__ Ret();
@@ -1224,9 +1224,9 @@
__ AddImmediate(SP, -8 * kWordSize);
__ LoadImmediate(T1, ~(8 - 1));
__ and_(T0, SP, T1); // Need 8 byte alignment.
- __ LoadImmediate(F0, 1.0);
- __ sdc1(F0, Address(T0));
- __ ldc1(F2, Address(T0));
+ __ LoadImmediate(D0, 1.0);
+ __ sdc1(D0, Address(T0));
+ __ ldc1(D1, Address(T0));
__ mfc1(V0, F2);
__ mfc1(V1, F3);
__ Ret();
@@ -1242,12 +1242,12 @@
ASSEMBLER_TEST_GENERATE(Addd_NaN, assembler) {
- __ LoadImmediate(F0, 1.0);
+ __ LoadImmediate(D0, 1.0);
// Double non-signaling NaN is 0x7FF8000000000000.
__ LoadImmediate(T0, 0x7FF80000);
__ mtc1(ZR, F2); // Load upper bits of NaN.
__ mtc1(T0, F3); // Load lower bits of NaN.
- __ addd(F4, F0, F2);
+ __ addd(D2, D0, D1);
__ mfc1(V0, F4);
__ mfc1(V1, F5);
__ Ret();
@@ -1263,11 +1263,11 @@
ASSEMBLER_TEST_GENERATE(Addd_Inf, assembler) {
- __ LoadImmediate(F0, 1.0f);
+ __ LoadImmediate(D0, 1.0);
__ LoadImmediate(T0, 0x7FF00000); // +inf
__ mtc1(ZR, F2);
__ mtc1(T0, F3);
- __ addd(F4, F0, F2);
+ __ addd(D2, D0, D1);
__ mfc1(V0, F4);
__ mfc1(V1, F5);
__ Ret();
@@ -1283,9 +1283,9 @@
ASSEMBLER_TEST_GENERATE(Subd, assembler) {
- __ LoadImmediate(F0, 2.5);
- __ LoadImmediate(F2, 1.5);
- __ subd(F4, F0, F2);
+ __ LoadImmediate(D0, 2.5);
+ __ LoadImmediate(D1, 1.5);
+ __ subd(D2, D0, D1);
__ mfc1(V0, F4);
__ mfc1(V1, F5);
__ Ret();
@@ -1301,9 +1301,9 @@
ASSEMBLER_TEST_GENERATE(Muld, assembler) {
- __ LoadImmediate(F0, 6.0);
- __ LoadImmediate(F2, 7.0);
- __ muld(F4, F0, F2);
+ __ LoadImmediate(D0, 6.0);
+ __ LoadImmediate(D1, 7.0);
+ __ muld(D2, D0, D1);
__ mfc1(V0, F4);
__ mfc1(V1, F5);
__ Ret();
@@ -1319,9 +1319,9 @@
ASSEMBLER_TEST_GENERATE(Divd, assembler) {
- __ LoadImmediate(F0, 42.0);
- __ LoadImmediate(F2, 7.0);
- __ divd(F4, F0, F2);
+ __ LoadImmediate(D0, 42.0);
+ __ LoadImmediate(D1, 7.0);
+ __ divd(D2, D0, D1);
__ mfc1(V0, F4);
__ mfc1(V1, F5);
__ Ret();
@@ -1337,8 +1337,8 @@
ASSEMBLER_TEST_GENERATE(Sqrtd, assembler) {
- __ LoadImmediate(F0, 36.0);
- __ sqrtd(F4, F0);
+ __ LoadImmediate(D0, 36.0);
+ __ sqrtd(D2, D0);
__ mfc1(V0, F4);
__ mfc1(V1, F5);
__ Ret();
@@ -1356,12 +1356,12 @@
ASSEMBLER_TEST_GENERATE(Cop1CUN, assembler) {
Label is_true;
- __ LoadImmediate(F0, 42.0);
+ __ LoadImmediate(D0, 42.0);
__ LoadImmediate(T0, 0x7FF80000);
__ mtc1(ZR, F2);
__ mtc1(T0, F3);
__ LoadImmediate(V0, 42);
- __ cund(F0, F2);
+ __ cund(D0, D1);
__ bc1t(&is_true);
__ mov(V0, ZR);
__ Bind(&is_true);
@@ -1378,10 +1378,10 @@
ASSEMBLER_TEST_GENERATE(Cop1CUN_not_taken, assembler) {
Label is_true;
- __ LoadImmediate(F0, 42.0);
- __ LoadImmediate(F2, 42.0);
+ __ LoadImmediate(D0, 42.0);
+ __ LoadImmediate(D1, 42.0);
__ LoadImmediate(V0, 42);
- __ cund(F0, F2);
+ __ cund(D0, D1);
__ bc1t(&is_true);
__ mov(V0, ZR);
__ Bind(&is_true);
@@ -1398,10 +1398,10 @@
ASSEMBLER_TEST_GENERATE(Cop1CEq, assembler) {
Label is_true;
- __ LoadImmediate(F0, 42.5);
- __ LoadImmediate(F2, 42.5);
+ __ LoadImmediate(D0, 42.5);
+ __ LoadImmediate(D1, 42.5);
__ LoadImmediate(V0, 42);
- __ ceqd(F0, F2);
+ __ ceqd(D0, D1);
__ bc1t(&is_true);
__ mov(V0, ZR);
__ Bind(&is_true);
@@ -1418,10 +1418,10 @@
ASSEMBLER_TEST_GENERATE(Cop1CEq_not_taken, assembler) {
Label is_true;
- __ LoadImmediate(F0, 42.0);
- __ LoadImmediate(F2, 42.5);
+ __ LoadImmediate(D0, 42.0);
+ __ LoadImmediate(D1, 42.5);
__ LoadImmediate(V0, 42);
- __ ceqd(F0, F2);
+ __ ceqd(D0, D1);
__ bc1t(&is_true);
__ mov(V0, ZR);
__ Bind(&is_true);
@@ -1438,10 +1438,10 @@
ASSEMBLER_TEST_GENERATE(Cop1CEq_false, assembler) {
Label is_true;
- __ LoadImmediate(F0, 42.0);
- __ LoadImmediate(F2, 42.5);
+ __ LoadImmediate(D0, 42.0);
+ __ LoadImmediate(D1, 42.5);
__ LoadImmediate(V0, 42);
- __ ceqd(F0, F2);
+ __ ceqd(D0, D1);
__ bc1f(&is_true);
__ mov(V0, ZR);
__ Bind(&is_true);
@@ -1458,10 +1458,10 @@
ASSEMBLER_TEST_GENERATE(Cop1CEq_false_not_taken, assembler) {
Label is_true;
- __ LoadImmediate(F0, 42.5);
- __ LoadImmediate(F2, 42.5);
+ __ LoadImmediate(D0, 42.5);
+ __ LoadImmediate(D1, 42.5);
__ LoadImmediate(V0, 42);
- __ ceqd(F0, F2);
+ __ ceqd(D0, D1);
__ bc1f(&is_true);
__ mov(V0, ZR);
__ Bind(&is_true);
@@ -1478,10 +1478,10 @@
ASSEMBLER_TEST_GENERATE(Cop1COLT, assembler) {
Label is_true;
- __ LoadImmediate(F0, 42.0);
- __ LoadImmediate(F2, 42.5);
+ __ LoadImmediate(D0, 42.0);
+ __ LoadImmediate(D1, 42.5);
__ LoadImmediate(V0, 42);
- __ coltd(F0, F2);
+ __ coltd(D0, D1);
__ bc1t(&is_true);
__ mov(V0, ZR);
__ Bind(&is_true);
@@ -1498,10 +1498,10 @@
ASSEMBLER_TEST_GENERATE(Cop1COLT_not_taken, assembler) {
Label is_true;
- __ LoadImmediate(F0, 42.5);
- __ LoadImmediate(F2, 42.0);
+ __ LoadImmediate(D0, 42.5);
+ __ LoadImmediate(D1, 42.0);
__ LoadImmediate(V0, 42);
- __ coltd(F0, F2);
+ __ coltd(D0, D1);
__ bc1t(&is_true);
__ mov(V0, ZR);
__ Bind(&is_true);
@@ -1518,10 +1518,10 @@
ASSEMBLER_TEST_GENERATE(Cop1COLE, assembler) {
Label is_true;
- __ LoadImmediate(F0, 42.0);
- __ LoadImmediate(F2, 42.0);
+ __ LoadImmediate(D0, 42.0);
+ __ LoadImmediate(D1, 42.0);
__ LoadImmediate(V0, 42);
- __ coled(F0, F2);
+ __ coled(D0, D1);
__ bc1t(&is_true);
__ mov(V0, ZR);
__ Bind(&is_true);
@@ -1538,10 +1538,10 @@
ASSEMBLER_TEST_GENERATE(Cop1COLE_not_taken, assembler) {
Label is_true;
- __ LoadImmediate(F0, 42.5);
- __ LoadImmediate(F2, 42.0);
+ __ LoadImmediate(D0, 42.5);
+ __ LoadImmediate(D1, 42.0);
__ LoadImmediate(V0, 42);
- __ coled(F0, F2);
+ __ coled(D0, D1);
__ bc1t(&is_true);
__ mov(V0, ZR);
__ Bind(&is_true);
@@ -1558,7 +1558,7 @@
ASSEMBLER_TEST_GENERATE(Cop1CvtDW, assembler) {
__ LoadImmediate(T0, 42);
__ mtc1(T0, F0);
- __ cvtdw(F2, F0);
+ __ cvtdw(D1, F0);
__ mfc1(V0, F2);
__ mfc1(V1, F3);
__ Ret();
@@ -1576,7 +1576,7 @@
ASSEMBLER_TEST_GENERATE(Cop1CvtDW_neg, assembler) {
__ LoadImmediate(T0, -42);
__ mtc1(T0, F0);
- __ cvtdw(F2, F0);
+ __ cvtdw(D1, F0);
__ mfc1(V0, F2);
__ mfc1(V1, F3);
__ Ret();
@@ -1595,7 +1595,7 @@
__ LoadImmediate(T0, 0x1);
__ mtc1(ZR, F0);
__ mtc1(T0, F1); // D0 <- 0x100000000 = 4294967296
- __ cvtdl(F2, F0);
+ __ cvtdl(D1, D0);
__ mfc1(V0, F2);
__ mfc1(V1, F3);
__ Ret();
@@ -1614,7 +1614,7 @@
__ LoadImmediate(T0, 0xffffffff);
__ mtc1(T0, F0);
__ mtc1(T0, F1); // D0 <- 0xffffffffffffffff = -1
- __ cvtdl(F2, F0);
+ __ cvtdl(D1, D0);
__ mfc1(V0, F2);
__ mfc1(V1, F3);
__ Ret();
@@ -1630,8 +1630,8 @@
ASSEMBLER_TEST_GENERATE(Cop1CvtWD, assembler) {
- __ LoadImmediate(F0, 42.0);
- __ cvtwd(F2, F0);
+ __ LoadImmediate(D0, 42.0);
+ __ cvtwd(F2, D0);
__ mfc1(V0, F2);
__ Ret();
}
@@ -1645,8 +1645,8 @@
ASSEMBLER_TEST_GENERATE(Cop1CvtWD_neg, assembler) {
- __ LoadImmediate(F0, -42.0);
- __ cvtwd(F2, F0);
+ __ LoadImmediate(D0, -42.0);
+ __ cvtwd(F2, D0);
__ mfc1(V0, F2);
__ Ret();
}
diff --git a/runtime/vm/ast.cc b/runtime/vm/ast.cc
index 4ac570b..7f88189 100644
--- a/runtime/vm/ast.cc
+++ b/runtime/vm/ast.cc
@@ -329,9 +329,6 @@
if (local().is_final()) {
return NULL;
}
- if (HasPseudo()) {
- return NULL;
- }
return new StoreLocalNode(token_pos(), &local(), rhs);
}
diff --git a/runtime/vm/ast.h b/runtime/vm/ast.h
index 07e2314..c65f991 100644
--- a/runtime/vm/ast.h
+++ b/runtime/vm/ast.h
@@ -55,6 +55,7 @@
V(LoadIndexedNode, "load indexed") \
V(StoreIndexedNode, "store indexed") \
V(SequenceNode, "seq") \
+ V(CommaNode, "comma") \
V(CatchClauseNode, "catch clause block") \
V(TryCatchNode, "try catch block") \
V(ThrowNode, "throw") \
@@ -180,6 +181,35 @@
};
+// Comma node represents a pair of expressions evaluated in sequence
+// and return the value of the second expression.
+class CommaNode : public AstNode {
+ public:
+ CommaNode(intptr_t token_pos,
+ AstNode* first,
+ AstNode* second)
+ : AstNode(token_pos),
+ first_(first),
+ second_(second) { }
+
+ AstNode* first() const { return first_; }
+ AstNode* second() const { return second_; }
+
+ void VisitChildren(AstNodeVisitor* visitor) const {
+ first_->Visit(visitor);
+ second_->Visit(visitor);
+ }
+
+ DECLARE_COMMON_NODE_FUNCTIONS(CommaNode);
+
+ private:
+ AstNode* first_;
+ AstNode* second_;
+
+ DISALLOW_COPY_AND_ASSIGN(CommaNode);
+};
+
+
class CloneContextNode : public AstNode {
public:
explicit CloneContextNode(intptr_t token_pos)
@@ -962,29 +992,13 @@
class LoadLocalNode : public AstNode {
public:
LoadLocalNode(intptr_t token_pos, const LocalVariable* local)
- : AstNode(token_pos), local_(*local), pseudo_(NULL) {
- ASSERT(local != NULL);
- }
-
- // A local variable load can optionally be a pair of an arbitrary 'pseudo'
- // AST node followed by the load. The pseudo node is evaluated for its
- // side-effects and the value of the expression is the value of the local
- // load after evaluating the pseudo node. Pseudo nodes are used, e.g., in
- // the desugaring of postincrement and cascade expressions.
- LoadLocalNode(intptr_t token_pos, const LocalVariable* local, AstNode* pseudo)
- : AstNode(token_pos), local_(*local), pseudo_(pseudo) {
+ : AstNode(token_pos), local_(*local) {
ASSERT(local != NULL);
}
const LocalVariable& local() const { return local_; }
- AstNode* pseudo() const { return pseudo_; } // Can be NULL.
- bool HasPseudo() const { return pseudo_ != NULL; }
- virtual void VisitChildren(AstNodeVisitor* visitor) const {
- if (HasPseudo()) {
- pseudo()->Visit(visitor);
- }
- }
+ virtual void VisitChildren(AstNodeVisitor* visitor) const { }
virtual const Instance* EvalConstExpr() const;
virtual AstNode* MakeAssignmentNode(AstNode* rhs);
@@ -993,7 +1007,6 @@
private:
const LocalVariable& local_;
- AstNode* pseudo_;
DISALLOW_IMPLICIT_CONSTRUCTORS(LoadLocalNode);
};
diff --git a/runtime/vm/ast_printer.cc b/runtime/vm/ast_printer.cc
index 0224c25..32bd0af8 100644
--- a/runtime/vm/ast_printer.cc
+++ b/runtime/vm/ast_printer.cc
@@ -38,6 +38,11 @@
}
+void AstPrinter::VisitCommaNode(CommaNode* node) {
+ VisitGenericAstNode(node);
+}
+
+
void AstPrinter::VisitCloneContextNode(CloneContextNode* node) {
VisitGenericAstNode(node);
}
diff --git a/runtime/vm/benchmark_test.cc b/runtime/vm/benchmark_test.cc
index 2b19ef5..3badf77 100644
--- a/runtime/vm/benchmark_test.cc
+++ b/runtime/vm/benchmark_test.cc
@@ -434,10 +434,8 @@
"import 'dart:isolate';\n"
"import 'dart:mirrors';\n"
"import 'dart:typed_data';\n"
- "import 'dart:uri';\n"
"import 'dart:utf';\n"
"import 'dart:json';\n"
- "import 'dart:crypto';\n"
"import 'dart:builtin';\n"
"import 'dart:io';\n"
"\n";
diff --git a/runtime/vm/bootstrap.cc b/runtime/vm/bootstrap.cc
index bdc5054..e174416 100644
--- a/runtime/vm/bootstrap.cc
+++ b/runtime/vm/bootstrap.cc
@@ -46,10 +46,6 @@
_collection-dev,
Bootstrap::collection_dev_source_paths_,
Bootstrap::collection_dev_patch_paths_),
- INIT_LIBRARY(ObjectStore::kCrypto,
- crypto,
- Bootstrap::crypto_source_paths_,
- NULL),
INIT_LIBRARY(ObjectStore::kIsolate,
isolate,
Bootstrap::isolate_source_paths_,
@@ -74,10 +70,6 @@
utf,
Bootstrap::utf_source_paths_,
NULL),
- INIT_LIBRARY(ObjectStore::kUri,
- uri,
- Bootstrap::uri_source_paths_,
- NULL),
{ ObjectStore::kNone, NULL, NULL, NULL, NULL }
};
diff --git a/runtime/vm/bootstrap.h b/runtime/vm/bootstrap.h
index d873541..843cf72 100644
--- a/runtime/vm/bootstrap.h
+++ b/runtime/vm/bootstrap.h
@@ -22,13 +22,11 @@
static const char* corelib_source_paths_[];
static const char* collection_source_paths_[];
static const char* collection_dev_source_paths_[];
- static const char* crypto_source_paths_[];
static const char* isolate_source_paths_[];
static const char* json_source_paths_[];
static const char* math_source_paths_[];
static const char* mirrors_source_paths_[];
static const char* typed_data_source_paths_[];
- static const char* uri_source_paths_[];
static const char* utf_source_paths_[];
// Source path mapping for patch URI and 'parts'.
diff --git a/runtime/vm/code_generator.cc b/runtime/vm/code_generator.cc
index ffc41a1..86ca5af 100644
--- a/runtime/vm/code_generator.cc
+++ b/runtime/vm/code_generator.cc
@@ -38,16 +38,8 @@
"Trace IC miss in optimized code");
DEFINE_FLAG(bool, trace_patching, false, "Trace patching of code.");
DEFINE_FLAG(bool, trace_runtime_calls, false, "Trace runtime calls");
-#if defined(TARGET_ARCH_IA32) || \
- defined(TARGET_ARCH_X64) || \
- defined(TARGET_ARCH_ARM)
DEFINE_FLAG(int, optimization_counter_threshold, 3000,
"Function's usage-counter value before it is optimized, -1 means never");
-#else
-// TODO(regis): Enable optimization on MIPS.
-DEFINE_FLAG(int, optimization_counter_threshold, -1,
- "Function's usage-counter value before it is optimized, -1 means never");
-#endif
DECLARE_FLAG(bool, enable_type_checks);
DECLARE_FLAG(bool, trace_type_checks);
DECLARE_FLAG(bool, report_usage_count);
@@ -1548,7 +1540,7 @@
ASSERT(!deopt_info.IsNull());
CopyFrame(optimized_code, *caller_frame);
- if (FLAG_trace_deoptimization) {
+ if (FLAG_trace_deoptimization || FLAG_trace_deoptimization_verbose) {
Function& function = Function::Handle(optimized_code.function());
OS::PrintErr(
"Deoptimizing (reason %"Pd" '%s') at pc %#"Px" '%s' (count %d)\n",
@@ -1714,7 +1706,7 @@
// Since this is the only step where GC can occur during deoptimization,
// use it to report the source line where deoptimization occured.
- if (FLAG_trace_deoptimization) {
+ if (FLAG_trace_deoptimization || FLAG_trace_deoptimization_verbose) {
DartFrameIterator iterator;
StackFrame* top_frame = iterator.NextFrame();
ASSERT(top_frame != NULL);
diff --git a/runtime/vm/compiler.cc b/runtime/vm/compiler.cc
index 9785e38..c9b16a7 100644
--- a/runtime/vm/compiler.cc
+++ b/runtime/vm/compiler.cc
@@ -499,11 +499,7 @@
}
// If not yet present, allocate deoptimization history array.
- Array& deopt_history = Array::Handle(function.deopt_history());
- if (deopt_history.IsNull()) {
- deopt_history = Array::New(FLAG_deoptimization_counter_threshold);
- function.set_deopt_history(deopt_history);
- }
+ function.EnsureDeoptHistory();
for (intptr_t i = 0; i < guarded_fields.length(); i++) {
const Field& field = *guarded_fields[i];
diff --git a/runtime/vm/constants_mips.h b/runtime/vm/constants_mips.h
index 32f608b..64a92c3 100644
--- a/runtime/vm/constants_mips.h
+++ b/runtime/vm/constants_mips.h
@@ -129,12 +129,38 @@
kNoFRegister = -1,
};
+// The double precision floating point registers are concatenated pairs of the
+// single precision registers, e.g. D0 is F1:F0, D1 is F3:F2, etc.. We only
+// tell the architecture generic code about the double precision registers, then
+// convert to the single precision registers when needed in the mips-specific
+// code.
+enum DRegister {
+ D0 = 0,
+ D1 = 1,
+ D2 = 2,
+ D3 = 3,
+ D4 = 4,
+ D5 = 5,
+ D6 = 6,
+ D7 = 7,
+ D8 = 8,
+ D9 = 9,
+ D10 = 10,
+ D11 = 11,
+ D12 = 12,
+ D13 = 13,
+ D14 = 14,
+ D15 = 15,
+ D16 = 16,
+ kNumberOfDRegisters = 16,
+ kNoDRegister = -1,
+};
// Architecture independent aliases.
-typedef FRegister FpuRegister;
-const FpuRegister FpuTMP = F0;
-const int kNumberOfFpuRegisters = kNumberOfFRegisters;
-const FpuRegister kNoFpuRegister = kNoFRegister;
+typedef DRegister FpuRegister;
+const FpuRegister FpuTMP = D0;
+const int kNumberOfFpuRegisters = kNumberOfDRegisters;
+const FpuRegister kNoFpuRegister = kNoDRegister;
// Register aliases.
diff --git a/runtime/vm/deopt_instructions.cc b/runtime/vm/deopt_instructions.cc
index 9c9dd24..8b37613 100644
--- a/runtime/vm/deopt_instructions.cc
+++ b/runtime/vm/deopt_instructions.cc
@@ -73,7 +73,8 @@
// Deoptimization instruction moving value from optimized frame at
// 'from_index' to specified slots in the unoptimized frame.
// 'from_index' represents the slot index of the frame (0 being first argument)
-// and accounts for saved return address, frame pointer and pc marker.
+// and accounts for saved return address, frame pointer, pool pointer and pc
+// marker.
class DeoptStackSlotInstr : public DeoptInstr {
public:
explicit DeoptStackSlotInstr(intptr_t from_index)
@@ -515,7 +516,7 @@
// Increment the deoptimization counter. This effectively increments each
// function occurring in the optimized frame.
function.set_deoptimization_counter(function.deoptimization_counter() + 1);
- if (FLAG_trace_deoptimization) {
+ if (FLAG_trace_deoptimization || FLAG_trace_deoptimization_verbose) {
OS::PrintErr("Deoptimizing %s (count %d)\n",
function.ToFullyQualifiedCString(),
function.deoptimization_counter());
@@ -863,7 +864,7 @@
intptr_t DeoptInfoBuilder::CalculateStackIndex(const Location& from_loc) const {
return from_loc.stack_index() < 0 ?
from_loc.stack_index() + num_args_ :
- from_loc.stack_index() + num_args_ - kFirstLocalSlotFromFp + 1;
+ from_loc.stack_index() + num_args_ + kDartFrameFixedSize;
}
diff --git a/runtime/vm/disassembler_arm.cc b/runtime/vm/disassembler_arm.cc
index 8a7b5ea..dc1258e 100644
--- a/runtime/vm/disassembler_arm.cc
+++ b/runtime/vm/disassembler_arm.cc
@@ -643,6 +643,11 @@
Format(instr, "smull'cond's 'rd, 'rn, 'rm, 'rs");
break;
}
+ case 7: {
+ // Registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs.
+ Format(instr, "smlal'cond's 'rd, 'rn, 'rm, 'rs");
+ break;
+ }
default: {
Unknown(instr); // Not used.
break;
diff --git a/runtime/vm/disassembler_mips.cc b/runtime/vm/disassembler_mips.cc
index 8c672b3..f6d7051 100644
--- a/runtime/vm/disassembler_mips.cc
+++ b/runtime/vm/disassembler_mips.cc
@@ -685,6 +685,14 @@
Format(instr, "sb 'rt, 'imms('rs)");
break;
}
+ case SLTI: {
+ Format(instr, "slti 'rt, 'rs, 'imms");
+ break;
+ }
+ case SLTIU: {
+ Format(instr, "sltu 'rt, 'rs, 'immu");
+ break;
+ }
case SH: {
Format(instr, "sh 'rt, 'imms('rs)");
break;
diff --git a/runtime/vm/flow_graph_builder.cc b/runtime/vm/flow_graph_builder.cc
index f0343db..0773a4f 100644
--- a/runtime/vm/flow_graph_builder.cc
+++ b/runtime/vm/flow_graph_builder.cc
@@ -2299,10 +2299,16 @@
owner()->parsed_function().function().Owner());
Value* instantiator_value =
BuildInstantiatorTypeArguments(token_pos, instantiator_class, NULL);
- return Bind(new InstantiateTypeArgumentsInstr(token_pos,
- type_arguments,
- instantiator_class,
- instantiator_value));
+ const bool use_instantiator_type_args =
+ type_arguments.IsUninstantiatedIdentity() ||
+ type_arguments.CanShareInstantiatorTypeArguments(
+ instantiator_class);
+ return use_instantiator_type_args
+ ? instantiator_value
+ : Bind(new InstantiateTypeArgumentsInstr(token_pos,
+ type_arguments,
+ instantiator_class,
+ instantiator_value));
}
@@ -2641,16 +2647,11 @@
// <Expression> ::= LoadLocal { local: LocalVariable }
void EffectGraphVisitor::VisitLoadLocalNode(LoadLocalNode* node) {
- if (node->HasPseudo()) {
- EffectGraphVisitor for_pseudo(owner(), temp_index());
- node->pseudo()->Visit(&for_pseudo);
- Append(for_pseudo);
- }
+ // Nothing to do.
}
void ValueGraphVisitor::VisitLoadLocalNode(LoadLocalNode* node) {
- EffectGraphVisitor::VisitLoadLocalNode(node);
Definition* load = BuildLoadLocal(node->local());
ReturnDefinition(load);
}
@@ -3141,6 +3142,29 @@
}
+void EffectGraphVisitor::VisitCommaNode(CommaNode* node) {
+ EffectGraphVisitor for_effect_first(owner(), temp_index());
+ node->first()->Visit(&for_effect_first);
+ Append(for_effect_first);
+
+ EffectGraphVisitor for_effect_second(owner(), temp_index());
+ node->second()->Visit(&for_effect_second);
+ Append(for_effect_second);
+}
+
+
+void ValueGraphVisitor::VisitCommaNode(CommaNode* node) {
+ EffectGraphVisitor for_effect(owner(), temp_index());
+ node->first()->Visit(&for_effect);
+ Append(for_effect);
+
+ ValueGraphVisitor for_value(owner(), temp_index());
+ node->second()->Visit(&for_value);
+ Append(for_value);
+ ReturnValue(for_value.value());
+}
+
+
void EffectGraphVisitor::VisitTryCatchNode(TryCatchNode* node) {
InlineBailout("EffectGraphVisitor::VisitTryCatchNode (exception)");
intptr_t old_try_index = owner()->try_index();
diff --git a/runtime/vm/flow_graph_builder.h b/runtime/vm/flow_graph_builder.h
index 59a752d..9f613eb 100644
--- a/runtime/vm/flow_graph_builder.h
+++ b/runtime/vm/flow_graph_builder.h
@@ -400,6 +400,7 @@
virtual void VisitStaticSetterNode(StaticSetterNode* node);
virtual void VisitStoreStaticFieldNode(StoreStaticFieldNode* node);
virtual void VisitTypeNode(TypeNode* node);
+ virtual void VisitCommaNode(CommaNode* node);
Value* value() const { return value_; }
diff --git a/runtime/vm/flow_graph_compiler.h b/runtime/vm/flow_graph_compiler.h
index a5672d4..6dbcaa4 100644
--- a/runtime/vm/flow_graph_compiler.h
+++ b/runtime/vm/flow_graph_compiler.h
@@ -442,10 +442,6 @@
bool may_reoptimize() const { return may_reoptimize_; }
- static Condition FlipCondition(Condition condition);
-
- static bool EvaluateCondition(Condition condition, intptr_t l, intptr_t r);
-
// Array/list element address computations.
static intptr_t DataOffsetFor(intptr_t cid);
static intptr_t ElementSizeFor(intptr_t cid);
diff --git a/runtime/vm/flow_graph_compiler_arm.cc b/runtime/vm/flow_graph_compiler_arm.cc
index 686c7e0..c4317a9 100644
--- a/runtime/vm/flow_graph_compiler_arm.cc
+++ b/runtime/vm/flow_graph_compiler_arm.cc
@@ -708,12 +708,8 @@
AddCurrentDescriptor(PcDescriptors::kDeopt,
assert->deopt_id(),
assert->token_pos());
- } else if (instr->IsGuardField()) {
- GuardFieldInstr* guard = instr->AsGuardField();
- AddCurrentDescriptor(PcDescriptors::kDeopt,
- guard->deopt_id(),
- Scanner::kDummyTokenIndex);
- } else if (instr->CanBeDeoptimizationTarget()) {
+ } else if (instr->IsGuardField() ||
+ instr->CanBecomeDeoptimizationTarget()) {
AddCurrentDescriptor(PcDescriptors::kDeopt,
instr->deopt_id(),
Scanner::kDummyTokenIndex);
@@ -1290,7 +1286,65 @@
intptr_t deopt_id,
intptr_t token_pos,
LocationSummary* locs) {
- UNIMPLEMENTED();
+ MegamorphicCacheTable* table = Isolate::Current()->megamorphic_cache_table();
+ const String& name = String::Handle(ic_data.target_name());
+ const MegamorphicCache& cache =
+ MegamorphicCache::ZoneHandle(table->Lookup(name, arguments_descriptor));
+ Label not_smi, load_cache;
+ __ LoadFromOffset(kLoadWord, R0, SP, (argument_count - 1) * kWordSize);
+ __ tst(R0, ShifterOperand(kSmiTagMask));
+ __ b(¬_smi, NE);
+ __ mov(R0, ShifterOperand(Smi::RawValue(kSmiCid)));
+ __ b(&load_cache);
+
+ __ Bind(¬_smi);
+ __ LoadClassId(R0, R0);
+ __ SmiTag(R0);
+
+ // R0: class ID of the receiver (smi).
+ __ Bind(&load_cache);
+ __ LoadObject(R1, cache);
+ __ ldr(R2, FieldAddress(R1, MegamorphicCache::buckets_offset()));
+ __ ldr(R1, FieldAddress(R1, MegamorphicCache::mask_offset()));
+ // R2: cache buckets array.
+ // R1: mask.
+ __ mov(R3, ShifterOperand(R0));
+
+ Label loop, update, call_target_function;
+ __ b(&loop);
+
+ __ Bind(&update);
+ __ add(R3, R3, ShifterOperand(Smi::RawValue(1)));
+ __ Bind(&loop);
+ __ and_(R3, R3, ShifterOperand(R1));
+ const intptr_t base = Array::data_offset();
+ // R3 is smi tagged, but table entries are two words, so LSL 2.
+ __ add(IP, R2, ShifterOperand(R3, LSL, 2));
+ __ ldr(R4, FieldAddress(IP, base));
+
+ ASSERT(kIllegalCid == 0);
+ __ tst(R4, ShifterOperand(R4));
+ __ b(&call_target_function, EQ);
+ __ cmp(R4, ShifterOperand(R0));
+ __ b(&update, NE);
+
+ __ Bind(&call_target_function);
+ // Call the target found in the cache. For a class id match, this is a
+ // proper target for the given name and arguments descriptor. If the
+ // illegal class id was found, the target is a cache miss handler that can
+ // be invoked as a normal Dart function.
+ __ add(IP, R2, ShifterOperand(R3, LSL, 2));
+ __ ldr(R0, FieldAddress(IP, base + kWordSize));
+ __ ldr(R0, FieldAddress(R0, Function::code_offset()));
+ __ ldr(R0, FieldAddress(R0, Code::instructions_offset()));
+ __ LoadObject(R5, ic_data);
+ __ LoadObject(R4, arguments_descriptor);
+ __ AddImmediate(R0, Instructions::HeaderSize() - kHeapObjectTag);
+ __ blx(R0);
+ AddCurrentDescriptor(PcDescriptors::kOther, Isolate::kNoDeoptId, token_pos);
+ RecordSafepoint(locs);
+ AddDeoptIndexAtCall(Isolate::ToDeoptAfter(deopt_id), token_pos);
+ __ Drop(argument_count);
}
@@ -1456,29 +1510,17 @@
}
-Condition FlowGraphCompiler::FlipCondition(Condition condition) {
- UNIMPLEMENTED();
- return condition;
-}
-
-
-bool FlowGraphCompiler::EvaluateCondition(Condition condition,
- intptr_t left,
- intptr_t right) {
- UNIMPLEMENTED();
- return false;
-}
-
-
+// Do not impelement or use this function.
FieldAddress FlowGraphCompiler::ElementAddressForIntIndex(intptr_t cid,
intptr_t index_scale,
Register array,
intptr_t index) {
- UNIMPLEMENTED();
+ UNREACHABLE();
return FieldAddress(array, index);
}
+// Do not implement or use this function.
FieldAddress FlowGraphCompiler::ElementAddressForRegIndex(intptr_t cid,
intptr_t index_scale,
Register array,
diff --git a/runtime/vm/flow_graph_compiler_ia32.cc b/runtime/vm/flow_graph_compiler_ia32.cc
index 593b42d..a42ed3b 100644
--- a/runtime/vm/flow_graph_compiler_ia32.cc
+++ b/runtime/vm/flow_graph_compiler_ia32.cc
@@ -727,12 +727,8 @@
AddCurrentDescriptor(PcDescriptors::kDeopt,
assert->deopt_id(),
assert->token_pos());
- } else if (instr->IsGuardField()) {
- GuardFieldInstr* guard = instr->AsGuardField();
- AddCurrentDescriptor(PcDescriptors::kDeopt,
- guard->deopt_id(),
- Scanner::kDummyTokenIndex);
- } else if (instr->CanBeDeoptimizationTarget()) {
+ } else if (instr->IsGuardField() ||
+ instr->CanBecomeDeoptimizationTarget()) {
AddCurrentDescriptor(PcDescriptors::kDeopt,
instr->deopt_id(),
Scanner::kDummyTokenIndex);
@@ -1653,48 +1649,6 @@
}
-Condition FlowGraphCompiler::FlipCondition(Condition condition) {
- switch (condition) {
- case EQUAL: return EQUAL;
- case NOT_EQUAL: return NOT_EQUAL;
- case LESS: return GREATER;
- case LESS_EQUAL: return GREATER_EQUAL;
- case GREATER: return LESS;
- case GREATER_EQUAL: return LESS_EQUAL;
- case BELOW: return ABOVE;
- case BELOW_EQUAL: return ABOVE_EQUAL;
- case ABOVE: return BELOW;
- case ABOVE_EQUAL: return BELOW_EQUAL;
- default:
- UNIMPLEMENTED();
- return EQUAL;
- }
-}
-
-
-bool FlowGraphCompiler::EvaluateCondition(Condition condition,
- intptr_t left,
- intptr_t right) {
- const uintptr_t unsigned_left = static_cast<uintptr_t>(left);
- const uintptr_t unsigned_right = static_cast<uintptr_t>(right);
- switch (condition) {
- case EQUAL: return left == right;
- case NOT_EQUAL: return left != right;
- case LESS: return left < right;
- case LESS_EQUAL: return left <= right;
- case GREATER: return left > right;
- case GREATER_EQUAL: return left >= right;
- case BELOW: return unsigned_left < unsigned_right;
- case BELOW_EQUAL: return unsigned_left <= unsigned_right;
- case ABOVE: return unsigned_left > unsigned_right;
- case ABOVE_EQUAL: return unsigned_left >= unsigned_right;
- default:
- UNIMPLEMENTED();
- return false;
- }
-}
-
-
FieldAddress FlowGraphCompiler::ElementAddressForIntIndex(intptr_t cid,
intptr_t index_scale,
Register array,
diff --git a/runtime/vm/flow_graph_compiler_mips.cc b/runtime/vm/flow_graph_compiler_mips.cc
index efcd64c..42d34aa 100644
--- a/runtime/vm/flow_graph_compiler_mips.cc
+++ b/runtime/vm/flow_graph_compiler_mips.cc
@@ -45,8 +45,96 @@
RawDeoptInfo* CompilerDeoptInfo::CreateDeoptInfo(FlowGraphCompiler* compiler,
DeoptInfoBuilder* builder) {
- UNIMPLEMENTED(); // TODO(regis): Copy ARM version.
- return NULL;
+ if (deopt_env_ == NULL) return DeoptInfo::null();
+
+ intptr_t stack_height = compiler->StackSize();
+ AllocateIncomingParametersRecursive(deopt_env_, &stack_height);
+
+ intptr_t slot_ix = 0;
+ Environment* current = deopt_env_;
+
+ // Emit all kMaterializeObject instructions describing objects to be
+ // materialized on the deoptimization as a prefix to the deoptimization info.
+ EmitMaterializations(deopt_env_, builder);
+
+ // The real frame starts here.
+ builder->MarkFrameStart();
+
+ // Current PP, FP, and PC.
+ builder->AddPp(current->function(), slot_ix++);
+ builder->AddCallerFp(slot_ix++);
+ builder->AddReturnAddress(current->function(), deopt_id(), slot_ix++);
+
+ // Callee's PC marker is not used anymore. Pass Function::null() to set to 0.
+ builder->AddPcMarker(Function::Handle(), slot_ix++);
+
+ // Emit all values that are needed for materialization as a part of the
+ // expression stack for the bottom-most frame. This guarantees that GC
+ // will be able to find them during materialization.
+ slot_ix = builder->EmitMaterializationArguments(slot_ix);
+
+ // For the innermost environment, set outgoing arguments and the locals.
+ for (intptr_t i = current->Length() - 1;
+ i >= current->fixed_parameter_count();
+ i--) {
+ builder->AddCopy(current->ValueAt(i), current->LocationAt(i), slot_ix++);
+ }
+
+ Environment* previous = current;
+ current = current->outer();
+ while (current != NULL) {
+ // PP, FP, and PC.
+ builder->AddPp(current->function(), slot_ix++);
+ builder->AddCallerFp(slot_ix++);
+
+ // For any outer environment the deopt id is that of the call instruction
+ // which is recorded in the outer environment.
+ builder->AddReturnAddress(current->function(),
+ Isolate::ToDeoptAfter(current->deopt_id()),
+ slot_ix++);
+
+ // PC marker.
+ builder->AddPcMarker(previous->function(), slot_ix++);
+
+ // The values of outgoing arguments can be changed from the inlined call so
+ // we must read them from the previous environment.
+ for (intptr_t i = previous->fixed_parameter_count() - 1; i >= 0; i--) {
+ builder->AddCopy(previous->ValueAt(i),
+ previous->LocationAt(i),
+ slot_ix++);
+ }
+
+ // Set the locals, note that outgoing arguments are not in the environment.
+ for (intptr_t i = current->Length() - 1;
+ i >= current->fixed_parameter_count();
+ i--) {
+ builder->AddCopy(current->ValueAt(i),
+ current->LocationAt(i),
+ slot_ix++);
+ }
+
+ // Iterate on the outer environment.
+ previous = current;
+ current = current->outer();
+ }
+ // The previous pointer is now the outermost environment.
+ ASSERT(previous != NULL);
+
+ // For the outermost environment, set caller PC, caller PP, and caller FP.
+ builder->AddCallerPp(slot_ix++);
+ builder->AddCallerFp(slot_ix++);
+ builder->AddCallerPc(slot_ix++);
+
+ // PC marker.
+ builder->AddPcMarker(previous->function(), slot_ix++);
+
+ // For the outermost environment, set the incoming arguments.
+ for (intptr_t i = previous->fixed_parameter_count() - 1; i >= 0; i--) {
+ builder->AddCopy(previous->ValueAt(i), previous->LocationAt(i), slot_ix++);
+ }
+
+ const DeoptInfo& deopt_info = DeoptInfo::Handle(builder->CreateDeoptInfo());
+ return deopt_info.raw();
}
@@ -78,8 +166,7 @@
Label* is_false) {
__ TraceSimMsg("BoolToJump");
Label fall_through;
- __ BranchEqual(bool_register, reinterpret_cast<intptr_t>(Object::null()),
- &fall_through);
+ __ beq(bool_register, NULLREG, &fall_through);
__ BranchEqual(bool_register, Bool::True(), is_true);
__ b(is_false);
__ Bind(&fall_through);
@@ -101,19 +188,14 @@
const SubtypeTestCache& type_test_cache =
SubtypeTestCache::ZoneHandle(SubtypeTestCache::New());
__ LoadObject(A2, type_test_cache);
- intptr_t null = reinterpret_cast<intptr_t>(Object::null());
- uint16_t null_lo = Utils::Low16Bits(null);
- uint16_t null_hi = Utils::High16Bits(null);
if (test_kind == kTestTypeOneArg) {
ASSERT(type_arguments_reg == kNoRegister);
- __ lui(A1, Immediate(null_hi));
__ BranchLink(&StubCode::Subtype1TestCacheLabel());
- __ delay_slot()->ori(A1, A1, Immediate(null_lo));
+ __ delay_slot()->mov(A1, NULLREG);
} else if (test_kind == kTestTypeTwoArgs) {
ASSERT(type_arguments_reg == kNoRegister);
- __ lui(A1, Immediate(null_hi));
__ BranchLink(&StubCode::Subtype2TestCacheLabel());
- __ delay_slot()->ori(A1, A1, Immediate(null_lo));
+ __ delay_slot()->mov(A1, NULLREG);
} else if (test_kind == kTestTypeThreeArgs) {
ASSERT(type_arguments_reg == A1);
__ BranchLink(&StubCode::Subtype3TestCacheLabel());
@@ -247,8 +329,7 @@
// Check if instance is a closure.
__ LoadClassById(T1, kClassIdReg);
__ lw(T1, FieldAddress(T1, Class::signature_function_offset()));
- __ BranchNotEqual(T1, reinterpret_cast<int32_t>(Object::null()),
- is_instance_lbl);
+ __ bne(T1, NULLREG, is_instance_lbl);
}
// Custom checking for numbers (Smi, Mint, Bigint and Double).
// Note that instance is not Smi (checked above).
@@ -315,8 +396,7 @@
__ lw(A1, Address(SP, 0)); // Get instantiator type arguments.
// A1: instantiator type arguments.
// Check if type argument is dynamic.
- __ BranchEqual(A1, reinterpret_cast<intptr_t>(Object::null()),
- is_instance_lbl);
+ __ beq(A1, NULLREG, is_instance_lbl);
// Can handle only type arguments that are instances of TypeArguments.
// (runtime checks canonicalize type arguments).
Label fall_through;
@@ -327,8 +407,7 @@
// R2: concrete type of type.
// Check if type argument is dynamic.
__ BranchEqual(T2, Type::ZoneHandle(Type::DynamicType()), is_instance_lbl);
- __ BranchEqual(T2, reinterpret_cast<intptr_t>(Object::null()),
- is_instance_lbl);
+ __ beq(T2, NULLREG, is_instance_lbl);
const Type& object_type = Type::ZoneHandle(Type::ObjectType());
__ BranchEqual(T2, object_type, is_instance_lbl);
@@ -487,7 +566,7 @@
// A null object is always assignable and is returned as result.
Label is_assignable, runtime_call;
- __ BranchEqual(A0, reinterpret_cast<int32_t>(Object::null()), &is_assignable);
+ __ beq(A0, NULLREG, &is_assignable);
__ delay_slot()->sw(A1, Address(SP, 0 * kWordSize));
if (!FLAG_eliminate_type_checks) {
@@ -570,12 +649,8 @@
AddCurrentDescriptor(PcDescriptors::kDeopt,
assert->deopt_id(),
assert->token_pos());
- } else if (instr->IsGuardField()) {
- GuardFieldInstr* guard = instr->AsGuardField();
- AddCurrentDescriptor(PcDescriptors::kDeopt,
- guard->deopt_id(),
- Scanner::kDummyTokenIndex);
- } else if (instr->CanBeDeoptimizationTarget()) {
+ } else if (instr->IsGuardField() ||
+ instr->CanBecomeDeoptimizationTarget()) {
AddCurrentDescriptor(PcDescriptors::kDeopt,
instr->deopt_id(),
Scanner::kDummyTokenIndex);
@@ -726,8 +801,7 @@
delete[] opt_param_position;
// Check that T0 now points to the null terminator in the array descriptor.
__ lw(T3, Address(T0));
- __ BranchEqual(T3, reinterpret_cast<int32_t>(Object::null()),
- &all_arguments_processed);
+ __ beq(T3, NULLREG, &all_arguments_processed);
} else {
ASSERT(num_opt_pos_params > 0);
__ lw(T2,
@@ -804,8 +878,6 @@
// implicitly final, since garbage collecting the unmodified value is not
// an issue anymore.
- __ LoadImmediate(T0, reinterpret_cast<intptr_t>(Object::null()));
-
// S4 : arguments descriptor array.
__ lw(T2, FieldAddress(S4, ArgumentsDescriptor::count_offset()));
__ sll(T2, T2, 1); // T2 is a Smi.
@@ -818,7 +890,7 @@
__ addiu(T2, T2, Immediate(-kWordSize));
__ addu(T3, T1, T2);
__ bgtz(T2, &null_args_loop);
- __ delay_slot()->sw(T0, Address(T3));
+ __ delay_slot()->sw(NULLREG, Address(T3));
__ Bind(&null_args_loop_exit);
}
@@ -841,12 +913,8 @@
__ lw(T0, Address(SP, 1 * kWordSize)); // Receiver.
__ lw(T1, Address(SP, 0 * kWordSize)); // Value.
__ StoreIntoObject(T0, FieldAddress(T0, offset), T1);
- intptr_t null = reinterpret_cast<intptr_t>(Object::null());
- uint16_t null_lo = Utils::Low16Bits(null);
- uint16_t null_hi = Utils::High16Bits(null);
- __ lui(V0, Immediate(null_hi));
__ Ret();
- __ delay_slot()->ori(V0, V0, Immediate(null_lo));
+ __ delay_slot()->mov(V0, NULLREG);
}
@@ -1039,10 +1107,9 @@
__ TraceSimMsg("Initialize spill slots");
__ Comment("Initialize spill slots");
const intptr_t slot_base = parsed_function().first_stack_local_index();
- __ LoadImmediate(T0, reinterpret_cast<intptr_t>(Object::null()));
for (intptr_t i = 0; i < num_locals; ++i) {
// Subtract index i (locals lie at lower addresses than FP).
- __ sw(T0, Address(FP, (slot_base - i) * kWordSize));
+ __ sw(NULLREG, Address(FP, (slot_base - i) * kWordSize));
}
}
@@ -1065,7 +1132,7 @@
AddCurrentDescriptor(PcDescriptors::kPatchCode,
Isolate::kNoDeoptId,
0); // No token position.
- __ Branch(&StubCode::FixCallersTargetLabel());
+ __ BranchPatchable(&StubCode::FixCallersTargetLabel());
AddCurrentDescriptor(PcDescriptors::kLazyDeoptJump,
Isolate::kNoDeoptId,
0); // No token position.
@@ -1229,7 +1296,7 @@
__ addiu(SP, SP, Immediate(2 * kWordSize)); // Discard constant.
return;
}
- __ CompareObject(CMPRES, reg, obj);
+ __ CompareObject(CMPRES, TMP1, reg, obj);
}
@@ -1252,7 +1319,8 @@
__ lw(left, Address(SP, 1 * kWordSize));
__ addiu(SP, SP, Immediate(2 * kWordSize));
} else {
- __ subu(CMPRES, left, right);
+ __ slt(CMPRES, left, right);
+ __ slt(TMP1, right, left);
}
}
@@ -1342,20 +1410,6 @@
}
-Condition FlowGraphCompiler::FlipCondition(Condition condition) {
- UNIMPLEMENTED();
- return condition;
-}
-
-
-bool FlowGraphCompiler::EvaluateCondition(Condition condition,
- intptr_t left,
- intptr_t right) {
- UNIMPLEMENTED();
- return false;
-}
-
-
FieldAddress FlowGraphCompiler::ElementAddressForIntIndex(intptr_t cid,
intptr_t index_scale,
Register array,
@@ -1482,7 +1536,7 @@
source.IsQuadStackSlot());
bool double_width = destination.IsDoubleStackSlot() ||
source.IsDoubleStackSlot();
- FRegister reg = source.IsFpuRegister() ? source.fpu_reg()
+ DRegister reg = source.IsFpuRegister() ? source.fpu_reg()
: destination.fpu_reg();
const Address& slot_address = source.IsFpuRegister()
? destination.ToStackSlotAddress()
diff --git a/runtime/vm/flow_graph_compiler_x64.cc b/runtime/vm/flow_graph_compiler_x64.cc
index 8c9e874..d15ecea 100644
--- a/runtime/vm/flow_graph_compiler_x64.cc
+++ b/runtime/vm/flow_graph_compiler_x64.cc
@@ -722,12 +722,8 @@
AddCurrentDescriptor(PcDescriptors::kDeopt,
assert->deopt_id(),
assert->token_pos());
- } else if (instr->IsGuardField()) {
- GuardFieldInstr* guard = instr->AsGuardField();
- AddCurrentDescriptor(PcDescriptors::kDeopt,
- guard->deopt_id(),
- Scanner::kDummyTokenIndex);
- } else if (instr->CanBeDeoptimizationTarget()) {
+ } else if (instr->IsGuardField() ||
+ instr->CanBecomeDeoptimizationTarget()) {
AddCurrentDescriptor(PcDescriptors::kDeopt,
instr->deopt_id(),
Scanner::kDummyTokenIndex);
@@ -1650,48 +1646,6 @@
}
-Condition FlowGraphCompiler::FlipCondition(Condition condition) {
- switch (condition) {
- case EQUAL: return EQUAL;
- case NOT_EQUAL: return NOT_EQUAL;
- case LESS: return GREATER;
- case LESS_EQUAL: return GREATER_EQUAL;
- case GREATER: return LESS;
- case GREATER_EQUAL: return LESS_EQUAL;
- case BELOW: return ABOVE;
- case BELOW_EQUAL: return ABOVE_EQUAL;
- case ABOVE: return BELOW;
- case ABOVE_EQUAL: return BELOW_EQUAL;
- default:
- UNIMPLEMENTED();
- return EQUAL;
- }
-}
-
-
-bool FlowGraphCompiler::EvaluateCondition(Condition condition,
- intptr_t left,
- intptr_t right) {
- const uintptr_t unsigned_left = static_cast<uintptr_t>(left);
- const uintptr_t unsigned_right = static_cast<uintptr_t>(right);
- switch (condition) {
- case EQUAL: return left == right;
- case NOT_EQUAL: return left != right;
- case LESS: return left < right;
- case LESS_EQUAL: return left <= right;
- case GREATER: return left > right;
- case GREATER_EQUAL: return left >= right;
- case BELOW: return unsigned_left < unsigned_right;
- case BELOW_EQUAL: return unsigned_left <= unsigned_right;
- case ABOVE: return unsigned_left > unsigned_right;
- case ABOVE_EQUAL: return unsigned_left >= unsigned_right;
- default:
- UNIMPLEMENTED();
- return false;
- }
-}
-
-
FieldAddress FlowGraphCompiler::ElementAddressForIntIndex(intptr_t cid,
intptr_t index_scale,
Register array,
diff --git a/runtime/vm/flow_graph_inliner.cc b/runtime/vm/flow_graph_inliner.cc
index 0c0a38d..4788723 100644
--- a/runtime/vm/flow_graph_inliner.cc
+++ b/runtime/vm/flow_graph_inliner.cc
@@ -614,11 +614,7 @@
// Functions can be inlined before they are optimized.
// If not yet present, allocate deoptimization history array.
- Array& deopt_history = Array::Handle(function.deopt_history());
- if (deopt_history.IsNull()) {
- deopt_history = Array::New(FLAG_deoptimization_counter_threshold);
- function.set_deopt_history(deopt_history);
- }
+ function.EnsureDeoptHistory();
// Build succeeded so we restore the bailout jump.
inlined_ = true;
diff --git a/runtime/vm/instructions_mips.h b/runtime/vm/instructions_mips.h
index ed16b16..5567ae6 100644
--- a/runtime/vm/instructions_mips.h
+++ b/runtime/vm/instructions_mips.h
@@ -25,6 +25,10 @@
uword TargetAddress() const;
void SetTargetAddress(uword target_address) const;
+ // This constant length is only valid for inserted call patterns used for
+ // lazy deoptimization. Regular call pattern may vary in length.
+ static const int kFixedLengthInBytes = 3 * Instr::kInstrSize;
+
private:
uword Back(int n) const;
int DecodeLoadObject(int end, Register* reg, Object* obj);
diff --git a/runtime/vm/intermediate_language.cc b/runtime/vm/intermediate_language.cc
index ce76be5..e5d855b 100644
--- a/runtime/vm/intermediate_language.cc
+++ b/runtime/vm/intermediate_language.cc
@@ -1455,12 +1455,12 @@
void JoinEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+ __ Bind(compiler->GetJumpLabel(this));
if (!compiler->is_optimizing()) {
compiler->AddCurrentDescriptor(PcDescriptors::kDeopt,
deopt_id_,
Scanner::kDummyTokenIndex);
}
- __ Bind(compiler->GetJumpLabel(this));
if (HasParallelMove()) {
compiler->parallel_move_resolver()->EmitNativeCode(parallel_move());
}
@@ -1474,12 +1474,12 @@
void TargetEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+ __ Bind(compiler->GetJumpLabel(this));
if (!compiler->is_optimizing()) {
compiler->AddCurrentDescriptor(PcDescriptors::kDeopt,
deopt_id_,
Scanner::kDummyTokenIndex);
}
- __ Bind(compiler->GetJumpLabel(this));
if (HasParallelMove()) {
compiler->parallel_move_resolver()->EmitNativeCode(parallel_move());
}
diff --git a/runtime/vm/intermediate_language.h b/runtime/vm/intermediate_language.h
index 683642f..19976f6 100644
--- a/runtime/vm/intermediate_language.h
+++ b/runtime/vm/intermediate_language.h
@@ -642,7 +642,7 @@
virtual Tag tag() const = 0;
intptr_t deopt_id() const {
- ASSERT(CanDeoptimize() || CanBeDeoptimizationTarget());
+ ASSERT(CanDeoptimize() || CanBecomeDeoptimizationTarget());
return deopt_id_;
}
@@ -846,10 +846,10 @@
virtual void InheritDeoptTarget(Instruction* other);
bool NeedsEnvironment() const {
- return CanDeoptimize() || CanBeDeoptimizationTarget();
+ return CanDeoptimize() || CanBecomeDeoptimizationTarget();
}
- virtual bool CanBeDeoptimizationTarget() const {
+ virtual bool CanBecomeDeoptimizationTarget() const {
return false;
}
@@ -1152,7 +1152,7 @@
virtual intptr_t ArgumentCount() const { return 0; }
- virtual bool CanBeDeoptimizationTarget() const {
+ virtual bool CanBecomeDeoptimizationTarget() const {
// BlockEntry environment is copied to Goto and Branch instructions
// when we insert new blocks targeting this block.
return true;
@@ -1860,7 +1860,7 @@
intptr_t token_pos() const { return token_pos_; }
Value* value() const { return inputs_[0]; }
- virtual bool CanBeDeoptimizationTarget() const {
+ virtual bool CanBecomeDeoptimizationTarget() const {
// Return instruction might turn into a Goto instruction after inlining.
// Every Goto must have an environment.
return true;
@@ -1940,7 +1940,7 @@
virtual intptr_t SuccessorCount() const;
virtual BlockEntryInstr* SuccessorAt(intptr_t index) const;
- virtual bool CanBeDeoptimizationTarget() const {
+ virtual bool CanBecomeDeoptimizationTarget() const {
// Goto instruction can be used as a deoptimization target when LICM
// hoists instructions out of the loop.
return true;
@@ -2016,7 +2016,7 @@
intptr_t InputCount() const;
Value* InputAt(intptr_t i) const;
virtual bool CanDeoptimize() const;
- virtual bool CanBeDeoptimizationTarget() const;
+ virtual bool CanBecomeDeoptimizationTarget() const;
virtual EffectSet Effects() const;
@@ -2762,8 +2762,8 @@
}
-inline bool BranchInstr::CanBeDeoptimizationTarget() const {
- return comparison()->CanBeDeoptimizationTarget();
+inline bool BranchInstr::CanBecomeDeoptimizationTarget() const {
+ return comparison()->CanBecomeDeoptimizationTarget();
}
@@ -2811,7 +2811,7 @@
virtual void PrintOperandsTo(BufferFormatter* f) const;
- virtual bool CanBeDeoptimizationTarget() const {
+ virtual bool CanBecomeDeoptimizationTarget() const {
// StrictCompare can be merged into Branch and thus needs an environment.
return true;
}
diff --git a/runtime/vm/intermediate_language_arm.cc b/runtime/vm/intermediate_language_arm.cc
index d07ab4d..7e3c96b 100644
--- a/runtime/vm/intermediate_language_arm.cc
+++ b/runtime/vm/intermediate_language_arm.cc
@@ -356,9 +356,6 @@
}
-// R1: left.
-// R0: right.
-// Uses R5 to load ic_call_data.
static void EmitEqualityAsInstanceCall(FlowGraphCompiler* compiler,
intptr_t deopt_id,
intptr_t token_pos,
@@ -376,6 +373,7 @@
Label check_identity;
__ LoadImmediate(IP, reinterpret_cast<intptr_t>(Object::null()));
+ __ ldm(IA, SP, (1 << R0) | (1 << R1));
__ cmp(R1, ShifterOperand(IP));
__ b(&check_identity, EQ);
__ cmp(R0, ShifterOperand(IP));
@@ -397,7 +395,6 @@
deopt_id,
kNumArgumentsChecked);
}
- __ PushList((1 << R0) | (1 << R1));
compiler->GenerateInstanceCall(deopt_id,
token_pos,
kNumberOfArguments,
@@ -411,6 +408,7 @@
Label equality_done;
if (compiler->is_optimizing()) {
// No need to update IC data.
+ __ PopList((1 << R0) | (1 << R1));
__ cmp(R0, ShifterOperand(R1));
__ LoadObject(R0, (kind == Token::kEQ) ? Bool::False() : Bool::True(), NE);
__ LoadObject(R0, (kind == Token::kEQ) ? Bool::True() : Bool::False(), EQ);
@@ -429,6 +427,7 @@
&StubCode::EqualityWithNullArgLabel(),
PcDescriptors::kRuntimeCall,
locs);
+ __ Drop(2);
}
__ Bind(&check_ne);
if (kind == Token::kNE) {
@@ -479,8 +478,8 @@
}
-// R1: left.
-// R0: right.
+// R1: left, also on stack.
+// R0: right, also on stack.
static void EmitEqualityAsPolymorphicCall(FlowGraphCompiler* compiler,
const ICData& orig_ic_data,
LocationSummary* locs,
@@ -518,6 +517,7 @@
const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(i));
if (target.Owner() == object_store->object_class()) {
// Object.== is same as ===.
+ __ Drop(2);
__ cmp(left, ShifterOperand(right));
if (branch != NULL) {
branch->EmitBranchOnCondition(compiler, cond);
@@ -608,12 +608,32 @@
__ Bind(&non_null_compare); // Receiver is not null.
ASSERT(left == R1);
ASSERT(right == R0);
+ __ PushList((1 << R0) | (1 << R1));
EmitEqualityAsPolymorphicCall(compiler, ic_data, locs, branch, kind,
deopt_id, token_pos);
__ Bind(&done);
}
+static Condition FlipCondition(Condition condition) {
+ switch (condition) {
+ case EQ: return EQ;
+ case NE: return NE;
+ case LT: return GT;
+ case LE: return GE;
+ case GT: return LT;
+ case GE: return LE;
+ case CC: return HI;
+ case LS: return CS;
+ case HI: return CC;
+ case CS: return LS;
+ default:
+ UNIMPLEMENTED();
+ return EQ;
+ }
+}
+
+
static void EmitSmiComparisonOp(FlowGraphCompiler* compiler,
const LocationSummary& locs,
Token::Kind kind,
@@ -626,7 +646,7 @@
if (left.IsConstant()) {
__ CompareObject(right.reg(), left.constant());
- true_condition = FlowGraphCompiler::FlipCondition(true_condition);
+ true_condition = FlipCondition(true_condition);
} else if (right.IsConstant()) {
__ CompareObject(left.reg(), right.constant());
} else {
@@ -698,6 +718,7 @@
Register right = locs()->in(1).reg();
ASSERT(left == R1);
ASSERT(right == R0);
+ __ PushList((1 << R0) | (1 << R1));
EmitEqualityAsInstanceCall(compiler,
deopt_id(),
token_pos(),
@@ -740,6 +761,7 @@
Register right = locs()->in(1).reg();
ASSERT(left == R1);
ASSERT(right == R0);
+ __ PushList((1 << R0) | (1 << R1));
EmitEqualityAsInstanceCall(compiler,
deopt_id(),
token_pos(),
@@ -1697,34 +1719,32 @@
// 'instantiator_reg' is the instantiator AbstractTypeArguments object
// (or null).
- if (!type_arguments().IsUninstantiatedIdentity() &&
- !type_arguments().CanShareInstantiatorTypeArguments(
- instantiator_class())) {
- // If the instantiator is null and if the type argument vector
- // instantiated from null becomes a vector of dynamic, then use null as
- // the type arguments.
- Label type_arguments_instantiated;
- const intptr_t len = type_arguments().Length();
- if (type_arguments().IsRawInstantiatedRaw(len)) {
- __ LoadImmediate(IP, reinterpret_cast<intptr_t>(Object::null()));
- __ cmp(instantiator_reg, ShifterOperand(IP));
- __ b(&type_arguments_instantiated, EQ);
- }
- // Instantiate non-null type arguments.
- // A runtime call to instantiate the type arguments is required.
- __ PushObject(Object::ZoneHandle()); // Make room for the result.
- __ PushObject(type_arguments());
- __ Push(instantiator_reg); // Push instantiator type arguments.
- compiler->GenerateCallRuntime(token_pos(),
- deopt_id(),
- kInstantiateTypeArgumentsRuntimeEntry,
- locs());
- __ Drop(2); // Drop instantiator and uninstantiated type arguments.
- __ Pop(result_reg); // Pop instantiated type arguments.
- __ Bind(&type_arguments_instantiated);
+ ASSERT(!type_arguments().IsUninstantiatedIdentity() &&
+ !type_arguments().CanShareInstantiatorTypeArguments(
+ instantiator_class()));
+ // If the instantiator is null and if the type argument vector
+ // instantiated from null becomes a vector of dynamic, then use null as
+ // the type arguments.
+ Label type_arguments_instantiated;
+ const intptr_t len = type_arguments().Length();
+ if (type_arguments().IsRawInstantiatedRaw(len)) {
+ __ LoadImmediate(IP, reinterpret_cast<intptr_t>(Object::null()));
+ __ cmp(instantiator_reg, ShifterOperand(IP));
+ __ b(&type_arguments_instantiated, EQ);
}
+ // Instantiate non-null type arguments.
+ // A runtime call to instantiate the type arguments is required.
+ __ PushObject(Object::ZoneHandle()); // Make room for the result.
+ __ PushObject(type_arguments());
+ __ Push(instantiator_reg); // Push instantiator type arguments.
+ compiler->GenerateCallRuntime(token_pos(),
+ deopt_id(),
+ kInstantiateTypeArgumentsRuntimeEntry,
+ locs());
+ __ Drop(2); // Drop instantiator and uninstantiated type arguments.
+ __ Pop(result_reg); // Pop instantiated type arguments.
+ __ Bind(&type_arguments_instantiated);
ASSERT(instantiator_reg == result_reg);
- // 'result_reg': Instantiated type arguments.
}
@@ -1925,6 +1945,115 @@
}
+static void EmitSmiShiftLeft(FlowGraphCompiler* compiler,
+ BinarySmiOpInstr* shift_left) {
+ const bool is_truncating = shift_left->is_truncating();
+ const LocationSummary& locs = *shift_left->locs();
+ Register left = locs.in(0).reg();
+ Register result = locs.out().reg();
+ Label* deopt = shift_left->CanDeoptimize() ?
+ compiler->AddDeoptStub(shift_left->deopt_id(), kDeoptBinarySmiOp) : NULL;
+ if (locs.in(1).IsConstant()) {
+ const Object& constant = locs.in(1).constant();
+ ASSERT(constant.IsSmi());
+ // Immediate shift operation takes 5 bits for the count.
+ const intptr_t kCountLimit = 0x1F;
+ const intptr_t value = Smi::Cast(constant).Value();
+ if (value == 0) {
+ // No code needed.
+ } else if ((value < 0) || (value >= kCountLimit)) {
+ // This condition may not be known earlier in some cases because
+ // of constant propagation, inlining, etc.
+ if ((value >=kCountLimit) && is_truncating) {
+ __ mov(result, ShifterOperand(0));
+ } else {
+ // Result is Mint or exception.
+ __ b(deopt);
+ }
+ } else {
+ if (!is_truncating) {
+ // Check for overflow (preserve left).
+ __ Lsl(IP, left, value);
+ __ cmp(left, ShifterOperand(IP, ASR, value));
+ __ b(deopt, NE); // Overflow.
+ }
+ // Shift for result now we know there is no overflow.
+ __ Lsl(result, left, value);
+ }
+ return;
+ }
+
+ // Right (locs.in(1)) is not constant.
+ Register right = locs.in(1).reg();
+ Range* right_range = shift_left->right()->definition()->range();
+ if (shift_left->left()->BindsToConstant() && !is_truncating) {
+ // TODO(srdjan): Implement code below for is_truncating().
+ // If left is constant, we know the maximal allowed size for right.
+ const Object& obj = shift_left->left()->BoundConstant();
+ if (obj.IsSmi()) {
+ const intptr_t left_int = Smi::Cast(obj).Value();
+ if (left_int == 0) {
+ __ cmp(right, ShifterOperand(0));
+ __ b(deopt, MI);
+ return;
+ }
+ const intptr_t max_right = kSmiBits - Utils::HighestBit(left_int);
+ const bool right_needs_check =
+ (right_range == NULL) ||
+ !right_range->IsWithin(0, max_right - 1);
+ if (right_needs_check) {
+ __ cmp(right,
+ ShifterOperand(reinterpret_cast<int32_t>(Smi::New(max_right))));
+ __ b(deopt, CS);
+ }
+ __ SmiUntag(right);
+ __ Lsl(result, left, right);
+ }
+ return;
+ }
+
+ const bool right_needs_check =
+ (right_range == NULL) || !right_range->IsWithin(0, (Smi::kBits - 1));
+ if (is_truncating) {
+ if (right_needs_check) {
+ const bool right_may_be_negative =
+ (right_range == NULL) ||
+ !right_range->IsWithin(0, RangeBoundary::kPlusInfinity);
+ if (right_may_be_negative) {
+ ASSERT(shift_left->CanDeoptimize());
+ __ cmp(right, ShifterOperand(0));
+ __ b(deopt, MI);
+ }
+ Label done, is_not_zero;
+ __ cmp(right,
+ ShifterOperand(reinterpret_cast<int32_t>(Smi::New(Smi::kBits))));
+ __ mov(result, ShifterOperand(0), CS);
+ __ SmiUntag(right, CC);
+ __ Lsl(result, left, right, CC);
+ } else {
+ __ SmiUntag(right);
+ __ Lsl(result, left, right);
+ }
+ } else {
+ if (right_needs_check) {
+ ASSERT(shift_left->CanDeoptimize());
+ __ cmp(right,
+ ShifterOperand(reinterpret_cast<int32_t>(Smi::New(Smi::kBits))));
+ __ b(deopt, CS);
+ }
+ // Left is not a constant.
+ // Check if count too large for handling it inlined.
+ __ SmiUntag(right);
+ // Overflow test (preserve left and right);
+ __ Lsl(IP, left, right);
+ __ cmp(left, ShifterOperand(IP, ASR, right));
+ __ b(deopt, NE); // Overflow.
+ // Shift for result now we know there is no overflow.
+ __ Lsl(result, left, right);
+ }
+}
+
+
LocationSummary* BinarySmiOpInstr::MakeLocationSummary() const {
const intptr_t kNumInputs = 2;
if (op_kind() == Token::kTRUNCDIV) {
@@ -1946,7 +2075,7 @@
void BinarySmiOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
if (op_kind() == Token::kSHL) {
- UNIMPLEMENTED();
+ EmitSmiShiftLeft(compiler, this);
return;
}
@@ -2040,7 +2169,24 @@
break;
}
case Token::kSHR: {
- UNIMPLEMENTED();
+ // sarl operation masks the count to 5 bits.
+ const intptr_t kCountLimit = 0x1F;
+ intptr_t value = Smi::Cast(constant).Value();
+
+ if (value == 0) {
+ // TODO(vegorov): should be handled outside.
+ break;
+ } else if (value < 0) {
+ // TODO(vegorov): should be handled outside.
+ __ b(deopt);
+ break;
+ }
+
+ value = value + kSmiTagSize;
+ if (value >= kCountLimit) value = kCountLimit;
+
+ __ Asr(result, left, value);
+ __ SmiTag(result);
break;
}
@@ -2530,7 +2676,8 @@
}
// Load receiver into R0.
- __ ldr(R0, Address(SP, (instance_call()->ArgumentCount() - 1) * kWordSize));
+ __ LoadFromOffset(kLoadWord, R0, SP,
+ (instance_call()->ArgumentCount() - 1) * kWordSize);
LoadValueCid(compiler, R2, R0,
(ic_data().GetReceiverClassIdAt(0) == kSmiCid) ? NULL : deopt);
@@ -2772,14 +2919,6 @@
void GotoInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- if (!compiler->is_optimizing()) {
- // Add deoptimization descriptor for deoptimizing instructions that may
- // be inserted before this instruction.
- compiler->AddCurrentDescriptor(PcDescriptors::kDeopt,
- GetDeoptId(),
- 0); // No token position.
- }
-
if (HasParallelMove()) {
compiler->parallel_move_resolver()->EmitNativeCode(parallel_move());
}
diff --git a/runtime/vm/intermediate_language_ia32.cc b/runtime/vm/intermediate_language_ia32.cc
index 23b6241..1d1ad45 100644
--- a/runtime/vm/intermediate_language_ia32.cc
+++ b/runtime/vm/intermediate_language_ia32.cc
@@ -629,6 +629,25 @@
}
+static Condition FlipCondition(Condition condition) {
+ switch (condition) {
+ case EQUAL: return EQUAL;
+ case NOT_EQUAL: return NOT_EQUAL;
+ case LESS: return GREATER;
+ case LESS_EQUAL: return GREATER_EQUAL;
+ case GREATER: return LESS;
+ case GREATER_EQUAL: return LESS_EQUAL;
+ case BELOW: return ABOVE;
+ case BELOW_EQUAL: return ABOVE_EQUAL;
+ case ABOVE: return BELOW;
+ case ABOVE_EQUAL: return BELOW_EQUAL;
+ default:
+ UNIMPLEMENTED();
+ return EQUAL;
+ }
+}
+
+
static void EmitSmiComparisonOp(FlowGraphCompiler* compiler,
const LocationSummary& locs,
Token::Kind kind,
@@ -641,7 +660,7 @@
if (left.IsConstant()) {
__ CompareObject(right.reg(), left.constant());
- true_condition = FlowGraphCompiler::FlipCondition(true_condition);
+ true_condition = FlipCondition(true_condition);
} else if (right.IsConstant()) {
__ CompareObject(left.reg(), right.constant());
} else if (right.IsStackSlot()) {
@@ -749,11 +768,11 @@
__ cmpl(left_tmp, right_tmp);
if (branch != NULL) {
__ j(hi_cond, compiler->GetJumpLabel(branch->true_successor()));
- __ j(FlowGraphCompiler::FlipCondition(hi_cond),
+ __ j(FlipCondition(hi_cond),
compiler->GetJumpLabel(branch->false_successor()));
} else {
__ j(hi_cond, &is_true);
- __ j(FlowGraphCompiler::FlipCondition(hi_cond), &is_false);
+ __ j(FlipCondition(hi_cond), &is_false);
}
// If upper is equal, compare lower half.
@@ -1883,35 +1902,33 @@
// 'instantiator_reg' is the instantiator AbstractTypeArguments object
// (or null).
- if (!type_arguments().IsUninstantiatedIdentity() &&
- !type_arguments().CanShareInstantiatorTypeArguments(
- instantiator_class())) {
- // If the instantiator is null and if the type argument vector
- // instantiated from null becomes a vector of dynamic, then use null as
- // the type arguments.
- Label type_arguments_instantiated;
- const intptr_t len = type_arguments().Length();
- if (type_arguments().IsRawInstantiatedRaw(len)) {
- const Immediate& raw_null =
- Immediate(reinterpret_cast<intptr_t>(Object::null()));
- __ cmpl(instantiator_reg, raw_null);
- __ j(EQUAL, &type_arguments_instantiated, Assembler::kNearJump);
- }
- // Instantiate non-null type arguments.
- // A runtime call to instantiate the type arguments is required.
- __ PushObject(Object::ZoneHandle()); // Make room for the result.
- __ PushObject(type_arguments());
- __ pushl(instantiator_reg); // Push instantiator type arguments.
- compiler->GenerateCallRuntime(token_pos(),
- deopt_id(),
- kInstantiateTypeArgumentsRuntimeEntry,
- locs());
- __ Drop(2); // Drop instantiator and uninstantiated type arguments.
- __ popl(result_reg); // Pop instantiated type arguments.
- __ Bind(&type_arguments_instantiated);
+ ASSERT(!type_arguments().IsUninstantiatedIdentity() &&
+ !type_arguments().CanShareInstantiatorTypeArguments(
+ instantiator_class()));
+ // If the instantiator is null and if the type argument vector
+ // instantiated from null becomes a vector of dynamic, then use null as
+ // the type arguments.
+ Label type_arguments_instantiated;
+ const intptr_t len = type_arguments().Length();
+ if (type_arguments().IsRawInstantiatedRaw(len)) {
+ const Immediate& raw_null =
+ Immediate(reinterpret_cast<intptr_t>(Object::null()));
+ __ cmpl(instantiator_reg, raw_null);
+ __ j(EQUAL, &type_arguments_instantiated, Assembler::kNearJump);
}
+ // Instantiate non-null type arguments.
+ // A runtime call to instantiate the type arguments is required.
+ __ PushObject(Object::ZoneHandle()); // Make room for the result.
+ __ PushObject(type_arguments());
+ __ pushl(instantiator_reg); // Push instantiator type arguments.
+ compiler->GenerateCallRuntime(token_pos(),
+ deopt_id(),
+ kInstantiateTypeArgumentsRuntimeEntry,
+ locs());
+ __ Drop(2); // Drop instantiator and uninstantiated type arguments.
+ __ popl(result_reg); // Pop instantiated type arguments.
+ __ Bind(&type_arguments_instantiated);
ASSERT(instantiator_reg == result_reg);
- // 'result_reg': Instantiated type arguments.
}
@@ -2181,11 +2198,7 @@
__ j(NEGATIVE, deopt);
return;
}
- intptr_t tmp = (left_int > 0) ? left_int : ~left_int;
- intptr_t max_right = kSmiBits;
- while ((tmp >>= 1) != 0) {
- max_right--;
- }
+ const intptr_t max_right = kSmiBits - Utils::HighestBit(left_int);
const bool right_needs_check =
(right_range == NULL) ||
!right_range->IsWithin(0, max_right - 1);
@@ -2295,7 +2308,12 @@
LocationSummary* summary =
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
summary->set_in(0, Location::RequiresRegister());
- summary->set_in(1, Location::RegisterOrSmiConstant(right()));
+ ConstantInstr* constant = right()->definition()->AsConstant();
+ if (constant != NULL) {
+ summary->set_in(1, Location::RegisterOrSmiConstant(right()));
+ } else {
+ summary->set_in(1, Location::PrefersRegister());
+ }
summary->set_out(Location::SameAsFirstInput());
return summary;
}
@@ -2416,8 +2434,49 @@
break;
}
return;
- }
+ } // if locs()->in(1).IsConstant()
+ if (locs()->in(1).IsStackSlot()) {
+ const Address& right = locs()->in(1).ToStackSlotAddress();
+ switch (op_kind()) {
+ case Token::kADD: {
+ __ addl(left, right);
+ if (deopt != NULL) __ j(OVERFLOW, deopt);
+ break;
+ }
+ case Token::kSUB: {
+ __ subl(left, right);
+ if (deopt != NULL) __ j(OVERFLOW, deopt);
+ break;
+ }
+ case Token::kMUL: {
+ __ SmiUntag(left);
+ __ imull(left, right);
+ if (deopt != NULL) __ j(OVERFLOW, deopt);
+ break;
+ }
+ case Token::kBIT_AND: {
+ // No overflow check.
+ __ andl(left, right);
+ break;
+ }
+ case Token::kBIT_OR: {
+ // No overflow check.
+ __ orl(left, right);
+ break;
+ }
+ case Token::kBIT_XOR: {
+ // No overflow check.
+ __ xorl(left, right);
+ break;
+ }
+ default:
+ UNREACHABLE();
+ }
+ return;
+ } // if locs()->in(1).IsStackSlot.
+
+ // if locs()->in(1).IsRegister.
Register right = locs()->in(1).reg();
switch (op_kind()) {
case Token::kADD: {
@@ -4268,14 +4327,6 @@
void GotoInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- if (!compiler->is_optimizing()) {
- // Add deoptimization descriptor for deoptimizing instructions that may
- // be inserted before this instruction.
- compiler->AddCurrentDescriptor(PcDescriptors::kDeopt,
- GetDeoptId(),
- 0); // No token position.
- }
-
if (HasParallelMove()) {
compiler->parallel_move_resolver()->EmitNativeCode(parallel_move());
}
diff --git a/runtime/vm/intermediate_language_mips.cc b/runtime/vm/intermediate_language_mips.cc
index 5107f34..5610b8b 100644
--- a/runtime/vm/intermediate_language_mips.cc
+++ b/runtime/vm/intermediate_language_mips.cc
@@ -92,9 +92,9 @@
const intptr_t fp_sp_dist =
(kFirstLocalSlotFromFp + 1 - compiler->StackSize()) * kWordSize;
ASSERT(fp_sp_dist <= 0);
- __ subu(T2, SP, FP);
+ __ subu(TMP1, SP, FP);
- __ BranchEqual(T2, fp_sp_dist, &stack_ok);
+ __ BranchEqual(TMP1, fp_sp_dist, &stack_ok);
__ break_(0);
__ Bind(&stack_ok);
@@ -328,7 +328,10 @@
const intptr_t kNumTemps = 1;
LocationSummary* locs =
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
- UNIMPLEMENTED(); // TODO(regis): Verify register allocation.
+ locs->set_in(0, Location::RegisterLocation(A1));
+ locs->set_in(1, Location::RegisterLocation(A0));
+ locs->set_temp(0, Location::RegisterLocation(T0));
+ locs->set_out(Location::RegisterLocation(V0));
return locs;
}
const intptr_t kNumTemps = 1;
@@ -363,9 +366,8 @@
const int kNumArgumentsChecked = 2;
Label check_identity;
- __ LoadImmediate(TMP1, reinterpret_cast<intptr_t>(Object::null()));
- __ beq(A1, TMP1, &check_identity);
- __ beq(A0, TMP1, &check_identity);
+ __ beq(A1, NULLREG, &check_identity);
+ __ beq(A0, NULLREG, &check_identity);
ICData& equality_ic_data = ICData::ZoneHandle();
if (compiler->is_optimizing() && FLAG_propagate_ic_data) {
@@ -496,6 +498,29 @@
}
+// Branches on condition c assuming comparison results in CMPRES and TMP1.
+static void EmitBranchAfterCompare(
+ FlowGraphCompiler* compiler, Condition c, Label* is_true) {
+ switch (c) {
+ case EQ: __ beq(CMPRES, TMP1, is_true); break;
+ case NE: __ bne(CMPRES, TMP1, is_true); break;
+ case GT: __ bne(TMP1, ZR, is_true); break;
+ case GE: __ beq(CMPRES, ZR, is_true); break;
+ case LT: __ bne(CMPRES, ZR, is_true); break;
+ case LE: __ beq(TMP1, ZR, is_true); break;
+ default:
+ UNREACHABLE();
+ break;
+ }
+}
+
+
+static Condition FlipCondition(Condition condition) {
+ UNIMPLEMENTED();
+ return condition;
+}
+
+
static void EmitSmiComparisonOp(FlowGraphCompiler* compiler,
const LocationSummary& locs,
Token::Kind kind,
@@ -508,12 +533,13 @@
Condition true_condition = TokenKindToSmiCondition(kind);
if (left.IsConstant()) {
- __ CompareObject(CMPRES, right.reg(), left.constant());
- true_condition = FlowGraphCompiler::FlipCondition(true_condition);
+ __ CompareObject(CMPRES, TMP1, right.reg(), left.constant());
+ true_condition = FlipCondition(true_condition);
} else if (right.IsConstant()) {
- __ CompareObject(CMPRES, left.reg(), right.constant());
+ __ CompareObject(CMPRES, TMP1, left.reg(), right.constant());
} else {
- __ subu(CMPRES, left.reg(), right.reg());
+ __ slt(CMPRES, left.reg(), right.reg());
+ __ slt(TMP1, right.reg(), left.reg());
}
if (branch != NULL) {
@@ -521,17 +547,7 @@
} else {
Register result = locs.out().reg();
Label done, is_true;
- switch (true_condition) {
- case EQ: __ beq(CMPRES, ZR, &is_true); break;
- case NE: __ bne(CMPRES, ZR, &is_true); break;
- case GT: __ bgtz(CMPRES, &is_true); break;
- case GE: __ bgez(CMPRES, &is_true); break;
- case LT: __ bltz(CMPRES, &is_true); break;
- case LE: __ blez(CMPRES, &is_true); break;
- default:
- UNREACHABLE();
- break;
- }
+ EmitBranchAfterCompare(compiler, true_condition, &is_true);
__ LoadObject(result, Bool::False());
__ b(&done);
__ Bind(&is_true);
@@ -649,7 +665,7 @@
EmitAssertBoolean(V0, token_pos(), deopt_id(), locs(), compiler);
}
Condition branch_condition = (kind() == Token::kNE) ? NE : EQ;
- __ CompareObject(CMPRES, V0, Bool::True());
+ __ CompareObject(CMPRES, TMP1, V0, Bool::True());
branch->EmitBranchOnCondition(compiler, branch_condition);
}
@@ -785,7 +801,7 @@
return;
}
EmitNativeCode(compiler);
- __ CompareObject(CMPRES, V0, Bool::True());
+ __ CompareObject(CMPRES, TMP1, V0, Bool::True());
branch->EmitBranchOnCondition(compiler, EQ);
}
@@ -859,13 +875,25 @@
LocationSummary* LoadClassIdInstr::MakeLocationSummary() const {
- UNIMPLEMENTED();
- return NULL;
+ const intptr_t kNumInputs = 1;
+ return LocationSummary::Make(kNumInputs,
+ Location::RequiresRegister(),
+ LocationSummary::kNoCall);
}
void LoadClassIdInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- UNIMPLEMENTED();
+ Register object = locs()->in(0).reg();
+ Register result = locs()->out().reg();
+ Label load, done;
+ __ andi(CMPRES, object, Immediate(kSmiTagMask));
+ __ bne(CMPRES, ZR, &load);
+ __ LoadImmediate(result, Smi::RawValue(kSmiCid));
+ __ b(&done);
+ __ Bind(&load);
+ __ LoadClassId(result, object);
+ __ SmiTag(result);
+ __ Bind(&done);
}
@@ -994,9 +1022,9 @@
default:
UNREACHABLE();
}
- __ AddImmediate(index.reg(),
+ __ addu(index.reg(), array, index.reg());
+ element_address = Address(index.reg(),
FlowGraphCompiler::DataOffsetFor(class_id()) - kHeapObjectTag);
- element_address = Address(array, index.reg());
}
if ((representation() == kUnboxedDouble) ||
@@ -1006,9 +1034,6 @@
}
Register result = locs()->out().reg();
- if ((index_scale() == 1) && index.IsRegister()) {
- __ SmiUntag(index.reg());
- }
switch (class_id()) {
case kTypedDataInt8ArrayCid:
ASSERT(index_scale() == 1);
@@ -1061,8 +1086,33 @@
Representation StoreIndexedInstr::RequiredInputRepresentation(
intptr_t idx) const {
- UNIMPLEMENTED();
- return kTagged;
+ // Array can be a Dart object or a pointer to external data.
+ if (idx == 0) return kNoRepresentation; // Flexible input representation.
+ if (idx == 1) return kTagged; // Index is a smi.
+ ASSERT(idx == 2);
+ switch (class_id_) {
+ case kArrayCid:
+ case kOneByteStringCid:
+ case kTypedDataInt8ArrayCid:
+ case kTypedDataUint8ArrayCid:
+ case kExternalTypedDataUint8ArrayCid:
+ case kTypedDataUint8ClampedArrayCid:
+ case kExternalTypedDataUint8ClampedArrayCid:
+ case kTypedDataInt16ArrayCid:
+ case kTypedDataUint16ArrayCid:
+ return kTagged;
+ case kTypedDataInt32ArrayCid:
+ case kTypedDataUint32ArrayCid:
+ return value()->IsSmiValue() ? kTagged : kUnboxedMint;
+ case kTypedDataFloat32ArrayCid:
+ case kTypedDataFloat64ArrayCid:
+ return kUnboxedDouble;
+ case kTypedDataFloat32x4ArrayCid:
+ return kUnboxedFloat32x4;
+ default:
+ UNIMPLEMENTED();
+ return kTagged;
+ }
}
@@ -1088,14 +1138,22 @@
case kTypedDataUint8ArrayCid:
case kTypedDataUint8ClampedArrayCid:
case kOneByteStringCid:
+ locs->set_in(2, Location::RegisterOrSmiConstant(value()));
+ break;
case kTypedDataInt16ArrayCid:
case kTypedDataUint16ArrayCid:
case kTypedDataInt32ArrayCid:
case kTypedDataUint32ArrayCid:
+ locs->set_in(2, Location::WritableRegister());
+ break;
case kTypedDataFloat32ArrayCid:
- case kTypedDataFloat64ArrayCid:
+ // TODO(regis): Verify.
+ // Need temp register for float-to-double conversion.
+ locs->AddTemp(Location::RequiresFpuRegister());
+ // Fall through.
+ case kTypedDataFloat64ArrayCid: // TODO(srdjan): Support Float64 constants.
case kTypedDataFloat32x4ArrayCid:
- UNIMPLEMENTED();
+ locs->set_in(2, Location::RequiresFpuRegister());
break;
default:
UNREACHABLE();
@@ -1143,10 +1201,9 @@
default:
UNREACHABLE();
}
- __ AddImmediate(index.reg(),
+ __ addu(index.reg(), array, index.reg());
+ element_address = Address(index.reg(),
FlowGraphCompiler::DataOffsetFor(class_id()) - kHeapObjectTag);
- __ addu(TMP1, array, index.reg());
- element_address = Address(TMP1);
}
switch (class_id()) {
@@ -1165,13 +1222,64 @@
case kTypedDataInt8ArrayCid:
case kTypedDataUint8ArrayCid:
case kExternalTypedDataUint8ArrayCid:
+ case kOneByteStringCid: {
+ if (locs()->in(2).IsConstant()) {
+ const Smi& constant = Smi::Cast(locs()->in(2).constant());
+ __ LoadImmediate(TMP, static_cast<int8_t>(constant.Value()));
+ __ sb(TMP, element_address);
+ } else {
+ Register value = locs()->in(2).reg();
+ __ SmiUntag(value);
+ __ sb(value, element_address);
+ }
+ break;
+ }
case kTypedDataUint8ClampedArrayCid:
- case kExternalTypedDataUint8ClampedArrayCid:
- case kOneByteStringCid:
+ case kExternalTypedDataUint8ClampedArrayCid: {
+ if (locs()->in(2).IsConstant()) {
+ const Smi& constant = Smi::Cast(locs()->in(2).constant());
+ intptr_t value = constant.Value();
+ // Clamp to 0x0 or 0xFF respectively.
+ if (value > 0xFF) {
+ value = 0xFF;
+ } else if (value < 0) {
+ value = 0;
+ }
+ __ LoadImmediate(TMP, static_cast<int8_t>(value));
+ __ sb(TMP, element_address);
+ } else {
+ Register value = locs()->in(2).reg();
+ Label store_value, bigger, smaller;
+ __ SmiUntag(value);
+ __ BranchUnsignedLess(value, 0xFF + 1, &store_value);
+ __ LoadImmediate(TMP, 0xFF);
+ __ slti(CMPRES, value, Immediate(1));
+ __ movn(TMP, ZR, CMPRES);
+ __ mov(value, TMP);
+ __ Bind(&store_value);
+ __ sb(value, element_address);
+ }
+ break;
+ }
case kTypedDataInt16ArrayCid:
- case kTypedDataUint16ArrayCid:
+ case kTypedDataUint16ArrayCid: {
+ Register value = locs()->in(2).reg();
+ __ SmiUntag(value);
+ __ sh(value, element_address);
+ break;
+ }
case kTypedDataInt32ArrayCid:
- case kTypedDataUint32ArrayCid:
+ case kTypedDataUint32ArrayCid: {
+ if (value()->IsSmiValue()) {
+ ASSERT(RequiredInputRepresentation(2) == kTagged);
+ Register value = locs()->in(2).reg();
+ __ SmiUntag(value);
+ __ sw(value, element_address);
+ } else {
+ UNIMPLEMENTED();
+ }
+ break;
+ }
case kTypedDataFloat32ArrayCid:
case kTypedDataFloat64ArrayCid:
case kTypedDataFloat32x4ArrayCid:
@@ -1299,8 +1407,7 @@
if (field().is_nullable() && (field_cid != kNullCid)) {
__ beq(CMPRES, ZR, &ok);
- __ LoadImmediate(TMP1, reinterpret_cast<intptr_t>(Object::null()));
- __ subu(CMPRES, value_reg, TMP1);
+ __ subu(CMPRES, value_reg, NULLREG);
}
if (ok_is_fall_through) {
@@ -1498,41 +1605,37 @@
// 'instantiator_reg' is the instantiator AbstractTypeArguments object
// (or null).
- if (!type_arguments().IsUninstantiatedIdentity() &&
- !type_arguments().CanShareInstantiatorTypeArguments(
- instantiator_class())) {
- // If the instantiator is null and if the type argument vector
- // instantiated from null becomes a vector of dynamic, then use null as
- // the type arguments.
- Label type_arguments_instantiated;
- const intptr_t len = type_arguments().Length();
- if (type_arguments().IsRawInstantiatedRaw(len)) {
- __ BranchEqual(instantiator_reg,
- reinterpret_cast<intptr_t>(Object::null()),
- &type_arguments_instantiated);
- }
- // Instantiate non-null type arguments.
- // A runtime call to instantiate the type arguments is required.
- __ addiu(SP, SP, Immediate(-3 * kWordSize));
- __ LoadObject(TMP1, Object::ZoneHandle());
- __ sw(TMP1, Address(SP, 2 * kWordSize)); // Make room for the result.
- __ LoadObject(TMP1, type_arguments());
- __ sw(TMP1, Address(SP, 1 * kWordSize));
- // Push instantiator type arguments.
- __ sw(instantiator_reg, Address(SP, 0 * kWordSize));
-
- compiler->GenerateCallRuntime(token_pos(),
- deopt_id(),
- kInstantiateTypeArgumentsRuntimeEntry,
- locs());
- // Pop instantiated type arguments.
- __ lw(result_reg, Address(SP, 2 * kWordSize));
- // Drop instantiator and uninstantiated type arguments.
- __ addiu(SP, SP, Immediate(3 * kWordSize));
- __ Bind(&type_arguments_instantiated);
+ ASSERT(!type_arguments().IsUninstantiatedIdentity() &&
+ !type_arguments().CanShareInstantiatorTypeArguments(
+ instantiator_class()));
+ // If the instantiator is null and if the type argument vector
+ // instantiated from null becomes a vector of dynamic, then use null as
+ // the type arguments.
+ Label type_arguments_instantiated;
+ const intptr_t len = type_arguments().Length();
+ if (type_arguments().IsRawInstantiatedRaw(len)) {
+ __ beq(instantiator_reg, NULLREG, &type_arguments_instantiated);
}
+ // Instantiate non-null type arguments.
+ // A runtime call to instantiate the type arguments is required.
+ __ addiu(SP, SP, Immediate(-3 * kWordSize));
+ __ LoadObject(TMP1, Object::ZoneHandle());
+ __ sw(TMP1, Address(SP, 2 * kWordSize)); // Make room for the result.
+ __ LoadObject(TMP1, type_arguments());
+ __ sw(TMP1, Address(SP, 1 * kWordSize));
+ // Push instantiator type arguments.
+ __ sw(instantiator_reg, Address(SP, 0 * kWordSize));
+
+ compiler->GenerateCallRuntime(token_pos(),
+ deopt_id(),
+ kInstantiateTypeArgumentsRuntimeEntry,
+ locs());
+ // Pop instantiated type arguments.
+ __ lw(result_reg, Address(SP, 2 * kWordSize));
+ // Drop instantiator and uninstantiated type arguments.
+ __ addiu(SP, SP, Immediate(3 * kWordSize));
+ __ Bind(&type_arguments_instantiated);
ASSERT(instantiator_reg == result_reg);
- // 'result_reg': Instantiated type arguments.
}
@@ -1564,9 +1667,7 @@
// the type arguments.
Label type_arguments_instantiated;
ASSERT(type_arguments().IsRawInstantiatedRaw(type_arguments().Length()));
- __ BranchEqual(instantiator_reg,
- reinterpret_cast<intptr_t>(Object::null()),
- &type_arguments_instantiated);
+ __ beq(instantiator_reg, NULLREG, &type_arguments_instantiated);
// Instantiate non-null type arguments.
// In the non-factory case, we rely on the allocation stub to
// instantiate the type arguments.
@@ -1606,8 +1707,7 @@
// the type arguments and do not pass the instantiator.
ASSERT(type_arguments().IsRawInstantiatedRaw(type_arguments().Length()));
Label instantiator_not_null;
- __ BranchNotEqual(instantiator_reg,
- reinterpret_cast<intptr_t>(Object::null()), &instantiator_not_null);
+ __ bne(instantiator_reg, NULLREG, &instantiator_not_null);
// Null was used in VisitExtractConstructorTypeArguments as the
// instantiated type arguments, no proper instantiator needed.
__ LoadImmediate(instantiator_reg,
@@ -1681,10 +1781,10 @@
Address(FP, stacktrace_var().index() * kWordSize));
Label next;
- __ mov(T0, RA); // Save return adress.
+ __ mov(TMP, RA); // Save return adress.
// Restore the pool pointer.
__ bal(&next); // Branch and link to next instruction to get PC in RA.
- __ delay_slot()->mov(T1, RA); // Save PC of the following mov.
+ __ delay_slot()->mov(CMPRES, RA); // Save PC of the following mov.
// Calculate offset of pool pointer from the PC.
const intptr_t object_pool_pc_dist =
@@ -1692,8 +1792,8 @@
compiler->assembler()->CodeSize();
__ Bind(&next);
- __ mov(RA, T0); // Restore return address.
- __ lw(PP, Address(T1, -object_pool_pc_dist));
+ __ mov(RA, TMP); // Restore return address.
+ __ lw(PP, Address(CMPRES, -object_pool_pc_dist));
}
@@ -1756,7 +1856,7 @@
UNIMPLEMENTED();
return NULL;
} else {
- const intptr_t kNumTemps = 0;
+ const intptr_t kNumTemps = op_kind() == Token::kADD ? 1 : 0;
LocationSummary* summary =
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
summary->set_in(0, Location::RequiresRegister());
@@ -2408,8 +2508,7 @@
if (null_check()) {
Label* deopt = compiler->AddDeoptStub(deopt_id(),
kDeoptCheckClass);
- __ BranchEqual(locs()->in(0).reg(),
- reinterpret_cast<intptr_t>(Object::null()), deopt);
+ __ beq(locs()->in(0).reg(), NULLREG, deopt);
return;
}
@@ -2608,14 +2707,6 @@
void GotoInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
__ TraceSimMsg("GotoInstr");
- if (!compiler->is_optimizing()) {
- // Add deoptimization descriptor for deoptimizing instructions that may
- // be inserted before this instruction.
- compiler->AddCurrentDescriptor(PcDescriptors::kDeopt,
- GetDeoptId(),
- 0); // No token position.
- }
-
if (HasParallelMove()) {
compiler->parallel_move_resolver()->EmitNativeCode(parallel_move());
}
@@ -2662,33 +2753,13 @@
if (compiler->CanFallThroughTo(false_successor())) {
// If the next block is the false successor we will fall through to it.
Label* label = compiler->GetJumpLabel(true_successor());
- switch (true_condition) {
- case EQ: __ beq(CMPRES, ZR, label); break;
- case NE: __ bne(CMPRES, ZR, label); break;
- case GT: __ bgtz(CMPRES, label); break;
- case GE: __ bgez(CMPRES, label); break;
- case LT: __ bltz(CMPRES, label); break;
- case LE: __ blez(CMPRES, label); break;
- default:
- UNREACHABLE();
- break;
- }
+ EmitBranchAfterCompare(compiler, true_condition, label);
} else {
// If the next block is the true successor we negate comparison and fall
// through to it.
Condition false_condition = NegateCondition(true_condition);
Label* label = compiler->GetJumpLabel(false_successor());
- switch (false_condition) {
- case EQ: __ beq(CMPRES, ZR, label); break;
- case NE: __ bne(CMPRES, ZR, label); break;
- case GT: __ bgtz(CMPRES, label); break;
- case GE: __ bgez(CMPRES, label); break;
- case LT: __ bltz(CMPRES, label); break;
- case LE: __ blez(CMPRES, label); break;
- default:
- UNREACHABLE();
- break;
- }
+ EmitBranchAfterCompare(compiler, false_condition, label);
// Fall through or jump to the true successor.
if (!compiler->CanFallThroughTo(true_successor())) {
__ b(compiler->GetJumpLabel(true_successor()));
@@ -2858,11 +2929,11 @@
Register dest_reg = locs()->in(1).reg();
if (value()->NeedsStoreBuffer()) {
- __ StoreIntoObject(dest_reg, FieldAddress(dest_reg, offset_in_bytes()),
- value_reg);
+ __ StoreIntoObject(dest_reg,
+ FieldAddress(dest_reg, offset_in_bytes()), value_reg);
} else {
- __ StoreIntoObjectNoBarrier(
- dest_reg, FieldAddress(dest_reg, offset_in_bytes()), value_reg);
+ __ StoreIntoObjectNoBarrier(dest_reg,
+ FieldAddress(dest_reg, offset_in_bytes()), value_reg);
}
}
diff --git a/runtime/vm/intermediate_language_x64.cc b/runtime/vm/intermediate_language_x64.cc
index 6cb751f..6318124 100644
--- a/runtime/vm/intermediate_language_x64.cc
+++ b/runtime/vm/intermediate_language_x64.cc
@@ -785,6 +785,25 @@
}
+static Condition FlipCondition(Condition condition) {
+ switch (condition) {
+ case EQUAL: return EQUAL;
+ case NOT_EQUAL: return NOT_EQUAL;
+ case LESS: return GREATER;
+ case LESS_EQUAL: return GREATER_EQUAL;
+ case GREATER: return LESS;
+ case GREATER_EQUAL: return LESS_EQUAL;
+ case BELOW: return ABOVE;
+ case BELOW_EQUAL: return ABOVE_EQUAL;
+ case ABOVE: return BELOW;
+ case ABOVE_EQUAL: return BELOW_EQUAL;
+ default:
+ UNIMPLEMENTED();
+ return EQUAL;
+ }
+}
+
+
static void EmitSmiComparisonOp(FlowGraphCompiler* compiler,
const LocationSummary& locs,
Token::Kind kind,
@@ -797,7 +816,7 @@
if (left.IsConstant()) {
__ CompareObject(right.reg(), left.constant());
- true_condition = FlowGraphCompiler::FlipCondition(true_condition);
+ true_condition = FlipCondition(true_condition);
} else if (right.IsConstant()) {
__ CompareObject(left.reg(), right.constant());
} else if (right.IsStackSlot()) {
@@ -1866,35 +1885,33 @@
// 'instantiator_reg' is the instantiator AbstractTypeArguments object
// (or null).
- if (!type_arguments().IsUninstantiatedIdentity() &&
- !type_arguments().CanShareInstantiatorTypeArguments(
- instantiator_class())) {
- // If the instantiator is null and if the type argument vector
- // instantiated from null becomes a vector of dynamic, then use null as
- // the type arguments.
- Label type_arguments_instantiated;
- const intptr_t len = type_arguments().Length();
- if (type_arguments().IsRawInstantiatedRaw(len)) {
- const Immediate& raw_null =
- Immediate(reinterpret_cast<intptr_t>(Object::null()));
- __ cmpq(instantiator_reg, raw_null);
- __ j(EQUAL, &type_arguments_instantiated, Assembler::kNearJump);
- }
- // Instantiate non-null type arguments.
- // A runtime call to instantiate the type arguments is required.
- __ PushObject(Object::ZoneHandle()); // Make room for the result.
- __ PushObject(type_arguments());
- __ pushq(instantiator_reg); // Push instantiator type arguments.
- compiler->GenerateCallRuntime(token_pos(),
- deopt_id(),
- kInstantiateTypeArgumentsRuntimeEntry,
- locs());
- __ Drop(2); // Drop instantiator and uninstantiated type arguments.
- __ popq(result_reg); // Pop instantiated type arguments.
- __ Bind(&type_arguments_instantiated);
+ ASSERT(!type_arguments().IsUninstantiatedIdentity() &&
+ !type_arguments().CanShareInstantiatorTypeArguments(
+ instantiator_class()));
+ // If the instantiator is null and if the type argument vector
+ // instantiated from null becomes a vector of dynamic, then use null as
+ // the type arguments.
+ Label type_arguments_instantiated;
+ const intptr_t len = type_arguments().Length();
+ if (type_arguments().IsRawInstantiatedRaw(len)) {
+ const Immediate& raw_null =
+ Immediate(reinterpret_cast<intptr_t>(Object::null()));
+ __ cmpq(instantiator_reg, raw_null);
+ __ j(EQUAL, &type_arguments_instantiated, Assembler::kNearJump);
}
+ // Instantiate non-null type arguments.
+ // A runtime call to instantiate the type arguments is required.
+ __ PushObject(Object::ZoneHandle()); // Make room for the result.
+ __ PushObject(type_arguments());
+ __ pushq(instantiator_reg); // Push instantiator type arguments.
+ compiler->GenerateCallRuntime(token_pos(),
+ deopt_id(),
+ kInstantiateTypeArgumentsRuntimeEntry,
+ locs());
+ __ Drop(2); // Drop instantiator and uninstantiated type arguments.
+ __ popq(result_reg); // Pop instantiated type arguments.
+ __ Bind(&type_arguments_instantiated);
ASSERT(instantiator_reg == result_reg);
- // 'result_reg': Instantiated type arguments.
}
@@ -2167,11 +2184,7 @@
__ j(NEGATIVE, deopt);
return;
}
- intptr_t tmp = (left_int > 0) ? left_int : ~left_int;
- intptr_t max_right = kSmiBits;
- while ((tmp >>= 1) != 0) {
- max_right--;
- }
+ const intptr_t max_right = kSmiBits - Utils::HighestBit(left_int);
const bool right_needs_check =
(right_range == NULL) ||
!right_range->IsWithin(0, max_right - 1);
@@ -2303,7 +2316,12 @@
LocationSummary* summary =
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
summary->set_in(0, Location::RequiresRegister());
- summary->set_in(1, Location::RegisterOrSmiConstant(right()));
+ ConstantInstr* constant = right()->definition()->AsConstant();
+ if (constant != NULL) {
+ summary->set_in(1, Location::RegisterOrSmiConstant(right()));
+ } else {
+ summary->set_in(1, Location::PrefersRegister());
+ }
summary->set_out(Location::SameAsFirstInput());
return summary;
}
@@ -2427,8 +2445,51 @@
break;
}
return;
- }
+ } // locs()->in(1).IsConstant().
+
+ if (locs()->in(1).IsStackSlot()) {
+ const Address& right = locs()->in(1).ToStackSlotAddress();
+ switch (op_kind()) {
+ case Token::kADD: {
+ __ addq(left, right);
+ if (deopt != NULL) __ j(OVERFLOW, deopt);
+ break;
+ }
+ case Token::kSUB: {
+ __ subq(left, right);
+ if (deopt != NULL) __ j(OVERFLOW, deopt);
+ break;
+ }
+ case Token::kMUL: {
+ __ SmiUntag(left);
+ __ imulq(left, right);
+ if (deopt != NULL) __ j(OVERFLOW, deopt);
+ break;
+ }
+ case Token::kBIT_AND: {
+ // No overflow check.
+ __ andq(left, right);
+ break;
+ }
+ case Token::kBIT_OR: {
+ // No overflow check.
+ __ orq(left, right);
+ break;
+ }
+ case Token::kBIT_XOR: {
+ // No overflow check.
+ __ xorq(left, right);
+ break;
+ }
+ default:
+ UNREACHABLE();
+ break;
+ }
+ return;
+ } // locs()->in(1).IsStackSlot().
+
+ // if locs()->in(1).IsRegister.
Register right = locs()->in(1).reg();
switch (op_kind()) {
case Token::kADD: {
@@ -4069,14 +4130,6 @@
void GotoInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- if (!compiler->is_optimizing()) {
- // Add deoptimization descriptor for deoptimizing instructions that may
- // be inserted before this instruction.
- compiler->AddCurrentDescriptor(PcDescriptors::kDeopt,
- GetDeoptId(),
- 0); // No token position.
- }
-
if (HasParallelMove()) {
compiler->parallel_move_resolver()->EmitNativeCode(parallel_move());
}
diff --git a/runtime/vm/intrinsifier_arm.cc b/runtime/vm/intrinsifier_arm.cc
index 49d87c0..694f64b 100644
--- a/runtime/vm/intrinsifier_arm.cc
+++ b/runtime/vm/intrinsifier_arm.cc
@@ -6,297 +6,1362 @@
#if defined(TARGET_ARCH_ARM)
#include "vm/intrinsifier.h"
+
+#include "vm/assembler.h"
+#include "vm/flow_graph_compiler.h"
#include "vm/object.h"
+#include "vm/object_store.h"
+#include "vm/symbols.h"
namespace dart {
+DECLARE_FLAG(bool, enable_type_checks);
+
+
+#define __ assembler->
+
bool Intrinsifier::ObjectArray_Allocate(Assembler* assembler) {
+ const intptr_t kTypeArgumentsOffset = 1 * kWordSize;
+ const intptr_t kArrayLengthOffset = 0 * kWordSize;
+ Label fall_through;
+
+ // Compute the size to be allocated, it is based on the array length
+ // and is computed as:
+ // RoundedAllocationSize((array_length * kwordSize) + sizeof(RawArray)).
+ __ ldr(R3, Address(SP, kArrayLengthOffset)); // Array length.
+
+ // Check that length is a positive Smi.
+ __ tst(R3, ShifterOperand(kSmiTagMask));
+ __ b(&fall_through, NE);
+ __ cmp(R3, ShifterOperand(0));
+ __ b(&fall_through, LT);
+
+ // Check for maximum allowed length.
+ const intptr_t max_len =
+ reinterpret_cast<int32_t>(Smi::New(Array::kMaxElements));
+ __ CompareImmediate(R3, max_len);
+ __ b(&fall_through, GT);
+
+ const intptr_t fixed_size = sizeof(RawArray) + kObjectAlignment - 1;
+ __ LoadImmediate(R2, fixed_size);
+ __ add(R2, R2, ShifterOperand(R3, LSL, 1)); // R3 is a Smi.
+ ASSERT(kSmiTagShift == 1);
+ __ bic(R2, R2, ShifterOperand(kObjectAlignment - 1));
+
+ // R2: Allocation size.
+
+ Isolate* isolate = Isolate::Current();
+ Heap* heap = isolate->heap();
+
+ __ LoadImmediate(R6, heap->TopAddress());
+ __ ldr(R0, Address(R6, 0)); // Potential new object start.
+ __ adds(R1, R0, ShifterOperand(R2)); // Potential next object start.
+ __ b(&fall_through, VS);
+
+ // Check if the allocation fits into the remaining space.
+ // R0: potential new object start.
+ // R1: potential next object start.
+ // R2: allocation size.
+ __ LoadImmediate(R3, heap->EndAddress());
+ __ ldr(R3, Address(R3, 0));
+ __ cmp(R1, ShifterOperand(R3));
+ __ b(&fall_through, CS);
+
+ // Successfully allocated the object(s), now update top to point to
+ // next object start and initialize the object.
+ __ str(R1, Address(R6, 0));
+ __ add(R0, R0, ShifterOperand(kHeapObjectTag));
+
+ // Initialize the tags.
+ // R0: new object start as a tagged pointer.
+ // R1: new object end address.
+ // R2: allocation size.
+ {
+ const intptr_t shift = RawObject::kSizeTagBit - kObjectAlignmentLog2;
+ const Class& cls = Class::Handle(isolate->object_store()->array_class());
+
+ __ CompareImmediate(R2, RawObject::SizeTag::kMaxSizeTag);
+ __ mov(R2, ShifterOperand(R2, LSL, shift), LS);
+ __ mov(R2, ShifterOperand(0), HI);
+
+ // Get the class index and insert it into the tags.
+ // R2: size and bit tags.
+ __ LoadImmediate(TMP, RawObject::ClassIdTag::encode(cls.id()));
+ __ orr(R2, R2, ShifterOperand(TMP));
+ __ str(R2, FieldAddress(R0, Array::tags_offset())); // Store tags.
+ }
+
+ // R0: new object start as a tagged pointer.
+ // R1: new object end address.
+ // Store the type argument field.
+ __ ldr(R2, Address(SP, kTypeArgumentsOffset)); // Type argument.
+ __ StoreIntoObjectNoBarrier(R0,
+ FieldAddress(R0, Array::type_arguments_offset()),
+ R2);
+
+ // Set the length field.
+ __ ldr(R2, Address(SP, kArrayLengthOffset)); // Array Length.
+ __ StoreIntoObjectNoBarrier(R0,
+ FieldAddress(R0, Array::length_offset()),
+ R2);
+
+ // Initialize all array elements to raw_null.
+ // R0: new object start as a tagged pointer.
+ // R1: new object end address.
+ // R2: iterator which initially points to the start of the variable
+ // data area to be initialized.
+ // R3: null
+ __ LoadImmediate(R3, reinterpret_cast<intptr_t>(Object::null()));
+ __ AddImmediate(R2, R0, sizeof(RawArray) - kHeapObjectTag);
+
+ Label init_loop;
+ __ Bind(&init_loop);
+ __ cmp(R2, ShifterOperand(R1));
+ __ str(R3, Address(R2, 0), CC);
+ __ AddImmediate(R2, kWordSize, CC);
+ __ b(&init_loop, CC);
+
+ __ Ret(); // Returns the newly allocated object in R0.
+ __ Bind(&fall_through);
return false;
}
bool Intrinsifier::Array_getLength(Assembler* assembler) {
- return false;
+ __ ldr(R0, Address(SP, 0 * kWordSize));
+ __ ldr(R0, FieldAddress(R0, Array::length_offset()));
+ __ Ret();
+ return true;
}
bool Intrinsifier::ImmutableArray_getLength(Assembler* assembler) {
- return false;
+ return Array_getLength(assembler);
}
bool Intrinsifier::Array_getIndexed(Assembler* assembler) {
+ Label fall_through;
+
+ __ ldr(R0, Address(SP, + 0 * kWordSize)); // Index
+ __ ldr(R1, Address(SP, + 1 * kWordSize)); // Array
+
+ __ tst(R0, ShifterOperand(kSmiTagMask));
+ __ b(&fall_through, NE); // Index is not an smi, fall through
+
+ // range check
+ __ ldr(R6, FieldAddress(R1, Array::length_offset()));
+ __ cmp(R0, ShifterOperand(R6));
+
+ ASSERT(kSmiTagShift == 1);
+ // array element at R1 + R0*2 + Array::data_offset - 1
+ __ add(R6, R1, ShifterOperand(R0, LSL, 1), CC);
+ __ ldr(R0, FieldAddress(R6, Array::data_offset()), CC);
+ __ bx(LR, CC);
+ __ Bind(&fall_through);
return false;
}
bool Intrinsifier::ImmutableArray_getIndexed(Assembler* assembler) {
- return false;
+ return Array_getIndexed(assembler);
}
+static intptr_t ComputeObjectArrayTypeArgumentsOffset() {
+ const Library& core_lib = Library::Handle(Library::CoreLibrary());
+ const Class& cls =
+ Class::Handle(core_lib.LookupClassAllowPrivate(Symbols::ObjectArray()));
+ ASSERT(!cls.IsNull());
+ ASSERT(cls.HasTypeArguments());
+ ASSERT(cls.NumTypeArguments() == 1);
+ const intptr_t field_offset = cls.type_arguments_field_offset();
+ ASSERT(field_offset != Class::kNoTypeArguments);
+ return field_offset;
+}
+
+
+// Intrinsify only for Smi value and index. Non-smi values need a store buffer
+// update. Array length is always a Smi.
bool Intrinsifier::Array_setIndexed(Assembler* assembler) {
+ Label fall_through;
+
+ if (FLAG_enable_type_checks) {
+ const intptr_t type_args_field_offset =
+ ComputeObjectArrayTypeArgumentsOffset();
+ // Inline simple tests (Smi, null), fallthrough if not positive.
+ const int32_t raw_null = reinterpret_cast<intptr_t>(Object::null());
+ Label checked_ok;
+ __ ldr(R2, Address(SP, 0 * kWordSize)); // Value.
+
+ // Null value is valid for any type.
+ __ CompareImmediate(R2, raw_null);
+ __ b(&checked_ok, EQ);
+
+ __ ldr(R1, Address(SP, 2 * kWordSize)); // Array.
+ __ ldr(R1, FieldAddress(R1, type_args_field_offset));
+
+ // R1: Type arguments of array.
+ __ CompareImmediate(R1, raw_null);
+ __ b(&checked_ok, EQ);
+
+ // Check if it's dynamic.
+ // For now handle only TypeArguments and bail out if InstantiatedTypeArgs.
+ __ CompareClassId(R1, kTypeArgumentsCid, R0);
+ __ b(&fall_through, NE);
+ // Get type at index 0.
+ __ ldr(R0, FieldAddress(R1, TypeArguments::type_at_offset(0)));
+ __ CompareObject(R0, Type::ZoneHandle(Type::DynamicType()));
+ __ b(&checked_ok, EQ);
+
+ // Check for int and num.
+ __ tst(R2, ShifterOperand(kSmiTagMask)); // Value is Smi?
+ __ b(&fall_through, NE); // Non-smi value.
+ __ CompareObject(R0, Type::ZoneHandle(Type::IntType()));
+ __ b(&checked_ok, EQ);
+ __ CompareObject(R0, Type::ZoneHandle(Type::Number()));
+ __ b(&fall_through, NE);
+ __ Bind(&checked_ok);
+ }
+ __ ldr(R1, Address(SP, 1 * kWordSize)); // Index.
+ __ tst(R1, ShifterOperand(kSmiTagMask));
+ // Index not Smi.
+ __ b(&fall_through, NE);
+ __ ldr(R0, Address(SP, 2 * kWordSize)); // Array.
+
+ // Range check.
+ __ ldr(R3, FieldAddress(R0, Array::length_offset())); // Array length.
+ __ cmp(R1, ShifterOperand(R3));
+ // Runtime throws exception.
+ __ b(&fall_through, CS);
+
+ // Note that R1 is Smi, i.e, times 2.
+ ASSERT(kSmiTagShift == 1);
+ // Destroy R2 as we will not continue in the function.
+ __ ldr(R2, Address(SP, 0 * kWordSize)); // Value.
+ __ add(R1, R0, ShifterOperand(R1, LSL, 1)); // R1 is Smi.
+ __ StoreIntoObject(R0,
+ FieldAddress(R1, Array::data_offset()),
+ R2);
+ // Caller is responsible of preserving the value if necessary.
+ __ Ret();
+ __ Bind(&fall_through);
return false;
}
+// Allocate a GrowableObjectArray using the backing array specified.
+// On stack: type argument (+1), data (+0).
bool Intrinsifier::GrowableArray_Allocate(Assembler* assembler) {
+ // The newly allocated object is returned in R0.
+ const intptr_t kTypeArgumentsOffset = 1 * kWordSize;
+ const intptr_t kArrayOffset = 0 * kWordSize;
+ Label fall_through;
+
+ // Compute the size to be allocated, it is based on the array length
+ // and is computed as:
+ // RoundedAllocationSize(sizeof(RawGrowableObjectArray)) +
+ intptr_t fixed_size = GrowableObjectArray::InstanceSize();
+
+ Isolate* isolate = Isolate::Current();
+ Heap* heap = isolate->heap();
+
+ __ LoadImmediate(R2, heap->TopAddress());
+ __ ldr(R0, Address(R2, 0));
+ __ AddImmediate(R1, R0, fixed_size);
+
+ // Check if the allocation fits into the remaining space.
+ // R0: potential new backing array object start.
+ // R1: potential next object start.
+ __ LoadImmediate(R3, heap->EndAddress());
+ __ ldr(R3, Address(R3, 0));
+ __ cmp(R1, ShifterOperand(R3));
+ __ b(&fall_through, CS);
+
+ // Successfully allocated the object(s), now update top to point to
+ // next object start and initialize the object.
+ __ str(R1, Address(R2, 0));
+ __ AddImmediate(R0, kHeapObjectTag);
+
+ // Initialize the tags.
+ // R0: new growable array object start as a tagged pointer.
+ const Class& cls = Class::Handle(
+ isolate->object_store()->growable_object_array_class());
+ uword tags = 0;
+ tags = RawObject::SizeTag::update(fixed_size, tags);
+ tags = RawObject::ClassIdTag::update(cls.id(), tags);
+ __ LoadImmediate(R1, tags);
+ __ str(R1, FieldAddress(R0, GrowableObjectArray::tags_offset()));
+
+ // Store backing array object in growable array object.
+ __ ldr(R1, Address(SP, kArrayOffset)); // Data argument.
+ // R0 is new, no barrier needed.
+ __ StoreIntoObjectNoBarrier(
+ R0,
+ FieldAddress(R0, GrowableObjectArray::data_offset()),
+ R1);
+
+ // R0: new growable array object start as a tagged pointer.
+ // Store the type argument field in the growable array object.
+ __ ldr(R1, Address(SP, kTypeArgumentsOffset)); // Type argument.
+ __ StoreIntoObjectNoBarrier(
+ R0,
+ FieldAddress(R0, GrowableObjectArray::type_arguments_offset()),
+ R1);
+
+ // Set the length field in the growable array object to 0.
+ __ LoadImmediate(R1, 0);
+ __ str(R1, FieldAddress(R0, GrowableObjectArray::length_offset()));
+ __ Ret(); // Returns the newly allocated object in R0.
+
+ __ Bind(&fall_through);
return false;
}
bool Intrinsifier::GrowableArray_getLength(Assembler* assembler) {
- return false;
+ __ ldr(R0, Address(SP, 0 * kWordSize));
+ __ ldr(R0, FieldAddress(R0, GrowableObjectArray::length_offset()));
+ __ Ret();
+ return true;
}
bool Intrinsifier::GrowableArray_getCapacity(Assembler* assembler) {
- return false;
+ __ ldr(R0, Address(SP, 0 * kWordSize));
+ __ ldr(R0, FieldAddress(R0, GrowableObjectArray::data_offset()));
+ __ ldr(R0, FieldAddress(R0, Array::length_offset()));
+ __ Ret();
+ return true;
}
bool Intrinsifier::GrowableArray_getIndexed(Assembler* assembler) {
+ Label fall_through;
+
+ __ ldr(R0, Address(SP, + 0 * kWordSize)); // Index
+ __ ldr(R1, Address(SP, + 1 * kWordSize)); // Array
+
+ __ tst(R0, ShifterOperand(kSmiTagMask));
+ __ b(&fall_through, NE); // Index is not an smi, fall through
+
+ // range check
+ __ ldr(R6, FieldAddress(R1, GrowableObjectArray::length_offset()));
+ __ cmp(R0, ShifterOperand(R6));
+
+ ASSERT(kSmiTagShift == 1);
+ // array element at R6 + R0 * 2 + Array::data_offset - 1
+ __ ldr(R6, FieldAddress(R1, GrowableObjectArray::data_offset()), CC); // data
+ __ add(R6, R6, ShifterOperand(R0, LSL, 1), CC);
+ __ ldr(R0, FieldAddress(R6, Array::data_offset()), CC);
+ __ bx(LR, CC);
+ __ Bind(&fall_through);
return false;
}
+// Set value into growable object array at specified index.
+// On stack: growable array (+2), index (+1), value (+0).
bool Intrinsifier::GrowableArray_setIndexed(Assembler* assembler) {
+ if (FLAG_enable_type_checks) {
+ return false;
+ }
+ Label fall_through;
+ __ ldr(R1, Address(SP, 1 * kWordSize)); // Index.
+ __ ldr(R0, Address(SP, 2 * kWordSize)); // GrowableArray.
+ __ tst(R1, ShifterOperand(kSmiTagMask));
+ __ b(&fall_through, NE); // Non-smi index.
+ // Range check using _length field.
+ __ ldr(R2, FieldAddress(R0, GrowableObjectArray::length_offset()));
+ __ cmp(R1, ShifterOperand(R2));
+ // Runtime throws exception.
+ __ b(&fall_through, CS);
+ __ ldr(R0, FieldAddress(R0, GrowableObjectArray::data_offset())); // data.
+ __ ldr(R2, Address(SP, 0 * kWordSize)); // Value.
+ // Note that R1 is Smi, i.e, times 2.
+ ASSERT(kSmiTagShift == 1);
+ __ add(R1, R0, ShifterOperand(R1, LSL, 1));
+ __ StoreIntoObject(R0,
+ FieldAddress(R1, Array::data_offset()),
+ R2);
+ __ Ret();
+ __ Bind(&fall_through);
return false;
}
+// Set length of growable object array. The length cannot
+// be greater than the length of the data container.
+// On stack: growable array (+1), length (+0).
bool Intrinsifier::GrowableArray_setLength(Assembler* assembler) {
+ __ ldr(R0, Address(SP, 1 * kWordSize)); // Growable array.
+ __ ldr(R1, Address(SP, 0 * kWordSize)); // Length value.
+ __ tst(R1, ShifterOperand(kSmiTagMask)); // Check for Smi.
+ __ str(R1, FieldAddress(R0, GrowableObjectArray::length_offset()), EQ);
+ __ bx(LR, EQ);
+ // Fall through on non-Smi.
return false;
}
+// Set data of growable object array.
+// On stack: growable array (+1), data (+0).
bool Intrinsifier::GrowableArray_setData(Assembler* assembler) {
+ if (FLAG_enable_type_checks) {
+ return false;
+ }
+ Label fall_through;
+ __ ldr(R1, Address(SP, 0 * kWordSize)); // Data.
+ // Check that data is an ObjectArray.
+ __ tst(R1, ShifterOperand(kSmiTagMask));
+ __ b(&fall_through, EQ); // Data is Smi.
+ __ CompareClassId(R1, kArrayCid, R0);
+ __ b(&fall_through, NE);
+ __ ldr(R0, Address(SP, 1 * kWordSize)); // Growable array.
+ __ StoreIntoObject(R0,
+ FieldAddress(R0, GrowableObjectArray::data_offset()),
+ R1);
+ __ Ret();
+ __ Bind(&fall_through);
return false;
}
+// Add an element to growable array if it doesn't need to grow, otherwise
+// call into regular code.
+// On stack: growable array (+1), value (+0).
bool Intrinsifier::GrowableArray_add(Assembler* assembler) {
+ // In checked mode we need to type-check the incoming argument.
+ if (FLAG_enable_type_checks) return false;
+ Label fall_through;
+ // R0: Array.
+ __ ldr(R0, Address(SP, 1 * kWordSize));
+ // R1: length.
+ __ ldr(R1, FieldAddress(R0, GrowableObjectArray::length_offset()));
+ // R2: data.
+ __ ldr(R2, FieldAddress(R0, GrowableObjectArray::data_offset()));
+ // R3: capacity.
+ __ ldr(R3, FieldAddress(R2, Array::length_offset()));
+ // Compare length with capacity.
+ __ cmp(R1, ShifterOperand(R3));
+ __ b(&fall_through, EQ); // Must grow data.
+ const int32_t value_one = reinterpret_cast<int32_t>(Smi::New(1));
+ // len = len + 1;
+ __ add(R3, R1, ShifterOperand(value_one));
+ __ str(R3, FieldAddress(R0, GrowableObjectArray::length_offset()));
+ __ ldr(R0, Address(SP, 0 * kWordSize)); // Value.
+ ASSERT(kSmiTagShift == 1);
+ __ add(R1, R2, ShifterOperand(R1, LSL, 1));
+ __ StoreIntoObject(R2,
+ FieldAddress(R1, Array::data_offset()),
+ R0);
+ const int32_t raw_null = reinterpret_cast<int32_t>(Object::null());
+ __ LoadImmediate(R0, raw_null);
+ __ Ret();
+ __ Bind(&fall_through);
return false;
}
+#define TYPED_ARRAY_ALLOCATION(type_name, cid, max_len, scale_shift) \
+ Label fall_through; \
+ const intptr_t kArrayLengthStackOffset = 0 * kWordSize; \
+ __ ldr(R2, Address(SP, kArrayLengthStackOffset)); /* Array length. */ \
+ /* Check that length is a positive Smi. */ \
+ /* R2: requested array length argument. */ \
+ __ tst(R2, ShifterOperand(kSmiTagMask)); \
+ __ b(&fall_through, NE); \
+ __ CompareImmediate(R2, 0); \
+ __ b(&fall_through, LT); \
+ __ SmiUntag(R2); \
+ /* Check for maximum allowed length. */ \
+ /* R2: untagged array length. */ \
+ __ CompareImmediate(R2, max_len); \
+ __ b(&fall_through, GT); \
+ __ mov(R2, ShifterOperand(R2, LSL, scale_shift)); \
+ const intptr_t fixed_size = sizeof(Raw##type_name) + kObjectAlignment - 1; \
+ __ AddImmediate(R2, fixed_size); \
+ __ bic(R2, R2, ShifterOperand(kObjectAlignment - 1)); \
+ Heap* heap = Isolate::Current()->heap(); \
+ \
+ __ LoadImmediate(R0, heap->TopAddress()); \
+ __ ldr(R0, Address(R0, 0)); \
+ \
+ /* R2: allocation size. */ \
+ __ add(R1, R0, ShifterOperand(R2)); \
+ __ b(&fall_through, VS); \
+ \
+ /* Check if the allocation fits into the remaining space. */ \
+ /* R0: potential new object start. */ \
+ /* R1: potential next object start. */ \
+ /* R2: allocation size. */ \
+ __ LoadImmediate(R3, heap->EndAddress()); \
+ __ ldr(R3, Address(R3, 0)); \
+ __ cmp(R1, ShifterOperand(R3)); \
+ __ b(&fall_through, CS); \
+ \
+ /* Successfully allocated the object(s), now update top to point to */ \
+ /* next object start and initialize the object. */ \
+ __ LoadImmediate(R3, heap->TopAddress()); \
+ __ str(R1, Address(R3, 0)); \
+ __ AddImmediate(R0, kHeapObjectTag); \
+ \
+ /* Initialize the tags. */ \
+ /* R0: new object start as a tagged pointer. */ \
+ /* R1: new object end address. */ \
+ /* R2: allocation size. */ \
+ { \
+ __ CompareImmediate(R2, RawObject::SizeTag::kMaxSizeTag); \
+ __ mov(R2, ShifterOperand(R2, LSL, \
+ RawObject::kSizeTagBit - kObjectAlignmentLog2), LS); \
+ __ mov(R2, ShifterOperand(0), HI); \
+ \
+ /* Get the class index and insert it into the tags. */ \
+ __ LoadImmediate(TMP, RawObject::ClassIdTag::encode(cid)); \
+ __ orr(R2, R2, ShifterOperand(TMP)); \
+ __ str(R2, FieldAddress(R0, type_name::tags_offset())); /* Tags. */ \
+ } \
+ /* Set the length field. */ \
+ /* R0: new object start as a tagged pointer. */ \
+ /* R1: new object end address. */ \
+ __ ldr(R2, Address(SP, kArrayLengthStackOffset)); /* Array length. */ \
+ __ StoreIntoObjectNoBarrier(R0, \
+ FieldAddress(R0, type_name::length_offset()), \
+ R2); \
+ /* Initialize all array elements to 0. */ \
+ /* R0: new object start as a tagged pointer. */ \
+ /* R1: new object end address. */ \
+ /* R2: iterator which initially points to the start of the variable */ \
+ /* R3: scratch register. */ \
+ /* data area to be initialized. */ \
+ __ LoadImmediate(R3, 0); \
+ __ AddImmediate(R2, R0, sizeof(Raw##type_name) - 1); \
+ Label init_loop; \
+ __ Bind(&init_loop); \
+ __ cmp(R2, ShifterOperand(R1)); \
+ __ str(R3, Address(R2, 0), CC); \
+ __ add(R2, R2, ShifterOperand(kWordSize), CC); \
+ __ b(&init_loop, CC); \
+ \
+ __ Ret(); \
+ __ Bind(&fall_through); \
+
+
+// Gets the length of a TypedData.
bool Intrinsifier::TypedData_getLength(Assembler* assembler) {
- return false;
+ __ ldr(R0, Address(SP, 0 * kWordSize));
+ __ ldr(R0, FieldAddress(R0, TypedData::length_offset()));
+ __ Ret();
+ return true;
}
+static int GetScaleFactor(intptr_t size) {
+ switch (size) {
+ case 1: return 0;
+ case 2: return 1;
+ case 4: return 2;
+ case 8: return 3;
+ case 16: return 4;
+ }
+ UNREACHABLE();
+ return -1;
+};
+
+
#define TYPED_DATA_ALLOCATOR(clazz) \
bool Intrinsifier::TypedData_##clazz##_new(Assembler* assembler) { \
+ intptr_t size = TypedData::ElementSizeInBytes(kTypedData##clazz##Cid); \
+ intptr_t max_len = TypedData::MaxElements(kTypedData##clazz##Cid); \
+ int shift = GetScaleFactor(size); \
+ TYPED_ARRAY_ALLOCATION(TypedData, kTypedData##clazz##Cid, max_len, shift); \
return false; \
} \
bool Intrinsifier::TypedData_##clazz##_factory(Assembler* assembler) { \
+ intptr_t size = TypedData::ElementSizeInBytes(kTypedData##clazz##Cid); \
+ intptr_t max_len = TypedData::MaxElements(kTypedData##clazz##Cid); \
+ int shift = GetScaleFactor(size); \
+ TYPED_ARRAY_ALLOCATION(TypedData, kTypedData##clazz##Cid, max_len, shift); \
return false; \
}
CLASS_LIST_TYPED_DATA(TYPED_DATA_ALLOCATOR)
#undef TYPED_DATA_ALLOCATOR
+// Loads args from stack into R0 and R1
+// Tests if they are smis, jumps to label not_smi if not.
+static void TestBothArgumentsSmis(Assembler* assembler, Label* not_smi) {
+ __ ldr(R0, Address(SP, + 0 * kWordSize));
+ __ ldr(R1, Address(SP, + 1 * kWordSize));
+ __ orr(TMP, R0, ShifterOperand(R1));
+ __ tst(TMP, ShifterOperand(kSmiTagMask));
+ __ b(not_smi, NE);
+ return;
+}
+
+
bool Intrinsifier::Integer_addFromInteger(Assembler* assembler) {
+ Label fall_through;
+ TestBothArgumentsSmis(assembler, &fall_through); // Checks two smis.
+ __ adds(R0, R0, ShifterOperand(R1)); // Adds.
+ __ bx(LR, VC); // Return if no overflow.
+ // Otherwise fall through.
+ __ Bind(&fall_through);
return false;
}
bool Intrinsifier::Integer_add(Assembler* assembler) {
- return false;
+ return Integer_addFromInteger(assembler);
}
bool Intrinsifier::Integer_subFromInteger(Assembler* assembler) {
+ Label fall_through;
+ TestBothArgumentsSmis(assembler, &fall_through);
+ __ subs(R0, R0, ShifterOperand(R1)); // Subtract.
+ __ bx(LR, VC); // Return if no overflow.
+ // Otherwise fall through.
+ __ Bind(&fall_through);
return false;
}
bool Intrinsifier::Integer_sub(Assembler* assembler) {
+ Label fall_through;
+ TestBothArgumentsSmis(assembler, &fall_through);
+ __ subs(R0, R1, ShifterOperand(R0)); // Subtract.
+ __ bx(LR, VC); // Return if no overflow.
+ // Otherwise fall through.
+ __ Bind(&fall_through);
return false;
}
bool Intrinsifier::Integer_mulFromInteger(Assembler* assembler) {
+ Label fall_through;
+
+ TestBothArgumentsSmis(assembler, &fall_through); // checks two smis
+ __ SmiUntag(R0); // untags R6. only want result shifted by one
+
+ __ smull(R0, IP, R0, R1); // IP:R0 <- R0 * R1.
+ __ cmp(IP, ShifterOperand(R0, ASR, 31));
+ __ bx(LR, EQ);
+ __ Bind(&fall_through); // Fall through on overflow.
return false;
}
bool Intrinsifier::Integer_mul(Assembler* assembler) {
- return false;
+ return Integer_mulFromInteger(assembler);
}
+// Optimizations:
+// - result is 0 if:
+// - left is 0
+// - left equals right
+// - result is left if
+// - left > 0 && left < right
+// R1: Tagged left (dividend).
+// R0: Tagged right (divisor).
+// Returns with result in R0, OR:
+// R1: Untagged result (remainder).
+static void EmitRemainderOperation(Assembler* assembler) {
+ Label modulo;
+ const Register left = R1;
+ const Register right = R0;
+ const Register result = R1;
+ ASSERT(left == result);
+
+ // Check for quick zero results.
+ __ cmp(left, ShifterOperand(0));
+ __ mov(R0, ShifterOperand(0), EQ);
+ __ bx(LR, EQ); // left is 0? Return 0.
+ __ cmp(left, ShifterOperand(right));
+ __ mov(R0, ShifterOperand(0), EQ);
+ __ bx(LR, EQ); // left == right? Return 0.
+
+ // Check if result should be left.
+ __ cmp(left, ShifterOperand(0));
+ __ b(&modulo, LT);
+ // left is positive.
+ __ cmp(left, ShifterOperand(right));
+ // left is less than right, result is left.
+ __ mov(R0, ShifterOperand(left), LT);
+ __ bx(LR, LT);
+
+ __ Bind(&modulo);
+ // result <- left - right * (left / right)
+ __ SmiUntag(left);
+ __ SmiUntag(right);
+ __ sdiv(TMP, left, right); // TMP <- left / right
+ __ mls(result, right, TMP, left); // result <- left - right * TMP
+ return;
+}
+
+
+// Implementation:
+// res = left % right;
+// if (res < 0) {
+// if (right < 0) {
+// res = res - right;
+// } else {
+// res = res + right;
+// }
+// }
bool Intrinsifier::Integer_modulo(Assembler* assembler) {
+ // Check to see if we have integer division
+ if (!CPUFeatures::integer_division_supported())
+ return false;
+
+ Label fall_through, subtract;
+ TestBothArgumentsSmis(assembler, &fall_through);
+ // R1: Tagged left (dividend).
+ // R0: Tagged right (divisor).
+ // Check if modulo by zero -> exception thrown in main function.
+ __ cmp(R0, ShifterOperand(0));
+ __ b(&fall_through, EQ);
+ EmitRemainderOperation(assembler);
+ // Untagged right in R0. Untagged remainder result in R1.
+
+ __ cmp(R1, ShifterOperand(0));
+ __ mov(R0, ShifterOperand(R1, LSL, 1), GE); // Tag and move result to R0.
+ __ bx(LR, GE);
+
+ // Result is negative, adjust it.
+ __ cmp(R0, ShifterOperand(0));
+ __ sub(R0, R1, ShifterOperand(R0), LT);
+ __ add(R0, R1, ShifterOperand(R0), GE);
+ __ SmiTag(R0);
+ __ Ret();
+
+ __ Bind(&fall_through);
return false;
}
bool Intrinsifier::Integer_remainder(Assembler* assembler) {
+ // Check to see if we have integer division
+ if (!CPUFeatures::integer_division_supported())
+ return false;
+
+ Label fall_through;
+ TestBothArgumentsSmis(assembler, &fall_through);
+ // R1: Tagged left (dividend).
+ // R0: Tagged right (divisor).
+ // Check if modulo by zero -> exception thrown in main function.
+ __ cmp(R0, ShifterOperand(0));
+ __ b(&fall_through, EQ);
+ EmitRemainderOperation(assembler);
+ // Untagged remainder result in R1.
+ __ mov(R0, ShifterOperand(R1, LSL, 1)); // Tag result and return.
+ __ Ret();
+
+ __ Bind(&fall_through);
return false;
}
bool Intrinsifier::Integer_truncDivide(Assembler* assembler) {
+ // Check to see if we have integer division
+ if (!CPUFeatures::integer_division_supported())
+ return false;
+
+ Label fall_through;
+
+ TestBothArgumentsSmis(assembler, &fall_through);
+ __ cmp(R0, ShifterOperand(0));
+ __ b(&fall_through, EQ); // If b is 0, fall through.
+
+ __ SmiUntag(R0);
+ __ SmiUntag(R1);
+ __ sdiv(R0, R1, R0);
+ // Check the corner case of dividing the 'MIN_SMI' with -1, in which case we
+ // cannot tag the result.
+ __ CompareImmediate(R0, 0x40000000);
+ __ SmiTag(R0, NE); // Not equal. Okay to tag and return.
+ __ bx(LR, NE); // Return.
+ __ Bind(&fall_through);
return false;
}
bool Intrinsifier::Integer_negate(Assembler* assembler) {
+ __ ldr(R0, Address(SP, + 0 * kWordSize)); // Grab first argument.
+ __ tst(R0, ShifterOperand(kSmiTagMask)); // Test for Smi.
+ __ rsb(R0, R0, ShifterOperand(0), EQ); // R0 is a Smi. R0 <- 0 - R0.
+ __ bx(LR, EQ); // Return.
+ // R0 is not a Smi. Fall through.
return false;
}
bool Intrinsifier::Integer_bitAndFromInteger(Assembler* assembler) {
+ Label fall_through;
+
+ TestBothArgumentsSmis(assembler, &fall_through); // checks two smis
+ __ and_(R0, R0, ShifterOperand(R1));
+
+ __ Ret();
+ __ Bind(&fall_through);
return false;
}
bool Intrinsifier::Integer_bitAnd(Assembler* assembler) {
- return false;
+ return Integer_bitAndFromInteger(assembler);
}
bool Intrinsifier::Integer_bitOrFromInteger(Assembler* assembler) {
+ Label fall_through;
+
+ TestBothArgumentsSmis(assembler, &fall_through); // checks two smis
+ __ orr(R0, R0, ShifterOperand(R1));
+
+ __ Ret();
+ __ Bind(&fall_through);
return false;
}
bool Intrinsifier::Integer_bitOr(Assembler* assembler) {
- return false;
+ return Integer_bitOrFromInteger(assembler);
}
bool Intrinsifier::Integer_bitXorFromInteger(Assembler* assembler) {
+ Label fall_through;
+ __ Untested("Intrinsifier::Integer_bitXorFromInteger");
+
+ TestBothArgumentsSmis(assembler, &fall_through); // checks two smis
+ __ eor(R0, R0, ShifterOperand(R1));
+
+ __ Ret();
+ __ Bind(&fall_through);
return false;
}
bool Intrinsifier::Integer_bitXor(Assembler* assembler) {
- return false;
+ return Integer_bitXorFromInteger(assembler);
}
bool Intrinsifier::Integer_shl(Assembler* assembler) {
+ ASSERT(kSmiTagShift == 1);
+ ASSERT(kSmiTag == 0);
+ Label fall_through;
+
+ TestBothArgumentsSmis(assembler, &fall_through);
+ __ CompareImmediate(R0, Smi::RawValue(Smi::kBits));
+ __ b(&fall_through, HI);
+
+ __ SmiUntag(R0);
+
+ // Check for overflow by shifting left and shifting back arithmetically.
+ // If the result is different from the original, there was overflow.
+ __ mov(IP, ShifterOperand(R1, LSL, R0));
+ __ cmp(R1, ShifterOperand(IP, ASR, R0));
+
+ // No overflow, result in R0.
+ __ mov(R0, ShifterOperand(R1, LSL, R0), EQ);
+ __ bx(LR, EQ);
+
+ // Arguments are Smi but the shift produced an overflow to Mint.
+ __ CompareImmediate(R6, 0);
+ __ b(&fall_through, LT);
+ __ SmiUntag(R6);
+
+ // Pull off high bits that will be shifted off of R6 by making a mask
+ // ((1 << R0) - 1), shifting it to the left, masking R6, then shifting back.
+ // high bits = (((1 << R0) - 1) << (32 - R0)) & R6) >> (32 - R0)
+ // lo bits = R6 << R0
+ __ LoadImmediate(R7, 1);
+ __ mov(R7, ShifterOperand(R7, LSL, R0)); // R7 <- 1 << R0
+ __ sub(R7, R7, ShifterOperand(1)); // R7 <- R7 - 1
+ __ rsb(R8, R0, ShifterOperand(32)); // R8 <- 32 - R0
+ __ mov(R7, ShifterOperand(R7, LSL, R8)); // R7 <- R7 << R8
+ __ and_(R7, R6, ShifterOperand(R7)); // R7 <- R7 & R6
+ __ mov(R7, ShifterOperand(R7, LSR, R8)); // R7 <- R7 >> R8
+ // Now R7 has the bits that fall off of R6 on a left shift.
+ __ mov(R1, ShifterOperand(R6, LSL, R0)); // R1 gets the low bits.
+
+ const Class& mint_class = Class::Handle(
+ Isolate::Current()->object_store()->mint_class());
+ __ TryAllocate(mint_class, &fall_through, R0);
+
+
+ __ str(R1, FieldAddress(R0, Mint::value_offset()));
+ __ str(R7, FieldAddress(R0, Mint::value_offset() + kWordSize));
+ __ Ret();
+ __ Bind(&fall_through);
+ return false;
+}
+
+
+static void Get64SmiOrMint(Assembler* assembler,
+ Register res_hi,
+ Register res_lo,
+ Register reg,
+ Label* not_smi_or_mint) {
+ Label not_smi, done;
+ __ tst(reg, ShifterOperand(kSmiTagMask));
+ __ b(¬_smi, NE);
+ __ SmiUntag(reg);
+
+ // Sign extend to 64 bit
+ __ mov(res_lo, ShifterOperand(reg));
+ __ mov(res_hi, ShifterOperand(res_lo, ASR, 31));
+ __ b(&done);
+
+ __ Bind(¬_smi);
+ __ CompareClassId(reg, kMintCid, res_lo);
+ __ b(not_smi_or_mint, NE);
+
+ // Mint.
+ __ ldr(res_lo, FieldAddress(reg, Mint::value_offset()));
+ __ ldr(res_hi, FieldAddress(reg, Mint::value_offset() + kWordSize));
+ __ Bind(&done);
+ return;
+}
+
+
+static bool CompareIntegers(Assembler* assembler, Condition true_condition) {
+ Label try_mint_smi, is_true, is_false, drop_two_fall_through, fall_through;
+ TestBothArgumentsSmis(assembler, &try_mint_smi);
+ // R0 contains the right argument. R1 contains left argument
+
+ __ cmp(R1, ShifterOperand(R0));
+ __ b(&is_true, true_condition);
+ __ Bind(&is_false);
+ __ LoadObject(R0, Bool::False());
+ __ Ret();
+ __ Bind(&is_true);
+ __ LoadObject(R0, Bool::True());
+ __ Ret();
+
+ // 64-bit comparison
+ Condition hi_true_cond, hi_false_cond, lo_false_cond;
+ switch (true_condition) {
+ case LT:
+ case LE:
+ hi_true_cond = LT;
+ hi_false_cond = GT;
+ lo_false_cond = (true_condition == LT) ? CS : HI;
+ break;
+ case GT:
+ case GE:
+ hi_true_cond = GT;
+ hi_false_cond = LT;
+ lo_false_cond = (true_condition == GT) ? LS : CC;
+ break;
+ default:
+ UNREACHABLE();
+ hi_true_cond = hi_false_cond = lo_false_cond = VS;
+ }
+
+ __ Bind(&try_mint_smi);
+ // Get left as 64 bit integer.
+ Get64SmiOrMint(assembler, R3, R2, R1, &fall_through);
+ // Get right as 64 bit integer.
+ Get64SmiOrMint(assembler, R7, R6, R0, &fall_through);
+ // R3: left high.
+ // R2: left low.
+ // R7: right high.
+ // R6: right low.
+
+ __ cmp(R3, ShifterOperand(R7)); // Compare left hi, right high.
+ __ b(&is_false, hi_false_cond);
+ __ b(&is_true, hi_true_cond);
+ __ cmp(R2, ShifterOperand(R6)); // Compare left lo, right lo.
+ __ b(&is_false, lo_false_cond);
+ // Else is true.
+ __ b(&is_true);
+
+ __ Bind(&fall_through);
return false;
}
bool Intrinsifier::Integer_greaterThanFromInt(Assembler* assembler) {
- return false;
+ return CompareIntegers(assembler, LT);
}
bool Intrinsifier::Integer_lessThan(Assembler* assembler) {
- return false;
+ return Integer_greaterThanFromInt(assembler);
}
bool Intrinsifier::Integer_greaterThan(Assembler* assembler) {
- return false;
+ return CompareIntegers(assembler, GT);
}
bool Intrinsifier::Integer_lessEqualThan(Assembler* assembler) {
- return false;
+ return CompareIntegers(assembler, LE);
}
bool Intrinsifier::Integer_greaterEqualThan(Assembler* assembler) {
- return false;
+ return CompareIntegers(assembler, GE);
}
+// This is called for Smi, Mint and Bigint receivers. The right argument
+// can be Smi, Mint, Bigint or double.
bool Intrinsifier::Integer_equalToInteger(Assembler* assembler) {
+ Label fall_through, true_label, check_for_mint;
+ // For integer receiver '===' check first.
+ __ ldr(R0, Address(SP, 0 * kWordSize));
+ __ ldr(R1, Address(SP, 1 * kWordSize));
+ __ cmp(R0, ShifterOperand(R1));
+ __ b(&true_label, EQ);
+
+ __ orr(R2, R0, ShifterOperand(R1));
+ __ tst(R2, ShifterOperand(kSmiTagMask));
+ __ b(&check_for_mint, NE); // If R0 or R1 is not a smi do Mint checks.
+
+ // Both arguments are smi, '===' is good enough.
+ __ LoadObject(R0, Bool::False());
+ __ Ret();
+ __ Bind(&true_label);
+ __ LoadObject(R0, Bool::True());
+ __ Ret();
+
+ // At least one of the arguments was not Smi.
+ Label receiver_not_smi;
+ __ Bind(&check_for_mint);
+
+ __ tst(R1, ShifterOperand(kSmiTagMask)); // Check receiver.
+ __ b(&receiver_not_smi, NE);
+
+ // Left (receiver) is Smi, return false if right is not Double.
+ // Note that an instance of Mint or Bigint never contains a value that can be
+ // represented by Smi.
+
+ __ CompareClassId(R0, kDoubleCid, R2);
+ __ b(&fall_through, EQ);
+ __ LoadObject(R0, Bool::False()); // Smi == Mint -> false.
+ __ Ret();
+
+ __ Bind(&receiver_not_smi);
+ // R1:: receiver.
+
+ __ CompareClassId(R1, kMintCid, R2);
+ __ b(&fall_through, NE);
+ // Receiver is Mint, return false if right is Smi.
+ __ tst(R0, ShifterOperand(kSmiTagMask));
+ __ b(&fall_through, NE);
+ __ LoadObject(R0, Bool::False());
+ __ Ret();
+ // TODO(srdjan): Implement Mint == Mint comparison.
+
+ __ Bind(&fall_through);
return false;
}
bool Intrinsifier::Integer_equal(Assembler* assembler) {
- return false;
+ return Integer_equalToInteger(assembler);
}
bool Intrinsifier::Integer_sar(Assembler* assembler) {
+ Label fall_through;
+
+ TestBothArgumentsSmis(assembler, &fall_through);
+ // Shift amount in R0. Value to shift in R1.
+
+ // Fall through if shift amount is negative.
+ __ SmiUntag(R0);
+ __ CompareImmediate(R0, 0);
+ __ b(&fall_through, LT);
+
+ // If shift amount is bigger than 31, set to 31.
+ __ CompareImmediate(R0, 0x1F);
+ __ LoadImmediate(R0, 0x1F, GT);
+ __ SmiUntag(R1);
+ __ mov(R0, ShifterOperand(R1, ASR, R0));
+ __ SmiTag(R0);
+ __ Ret();
+ __ Bind(&fall_through);
return false;
}
bool Intrinsifier::Smi_bitNegate(Assembler* assembler) {
+ __ ldr(R0, Address(SP, 0 * kWordSize));
+ __ mvn(R0, ShifterOperand(R0));
+ __ bic(R0, R0, ShifterOperand(kSmiTagMask)); // Remove inverted smi-tag.
+ __ Ret();
+ return false;
+}
+
+
+// Check if the last argument is a double, jump to label 'is_smi' if smi
+// (easy to convert to double), otherwise jump to label 'not_double_smi',
+// Returns the last argument in R0.
+static void TestLastArgumentIsDouble(Assembler* assembler,
+ Label* is_smi,
+ Label* not_double_smi) {
+ __ ldr(R0, Address(SP, 0 * kWordSize));
+ __ tst(R0, ShifterOperand(kSmiTagMask));
+ __ b(is_smi, EQ);
+ __ CompareClassId(R0, kDoubleCid, R1);
+ __ b(not_double_smi, NE);
+ // Fall through with Double in R0.
+}
+
+
+// Both arguments on stack, arg0 (left) is a double, arg1 (right) is of unknown
+// type. Return true or false object in the register R0. Any NaN argument
+// returns false. Any non-double arg1 causes control flow to fall through to the
+// slow case (compiled method body).
+static bool CompareDoubles(Assembler* assembler, Condition true_condition) {
+ Label fall_through, is_smi, double_op;
+
+ TestLastArgumentIsDouble(assembler, &is_smi, &fall_through);
+ // Both arguments are double, right operand is in R0.
+
+ __ AddImmediate(R0, Double::value_offset() - kHeapObjectTag);
+ __ vldrd(D1, Address(R0));
+ __ Bind(&double_op);
+ __ ldr(R0, Address(SP, 1 * kWordSize)); // Left argument.
+ __ AddImmediate(R0, Double::value_offset() - kHeapObjectTag);
+ __ vldrd(D0, Address(R0));
+
+ __ vcmpd(D0, D1);
+ __ vmstat();
+ __ LoadObject(R0, Bool::False());
+ // Return false if D0 or D1 was NaN before checking true condition.
+ __ bx(LR, VS);
+ __ LoadObject(R0, Bool::True(), true_condition);
+ __ Ret();
+
+ __ Bind(&is_smi); // Convert R0 to a double.
+ __ SmiUntag(R0);
+ __ vmovsr(S0, R0);
+ __ vcvtdi(D1, S0);
+ __ b(&double_op); // Then do the comparison.
+ __ Bind(&fall_through);
return false;
}
bool Intrinsifier::Double_greaterThan(Assembler* assembler) {
- return false;
+ return CompareDoubles(assembler, HI);
}
bool Intrinsifier::Double_greaterEqualThan(Assembler* assembler) {
- return false;
+ return CompareDoubles(assembler, CS);
}
bool Intrinsifier::Double_lessThan(Assembler* assembler) {
- return false;
+ return CompareDoubles(assembler, CC);
}
bool Intrinsifier::Double_equal(Assembler* assembler) {
- return false;
+ return CompareDoubles(assembler, EQ);
}
bool Intrinsifier::Double_lessEqualThan(Assembler* assembler) {
+ return CompareDoubles(assembler, LS);
+}
+
+
+// Expects left argument to be double (receiver). Right argument is unknown.
+// Both arguments are on stack.
+static bool DoubleArithmeticOperations(Assembler* assembler, Token::Kind kind) {
+ Label fall_through;
+
+ TestLastArgumentIsDouble(assembler, &fall_through, &fall_through);
+ // Both arguments are double, right operand is in R0.
+ // Can't use FieldAddress here. R0 is heap-object-tagged, so the offset will
+ // not be 4-byte aligned.
+ __ AddImmediate(R0, Double::value_offset() - kHeapObjectTag);
+ __ vldrd(D1, Address(R0));
+ __ ldr(R0, Address(SP, 1 * kWordSize)); // Left argument.
+ __ AddImmediate(R0, Double::value_offset() - kHeapObjectTag);
+ __ vldrd(D0, Address(R0));
+ switch (kind) {
+ case Token::kADD: __ vaddd(D0, D0, D1); break;
+ case Token::kSUB: __ vsubd(D0, D0, D1); break;
+ case Token::kMUL: __ vmuld(D0, D0, D1); break;
+ case Token::kDIV: __ vdivd(D0, D0, D1); break;
+ default: UNREACHABLE();
+ }
+ const Class& double_class = Class::Handle(
+ Isolate::Current()->object_store()->double_class());
+ __ TryAllocate(double_class, &fall_through, R0); // Result register.
+ __ AddImmediate(R1, R0, Double::value_offset() - kHeapObjectTag);
+ __ vstrd(D0, Address(R1));
+ __ Ret();
+ __ Bind(&fall_through);
return false;
}
bool Intrinsifier::Double_add(Assembler* assembler) {
- return false;
+ return DoubleArithmeticOperations(assembler, Token::kADD);
}
bool Intrinsifier::Double_mul(Assembler* assembler) {
- return false;
+ return DoubleArithmeticOperations(assembler, Token::kMUL);
}
bool Intrinsifier::Double_sub(Assembler* assembler) {
- return false;
+ return DoubleArithmeticOperations(assembler, Token::kSUB);
}
bool Intrinsifier::Double_div(Assembler* assembler) {
- return false;
+ return DoubleArithmeticOperations(assembler, Token::kDIV);
}
+// Left is double right is integer (Bigint, Mint or Smi)
bool Intrinsifier::Double_mulFromInteger(Assembler* assembler) {
+ Label fall_through;
+ __ Untested("Intrinsifier::Double_mulFromInteger");
+ // Only Smi-s allowed.
+ __ ldr(R0, Address(SP, 0 * kWordSize));
+ __ tst(R0, ShifterOperand(kSmiTagMask));
+ __ b(&fall_through, NE);
+ // Is Smi.
+ __ SmiUntag(R0);
+ __ vmovsr(S0, R0);
+ __ vcvtdi(D1, S0);
+ __ ldr(R0, Address(SP, 1 * kWordSize));
+ __ AddImmediate(R0, Double::value_offset() - kHeapObjectTag);
+ __ vldrd(D0, Address(R0));
+ __ vmuld(D0, D0, D1);
+ const Class& double_class = Class::Handle(
+ Isolate::Current()->object_store()->double_class());
+ __ TryAllocate(double_class, &fall_through, R0); // Result register.
+ __ AddImmediate(R1, R0, Double::value_offset() - kHeapObjectTag);
+ __ vstrd(D0, Address(R1));
+ __ Ret();
+ __ Bind(&fall_through);
return false;
}
bool Intrinsifier::Double_fromInteger(Assembler* assembler) {
+ Label fall_through;
+
+ __ ldr(R0, Address(SP, 0 * kWordSize));
+ __ tst(R0, ShifterOperand(kSmiTagMask));
+ __ b(&fall_through, NE);
+ // Is Smi.
+ __ SmiUntag(R0);
+ __ vmovsr(S0, R0);
+ __ vcvtdi(D0, S0);
+ const Class& double_class = Class::Handle(
+ Isolate::Current()->object_store()->double_class());
+ __ TryAllocate(double_class, &fall_through, R0); // Result register.
+ __ AddImmediate(R1, R0, Double::value_offset() - kHeapObjectTag);
+ __ vstrd(D0, Address(R1));
+ __ Ret();
+ __ Bind(&fall_through);
return false;
}
bool Intrinsifier::Double_getIsNaN(Assembler* assembler) {
- return false;
+ Label is_true;
+ __ Untested("Intrinsifier::Double_getIsNaN");
+ __ ldr(R0, Address(SP, 0 * kWordSize));
+ __ AddImmediate(R0, Double::value_offset() - kHeapObjectTag);
+ __ vldrd(D0, Address(R0));
+ __ vcmpd(D0, D0);
+ __ vmstat();
+ __ LoadObject(R0, Bool::False(), VS);
+ __ LoadObject(R0, Bool::True(), VC);
+ __ Ret();
+ return true;
}
bool Intrinsifier::Double_getIsNegative(Assembler* assembler) {
- return false;
+ Label is_false, is_true, is_zero;
+ __ Untested("Intrinsifier::Double_getIsNegative");
+ __ ldr(R0, Address(SP, 0 * kWordSize));
+ __ AddImmediate(R0, Double::value_offset() - kHeapObjectTag);
+ __ vldrd(D0, Address(R0));
+ __ LoadDImmediate(D1, 0.0, R1);
+ __ vcmpd(D0, D1);
+ __ vmstat();
+ __ b(&is_false, VS); // NaN -> false.
+ __ b(&is_zero, EQ); // Check for negative zero.
+ __ b(&is_false, CS); // >= 0 -> false.
+
+ __ Bind(&is_true);
+ __ LoadObject(R0, Bool::True());
+ __ Ret();
+
+ __ Bind(&is_false);
+ __ LoadObject(R0, Bool::False());
+ __ Ret();
+
+ __ Bind(&is_zero);
+ // Check for negative zero by looking at the sign bit.
+ __ vmovrrd(R0, R1, D0); // R1:R0 <- D0, so sign bit is in bit 31 of R1.
+ __ mov(R1, ShifterOperand(R1, LSR, 31));
+ __ tst(R1, ShifterOperand(1));
+ __ b(&is_true, NE); // Sign bit set.
+ __ b(&is_false);
+ return true;
}
bool Intrinsifier::Double_toInt(Assembler* assembler) {
+ __ ldr(R0, Address(SP, 0 * kWordSize));
+ __ AddImmediate(R0, Double::value_offset() - kHeapObjectTag);
+ __ vldrd(D0, Address(R0));
+ __ vcvtid(S0, D0);
+ __ vmovrs(R0, S0);
+ // Overflow is signaled with minint.
+ Label fall_through;
+ // Check for overflow and that it fits into Smi.
+ __ CompareImmediate(R0, 0xC0000000);
+ __ b(&fall_through, MI);
+ __ SmiTag(R0);
+ __ Ret();
+ __ Bind(&fall_through);
return false;
}
bool Intrinsifier::Math_sqrt(Assembler* assembler) {
+ Label fall_through, is_smi, double_op;
+ __ Untested("Intrinsifier::Math_sqrt");
+ TestLastArgumentIsDouble(assembler, &is_smi, &fall_through);
+ // Argument is double and is in R0.
+ __ AddImmediate(R0, Double::value_offset() - kHeapObjectTag);
+ __ vldrd(D1, Address(R0));
+ __ Bind(&double_op);
+ __ vsqrtd(D0, D1);
+ const Class& double_class = Class::Handle(
+ Isolate::Current()->object_store()->double_class());
+ __ TryAllocate(double_class, &fall_through, R0); // Result register.
+ __ AddImmediate(R1, R0, Double::value_offset() - kHeapObjectTag);
+ __ vstrd(D0, Address(R1));
+ __ Ret();
+ __ Bind(&is_smi);
+ __ SmiUntag(R0);
+ __ vmovsr(S0, R0);
+ __ vcvtdi(D1, S0);
+ __ b(&double_op);
+ __ Bind(&fall_through);
return false;
}
@@ -311,52 +1376,332 @@
}
+// var state = ((_A * (_state[kSTATE_LO])) + _state[kSTATE_HI]) & _MASK_64;
+// _state[kSTATE_LO] = state & _MASK_32;
+// _state[kSTATE_HI] = state >> 32;
bool Intrinsifier::Random_nextState(Assembler* assembler) {
- return false;
+ const Library& math_lib = Library::Handle(Library::MathLibrary());
+ ASSERT(!math_lib.IsNull());
+ const Class& random_class =
+ Class::Handle(math_lib.LookupClassAllowPrivate(Symbols::_Random()));
+ ASSERT(!random_class.IsNull());
+ const Field& state_field = Field::ZoneHandle(
+ random_class.LookupInstanceField(Symbols::_state()));
+ ASSERT(!state_field.IsNull());
+ const Field& random_A_field = Field::ZoneHandle(
+ random_class.LookupStaticField(Symbols::_A()));
+ ASSERT(!random_A_field.IsNull());
+ ASSERT(random_A_field.is_const());
+ const Instance& a_value = Instance::Handle(random_A_field.value());
+ const int64_t a_int_value = Integer::Cast(a_value).AsInt64Value();
+ // 'a_int_value' is a mask.
+ ASSERT(Utils::IsUint(32, a_int_value));
+ int32_t a_int32_value = static_cast<int32_t>(a_int_value);
+
+ __ Untested("Random_nextState");
+
+ __ ldr(R0, Address(SP, 0 * kWordSize)); // Receiver.
+ __ ldr(R1, FieldAddress(R0, state_field.Offset())); // Field '_state'.
+ // Addresses of _state[0] and _state[1].
+
+ const int64_t disp_0 =
+ FlowGraphCompiler::DataOffsetFor(kTypedDataUint32ArrayCid);
+
+ const int64_t disp_1 =
+ FlowGraphCompiler::ElementSizeFor(kTypedDataUint32ArrayCid) +
+ FlowGraphCompiler::DataOffsetFor(kTypedDataUint32ArrayCid);
+
+ __ LoadImmediate(R0, a_int32_value);
+ __ LoadFromOffset(kLoadWord, R2, R1, disp_0 - 1);
+ __ LoadFromOffset(kLoadWord, R3, R1, disp_1 - 1);
+ __ mov(R6, ShifterOperand(R3, ASR, 31)); // Sign extend into R6.
+ // 64-bit multiply and accumulate into R6:R3.
+ __ smlal(R3, R6, R0, R2); // R6:R3 <- R6:R3 + R0 * R2.
+ __ StoreToOffset(kStoreWord, R3, R1, disp_0 - 1);
+ __ StoreToOffset(kStoreWord, R6, R1, disp_1 - 1);
+ __ Ret();
+ return true;
}
bool Intrinsifier::Object_equal(Assembler* assembler) {
- return false;
+ __ ldr(R0, Address(SP, 0 * kWordSize));
+ __ ldr(R1, Address(SP, 1 * kWordSize));
+ __ cmp(R0, ShifterOperand(R1));
+ __ LoadObject(R0, Bool::False(), NE);
+ __ LoadObject(R0, Bool::True(), EQ);
+ __ Ret();
+ return true;
}
bool Intrinsifier::String_getHashCode(Assembler* assembler) {
+ __ Untested("Intrinsifier::String_getHashCode");
+ __ ldr(R0, Address(SP, 0 * kWordSize));
+ __ ldr(R0, FieldAddress(R0, String::hash_offset()));
+ __ cmp(R0, ShifterOperand(0));
+ __ bx(LR, NE); // Hash not yet computed.
return false;
}
bool Intrinsifier::String_getLength(Assembler* assembler) {
- return false;
+ __ ldr(R0, Address(SP, 0 * kWordSize));
+ __ ldr(R0, FieldAddress(R0, String::length_offset()));
+ __ Ret();
+ return true;
}
+// TODO(srdjan): Implement for two and four byte strings as well.
bool Intrinsifier::String_codeUnitAt(Assembler* assembler) {
+ Label fall_through;
+
+ __ ldr(R1, Address(SP, 0 * kWordSize)); // Index.
+ __ ldr(R0, Address(SP, 1 * kWordSize)); // String.
+ __ tst(R1, ShifterOperand(kSmiTagMask));
+ __ b(&fall_through, NE); // Index is not a Smi.
+ // Range check.
+ __ ldr(R2, FieldAddress(R0, String::length_offset()));
+ __ cmp(R1, ShifterOperand(R2));
+ __ b(&fall_through, CS); // Runtime throws exception.
+ __ CompareClassId(R0, kOneByteStringCid, R3);
+ __ b(&fall_through, NE);
+ __ SmiUntag(R1);
+ __ AddImmediate(R0, OneByteString::data_offset() - kHeapObjectTag);
+ __ ldrb(R0, Address(R0, R1));
+ __ SmiTag(R0);
+ __ Ret();
+ __ Bind(&fall_through);
return false;
}
bool Intrinsifier::String_getIsEmpty(Assembler* assembler) {
- return false;
+ __ ldr(R0, Address(SP, 0 * kWordSize));
+ __ ldr(R0, FieldAddress(R0, String::length_offset()));
+ __ cmp(R0, ShifterOperand(Smi::RawValue(0)));
+ __ LoadObject(R0, Bool::True(), EQ);
+ __ LoadObject(R0, Bool::False(), NE);
+ __ Ret();
+ return true;
}
bool Intrinsifier::OneByteString_getHashCode(Assembler* assembler) {
+ __ ldr(R1, Address(SP, 0 * kWordSize));
+ __ ldr(R0, FieldAddress(R1, String::hash_offset()));
+ __ cmp(R0, ShifterOperand(0));
+ __ bx(LR, NE); // Return if already computed.
+
+ __ ldr(R2, FieldAddress(R1, String::length_offset()));
+
+ Label done;
+ // If the string is empty, set the hash to 1, and return.
+ __ cmp(R2, ShifterOperand(Smi::RawValue(0)));
+ __ b(&done, EQ);
+
+ __ SmiUntag(R2);
+ __ mov(R3, ShifterOperand(0));
+ __ AddImmediate(R6, R1, OneByteString::data_offset() - kHeapObjectTag);
+ // R1: Instance of OneByteString.
+ // R2: String length, untagged integer.
+ // R3: Loop counter, untagged integer.
+ // R6: String data.
+ // R0: Hash code, untagged integer.
+
+ Label loop;
+ // Add to hash code: (hash_ is uint32)
+ // hash_ += ch;
+ // hash_ += hash_ << 10;
+ // hash_ ^= hash_ >> 6;
+ // Get one characters (ch).
+ __ Bind(&loop);
+ __ ldrb(R7, Address(R6, 0));
+ // R7: ch.
+ __ add(R3, R3, ShifterOperand(1));
+ __ add(R6, R6, ShifterOperand(1));
+ __ add(R0, R0, ShifterOperand(R7));
+ __ add(R0, R0, ShifterOperand(R0, LSL, 10));
+ __ eor(R0, R0, ShifterOperand(R0, LSR, 6));
+ __ cmp(R3, ShifterOperand(R2));
+ __ b(&loop, NE);
+
+ // Finalize.
+ // hash_ += hash_ << 3;
+ // hash_ ^= hash_ >> 11;
+ // hash_ += hash_ << 15;
+ __ add(R0, R0, ShifterOperand(R0, LSL, 3));
+ __ eor(R0, R0, ShifterOperand(R0, LSR, 11));
+ __ add(R0, R0, ShifterOperand(R0, LSL, 15));
+ // hash_ = hash_ & ((static_cast<intptr_t>(1) << bits) - 1);
+ __ LoadImmediate(R2, (static_cast<intptr_t>(1) << String::kHashBits) - 1);
+ __ and_(R0, R0, ShifterOperand(R2));
+ __ cmp(R0, ShifterOperand(0));
+ // return hash_ == 0 ? 1 : hash_;
+ __ Bind(&done);
+ __ mov(R0, ShifterOperand(1), EQ);
+ __ SmiTag(R0);
+ __ str(R0, FieldAddress(R1, String::hash_offset()));
+ __ Ret();
return false;
}
+// Allocates one-byte string of length 'end - start'. The content is not
+// initialized.
+// 'length-reg' (R2) contains tagged length.
+// Returns new string as tagged pointer in R0.
+static void TryAllocateOnebyteString(Assembler* assembler,
+ Label* ok,
+ Label* failure) {
+ const Register length_reg = R2;
+ Label fail;
+
+ __ mov(R6, ShifterOperand(length_reg)); // Save the length register.
+ __ SmiUntag(length_reg);
+ const intptr_t fixed_size = sizeof(RawString) + kObjectAlignment - 1;
+ __ AddImmediate(length_reg, fixed_size);
+ __ bic(length_reg, length_reg, ShifterOperand(kObjectAlignment - 1));
+
+ Isolate* isolate = Isolate::Current();
+ Heap* heap = isolate->heap();
+
+ __ LoadImmediate(R3, heap->TopAddress());
+ __ ldr(R0, Address(R3, 0));
+
+ // length_reg: allocation size.
+ __ adds(R1, R0, ShifterOperand(length_reg));
+ __ b(&fail, VS); // Fail on overflow.
+
+ // Check if the allocation fits into the remaining space.
+ // R0: potential new object start.
+ // R1: potential next object start.
+ // R2: allocation size.
+ // R3: heap->Top->Address().
+ __ LoadImmediate(R7, heap->EndAddress());
+ __ ldr(R7, Address(R7, 0));
+ __ cmp(R1, ShifterOperand(R7));
+ __ b(&fail, CS);
+
+ // Successfully allocated the object(s), now update top to point to
+ // next object start and initialize the object.
+ __ str(R1, Address(R3, 0));
+ __ AddImmediate(R0, kHeapObjectTag);
+
+ // Initialize the tags.
+ // R0: new object start as a tagged pointer.
+ // R1: new object end address.
+ // R2: allocation size.
+ {
+ const intptr_t shift = RawObject::kSizeTagBit - kObjectAlignmentLog2;
+ const Class& cls =
+ Class::Handle(isolate->object_store()->one_byte_string_class());
+
+ __ CompareImmediate(R2, RawObject::SizeTag::kMaxSizeTag);
+ __ mov(R2, ShifterOperand(R2, LSL, shift), LS);
+ __ mov(R2, ShifterOperand(0), HI);
+
+ // Get the class index and insert it into the tags.
+ // R2: size and bit tags.
+ __ LoadImmediate(TMP, RawObject::ClassIdTag::encode(cls.id()));
+ __ orr(R2, R2, ShifterOperand(TMP));
+ __ str(R2, FieldAddress(R0, String::tags_offset())); // Store tags.
+ }
+
+ // Set the length field using the saved length (R6).
+ __ StoreIntoObjectNoBarrier(R0,
+ FieldAddress(R0, String::length_offset()),
+ R6);
+ // Clear hash.
+ __ LoadImmediate(TMP, 0);
+ __ str(TMP, FieldAddress(R0, String::hash_offset()));
+ __ b(ok);
+
+ __ Bind(&fail);
+ __ b(failure);
+}
+
+
+// Arg0: Onebyte String
+// Arg1: Start index as Smi.
+// Arg2: End index as Smi.
+// The indexes must be valid.
bool Intrinsifier::OneByteString_substringUnchecked(Assembler* assembler) {
+ const intptr_t kStringOffset = 2 * kWordSize;
+ const intptr_t kStartIndexOffset = 1 * kWordSize;
+ const intptr_t kEndIndexOffset = 0 * kWordSize;
+ Label fall_through, ok;
+
+ __ ldr(R2, Address(SP, kEndIndexOffset));
+ __ ldr(TMP, Address(SP, kStartIndexOffset));
+ __ sub(R2, R2, ShifterOperand(TMP));
+ TryAllocateOnebyteString(assembler, &ok, &fall_through);
+ __ Bind(&ok);
+ // R0: new string as tagged pointer.
+ // Copy string.
+ __ ldr(R3, Address(SP, kStringOffset));
+ __ ldr(R1, Address(SP, kStartIndexOffset));
+ __ SmiUntag(R1);
+ __ add(R3, R3, ShifterOperand(R1));
+ // Calculate start address and untag (- 1).
+ __ AddImmediate(R3, OneByteString::data_offset() - 1);
+
+ // R3: Start address to copy from (untagged).
+ // R1: Untagged start index.
+ __ ldr(R2, Address(SP, kEndIndexOffset));
+ __ SmiUntag(R2);
+ __ sub(R2, R2, ShifterOperand(R1));
+
+ // R3: Start address to copy from (untagged).
+ // R2: Untagged number of bytes to copy.
+ // R0: Tagged result string.
+ // R6: Pointer into R3.
+ // R7: Pointer into R0.
+ // R1: Scratch register.
+ Label loop, done;
+ __ cmp(R2, ShifterOperand(0));
+ __ b(&done, LE);
+ __ mov(R6, ShifterOperand(R3));
+ __ mov(R7, ShifterOperand(R0));
+ __ Bind(&loop);
+ __ ldrb(R1, Address(R6, 0));
+ __ AddImmediate(R6, 1);
+ __ sub(R2, R2, ShifterOperand(1));
+ __ cmp(R2, ShifterOperand(0));
+ __ strb(R1, FieldAddress(R7, OneByteString::data_offset()));
+ __ AddImmediate(R7, 1);
+ __ b(&loop, GT);
+
+ __ Bind(&done);
+ __ Ret();
+ __ Bind(&fall_through);
return false;
}
bool Intrinsifier::OneByteString_setAt(Assembler* assembler) {
- return false;
+ __ ldr(R2, Address(SP, 0 * kWordSize)); // Value.
+ __ ldr(R1, Address(SP, 1 * kWordSize)); // Index.
+ __ ldr(R0, Address(SP, 2 * kWordSize)); // OneByteString.
+ __ SmiUntag(R1);
+ __ SmiUntag(R2);
+ __ AddImmediate(R3, R0, OneByteString::data_offset() - kHeapObjectTag);
+ __ strb(R2, Address(R3, R1));
+ __ Ret();
+ return true;
}
bool Intrinsifier::OneByteString_allocate(Assembler* assembler) {
+ __ ldr(R2, Address(SP, 0 * kWordSize)); // Length.
+ Label fall_through, ok;
+ TryAllocateOnebyteString(assembler, &ok, &fall_through);
+
+ __ Bind(&ok);
+ __ Ret();
+
+ __ Bind(&fall_through);
return false;
}
diff --git a/runtime/vm/intrinsifier_ia32.cc b/runtime/vm/intrinsifier_ia32.cc
index 8d5ff5a..5b704ce 100644
--- a/runtime/vm/intrinsifier_ia32.cc
+++ b/runtime/vm/intrinsifier_ia32.cc
@@ -677,7 +677,7 @@
// EAX: Tagged left (dividend).
// EBX: Tagged right (divisor).
// EDX: Untagged result (remainder).
-void EmitRemainderOperation(Assembler* assembler) {
+static void EmitRemainderOperation(Assembler* assembler) {
Label return_zero, modulo;
// Check for quick zero results.
__ cmpl(EAX, Immediate(0));
@@ -1632,7 +1632,7 @@
__ pushl(EDI); // Preserve length.
__ SmiUntag(EDI);
const intptr_t fixed_size = sizeof(RawString) + kObjectAlignment - 1;
- __ leal(EDI, Address(EDI, TIMES_1, fixed_size)); // EDI is a Smi.
+ __ leal(EDI, Address(EDI, TIMES_1, fixed_size)); // EDI is untagged.
__ andl(EDI, Immediate(-kObjectAlignment));
Isolate* isolate = Isolate::Current();
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index f455a0a..4c1a93b 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -53,6 +53,7 @@
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);
@@ -2299,74 +2300,53 @@
bool Class::IsTopLevel() const {
- return String::Handle(Name()).Equals("::");
+ return Name() == Symbols::TopLevel().raw();
}
RawFunction* Class::LookupDynamicFunction(const String& name) const {
- Function& function = Function::Handle(LookupFunction(name));
- if (function.IsNull() || !function.IsDynamicFunction()) {
- return Function::null();
- }
- return function.raw();
+ return LookupFunction(name, kInstance);
}
RawFunction* Class::LookupDynamicFunctionAllowPrivate(
const String& name) const {
- Function& function = Function::Handle(LookupFunctionAllowPrivate(name));
- if (function.IsNull() || !function.IsDynamicFunction()) {
- return Function::null();
- }
- return function.raw();
+ return LookupFunctionAllowPrivate(name, kInstance);
}
RawFunction* Class::LookupStaticFunction(const String& name) const {
- Function& function = Function::Handle(LookupFunction(name));
- if (function.IsNull() || !function.IsStaticFunction()) {
- return Function::null();
- }
- return function.raw();
+ return LookupFunction(name, kStatic);
}
RawFunction* Class::LookupStaticFunctionAllowPrivate(const String& name) const {
- Function& function = Function::Handle(LookupFunctionAllowPrivate(name));
- if (function.IsNull() || !function.IsStaticFunction()) {
- return Function::null();
- }
- return function.raw();
+ return LookupFunctionAllowPrivate(name, kStatic);
}
RawFunction* Class::LookupConstructor(const String& name) const {
- Function& function = Function::Handle(LookupFunction(name));
- if (function.IsNull() || !function.IsConstructor()) {
- return Function::null();
- }
- ASSERT(!function.is_static());
- return function.raw();
+ return LookupFunction(name, kConstructor);
}
RawFunction* Class::LookupConstructorAllowPrivate(const String& name) const {
- Function& function = Function::Handle(LookupFunctionAllowPrivate(name));
- if (function.IsNull() || !function.IsConstructor()) {
- return Function::null();
- }
- ASSERT(!function.is_static());
- return function.raw();
+ return LookupFunctionAllowPrivate(name, kConstructor);
}
RawFunction* Class::LookupFactory(const String& name) const {
- Function& function = Function::Handle(LookupFunction(name));
- if (function.IsNull() || !function.IsFactory()) {
- return Function::null();
- }
- ASSERT(function.is_static());
- return function.raw();
+ return LookupFunction(name, kFactory);
+}
+
+
+RawFunction* Class::LookupFunction(const String& name) const {
+ return LookupFunction(name, kAny);
+}
+
+
+RawFunction* Class::LookupFunctionAllowPrivate(const String& name) const {
+ return LookupFunctionAllowPrivate(name, kAny);
}
@@ -2395,7 +2375,33 @@
}
-RawFunction* Class::LookupFunction(const String& name) const {
+RawFunction* Class::CheckFunctionType(const Function& func, intptr_t type) {
+ if (type == kInstance) {
+ if (func.IsDynamicFunction()) {
+ return func.raw();
+ }
+ } else if (type == kStatic) {
+ if (func.IsStaticFunction()) {
+ return func.raw();
+ }
+ } else if (type == kConstructor) {
+ if (func.IsConstructor()) {
+ ASSERT(!func.is_static());
+ return func.raw();
+ }
+ } else if (type == kFactory) {
+ if (func.IsFactory()) {
+ ASSERT(func.is_static());
+ return func.raw();
+ }
+ } else if (type == kAny) {
+ return func.raw();
+ }
+ return Function::null();
+}
+
+
+RawFunction* Class::LookupFunction(const String& name, intptr_t type) const {
Isolate* isolate = Isolate::Current();
if (EnsureIsFinalized(isolate) != Error::null()) {
return Function::null();
@@ -2405,7 +2411,7 @@
// This can occur, e.g., for Null classes.
return Function::null();
}
- Function& function = Function::Handle(isolate, Function::null());
+ Function& function = Function::Handle(isolate);
const intptr_t len = funcs.Length();
if (name.IsSymbol()) {
// Quick Symbol compare.
@@ -2413,16 +2419,16 @@
for (intptr_t i = 0; i < len; i++) {
function ^= funcs.At(i);
if (function.name() == name.raw()) {
- return function.raw();
+ return CheckFunctionType(function, type);
}
}
} else {
- String& function_name = String::Handle(isolate, String::null());
+ String& function_name = String::Handle(isolate);
for (intptr_t i = 0; i < len; i++) {
function ^= funcs.At(i);
function_name ^= function.name();
if (function_name.Equals(name)) {
- return function.raw();
+ return CheckFunctionType(function, type);
}
}
}
@@ -2431,7 +2437,8 @@
}
-RawFunction* Class::LookupFunctionAllowPrivate(const String& name) const {
+RawFunction* Class::LookupFunctionAllowPrivate(const String& name,
+ intptr_t type) const {
Isolate* isolate = Isolate::Current();
if (EnsureIsFinalized(isolate) != Error::null()) {
return Function::null();
@@ -2441,14 +2448,14 @@
// This can occur, e.g., for Null classes.
return Function::null();
}
- Function& function = Function::Handle(isolate, Function::null());
- String& function_name = String::Handle(isolate, String::null());
+ Function& function = Function::Handle(isolate);
+ String& function_name = String::Handle(isolate);
intptr_t len = funcs.Length();
for (intptr_t i = 0; i < len; i++) {
function ^= funcs.At(i);
function_name ^= function.name();
if (String::EqualsIgnoringPrivateKey(function_name, name)) {
- return function.raw();
+ return CheckFunctionType(function, type);
}
}
// No function found.
@@ -2517,44 +2524,21 @@
RawField* Class::LookupInstanceField(const String& name) const {
- Isolate* isolate = Isolate::Current();
- if (EnsureIsFinalized(isolate) != Error::null()) {
- return Field::null();
- }
- ASSERT(is_finalized());
- const Field& field = Field::Handle(isolate, LookupField(name));
- if (!field.IsNull()) {
- if (field.is_static()) {
- // Name matches but it is not of the correct kind, return NULL.
- return Field::null();
- }
- return field.raw();
- }
- // No field found.
- return Field::null();
+ return LookupField(name, kInstance);
}
RawField* Class::LookupStaticField(const String& name) const {
- Isolate* isolate = Isolate::Current();
- if (EnsureIsFinalized(isolate) != Error::null()) {
- return Field::null();
- }
- ASSERT(is_finalized());
- const Field& field = Field::Handle(isolate, LookupField(name));
- if (!field.IsNull()) {
- if (!field.is_static()) {
- // Name matches but it is not of the correct kind, return NULL.
- return Field::null();
- }
- return field.raw();
- }
- // No field found.
- return Field::null();
+ return LookupField(name, kStatic);
}
RawField* Class::LookupField(const String& name) const {
+ return LookupField(name, kAny);
+}
+
+
+RawField* Class::LookupField(const String& name, intptr_t type) const {
Isolate* isolate = Isolate::Current();
if (EnsureIsFinalized(isolate) != Error::null()) {
return Field::null();
@@ -2567,7 +2551,18 @@
field ^= flds.At(i);
field_name ^= field.name();
if (String::EqualsIgnoringPrivateKey(field_name, name)) {
- return field.raw();
+ if (type == kInstance) {
+ if (!field.is_static()) {
+ return field.raw();
+ }
+ } else if (type == kStatic) {
+ if (field.is_static()) {
+ return field.raw();
+ }
+ } else if (type == kAny) {
+ return field.raw();
+ }
+ return Field::null();
}
}
// No field found.
@@ -3424,6 +3419,15 @@
}
+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_);
@@ -6688,11 +6692,6 @@
}
-RawLibrary* Library::CryptoLibrary() {
- return Isolate::Current()->object_store()->crypto_library();
-}
-
-
RawLibrary* Library::IsolateLibrary() {
return Isolate::Current()->object_store()->isolate_library();
}
@@ -6723,11 +6722,6 @@
}
-RawLibrary* Library::UriLibrary() {
- return Isolate::Current()->object_store()->uri_library();
-}
-
-
RawLibrary* Library::UtfLibrary() {
return Isolate::Current()->object_store()->utf_library();
}
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 480ce5b..01b8c78 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -917,6 +917,13 @@
private:
enum {
+ kAny = 0,
+ kStatic,
+ kInstance,
+ kConstructor,
+ kFactory,
+ };
+ enum {
kConstBit = 0,
kImplementedBit = 1,
kAbstractBit = 2,
@@ -953,6 +960,12 @@
// Assigns empty array to all raw class array fields.
void InitEmptyFields();
+ static RawFunction* CheckFunctionType(const Function& func, intptr_t type);
+ RawFunction* LookupFunction(const String& name, intptr_t type) const;
+ RawFunction* LookupFunctionAllowPrivate(const String& name,
+ intptr_t type) const;
+ RawField* LookupField(const String& name, intptr_t type) const;
+
RawFunction* LookupAccessorFunction(const char* prefix,
intptr_t prefix_length,
const String& name) const;
@@ -1316,6 +1329,8 @@
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.
diff --git a/runtime/vm/object_store.cc b/runtime/vm/object_store.cc
index 1f8a131..67c588c 100644
--- a/runtime/vm/object_store.cc
+++ b/runtime/vm/object_store.cc
@@ -50,7 +50,6 @@
async_library_(Library::null()),
builtin_library_(Library::null()),
core_library_(Library::null()),
- crypto_library_(Library::null()),
isolate_library_(Library::null()),
json_library_(Library::null()),
math_library_(Library::null()),
@@ -58,7 +57,6 @@
native_wrappers_library_(Library::null()),
root_library_(Library::null()),
typed_data_library_(Library::null()),
- uri_library_(Library::null()),
utf_library_(Library::null()),
libraries_(GrowableObjectArray::null()),
pending_classes_(GrowableObjectArray::null()),
diff --git a/runtime/vm/object_store.h b/runtime/vm/object_store.h
index f7fce5d..ffe1419 100644
--- a/runtime/vm/object_store.h
+++ b/runtime/vm/object_store.h
@@ -25,14 +25,12 @@
kCore,
kCollection,
kCollectionDev,
- kCrypto,
kIsolate,
kJson,
kMath,
kMirrors,
kTypedData,
kUtf,
- kUri,
};
~ObjectStore();
@@ -261,13 +259,11 @@
RawLibrary* collection_dev_library() const {
return collection_dev_library_;
}
- RawLibrary* crypto_library() const { return crypto_library_; }
RawLibrary* isolate_library() const { return isolate_library_; }
RawLibrary* json_library() const { return json_library_; }
RawLibrary* math_library() const { return math_library_; }
RawLibrary* mirrors_library() const { return mirrors_library_; }
RawLibrary* typed_data_library() const { return typed_data_library_; }
- RawLibrary* uri_library() const { return uri_library_; }
RawLibrary* utf_library() const { return utf_library_; }
void set_bootstrap_library(intptr_t index, const Library& value) {
switch (index) {
@@ -283,9 +279,6 @@
case kCollectionDev:
collection_dev_library_ = value.raw();
break;
- case kCrypto:
- crypto_library_ = value.raw();
- break;
case kIsolate:
isolate_library_ = value.raw();
break;
@@ -304,9 +297,6 @@
case kUtf:
utf_library_ = value.raw();
break;
- case kUri:
- uri_library_ = value.raw();
- break;
default:
UNREACHABLE();
}
@@ -463,7 +453,6 @@
RawLibrary* core_library_;
RawLibrary* collection_library_;
RawLibrary* collection_dev_library_;
- RawLibrary* crypto_library_;
RawLibrary* isolate_library_;
RawLibrary* json_library_;
RawLibrary* math_library_;
@@ -471,7 +460,6 @@
RawLibrary* native_wrappers_library_;
RawLibrary* root_library_;
RawLibrary* typed_data_library_;
- RawLibrary* uri_library_;
RawLibrary* utf_library_;
RawGrowableObjectArray* libraries_;
RawGrowableObjectArray* pending_classes_;
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
index f396f3b..303bd75 100644
--- a/runtime/vm/parser.cc
+++ b/runtime/vm/parser.cc
@@ -1517,13 +1517,7 @@
// Simple test if a node is side effect free.
static bool IsSimpleLocalOrLiteralNode(AstNode* node) {
- if (node->IsLiteralNode()) {
- return true;
- }
- if (node->IsLoadLocalNode() && !node->AsLoadLocalNode()->HasPseudo()) {
- return true;
- }
- return false;
+ return node->IsLiteralNode() || node->IsLoadLocalNode();
}
@@ -1573,8 +1567,9 @@
ASSERT(!super_class.IsNull());
super_op =
new LoadIndexedNode(operator_pos, receiver, index_expr, super_class);
- } else if (Token::CanBeOverloaded(CurrentToken()) ||
- (CurrentToken() == Token::kNE)) {
+ } else {
+ ASSERT(Token::CanBeOverloaded(CurrentToken()) ||
+ (CurrentToken() == Token::kNE));
Token::Kind op = CurrentToken();
ConsumeToken();
@@ -1656,28 +1651,24 @@
String::ZoneHandle(Field::SetterName(field_name));
const Function& super_setter = Function::ZoneHandle(
Resolver::ResolveDynamicAnyArgs(super_class, setter_name));
- if (!super_setter.IsNull()) {
- return new StaticGetterNode(
- field_pos, implicit_argument, true, super_class, field_name);
+ if (super_setter.IsNull()) {
+ // Check if this is an access to an implicit closure using 'super'.
+ // If a function exists of the specified field_name then try
+ // accessing it as a getter, at runtime we will handle this by
+ // creating an implicit closure of the function and returning it.
+ const Function& super_function = Function::ZoneHandle(
+ Resolver::ResolveDynamicAnyArgs(super_class, field_name));
+ if (!super_function.IsNull()) {
+ // In case CreateAssignmentNode is called later on this
+ // CreateImplicitClosureNode, it will be replaced by a StaticSetterNode.
+ return CreateImplicitClosureNode(super_function,
+ field_pos,
+ implicit_argument);
+ }
+ // No function or field exists of the specified field_name.
+ // Emit a StaticGetterNode anyway, so that noSuchMethod gets called.
}
}
- if (super_getter.IsNull()) {
- // Check if this is an access to an implicit closure using 'super'.
- // If a function exists of the specified field_name then try
- // accessing it as a getter, at runtime we will handle this by
- // creating an implicit closure of the function and returning it.
- const Function& super_function = Function::ZoneHandle(
- Resolver::ResolveDynamicAnyArgs(super_class, field_name));
- if (!super_function.IsNull()) {
- // In case CreateAssignmentNode is called later on this
- // CreateImplicitClosureNode, it will be replaced by a StaticSetterNode.
- return CreateImplicitClosureNode(super_function,
- field_pos,
- implicit_argument);
- }
- // No function or field exists of the specified field_name.
- // Emit a StaticGetterNode anyway, so that noSuchMethod gets called.
- }
return new StaticGetterNode(
field_pos, implicit_argument, true, super_class, field_name);
}
@@ -5420,7 +5411,7 @@
// Do not add statements with no effect (e.g., LoadLocalNode).
if ((statement != NULL) && statement->IsLoadLocalNode()) {
// Skip load local.
- statement = statement->AsLoadLocalNode()->pseudo();
+ continue;
}
if (statement != NULL) {
if (!dead_code_allowed && abrupt_completing_seen) {
@@ -6886,7 +6877,7 @@
bool Parser::IsAssignableExpr(AstNode* expr) {
- return (expr->IsLoadLocalNode() && !expr->AsLoadLocalNode()->HasPseudo()
+ return (expr->IsLoadLocalNode()
&& (!expr->AsLoadLocalNode()->local().is_final()))
|| expr->IsLoadStaticFieldNode()
|| expr->IsStaticGetterNode()
@@ -7179,7 +7170,10 @@
}
// The result is a pair of the (side effects of the) cascade sequence
// followed by the (value of the) receiver temp variable load.
- return new LoadLocalNode(cascade_pos, cascade_receiver_var, cascade);
+ return new CommaNode(
+ cascade_pos,
+ cascade,
+ new LoadLocalNode(cascade_pos, cascade_receiver_var));
}
@@ -7790,9 +7784,10 @@
AstNode* store = CreateAssignmentNode(left_expr, add);
// The result is a pair of the (side effects of the) store followed by
// the (value of the) initial value temp variable load.
- LoadLocalNode* load_res =
- new LoadLocalNode(postfix_expr_pos, temp, store);
- return load_res;
+ return new CommaNode(
+ postfix_expr_pos,
+ store,
+ new LoadLocalNode(postfix_expr_pos, temp));
}
return postfix_expr;
}
diff --git a/runtime/vm/simulator_arm.cc b/runtime/vm/simulator_arm.cc
index 4e161c6..3542587 100644
--- a/runtime/vm/simulator_arm.cc
+++ b/runtime/vm/simulator_arm.cc
@@ -114,11 +114,13 @@
bool GetFValue(char* desc, float* value);
bool GetDValue(char* desc, double* value);
- void PrintDartFrame(uword pc, uword fp, uword sp,
- const Function& function,
- intptr_t token_pos,
- bool is_optimized,
- bool is_inlined);
+ static intptr_t GetApproximateTokenIndex(const Code& code, uword pc);
+
+ static void PrintDartFrame(uword pc, uword fp, uword sp,
+ const Function& function,
+ intptr_t token_pos,
+ bool is_optimized,
+ bool is_inlined);
void PrintBacktrace();
// Set or delete a breakpoint. Returns true if successful.
@@ -262,6 +264,23 @@
}
+intptr_t SimulatorDebugger::GetApproximateTokenIndex(const Code& code,
+ uword pc) {
+ intptr_t token_pos = -1;
+ const PcDescriptors& descriptors =
+ PcDescriptors::Handle(code.pc_descriptors());
+ for (intptr_t i = 0; i < descriptors.Length(); i++) {
+ if (descriptors.PC(i) == pc) {
+ token_pos = descriptors.TokenPos(i);
+ break;
+ } else if ((token_pos <= 0) && (descriptors.PC(i) > pc)) {
+ token_pos = descriptors.TokenPos(i);
+ }
+ }
+ return token_pos;
+}
+
+
void SimulatorDebugger::PrintDartFrame(uword pc, uword fp, uword sp,
const Function& function,
intptr_t token_pos,
@@ -313,7 +332,8 @@
if (!it.Done()) {
PrintDartFrame(unoptimized_pc, frame->fp(), frame->sp(),
inlined_function,
- unoptimized_code.GetTokenIndexOfPC(unoptimized_pc),
+ GetApproximateTokenIndex(unoptimized_code,
+ unoptimized_pc),
true, true);
}
}
@@ -321,7 +341,7 @@
}
PrintDartFrame(frame->pc(), frame->fp(), frame->sp(),
function,
- code.GetTokenIndexOfPC(frame->pc()),
+ GetApproximateTokenIndex(code, frame->pc()),
code.is_optimized(), false);
} else {
OS::Print("pc=0x%"Px" fp=0x%"Px" sp=0x%"Px" %s frame\n",
@@ -1664,6 +1684,32 @@
}
break;
}
+ case 7: {
+ // Registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs.
+ // Format(instr, "smlal'cond's 'rd, 'rn, 'rm, 'rs");
+ int32_t rd_lo_val = get_register(rd);
+ int32_t rd_hi_val = get_register(rn);
+ int64_t left_op = static_cast<int32_t>(rm_val);
+ int64_t right_op = static_cast<int32_t>(rs_val);
+ uint32_t accum_lo = static_cast<uint32_t>(rd_lo_val);
+ int32_t accum_hi = static_cast<int32_t>(rd_hi_val);
+ int64_t accum = Utils::LowHighTo64Bits(accum_lo, accum_hi);
+ int64_t result = accum + left_op * right_op;
+ int32_t hi_res = Utils::High32Bits(result);
+ int32_t lo_res = Utils::Low32Bits(result);
+ set_register(rd, lo_res);
+ set_register(rn, hi_res);
+ if (instr->HasS()) {
+ if (lo_res != 0) {
+ // Collapse bits 0..31 into bit 32 so that 32-bit Z check works.
+ hi_res |= 1;
+ }
+ ASSERT((result == 0) == (hi_res == 0)); // Z bit
+ ASSERT(((result & (1LL << 63)) != 0) == (hi_res < 0)); // N bit
+ SetNZFlags(hi_res);
+ }
+ break;
+ }
default: {
UnimplementedInstruction(instr);
break;
diff --git a/runtime/vm/simulator_mips.cc b/runtime/vm/simulator_mips.cc
index 393e261..0da94b0 100644
--- a/runtime/vm/simulator_mips.cc
+++ b/runtime/vm/simulator_mips.cc
@@ -1762,6 +1762,20 @@
}
break;
}
+ case SLTI: {
+ // Format(instr, "slti 'rt, 'rs, 'imms");
+ int32_t rs_val = get_register(instr->RsField());
+ int32_t imm_val = instr->SImmField();
+ set_register(instr->RtField(), rs_val < imm_val ? 1 : 0);
+ break;
+ }
+ case SLTIU: {
+ // Format(instr, "slti 'rt, 'rs, 'immu");
+ uint32_t rs_val = get_register(instr->RsField());
+ uint32_t imm_val = instr->UImmField();
+ set_register(instr->RtField(), rs_val < imm_val ? 1 : 0);
+ break;
+ }
case SDC1: {
// Format(instr, "sdc1 'ft, 'imms('rs)");
int32_t base_val = get_register(instr->RsField());
diff --git a/runtime/vm/stub_code_arm.cc b/runtime/vm/stub_code_arm.cc
index 0b8a041..1491ec3 100644
--- a/runtime/vm/stub_code_arm.cc
+++ b/runtime/vm/stub_code_arm.cc
@@ -437,13 +437,9 @@
// Push arguments descriptor array.
__ LoadImmediate(IP, reinterpret_cast<intptr_t>(Object::null()));
__ PushList((1 << R4) | (1 << R5) | (1 << R6) | (1 << IP));
-
- // R2: Smi-tagged arguments array length.
- PushArgumentsArray(assembler);
-
__ CallRuntime(kMegamorphicCacheMissHandlerRuntimeEntry);
// Remove arguments.
- __ Drop(4);
+ __ Drop(3);
__ Pop(R0); // Get result into R0.
// Restore IC data and arguments descriptor.
diff --git a/runtime/vm/stub_code_ia32.cc b/runtime/vm/stub_code_ia32.cc
index 0657984..1acfc81 100644
--- a/runtime/vm/stub_code_ia32.cc
+++ b/runtime/vm/stub_code_ia32.cc
@@ -448,7 +448,7 @@
__ pushl(raw_null); // Space for the result of the runtime call.
__ pushl(EAX); // Pass receiver.
__ pushl(ECX); // Pass IC data.
- __ pushl(EDX); // Pass rguments descriptor.
+ __ pushl(EDX); // Pass arguments descriptor.
__ CallRuntime(kMegamorphicCacheMissHandlerRuntimeEntry);
// Discard arguments.
__ popl(EAX);
diff --git a/runtime/vm/stub_code_mips.cc b/runtime/vm/stub_code_mips.cc
index 5881403..39d3357 100644
--- a/runtime/vm/stub_code_mips.cc
+++ b/runtime/vm/stub_code_mips.cc
@@ -111,8 +111,22 @@
}
+// Print the stop message.
+DEFINE_LEAF_RUNTIME_ENTRY(void, PrintStopMessage, const char* message) {
+ OS::Print("Stop message: %s\n", message);
+}
+END_LEAF_RUNTIME_ENTRY
+
+
+// Input parameters:
+// A0 : stop message (const char*).
+// Must preserve all registers.
void StubCode::GeneratePrintStopMessageStub(Assembler* assembler) {
- __ Unimplemented("PrintStopMessage stub");
+ __ EnterCallRuntimeFrame(0);
+ // Call the runtime leaf function. A0 already contains the parameter.
+ __ CallRuntime(kPrintStopMessageRuntimeEntry);
+ __ LeaveCallRuntimeFrame();
+ __ Ret();
}
@@ -239,6 +253,7 @@
void StubCode::GenerateFixCallersTargetStub(Assembler* assembler) {
// Create a stub frame as we are pushing some objects on the stack before
// calling into the runtime.
+ __ TraceSimMsg("FixCallersTarget");
__ EnterStubFrame();
// Setup space on stack for return value and preserve arguments descriptor.
__ addiu(SP, SP, Immediate(-2 * kWordSize));
@@ -324,17 +339,6 @@
PushArgumentsArray(assembler);
__ TraceSimMsg("InstanceFunctionLookupStub return");
- // Stack:
- // TOS + 0: argument array.
- // TOS + 1: arguments descriptor array.
- // TOS + 2: IC data object.
- // TOS + 3: Receiver.
- // TOS + 4: place for result from the call.
- // TOS + 5: saved FP of previous frame.
- // TOS + 6: dart code return address
- // TOS + 7: pc marker (0 for stub).
- // TOS + 8: last argument of caller.
- // ....
__ CallRuntime(kInstanceFunctionLookupRuntimeEntry);
__ lw(V0, Address(SP, 4 * kWordSize)); // Get result into V0.
@@ -351,6 +355,8 @@
DECLARE_LEAF_RUNTIME_ENTRY(void, DeoptimizeFillFrame, uword last_fp);
+
+
// Used by eager and lazy deoptimization. Preserve result in V0 if necessary.
// This stub translates optimized frame into unoptimized frame. The optimized
// frame can contain values in registers and on stack, the unoptimized
@@ -364,42 +370,53 @@
// GC can occur only after frame is fully rewritten.
// Stack after EnterFrame(...) below:
// +------------------+
-// | Saved FP | <- TOS
+// | Saved PP | <- TOS
// +------------------+
-// | return-address | (deoptimization point)
+// | Saved FP | <- FP of stub
// +------------------+
-// | optimized frame |
-// | ... |
+// | Saved LR | (deoptimization point)
+// +------------------+
+// | PC marker |
+// +------------------+
+// | ... | <- SP of optimized frame
//
// Parts of the code cannot GC, part of the code can GC.
static void GenerateDeoptimizationSequence(Assembler* assembler,
bool preserve_result) {
+ __ TraceSimMsg("GenerateDeoptimizationSequence");
const intptr_t kPushedRegistersSize =
kNumberOfCpuRegisters * kWordSize +
- 2 * kWordSize + // FP and RA.
+ 4 * kWordSize + // PP, FP, RA, PC marker.
kNumberOfFRegisters * kWordSize;
+ // DeoptimizeCopyFrame expects a Dart frame, i.e. EnterDartFrame(0), but there
+ // is no need to set the correct PC marker or load PP, since they get patched.
__ addiu(SP, SP, Immediate(-kPushedRegistersSize * kWordSize));
- __ sw(RA, Address(SP, kPushedRegistersSize - 1 * kWordSize));
- __ sw(FP, Address(SP, kPushedRegistersSize - 2 * kWordSize));
- __ addiu(FP, SP, Immediate(kPushedRegistersSize - 2 * kWordSize));
-
+ __ sw(ZR, Address(SP, kPushedRegistersSize - 1 * kWordSize));
+ __ sw(RA, Address(SP, kPushedRegistersSize - 2 * kWordSize));
+ __ sw(FP, Address(SP, kPushedRegistersSize - 3 * kWordSize));
+ __ sw(PP, Address(SP, kPushedRegistersSize - 4 * kWordSize));
+ __ addiu(FP, SP, Immediate(kPushedRegistersSize - 3 * kWordSize));
// The code in this frame may not cause GC. kDeoptimizeCopyFrameRuntimeEntry
// and kDeoptimizeFillFrameRuntimeEntry are leaf runtime calls.
- const intptr_t saved_v0_offset_from_fp = -(kNumberOfCpuRegisters - V0);
+ const intptr_t saved_result_slot_from_fp =
+ kFirstLocalSlotFromFp + 1 - (kNumberOfCpuRegisters - V0);
// Result in V0 is preserved as part of pushing all registers below.
+ // TODO(regis): Should we align the stack before pushing the fpu registers?
+ // If we do, saved_result_slot_from_fp is not constant anymore.
+
// Push registers in their enumeration order: lowest register number at
// lowest address.
for (int i = 0; i < kNumberOfCpuRegisters; i++) {
- const int slot = 2 + kNumberOfCpuRegisters - i;
+ const int slot = 4 + kNumberOfCpuRegisters - i;
Register reg = static_cast<Register>(i);
__ sw(reg, Address(SP, kPushedRegistersSize - slot * kWordSize));
}
for (int i = 0; i < kNumberOfFRegisters; i++) {
// These go below the CPU registers.
- const int slot = 2 + kNumberOfCpuRegisters + kNumberOfFRegisters - i;
+ const int slot = 4 + kNumberOfCpuRegisters + kNumberOfFRegisters - i;
FRegister reg = static_cast<FRegister>(i);
__ swc1(reg, Address(SP, kPushedRegistersSize - slot * kWordSize));
}
@@ -411,38 +428,40 @@
if (preserve_result) {
// Restore result into T1 temporarily.
- __ lw(T1, Address(FP, saved_v0_offset_from_fp * kWordSize));
+ __ lw(T1, Address(FP, saved_result_slot_from_fp * kWordSize));
}
- __ mov(SP, FP);
- __ lw(FP, Address(SP, 0 * kWordSize));
- __ lw(RA, Address(SP, 1 * kWordSize));
- __ addiu(SP, SP, Immediate(2 * kWordSize));
-
+ __ addiu(SP, FP, Immediate(-kWordSize));
+ __ lw(RA, Address(SP, 2 * kWordSize));
+ __ lw(FP, Address(SP, 1 * kWordSize));
+ __ lw(PP, Address(SP, 0 * kWordSize));
__ subu(SP, FP, V0);
- __ addiu(SP, SP, Immediate(-2 * kWordSize));
- __ sw(RA, Address(SP, 1 * kWordSize));
- __ sw(FP, Address(SP, 0 * kWordSize));
- __ mov(FP, SP);
+ // DeoptimizeFillFrame expects a Dart frame, i.e. EnterDartFrame(0), but there
+ // is no need to set the correct PC marker or load PP, since they get patched.
+ __ addiu(SP, SP, Immediate(-4 * kWordSize));
+ __ sw(ZR, Address(SP, 3 * kWordSize));
+ __ sw(RA, Address(SP, 2 * kWordSize));
+ __ sw(FP, Address(SP, 1 * kWordSize));
+ __ sw(PP, Address(SP, 0 * kWordSize));
+ __ addiu(FP, SP, Immediate(kWordSize));
- __ mov(A0, SP); // Get last FP address.
+ __ mov(A0, FP); // Get last FP address.
if (preserve_result) {
- __ Push(T1); // Preserve result.
+ __ Push(T1); // Preserve result as first local.
}
__ ReserveAlignedFrameSpace(0);
__ CallRuntime(kDeoptimizeFillFrameRuntimeEntry); // Pass last FP in A0.
- // Result (V0) is our FP.
if (preserve_result) {
// Restore result into T1.
- __ lw(T1, Address(FP, -1 * kWordSize));
+ __ lw(T1, Address(FP, kFirstLocalSlotFromFp * kWordSize));
}
// Code above cannot cause GC.
- __ mov(SP, FP);
- __ lw(FP, Address(SP, 0 * kWordSize));
- __ lw(RA, Address(SP, 1 * kWordSize));
- __ addiu(SP, SP, Immediate(2 * kWordSize));
- __ mov(FP, V0);
+ __ addiu(SP, FP, Immediate(-kWordSize));
+ __ lw(RA, Address(SP, 2 * kWordSize));
+ __ lw(FP, Address(SP, 1 * kWordSize));
+ __ lw(PP, Address(SP, 0 * kWordSize));
+ __ addiu(SP, SP, Immediate(4 * kWordSize));
// Frame is fully rewritten at this point and it is safe to perform a GC.
// Materialize any objects that were deferred by FillFrame because they
@@ -456,20 +475,22 @@
// Result tells stub how many bytes to remove from the expression stack
// of the bottom-most frame. They were used as materialization arguments.
__ Pop(T1);
- __ SmiUntag(T1);
if (preserve_result) {
__ Pop(V0); // Restore result.
}
__ LeaveStubFrame();
-
- // Return.
- __ jr(RA);
- __ delay_slot()->addu(SP, SP, T1); // Remove materialization arguments.
+ // Remove materialization arguments.
+ __ SmiUntag(T1);
+ __ addu(SP, SP, T1);
+ __ Ret();
}
void StubCode::GenerateDeoptimizeLazyStub(Assembler* assembler) {
- __ Unimplemented("DeoptimizeLazy stub");
+ // Correct return address to point just after the call that is being
+ // deoptimized.
+ __ AddImmediate(RA, -CallPattern::kFixedLengthInBytes);
+ GenerateDeoptimizationSequence(assembler, true); // Preserve V0.
}
@@ -480,6 +501,7 @@
void StubCode::GenerateMegamorphicMissStub(Assembler* assembler) {
__ Unimplemented("MegamorphicMiss stub");
+ return;
}
@@ -866,6 +888,7 @@
// Output:
// V0: new allocated RawContext object.
void StubCode::GenerateAllocateContextStub(Assembler* assembler) {
+ __ TraceSimMsg("AllocateContext");
if (FLAG_inline_alloc) {
const Class& context_class = Class::ZoneHandle(Object::context_class());
Label slow_case;
@@ -1757,6 +1780,7 @@
void StubCode::GenerateBreakpointDynamicStub(Assembler* assembler) {
// Create a stub frame as we are pushing some objects on the stack before
// calling into the runtime.
+ __ TraceSimMsg("BreakpointDynamicStub");
__ EnterStubFrame();
__ addiu(SP, SP, Immediate(-2 * kWordSize));
__ sw(S5, Address(SP, 1 * kWordSize));
@@ -2137,6 +2161,8 @@
__ Bind(&reference_compare);
__ subu(ret, left, right);
__ Bind(&done);
+ // A branch or test after this comparison will check CMPRES == TMP1.
+ __ mov(TMP1, ZR);
__ lw(T0, Address(SP, 0 * kWordSize));
__ lw(T1, Address(SP, 1 * kWordSize));
__ Ret();
diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h
index 8a4b2c9..6bc6f34 100644
--- a/runtime/vm/symbols.h
+++ b/runtime/vm/symbols.h
@@ -251,13 +251,11 @@
V(DartCore, "dart:core") \
V(DartCollection, "dart:collection") \
V(DartCollectionDev, "dart:_collection-dev") \
- V(DartCrypto, "dart:crypto") \
V(DartIsolate, "dart:isolate") \
V(DartJson, "dart:json") \
V(DartMath, "dart:math") \
V(DartMirrors, "dart:mirrors") \
V(DartTypedData, "dart:typed_data") \
- V(DartUri, "dart:uri") \
V(DartUtf, "dart:utf") \
V(_Random, "_Random") \
V(_state, "_state") \
diff --git a/runtime/vm/vm.gypi b/runtime/vm/vm.gypi
index 058f5ce..1e1da59 100644
--- a/runtime/vm/vm.gypi
+++ b/runtime/vm/vm.gypi
@@ -15,7 +15,6 @@
'collection_patch_cc_file': '<(gen_source_dir)/collection_patch_gen.cc',
'collection_dev_cc_file': '<(gen_source_dir)/collection_dev_gen.cc',
'collection_dev_patch_cc_file': '<(gen_source_dir)/collection_dev_patch_gen.cc',
- 'crypto_cc_file': '<(gen_source_dir)/crypto_gen.cc',
'math_cc_file': '<(gen_source_dir)/math_gen.cc',
'math_patch_cc_file': '<(gen_source_dir)/math_patch_gen.cc',
'mirrors_cc_file': '<(gen_source_dir)/mirrors_gen.cc',
@@ -26,7 +25,6 @@
'json_patch_cc_file': '<(gen_source_dir)/json_patch_gen.cc',
'typed_data_cc_file': '<(gen_source_dir)/typed_data_gen.cc',
'typed_data_patch_cc_file': '<(gen_source_dir)/typed_data_patch_gen.cc',
- 'uri_cc_file': '<(gen_source_dir)/uri_gen.cc',
'utf_cc_file': '<(gen_source_dir)/utf_gen.cc',
'snapshot_test_dat_file': '<(gen_source_dir)/snapshot_test.dat',
'snapshot_test_in_dat_file': 'snapshot_test_in.dat',
@@ -103,7 +101,6 @@
'generate_collection_patch_cc_file',
'generate_collection_dev_cc_file',
'generate_collection_dev_patch_cc_file',
- 'generate_crypto_cc_file',
'generate_math_cc_file',
'generate_math_patch_cc_file',
'generate_isolate_cc_file',
@@ -114,7 +111,6 @@
'generate_mirrors_patch_cc_file',
'generate_typed_data_cc_file',
'generate_typed_data_patch_cc_file',
- 'generate_uri_cc_file',
'generate_utf_cc_file',
],
'includes': [
@@ -137,7 +133,6 @@
'<(collection_patch_cc_file)',
'<(collection_dev_cc_file)',
'<(collection_dev_patch_cc_file)',
- '<(crypto_cc_file)',
'<(math_cc_file)',
'<(math_patch_cc_file)',
'<(isolate_cc_file)',
@@ -148,7 +143,6 @@
'<(mirrors_patch_cc_file)',
'<(typed_data_cc_file)',
'<(typed_data_patch_cc_file)',
- '<(uri_cc_file)',
'<(utf_cc_file)',
],
'include_dirs': [
@@ -415,39 +409,6 @@
]
},
{
- 'target_name': 'generate_crypto_cc_file',
- 'type': 'none',
- 'toolsets':['host', 'target'],
- 'includes': [
- # Load the shared crypto sources.
- '../../sdk/lib/crypto/crypto_sources.gypi',
- ],
- 'actions': [
- {
- 'action_name': 'generate_crypto_cc',
- 'inputs': [
- '../tools/gen_library_src_paths.py',
- '<(libgen_in_cc_file)',
- '<@(_sources)',
- ],
- 'outputs': [
- '<(crypto_cc_file)',
- ],
- 'action': [
- 'python',
- 'tools/gen_library_src_paths.py',
- '--output', '<(crypto_cc_file)',
- '--input_cc', '<(libgen_in_cc_file)',
- '--include', 'vm/bootstrap.h',
- '--var_name', 'dart::Bootstrap::crypto_source_paths_',
- '--library_name', 'dart:crypto',
- '<@(_sources)',
- ],
- 'message': 'Generating ''<(crypto_cc_file)'' file.'
- },
- ]
- },
- {
'target_name': 'generate_math_cc_file',
'type': 'none',
'toolsets':['host', 'target'],
@@ -921,39 +882,6 @@
]
},
{
- 'target_name': 'generate_uri_cc_file',
- 'type': 'none',
- 'toolsets':['host', 'target'],
- 'includes': [
- # Load the shared uri sources.
- '../../sdk/lib/uri/uri_sources.gypi',
- ],
- 'actions': [
- {
- 'action_name': 'generate_uri_cc',
- 'inputs': [
- '../tools/gen_library_src_paths.py',
- '<(libgen_in_cc_file)',
- '<@(_sources)',
- ],
- 'outputs': [
- '<(uri_cc_file)',
- ],
- 'action': [
- 'python',
- 'tools/gen_library_src_paths.py',
- '--output', '<(uri_cc_file)',
- '--input_cc', '<(libgen_in_cc_file)',
- '--include', 'vm/bootstrap.h',
- '--var_name', 'dart::Bootstrap::uri_source_paths_',
- '--library_name', 'dart:uri',
- '<@(_sources)',
- ],
- 'message': 'Generating ''<(uri_cc_file)'' file.'
- },
- ]
- },
- {
'target_name': 'generate_utf_cc_file',
'type': 'none',
'toolsets':['host', 'target'],
diff --git a/sdk/bin/dartanalyzer b/sdk/bin/dartanalyzer
index 3f0f947..cc33e5c 100755
--- a/sdk/bin/dartanalyzer
+++ b/sdk/bin/dartanalyzer
@@ -29,16 +29,16 @@
DART_SDK=""
if [ $FOUND_SDK = 0 ] ; then
- if [ -f $DART_ANALYZER_HOME/lib/core/core.dart ] ; then
- DART_SDK="--dart-sdk $DART_ANALYZER_HOME"
+ if [ -f "$DART_ANALYZER_HOME/lib/core/core.dart" ] ; then
+ DART_SDK=(--dart-sdk "$DART_ANALYZER_HOME")
else
- DART_SDK_HOME=$(dirname $DART_ANALYZER_HOME)/dart-sdk
- if [ -d $DART_SDK_HOME ] ; then
- DART_SDK="--dart-sdk $DART_SDK_HOME"
+ DART_SDK_HOME=$(dirname "$DART_ANALYZER_HOME")/dart-sdk
+ if [ -d "$DART_SDK_HOME" ] ; then
+ DART_SDK=(--dart-sdk "$DART_SDK_HOME")
else
- DART_SDK_HOME=$(dirname $DART_SDK_HOME)/dart-sdk
- if [ -d $DART_SDK_HOME ] ; then
- DART_SDK="--dart-sdk $DART_SDK_HOME"
+ DART_SDK_HOME=$(dirname "$DART_SDK_HOME")/dart-sdk
+ if [ -d "$DART_SDK_HOME" ] ; then
+ DART_SDK=(--dart-sdk "$DART_SDK_HOME")
else
echo "Couldn't find Dart SDK. Specify with --dart-sdk cmdline argument"
fi
@@ -46,9 +46,9 @@
fi
fi
-if [ -f $DART_SDK_HOME/util/dartanalyzer/dartanalyzer.jar ] ; then
+if [ -f "$DART_SDK_HOME/util/dartanalyzer/dartanalyzer.jar" ] ; then
DART_ANALYZER_LIBS=$DART_SDK_HOME/util/dartanalyzer
-elif [ -f $DART_ANALYZER_HOME/util/dartanalyzer/dartanalyzer.jar ] ; then
+elif [ -f "$DART_ANALYZER_HOME/util/dartanalyzer/dartanalyzer.jar" ] ; then
DART_ANALYZER_LIBS=$DART_ANALYZER_HOME/util/dartanalyzer
else
echo "Configuration problem. Couldn't find dartanalyzer.jar."
@@ -76,4 +76,4 @@
fi
exec java $EXTRA_JVMARGS $DART_JVMARGS -ea -jar \
- "$DART_ANALYZER_LIBS/dartanalyzer.jar" ${DART_SDK} $@
+ "$DART_ANALYZER_LIBS/dartanalyzer.jar" "${DART_SDK[@]}" $@
diff --git a/sdk/bin/dartanalyzer.bat b/sdk/bin/dartanalyzer.bat
index d3ed53b..4905124 100644
--- a/sdk/bin/dartanalyzer.bat
+++ b/sdk/bin/dartanalyzer.bat
@@ -36,12 +36,12 @@
)
)
)
-endlocal & set "DART_SDK=%DART_SDK%" & set "DART_SDK_HOME=%DART_SDK_HOME%"
+endlocal & set DART_SDK=%DART_SDK% & set DART_SDK_HOME=%DART_SDK_HOME%
if exist "%DART_SDK_HOME%\util\dartanalyzer\dartanalyzer.jar" (
- set DART_ANALYZER_LIBS="%DART_SDK_HOME%\util\dartanalyzer"
+ set DART_ANALYZER_LIBS=%DART_SDK_HOME%\util\dartanalyzer
) else if exist "%DART_ANALYZER_HOME%\util\dartanalyzer\dartanalyzer.jar" (
- set DART_ANALYZER_LIBS="%DART_ANALYZER_HOME%\util\dartanalyzer"
+ set DART_ANALYZER_LIBS=%DART_ANALYZER_HOME%\util\dartanalyzer
) else (
echo Configuration problem. Couldn't find dartanalyzer.jar.
exit /b 1
diff --git a/sdk/lib/_collection_dev/list.dart b/sdk/lib/_collection_dev/list.dart
index c14cb50..90a1d16 100644
--- a/sdk/lib/_collection_dev/list.dart
+++ b/sdk/lib/_collection_dev/list.dart
@@ -238,6 +238,7 @@
Iterable<int> get keys => new _ListIndicesIterable(_values);
bool get isEmpty => _values.isEmpty;
+ bool get isNotEmpty => _values.isNotEmpty;
bool containsValue(E value) => _values.contains(value);
bool containsKey(int key) => key is int && key >= 0 && key < length;
diff --git a/sdk/lib/_internal/compiler/compiler.dart b/sdk/lib/_internal/compiler/compiler.dart
index 41c5ac1..e0be239 100644
--- a/sdk/lib/_internal/compiler/compiler.dart
+++ b/sdk/lib/_internal/compiler/compiler.dart
@@ -5,7 +5,6 @@
library compiler;
import 'dart:async';
-import 'dart:uri';
import 'implementation/apiimpl.dart';
// Unless explicitly allowed, passing [:null:] for any argument to the
diff --git a/sdk/lib/_internal/compiler/implementation/apiimpl.dart b/sdk/lib/_internal/compiler/implementation/apiimpl.dart
index 69d3cfa..c582bc0 100644
--- a/sdk/lib/_internal/compiler/implementation/apiimpl.dart
+++ b/sdk/lib/_internal/compiler/implementation/apiimpl.dart
@@ -4,7 +4,6 @@
library leg_apiimpl;
-import 'dart:uri';
import 'dart:async';
import '../compiler.dart' as api;
@@ -136,7 +135,7 @@
elements.LibraryElement scanBuiltinLibrary(String path) {
Uri uri = libraryRoot.resolve(lookupLibraryPath(path));
- Uri canonicalUri = new Uri.fromComponents(scheme: "dart", path: path);
+ Uri canonicalUri = new Uri(scheme: "dart", path: path);
elements.LibraryElement library =
libraryLoader.loadLibrary(uri, null, canonicalUri);
return library;
diff --git a/sdk/lib/_internal/compiler/implementation/code_buffer.dart b/sdk/lib/_internal/compiler/implementation/code_buffer.dart
index 1d58b9b..4934ea3 100644
--- a/sdk/lib/_internal/compiler/implementation/code_buffer.dart
+++ b/sdk/lib/_internal/compiler/implementation/code_buffer.dart
@@ -20,6 +20,8 @@
return buffer.isEmpty;
}
+ bool get isNotEmpty => !isEmpty;
+
CodeBuffer add(var object) {
write(object);
return this;
diff --git a/sdk/lib/_internal/compiler/implementation/compiler.dart b/sdk/lib/_internal/compiler/implementation/compiler.dart
index a292e28..f14543f 100644
--- a/sdk/lib/_internal/compiler/implementation/compiler.dart
+++ b/sdk/lib/_internal/compiler/implementation/compiler.dart
@@ -318,6 +318,7 @@
ClassElement typeClass;
ClassElement mapClass;
ClassElement symbolClass;
+ ClassElement stackTraceClass;
// Initialized after mirrorSystemClass has been resolved.
FunctionElement symbolConstructor;
@@ -579,7 +580,8 @@
} else if (node is Element) {
return spanFromElement(node);
} else if (node is MetadataAnnotation) {
- return spanFromTokens(node.beginToken, node.endToken);
+ MetadataAnnotation annotation = node;
+ return spanFromTokens(annotation.beginToken, annotation.endToken);
} else {
throw 'No error location.';
}
@@ -679,6 +681,7 @@
listClass = lookupCoreClass('List');
typeClass = lookupCoreClass('Type');
mapClass = lookupCoreClass('Map');
+ stackTraceClass = lookupCoreClass('StackTrace');
if (!missingCoreClasses.isEmpty) {
internalErrorOnElement(coreLibrary,
'dart:core library does not contain required classes: '
@@ -741,7 +744,7 @@
invokeOnMethod = jsInvocationMirrorClass.lookupLocalMember(INVOKE_ON);
if (preserveComments) {
- var uri = new Uri.fromComponents(scheme: 'dart', path: 'mirrors');
+ var uri = new Uri(scheme: 'dart', path: 'mirrors');
LibraryElement libraryElement =
libraryLoader.loadLibrary(uri, null, uri);
documentClass = libraryElement.find(const SourceString('Comment'));
@@ -1108,7 +1111,9 @@
if (Elements.isErroneousElement(element)) {
element = element.enclosingElement;
}
- if (element.position() == null && !element.isCompilationUnit()) {
+ if (element.position() == null &&
+ !element.isLibrary() &&
+ !element.isCompilationUnit()) {
// Sometimes, the backend fakes up elements that have no
// position. So we use the enclosing element instead. It is
// not a good error location, but cancel really is "internal
diff --git a/sdk/lib/_internal/compiler/implementation/dart2js.dart b/sdk/lib/_internal/compiler/implementation/dart2js.dart
index 20856b7..8d3c7da 100644
--- a/sdk/lib/_internal/compiler/implementation/dart2js.dart
+++ b/sdk/lib/_internal/compiler/implementation/dart2js.dart
@@ -7,7 +7,6 @@
import 'dart:async';
import 'dart:collection' show Queue, LinkedHashMap;
import 'dart:io';
-import 'dart:uri';
import 'dart:utf';
import '../compiler.dart' as api;
diff --git a/sdk/lib/_internal/compiler/implementation/dart2jslib.dart b/sdk/lib/_internal/compiler/implementation/dart2jslib.dart
index 6dd95ef..c006c95 100644
--- a/sdk/lib/_internal/compiler/implementation/dart2jslib.dart
+++ b/sdk/lib/_internal/compiler/implementation/dart2jslib.dart
@@ -5,7 +5,6 @@
library dart2js;
import 'dart:async';
-import 'dart:uri';
import 'dart:collection' show Queue, LinkedHashMap;
import 'closure.dart' as closureMapping;
diff --git a/sdk/lib/_internal/compiler/implementation/dart_backend/backend.dart b/sdk/lib/_internal/compiler/implementation/dart_backend/backend.dart
index 26b930d..5bc30cd 100644
--- a/sdk/lib/_internal/compiler/implementation/dart_backend/backend.dart
+++ b/sdk/lib/_internal/compiler/implementation/dart_backend/backend.dart
@@ -77,8 +77,10 @@
visitBlock(Block block) {
shouldOmit(Statement statement) {
if (statement is EmptyStatement) return true;
- if (statement is ExpressionStatement) {
- Send send = statement.expression.asSend();
+ ExpressionStatement expressionStatement =
+ statement.asExpressionStatement();
+ if (expressionStatement != null) {
+ Send send = expressionStatement.expression.asSend();
if (send != null) {
Element element = originalTreeElements[send];
if (stripAsserts && identical(element, compiler.assertMethod)) {
@@ -90,8 +92,9 @@
}
rewriteStatement(Statement statement) {
- if (statement is Block) {
- Link statements = statement.statements.nodes;
+ Block block = statement.asBlock();
+ if (block != null) {
+ Link statements = block.statements.nodes;
if (!statements.isEmpty && statements.tail.isEmpty) {
Statement single = statements.head;
bool isDeclaration =
@@ -150,7 +153,8 @@
if (typeArguments == null) return;
for (Node typeArgument in typeArguments.nodes) {
if (typeArgument is TypeVariable) {
- typeArgument = typeArgument.bound;
+ TypeVariable typeVariable = typeArgument;
+ typeArgument = typeVariable.bound;
}
if (typeArgument == null) continue;
assert(typeArgument is TypeAnnotation);
diff --git a/sdk/lib/_internal/compiler/implementation/dart_backend/placeholder_collector.dart b/sdk/lib/_internal/compiler/implementation/dart_backend/placeholder_collector.dart
index e5ecbf3..2d67ace 100644
--- a/sdk/lib/_internal/compiler/implementation/dart_backend/placeholder_collector.dart
+++ b/sdk/lib/_internal/compiler/implementation/dart_backend/placeholder_collector.dart
@@ -265,12 +265,13 @@
}
void makeTypePlaceholder(Node node, DartType type) {
- if (node is Send) {
+ Send send = node.asSend();
+ if (send != null) {
// Prefix.
- assert(node.receiver is Identifier);
- assert(node.selector is Identifier);
- makeNullPlaceholder(node.receiver);
- node = node.selector;
+ assert(send.receiver is Identifier);
+ assert(send.selector is Identifier);
+ makeNullPlaceholder(send.receiver);
+ node = send.selector;
}
makeElementPlaceholder(node, type.element);
}
@@ -497,20 +498,21 @@
// TODO(smok): Fix this when resolver correctly deals with
// such cases.
if (definitionElement == null) continue;
- if (definition is Send) {
+ Send send = definition.asSend();
+ if (send != null) {
// May get FunctionExpression here in definition.selector
// in case of A(int this.f());
- if (definition.selector is Identifier) {
+ if (send.selector is Identifier) {
if (identical(definitionElement.kind, ElementKind.FIELD_PARAMETER)) {
- tryMakeMemberPlaceholder(definition.selector);
+ tryMakeMemberPlaceholder(send.selector);
} else {
- tryMakeLocalPlaceholder(definitionElement, definition.selector);
+ tryMakeLocalPlaceholder(definitionElement, send.selector);
}
} else {
- assert(definition.selector is FunctionExpression);
+ assert(send.selector is FunctionExpression);
if (identical(definitionElement.kind, ElementKind.FIELD_PARAMETER)) {
tryMakeMemberPlaceholder(
- definition.selector.asFunctionExpression().name);
+ send.selector.asFunctionExpression().name);
}
}
} else if (definition is Identifier) {
diff --git a/sdk/lib/_internal/compiler/implementation/dart_backend/renamer.dart b/sdk/lib/_internal/compiler/implementation/dart_backend/renamer.dart
index 83531c7..5ad2230 100644
--- a/sdk/lib/_internal/compiler/implementation/dart_backend/renamer.dart
+++ b/sdk/lib/_internal/compiler/implementation/dart_backend/renamer.dart
@@ -88,9 +88,10 @@
// js-helpers.
StringBuffer result = new StringBuffer(renameElement(type.element));
if (type is InterfaceType) {
- if (!type.isRaw) {
+ InterfaceType interfaceType = type;
+ if (!interfaceType.isRaw) {
result.write('<');
- Link<DartType> argumentsLink = type.typeArguments;
+ Link<DartType> argumentsLink = interfaceType.typeArguments;
result.write(renameType(argumentsLink.head, renameElement));
for (Link<DartType> link = argumentsLink.tail; !link.isEmpty;
link = link.tail) {
diff --git a/sdk/lib/_internal/compiler/implementation/deferred_load.dart b/sdk/lib/_internal/compiler/implementation/deferred_load.dart
index abcf627..1a8d770 100644
--- a/sdk/lib/_internal/compiler/implementation/deferred_load.dart
+++ b/sdk/lib/_internal/compiler/implementation/deferred_load.dart
@@ -4,9 +4,6 @@
library deferred_load;
-import 'dart:uri'
- show Uri;
-
import 'dart:collection'
show LinkedHashMap,
LinkedHashSet;
@@ -65,7 +62,7 @@
}
ClassElement findDeferredLibraryClass() {
- var uri = new Uri.fromComponents(scheme: 'dart', path: 'async');
+ var uri = new Uri(scheme: 'dart', path: 'async');
LibraryElement asyncLibrary =
compiler.libraryLoader.loadLibrary(uri, null, uri);
var element = asyncLibrary.find(const SourceString('DeferredLibrary'));
diff --git a/sdk/lib/_internal/compiler/implementation/elements/elements.dart b/sdk/lib/_internal/compiler/implementation/elements/elements.dart
index c0bc01e4..bd1fac2 100644
--- a/sdk/lib/_internal/compiler/implementation/elements/elements.dart
+++ b/sdk/lib/_internal/compiler/implementation/elements/elements.dart
@@ -4,7 +4,6 @@
library elements;
-import 'dart:uri';
import 'modelx.dart';
import '../tree/tree.dart';
@@ -827,8 +826,8 @@
void reverseBackendMembers();
Element lookupMember(SourceString memberName);
- Element lookupSelector(Selector selector);
- Element lookupSuperSelector(Selector selector);
+ Element lookupSelector(Selector selector, Compiler compiler);
+ Element lookupSuperSelector(Selector selector, Compiler compiler);
Element lookupLocalMember(SourceString memberName);
Element lookupBackendMember(SourceString memberName);
diff --git a/sdk/lib/_internal/compiler/implementation/elements/modelx.dart b/sdk/lib/_internal/compiler/implementation/elements/modelx.dart
index 5762744..1ea7a23 100644
--- a/sdk/lib/_internal/compiler/implementation/elements/modelx.dart
+++ b/sdk/lib/_internal/compiler/implementation/elements/modelx.dart
@@ -4,7 +4,6 @@
library elements.modelx;
-import 'dart:uri';
import 'dart:collection' show LinkedHashMap;
import 'elements.dart';
@@ -1582,15 +1581,17 @@
* When called on the implementation element both members declared in the
* origin and the patch class are returned.
*/
- Element lookupSelector(Selector selector) {
- return internalLookupSelector(selector, false);
+ Element lookupSelector(Selector selector, Compiler compiler) {
+ return internalLookupSelector(selector, compiler, false);
}
- Element lookupSuperSelector(Selector selector) {
- return internalLookupSelector(selector, true);
+ Element lookupSuperSelector(Selector selector, Compiler compiler) {
+ return internalLookupSelector(selector, compiler, true);
}
- Element internalLookupSelector(Selector selector, bool isSuperLookup) {
+ Element internalLookupSelector(Selector selector,
+ Compiler compiler,
+ bool isSuperLookup) {
SourceString name = selector.name;
bool isPrivate = name.isPrivate();
LibraryElement library = selector.library;
@@ -1616,12 +1617,14 @@
FunctionElement getter = field.getter;
FunctionElement setter = field.setter;
if (selector.isSetter()) {
- if (setter != null) return setter;
+ // Abstract members can be defined in a super class.
+ if (setter != null && !setter.isAbstract(compiler)) return setter;
} else {
assert(selector.isGetter() || selector.isCall());
- if (getter != null) return getter;
+ if (getter != null && !getter.isAbstract(compiler)) return getter;
}
- } else {
+ // Abstract members can be defined in a super class.
+ } else if (!member.isAbstract(compiler)) {
return member;
}
}
diff --git a/sdk/lib/_internal/compiler/implementation/enqueue.dart b/sdk/lib/_internal/compiler/implementation/enqueue.dart
index ca6d2d6..18bf774 100644
--- a/sdk/lib/_internal/compiler/implementation/enqueue.dart
+++ b/sdk/lib/_internal/compiler/implementation/enqueue.dart
@@ -23,7 +23,11 @@
if (element.isLibrary()) {
LibraryElementX library = element;
Uri uri = library.canonicalUri;
- if (uri.scheme != 'dart' && !uri.path.startsWith('_')) {
+ // Don't include private implementation libraries. These
+ // libraries contain special classes that cause problems
+ // in other parts of the resolver (in particular Null and Void).
+ // TODO(ahe): Consider lifting this restriction.
+ if (uri.scheme != 'dart' || !uri.path.startsWith('_')) {
members = library.localMembers;
// TODO(ahe): Is this right? Is this necessary?
name = library.getLibraryOrScriptName();
@@ -278,6 +282,12 @@
cls.ensureResolved(compiler);
cls.implementation.forEachMember(processInstantiatedClassMember);
if (isResolutionQueue) {
+ // Only the resolution queue needs to operate on individual
+ // fields. The codegen enqueuer inlines the potential field
+ // intializations in the constructor.
+ cls.implementation.forEachInstanceField((_, Element field) {
+ addToWorkList(field);
+ }, includeSuperAndInjectedMembers: true);
compiler.resolver.checkClass(cls);
}
}
diff --git a/sdk/lib/_internal/compiler/implementation/filenames.dart b/sdk/lib/_internal/compiler/implementation/filenames.dart
index 46bc421..c5cc4e9 100644
--- a/sdk/lib/_internal/compiler/implementation/filenames.dart
+++ b/sdk/lib/_internal/compiler/implementation/filenames.dart
@@ -5,7 +5,6 @@
library filenames;
import 'dart:io';
-import 'dart:uri';
// TODO(ahe): This library should be replaced by a general
// path-munging library.
@@ -21,7 +20,7 @@
return new Path(path).toNativePath();
}
-final Uri currentDirectory = new Uri.fromComponents(
+final Uri currentDirectory = new Uri(
scheme: 'file',
path: appendSlash(nativeToUriPath(new File('.').fullPathSync())));
diff --git a/sdk/lib/_internal/compiler/implementation/js/printer.dart b/sdk/lib/_internal/compiler/implementation/js/printer.dart
index 2645362..f7d65c1 100644
--- a/sdk/lib/_internal/compiler/implementation/js/printer.dart
+++ b/sdk/lib/_internal/compiler/implementation/js/printer.dart
@@ -161,7 +161,8 @@
void blockOutWithoutBraces(Node node) {
if (node is Block) {
- node.statements.forEach(blockOutWithoutBraces);
+ Block block = node;
+ block.statements.forEach(blockOutWithoutBraces);
} else {
visit(node);
}
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart b/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart
index d2584bc..fde02b4 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart
@@ -828,6 +828,10 @@
return interceptedElements[name] != null;
}
+ bool isInterceptedSelector(Selector selector) {
+ return interceptedElements[selector.name] != null;
+ }
+
final Map<SourceString, Set<ClassElement>> interceptedClassesCache =
new Map<SourceString, Set<ClassElement>>();
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart b/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart
index 54ded9c..6ecbfd5 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart
@@ -1254,7 +1254,6 @@
String holder = namer.isolateAccess(backend.getImplementationClass(cls));
for (TypeCheck check in typeChecks[cls]) {
ClassElement cls = check.cls;
- buffer.write('$holder.${namer.operatorIs(check.cls)}$_=${_}true$N');
buffer.write('$holder.${namer.operatorIs(cls)}$_=${_}true$N');
Substitution substitution = check.substitution;
if (substitution != null) {
@@ -1741,7 +1740,8 @@
List<Constant> constants = handler.getConstantsForEmission();
for (Constant constant in constants) {
if (constant is InterceptorConstant) {
- needed.add(constant.dispatchedType.element);
+ InterceptorConstant inceptorConstant = constant;
+ needed.add(inceptorConstant.dispatchedType.element);
}
}
@@ -3033,16 +3033,28 @@
for (LibraryElement library in sortedLibraries) {
List<CodeBuffer> buffers = libraryBuffers[library];
var buffer = buffers[0];
+ var uri = library.canonicalUri;
+ if (uri.scheme == 'file' && compiler.sourceMapUri != null) {
+ // TODO(ahe): It is a hack to use compiler.sourceMapUri
+ // here. It should be relative to the main JavaScript
+ // output file.
+ uri = relativize(
+ compiler.sourceMapUri, library.canonicalUri, false);
+ }
if (buffer != null) {
mainBuffer
- ..write('["${library.getLibraryOrScriptName()}",$_{$n')
+ ..write('["${library.getLibraryOrScriptName()}",$_')
+ ..write('"${uri}",$_')
+ ..write('{$n')
..addBuffer(buffer)
..write('}],$n');
}
buffer = buffers[1];
if (buffer != null) {
deferredBuffer
- ..write('["${library.getLibraryOrScriptName()}",$_{$n')
+ ..write('["${library.getLibraryOrScriptName()}",$_')
+ ..write('"${uri}",$_')
+ ..write('{$n')
..addBuffer(buffer)
..write('}],$n');
}
@@ -3227,7 +3239,8 @@
for (var i = 0; i < length; i++) {
var data = reflectionData[i];
var name = data[0];
- var descriptor = data[1];
+ var uri = data[1];
+ var descriptor = data[2];
var classes = [];
var functions = [];
for (var property in descriptor) {
@@ -3242,7 +3255,6 @@
classes.push(element[""]);
}
}
- var uri = ".../library" + i + ".dart";
libraries.push([name, uri, classes, functions]);
}
})''';
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/js_backend.dart b/sdk/lib/_internal/compiler/implementation/js_backend/js_backend.dart
index fae1efc..4f7b499 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/js_backend.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/js_backend.dart
@@ -25,6 +25,7 @@
import '../universe/universe.dart' hide js; // TODO(ahe): VM bug, see above.
import '../util/characters.dart';
import '../util/util.dart';
+import '../util/uri_extras.dart' show relativize;
part 'backend.dart';
part 'constant_emitter.dart';
diff --git a/sdk/lib/_internal/compiler/implementation/lib/collection_patch.dart b/sdk/lib/_internal/compiler/implementation/lib/collection_patch.dart
index a5a7b89..803c97e 100644
--- a/sdk/lib/_internal/compiler/implementation/lib/collection_patch.dart
+++ b/sdk/lib/_internal/compiler/implementation/lib/collection_patch.dart
@@ -30,6 +30,7 @@
patch int get length => _length;
patch bool get isEmpty => _length == 0;
+ patch bool get isNotEmpty => !isEmpty;
patch Iterable<K> get keys {
return new HashMapKeyIterable<K>(this);
@@ -391,6 +392,8 @@
patch int get length => _length;
patch bool get isEmpty => _length == 0;
+ patch bool get isNotEmpty => !isEmpty;
+
patch Iterable<K> get keys {
return new LinkedHashMapKeyIterable<K>(this);
@@ -744,6 +747,7 @@
patch int get length => _length;
patch bool get isEmpty => _length == 0;
+ patch bool get isNotEmpty => !isEmpty;
patch bool contains(Object object) {
if (_isStringElement(object)) {
@@ -1038,6 +1042,7 @@
patch int get length => _length;
patch bool get isEmpty => _length == 0;
+ patch bool get isNotEmpty => !isEmpty;
patch bool contains(Object object) {
if (_isStringElement(object)) {
diff --git a/sdk/lib/_internal/compiler/implementation/lib/constant_map.dart b/sdk/lib/_internal/compiler/implementation/lib/constant_map.dart
index d84b4a5..1647f32 100644
--- a/sdk/lib/_internal/compiler/implementation/lib/constant_map.dart
+++ b/sdk/lib/_internal/compiler/implementation/lib/constant_map.dart
@@ -40,6 +40,8 @@
bool get isEmpty => length == 0;
+ bool get isNotEmpty => !isEmpty;
+
String toString() => Maps.mapToString(this);
_throwUnmodifiable() {
diff --git a/sdk/lib/_internal/compiler/implementation/lib/core_patch.dart b/sdk/lib/_internal/compiler/implementation/lib/core_patch.dart
index 4d6d4c1..dec98f1 100644
--- a/sdk/lib/_internal/compiler/implementation/lib/core_patch.dart
+++ b/sdk/lib/_internal/compiler/implementation/lib/core_patch.dart
@@ -6,7 +6,6 @@
import 'dart:_interceptors';
import 'dart:_js_helper' show checkNull,
getRuntimeType,
- isJsArray,
JSSyntaxRegExp,
Primitives,
stringJoinUnchecked;
@@ -213,7 +212,7 @@
patch class String {
patch factory String.fromCharCodes(Iterable<int> charCodes) {
- if (!isJsArray(charCodes)) {
+ if (charCodes is! JSArray) {
charCodes = new List.from(charCodes);
}
return Primitives.stringFromCharCodes(charCodes);
diff --git a/sdk/lib/_internal/compiler/implementation/lib/foreign_helper.dart b/sdk/lib/_internal/compiler/implementation/lib/foreign_helper.dart
index 0e72750..fb06bf3 100644
--- a/sdk/lib/_internal/compiler/implementation/lib/foreign_helper.dart
+++ b/sdk/lib/_internal/compiler/implementation/lib/foreign_helper.dart
@@ -157,3 +157,9 @@
* Returns the prefix used for generated type argument substitutions on classes.
*/
String JS_OPERATOR_AS_PREFIX() {}
+
+/**
+ * Returns the field name used for determining if an object or its
+ * interceptor has JavaScript indexing behavior.
+ */
+String JS_IS_INDEXABLE_FIELD_NAME() {}
diff --git a/sdk/lib/_internal/compiler/implementation/lib/interceptors.dart b/sdk/lib/_internal/compiler/implementation/lib/interceptors.dart
index 67e6a0c..b144a30 100644
--- a/sdk/lib/_internal/compiler/implementation/lib/interceptors.dart
+++ b/sdk/lib/_internal/compiler/implementation/lib/interceptors.dart
@@ -11,8 +11,6 @@
Null,
JSSyntaxRegExp,
Primitives,
- checkGrowable,
- checkMutable,
checkNull,
checkNum,
checkString,
@@ -51,6 +49,9 @@
// This is a magic method: the compiler does specialization of it
// depending on the uses of intercepted methods and instantiated
// primitive types.
+ // This method is recursive to prevent the type analyzer from thinking that
+ // the method returns `null`.
+ return getInterceptor(object);
}
/**
@@ -79,7 +80,7 @@
defineProperty(object, dispatchPropertyName, value);
}
-makeDispatchRecord(interceptor, proto, extension) {
+makeDispatchRecord(interceptor, proto, extension, indexability) {
// Dispatch records are stored in the prototype chain, and in some cases, on
// instances.
//
@@ -108,21 +109,18 @@
// P I if object's prototype is P, use I
// F - P if object's prototype is P, call F
- // TODO(kasperl): Remove this hack. It is needed to avoid inlining
- // this method because inlining gives us multiple allocation points
- // for records which is bad because it leads to polymorphic access.
+ // BUG(10903): Remove this hack. It is needed to avoid inlining this
+ // method because inlining gives us multiple allocation points for
+ // records which is bad because it leads to polymorphic access.
if (false) return null;
- return JS('', '{i: #, p: #, e: #, x: null}', interceptor, proto, extension);
+ return JS('', '{i: #, p: #, e: #, x: #}',
+ interceptor, proto, extension, indexability);
}
dispatchRecordInterceptor(record) => JS('', '#.i', record);
dispatchRecordProto(record) => JS('', '#.p', record);
dispatchRecordExtension(record) => JS('', '#.e', record);
-
dispatchRecordIndexability(record) => JS('bool|Null', '#.x', record);
-setDispatchRecordIndexability(record, bool value) {
- JS('void', '#.x = #', record, value);
-}
/**
* Returns the interceptor for a native class instance. Used by
@@ -201,7 +199,7 @@
JS('void', '#(#)', setGetDispatchPropertyFn, getter);
setDispatchProperty(
objectProto,
- makeDispatchRecord(jsObjectInterceptor, objectProto, null));
+ makeDispatchRecord(jsObjectInterceptor, objectProto, null, null));
return;
}
}
@@ -233,7 +231,7 @@
}
setDispatchProperty(
objectProto,
- makeDispatchRecord(jsObjectInterceptor, objectProto, null));
+ makeDispatchRecord(jsObjectInterceptor, objectProto, null, null));
return;
}
}
diff --git a/sdk/lib/_internal/compiler/implementation/lib/js_array.dart b/sdk/lib/_internal/compiler/implementation/lib/js_array.dart
index 30e0a39..40ce9fa 100644
--- a/sdk/lib/_internal/compiler/implementation/lib/js_array.dart
+++ b/sdk/lib/_internal/compiler/implementation/lib/js_array.dart
@@ -13,8 +13,20 @@
class JSArray<E> extends Interceptor implements List<E>, JSIndexable {
const JSArray();
+ checkMutable(reason) {
+ if (this is !JSMutableArray) {
+ throw new UnsupportedError(reason);
+ }
+ }
+
+ checkGrowable(reason) {
+ if (this is !JSExtendableArray) {
+ throw new UnsupportedError(reason);
+ }
+ }
+
void add(E value) {
- checkGrowable(this, 'add');
+ checkGrowable('add');
JS('void', r'#.push(#)', this, value);
}
@@ -23,7 +35,7 @@
if (index < 0 || index >= length) {
throw new RangeError.value(index);
}
- checkGrowable(this, 'removeAt');
+ checkGrowable('removeAt');
return JS('var', r'#.splice(#, 1)[0]', this, index);
}
@@ -32,28 +44,28 @@
if (index < 0 || index > length) {
throw new RangeError.value(index);
}
- checkGrowable(this, 'insert');
+ checkGrowable('insert');
JS('void', r'#.splice(#, 0, #)', this, index, value);
}
void insertAll(int index, Iterable<E> iterable) {
- checkGrowable(this, 'insertAll');
+ checkGrowable('insertAll');
IterableMixinWorkaround.insertAllList(this, index, iterable);
}
void setAll(int index, Iterable<E> iterable) {
- checkMutable(this, 'setAll');
+ checkMutable('setAll');
IterableMixinWorkaround.setAllList(this, index, iterable);
}
E removeLast() {
- checkGrowable(this, 'removeLast');
+ checkGrowable('removeLast');
if (length == 0) throw new RangeError.value(-1);
return JS('var', r'#.pop()', this);
}
bool remove(Object element) {
- checkGrowable(this, 'remove');
+ checkGrowable('remove');
for (int i = 0; i < this.length; i++) {
if (this[i] == element) {
JS('var', r'#.splice(#, 1)', this, i);
@@ -188,7 +200,7 @@
}
void removeRange(int start, int end) {
- checkGrowable(this, 'removeRange');
+ checkGrowable('removeRange');
int receiverLength = this.length;
if (start < 0 || start > receiverLength) {
throw new RangeError.range(start, 0, receiverLength);
@@ -205,17 +217,17 @@
}
void setRange(int start, int end, Iterable<E> iterable, [int skipCount = 0]) {
- checkMutable(this, 'set range');
+ checkMutable('set range');
IterableMixinWorkaround.setRangeList(this, start, end, iterable, skipCount);
}
void fillRange(int start, int end, [E fillValue]) {
- checkMutable(this, 'fill range');
+ checkMutable('fill range');
IterableMixinWorkaround.fillRangeList(this, start, end, fillValue);
}
void replaceRange(int start, int end, Iterable<E> iterable) {
- checkGrowable(this, 'removeRange');
+ checkGrowable('removeRange');
IterableMixinWorkaround.replaceRangeList(this, start, end, iterable);
}
@@ -226,7 +238,7 @@
Iterable<E> get reversed => IterableMixinWorkaround.reversedList(this);
void sort([int compare(E a, E b)]) {
- checkMutable(this, 'sort');
+ checkMutable('sort');
IterableMixinWorkaround.sortList(this, compare);
}
@@ -247,6 +259,8 @@
bool get isEmpty => length == 0;
+ bool get isNotEmpty => !isEmpty;
+
String toString() => ToString.iterableToString(this);
List<E> toList({ bool growable: true }) =>
@@ -263,7 +277,7 @@
void set length(int newLength) {
if (newLength is !int) throw new ArgumentError(newLength);
if (newLength < 0) throw new RangeError.value(newLength);
- checkGrowable(this, 'set length');
+ checkGrowable('set length');
JS('void', r'#.length = #', this, newLength);
}
@@ -274,7 +288,7 @@
}
void operator []=(int index, E value) {
- checkMutable(this, 'indexed set');
+ checkMutable('indexed set');
if (index is !int) throw new ArgumentError(index);
if (index >= length || index < 0) throw new RangeError.value(index);
JS('void', r'#[#] = #', this, index, value);
diff --git a/sdk/lib/_internal/compiler/implementation/lib/js_helper.dart b/sdk/lib/_internal/compiler/implementation/lib/js_helper.dart
index 3b5371c..17507a2 100644
--- a/sdk/lib/_internal/compiler/implementation/lib/js_helper.dart
+++ b/sdk/lib/_internal/compiler/implementation/lib/js_helper.dart
@@ -12,16 +12,9 @@
JS_DART_OBJECT_CONSTRUCTOR,
JS_OPERATOR_IS_PREFIX,
JS_OPERATOR_AS_PREFIX,
+ JS_IS_INDEXABLE_FIELD_NAME,
RAW_DART_FUNCTION_REF;
-import 'dart:_interceptors' show getInterceptor,
- interceptedNames,
- makeDispatchRecord,
- getDispatchProperty,
- dispatchRecordIndexability,
- setDispatchRecordIndexability,
- Interceptor,
- JSMutableIndexable,
- JSUnknown;
+import 'dart:_interceptors';
import "dart:_collection-dev" as _symbol_dev;
part 'constant_map.dart';
@@ -39,32 +32,7 @@
var result = dispatchRecordIndexability(record);
if (result != null) return result;
}
- return isJsIndexableSlow(object);
-}
-
-// We keep the slow path of the indexability check in a separate method
-// to get better code generated for the fast path and to increase the
-// chance of having it inlined.
-bool isJsIndexableSlow(var object) {
- bool result = object is JavaScriptIndexingBehavior;
- var record = getDispatchProperty(object);
- if (record == null) return result;
- // This is intentionally written to have two return points, so we
- // will not inline the slow path function into the fast one.
- setDispatchRecordIndexability(record, result);
- return result;
-}
-
-checkMutable(list, reason) {
- if (JS('bool', r'!!(#.immutable$list)', list)) {
- throw new UnsupportedError(reason);
- }
-}
-
-checkGrowable(list, reason) {
- if (JS('bool', r'!!(#.fixed$length)', list)) {
- throw new UnsupportedError(reason);
- }
+ return object is JavaScriptIndexingBehavior;
}
String S(value) {
@@ -329,7 +297,7 @@
/// Returns the type of [object] as a string (including type arguments).
static String objectTypeName(Object object) {
- String name = constructorNameFallback(object);
+ String name = constructorNameFallback(getInterceptor(object));
if (name == 'Object') {
// Try to decompile the constructor by turning it into a string
// and get the name out of that. If the decompiled name is a
@@ -600,6 +568,14 @@
}
static getConstructor(String className) {
+ // TODO(ahe): Generalize this and improve test coverage of
+ // reflecting on intercepted classes.
+ if (JS('bool', '# == "String"', className)) return const JSString();
+ if (JS('bool', '# == "int"', int)) return const JSInt();
+ if (JS('bool', '# == "double"', int)) return const JSDouble();
+ if (JS('bool', '# == "num"', int)) return const JSNumber();
+ if (JS('bool', '# == "bool"', int)) return const JSBool();
+ if (JS('bool', '# == "List"', int)) return const JSArray();
// TODO(ahe): How to safely access $?
return JS('var', r'$[#]', className);
}
diff --git a/sdk/lib/_internal/compiler/implementation/lib/js_number.dart b/sdk/lib/_internal/compiler/implementation/lib/js_number.dart
index b6219e7..445e927 100644
--- a/sdk/lib/_internal/compiler/implementation/lib/js_number.dart
+++ b/sdk/lib/_internal/compiler/implementation/lib/js_number.dart
@@ -264,7 +264,14 @@
}
}
-class JSInt extends JSNumber implements int {
+/**
+ * The interceptor class for [int]s.
+ *
+ * This class implements double since in JavaScript all numbers are doubles, so
+ * while we want to treat `2.0` as an integer for some operations, its
+ * interceptor should answer `true` to `is double`.
+ */
+class JSInt extends JSNumber implements int, double {
const JSInt();
bool get isEven => (this & 1) == 0;
diff --git a/sdk/lib/_internal/compiler/implementation/lib/js_rti.dart b/sdk/lib/_internal/compiler/implementation/lib/js_rti.dart
index 21be9af..721f38f 100644
--- a/sdk/lib/_internal/compiler/implementation/lib/js_rti.dart
+++ b/sdk/lib/_internal/compiler/implementation/lib/js_rti.dart
@@ -5,7 +5,7 @@
part of _js_helper;
setRuntimeTypeInfo(target, typeInfo) {
- assert(typeInfo == null || isJsArray(typeInfo));
+ assert(typeInfo == null || typeInfo is JSArray);
// We have to check for null because factories may return null.
if (target != null) JS('var', r'#.$builtinTypeInfo = #', target, typeInfo);
}
@@ -49,7 +49,7 @@
String runtimeTypeToString(type) {
if (type == null) {
return 'dynamic';
- } else if (isJsArray(type)) {
+ } else if (type is JSArray) {
// A list representing a type with arguments.
return getRuntimeTypeAsString(type);
} else {
@@ -79,7 +79,7 @@
}
String getRuntimeTypeString(var object) {
- String className = isJsArray(object) ? 'List' : getClassName(object);
+ String className = object is JSArray ? 'List' : getClassName(object);
var typeInfo = JS('var', r'#.$builtinTypeInfo', object);
return "$className${joinArguments(typeInfo, 0)}";
}
@@ -98,7 +98,7 @@
Object call(target, name) => JS('var', r'#[#]()', target, name);
substitute(var substitution, var arguments) {
- if (isJsArray(substitution)) {
+ if (substitution is JSArray) {
arguments = substitution;
} else if (isJsFunction(substitution)) {
arguments = invoke(substitution, arguments);
@@ -176,8 +176,8 @@
// [:null:] means a raw type.
if (s == null || t == null) return true;
- assert(isJsArray(s));
- assert(isJsArray(t));
+ assert(s is JSArray);
+ assert(t is JSArray);
assert(s.length == t.length);
int len = s.length;
@@ -190,7 +190,7 @@
}
getArguments(var type) {
- return isJsArray(type) ? JS('var', r'#.slice(1)', type) : null;
+ return type is JSArray ? JS('var', r'#.slice(1)', type) : null;
}
getField(var object, var name) => JS('var', r'#[#]', object, name);
@@ -205,9 +205,7 @@
// Get the runtime type information from the object here, because we may
// overwrite o with the interceptor below.
var rti = getRuntimeTypeInfo(o);
- // Check for native objects and use the interceptor instead of the object.
- // TODO(9586): Move type info for static functions onto an interceptor.
- o = isJsFunction(o) ? o : getInterceptor(o);
+ o = getInterceptor(o);
// We can use the object as its own type representation because we install
// the subtype flags and the substitution on the prototype, so they are
// properties of the object in JS.
@@ -263,8 +261,8 @@
if (JS('bool', '# === #', s, t)) return true;
// Get the object describing the class and check for the subtyping flag
// constructed from the type of [t].
- var typeOfS = isJsArray(s) ? s[0] : s;
- var typeOfT = isJsArray(t) ? t[0] : t;
+ var typeOfS = s is JSArray ? s[0] : s;
+ var typeOfT = t is JSArray ? t[0] : t;
// TODO(johnniwinther): replace this with the real function subtype test.
if (JS('bool', '#.func', s) == true || JS('bool', '#.func', t) == true ) {
return true;
@@ -282,8 +280,8 @@
// arguments and no substitution, it is used as raw type. If [t] has no
// type arguments, it used as a raw type. In both cases, [s] is a subtype
// of [t].
- if ((!isJsArray(s) && JS('bool', '# == null', substitution)) ||
- !isJsArray(t)) {
+ if ((s is! JSArray && JS('bool', '# == null', substitution)) ||
+ t is! JSArray) {
return true;
}
// Recursively check the type arguments.
diff --git a/sdk/lib/_internal/compiler/implementation/lib/js_string.dart b/sdk/lib/_internal/compiler/implementation/lib/js_string.dart
index 04cfa7d..610f7f8 100644
--- a/sdk/lib/_internal/compiler/implementation/lib/js_string.dart
+++ b/sdk/lib/_internal/compiler/implementation/lib/js_string.dart
@@ -227,6 +227,8 @@
bool get isEmpty => length == 0;
+ bool get isNotEmpty => !isEmpty;
+
int compareTo(String other) {
if (other is !String) throw new ArgumentError(other);
return this == other ? 0
diff --git a/sdk/lib/_internal/compiler/implementation/lib/mirrors_patch.dart b/sdk/lib/_internal/compiler/implementation/lib/mirrors_patch.dart
index 88e9bba..ffcef0a 100644
--- a/sdk/lib/_internal/compiler/implementation/lib/mirrors_patch.dart
+++ b/sdk/lib/_internal/compiler/implementation/lib/mirrors_patch.dart
@@ -7,7 +7,7 @@
import 'dart:_foreign_helper' show JS;
import 'dart:_collection-dev' as _symbol_dev;
import 'dart:_js_helper' show createInvocationMirror;
-import 'dart:_interceptors' show getInterceptor;
+import 'dart:_interceptors' show Interceptor;
patch class MirrorSystem {
patch static String getName(Symbol symbol) => _n(symbol);
@@ -38,7 +38,7 @@
List<String> classes = data[2];
List<String> functions = data[3];
var libraries = result.putIfAbsent(name, () => <LibraryMirror>[]);
- libraries.add(new _LibraryMirror(name, uri, classes, functions));
+ libraries.add(new _LibraryMirror(_s(name), uri, classes, functions));
}
return result;
}
@@ -50,18 +50,22 @@
}
class _LibraryMirror extends _ObjectMirror implements LibraryMirror {
- final String _name;
+ final Symbol simpleName;
final Uri uri;
final List<String> _classes;
final List<String> _functions;
- _LibraryMirror(this._name, this.uri, this._classes, this._functions);
+ _LibraryMirror(this.simpleName, this.uri, this._classes, this._functions);
+
+ Symbol get qualifiedName => simpleName;
Map<Symbol, ClassMirror> get classes {
var result = new Map<Symbol, ClassMirror>();
for (int i = 0; i < _classes.length; i += 2) {
Symbol symbol = _s(_classes[i]);
- result[symbol] = _reflectClass(symbol, _classes[i + 1]);
+ _ClassMirror cls = _reflectClass(symbol, _classes[i + 1]);
+ result[symbol] = cls;
+ cls._owner = this;
}
return result;
}
@@ -76,6 +80,53 @@
// TODO(ahe): This is extremely dangerous!!!
return _reflect(JS('', r'$[#]', _n(fieldName)));
}
+
+ Map<Symbol, MethodMirror> get functions {
+ var result = new Map<Symbol, MethodMirror>();
+ for (int i = 0; i < _functions.length; i++) {
+ String name = _functions[i];
+ Symbol symbol = _s(name);
+ int parameterCount = null; // TODO(ahe): Compute this.
+ _MethodMirror mirror =
+ // TODO(ahe): Create accessor for accessing $. It is also
+ // used in js_helper.
+ new _MethodMirror(symbol, JS('', r'$[#]', name), parameterCount);
+ // TODO(ahe): Cache mirrors.
+ result[symbol] = mirror;
+ mirror._owner = this;
+ }
+ return result;
+ }
+
+ Map<Symbol, MethodMirror> get getters {
+ var result = new Map<Symbol, MethodMirror>();
+ // TODO(ahe): Implement this.
+ return result;
+ }
+
+ Map<Symbol, MethodMirror> get setters {
+ var result = new Map<Symbol, MethodMirror>();
+ // TODO(ahe): Implement this.
+ return result;
+ }
+
+ Map<Symbol, VariableMirror> get variables {
+ var result = new Map<Symbol, VariableMirror>();
+ // TODO(ahe): Implement this.
+ return result;
+ }
+
+ Map<Symbol, Mirror> get members {
+ Map<Symbol, Mirror> result = new Map<Symbol, Mirror>.from(classes);
+ addToResult(Symbol key, Mirror value) {
+ result[key] = value;
+ }
+ functions.forEach(addToResult);
+ getters.forEach(addToResult);
+ setters.forEach(addToResult);
+ variables.forEach(addToResult);
+ return result;
+ }
}
String _n(Symbol symbol) => _symbol_dev.Symbol.getName(symbol);
@@ -205,20 +256,54 @@
final Symbol simpleName;
final _jsConstructor;
final String _fields;
+ // Set as side-effect of accessing _LibraryMirror.classes.
+ _LibraryMirror _owner;
_ClassMirror(this.simpleName, this._jsConstructor, this._fields);
- Map<Symbol, Mirror> get members {
- var result = new Map<Symbol, Mirror>();
+ Symbol get qualifiedName => _computeQualifiedName(owner, simpleName);
+
+ Map<Symbol, MethodMirror> get functions {
+ var result = new Map<Symbol, MethodMirror>();
+ // TODO(ahe): Implement this.
+ return result;
+ }
+
+ Map<Symbol, MethodMirror> get getters {
+ var result = new Map<Symbol, MethodMirror>();
+ // TODO(ahe): Implement this.
+ return result;
+ }
+
+ Map<Symbol, MethodMirror> get setters {
+ var result = new Map<Symbol, MethodMirror>();
+ // TODO(ahe): Implement this.
+ return result;
+ }
+
+ Map<Symbol, VariableMirror> get variables {
+ var result = new Map<Symbol, VariableMirror>();
var s = _fields.split(";");
var fields = s[1] == "" ? [] : s[1].split(",");
for (String field in fields) {
_VariableMirror mirror = new _VariableMirror.from(field);
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;
+ }
+ getters.forEach(addToResult);
+ setters.forEach(addToResult);
+ variables.forEach(addToResult);
+ return result;
+ }
+
InstanceMirror setField(Symbol fieldName, Object arg) {
// TODO(ahe): This is extremely dangerous!!!
JS('void', r'$[#] = #', '${_n(simpleName)}_${_n(fieldName)}', arg);
@@ -254,6 +339,26 @@
constructorName, positionalArguments, namedArguments));
}
+ DeclarationMirror get owner {
+ if (_owner == null) {
+ if (_jsConstructor is Interceptor) {
+ _owner = __reflectClass(Object).owner;
+ } else {
+ for (var list in _MirrorSystem.librariesByName.values) {
+ for (_LibraryMirror library in list) {
+ // This will set _owner field on all clasess as a side
+ // effect. This gives us a fast path to reflect on a
+ // class without parsing reflection data.
+ library.classes;
+ }
+ }
+ }
+ if (_owner == null) {
+ throw new StateError('Class "${_n(simpleName)}" has no owner');
+ }
+ }
+ return _owner;
+ }
String toString() => 'ClassMirror(${_n(simpleName)})';
}
@@ -263,6 +368,7 @@
final Symbol simpleName;
final String _jsName;
final bool _readOnly;
+ DeclarationMirror _owner;
_VariableMirror(this.simpleName, this._jsName, this._readOnly);
@@ -287,6 +393,10 @@
TypeMirror get type => _MirrorSystem._dynamicType;
+ DeclarationMirror get owner => _owner;
+
+ Symbol get qualifiedName => _computeQualifiedName(owner, simpleName);
+
static int fieldCode(int code) {
if (code >= 60 && code <= 64) return code - 59;
if (code >= 123 && code <= 126) return code - 117;
@@ -314,7 +424,7 @@
}
var jsFunction = JS('', '#[#]', reflectee, callName);
int parameterCount = int.parse(callName.split(r'$')[1]);
- return new _MethodMirror(jsFunction, parameterCount);
+ return new _MethodMirror(_s(callName), jsFunction, parameterCount);
}
InstanceMirror apply(List positionalArguments,
@@ -331,13 +441,26 @@
}
class _MethodMirror implements MethodMirror {
+ final Symbol simpleName;
final _jsFunction;
final int _parameterCount;
+ DeclarationMirror _owner;
- _MethodMirror(this._jsFunction, this._parameterCount);
+ _MethodMirror(this.simpleName, this._jsFunction, this._parameterCount);
List<ParameterMirror> get parameters {
// TODO(ahe): Fill the list with parameter mirrors.
return new List<ParameterMirror>(_parameterCount);
}
+
+ DeclarationMirror get owner => _owner;
+
+ Symbol get qualifiedName => _computeQualifiedName(owner, simpleName);
+}
+
+Symbol _computeQualifiedName(DeclarationMirror owner, Symbol simpleName) {
+ if (owner == null) return simpleName;
+ String ownerName = _n(owner.qualifiedName);
+ if (ownerName == '') return simpleName;
+ return _s('$ownerName.${_n(simpleName)}');
}
diff --git a/sdk/lib/_internal/compiler/implementation/lib/native_helper.dart b/sdk/lib/_internal/compiler/implementation/lib/native_helper.dart
index b7a1f44..f4c1fe2 100644
--- a/sdk/lib/_internal/compiler/implementation/lib/native_helper.dart
+++ b/sdk/lib/_internal/compiler/implementation/lib/native_helper.dart
@@ -163,6 +163,7 @@
if (!identical(JS('String', 'typeof(navigator)'), 'object')) return typeNameInChrome;
String userAgent = JS('String', "navigator.userAgent");
+ // TODO(antonm): remove a reference to DumpRenderTree.
if (contains(userAgent, 'Chrome') || contains(userAgent, 'DumpRenderTree')) {
return typeNameInChrome;
} else if (contains(userAgent, 'Firefox')) {
@@ -302,9 +303,11 @@
var isLeaf =
(leafTags != null) && JS('bool', '(#[#]) === true', leafTags, tag);
if (isLeaf) {
- return makeDispatchRecord(interceptor, false, null);
+ var fieldName = JS_IS_INDEXABLE_FIELD_NAME();
+ bool indexability = JS('bool', r'!!#[#]', interceptor, fieldName);
+ return makeDispatchRecord(interceptor, false, null, indexability);
} else {
var proto = JS('', 'Object.getPrototypeOf(#)', obj);
- return makeDispatchRecord(interceptor, proto, null);
+ return makeDispatchRecord(interceptor, proto, null, null);
}
}
diff --git a/sdk/lib/_internal/compiler/implementation/library_loader.dart b/sdk/lib/_internal/compiler/implementation/library_loader.dart
index b0784da..872aa58 100644
--- a/sdk/lib/_internal/compiler/implementation/library_loader.dart
+++ b/sdk/lib/_internal/compiler/implementation/library_loader.dart
@@ -337,7 +337,7 @@
*/
LibraryElement loadCoreLibrary(LibraryDependencyHandler handler) {
if (compiler.coreLibrary == null) {
- Uri coreUri = new Uri.fromComponents(scheme: 'dart', path: 'core');
+ Uri coreUri = new Uri(scheme: 'dart', path: 'core');
compiler.coreLibrary
= createLibrary(handler, null, coreUri, null, coreUri);
}
diff --git a/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirror.dart b/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirror.dart
index 9be802d..1493438 100644
--- a/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirror.dart
+++ b/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirror.dart
@@ -6,7 +6,6 @@
import 'dart:async';
import 'dart:collection' show LinkedHashMap;
-import 'dart:uri';
import '../../compiler.dart' as api;
import '../elements/elements.dart';
diff --git a/sdk/lib/_internal/compiler/implementation/mirrors/mirrors.dart b/sdk/lib/_internal/compiler/implementation/mirrors/mirrors.dart
index 4b2ad1b..54e71ad 100644
--- a/sdk/lib/_internal/compiler/implementation/mirrors/mirrors.dart
+++ b/sdk/lib/_internal/compiler/implementation/mirrors/mirrors.dart
@@ -5,7 +5,6 @@
library mirrors;
import 'dart:async';
-import 'dart:uri';
/**
* The main interface for the whole mirror system.
diff --git a/sdk/lib/_internal/compiler/implementation/mirrors/util.dart b/sdk/lib/_internal/compiler/implementation/mirrors/util.dart
index 7760da1..72b05b9 100644
--- a/sdk/lib/_internal/compiler/implementation/mirrors/util.dart
+++ b/sdk/lib/_internal/compiler/implementation/mirrors/util.dart
@@ -58,6 +58,7 @@
}
bool get isEmpty => length == 0;
+ bool get isNotEmpty => !isEmpty;
V putIfAbsent(K key, V ifAbsent()) {
if (!containsKey(key)) {
V value = this[key];
diff --git a/sdk/lib/_internal/compiler/implementation/native_handler.dart b/sdk/lib/_internal/compiler/implementation/native_handler.dart
index 4dc4f9c..6a70a51b 100644
--- a/sdk/lib/_internal/compiler/implementation/native_handler.dart
+++ b/sdk/lib/_internal/compiler/implementation/native_handler.dart
@@ -5,7 +5,6 @@
library native;
import 'dart:collection' show Queue;
-import 'dart:uri';
import 'dart2jslib.dart' hide SourceString;
import 'dart_types.dart';
import 'elements/elements.dart';
@@ -286,7 +285,8 @@
return compiler.withCurrentElement(element, () {
Node node = element.parseNode(compiler);
if (node is! FunctionExpression) return false;
- node = node.body;
+ FunctionExpression functionExpression = node;
+ node = functionExpression.body;
Token token = node.getBeginToken();
if (identical(token.stringValue, 'native')) return true;
return false;
@@ -783,10 +783,11 @@
void _escape(DartType type, Compiler compiler) {
type = type.unalias(compiler);
if (type is FunctionType) {
+ FunctionType functionType = type;
// A function might be called from native code, passing us novel
// parameters.
- _escape(type.returnType, compiler);
- for (Link<DartType> parameters = type.parameterTypes;
+ _escape(functionType.returnType, compiler);
+ for (Link<DartType> parameters = functionType.parameterTypes;
!parameters.isEmpty;
parameters = parameters.tail) {
_capture(parameters.head, compiler);
@@ -800,8 +801,9 @@
void _capture(DartType type, Compiler compiler) {
type = type.unalias(compiler);
if (type is FunctionType) {
- _capture(type.returnType, compiler);
- for (Link<DartType> parameters = type.parameterTypes;
+ FunctionType functionType = type;
+ _capture(functionType.returnType, compiler);
+ for (Link<DartType> parameters = functionType.parameterTypes;
!parameters.isEmpty;
parameters = parameters.tail) {
_escape(parameters.head, compiler);
diff --git a/sdk/lib/_internal/compiler/implementation/patch_parser.dart b/sdk/lib/_internal/compiler/implementation/patch_parser.dart
index 128ba88..02c4ecc 100644
--- a/sdk/lib/_internal/compiler/implementation/patch_parser.dart
+++ b/sdk/lib/_internal/compiler/implementation/patch_parser.dart
@@ -114,7 +114,6 @@
library patchparser;
-import "dart:uri";
import "tree/tree.dart" as tree;
import "dart2jslib.dart" as leg; // CompilerTask, Compiler.
import "apiimpl.dart";
diff --git a/sdk/lib/_internal/compiler/implementation/resolution/members.dart b/sdk/lib/_internal/compiler/implementation/resolution/members.dart
index b4fe9d9..ae787be 100644
--- a/sdk/lib/_internal/compiler/implementation/resolution/members.dart
+++ b/sdk/lib/_internal/compiler/implementation/resolution/members.dart
@@ -20,6 +20,12 @@
void setSelector(Node node, Selector selector);
void setGetterSelectorInComplexSendSet(SendSet node, Selector selector);
void setOperatorSelectorInComplexSendSet(SendSet node, Selector selector);
+ Selector getIteratorSelector(ForIn node);
+ Selector getMoveNextSelector(ForIn node);
+ Selector getCurrentSelector(ForIn node);
+ Selector setIteratorSelector(ForIn node, Selector selector);
+ Selector setMoveNextSelector(ForIn node, Selector selector);
+ Selector setCurrentSelector(ForIn node, Selector selector);
/// Register additional dependencies required by [currentElement].
/// For example, elements that are used by a backend.
@@ -41,8 +47,9 @@
operator []=(Node node, Element element) {
assert(invariant(node, () {
- if (node is FunctionExpression) {
- return !node.modifiers.isExternal();
+ FunctionExpression functionExpression = node.asFunctionExpression();
+ if (functionExpression != null) {
+ return !functionExpression.modifiers.isExternal();
}
return true;
}));
@@ -99,6 +106,34 @@
return selectors[node.assignmentOperator];
}
+ // The following methods set selectors on the "for in" node. Since
+ // we're using three selectors, we need to use children of the node,
+ // and we arbitrarily choose which ones.
+
+ Selector setIteratorSelector(ForIn node, Selector selector) {
+ selectors[node] = selector;
+ }
+
+ Selector getIteratorSelector(ForIn node) {
+ return selectors[node];
+ }
+
+ Selector setMoveNextSelector(ForIn node, Selector selector) {
+ selectors[node.forToken] = selector;
+ }
+
+ Selector getMoveNextSelector(ForIn node) {
+ return selectors[node.forToken];
+ }
+
+ Selector setCurrentSelector(ForIn node, Selector selector) {
+ selectors[node.inToken] = selector;
+ }
+
+ Selector getCurrentSelector(ForIn node) {
+ return selectors[node.inToken];
+ }
+
bool isParameterChecked(Element element) {
return checkedParameters.contains(element);
}
@@ -1953,8 +1988,8 @@
visitIf(If node) {
visit(node.condition);
- visit(node.thenPart);
- visit(node.elsePart);
+ visitIn(node.thenPart, new BlockScope(scope));
+ visitIn(node.elsePart, new BlockScope(scope));
}
static bool isLogicalOperator(Identifier op) {
@@ -2016,7 +2051,7 @@
}
// TODO(johnniwinther): Ensure correct behavior if currentClass is a
// patch.
- target = currentClass.lookupSuperSelector(selector);
+ target = currentClass.lookupSuperSelector(selector, compiler);
// [target] may be null which means invoking noSuchMethod on
// super.
if (target == null) {
@@ -2349,7 +2384,7 @@
registerSend(getterSelector, getter);
mapping.setGetterSelectorInComplexSendSet(node, getterSelector);
if (node.isSuperCall) {
- getter = currentClass.lookupSuperSelector(getterSelector);
+ getter = currentClass.lookupSuperSelector(getterSelector, compiler);
if (getter == null) {
target = warnAndCreateErroneousElement(
node, selector.name, MessageKind.NO_SUCH_SUPER_MEMBER,
@@ -2554,13 +2589,6 @@
if (cls.isAbstract(compiler)) {
compiler.backend.registerAbstractClassInstantiation(mapping);
}
- // [cls] might be the declaration element and we want to include injected
- // members.
- cls.implementation.forEachInstanceField(
- (ClassElement enclosingClass, Element member) {
- world.addToWorkList(member);
- },
- includeSuperAndInjectedMembers: true);
if (isSymbolConstructor) {
if (node.isConst()) {
@@ -2754,10 +2782,13 @@
visitForIn(ForIn node) {
LibraryElement library = enclosingElement.getLibrary();
+ mapping.setIteratorSelector(node, compiler.iteratorSelector);
world.registerDynamicGetter(compiler.iteratorSelector.name,
compiler.iteratorSelector);
+ mapping.setCurrentSelector(node, compiler.currentSelector);
world.registerDynamicGetter(compiler.currentSelector.name,
compiler.currentSelector);
+ mapping.setMoveNextSelector(node, compiler.moveNextSelector);
world.registerDynamicInvocation(compiler.moveNextSelector.name,
compiler.moveNextSelector);
@@ -2974,17 +3005,25 @@
compiler.backend.registerCatchStatement(world, mapping);
// Check that if catch part is present, then
// it has one or two formal parameters.
+ VariableDefinitions exceptionDefinition;
+ VariableDefinitions stackTraceDefinition;
if (node.formals != null) {
- if (node.formals.isEmpty) {
+ Link<Node> formalsToProcess = node.formals.nodes;
+ if (formalsToProcess.isEmpty) {
error(node, MessageKind.EMPTY_CATCH_DECLARATION);
- }
- if (!node.formals.nodes.tail.isEmpty) {
- if (!node.formals.nodes.tail.tail.isEmpty) {
- for (Node extra in node.formals.nodes.tail.tail) {
- error(extra, MessageKind.EXTRA_CATCH_DECLARATION);
+ } else {
+ exceptionDefinition = formalsToProcess.head.asVariableDefinitions();
+ formalsToProcess = formalsToProcess.tail;
+ if (!formalsToProcess.isEmpty) {
+ stackTraceDefinition = formalsToProcess.head.asVariableDefinitions();
+ formalsToProcess = formalsToProcess.tail;
+ if (!formalsToProcess.isEmpty) {
+ for (Node extra in formalsToProcess) {
+ error(extra, MessageKind.EXTRA_CATCH_DECLARATION);
+ }
}
+ compiler.backend.registerStackTraceInCatch(mapping);
}
- compiler.backend.registerStackTraceInCatch(mapping);
}
// Check that the formals aren't optional and that they have no
@@ -3020,6 +3059,19 @@
inCatchBlock = true;
visitIn(node.block, blockScope);
inCatchBlock = oldInCatchBlock;
+
+ if (node.type != null && exceptionDefinition != null) {
+ DartType exceptionType = mapping.getType(node.type);
+ Node exceptionVariable = exceptionDefinition.definitions.nodes.head;
+ VariableElementX exceptionElement = mapping[exceptionVariable];
+ exceptionElement.variables.type = exceptionType;
+ }
+ if (stackTraceDefinition != null) {
+ Node stackTraceVariable = stackTraceDefinition.definitions.nodes.head;
+ VariableElementX stackTraceElement = mapping[stackTraceVariable];
+ world.registerInstantiatedClass(compiler.stackTraceClass, mapping);
+ stackTraceElement.variables.type = compiler.stackTraceClass.rawType;
+ }
}
visitTypedef(Typedef node) {
diff --git a/sdk/lib/_internal/compiler/implementation/resolution/secret_tree_element.dart b/sdk/lib/_internal/compiler/implementation/resolution/secret_tree_element.dart
index c9a67a6..665938e 100644
--- a/sdk/lib/_internal/compiler/implementation/resolution/secret_tree_element.dart
+++ b/sdk/lib/_internal/compiler/implementation/resolution/secret_tree_element.dart
@@ -10,7 +10,7 @@
* testing.
*
* We have taken great care to ensure AST nodes can be cached between
- * compiler instances. Part of this is requires that we always access
+ * compiler instances. Part of this requires that we always access
* resolution results through TreeElements.
*
* So please, do not add additional elements to this library, and do
diff --git a/sdk/lib/_internal/compiler/implementation/scanner/scannerlib.dart b/sdk/lib/_internal/compiler/implementation/scanner/scannerlib.dart
index 8bdf120..f9a175f 100644
--- a/sdk/lib/_internal/compiler/implementation/scanner/scannerlib.dart
+++ b/sdk/lib/_internal/compiler/implementation/scanner/scannerlib.dart
@@ -5,7 +5,6 @@
library scanner;
import 'dart:collection' show LinkedHashMap, IterableBase;
-import 'dart:uri';
import 'scanner_implementation.dart';
import '../elements/elements.dart';
diff --git a/sdk/lib/_internal/compiler/implementation/source_file_provider.dart b/sdk/lib/_internal/compiler/implementation/source_file_provider.dart
index 874300b..e10a4bd 100644
--- a/sdk/lib/_internal/compiler/implementation/source_file_provider.dart
+++ b/sdk/lib/_internal/compiler/implementation/source_file_provider.dart
@@ -5,7 +5,6 @@
library source_file_provider;
import 'dart:async';
-import 'dart:uri';
import 'dart:io';
import 'dart:utf';
diff --git a/sdk/lib/_internal/compiler/implementation/source_map_builder.dart b/sdk/lib/_internal/compiler/implementation/source_map_builder.dart
index 2f732d3..dd07af6 100644
--- a/sdk/lib/_internal/compiler/implementation/source_map_builder.dart
+++ b/sdk/lib/_internal/compiler/implementation/source_map_builder.dart
@@ -4,7 +4,6 @@
library source_map_builder;
-import 'dart:uri';
import 'util/util.dart';
import 'scanner/scannerlib.dart' show Token;
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/bailout.dart b/sdk/lib/_internal/compiler/implementation/ssa/bailout.dart
index 0ef2257..c22a52c 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/bailout.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/bailout.dart
@@ -37,7 +37,8 @@
// for parameters that are not 'this', which is always passed as
// the receiver.
if (instruction is HCheck) {
- add(instruction.checkedInput);
+ HCheck check = instruction;
+ add(check.checkedInput);
} else if (!instruction.isCodeMotionInvariant()
|| (instruction is HParameterValue && instruction is !HThis)) {
lives.add(instruction);
@@ -294,7 +295,10 @@
receiverSelectorOnThrow = selector;
willThrow = true;
}
- } else if (willThrowArgumentError(selector, receiver, speculativeType)) {
+ // We need to call the actual method in checked mode to get
+ // the right type error.
+ } else if (!compiler.enableTypeAssertions
+ && willThrowArgumentError(selector, receiver, speculativeType)) {
willThrow = true;
}
@@ -730,7 +734,10 @@
}
if (blocks.isEmpty) {
- if (firstBailoutTarget == null) {
+ // If [currentBlockInformation] is not null, we are in the
+ // middle of a loop/labeled block and this is too complex to handle for
+ // now.
+ if (firstBailoutTarget == null && currentBlockInformation == null) {
firstBailoutTarget = target;
} else {
hasComplexBailoutTargets = true;
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/builder.dart b/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
index cb5b362..6f4cd16 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
@@ -44,6 +44,7 @@
kind == ElementKind.SETTER) {
graph = builder.buildMethod(element);
} else if (kind == ElementKind.FIELD) {
+ assert(!element.isInstanceMember());
graph = builder.buildLazyInitializer(element);
} else {
compiler.internalErrorOnElement(element,
@@ -1105,8 +1106,11 @@
bodyElement.origin.patch = bodyElement;
classElement.origin.addBackendMember(bodyElement.origin);
}
- compiler.enqueuer.codegen.addToWorkList(bodyElement.declaration,
- treeElements);
+ // Set the [TreeElements] of the generative constructor body to
+ // be the same as the generative constructor.
+ compiler.enqueuer.resolution.ensureCachedElements(
+ bodyElement.declaration,
+ treeElements);
}
assert(bodyElement.isGenerativeConstructorBody());
return bodyElement;
@@ -1131,7 +1135,6 @@
*/
InliningState enterInlinedMethod(FunctionElement function,
Selector selector,
- Link<Node> argumentsNodes,
List<HInstruction> providedArguments,
Node currentNode) {
assert(invariant(function, function.isImplementation));
@@ -1139,7 +1142,16 @@
List<HInstruction> compiledArguments;
bool isInstanceMember = function.isInstanceMember();
- if (isInstanceMember && !function.isGenerativeConstructorBody()) {
+ if (currentNode == null
+ || currentNode.asForIn() != null
+ || !isInstanceMember
+ || function.isGenerativeConstructorBody()) {
+ // For these cases, the provided arguments must match the
+ // expected parameters.
+ assert(providedArguments != null);
+ compiledArguments = providedArguments;
+ } else {
+ Send send = currentNode.asSend();
assert(providedArguments != null);
compiledArguments = new List<HInstruction>();
compiledArguments.add(providedArguments[0]);
@@ -1148,7 +1160,7 @@
// call [Selector.addArgumentsToList] only for getting the
// default values of the optional parameters.
bool succeeded = selector.addArgumentsToList(
- argumentsNodes,
+ send.isPropertyAccess ? null : send.arguments,
compiledArguments,
function,
(node) => null,
@@ -1167,9 +1179,6 @@
// The caller of [enterInlinedMethod] has ensured the selector
// matches the element.
assert(succeeded);
- } else {
- assert(providedArguments != null);
- compiledArguments = providedArguments;
}
// Create the inlining state after evaluating the arguments, that
@@ -1236,7 +1245,6 @@
*/
bool tryInlineMethod(Element element,
Selector selector,
- Link<Node> argumentsNodes,
List<HInstruction> providedArguments,
Node currentNode) {
// We cannot inline a method from a deferred library into a method
@@ -1244,26 +1252,11 @@
// TODO(ahe): But we should still inline into the same
// connected-component of the deferred library.
if (compiler.deferredLoadTask.isDeferred(element)) return false;
-
if (compiler.disableInlining) return false;
+ if (inliningStack.length > MAX_INLINING_DEPTH) return false;
+
// Ensure that [element] is an implementation element.
element = element.implementation;
- // TODO(floitsch): find a cleaner way to know if the element is a function
- // containing nodes.
- // [PartialFunctionElement]s are [FunctionElement]s that have [Node]s.
- if (element is !PartialFunctionElement
- && !element.isGenerativeConstructorBody()) {
- return false;
- }
- if (inliningStack.length > MAX_INLINING_DEPTH) return false;
- // Don't inline recursive calls. We use the same elements for the inlined
- // functions and would thus clobber our local variables.
- // Use [:element.declaration:] since [work.element] is always a declaration.
- if (currentElement == element.declaration) return false;
- for (int i = 0; i < inliningStack.length; i++) {
- if (inliningStack[i].function == element) return false;
- }
-
FunctionElement function = element;
bool canBeInlined = backend.canBeInlined[function];
if (canBeInlined == false) return false;
@@ -1304,7 +1297,7 @@
new HFieldGet(element, providedArguments[0]), currentNode);
}
InliningState state = enterInlinedMethod(
- function, selector, argumentsNodes, providedArguments, currentNode);
+ function, selector, providedArguments, currentNode);
inlinedFrom(element, () {
FunctionElement function = element;
@@ -1673,11 +1666,11 @@
bodyCallInputs.add(localsHandler.readLocal(scopeData.boxElement));
}
- if (tryInlineMethod(body, null, null, bodyCallInputs, function)) {
+ if (tryInlineMethod(body, null, bodyCallInputs, function)) {
pop();
} else {
HInvokeConstructorBody invoke =
- new HInvokeConstructorBody(body, bodyCallInputs);
+ new HInvokeConstructorBody(body.declaration, bodyCallInputs);
invoke.sideEffects =
compiler.world.getSideEffectsOfElement(constructor);
add(invoke);
@@ -2711,9 +2704,8 @@
}
}
- HInstruction invokeInterceptor(Set<ClassElement> intercepted,
- HInstruction receiver) {
- HInterceptor interceptor = new HInterceptor(intercepted, receiver);
+ HInstruction invokeInterceptor(HInstruction receiver) {
+ HInterceptor interceptor = new HInterceptor(receiver);
add(interceptor);
return interceptor;
}
@@ -3126,6 +3118,10 @@
stack.add(addConstantString(node, backend.namer.operatorAsPrefix()));
} else if (name == const SourceString('JS_DART_OBJECT_CONSTRUCTOR')) {
handleForeignDartObjectJsConstructorFunction(node);
+ } else if (name == const SourceString('JS_IS_INDEXABLE_FIELD_NAME')) {
+ Element element = compiler.findHelper(
+ const SourceString('JavaScriptIndexingBehavior'));
+ stack.add(addConstantString(node, backend.namer.operatorIs(element)));
} else {
throw "Unknown foreign: ${selector}";
}
@@ -3686,7 +3682,7 @@
}
}
- bool isOptimizableOperation(Send node, Selector selector, Element element) {
+ bool isOptimizableOperation(Selector selector, Element element) {
ClassElement cls = element.getEnclosingClass();
if (isOptimizableOperationOnIndexable(selector, element)) return true;
if (!backend.interceptedClasses.contains(cls)) return false;
@@ -3704,26 +3700,20 @@
Element element = compiler.world.locateSingleElement(selector);
if (element != null
- // TODO(ngeoffray): Handle non-send nodes.
- && (node.asSend() != null)
+ && !element.isField()
&& !(element.isGetter() && selector.isCall())
&& !(element.isFunction() && selector.isGetter())
- && !isOptimizableOperation(node, selector, element)) {
- Send send = node.asSend();
- Link<Node> nodes = send.isPropertyAccess ? null : send.arguments;
- if (tryInlineMethod(element, selector, nodes, arguments, node)) {
+ && !isOptimizableOperation(selector, element)) {
+ if (tryInlineMethod(element, selector, arguments, node)) {
return;
}
}
HInstruction receiver = arguments[0];
- Set<ClassElement> interceptedClasses =
- backend.getInterceptedClassesOn(selector.name);
List<HInstruction> inputs = <HInstruction>[];
- bool isIntercepted = interceptedClasses != null;
+ bool isIntercepted = backend.isInterceptedSelector(selector);
if (isIntercepted) {
- assert(!interceptedClasses.isEmpty);
- inputs.add(invokeInterceptor(interceptedClasses, receiver));
+ inputs.add(invokeInterceptor(receiver));
}
inputs.addAll(arguments);
if (selector.isGetter()) {
@@ -3747,7 +3737,7 @@
Element element,
List<HInstruction> arguments,
[HType type = null]) {
- if (tryInlineMethod(element, null, null, arguments, location)) {
+ if (tryInlineMethod(element, null, arguments, location)) {
return;
}
@@ -3781,10 +3771,8 @@
// TODO(5346): Try to avoid the need for calling [declaration] before
// creating an [HStatic].
List<HInstruction> inputs = <HInstruction>[];
- Set<ClassElement> interceptedClasses =
- backend.getInterceptedClassesOn(selector.name);
- if (interceptedClasses != null) {
- inputs.add(invokeInterceptor(interceptedClasses, receiver));
+ if (backend.isInterceptedSelector(selector)) {
+ inputs.add(invokeInterceptor(receiver));
}
inputs.add(receiver);
inputs.addAll(arguments);
@@ -4040,9 +4028,11 @@
native.handleSsaNative(this, node.expression);
return;
}
- assert(invariant(node, !node.isRedirectingFactoryBody));
HInstruction value;
- if (node.expression == null) {
+ if (node.isRedirectingFactoryBody) {
+ // TODO(ahe): This is only for reflection, and it is not correct yet.
+ value = graph.addConstantNull(constantSystem);
+ } else if (node.expression == null) {
value = graph.addConstantNull(constantSystem);
} else {
visit(node.expression);
@@ -4199,19 +4189,19 @@
// The iterator is shared between initializer, condition and body.
HInstruction iterator;
void buildInitializer() {
- Selector selector = compiler.iteratorSelector;
+ Selector selector = elements.getIteratorSelector(node);
visit(node.expression);
HInstruction receiver = pop();
pushInvokeDynamic(node, selector, [receiver]);
iterator = pop();
}
HInstruction buildCondition() {
- Selector selector = compiler.moveNextSelector;
+ Selector selector = elements.getMoveNextSelector(node);
pushInvokeDynamic(node, selector, [iterator]);
return popBoolified();
}
void buildBody() {
- Selector call = compiler.currentSelector;
+ Selector call = elements.getCurrentSelector(node);
pushInvokeDynamic(node, call, [iterator]);
Node identifier = node.declaredIdentifier;
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/codegen.dart b/sdk/lib/_internal/compiler/implementation/ssa/codegen.dart
index 76b6bff..120f91c 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/codegen.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/codegen.dart
@@ -604,7 +604,8 @@
// argument.
bool needsAssignment = true;
if (instruction is HTypeConversion) {
- String inputName = variableNames.getName(instruction.checkedInput);
+ HTypeConversion typeConversion = instruction;
+ String inputName = variableNames.getName(typeConversion.checkedInput);
if (variableNames.getName(instruction) == inputName) {
needsAssignment = false;
}
@@ -805,7 +806,8 @@
// go away.
List<js.Expression> expressions;
if (jsInitialization is js.Sequence) {
- expressions = jsInitialization.expressions;
+ js.Sequence sequence = jsInitialization;
+ expressions = sequence.expressions;
} else {
expressions = <js.Expression>[jsInitialization];
}
@@ -1523,6 +1525,7 @@
String methodName = backend.namer.getName(node.element);
List<js.Expression> arguments = visitArguments(node.inputs);
push(jsPropertyCall(object, methodName, arguments), node);
+ world.registerStaticUse(node.element);
}
void visitOneShotInterceptor(HOneShotInterceptor node) {
@@ -1760,13 +1763,7 @@
visitForeignNew(HForeignNew node) {
String jsClassReference = backend.namer.isolateAccess(node.element);
- List<HInstruction> inputs = node.inputs;
- // We can't use 'visitArguments', since our arguments start at input[0].
- List<js.Expression> arguments = <js.Expression>[];
- for (int i = 0; i < inputs.length; i++) {
- use(inputs[i]);
- arguments.add(pop());
- }
+ List<js.Expression> arguments = visitArguments(node.inputs, start: 0);
// TODO(floitsch): jsClassReference is an Access. We shouldn't treat it
// as if it was a string.
push(new js.New(new js.VariableUse(jsClassReference), arguments), node);
@@ -1848,7 +1845,8 @@
if (input is HIs) {
emitIs(input, '!==');
} else if (input is HIdentity && generateAtUseSite) {
- emitIdentityComparison(input.left, input.right, true);
+ HIdentity identity = input;
+ emitIdentityComparison(identity.left, identity.right, true);
} else if (input is HBoolify && generateAtUseSite) {
use(input.inputs[0]);
push(new js.Binary("!==", pop(), newLiteralBool(true)), input);
@@ -1993,7 +1991,8 @@
world.registerStaticUse(helper);
js.VariableUse jsHelper =
new js.VariableUse(backend.namer.isolateAccess(helper));
- js.Call value = new js.Call(jsHelper, visitArguments([null, argument]));
+ use(argument);
+ js.Call value = new js.Call(jsHelper, [pop()]);
attachLocation(value, argument);
// BUG(4906): Using throw here adds to the size of the generated code
// but it has the advantage of explicitly telling the JS engine that
@@ -2044,10 +2043,14 @@
void visitStaticStore(HStaticStore node) {
world.registerStaticUse(node.element);
- js.VariableUse variableUse =
- new js.VariableUse(backend.namer.isolateAccess(node.element));
+ js.VariableUse isolate = new js.VariableUse(backend.namer.CURRENT_ISOLATE);
+ // Create a property access to make sure expressions and variable
+ // declarations recognizers don't see this assignment as a local
+ // assignment.
+ js.Node variable = new js.PropertyAccess.field(
+ isolate, backend.namer.getName(node.element));
use(node.inputs[0]);
- push(new js.Assignment(variableUse, pop()), node);
+ push(new js.Assignment(variable, pop()), node);
}
void visitStringConcat(HStringConcat node) {
@@ -2182,12 +2185,22 @@
push(new js.Prefix('!', new js.Prefix('!', field)));
}
+ void checkFieldDoesNotExist(HInstruction input, String fieldName) {
+ use(input);
+ js.PropertyAccess field = new js.PropertyAccess.field(pop(), fieldName);
+ push(new js.Prefix('!', field));
+ }
+
void checkImmutableArray(HInstruction input) {
checkFieldExists(input, 'immutable\$list');
}
+ void checkMutableArray(HInstruction input) {
+ checkFieldDoesNotExist(input, 'immutable\$list');
+ }
+
void checkExtendableArray(HInstruction input) {
- checkFieldExists(input, 'fixed\$length');
+ checkFieldDoesNotExist(input, 'fixed\$length');
}
void checkFixedArray(HInstruction input) {
@@ -2233,8 +2246,33 @@
void checkType(HInstruction input, DartType type, {bool negative: false}) {
assert(invariant(input, !type.isMalformed,
message: 'Attempt to check malformed type $type'));
- world.registerIsCheck(type, work.resolutionTree);
Element element = type.element;
+
+ if (element == backend.jsArrayClass) {
+ checkArray(input, negative ? '!==': '===');
+ return;
+ } else if (element == backend.jsMutableArrayClass) {
+ if (negative) {
+ checkImmutableArray(input);
+ } else {
+ checkMutableArray(input);
+ }
+ return;
+ } else if (element == backend.jsExtendableArrayClass) {
+ if (negative) {
+ checkFixedArray(input);
+ } else {
+ checkExtendableArray(input);
+ }
+ return;
+ } else if (element == backend.jsFixedArrayClass) {
+ if (negative) {
+ checkExtendableArray(input);
+ } else {
+ checkFixedArray(input);
+ }
+ return;
+ }
use(input);
// Hack in interceptor. Ideally the interceptor would occur at the
@@ -2247,24 +2285,7 @@
List<js.Expression> arguments = <js.Expression>[pop()];
push(jsPropertyCall(isolate, interceptorName, arguments));
backend.registerUseInterceptor(world);
-
- // TODO(9586): If a static function can have the type, the type info is
- // sitting on the function. So generate:
- //
- // (typeof x == "function" ? x : getInterceptor(x)).$isFoo
- //
- if (type.unalias(compiler) is FunctionType) {
- js.Expression whenNotFunction = pop();
- use(input);
- js.Expression whenFunction = pop();
- use(input);
- push(new js.Conditional(
- new js.Binary('==',
- new js.Prefix("typeof", pop()),
- js.string('function')),
- whenFunction,
- whenNotFunction));
- }
+ world.registerIsCheck(type, work.resolutionTree);
js.PropertyAccess field =
new js.PropertyAccess.field(pop(), backend.namer.operatorIs(element));
@@ -2399,7 +2420,9 @@
checkType(input, type, negative: negative);
push(new js.Binary(negative ? '||' : '&&', nullTest, pop()));
attachLocationToLast(node);
- } else if (input.canBePrimitive(compiler) || input.canBeNull()) {
+ } else if ((input.canBePrimitive(compiler)
+ && !input.canBePrimitiveArray(compiler))
+ || input.canBeNull()) {
checkObject(input, relation);
js.Expression objectTest = pop();
checkType(input, type, negative: negative);
@@ -2519,12 +2542,12 @@
assert(node.isCheckedModeCheck || node.isCastTypeCheck);
DartType type = node.typeExpression;
- if (type.kind == TypeKind.FUNCTION) {
- // TODO(5022): We currently generate $isFunction checks for
- // function types.
- world.registerIsCheck(
- compiler.functionClass.computeType(compiler), work.resolutionTree);
- }
+ if (type.kind == TypeKind.FUNCTION) {
+ // TODO(5022): We currently generate $isFunction checks for
+ // function types.
+ world.registerIsCheck(
+ compiler.functionClass.computeType(compiler), work.resolutionTree);
+ }
world.registerIsCheck(type, work.resolutionTree);
FunctionElement helperElement;
@@ -2724,7 +2747,7 @@
// find the name of its checked input. Note that there must be a
// name, otherwise the instruction would not be in the live
// environment.
- HInstruction unwrap(HInstruction argument) {
+ HInstruction unwrap(var argument) {
while (argument is HCheck && !variableNames.hasName(argument)) {
argument = argument.checkedInput;
}
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/interceptor_simplifier.dart b/sdk/lib/_internal/compiler/implementation/ssa/interceptor_simplifier.dart
new file mode 100644
index 0000000..e3f7a46
--- /dev/null
+++ b/sdk/lib/_internal/compiler/implementation/ssa/interceptor_simplifier.dart
@@ -0,0 +1,282 @@
+// 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 ssa;
+
+/**
+ * This phase simplifies interceptors in multiple ways:
+ *
+ * 1) If the interceptor is for an object whose type is known, it
+ * tries to use a constant interceptor instead.
+ *
+ * 2) It specializes interceptors based on the selectors it is being
+ * called with.
+ *
+ * 3) If we know the object is not intercepted, we just use it
+ * instead.
+ *
+ * 4) It replaces all interceptors that are used only once with
+ * one-shot interceptors. It saves code size and makes the receiver of
+ * an intercepted call a candidate for being generated at use site.
+ *
+ */
+class SsaSimplifyInterceptors extends HBaseVisitor
+ implements OptimizationPhase {
+ final String name = "SsaSimplifyInterceptors";
+ final ConstantSystem constantSystem;
+ final Compiler compiler;
+ final CodegenWorkItem work;
+ HGraph graph;
+
+ SsaSimplifyInterceptors(this.compiler, this.constantSystem, this.work);
+
+ void visitGraph(HGraph graph) {
+ this.graph = graph;
+ visitDominatorTree(graph);
+ }
+
+ void visitBasicBlock(HBasicBlock node) {
+ currentBlock = node;
+
+ HInstruction instruction = node.first;
+ while (instruction != null) {
+ bool shouldRemove = instruction.accept(this);
+ HInstruction next = instruction.next;
+ if (shouldRemove) {
+ instruction.block.remove(instruction);
+ }
+ instruction = next;
+ }
+ }
+
+ bool visitInstruction(HInstruction instruction) => false;
+
+ bool canUseSelfForInterceptor(HType receiverType,
+ Set<ClassElement> interceptedClasses) {
+ JavaScriptBackend backend = compiler.backend;
+ if (receiverType.canBePrimitive(compiler)) {
+ // Primitives always need interceptors.
+ return false;
+ }
+ if (receiverType.canBeNull()
+ && interceptedClasses.contains(backend.jsNullClass)) {
+ // Need the JSNull interceptor.
+ return false;
+ }
+
+ // [interceptedClasses] is sparse - it is just the classes that define some
+ // intercepted method. Their subclasses (that inherit the method) are
+ // implicit, so we have to extend them.
+
+ TypeMask receiverMask = receiverType.computeMask(compiler);
+ return interceptedClasses
+ .where((cls) => cls != compiler.objectClass)
+ .map((cls) => backend.classesMixedIntoNativeClasses.contains(cls)
+ ? new TypeMask.subtype(cls.rawType)
+ : new TypeMask.subclass(cls.rawType))
+ .every((mask) => receiverMask.intersection(mask, compiler).isEmpty);
+ }
+
+ HInstruction tryComputeConstantInterceptor(
+ HInstruction input,
+ Set<ClassElement> interceptedClasses) {
+ if (input == graph.explicitReceiverParameter) {
+ // If `explicitReceiverParameter` is set it means the current method is an
+ // interceptor method, and `this` is the interceptor. The caller just did
+ // `getInterceptor(foo).currentMethod(foo)` to enter the current method.
+ return graph.thisInstruction;
+ }
+
+ HType type = input.instructionType;
+ ClassElement constantInterceptor;
+ JavaScriptBackend backend = compiler.backend;
+ if (type.isInteger()) {
+ constantInterceptor = backend.jsIntClass;
+ } else if (type.isDouble()) {
+ constantInterceptor = backend.jsDoubleClass;
+ } else if (type.isBoolean()) {
+ constantInterceptor = backend.jsBoolClass;
+ } else if (type.isString()) {
+ constantInterceptor = backend.jsStringClass;
+ } else if (type.isArray()) {
+ constantInterceptor = backend.jsArrayClass;
+ } else if (type.isNull()) {
+ constantInterceptor = backend.jsNullClass;
+ } else if (type.isNumber()
+ && !interceptedClasses.contains(backend.jsIntClass)
+ && !interceptedClasses.contains(backend.jsDoubleClass)) {
+ // If the method being intercepted is not defined in [int] or [double] we
+ // can safely use the number interceptor. This is because none of the
+ // [int] or [double] methods are called from a method defined on [num].
+ constantInterceptor = backend.jsNumberClass;
+ } else {
+ // Try to find constant interceptor for a native class. If the receiver
+ // is constrained to a leaf native class, we can use the class's
+ // interceptor directly.
+
+ // TODO(sra): Key DOM classes like Node, Element and Event are not leaf
+ // classes. When the receiver type is not a leaf class, we might still be
+ // able to use the receiver class as a constant interceptor. It is
+ // usually the case that methods defined on a non-leaf class don't test
+ // 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;
+ }
+ }
+ }
+
+ if (constantInterceptor == null) return null;
+ if (constantInterceptor == work.element.getEnclosingClass()) {
+ return graph.thisInstruction;
+ }
+
+ Constant constant = new InterceptorConstant(
+ constantInterceptor.computeType(compiler));
+ return graph.addConstant(constant);
+ }
+
+ HInstruction findDominator(Iterable<HInstruction> instructions) {
+ HInstruction result;
+ L1: for (HInstruction candidate in instructions) {
+ for (HInstruction current in instructions) {
+ if (current != candidate && !candidate.dominates(current)) continue L1;
+ }
+ result = candidate;
+ break;
+ }
+ return result;
+ }
+
+ bool visitInterceptor(HInterceptor node) {
+ if (node.isConstant()) return false;
+
+ // If the interceptor is used by multiple instructions, specialize
+ // it with a set of classes it intercepts.
+ Set<ClassElement> interceptedClasses;
+ JavaScriptBackend backend = compiler.backend;
+ HInstruction dominator =
+ findDominator(node.usedBy.where((i) => i is HInvokeDynamic));
+ // If there is an instruction that dominates all others, we can
+ // use only the selector of that instruction.
+ if (dominator != null) {
+ interceptedClasses =
+ backend.getInterceptedClassesOn(dominator.selector.name);
+
+ // If we found that we need number, we must still go through all
+ // uses to check if they require int, or double.
+ if (interceptedClasses.contains(backend.jsNumberClass)
+ && !(interceptedClasses.contains(backend.jsDoubleClass)
+ || interceptedClasses.contains(backend.jsIntClass))) {
+ for (var user in node.usedBy) {
+ if (user is! HInvoke) continue;
+ Set<ClassElement> intercepted =
+ backend.getInterceptedClassesOn(user.selector.name);
+ if (intercepted.contains(backend.jsIntClass)) {
+ interceptedClasses.add(backend.jsIntClass);
+ }
+ if (intercepted.contains(backend.jsDoubleClass)) {
+ interceptedClasses.add(backend.jsDoubleClass);
+ }
+ }
+ }
+ } else {
+ interceptedClasses = new Set<ClassElement>();
+ for (var user in node.usedBy) {
+ if (user is! HInvoke) continue;
+ // We don't handle escaping interceptors yet.
+ interceptedClasses.addAll(
+ backend.getInterceptedClassesOn(user.selector.name));
+ }
+ }
+
+ HInstruction receiver = node.receiver;
+ HType instructionType = receiver.instructionType;
+ if (canUseSelfForInterceptor(instructionType, interceptedClasses)) {
+ node.block.rewrite(node, receiver);
+ return false;
+ }
+
+ // Try computing a constant interceptor.
+ HInstruction constantInterceptor =
+ tryComputeConstantInterceptor(receiver, interceptedClasses);
+ if (constantInterceptor != null) {
+ node.block.rewrite(node, constantInterceptor);
+ return false;
+ }
+
+ if (node.usedBy.every((e) => e is HBailoutTarget || e is HTypeGuard)) {
+ // The interceptor is only used by the bailout version. We don't
+ // remove it because the bailout version will use it.
+ node.interceptedClasses = backend.interceptedClasses;
+ return false;
+ }
+
+ node.interceptedClasses = interceptedClasses;
+
+ // Try creating a one-shot interceptor.
+ if (node.usedBy.length != 1) return false;
+ if (node.usedBy[0] is !HInvokeDynamic) return false;
+
+ HInvokeDynamic user = node.usedBy[0];
+
+ // If [node] was loop hoisted, we keep the interceptor.
+ if (!user.hasSameLoopHeaderAs(node)) return false;
+
+ // Replace the user with a [HOneShotInterceptor].
+ HConstant nullConstant = graph.addConstantNull(constantSystem);
+ List<HInstruction> inputs = new List<HInstruction>.from(user.inputs);
+ inputs[0] = nullConstant;
+ HOneShotInterceptor interceptor = new HOneShotInterceptor(
+ user.selector, inputs, node.interceptedClasses);
+ interceptor.sourcePosition = user.sourcePosition;
+ interceptor.sourceElement = user.sourceElement;
+ interceptor.instructionType = user.instructionType;
+
+ HBasicBlock block = user.block;
+ block.addAfter(user, interceptor);
+ block.rewrite(user, interceptor);
+ block.remove(user);
+ return true;
+ }
+
+
+ bool visitOneShotInterceptor(HOneShotInterceptor node) {
+ HInstruction constant = tryComputeConstantInterceptor(
+ node.inputs[1], node.interceptedClasses);
+
+ if (constant == null) return false;
+
+ Selector selector = node.selector;
+ // TODO(ngeoffray): make one shot interceptors know whether
+ // they have side effects.
+ HInstruction instruction;
+ if (selector.isGetter()) {
+ instruction= new HInvokeDynamicGetter(
+ selector,
+ node.element,
+ <HInstruction>[constant, node.inputs[1]],
+ false);
+ } else if (node.selector.isSetter()) {
+ instruction = new HInvokeDynamicSetter(
+ selector,
+ node.element,
+ <HInstruction>[constant, node.inputs[1], node.inputs[2]],
+ false);
+ } else {
+ List<HInstruction> inputs = new List<HInstruction>.from(node.inputs);
+ inputs[0] = constant;
+ instruction = new HInvokeDynamicMethod(selector, inputs, true);
+ }
+
+ HBasicBlock block = node.block;
+ block.addAfter(node, instruction);
+ block.rewrite(node, instruction);
+ return true;
+ }
+}
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 d1f80ec..426332e 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/invoke_dynamic_specializers.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/invoke_dynamic_specializers.dart
@@ -100,6 +100,10 @@
HInstruction tryConvertToBuiltin(HInvokeDynamic instruction,
Compiler compiler) {
if (instruction.inputs[1].isMutableIndexable(compiler)) {
+ if (!instruction.inputs[2].isInteger() && compiler.enableTypeAssertions) {
+ // We want the right checked mode error.
+ return null;
+ }
return new HIndexAssign(instruction.inputs[1],
instruction.inputs[2],
instruction.inputs[3],
@@ -130,6 +134,10 @@
HInstruction tryConvertToBuiltin(HInvokeDynamic instruction,
Compiler compiler) {
if (instruction.inputs[1].isIndexable(compiler)) {
+ if (!instruction.inputs[2].isInteger() && compiler.enableTypeAssertions) {
+ // We want the right checked mode error.
+ return null;
+ }
HInstruction index = new HIndex(
instruction.inputs[1], instruction.inputs[2], instruction.selector);
index.instructionType =
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart b/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart
index 088fe6e..757230d 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart
@@ -838,9 +838,12 @@
bool isNumberOrNull() => instructionType.isNumberOrNull();
bool isString() => instructionType.isString();
bool isPrimitive() => instructionType.isPrimitive();
+ bool isNull() => instructionType.isNull();
bool canBeNull() => instructionType.canBeNull();
bool canBePrimitive(Compiler compiler) =>
instructionType.canBePrimitive(compiler);
+ bool canBePrimitiveArray(Compiler compiler) =>
+ instructionType.canBePrimitiveArray(compiler);
bool isIndexable(Compiler compiler) =>
instructionType.isIndexable(compiler);
@@ -2044,9 +2047,10 @@
}
class HInterceptor extends HInstruction {
+ // This field should originally be null to allow GVN'ing all
+ // [HInterceptor] on the same input.
Set<ClassElement> interceptedClasses;
- HInterceptor(this.interceptedClasses, HInstruction receiver)
- : super(<HInstruction>[receiver]) {
+ HInterceptor(HInstruction receiver) : super(<HInstruction>[receiver]) {
sideEffects.clearAllSideEffects();
setUseGvn();
}
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/optimize.dart b/sdk/lib/_internal/compiler/implementation/ssa/optimize.dart
index 26523a5..c803976 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/optimize.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/optimize.dart
@@ -50,14 +50,13 @@
new SsaDeadPhiEliminator(),
new SsaConstantFolder(constantSystem, backend, work),
new SsaNonSpeculativeTypePropagator(compiler),
- new SsaReceiverSpecialization(compiler),
new SsaGlobalValueNumberer(compiler),
new SsaCodeMotion(),
new SsaValueRangeAnalyzer(compiler, constantSystem, work),
// Previous optimizations may have generated new
// opportunities for constant folding.
new SsaConstantFolder(constantSystem, backend, work),
- new SsaSimplifyInterceptors(constantSystem),
+ new SsaSimplifyInterceptors(compiler, constantSystem, work),
new SsaDeadCodeEliminator()];
runPhases(graph, phases);
if (!speculative) {
@@ -72,6 +71,7 @@
return false;
}
JavaScriptItemCompilationContext context = work.compilationContext;
+ ConstantSystem constantSystem = compiler.backend.constantSystem;
return measure(() {
SsaTypeGuardInserter inserter = new SsaTypeGuardInserter(compiler, work);
@@ -488,6 +488,10 @@
return graph.addConstantBool(false, constantSystem);
}
+ if (left.isNull() && right.isNull()) {
+ return graph.addConstantBool(true, constantSystem);
+ }
+
if (left.isConstantBoolean() && right.isBoolean()) {
HConstant constant = left;
if (constant.constant.isTrue()) {
@@ -580,13 +584,6 @@
} else {
return graph.addConstantBool(false, constantSystem);
}
- } else if (expressionType.isArray()) {
- if (identical(element, compiler.listClass)
- || Elements.isListSupertype(element, compiler)) {
- return graph.addConstantBool(true, constantSystem);
- } else {
- return graph.addConstantBool(false, constantSystem);
- }
// We need the [:hasTypeArguments:] check because we don't have
// the notion of generics in the backend. For example, [:this:] in
// a class [:A<T>:], is currently always considered to have the
@@ -796,140 +793,8 @@
return node;
}
- HInstruction visitInterceptor(HInterceptor node) {
- if (node.isConstant()) return node;
- // If the intercepted object does not need to be intercepted, just
- // return the object (the [:getInterceptor:] method would have
- // returned the object).
- HType type = node.receiver.instructionType;
- if (canUseSelfForInterceptor(type, node.interceptedClasses)) {
- return node.receiver;
- }
- HInstruction constant = tryComputeConstantInterceptor(
- node.inputs[0], node.interceptedClasses);
- if (constant == null) return node;
-
- return constant;
- }
-
- bool canUseSelfForInterceptor(HType receiverType,
- Set<ClassElement> interceptedClasses) {
- if (receiverType.canBePrimitive(compiler)) {
- // Primitives always need interceptors.
- return false;
- }
- if (receiverType.canBeNull()
- && interceptedClasses.contains(backend.jsNullClass)) {
- // Need the JSNull interceptor.
- return false;
- }
-
- // [interceptedClasses] is sparse - it is just the classes that define some
- // intercepted method. Their subclasses (that inherit the method) are
- // implicit, so we have to extend them.
-
- TypeMask receiverMask = receiverType.computeMask(compiler);
- return interceptedClasses
- .where((cls) => cls != compiler.objectClass)
- .map((cls) => backend.classesMixedIntoNativeClasses.contains(cls)
- ? new TypeMask.subtype(cls.rawType)
- : new TypeMask.subclass(cls.rawType))
- .every((mask) => receiverMask.intersection(mask, compiler).isEmpty);
- }
-
- HInstruction tryComputeConstantInterceptor(HInstruction input,
- Set<ClassElement> intercepted) {
- if (input == graph.explicitReceiverParameter) {
- // If `explicitReceiverParameter` is set it means the current method is an
- // interceptor method, and `this` is the interceptor. The caller just did
- // `getInterceptor(foo).currentMethod(foo)` to enter the current method.
- return graph.thisInstruction;
- }
-
- HType type = input.instructionType;
- ClassElement constantInterceptor;
- if (type.isInteger()) {
- constantInterceptor = backend.jsIntClass;
- } else if (type.isDouble()) {
- constantInterceptor = backend.jsDoubleClass;
- } else if (type.isBoolean()) {
- constantInterceptor = backend.jsBoolClass;
- } else if (type.isString()) {
- constantInterceptor = backend.jsStringClass;
- } else if (type.isArray()) {
- constantInterceptor = backend.jsArrayClass;
- } else if (type.isNull()) {
- constantInterceptor = backend.jsNullClass;
- } else if (type.isNumber()) {
- // If the method being intercepted is not defined in [int] or [double] we
- // can safely use the number interceptor. This is because none of the
- // [int] or [double] methods are called from a method defined on [num].
- if (!intercepted.contains(backend.jsIntClass)
- && !intercepted.contains(backend.jsDoubleClass)) {
- constantInterceptor = backend.jsNumberClass;
- }
- } else {
- // Try to find constant interceptor for a native class. If the receiver
- // is constrained to a leaf native class, we can use the class's
- // interceptor directly.
-
- // TODO(sra): Key DOM classes like Node, Element and Event are not leaf
- // classes. When the receiver type is not a leaf class, we might still be
- // able to use the receiver class as a constant interceptor. It is
- // usually the case that methods defined on a non-leaf class don't test
- // 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;
- }
- }
- }
-
- if (constantInterceptor == null) return null;
- if (constantInterceptor == work.element.getEnclosingClass()) {
- return graph.thisInstruction;
- }
-
- Constant constant = new InterceptorConstant(
- constantInterceptor.computeType(compiler));
- return graph.addConstant(constant);
- }
-
HInstruction visitOneShotInterceptor(HOneShotInterceptor node) {
- HInstruction newInstruction = handleInterceptedCall(node);
- if (newInstruction != node) return newInstruction;
-
- HInstruction constant = tryComputeConstantInterceptor(
- node.inputs[1], node.interceptedClasses);
-
- if (constant == null) return node;
-
- Selector selector = node.selector;
- // TODO(ngeoffray): make one shot interceptors know whether
- // they have side effects.
- if (selector.isGetter()) {
- HInstruction res = new HInvokeDynamicGetter(
- selector,
- node.element,
- <HInstruction>[constant, node.inputs[1]],
- false);
- return res;
- } else if (node.selector.isSetter()) {
- HInstruction res = new HInvokeDynamicSetter(
- selector,
- node.element,
- <HInstruction>[constant, node.inputs[1], node.inputs[2]],
- false);
- return res;
- } else {
- List<HInstruction> inputs = new List<HInstruction>.from(node.inputs);
- inputs[0] = constant;
- return new HInvokeDynamicMethod(selector, inputs, true);
- }
+ return handleInterceptedCall(node);
}
}
@@ -1572,6 +1437,11 @@
}
visitForeignNew(HForeignNew node) {
+ if (!work.element.isGenerativeConstructor()) return;
+ // Check if this is the new object allocated by this generative
+ // constructor. Inlining might add other [HForeignNew]
+ // instructions in the graph.
+ if (!node.usedBy.any((user) => user is HReturn)) return;
// The HForeignNew instruction is used in the generative constructor to
// initialize all fields in newly created objects. The fields are
// initialized to the value present in the initializer list or set to null
@@ -1623,100 +1493,3 @@
});
}
}
-
-/**
- * This phase specializes dominated uses of a call, where the call
- * can give us some type information of what the receiver might be.
- * For example, after a call to [:a.foo():], if [:foo:] is only
- * in class [:A:], a can be of type [:A:].
- */
-class SsaReceiverSpecialization extends HBaseVisitor
- implements OptimizationPhase {
- final String name = "SsaReceiverSpecialization";
- final Compiler compiler;
-
- SsaReceiverSpecialization(this.compiler);
-
- void visitGraph(HGraph graph) {
- visitDominatorTree(graph);
- }
-
- void visitInterceptor(HInterceptor interceptor) {
- HInstruction receiver = interceptor.receiver;
- JavaScriptBackend backend = compiler.backend;
- for (var user in receiver.usedBy) {
- if (user is HInterceptor && interceptor.dominates(user)) {
- Set<ClassElement> otherIntercepted = user.interceptedClasses;
- // If the dominated interceptor intercepts the int class or
- // the double class, we make sure these classes are also being
- // intercepted by the dominating interceptor. Otherwise, the
- // dominating interceptor could just intercept the number
- // class and therefore not implement the methods in the int or
- // double class.
- if (otherIntercepted.contains(backend.jsIntClass)
- || otherIntercepted.contains(backend.jsDoubleClass)) {
- // We cannot modify the intercepted classes set without
- // copying because it may be shared by multiple interceptors
- // because of caching in the backend.
- Set<ClassElement> copy = interceptor.interceptedClasses.toSet();
- copy.addAll(user.interceptedClasses);
- interceptor.interceptedClasses = copy;
- }
- user.interceptedClasses = interceptor.interceptedClasses;
- }
- }
- }
-
- // TODO(ngeoffray): Also implement it for non-intercepted calls.
-}
-
-/**
- * This phase replaces all interceptors that are used only once with
- * one-shot interceptors. It saves code size and makes the receiver of
- * an intercepted call a candidate for being generated at use site.
- */
-class SsaSimplifyInterceptors extends HBaseVisitor
- implements OptimizationPhase {
- final String name = "SsaSimplifyInterceptors";
- final ConstantSystem constantSystem;
- HGraph graph;
-
- SsaSimplifyInterceptors(this.constantSystem);
-
- void visitGraph(HGraph graph) {
- this.graph = graph;
- visitDominatorTree(graph);
- }
-
- void visitInterceptor(HInterceptor node) {
- if (node.usedBy.length != 1) return;
- // [HBailoutTarget] instructions might have the interceptor as
- // input. In such situation we let the dead code analyzer find out
- // the interceptor is not needed.
- if (node.usedBy[0] is !HInvokeDynamic) return;
-
- HInvokeDynamic user = node.usedBy[0];
-
- // If [node] was loop hoisted, we keep the interceptor.
- if (!user.hasSameLoopHeaderAs(node)) return;
-
- // Replace the user with a [HOneShotInterceptor].
- HConstant nullConstant = graph.addConstantNull(constantSystem);
- List<HInstruction> inputs = new List<HInstruction>.from(user.inputs);
- inputs[0] = nullConstant;
- HOneShotInterceptor interceptor = new HOneShotInterceptor(
- user.selector, inputs, node.interceptedClasses);
- interceptor.sourcePosition = user.sourcePosition;
- interceptor.sourceElement = user.sourceElement;
- interceptor.instructionType = user.instructionType;
-
- HBasicBlock block = user.block;
- block.addAfter(user, interceptor);
- block.rewrite(user, interceptor);
- block.remove(user);
-
- // The interceptor will be removed in the dead code elimination
- // phase. Note that removing it here would not work because of how
- // the [visitBasicBlock] is implemented.
- }
-}
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/ssa.dart b/sdk/lib/_internal/compiler/implementation/ssa/ssa.dart
index fe79732..c62f67e 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/ssa.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/ssa.dart
@@ -32,6 +32,7 @@
part 'builder.dart';
part 'codegen.dart';
part 'codegen_helpers.dart';
+part 'interceptor_simplifier.dart';
part 'invoke_dynamic_specializers.dart';
part 'nodes.dart';
part 'optimize.dart';
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/tracer.dart b/sdk/lib/_internal/compiler/implementation/ssa/tracer.dart
index 02d7cfe..c603386 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/tracer.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/tracer.dart
@@ -367,9 +367,7 @@
String visitInvokeConstructorBody(HInvokeConstructorBody invoke) {
String target = invoke.element.name.slowToString();
- int offset = HInvoke.ARGUMENTS_OFFSET + 1;
- List arguments = invoke.inputs.sublist(offset);
- return visitGenericInvoke("Invoke constructor body", target, arguments);
+ return visitGenericInvoke("Invoke constructor body", target, invoke.inputs);
}
String visitForeign(HForeign foreign) {
@@ -553,8 +551,12 @@
}
String visitTypeConversion(HTypeConversion node) {
+ assert(node.inputs.length <= 2);
+ String otherInput = (node.inputs.length == 2)
+ ? temporaryId(node.inputs[1])
+ : '';
return "TypeConversion: ${temporaryId(node.checkedInput)} to "
- "${node.instructionType}";
+ "${node.instructionType} $otherInput";
}
String visitRangeConversion(HRangeConversion node) {
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/types_propagation.dart b/sdk/lib/_internal/compiler/implementation/ssa/types_propagation.dart
index 5e1eb2a..9e85957 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/types_propagation.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/types_propagation.dart
@@ -190,14 +190,18 @@
}
}
- HType visitInvokeDynamicMethod(HInvokeDynamicMethod instruction) {
+ HType visitInvokeDynamic(HInvokeDynamic instruction) {
// Update the pending optimizations map based on the potentially
// new types of the operands. If the operand types no longer allow
// us to optimize, we remove the pending optimization.
if (instruction.specializer is BinaryArithmeticSpecializer) {
HInstruction left = instruction.inputs[1];
HInstruction right = instruction.inputs[2];
- if (left.isNumber() && !right.isNumber()) {
+ if (left.isNumber()
+ && !right.isNumber()
+ // We need to call the actual method in checked mode to get
+ // the right type error.
+ && !compiler.enableTypeAssertions) {
pendingOptimizations[instruction] = () {
// This callback function is invoked after we're done
// propagating types. The types shouldn't have changed.
@@ -208,7 +212,7 @@
pendingOptimizations.remove(instruction);
}
}
- return super.visitInvokeDynamicMethod(instruction);
+ return super.visitInvokeDynamic(instruction);
}
}
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/validate.dart b/sdk/lib/_internal/compiler/implementation/ssa/validate.dart
index 16de943..e751b4d 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/validate.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/validate.dart
@@ -150,7 +150,8 @@
bool inBasicBlock = instruction.isInBasicBlock();
return everyInstruction(instruction.inputs, (input, count) {
if (inBasicBlock) {
- return countInstruction(input.usedBy, instruction) == count;
+ return input.isInBasicBlock()
+ && countInstruction(input.usedBy, instruction) == count;
} else {
return countInstruction(input.usedBy, instruction) == 0;
}
@@ -161,7 +162,8 @@
bool hasCorrectUses() {
if (!instruction.isInBasicBlock()) return true;
return everyInstruction(instruction.usedBy, (use, count) {
- return countInstruction(use.inputs, instruction) == count;
+ return use.isInBasicBlock()
+ && countInstruction(use.inputs, instruction) == count;
});
}
diff --git a/sdk/lib/_internal/compiler/implementation/typechecker.dart b/sdk/lib/_internal/compiler/implementation/typechecker.dart
index b58a0eb..6ab80fd 100644
--- a/sdk/lib/_internal/compiler/implementation/typechecker.dart
+++ b/sdk/lib/_internal/compiler/implementation/typechecker.dart
@@ -680,6 +680,20 @@
}
}
+ /// Returns the first type in the list or [:dynamic:] if the list is empty.
+ DartType firstType(Link<DartType> link) {
+ return link.isEmpty ? types.dynamicType : link.head;
+ }
+
+ /**
+ * Returns the second type in the list or [:dynamic:] if the list is too
+ * short.
+ */
+ DartType secondType(Link<DartType> link) {
+ return link.isEmpty || link.tail.isEmpty
+ ? types.dynamicType : link.tail.head;
+ }
+
/**
* Checks [: target o= value :] for some operator o, and returns the type
* of the result. This method also handles increment/decrement expressions
@@ -701,7 +715,7 @@
FunctionType operatorType = operator;
// [result] is the type of target o value.
DartType result = operatorType.returnType;
- DartType operatorArgument = operatorType.parameterTypes.head;
+ DartType operatorArgument = firstType(operatorType.parameterTypes);
// Check target o value.
bool validValue = checkAssignable(valueNode, value, operatorArgument);
if (validValue || !(node.isPrefix || node.isPostfix)) {
@@ -732,7 +746,7 @@
node, base, const SourceString('[]'), MemberKind.OPERATOR);
if (indexGet is FunctionType) {
FunctionType indexGetType = indexGet;
- DartType indexGetKey = indexGetType.parameterTypes.head;
+ DartType indexGetKey = firstType(indexGetType.parameterTypes);
// Check base[key].
bool validKey = checkAssignable(keyNode, key, indexGetKey);
@@ -745,7 +759,7 @@
FunctionType operatorType = operator;
// Check base[key] o value.
- DartType operatorArgument = operatorType.parameterTypes.head;
+ DartType operatorArgument = firstType(operatorType.parameterTypes);
bool validValue = checkAssignable(valueNode, value, operatorArgument);
// [result] is the type of base[key] o value.
@@ -756,9 +770,8 @@
node, base, const SourceString('[]='), MemberKind.OPERATOR);
if (indexSet is FunctionType) {
FunctionType indexSetType = indexSet;
- DartType indexSetKey = indexSetType.parameterTypes.head;
- DartType indexSetValue =
- indexSetType.parameterTypes.tail.head;
+ DartType indexSetKey = firstType(indexSetType.parameterTypes);
+ DartType indexSetValue = secondType(indexSetType.parameterTypes);
if (validKey || indexGetKey != indexSetKey) {
// Only check base[key] on []= if base[key] was valid for [] or
@@ -793,9 +806,9 @@
node, base, const SourceString('[]='), MemberKind.OPERATOR);
if (indexSet is FunctionType) {
FunctionType indexSetType = indexSet;
- DartType indexSetKey = indexSetType.parameterTypes.head;
+ DartType indexSetKey = firstType(indexSetType.parameterTypes);
checkAssignable(keyNode, key, indexSetKey);
- DartType indexSetValue = indexSetType.parameterTypes.tail.head;
+ DartType indexSetValue = secondType(indexSetType.parameterTypes);
checkAssignable(node.assignmentOperator, value, indexSetValue);
}
return value;
@@ -899,7 +912,7 @@
DartType visitLiteralList(LiteralList node) {
InterfaceType listType = elements.getType(node);
- DartType listElementType = listType.typeArguments.head;
+ DartType listElementType = firstType(listType.typeArguments);
for (Link<Node> link = node.elements.nodes;
!link.isEmpty;
link = link.tail) {
@@ -1087,8 +1100,8 @@
visitLiteralMap(LiteralMap node) {
InterfaceType mapType = elements.getType(node);
- DartType mapKeyType = mapType.typeArguments.head;
- DartType mapValueType = mapType.typeArguments.tail.head;
+ DartType mapKeyType = firstType(mapType.typeArguments);
+ DartType mapValueType = secondType(mapType.typeArguments);
for (Link<Node> link = node.entries.nodes;
!link.isEmpty;
link = link.tail) {
@@ -1106,7 +1119,12 @@
}
visitNamedArgument(NamedArgument node) {
- return unhandledExpression();
+ // Named arguments are visited as part of analyzing invocations of
+ // unresolved methods. For instance [: foo(a: 42); :] where 'foo' is neither
+ // found in the enclosing scope nor through lookup on 'this' or
+ // [: x.foo(b: 42); :] where 'foo' cannot be not found through lookup on
+ // the static type of 'x'.
+ return analyze(node.expression);
}
visitSwitchStatement(SwitchStatement node) {
@@ -1122,7 +1140,15 @@
}
visitTryStatement(TryStatement node) {
- return unhandledStatement();
+ // TODO(johnniwinther): Use reachability information of try-block,
+ // catch-blocks and finally-block to compute the whether the try statement
+ // is returning.
+ analyze(node.tryBlock);
+ for (CatchBlock catchBlock in node.catchBlocks) {
+ analyze(catchBlock);
+ }
+ analyzeWithDefault(node.finallyBlock, null);
+ return StatementType.NOT_RETURNING;
}
visitScriptTag(ScriptTag node) {
@@ -1130,7 +1156,7 @@
}
visitCatchBlock(CatchBlock node) {
- return unhandledStatement();
+ return analyze(node.block);
}
visitTypedef(Typedef node) {
diff --git a/sdk/lib/_internal/compiler/implementation/types/concrete_types_inferrer.dart b/sdk/lib/_internal/compiler/implementation/types/concrete_types_inferrer.dart
index 6ad589e..f1e5291 100644
--- a/sdk/lib/_internal/compiler/implementation/types/concrete_types_inferrer.dart
+++ b/sdk/lib/_internal/compiler/implementation/types/concrete_types_inferrer.dart
@@ -33,7 +33,7 @@
ClassBaseType(this.element);
- bool operator ==(BaseType other) {
+ bool operator ==(var other) {
if (identical(this, other)) return true;
if (other is! ClassBaseType) return false;
return element == other.element;
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 0f0ee58..59f6874 100644
--- a/sdk/lib/_internal/compiler/implementation/types/flat_type_mask.dart
+++ b/sdk/lib/_internal/compiler/implementation/types/flat_type_mask.dart
@@ -383,19 +383,22 @@
*/
static bool hasElementIn(ClassElement cls,
Selector selector,
- Element element) {
+ Element element,
+ Compiler compiler) {
// Use [:implementation:] of [element]
// because our function set only stores declarations.
- Element result = findMatchIn(cls, selector);
+ Element result = findMatchIn(cls, selector, compiler);
return result == null
? false
: result.implementation == element.implementation;
}
- static Element findMatchIn(ClassElement cls, Selector selector) {
+ static Element findMatchIn(ClassElement cls,
+ Selector selector,
+ Compiler compiler) {
// Use the [:implementation] of [cls] in case the found [element]
// is in the patch class.
- return cls.implementation.lookupSelector(selector);
+ return cls.implementation.lookupSelector(selector, compiler);
}
/**
@@ -408,7 +411,7 @@
if (isEmpty) {
if (!isNullable) return false;
return hasElementIn(
- compiler.backend.nullImplementation, selector, element);
+ compiler.backend.nullImplementation, selector, element, compiler);
}
// TODO(kasperl): Can't we just avoid creating typed selectors
@@ -424,14 +427,14 @@
if (compiler.backend.isNullImplementation(other)) {
return isNullable;
} else if (isExact) {
- return hasElementIn(self, selector, element);
+ return hasElementIn(self, selector, element, compiler);
} else if (isSubclass) {
- return hasElementIn(self, selector, element)
+ return hasElementIn(self, selector, element, compiler)
|| other.isSubclassOf(self)
|| compiler.world.hasAnySubclassThatMixes(self, other);
} else {
assert(isSubtype);
- return hasElementIn(self, selector, element)
+ return hasElementIn(self, selector, element, compiler)
|| other.implementsInterface(self)
|| other.isSubclassOf(self)
|| compiler.world.hasAnySubclassThatMixes(self, other)
@@ -446,7 +449,7 @@
static bool hasConcreteMatch(ClassElement cls,
Selector selector,
Compiler compiler) {
- Element element = findMatchIn(cls, selector);
+ Element element = findMatchIn(cls, selector, compiler);
if (element == null) return false;
if (element.isAbstract(compiler)) {
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 c6c2e26..9241edc 100644
--- a/sdk/lib/_internal/compiler/implementation/types/simple_types_inferrer.dart
+++ b/sdk/lib/_internal/compiler/implementation/types/simple_types_inferrer.dart
@@ -961,23 +961,23 @@
}
}
- void unregisterCalledElement(Send send,
+ void unregisterCalledElement(Node node,
Selector selector,
Element caller,
Element callee) {
if (callee.isField()) {
if (selector.isSetter()) {
Map<Node, TypeMask> types = typeOfFields[callee];
- if (types == null || !types.containsKey(send)) return;
- types.remove(send);
+ if (types == null || !types.containsKey(node)) return;
+ types.remove(node);
if (hasAnalyzedAll) updateNonFinalFieldType(callee);
}
} else if (callee.isGetter()) {
return;
} else {
Map<Node, ArgumentsTypes> types = typeOfArguments[callee];
- if (types == null || !types.containsKey(send)) return;
- types.remove(send);
+ if (types == null || !types.containsKey(node)) return;
+ types.remove(node);
if (hasAnalyzedAll) enqueueAgain(callee);
}
}
@@ -2224,9 +2224,18 @@
assert(selector.isOperator());
elements.setOperatorSelectorInComplexSendSet(node, selector);
}
- } else {
- assert(node.asSend() != null);
+ } else if (node.asSend() != null) {
elements.setSelector(node, selector);
+ } else {
+ assert(node.asForIn() != null);
+ if (selector.asUntyped == compiler.iteratorSelector) {
+ elements.setIteratorSelector(node, selector);
+ } else if (selector.asUntyped == compiler.currentSelector) {
+ elements.setCurrentSelector(node, selector);
+ } else {
+ assert(selector.asUntyped == compiler.moveNextSelector);
+ elements.setMoveNextSelector(node, selector);
+ }
}
}
@@ -2447,22 +2456,41 @@
TypeMask visitForIn(ForIn node) {
bool changed = false;
- visit(node.expression);
- if (!isThisExposed && node.expression.isThis()) {
- Selector iteratorSelector = compiler.iteratorSelector;
- checkIfExposesThis(new TypedSelector(thisType, iteratorSelector));
- TypeMask iteratorType = inferrer.typeOfSelector(iteratorSelector);
+ TypeMask expressionType = visit(node.expression);
+ Selector iteratorSelector = elements.getIteratorSelector(node);
+ Selector currentSelector = elements.getCurrentSelector(node);
+ Selector moveNextSelector = elements.getMoveNextSelector(node);
- checkIfExposesThis(
- new TypedSelector(iteratorType, compiler.moveNextSelector));
- checkIfExposesThis(
- new TypedSelector(iteratorType, compiler.currentSelector));
+ TypeMask iteratorType =
+ handleDynamicSend(node, iteratorSelector, expressionType, null);
+ handleDynamicSend(node, moveNextSelector,
+ iteratorType, new ArgumentsTypes([], null));
+ TypeMask currentType =
+ handleDynamicSend(node, currentSelector, iteratorType, null);
+
+ // We nullify the type in case there is no element in the
+ // iterable.
+ currentType = currentType.nullable();
+
+ if (node.expression.isThis()) {
+ // Any reasonable implementation of an iterator would expose
+ // this, so we play it safe and assume it will.
+ isThisExposed = true;
}
+
Node identifier = node.declaredIdentifier;
- Element variable = elements[identifier];
+ Element element = elements[identifier];
Selector selector = elements.getSelector(identifier);
- handlePlainAssignment(identifier, variable, selector,
- inferrer.dynamicType, inferrer.dynamicType,
+
+ TypeMask receiverType;
+ if (element != null && element.isInstanceMember()) {
+ receiverType = thisType;
+ } else {
+ receiverType = inferrer.dynamicType;
+ }
+
+ handlePlainAssignment(identifier, element, selector,
+ receiverType, currentType,
node.expression);
return handleLoop(node, () {
visit(node.body);
diff --git a/sdk/lib/_internal/compiler/implementation/util/uri_extras.dart b/sdk/lib/_internal/compiler/implementation/util/uri_extras.dart
index f43e826..654341d 100644
--- a/sdk/lib/_internal/compiler/implementation/util/uri_extras.dart
+++ b/sdk/lib/_internal/compiler/implementation/util/uri_extras.dart
@@ -5,7 +5,6 @@
library uri_extras;
import 'dart:math';
-import 'dart:uri';
String relativize(Uri base, Uri uri, bool isWindows) {
if (!base.path.startsWith('/')) {
@@ -31,7 +30,7 @@
if (equalsNCS(base.scheme, 'file') &&
equalsNCS(base.scheme, uri.scheme) &&
base.userInfo == uri.userInfo &&
- equalsNCS(base.domain, uri.domain) &&
+ equalsNCS(base.host, uri.host) &&
base.port == uri.port &&
uri.query == "" && uri.fragment == "") {
if (normalize(uri.path).startsWith(normalize(base.path))) {
diff --git a/sdk/lib/_internal/compiler/samples/compile_loop/compile_loop.dart b/sdk/lib/_internal/compiler/samples/compile_loop/compile_loop.dart
index cb0e64b..df3f21a 100644
--- a/sdk/lib/_internal/compiler/samples/compile_loop/compile_loop.dart
+++ b/sdk/lib/_internal/compiler/samples/compile_loop/compile_loop.dart
@@ -7,7 +7,6 @@
library sample.compile_loop;
import 'dart:async';
-import 'dart:uri';
import '../../compiler.dart' as compiler;
diff --git a/sdk/lib/_internal/compiler/samples/darttags/darttags.dart b/sdk/lib/_internal/compiler/samples/darttags/darttags.dart
index f600188..347b230 100644
--- a/sdk/lib/_internal/compiler/samples/darttags/darttags.dart
+++ b/sdk/lib/_internal/compiler/samples/darttags/darttags.dart
@@ -24,7 +24,6 @@
// Where DART_LOCATION is the gclient directory where you found .gclient.
import 'dart:io';
-import 'dart:uri';
// TODO(ahe): Should be dart:mirrors.
import '../../implementation/mirrors/mirrors.dart';
diff --git a/sdk/lib/_internal/compiler/samples/jsonify/jsonify.dart b/sdk/lib/_internal/compiler/samples/jsonify/jsonify.dart
index 891f505..82232c9 100644
--- a/sdk/lib/_internal/compiler/samples/jsonify/jsonify.dart
+++ b/sdk/lib/_internal/compiler/samples/jsonify/jsonify.dart
@@ -4,7 +4,6 @@
import 'dart:io';
import 'dart:json';
-import 'dart:uri';
// TODO(ahe): Should be dart:mirrors.
import '../../implementation/mirrors/mirrors.dart';
diff --git a/sdk/lib/_internal/compiler/samples/leap/leap.dart b/sdk/lib/_internal/compiler/samples/leap/leap.dart
index 3dba298..f352287 100644
--- a/sdk/lib/_internal/compiler/samples/leap/leap.dart
+++ b/sdk/lib/_internal/compiler/samples/leap/leap.dart
@@ -5,7 +5,6 @@
library leap;
import 'dart:isolate';
-import 'dart:uri';
import 'dart:html' as html;
import 'request_cache.dart';
diff --git a/sdk/lib/_internal/dartdoc/bin/dartdoc.dart b/sdk/lib/_internal/dartdoc/bin/dartdoc.dart
index 47eb828..d9fe3d9 100644
--- a/sdk/lib/_internal/dartdoc/bin/dartdoc.dart
+++ b/sdk/lib/_internal/dartdoc/bin/dartdoc.dart
@@ -18,7 +18,6 @@
import 'dart:async';
import 'dart:io';
-import 'dart:uri';
// TODO(rnystrom): Use "package:" URL (#4968).
import '../lib/dartdoc.dart';
diff --git a/sdk/lib/_internal/dartdoc/lib/dartdoc.dart b/sdk/lib/_internal/dartdoc/lib/dartdoc.dart
index 152f32c..dfc0f45 100644
--- a/sdk/lib/_internal/dartdoc/lib/dartdoc.dart
+++ b/sdk/lib/_internal/dartdoc/lib/dartdoc.dart
@@ -21,7 +21,6 @@
import 'dart:isolate';
import 'dart:json' as json;
import 'dart:math';
-import 'dart:uri';
import 'package:pathos/path.dart' as pathos;
diff --git a/sdk/lib/_internal/dartdoc/lib/src/dart2js_mirrors.dart b/sdk/lib/_internal/dartdoc/lib/src/dart2js_mirrors.dart
index 8ce26c0..7e421f8 100644
--- a/sdk/lib/_internal/dartdoc/lib/src/dart2js_mirrors.dart
+++ b/sdk/lib/_internal/dartdoc/lib/src/dart2js_mirrors.dart
@@ -6,7 +6,6 @@
import 'dart:async' show Future;
import 'dart:io' show Path;
-import 'dart:uri';
import '../../../compiler/compiler.dart' as api;
import '../../../compiler/implementation/mirrors/dart2js_mirror.dart' as dart2js
diff --git a/sdk/lib/_internal/dartdoc/lib/src/dartdoc/utils.dart b/sdk/lib/_internal/dartdoc/lib/src/dartdoc/utils.dart
index 016a354..4b95669 100644
--- a/sdk/lib/_internal/dartdoc/lib/src/dartdoc/utils.dart
+++ b/sdk/lib/_internal/dartdoc/lib/src/dartdoc/utils.dart
@@ -6,7 +6,6 @@
library utils;
import 'dart:io';
-import 'dart:uri';
import 'dart:math' as math;
import 'package:pathos/path.dart' as pathos;
diff --git a/sdk/lib/_internal/dartdoc/lib/src/export_map.dart b/sdk/lib/_internal/dartdoc/lib/src/export_map.dart
index 512991d..0173009 100644
--- a/sdk/lib/_internal/dartdoc/lib/src/export_map.dart
+++ b/sdk/lib/_internal/dartdoc/lib/src/export_map.dart
@@ -9,7 +9,6 @@
library export_map;
import 'dart:io';
-import 'dart:uri';
import 'package:analyzer_experimental/analyzer.dart';
import 'package:pathos/path.dart' as pathos;
diff --git a/sdk/lib/_internal/dartdoc/test/export_map_test.dart b/sdk/lib/_internal/dartdoc/test/export_map_test.dart
index 9ac4288..7d271d8 100644
--- a/sdk/lib/_internal/dartdoc/test/export_map_test.dart
+++ b/sdk/lib/_internal/dartdoc/test/export_map_test.dart
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
import 'dart:io';
-import 'dart:uri';
import 'package:pathos/path.dart' as pathos;
import 'package:unittest/unittest.dart';
diff --git a/sdk/lib/_internal/libraries.dart b/sdk/lib/_internal/libraries.dart
index ea69f77..2e8efef 100644
--- a/sdk/lib/_internal/libraries.dart
+++ b/sdk/lib/_internal/libraries.dart
@@ -38,9 +38,6 @@
"core/core.dart",
dart2jsPatchPath: "_internal/compiler/implementation/lib/core_patch.dart"),
- "crypto": const LibraryInfo(
- "crypto/crypto.dart"),
-
"html": const LibraryInfo(
"html/dartium/html_dartium.dart",
category: "Client",
@@ -101,9 +98,6 @@
category: "Client",
dart2jsPath: "svg/dart2js/svg_dart2js.dart"),
- "uri": const LibraryInfo(
- "uri/uri.dart"),
-
"utf": const LibraryInfo(
"utf/utf.dart"),
diff --git a/sdk/lib/_internal/pub/lib/src/command.dart b/sdk/lib/_internal/pub/lib/src/command.dart
index d1f8516..abc2468 100644
--- a/sdk/lib/_internal/pub/lib/src/command.dart
+++ b/sdk/lib/_internal/pub/lib/src/command.dart
@@ -134,11 +134,11 @@
return commandFuture;
}).whenComplete(() => cache.deleteTempDir()).catchError((e) {
if (e is PubspecNotFoundException && e.name == null) {
- e = 'Could not find a file named "pubspec.yaml" in the directory '
- '${path.current}.';
+ e = new ApplicationException('Could not find a file named '
+ '"pubspec.yaml" in the directory ${path.current}.');
} else if (e is PubspecHasNoNameException && e.name == null) {
- e = 'pubspec.yaml is missing the required "name" field (e.g. "name: '
- '${path.basename(path.current)}").';
+ e = new ApplicationException('pubspec.yaml is missing the required '
+ '"name" field (e.g. "name: ${path.basename(path.current)}").');
}
handleError(e);
diff --git a/sdk/lib/_internal/pub/lib/src/command_lish.dart b/sdk/lib/_internal/pub/lib/src/command_lish.dart
index 9fc723c..20bbdd8 100644
--- a/sdk/lib/_internal/pub/lib/src/command_lish.dart
+++ b/sdk/lib/_internal/pub/lib/src/command_lish.dart
@@ -7,7 +7,6 @@
import 'dart:async';
import 'dart:io';
import 'dart:json';
-import 'dart:uri';
import 'package:args/args.dart';
import 'package:http/http.dart' as http;
@@ -52,34 +51,36 @@
Future _publish(packageBytes) {
var cloudStorageUrl;
return oauth2.withClient(cache, (client) {
- // TODO(nweiz): Cloud Storage can provide an XML-formatted error. We
- // should report that error and exit.
- var newUri = server.resolve("/packages/versions/new.json");
- return client.get(newUri).then((response) {
- var parameters = parseJsonResponse(response);
+ return log.progress('Uploading', () {
+ // TODO(nweiz): Cloud Storage can provide an XML-formatted error. We
+ // should report that error and exit.
+ var newUri = server.resolve("/packages/versions/new.json");
+ return client.get(newUri).then((response) {
+ var parameters = parseJsonResponse(response);
- var url = _expectField(parameters, 'url', response);
- if (url is! String) invalidServerResponse(response);
- cloudStorageUrl = Uri.parse(url);
- var request = new http.MultipartRequest('POST', cloudStorageUrl);
+ var url = _expectField(parameters, 'url', response);
+ if (url is! String) invalidServerResponse(response);
+ cloudStorageUrl = Uri.parse(url);
+ var request = new http.MultipartRequest('POST', cloudStorageUrl);
- var fields = _expectField(parameters, 'fields', response);
- if (fields is! Map) invalidServerResponse(response);
- fields.forEach((key, value) {
- if (value is! String) invalidServerResponse(response);
- request.fields[key] = value;
- });
+ var fields = _expectField(parameters, 'fields', response);
+ if (fields is! Map) invalidServerResponse(response);
+ fields.forEach((key, value) {
+ if (value is! String) invalidServerResponse(response);
+ request.fields[key] = value;
+ });
- request.followRedirects = false;
- request.files.add(new http.MultipartFile.fromBytes(
- 'file', packageBytes, filename: 'package.tar.gz'));
- return client.send(request);
- }).then(http.Response.fromStream).then((response) {
- var location = response.headers['location'];
- if (location == null) throw new PubHttpException(response);
- return location;
- }).then((location) => client.get(location))
- .then(handleJsonSuccess);
+ request.followRedirects = false;
+ request.files.add(new http.MultipartFile.fromBytes(
+ 'file', packageBytes, filename: 'package.tar.gz'));
+ return client.send(request);
+ }).then(http.Response.fromStream).then((response) {
+ var location = response.headers['location'];
+ if (location == null) throw new PubHttpException(response);
+ return location;
+ }).then((location) => client.get(location))
+ .then(handleJsonSuccess);
+ });
}).catchError((error) {
if (error is! PubHttpException) throw error;
var url = error.response.request.url;
@@ -87,7 +88,7 @@
// TODO(nweiz): the response may have XML-formatted information about
// the error. Try to parse that out once we have an easily-accessible
// XML parser.
- throw new Exception('Failed to upload the package.');
+ throw new ApplicationException('Failed to upload the package.');
} else if (urisEqual(Uri.parse(url.origin), Uri.parse(server.origin))) {
handleJsonError(error.response);
} else {
diff --git a/sdk/lib/_internal/pub/lib/src/command_uploader.dart b/sdk/lib/_internal/pub/lib/src/command_uploader.dart
index 2f4208d..c3b9be8 100644
--- a/sdk/lib/_internal/pub/lib/src/command_uploader.dart
+++ b/sdk/lib/_internal/pub/lib/src/command_uploader.dart
@@ -6,7 +6,6 @@
import 'dart:async';
import 'dart:io';
-import 'dart:uri';
import 'package:args/args.dart';
import 'package:pathos/path.dart' as path;
@@ -64,12 +63,12 @@
var uploader = commandOptions.rest[0];
return oauth2.withClient(cache, (client) {
if (command == 'add') {
- var url = server.resolve("/packages/${encodeUriComponent(package)}"
+ var url = server.resolve("/packages/${Uri.encodeComponent(package)}"
"/uploaders.json");
return client.post(url, fields: {"email": uploader});
} else { // command == 'remove'
- var url = server.resolve("/packages/${encodeUriComponent(package)}"
- "/uploaders/${encodeUriComponent(uploader)}.json");
+ var url = server.resolve("/packages/${Uri.encodeComponent(package)}"
+ "/uploaders/${Uri.encodeComponent(uploader)}.json");
return client.delete(url);
}
});
diff --git a/sdk/lib/_internal/pub/lib/src/error_group.dart b/sdk/lib/_internal/pub/lib/src/error_group.dart
index 694638c..a6f9e86 100644
--- a/sdk/lib/_internal/pub/lib/src/error_group.dart
+++ b/sdk/lib/_internal/pub/lib/src/error_group.dart
@@ -129,7 +129,7 @@
_isDone = true;
_done._signalError(error);
- if (!caught && !_done._hasListeners) error.throwDelayed();
+ if (!caught && !_done._hasListeners) runAsync((){ throw error; });
}
/// Notifies [this] that one of its member [Future]s is complete.
diff --git a/sdk/lib/_internal/pub/lib/src/hosted_source.dart b/sdk/lib/_internal/pub/lib/src/hosted_source.dart
index a793f65..a5c9992 100644
--- a/sdk/lib/_internal/pub/lib/src/hosted_source.dart
+++ b/sdk/lib/_internal/pub/lib/src/hosted_source.dart
@@ -7,7 +7,6 @@
import 'dart:async';
import 'dart:io' as io;
import 'dart:json' as json;
-import 'dart:uri';
import 'package:http/http.dart' as http;
import 'package:pathos/path.dart' as path;
@@ -214,8 +213,8 @@
Uri _makeUrl(description, String pattern(String server, String package)) {
var parsed = _parseDescription(description);
var server = parsed.last;
- var package = encodeUriComponent(parsed.first);
- return new Uri(pattern(server, package));
+ var package = Uri.encodeComponent(parsed.first);
+ return Uri.parse(pattern(server, package));
}
/// Parses [id] into its server, package name, and version components, then
@@ -225,9 +224,9 @@
String pattern(String server, String package, String version)) {
var parsed = _parseDescription(id.description);
var server = parsed.last;
- var package = encodeUriComponent(parsed.first);
- var version = encodeUriComponent(id.version.toString());
- return new Uri(pattern(server, package, version));
+ var package = Uri.encodeComponent(parsed.first);
+ var version = Uri.encodeComponent(id.version.toString());
+ return Uri.parse(pattern(server, package, version));
}
/// Parses the description for a package.
diff --git a/sdk/lib/_internal/pub/lib/src/io.dart b/sdk/lib/_internal/pub/lib/src/io.dart
index 659661f..e9a1316 100644
--- a/sdk/lib/_internal/pub/lib/src/io.dart
+++ b/sdk/lib/_internal/pub/lib/src/io.dart
@@ -10,7 +10,6 @@
import 'dart:io';
import 'dart:isolate';
import 'dart:json';
-import 'dart:uri';
import 'package:pathos/path.dart' as path;
import 'package:http/http.dart' show ByteStream;
diff --git a/sdk/lib/_internal/pub/lib/src/log.dart b/sdk/lib/_internal/pub/lib/src/log.dart
index e01425b..047f621 100644
--- a/sdk/lib/_internal/pub/lib/src/log.dart
+++ b/sdk/lib/_internal/pub/lib/src/log.dart
@@ -18,6 +18,13 @@
/// [recordTranscript()] is called.
List<Entry> _transcript;
+/// The timer used to write "..." during a progress log.
+Timer _progressTimer;
+
+/// The progress message as it's being incrementally appended. When the
+/// progress is done, a single entry will be added to the log for it.
+String _progressMessage;
+
/// An enum type for defining the different logging levels. By default, [ERROR]
/// and [WARNING] messages are printed to sterr. [MESSAGE] messages are printed
/// to stdout, and others are ignored.
@@ -178,6 +185,40 @@
stderr.writeln('---- End log transcript ----');
}
+/// Prints [message] then slowly prints additional "..." after it until the
+/// future returned by [callback] completes. If anything else is logged during
+/// this, it cancels the progress.
+Future progress(String message, Future callback()) {
+ if (_progressTimer != null) throw new StateError("Already in progress.");
+
+ _progressMessage = '$message...';
+ stdout.write(_progressMessage);
+
+ _progressTimer = new Timer.periodic(new Duration(milliseconds: 500), (_) {
+ stdout.write('.');
+ _progressMessage += '.';
+ });
+
+ return callback().whenComplete(_stopProgress);
+}
+
+/// Stops the running progress indicator, if currently running.
+_stopProgress() {
+ if (_progressTimer == null) return;
+
+ // Stop the timer.
+ _progressTimer.cancel();
+ _progressTimer = null;
+ stdout.writeln();
+
+ // Add the progress message to the transcript.
+ if (_transcript != null) {
+ _transcript.add(new Entry(Level.MESSAGE, [_progressMessage]));
+ }
+
+ _progressMessage = null;
+}
+
/// Sets the verbosity to "normal", which shows errors, warnings, and messages.
void showNormal() {
_loggers[Level.ERROR] = _logToStderr;
@@ -241,6 +282,8 @@
}
void _logToStream(IOSink sink, Entry entry, {bool showLabel}) {
+ _stopProgress();
+
bool firstLine = true;
for (var line in entry.lines) {
if (showLabel) {
diff --git a/sdk/lib/_internal/pub/lib/src/oauth2.dart b/sdk/lib/_internal/pub/lib/src/oauth2.dart
index 56b1494..dd2c7b6 100644
--- a/sdk/lib/_internal/pub/lib/src/oauth2.dart
+++ b/sdk/lib/_internal/pub/lib/src/oauth2.dart
@@ -6,7 +6,6 @@
import 'dart:async';
import 'dart:io';
-import 'dart:uri';
import 'package:oauth2/oauth2.dart';
import 'package:pathos/path.dart' as path;
diff --git a/sdk/lib/_internal/pub/lib/src/package.dart b/sdk/lib/_internal/pub/lib/src/package.dart
index a2a1b12..22d3bee 100644
--- a/sdk/lib/_internal/pub/lib/src/package.dart
+++ b/sdk/lib/_internal/pub/lib/src/package.dart
@@ -11,6 +11,7 @@
import 'io.dart';
import 'pubspec.dart';
import 'source_registry.dart';
+import 'utils.dart';
import 'version.dart';
final _README_REGEXP = new RegExp(r"^README($|\.)", caseSensitive: false);
@@ -190,29 +191,30 @@
}
}
-class PubspecNotFoundException implements Exception {
+class PubspecNotFoundException extends ApplicationException {
final String name;
- PubspecNotFoundException(this.name);
-
- String toString() => 'Package "$name" doesn\'t have a pubspec.yaml file.';
+ PubspecNotFoundException(String name)
+ : name = name,
+ super('Package "$name" doesn\'t have a pubspec.yaml file.');
}
-class PubspecHasNoNameException implements Exception {
+class PubspecHasNoNameException extends ApplicationException {
final String name;
- PubspecHasNoNameException(this.name);
-
- String toString() => 'Package "$name"\'s pubspec.yaml file is missing the '
- 'required "name" field (e.g. "name: $name").';
+ PubspecHasNoNameException(String name)
+ : name = name,
+ super('Package "$name"\'s pubspec.yaml file is missing the '
+ 'required "name" field (e.g. "name: $name").');
}
-class PubspecNameMismatchException implements Exception {
+class PubspecNameMismatchException extends ApplicationException {
final String expectedName;
final String actualName;
- PubspecNameMismatchException(this.expectedName, this.actualName);
-
- String toString() => 'The name you specified for your dependency, '
- '"$expectedName", doesn\'t match the name "$actualName" in its pubspec.';
+ PubspecNameMismatchException(String expectedName, String actualName)
+ : expectedName = expectedName,
+ actualName = actualName,
+ super('The name you specified for your dependency, "$expectedName", '
+ 'doesn\'t match the name "$actualName" in its pubspec.');
}
diff --git a/sdk/lib/_internal/pub/lib/src/safe_http_server.dart b/sdk/lib/_internal/pub/lib/src/safe_http_server.dart
index 25d57ee..c9885f1 100644
--- a/sdk/lib/_internal/pub/lib/src/safe_http_server.dart
+++ b/sdk/lib/_internal/pub/lib/src/safe_http_server.dart
@@ -6,7 +6,6 @@
import 'dart:async';
import 'dart:io';
-import 'dart:uri';
// TODO(nweiz): remove this when issue 9140 is fixed.
/// A wrapper around [HttpServer] that swallows errors caused by requests
diff --git a/sdk/lib/_internal/pub/lib/src/solver/version_solver.dart b/sdk/lib/_internal/pub/lib/src/solver/version_solver.dart
index 7b6713b..9a98698 100644
--- a/sdk/lib/_internal/pub/lib/src/solver/version_solver.dart
+++ b/sdk/lib/_internal/pub/lib/src/solver/version_solver.dart
@@ -27,12 +27,12 @@
/// packages.
Future<SolveResult> resolveVersions(SourceRegistry sources, Package root,
{LockFile lockFile, List<String> useLatest}) {
- log.message('Resolving dependencies...');
-
if (lockFile == null) lockFile = new LockFile.empty();
if (useLatest == null) useLatest = [];
- return new BacktrackingSolver(sources, root, lockFile, useLatest).solve();
+ return log.progress('Resolving dependencies', () {
+ return new BacktrackingSolver(sources, root, lockFile, useLatest).solve();
+ });
}
/// The result of a version resolution.
@@ -176,29 +176,6 @@
SolveFailure(this.package, Iterable<Dependency> dependencies)
: dependencies = dependencies != null ? dependencies : <Dependency>[];
- /// Writes [dependencies] to [buffer] as a bullet list. If [describe] is
- /// passed, it will be called for each dependency and the result will be
- /// written next to the dependency.
- void writeDependencies(StringBuffer buffer,
- [String describe(PackageDep dep)]) {
- var map = {};
- for (var dep in dependencies) {
- map[dep.depender] = dep.dep;
- }
-
- var names = map.keys.toList();
- names.sort();
-
- for (var name in names) {
- buffer.writeln("- '$name' ");
- if (describe != null) {
- buffer.writeln(describe(map[name]));
- } else {
- buffer.writeln("depends on version ${map[name].constraint}");
- }
- }
- }
-
String toString() {
if (dependencies.isEmpty) return _message;
@@ -213,9 +190,8 @@
var names = map.keys.toList();
names.sort();
- for (var name in names) {
- buffer.writeln("- '$name' ${_describeDependency(map[name])}");
- }
+ buffer.writeAll(names.map(
+ (name) => "- '$name' ${_describeDependency(map[name])}"), '\n');
return buffer.toString();
}
diff --git a/sdk/lib/_internal/pub/lib/src/utils.dart b/sdk/lib/_internal/pub/lib/src/utils.dart
index 0311c9d..b3ae863 100644
--- a/sdk/lib/_internal/pub/lib/src/utils.dart
+++ b/sdk/lib/_internal/pub/lib/src/utils.dart
@@ -6,13 +6,12 @@
library utils;
import 'dart:async';
-import 'dart:crypto';
import 'dart:io';
import 'dart:isolate';
import 'dart:json' as json;
import 'dart:mirrors';
-import 'dart:uri';
+import "package:crypto/crypto.dart";
import 'package:pathos/path.dart' as path;
/// A pair of values.
@@ -321,8 +320,9 @@
String mapToQuery(Map<String, String> map) {
var pairs = <List<String>>[];
map.forEach((key, value) {
- key = encodeUriComponent(key);
- value = (value == null || value.isEmpty) ? null : encodeUriComponent(value);
+ key = Uri.encodeQueryComponent(key);
+ value = (value == null || value.isEmpty)
+ ? null : Uri.encodeQueryComponent(value);
pairs.add([key, value]);
});
return pairs.map((pair) {
@@ -339,13 +339,6 @@
/// Return [uri] with redundant port information removed.
Uri canonicalizeUri(Uri uri) {
- if (uri == null) return null;
-
- var sansPort = new Uri.fromComponents(
- scheme: uri.scheme, userInfo: uri.userInfo, domain: uri.domain,
- path: uri.path, query: uri.query, fragment: uri.fragment);
- if (uri.scheme == 'http' && uri.port == 80) return sansPort;
- if (uri.scheme == 'https' && uri.port == 443) return sansPort;
return uri;
}
@@ -354,10 +347,10 @@
void mapAddAll(Map destination, Map source) =>
source.forEach((key, value) => destination[key] = value);
-/// Decodes a URL-encoded string. Unlike [decodeUriComponent], this includes
+/// Decodes a URL-encoded string. Unlike [Uri.decodeComponent], this includes
/// replacing `+` with ` `.
String urlDecode(String encoded) =>
- decodeUriComponent(encoded.replaceAll("+", " "));
+ Uri.decodeComponent(encoded.replaceAll("+", " "));
/// Takes a simple data structure (composed of [Map]s, [Iterable]s, scalar
/// objects, and [Future]s) and recursively resolves all the [Future]s contained
@@ -472,8 +465,8 @@
// TODO(nweiz): Serialize using the YAML library once it supports
// serialization.
- // Use indentation for maps.
- if (data is Map) {
+ // Use indentation for (non-empty) maps.
+ if (data is Map && !data.isEmpty) {
if (isMapValue) {
buffer.writeln();
indent += ' ';
diff --git a/sdk/lib/_internal/pub/test/deploy/copies_dart_js_next_to_entrypoints_test.dart b/sdk/lib/_internal/pub/test/deploy/copies_dart_js_next_to_entrypoints_test.dart
index d95b3d9..7eecff3 100644
--- a/sdk/lib/_internal/pub/test/deploy/copies_dart_js_next_to_entrypoints_test.dart
+++ b/sdk/lib/_internal/pub/test/deploy/copies_dart_js_next_to_entrypoints_test.dart
@@ -45,8 +45,7 @@
])
]).create();
- schedulePub(args: ["install"],
- output: new RegExp(r"Dependencies installed!$"));
+ pubInstall();
schedulePub(args: ["deploy"],
output: '''
diff --git a/sdk/lib/_internal/pub/test/dev_dependency_test.dart b/sdk/lib/_internal/pub/test/dev_dependency_test.dart
index 1e37807..88df801 100644
--- a/sdk/lib/_internal/pub/test/dev_dependency_test.dart
+++ b/sdk/lib/_internal/pub/test/dev_dependency_test.dart
@@ -30,8 +30,7 @@
})
]).create();
- schedulePub(args: ["install"],
- output: new RegExp(r"Dependencies installed!$"));
+ pubInstall();
d.dir(packagesPath, [
d.dir("foo", [
@@ -65,8 +64,7 @@
})
]).create();
- schedulePub(args: ["install"],
- output: new RegExp(r"Dependencies installed!$"));
+ pubInstall();
d.dir(packagesPath, [
d.dir("foo", [
@@ -104,8 +102,7 @@
})
]).create();
- schedulePub(args: ["install"],
- output: new RegExp(r"Dependencies installed!$"));
+ pubInstall();
d.dir(packagesPath, [
d.dir("foo", [
diff --git a/sdk/lib/_internal/pub/test/error_group_test.dart b/sdk/lib/_internal/pub/test/error_group_test.dart
index ff2f699..d22f12c 100644
--- a/sdk/lib/_internal/pub/test/error_group_test.dart
+++ b/sdk/lib/_internal/pub/test/error_group_test.dart
@@ -210,8 +210,16 @@
});
test('should pass through values from the stream', () {
- expect(stream.elementAt(0), completion(equals(1)));
- expect(stream.elementAt(1), completion(equals(2)));
+ StreamIterator iter = new StreamIterator(stream);
+ iter.moveNext().then((hasNext) {
+ expect(hasNext, isTrue);
+ expect(iter.current, equals(1));
+ iter.moveNext().then((hasNext) {
+ expect(hasNext, isTrue);
+ expect(iter.current, equals(2));
+ expect(iter.moveNext(), completion(isFalse));
+ });
+ });
expect(errorGroup.done, completes);
controller..add(1)..add(2)..close();
@@ -232,15 +240,14 @@
});
test('should pass a signaled exception to the stream if it has a listener '
- 'and should unsubscribe that stream', () {
- expect(stream.first, throwsFormatException);
+ 'and should unsubscribe that stream', () {
// errorGroup shouldn't top-level the exception
+ expect(stream.first, throwsFormatException);
errorGroup.signalError(new FormatException());
- expect(stream.first.catchError((_) {
+ expect(new Future(() {
controller.add('value');
- return stream.isEmpty;
- }), completion(isTrue));
+ }), completes);
});
test('should notify the error group of a signaled exception even if the '
@@ -345,10 +352,12 @@
test("shouldn't throw a top-level exception if a stream receives an error "
"after the other listened stream completes", () {
- expect(stream1.toList(), completion(equals(['value1', 'value2'])));
+ var signal = new Completer();
+ expect(stream1.toList().whenComplete(signal.complete),
+ completion(equals(['value1', 'value2'])));
controller1..add('value1')..add('value2')..close();
- expect(stream1.toList().then((_) {
+ expect(signal.future.then((_) {
// shouldn't cause a top-level exception
controller2.addError(new FormatException());
}), completes);
@@ -356,10 +365,12 @@
test("shouldn't throw a top-level exception if an error is signaled after "
"one listened stream completes", () {
- expect(stream1.toList(), completion(equals(['value1', 'value2'])));
+ var signal = new Completer();
+ expect(stream1.toList().whenComplete(signal.complete),
+ completion(equals(['value1', 'value2'])));
controller1..add('value1')..add('value2')..close();
- expect(stream1.toList().then((_) {
+ expect(signal.future.then((_) {
// shouldn't cause a top-level exception
errorGroup.signalError(new FormatException());
}), completes);
@@ -419,10 +430,12 @@
test("shouldn't throw a top-level exception if the future receives an "
"error after the listened stream completes", () {
- expect(stream.toList(), completion(equals(['value1', 'value2'])));
+ var signal = new Completer();
+ expect(stream.toList().whenComplete(signal.complete),
+ completion(equals(['value1', 'value2'])));
controller..add('value1')..add('value2')..close();
- expect(stream.toList().then((_) {
+ expect(signal.future.then((_) {
// shouldn't cause a top-level exception
completer.completeError(new FormatException());
}), completes);
diff --git a/sdk/lib/_internal/pub/test/hosted/fail_gracefully_on_missing_package_test.dart b/sdk/lib/_internal/pub/test/hosted/fail_gracefully_on_missing_package_test.dart
index 675e52e..5d79470 100644
--- a/sdk/lib/_internal/pub/test/hosted/fail_gracefully_on_missing_package_test.dart
+++ b/sdk/lib/_internal/pub/test/hosted/fail_gracefully_on_missing_package_test.dart
@@ -18,8 +18,8 @@
d.appDir([dependencyMap("foo", "1.2.3")]).create();
- pubCommand(command, error:
- new RegExp('Could not find package "foo" at http://localhost:'));
+ pubCommand(command, error: new RegExp(
+ r'Could not find package "foo" at http://localhost:\d+\.$'));
});
});
}
diff --git a/sdk/lib/_internal/pub/test/hosted/fail_gracefully_on_url_resolve_test.dart b/sdk/lib/_internal/pub/test/hosted/fail_gracefully_on_url_resolve_test.dart
index 49742d3..f6f4628 100644
--- a/sdk/lib/_internal/pub/test/hosted/fail_gracefully_on_url_resolve_test.dart
+++ b/sdk/lib/_internal/pub/test/hosted/fail_gracefully_on_url_resolve_test.dart
@@ -28,8 +28,7 @@
})
]).create();
- pubCommand(command, error:
- new RegExp('Could not resolve URL "http://pub.invalid".'));
+ pubCommand(command, error: 'Could not resolve URL "http://pub.invalid".');
});
});
}
diff --git a/sdk/lib/_internal/pub/test/hosted/offline_test.dart b/sdk/lib/_internal/pub/test/hosted/offline_test.dart
index eaca7f2..3019a6b 100644
--- a/sdk/lib/_internal/pub/test/hosted/offline_test.dart
+++ b/sdk/lib/_internal/pub/test/hosted/offline_test.dart
@@ -50,7 +50,7 @@
]).create();
pubCommand(command, args: ['--offline'],
- error: new RegExp('Could not find package "foo" in cache'));
+ error: 'Could not find package "foo" in cache.');
});
integration('fails gracefully no cached versions match', () {
@@ -65,8 +65,9 @@
dependencyMap("foo", ">2.0.0")
]).create();
- pubCommand(command, args: ['--offline'],
- error: new RegExp("Package 'foo' has no versions that match >2.0.0"));
+ pubCommand(command, args: ['--offline'], error:
+ "Package 'foo' has no versions that match >2.0.0 derived from:\n"
+ "- 'myapp' depends on version >2.0.0");
});
});
}
diff --git a/sdk/lib/_internal/pub/test/install/broken_symlink_test.dart b/sdk/lib/_internal/pub/test/install/broken_symlink_test.dart
index 7b627b2..2d9e551 100644
--- a/sdk/lib/_internal/pub/test/install/broken_symlink_test.dart
+++ b/sdk/lib/_internal/pub/test/install/broken_symlink_test.dart
@@ -23,8 +23,7 @@
// Create a broken "packages" symlink in "bin".
scheduleSymlink("nonexistent", path.join(appPath, "packages"));
- schedulePub(args: ['install'],
- output: new RegExp(r"Dependencies installed!$"));
+ pubInstall();
d.dir(appPath, [
d.dir("bin", [
@@ -47,8 +46,7 @@
// Create a broken "packages" symlink in "bin".
scheduleSymlink("nonexistent", path.join(appPath, "bin", "packages"));
- schedulePub(args: ['install'],
- output: new RegExp(r"Dependencies installed!$"));
+ pubInstall();
d.dir(appPath, [
d.dir("bin", [
diff --git a/sdk/lib/_internal/pub/test/install/git/check_out_and_update_test.dart b/sdk/lib/_internal/pub/test/install/git/check_out_and_update_test.dart
index 3af7fb7..b606972 100644
--- a/sdk/lib/_internal/pub/test/install/git/check_out_and_update_test.dart
+++ b/sdk/lib/_internal/pub/test/install/git/check_out_and_update_test.dart
@@ -21,8 +21,7 @@
d.appDir([{"git": "../foo.git"}]).create();
- schedulePub(args: ['install'],
- output: new RegExp(r"Dependencies installed!$"));
+ pubInstall();
d.dir(cachePath, [
d.dir('git', [
@@ -42,8 +41,7 @@
d.libPubspec('foo', '1.0.0')
]).commit();
- schedulePub(args: ['update'],
- output: new RegExp(r"Dependencies updated!$"));
+ pubUpdate();
// When we download a new version of the git package, we should re-use the
// git/cache directory but create a new git/ directory.
diff --git a/sdk/lib/_internal/pub/test/install/git/check_out_branch_test.dart b/sdk/lib/_internal/pub/test/install/git/check_out_branch_test.dart
index 2df0198..3e5aef0 100644
--- a/sdk/lib/_internal/pub/test/install/git/check_out_branch_test.dart
+++ b/sdk/lib/_internal/pub/test/install/git/check_out_branch_test.dart
@@ -28,8 +28,7 @@
d.appDir([{"git": {"url": "../foo.git", "ref": "old"}}]).create();
- schedulePub(args: ['install'],
- output: new RegExp(r"Dependencies installed!$"));
+ pubInstall();
d.dir(packagesPath, [
d.dir('foo', [
diff --git a/sdk/lib/_internal/pub/test/install/git/check_out_revision_test.dart b/sdk/lib/_internal/pub/test/install/git/check_out_revision_test.dart
index b763dd4..cd1587a 100644
--- a/sdk/lib/_internal/pub/test/install/git/check_out_revision_test.dart
+++ b/sdk/lib/_internal/pub/test/install/git/check_out_revision_test.dart
@@ -28,8 +28,7 @@
d.appDir([{"git": {"url": "../foo.git", "ref": commit}}]).create();
- schedulePub(args: ['install'],
- output: new RegExp(r"Dependencies installed!$"));
+ pubInstall();
d.dir(packagesPath, [
d.dir('foo', [
diff --git a/sdk/lib/_internal/pub/test/install/git/check_out_test.dart b/sdk/lib/_internal/pub/test/install/git/check_out_test.dart
index c2a4f68..9c36368 100644
--- a/sdk/lib/_internal/pub/test/install/git/check_out_test.dart
+++ b/sdk/lib/_internal/pub/test/install/git/check_out_test.dart
@@ -21,8 +21,7 @@
d.appDir([{"git": "../foo.git"}]).create();
- schedulePub(args: ['install'],
- output: new RegExp(r"Dependencies installed!$"));
+ pubInstall();
d.dir(cachePath, [
d.dir('git', [
diff --git a/sdk/lib/_internal/pub/test/install/git/check_out_transitive_test.dart b/sdk/lib/_internal/pub/test/install/git/check_out_transitive_test.dart
index d68763c..d07b3e2 100644
--- a/sdk/lib/_internal/pub/test/install/git/check_out_transitive_test.dart
+++ b/sdk/lib/_internal/pub/test/install/git/check_out_transitive_test.dart
@@ -26,8 +26,7 @@
d.appDir([{"git": "../foo.git"}]).create();
- schedulePub(args: ['install'],
- output: new RegExp("Dependencies installed!\$"));
+ pubInstall();
d.dir(cachePath, [
d.dir('git', [
diff --git a/sdk/lib/_internal/pub/test/install/git/check_out_twice_test.dart b/sdk/lib/_internal/pub/test/install/git/check_out_twice_test.dart
index 87d9a94..2aef954 100644
--- a/sdk/lib/_internal/pub/test/install/git/check_out_twice_test.dart
+++ b/sdk/lib/_internal/pub/test/install/git/check_out_twice_test.dart
@@ -21,8 +21,7 @@
d.appDir([{"git": "../foo.git"}]).create();
- schedulePub(args: ['install'],
- output: new RegExp(r"Dependencies installed!$"));
+ pubInstall();
d.dir(cachePath, [
d.dir('git', [
@@ -39,7 +38,6 @@
// Verify that nothing breaks if we install a Git revision that's already
// in the cache.
- schedulePub(args: ['update'],
- output: new RegExp(r"Dependencies updated!$"));
+ pubUpdate();
});
}
diff --git a/sdk/lib/_internal/pub/test/install/git/check_out_with_trailing_slash_test.dart b/sdk/lib/_internal/pub/test/install/git/check_out_with_trailing_slash_test.dart
index e414483..5162b2f 100644
--- a/sdk/lib/_internal/pub/test/install/git/check_out_with_trailing_slash_test.dart
+++ b/sdk/lib/_internal/pub/test/install/git/check_out_with_trailing_slash_test.dart
@@ -24,8 +24,7 @@
d.appDir([{"git": "../foo.git/"}]).create();
- schedulePub(args: ['install'],
- output: new RegExp(r"Dependencies installed!$"));
+ pubInstall();
d.dir(cachePath, [
d.dir('git', [
diff --git a/sdk/lib/_internal/pub/test/install/git/dependency_name_match_pubspec_test.dart b/sdk/lib/_internal/pub/test/install/git/dependency_name_match_pubspec_test.dart
index c1e5572..c6f89ee 100644
--- a/sdk/lib/_internal/pub/test/install/git/dependency_name_match_pubspec_test.dart
+++ b/sdk/lib/_internal/pub/test/install/git/dependency_name_match_pubspec_test.dart
@@ -29,12 +29,8 @@
})
]).create();
- // TODO(nweiz): clean up this RegExp when either issue 4706 or 4707 is
- // fixed.
- schedulePub(args: ['install'],
- error: new RegExp(r'^The name you specified for your dependency, '
- '"weirdname", doesn\'t match the name "foo" in its '
- r'pubspec\.'),
- exitCode: 1);
+ pubInstall(error:
+ 'The name you specified for your dependency, "weirdname", doesn\'t '
+ 'match the name "foo" in its pubspec.');
});
}
diff --git a/sdk/lib/_internal/pub/test/install/git/different_repo_name_test.dart b/sdk/lib/_internal/pub/test/install/git/different_repo_name_test.dart
index 3e5378c..0203f9b 100644
--- a/sdk/lib/_internal/pub/test/install/git/different_repo_name_test.dart
+++ b/sdk/lib/_internal/pub/test/install/git/different_repo_name_test.dart
@@ -29,8 +29,7 @@
})
]).create();
- schedulePub(args: ['install'],
- output: new RegExp(r"Dependencies installed!$"));
+ pubInstall();
d.dir(packagesPath, [
d.dir('weirdname', [
diff --git a/sdk/lib/_internal/pub/test/install/git/lock_version_test.dart b/sdk/lib/_internal/pub/test/install/git/lock_version_test.dart
index ed4994b..8eb7087 100644
--- a/sdk/lib/_internal/pub/test/install/git/lock_version_test.dart
+++ b/sdk/lib/_internal/pub/test/install/git/lock_version_test.dart
@@ -26,8 +26,7 @@
d.appDir([{"git": "../foo.git"}]).create();
// This install should lock the foo.git dependency to the current revision.
- schedulePub(args: ['install'],
- output: new RegExp(r"Dependencies installed!$"));
+ pubInstall();
d.dir(packagesPath, [
d.dir('foo', [
@@ -44,8 +43,7 @@
]).commit();
// This install shouldn't update the foo.git dependency due to the lockfile.
- schedulePub(args: ['install'],
- output: new RegExp(r"Dependencies installed!$"));
+ pubInstall();
d.dir(packagesPath, [
d.dir('foo', [
diff --git a/sdk/lib/_internal/pub/test/install/git/require_pubspec_name_test.dart b/sdk/lib/_internal/pub/test/install/git/require_pubspec_name_test.dart
index aad6a52..eafd067 100644
--- a/sdk/lib/_internal/pub/test/install/git/require_pubspec_name_test.dart
+++ b/sdk/lib/_internal/pub/test/install/git/require_pubspec_name_test.dart
@@ -24,9 +24,8 @@
// TODO(nweiz): clean up this RegExp when either issue 4706 or 4707 is
// fixed.
- schedulePub(args: ['install'],
- error: new RegExp(r'^Package "foo"' "'" 's pubspec.yaml file is '
- r'missing the required "name" field \(e\.g\. "name: foo"\)\.'),
- exitCode: 1);
+ pubInstall(error:
+ 'Package "foo"\'s pubspec.yaml file is '
+ 'missing the required "name" field (e.g. "name: foo").');
});
}
diff --git a/sdk/lib/_internal/pub/test/install/git/require_pubspec_test.dart b/sdk/lib/_internal/pub/test/install/git/require_pubspec_test.dart
index ad1a22d..ba2b5c6 100644
--- a/sdk/lib/_internal/pub/test/install/git/require_pubspec_test.dart
+++ b/sdk/lib/_internal/pub/test/install/git/require_pubspec_test.dart
@@ -22,9 +22,6 @@
// TODO(nweiz): clean up this RegExp when either issue 4706 or 4707 is
// fixed.
- schedulePub(args: ['install'],
- error: new RegExp('^Package "foo" doesn\'t have a '
- 'pubspec.yaml file.'),
- exitCode: 1);
+ pubInstall(error: 'Package "foo" doesn\'t have a pubspec.yaml file.');
});
}
diff --git a/sdk/lib/_internal/pub/test/install/git/stay_locked_if_compatible_test.dart b/sdk/lib/_internal/pub/test/install/git/stay_locked_if_compatible_test.dart
index 8bc5025..f59b93b 100644
--- a/sdk/lib/_internal/pub/test/install/git/stay_locked_if_compatible_test.dart
+++ b/sdk/lib/_internal/pub/test/install/git/stay_locked_if_compatible_test.dart
@@ -22,8 +22,7 @@
d.appDir([{"git": "../foo.git"}]).create();
- schedulePub(args: ['install'],
- output: new RegExp(r"Dependencies installed!$"));
+ pubInstall();
d.dir(packagesPath, [
d.dir('foo', [
@@ -38,8 +37,7 @@
d.appDir([{"git": "../foo.git", "version": ">=1.0.0"}]).create();
- schedulePub(args: ['install'],
- output: new RegExp(r"Dependencies installed!$"));
+ pubInstall();
d.dir(packagesPath, [
d.dir('foo', [
diff --git a/sdk/lib/_internal/pub/test/install/git/unlock_if_incompatible_test.dart b/sdk/lib/_internal/pub/test/install/git/unlock_if_incompatible_test.dart
index 1b23fba..644650b 100644
--- a/sdk/lib/_internal/pub/test/install/git/unlock_if_incompatible_test.dart
+++ b/sdk/lib/_internal/pub/test/install/git/unlock_if_incompatible_test.dart
@@ -22,8 +22,7 @@
d.appDir([{"git": "../foo.git"}]).create();
- schedulePub(args: ['install'],
- output: new RegExp(r"Dependencies installed!$"));
+ pubInstall();
d.dir(packagesPath, [
d.dir('foo', [
@@ -38,8 +37,7 @@
d.appDir([{"git": "../foo.git", "version": ">=1.0.0"}]).create();
- schedulePub(args: ['install'],
- output: new RegExp(r"Dependencies installed!$"));
+ pubInstall();
d.dir(packagesPath, [
d.dir('foo', [
diff --git a/sdk/lib/_internal/pub/test/install/hosted/cached_pubspec_test.dart b/sdk/lib/_internal/pub/test/install/hosted/cached_pubspec_test.dart
index 153431a..5949d4b 100644
--- a/sdk/lib/_internal/pub/test/install/hosted/cached_pubspec_test.dart
+++ b/sdk/lib/_internal/pub/test/install/hosted/cached_pubspec_test.dart
@@ -20,8 +20,7 @@
d.appDir([dependencyMap("foo", "1.2.3")]).create();
// Run install once so it gets cached.
- schedulePub(args: ['install'],
- output: new RegExp("Dependencies installed!\$"));
+ pubInstall();
// Clear the cache. We don't care about anything that was served during
// the initial install.
@@ -31,8 +30,7 @@
d.packagesDir({"foo": "1.2.3"}).validate();
// Run the solver again now that it's cached.
- schedulePub(args: ['install'],
- output: new RegExp("Dependencies installed!\$"));
+ pubInstall();
// The update should not have requested the pubspec since it's installed
// locally already.
diff --git a/sdk/lib/_internal/pub/test/install/hosted/do_not_update_on_removed_constraints_test.dart b/sdk/lib/_internal/pub/test/install/hosted/do_not_update_on_removed_constraints_test.dart
index 539d263..9184b83 100644
--- a/sdk/lib/_internal/pub/test/install/hosted/do_not_update_on_removed_constraints_test.dart
+++ b/sdk/lib/_internal/pub/test/install/hosted/do_not_update_on_removed_constraints_test.dart
@@ -22,8 +22,7 @@
d.appDir([dependencyMap("foo"), dependencyMap("bar")]).create();
- schedulePub(args: ['install'],
- output: new RegExp(r"Dependencies installed!$"));
+ pubInstall();
d.packagesDir({
"foo": "1.0.0",
@@ -33,8 +32,7 @@
d.appDir([dependencyMap("foo")]).create();
- schedulePub(args: ['install'],
- output: new RegExp(r"Dependencies installed!$"));
+ pubInstall();
d.packagesDir({
"foo": "1.0.0",
diff --git a/sdk/lib/_internal/pub/test/install/hosted/install_test.dart b/sdk/lib/_internal/pub/test/install/hosted/install_test.dart
index 5db5553..375860a 100644
--- a/sdk/lib/_internal/pub/test/install/hosted/install_test.dart
+++ b/sdk/lib/_internal/pub/test/install/hosted/install_test.dart
@@ -16,8 +16,7 @@
d.appDir([dependencyMap("foo", "1.2.3")]).create();
- schedulePub(args: ['install'],
- output: new RegExp("Dependencies installed!\$"));
+ pubInstall();
d.cacheDir({"foo": "1.2.3"}).validate();
d.packagesDir({"foo": "1.2.3"}).validate();
@@ -28,9 +27,7 @@
d.appDir([dependencyMap("bad name!", "1.2.3")]).create();
- schedulePub(args: ['install'],
- error: new RegExp('Could not find package "bad name!" at '
- 'http://localhost:'),
- exitCode: 1);
+ pubInstall(error: new RegExp(
+ r'Could not find package "bad name!" at http://localhost:\d+\.$'));
});
}
diff --git a/sdk/lib/_internal/pub/test/install/hosted/install_transitive_test.dart b/sdk/lib/_internal/pub/test/install/hosted/install_transitive_test.dart
index 7da990f5..e474897 100644
--- a/sdk/lib/_internal/pub/test/install/hosted/install_transitive_test.dart
+++ b/sdk/lib/_internal/pub/test/install/hosted/install_transitive_test.dart
@@ -21,8 +21,7 @@
d.appDir([dependencyMap("foo", "1.2.3")]).create();
- schedulePub(args: ['install'],
- output: new RegExp("Dependencies installed!\$"));
+ pubInstall();
d.cacheDir({"foo": "1.2.3", "bar": "2.0.4"}).validate();
d.packagesDir({"foo": "1.2.3", "bar": "2.0.4"}).validate();
diff --git a/sdk/lib/_internal/pub/test/install/hosted/repair_cache_test.dart b/sdk/lib/_internal/pub/test/install/hosted/repair_cache_test.dart
index a343cc4..94874ad 100644
--- a/sdk/lib/_internal/pub/test/install/hosted/repair_cache_test.dart
+++ b/sdk/lib/_internal/pub/test/install/hosted/repair_cache_test.dart
@@ -30,8 +30,7 @@
d.appDir([dependencyMap("foo", "1.2.3")]).create();
- schedulePub(args: ['install'],
- output: new RegExp("Dependencies installed!\$"));
+ pubInstall();
d.cacheDir({"foo": "1.2.3"}).validate();
d.packagesDir({"foo": "1.2.3"}).validate();
@@ -54,8 +53,7 @@
d.appDir([dependencyMap("foo", "1.2.3")]).create();
- schedulePub(args: ['install'],
- output: new RegExp("Dependencies installed!\$"));
+ pubInstall();
d.cacheDir({"foo": "1.2.3"}).validate();
d.packagesDir({"foo": "1.2.3"}).validate();
diff --git a/sdk/lib/_internal/pub/test/install/hosted/resolve_constraints_test.dart b/sdk/lib/_internal/pub/test/install/hosted/resolve_constraints_test.dart
index 0da297a..522f21a 100644
--- a/sdk/lib/_internal/pub/test/install/hosted/resolve_constraints_test.dart
+++ b/sdk/lib/_internal/pub/test/install/hosted/resolve_constraints_test.dart
@@ -22,8 +22,7 @@
d.appDir([dependencyMap("foo"), dependencyMap("bar")]).create();
- schedulePub(args: ['install'],
- output: new RegExp("Dependencies installed!\$"));
+ pubInstall();
d.cacheDir({
"foo": "1.2.3",
diff --git a/sdk/lib/_internal/pub/test/install/hosted/stay_locked_if_compatible_test.dart b/sdk/lib/_internal/pub/test/install/hosted/stay_locked_if_compatible_test.dart
index 7c08ab5..dfe1b50 100644
--- a/sdk/lib/_internal/pub/test/install/hosted/stay_locked_if_compatible_test.dart
+++ b/sdk/lib/_internal/pub/test/install/hosted/stay_locked_if_compatible_test.dart
@@ -17,8 +17,7 @@
d.appDir([dependencyMap("foo")]).create();
- schedulePub(args: ['install'],
- output: new RegExp(r"Dependencies installed!$"));
+ pubInstall();
d.packagesDir({"foo": "1.0.0"}).validate();
@@ -26,8 +25,7 @@
d.appDir([dependencyMap("foo", ">=1.0.0")]).create();
- schedulePub(args: ['install'],
- output: new RegExp(r"Dependencies installed!$"));
+ pubInstall();
d.packagesDir({"foo": "1.0.0"}).validate();
});
diff --git a/sdk/lib/_internal/pub/test/install/hosted/stay_locked_if_new_is_satisfied_test.dart b/sdk/lib/_internal/pub/test/install/hosted/stay_locked_if_new_is_satisfied_test.dart
index fd2f244..1f57d92 100644
--- a/sdk/lib/_internal/pub/test/install/hosted/stay_locked_if_new_is_satisfied_test.dart
+++ b/sdk/lib/_internal/pub/test/install/hosted/stay_locked_if_new_is_satisfied_test.dart
@@ -21,8 +21,7 @@
d.appDir([dependencyMap("foo")]).create();
- schedulePub(args: ['install'],
- output: new RegExp(r"Dependencies installed!$"));
+ pubInstall();
d.packagesDir({
"foo": "1.0.0",
@@ -39,8 +38,7 @@
d.appDir([dependencyMap("foo"), dependencyMap("newdep")]).create();
- schedulePub(args: ['install'],
- output: new RegExp(r"Dependencies installed!$"));
+ pubInstall();
d.packagesDir({
"foo": "1.0.0",
diff --git a/sdk/lib/_internal/pub/test/install/hosted/stay_locked_test.dart b/sdk/lib/_internal/pub/test/install/hosted/stay_locked_test.dart
index 188012e..4cbafe3 100644
--- a/sdk/lib/_internal/pub/test/install/hosted/stay_locked_test.dart
+++ b/sdk/lib/_internal/pub/test/install/hosted/stay_locked_test.dart
@@ -22,8 +22,7 @@
d.appDir([dependencyMap("foo")]).create();
// This install should lock the foo dependency to version 1.0.0.
- schedulePub(args: ['install'],
- output: new RegExp(r"Dependencies installed!$"));
+ pubInstall();
d.packagesDir({"foo": "1.0.0"}).validate();
@@ -34,8 +33,7 @@
servePackages([packageMap("foo", "1.0.1")]);
// This install shouldn't update the foo dependency due to the lockfile.
- schedulePub(args: ['install'],
- output: new RegExp(r"Dependencies installed!$"));
+ pubInstall();
d.packagesDir({"foo": "1.0.0"}).validate();
});
diff --git a/sdk/lib/_internal/pub/test/install/hosted/unlock_if_incompatible_test.dart b/sdk/lib/_internal/pub/test/install/hosted/unlock_if_incompatible_test.dart
index 082a36c..348a400 100644
--- a/sdk/lib/_internal/pub/test/install/hosted/unlock_if_incompatible_test.dart
+++ b/sdk/lib/_internal/pub/test/install/hosted/unlock_if_incompatible_test.dart
@@ -17,17 +17,13 @@
d.appDir([dependencyMap("foo")]).create();
- schedulePub(args: ['install'],
- output: new RegExp(r"Dependencies installed!$"));
+ pubInstall();
d.packagesDir({"foo": "1.0.0"}).validate();
-
servePackages([packageMap("foo", "1.0.1")]);
-
d.appDir([dependencyMap("foo", ">1.0.0")]).create();
- schedulePub(args: ['install'],
- output: new RegExp(r"Dependencies installed!$"));
+ pubInstall();
d.packagesDir({"foo": "1.0.1"}).validate();
});
diff --git a/sdk/lib/_internal/pub/test/install/hosted/unlock_if_new_is_unsatisfied_test.dart b/sdk/lib/_internal/pub/test/install/hosted/unlock_if_new_is_unsatisfied_test.dart
index 44ecb89..a80bc58 100644
--- a/sdk/lib/_internal/pub/test/install/hosted/unlock_if_new_is_unsatisfied_test.dart
+++ b/sdk/lib/_internal/pub/test/install/hosted/unlock_if_new_is_unsatisfied_test.dart
@@ -22,8 +22,7 @@
d.appDir([dependencyMap("foo")]).create();
- schedulePub(args: ['install'],
- output: new RegExp(r"Dependencies installed!$"));
+ pubInstall();
d.packagesDir({
"foo": "1.0.0",
@@ -42,8 +41,7 @@
d.appDir([dependencyMap("foo"), dependencyMap("newdep")]).create();
- schedulePub(args: ['install'],
- output: new RegExp(r"Dependencies installed!$"));
+ pubInstall();
d.packagesDir({
"foo": "2.0.0",
diff --git a/sdk/lib/_internal/pub/test/install/path/absolute_path_test.dart b/sdk/lib/_internal/pub/test/install/path/absolute_path_test.dart
index 9d12d16..42b2636 100644
--- a/sdk/lib/_internal/pub/test/install/path/absolute_path_test.dart
+++ b/sdk/lib/_internal/pub/test/install/path/absolute_path_test.dart
@@ -26,8 +26,7 @@
})
]).create();
- schedulePub(args: ["install"],
- output: new RegExp(r"Dependencies installed!$"));
+ pubInstall();
d.dir(packagesPath, [
d.dir("foo", [
diff --git a/sdk/lib/_internal/pub/test/install/path/absolute_symlink_test.dart b/sdk/lib/_internal/pub/test/install/path/absolute_symlink_test.dart
index 4e4b196..83724c3 100644
--- a/sdk/lib/_internal/pub/test/install/path/absolute_symlink_test.dart
+++ b/sdk/lib/_internal/pub/test/install/path/absolute_symlink_test.dart
@@ -26,8 +26,7 @@
})
]).create();
- schedulePub(args: ["install"],
- output: new RegExp(r"Dependencies installed!$"));
+ pubInstall();
d.dir("moved").create();
diff --git a/sdk/lib/_internal/pub/test/install/path/no_pubspec_test.dart b/sdk/lib/_internal/pub/test/install/path/no_pubspec_test.dart
index 4553861..61789ad 100644
--- a/sdk/lib/_internal/pub/test/install/path/no_pubspec_test.dart
+++ b/sdk/lib/_internal/pub/test/install/path/no_pubspec_test.dart
@@ -26,8 +26,6 @@
})
]).create();
- schedulePub(args: ['install'],
- error: new RegExp('Package "foo" doesn\'t have a pubspec.yaml file.'),
- exitCode: 1);
+ pubInstall(error: 'Package "foo" doesn\'t have a pubspec.yaml file.');
});
}
\ No newline at end of file
diff --git a/sdk/lib/_internal/pub/test/install/path/nonexistent_dir_test.dart b/sdk/lib/_internal/pub/test/install/path/nonexistent_dir_test.dart
index 053c922..3564817 100644
--- a/sdk/lib/_internal/pub/test/install/path/nonexistent_dir_test.dart
+++ b/sdk/lib/_internal/pub/test/install/path/nonexistent_dir_test.dart
@@ -24,15 +24,6 @@
})
]).create();
- // TODO(rnystrom): The "\" in a Windows path gets treated like a regex
- // character, so hack escape. A better fix is to use a literal string
- // instead of a RegExp to validate, but that requires us to move the
- // stack traces out of the stderr when we invoke pub. See also: #4706.
- var escapePath = badPath.replaceAll(r"\", r"\\");
-
- schedulePub(args: ['install'],
- error:
- new RegExp("Could not find package 'foo' at '$escapePath'."),
- exitCode: 1);
+ pubInstall(error: "Could not find package 'foo' at '$badPath'.");
});
}
\ No newline at end of file
diff --git a/sdk/lib/_internal/pub/test/install/path/path_is_file_test.dart b/sdk/lib/_internal/pub/test/install/path/path_is_file_test.dart
index 7779467..dbbc0df 100644
--- a/sdk/lib/_internal/pub/test/install/path/path_is_file_test.dart
+++ b/sdk/lib/_internal/pub/test/install/path/path_is_file_test.dart
@@ -10,7 +10,7 @@
main() {
initConfig();
- integration('path dependency when path is a d.file', () {
+ integration('path dependency when path is a file', () {
d.dir('foo', [
d.libDir('foo'),
d.libPubspec('foo', '0.0.1')
@@ -28,15 +28,7 @@
})
]).create();
- // TODO(rnystrom): The "\" in a Windows path gets treated like a regex
- // character, so hack escape. A better fix is to use a literal string
- // instead of a RegExp to validate, but that requires us to move the
- // stack traces out of the stderr when we invoke pub. See also: #4706.
- var escapePath = dummyPath.replaceAll(r"\", r"\\");
-
- schedulePub(args: ['install'],
- error: new RegExp("Path dependency for package 'foo' must refer to a "
- "directory, not a file. Was '$escapePath'."),
- exitCode: 1);
+ pubInstall(error: "Path dependency for package 'foo' must refer to a "
+ "directory, not a file. Was '$dummyPath'.");
});
}
\ No newline at end of file
diff --git a/sdk/lib/_internal/pub/test/install/path/relative_path_test.dart b/sdk/lib/_internal/pub/test/install/path/relative_path_test.dart
index b9c9c31..5abaf09 100644
--- a/sdk/lib/_internal/pub/test/install/path/relative_path_test.dart
+++ b/sdk/lib/_internal/pub/test/install/path/relative_path_test.dart
@@ -25,8 +25,7 @@
})
]).create();
- schedulePub(args: ["install"],
- output: new RegExp(r"Dependencies installed!$"));
+ pubInstall();
d.dir(packagesPath, [
d.dir("foo", [
@@ -58,8 +57,7 @@
})
]).create();
- schedulePub(args: ["install"],
- output: new RegExp(r"Dependencies installed!$"));
+ pubInstall();
d.dir(packagesPath, [
d.dir("foo", [
diff --git a/sdk/lib/_internal/pub/test/install/path/relative_symlink_test.dart b/sdk/lib/_internal/pub/test/install/path/relative_symlink_test.dart
index 859f12c..97bd902 100644
--- a/sdk/lib/_internal/pub/test/install/path/relative_symlink_test.dart
+++ b/sdk/lib/_internal/pub/test/install/path/relative_symlink_test.dart
@@ -34,8 +34,7 @@
})
]).create();
- schedulePub(args: ["install"],
- output: new RegExp(r"Dependencies installed!$"));
+ pubInstall();
d.dir("moved").create();
diff --git a/sdk/lib/_internal/pub/test/install/path/shared_dependency_symlink_test.dart b/sdk/lib/_internal/pub/test/install/path/shared_dependency_symlink_test.dart
index d3b75da..bfb26dc 100644
--- a/sdk/lib/_internal/pub/test/install/path/shared_dependency_symlink_test.dart
+++ b/sdk/lib/_internal/pub/test/install/path/shared_dependency_symlink_test.dart
@@ -44,8 +44,7 @@
d.dir("link").create();
scheduleSymlink("shared", path.join("link", "shared"));
- schedulePub(args: ["install"],
- output: new RegExp(r"Dependencies installed!$"));
+ pubInstall();
d.dir(packagesPath, [
d.dir("foo", [d.file("foo.dart", 'main() => "foo";')]),
diff --git a/sdk/lib/_internal/pub/test/install/path/shared_dependency_test.dart b/sdk/lib/_internal/pub/test/install/path/shared_dependency_test.dart
index 65e7992..ee8a7c3 100644
--- a/sdk/lib/_internal/pub/test/install/path/shared_dependency_test.dart
+++ b/sdk/lib/_internal/pub/test/install/path/shared_dependency_test.dart
@@ -39,8 +39,7 @@
})
]).create();
- schedulePub(args: ["install"],
- output: new RegExp(r"Dependencies installed!$"));
+ pubInstall();
d.dir(packagesPath, [
d.dir("foo", [d.file("foo.dart", 'main() => "foo";')]),
@@ -79,8 +78,7 @@
})
]).create();
- schedulePub(args: ["install"],
- output: new RegExp(r"Dependencies installed!$"));
+ pubInstall();
d.dir(packagesPath, [
d.dir("foo", [d.file("foo.dart", 'main() => "foo";')]),
@@ -119,8 +117,7 @@
})
]).create();
- schedulePub(args: ["install"],
- output: new RegExp(r"Dependencies installed!$"));
+ pubInstall();
d.dir(packagesPath, [
d.dir("foo", [d.file("foo.dart", 'main() => "foo";')]),
diff --git a/sdk/lib/_internal/pub/test/install/relative_symlink_test.dart b/sdk/lib/_internal/pub/test/install/relative_symlink_test.dart
index aeb0a2a..deb2254 100644
--- a/sdk/lib/_internal/pub/test/install/relative_symlink_test.dart
+++ b/sdk/lib/_internal/pub/test/install/relative_symlink_test.dart
@@ -25,8 +25,7 @@
d.libDir('foo')
]).create();
- schedulePub(args: ['install'],
- output: new RegExp(r"Dependencies installed!$"));
+ pubInstall();
scheduleRename(appPath, "moved");
@@ -46,8 +45,7 @@
d.dir("bin")
]).create();
- schedulePub(args: ['install'],
- output: new RegExp(r"Dependencies installed!$"));
+ pubInstall();
scheduleRename(appPath, "moved");
diff --git a/sdk/lib/_internal/pub/test/install/switch_source_test.dart b/sdk/lib/_internal/pub/test/install/switch_source_test.dart
index db8864e..428292e 100644
--- a/sdk/lib/_internal/pub/test/install/switch_source_test.dart
+++ b/sdk/lib/_internal/pub/test/install/switch_source_test.dart
@@ -19,17 +19,13 @@
d.appDir([{"path": "../foo"}]).create();
- schedulePub(args: ['install'],
- output: new RegExp("Dependencies installed!\$"));
+ pubInstall();
d.packagesDir({"foo": "0.0.1"}).validate();
-
servePackages([packageMap("foo", "1.2.3")]);
-
d.appDir([dependencyMap("foo", "any")]).create();
- schedulePub(args: ['install'],
- output: new RegExp("Dependencies installed!\$"));
+ pubInstall();
d.packagesDir({"foo": "1.2.3"}).validate();
});
diff --git a/sdk/lib/_internal/pub/test/lish/archives_and_uploads_a_package_test.dart b/sdk/lib/_internal/pub/test/lish/archives_and_uploads_a_package_test.dart
index 4e65965..f1460b5 100644
--- a/sdk/lib/_internal/pub/test/lish/archives_and_uploads_a_package_test.dart
+++ b/sdk/lib/_internal/pub/test/lish/archives_and_uploads_a_package_test.dart
@@ -31,6 +31,8 @@
request.response.close();
});
+ expect(pub.nextLine(), completion(matches(r'Uploading\.\.\.+')));
+
expect(pub.nextLine(),
completion(equals('Package test_pkg 1.0.0 uploaded!')));
pub.shouldExit(0);
diff --git a/sdk/lib/_internal/pub/test/oauth2/utils.dart b/sdk/lib/_internal/pub/test/oauth2/utils.dart
index fa3ce98..7544506 100644
--- a/sdk/lib/_internal/pub/test/oauth2/utils.dart
+++ b/sdk/lib/_internal/pub/test/oauth2/utils.dart
@@ -6,7 +6,6 @@
import 'dart:io';
import 'dart:json' as json;
-import 'dart:uri';
import 'package:http/http.dart' as http;
import 'package:scheduled_test/scheduled_process.dart';
@@ -27,7 +26,7 @@
.firstMatch(line);
expect(match, isNotNull);
- var redirectUrl = Uri.parse(decodeUriComponent(match.group(1)));
+ var redirectUrl = Uri.parse(Uri.decodeComponent(match.group(1)));
redirectUrl = addQueryParameters(redirectUrl, {'code': 'access code'});
return (new http.Request('GET', redirectUrl)..followRedirects = false)
.send();
diff --git a/sdk/lib/_internal/pub/test/oauth2/with_a_server_rejected_refresh_token_authenticates_again_test.dart b/sdk/lib/_internal/pub/test/oauth2/with_a_server_rejected_refresh_token_authenticates_again_test.dart
index 154388b..1a103e9 100644
--- a/sdk/lib/_internal/pub/test/oauth2/with_a_server_rejected_refresh_token_authenticates_again_test.dart
+++ b/sdk/lib/_internal/pub/test/oauth2/with_a_server_rejected_refresh_token_authenticates_again_test.dart
@@ -28,6 +28,7 @@
.create();
var pub = startPublish(server);
+
confirmPublish(pub);
server.handle('POST', '/token', (request) {
@@ -41,6 +42,7 @@
});
});
+ expect(pub.nextLine(), completion(matches(r'Uploading\.\.\.+')));
authorizePub(pub, server, 'new access token');
server.handle('GET', '/packages/versions/new.json', (request) {
diff --git a/sdk/lib/_internal/pub/test/pub_install_and_update_test.dart b/sdk/lib/_internal/pub/test/pub_install_and_update_test.dart
index 1cbd5a3..d645071 100644
--- a/sdk/lib/_internal/pub/test/pub_install_and_update_test.dart
+++ b/sdk/lib/_internal/pub/test/pub_install_and_update_test.dart
@@ -20,7 +20,8 @@
d.dir(appPath, []).create();
pubCommand(command,
- error: new RegExp(r'^Could not find a file named "pubspec.yaml"'));
+ error: new RegExp(r'^Could not find a file named "pubspec.yaml" '
+ r'in the directory .*\.$'));
});
integration('a pubspec with a "name" key', () {
@@ -28,9 +29,9 @@
d.pubspec({"dependencies": {"foo": null}})
]).create();
- pubCommand(command, error: new RegExp(
- r'^pubspec.yaml is missing the required "name" field '
- r'\(e\.g\. "name: myapp"\)\.'));
+ pubCommand(command, error:
+ 'pubspec.yaml is missing the required "name" field '
+ '(e.g. "name: myapp").');
});
});
@@ -112,7 +113,7 @@
]).create();
pubCommand(command,
- error: new RegExp(r"^Incompatible dependencies on 'baz':"));
+ error: new RegExp("^Incompatible dependencies on 'baz':\n"));
});
});
}
diff --git a/sdk/lib/_internal/pub/test/test_pub.dart b/sdk/lib/_internal/pub/test/test_pub.dart
index 50f6343..1a784e7 100644
--- a/sdk/lib/_internal/pub/test/test_pub.dart
+++ b/sdk/lib/_internal/pub/test/test_pub.dart
@@ -13,7 +13,6 @@
import 'dart:io' hide sleep;
import 'dart:json' as json;
import 'dart:math';
-import 'dart:uri';
import 'dart:utf';
import 'package:http/testing.dart';
@@ -238,15 +237,13 @@
/// Enum identifying a pub command that can be run with a well-defined success
/// output.
class RunCommand {
- static final install = new RunCommand('install',
- new RegExp("Dependencies installed!\$"));
-
- static final update = new RunCommand('update',
- new RegExp("Dependencies updated!\$"));
+ static final install = new RunCommand('install', 'installed');
+ static final update = new RunCommand('update', 'updated');
final String name;
final RegExp success;
- RunCommand(this.name, this.success);
+ RunCommand(this.name, String verb)
+ : success = new RegExp("Dependencies $verb!\$");
}
/// Many tests validate behavior that is the same between pub install and
diff --git a/sdk/lib/_internal/pub/test/unknown_source_test.dart b/sdk/lib/_internal/pub/test/unknown_source_test.dart
index 6b0cde0..511b795 100644
--- a/sdk/lib/_internal/pub/test/unknown_source_test.dart
+++ b/sdk/lib/_internal/pub/test/unknown_source_test.dart
@@ -17,8 +17,8 @@
integration('fails gracefully on a dependency from an unknown source', () {
d.appDir([{"bad": "foo"}]).create();
- pubCommand(command, error: new RegExp(
- "Package 'myapp' depends on 'foo' from unknown source 'bad'.\$"));
+ pubCommand(command, error:
+ "Package 'myapp' depends on 'foo' from unknown source 'bad'.");
});
integration('fails gracefully on transitive dependency from an unknown '
@@ -30,8 +30,8 @@
d.appDir([{"path": "../foo"}]).create();
- pubCommand(command, error: new RegExp(
- "Package 'foo' depends on 'bar' from unknown source 'bad'.\$"));
+ pubCommand(command, error:
+ "Package 'foo' depends on 'bar' from unknown source 'bad'.");
});
integration('ignores unknown source in lockfile', () {
diff --git a/sdk/lib/_internal/pub/test/update/git/do_not_update_if_unneeded_test.dart b/sdk/lib/_internal/pub/test/update/git/do_not_update_if_unneeded_test.dart
index 512b619..d48899a 100644
--- a/sdk/lib/_internal/pub/test/update/git/do_not_update_if_unneeded_test.dart
+++ b/sdk/lib/_internal/pub/test/update/git/do_not_update_if_unneeded_test.dart
@@ -27,8 +27,7 @@
d.appDir([{"git": "../foo.git"}]).create();
- schedulePub(args: ['install'],
- output: new RegExp(r"Dependencies installed!$"));
+ pubInstall();
d.dir(packagesPath, [
d.dir('foo', [
@@ -49,8 +48,7 @@
d.libPubspec('foo-dep', '1.0.0')
]).commit();
- schedulePub(args: ['update', 'foo'],
- output: new RegExp(r"Dependencies updated!$"));
+ pubUpdate(args: ['foo']);
d.dir(packagesPath, [
d.dir('foo', [
diff --git a/sdk/lib/_internal/pub/test/update/git/update_locked_test.dart b/sdk/lib/_internal/pub/test/update/git/update_locked_test.dart
index 3ed68c5..c17f641 100644
--- a/sdk/lib/_internal/pub/test/update/git/update_locked_test.dart
+++ b/sdk/lib/_internal/pub/test/update/git/update_locked_test.dart
@@ -26,8 +26,7 @@
d.appDir([{"git": "../foo.git"}, {"git": "../bar.git"}]).create();
- schedulePub(args: ['install'],
- output: new RegExp(r"Dependencies installed!$"));
+ pubInstall();
d.dir(packagesPath, [
d.dir('foo', [
@@ -48,8 +47,7 @@
d.libPubspec('bar', '1.0.0')
]).commit();
- schedulePub(args: ['update'],
- output: new RegExp(r"Dependencies updated!$"));
+ pubUpdate();
d.dir(packagesPath, [
d.dir('foo', [
diff --git a/sdk/lib/_internal/pub/test/update/git/update_one_locked_test.dart b/sdk/lib/_internal/pub/test/update/git/update_one_locked_test.dart
index 976553e..35370e7 100644
--- a/sdk/lib/_internal/pub/test/update/git/update_one_locked_test.dart
+++ b/sdk/lib/_internal/pub/test/update/git/update_one_locked_test.dart
@@ -26,8 +26,7 @@
d.appDir([{"git": "../foo.git"}, {"git": "../bar.git"}]).create();
- schedulePub(args: ['install'],
- output: new RegExp(r"Dependencies installed!$"));
+ pubInstall();
d.dir(packagesPath, [
d.dir('foo', [
@@ -48,8 +47,7 @@
d.libPubspec('bar', '1.0.0')
]).commit();
- schedulePub(args: ['update', 'foo'],
- output: new RegExp(r"Dependencies updated!$"));
+ pubUpdate(args: ['foo']);
d.dir(packagesPath, [
d.dir('foo', [
diff --git a/sdk/lib/_internal/pub/test/update/git/update_to_incompatible_pubspec_test.dart b/sdk/lib/_internal/pub/test/update/git/update_to_incompatible_pubspec_test.dart
index 09123f4..348d6db 100644
--- a/sdk/lib/_internal/pub/test/update/git/update_to_incompatible_pubspec_test.dart
+++ b/sdk/lib/_internal/pub/test/update/git/update_to_incompatible_pubspec_test.dart
@@ -21,8 +21,7 @@
d.appDir([{"git": "../foo.git"}]).create();
- schedulePub(args: ['install'],
- output: new RegExp(r"Dependencies installed!$"));
+ pubInstall();
d.dir(packagesPath, [
d.dir('foo', [
@@ -35,10 +34,8 @@
d.libPubspec('zoo', '1.0.0')
]).commit();
- schedulePub(args: ['update'],
- error: new RegExp(r'The name you specified for your dependency, '
- r'"foo", doesn' "'" r't match the name "zoo" in its pubspec.'),
- exitCode: 1);
+ pubUpdate(error: 'The name you specified for your dependency, '
+ '"foo", doesn\'t match the name "zoo" in its pubspec.');
d.dir(packagesPath, [
d.dir('foo', [
diff --git a/sdk/lib/_internal/pub/test/update/git/update_to_nonexistent_pubspec_test.dart b/sdk/lib/_internal/pub/test/update/git/update_to_nonexistent_pubspec_test.dart
index 9e2e995..f746ee6 100644
--- a/sdk/lib/_internal/pub/test/update/git/update_to_nonexistent_pubspec_test.dart
+++ b/sdk/lib/_internal/pub/test/update/git/update_to_nonexistent_pubspec_test.dart
@@ -22,8 +22,7 @@
d.appDir([{"git": "../foo.git"}]).create();
- schedulePub(args: ['install'],
- output: new RegExp(r"Dependencies installed!$"));
+ pubInstall();
d.dir(packagesPath, [
d.dir('foo', [
@@ -34,10 +33,7 @@
repo.runGit(['rm', 'pubspec.yaml']);
repo.runGit(['commit', '-m', 'delete']);
- schedulePub(args: ['update'],
- error: new RegExp(r'Package "foo" doesn' "'" r't have a '
- r'pubspec.yaml file.'),
- exitCode: 1);
+ pubUpdate(error: 'Package "foo" doesn\'t have a pubspec.yaml file.');
d.dir(packagesPath, [
d.dir('foo', [
diff --git a/sdk/lib/_internal/pub/test/update/hosted/unlock_dependers_test.dart b/sdk/lib/_internal/pub/test/update/hosted/unlock_dependers_test.dart
index f1b8e4d..b007e00 100644
--- a/sdk/lib/_internal/pub/test/update/hosted/unlock_dependers_test.dart
+++ b/sdk/lib/_internal/pub/test/update/hosted/unlock_dependers_test.dart
@@ -20,8 +20,7 @@
d.appDir([dependencyMap("foo"), dependencyMap("bar")]).create();
- schedulePub(args: ['install'],
- output: new RegExp(r"Dependencies installed!$"));
+ pubInstall();
d.packagesDir({
"foo": "1.0.0",
@@ -33,8 +32,7 @@
packageMap("bar", "2.0.0")
]);
- schedulePub(args: ['update', 'bar'],
- output: new RegExp(r"Dependencies updated!$"));
+ pubUpdate(args: ['bar']);
d.packagesDir({
"foo": "2.0.0",
diff --git a/sdk/lib/_internal/pub/test/update/hosted/unlock_if_necessary_test.dart b/sdk/lib/_internal/pub/test/update/hosted/unlock_if_necessary_test.dart
index 3115942..3f24c78 100644
--- a/sdk/lib/_internal/pub/test/update/hosted/unlock_if_necessary_test.dart
+++ b/sdk/lib/_internal/pub/test/update/hosted/unlock_if_necessary_test.dart
@@ -20,8 +20,7 @@
d.appDir([dependencyMap("foo")]).create();
- schedulePub(args: ['install'],
- output: new RegExp(r"Dependencies installed!$"));
+ pubInstall();
d.packagesDir({
"foo": "1.0.0",
@@ -33,8 +32,7 @@
packageMap("foo-dep", "2.0.0")
]);
- schedulePub(args: ['update', 'foo'],
- output: new RegExp(r"Dependencies updated!$"));
+ pubUpdate(args: ['foo']);
d.packagesDir({
"foo": "2.0.0",
diff --git a/sdk/lib/_internal/pub/test/update/hosted/update_removed_constraints_test.dart b/sdk/lib/_internal/pub/test/update/hosted/update_removed_constraints_test.dart
index dc20323..3ff3efc 100644
--- a/sdk/lib/_internal/pub/test/update/hosted/update_removed_constraints_test.dart
+++ b/sdk/lib/_internal/pub/test/update/hosted/update_removed_constraints_test.dart
@@ -21,8 +21,7 @@
d.appDir([dependencyMap("foo"), dependencyMap("bar")]).create();
- schedulePub(args: ['update'],
- output: new RegExp(r"Dependencies updated!$"));
+ pubUpdate();
d.packagesDir({
"foo": "1.0.0",
@@ -32,8 +31,7 @@
d.appDir([dependencyMap("foo")]).create();
- schedulePub(args: ['update'],
- output: new RegExp(r"Dependencies updated!$"));
+ pubUpdate();
d.packagesDir({
"foo": "1.0.0",
diff --git a/sdk/lib/_internal/pub/test/utils_test.dart b/sdk/lib/_internal/pub/test/utils_test.dart
index c1c29a8..a137d2d 100644
--- a/sdk/lib/_internal/pub/test/utils_test.dart
+++ b/sdk/lib/_internal/pub/test/utils_test.dart
@@ -80,5 +80,12 @@
null: null
true: bool"""));
});
+
+ test('handles empty maps', () {
+ expect(yamlToString({}), equals("{}"));
+ expect(yamlToString({'a': {}, 'b': {}}), equals("""
+a: {}
+b: {}"""));
+ });
});
}
diff --git a/sdk/lib/async/async.dart b/sdk/lib/async/async.dart
index 7d22e8b..b028d80 100644
--- a/sdk/lib/async/async.dart
+++ b/sdk/lib/async/async.dart
@@ -4,6 +4,8 @@
library dart.async;
+import "dart:collection";
+
part 'async_error.dart';
part 'deferred_load.dart';
part 'event_loop.dart';
diff --git a/sdk/lib/async/event_loop.dart b/sdk/lib/async/event_loop.dart
index 3ceccd2..2802e40 100644
--- a/sdk/lib/async/event_loop.dart
+++ b/sdk/lib/async/event_loop.dart
@@ -7,31 +7,18 @@
typedef void _AsyncCallback();
bool _callbacksAreEnqueued = false;
-List<_AsyncCallback> _asyncCallbacks = <_AsyncCallback>[];
+Queue<_AsyncCallback> _asyncCallbacks = new Queue<_AsyncCallback>();
void _asyncRunCallback() {
// As long as we are iterating over the registered callbacks we don't
// unset the [_callbacksAreEnqueued] boolean.
while (!_asyncCallbacks.isEmpty) {
- List callbacks = _asyncCallbacks;
- // The callbacks we execute can register new callbacks. This means that
- // the for-loop below could grow the list if we don't replace it here.
- _asyncCallbacks = <_AsyncCallback>[];
- for (int i = 0; i < callbacks.length; i++) {
- Function callback = callbacks[i];
- callbacks[i] = null;
- try {
- callback();
- } catch (e) {
- i++; // Skip current callback.
- List remainingCallbacks = callbacks.sublist(i);
- List newCallbacks = _asyncCallbacks;
- _asyncCallbacks = <_AsyncCallback>[];
- _asyncCallbacks.addAll(remainingCallbacks);
- _asyncCallbacks.addAll(newCallbacks);
- _AsyncRun._enqueueImmediate(_asyncRunCallback);
- throw;
- }
+ Function callback = _asyncCallbacks.removeFirst();
+ try {
+ callback();
+ } catch (e) {
+ _AsyncRun._enqueueImmediate(_asyncRunCallback);
+ throw;
}
}
// Any new callback must register a callback function now.
diff --git a/sdk/lib/async/stream.dart b/sdk/lib/async/stream.dart
index dbe3374..07378b5 100644
--- a/sdk/lib/async/stream.dart
+++ b/sdk/lib/async/stream.dart
@@ -62,24 +62,24 @@
* data or error, and then close with a done-event.
*/
factory Stream.fromFuture(Future<T> future) {
- _StreamImpl<T> stream = new _SingleStreamImpl<T>();
+ StreamController<T> controller = new StreamController<T>();
future.then((value) {
- stream._add(value);
- stream._close();
+ controller.add(value);
+ controller.close();
},
onError: (error) {
- stream._addError(error);
- stream._close();
+ controller.addError(error);
+ controller.close();
});
- return stream;
+ return controller.stream;
}
/**
* Creates a single-subscription stream that gets its data from [data].
*/
factory Stream.fromIterable(Iterable<T> data) {
- _PendingEvents iterableEvents = new _IterablePendingEvents<T>(data);
- return new _GeneratedSingleStreamImpl<T>(iterableEvents);
+ return new _GeneratedStreamImpl<T>(
+ () => new _IterablePendingEvents<T>(data));
}
/**
@@ -152,13 +152,13 @@
* If this stream is single-subscription, return a new stream that allows
* multiple subscribers. It will subscribe to this stream when its first
* subscriber is added, and unsubscribe again when the last subscription is
- * cancelled.
+ * canceled.
*
* If this stream is already a broadcast stream, it is returned unmodified.
*/
Stream<T> asBroadcastStream() {
if (isBroadcast) return this;
- return new _SingleStreamMultiplexer<T>(this);
+ return new _AsBroadcastStream<T>(this);
}
/**
@@ -1049,22 +1049,7 @@
const StreamEventTransformer();
Stream<T> bind(Stream<S> source) {
- // Hackish way of buffering data that goes out of the event-transformer.
- // TODO(floitsch): replace this with a correct solution.
- Stream transformingStream = new EventTransformStream<S, T>(source, this);
- StreamController controller;
- StreamSubscription subscription;
- controller = new StreamController<T>(
- onListen: () {
- subscription = transformingStream.listen(
- controller.add,
- onError: controller.addError,
- onDone: controller.close);
- },
- onPause: () => subscription.pause(),
- onResume: () => subscription.resume(),
- onCancel: () => subscription.cancel());
- return controller.stream;
+ return new EventTransformStream<S, T>(source, this);
}
/**
@@ -1119,6 +1104,9 @@
{ void onError(error),
void onDone(),
bool cancelOnError }) {
+ if (onData == null) onData = _nullDataHandler;
+ if (onError == null) onError = _nullErrorHandler;
+ if (onDone == null) onDone = _nullDoneHandler;
cancelOnError = identical(true, cancelOnError);
return new _EventTransformStreamSubscription(_source, _transformer,
onData, onError, onDone,
@@ -1127,16 +1115,16 @@
}
class _EventTransformStreamSubscription<S, T>
- extends _BaseStreamSubscription<T>
- implements _EventOutputSink<T> {
+ extends _BufferingStreamSubscription<T> {
/** The transformer used to transform events. */
final StreamEventTransformer<S, T> _transformer;
- /** Whether to unsubscribe when emitting an error. */
- final bool _cancelOnError;
+
/** Whether this stream has sent a done event. */
bool _isClosed = false;
+
/** Source of incoming events. */
StreamSubscription<S> _subscription;
+
/** Cached EventSink wrapper for this class. */
EventSink<T> _sink;
@@ -1145,9 +1133,9 @@
void onData(T data),
void onError(error),
void onDone(),
- this._cancelOnError)
- : super(onData, onError, onDone) {
- _sink = new _EventOutputSinkWrapper<T>(this);
+ bool cancelOnError)
+ : super(onData, onError, onDone, cancelOnError) {
+ _sink = new _EventSinkAdapter<T>(this);
_subscription = source.listen(_handleData,
onError: _handleError,
onDone: _handleDone);
@@ -1156,17 +1144,15 @@
/** Whether this subscription is still subscribed to its source. */
bool get _isSubscribed => _subscription != null;
- void pause([Future pauseSignal]) {
- if (_isSubscribed) _subscription.pause(pauseSignal);
+ void _onPause() {
+ if (_isSubscribed) _subscription.pause();
}
- void resume() {
+ void _onResume() {
if (_isSubscribed) _subscription.resume();
}
- bool get isPaused => _isSubscribed ? _subscription.isPaused : false;
-
- void cancel() {
+ void _onCancel() {
if (_isSubscribed) {
StreamSubscription subscription = _subscription;
_subscription = null;
@@ -1179,7 +1165,7 @@
try {
_transformer.handleData(data, _sink);
} catch (e, s) {
- _sendError(_asyncError(e, s));
+ _addError(_asyncError(e, s));
}
}
@@ -1187,7 +1173,7 @@
try {
_transformer.handleError(error, _sink);
} catch (e, s) {
- _sendError(_asyncError(e, s));
+ _addError(_asyncError(e, s));
}
}
@@ -1196,40 +1182,69 @@
_subscription = null;
_transformer.handleDone(_sink);
} catch (e, s) {
- _sendError(_asyncError(e, s));
+ _addError(_asyncError(e, s));
}
}
-
- // EventOutputSink interface.
- void _sendData(T data) {
- if (_isClosed) return;
- _onData(data);
- }
-
- void _sendError(error) {
- if (_isClosed) return;
- _onError(error);
- if (_cancelOnError) {
- cancel();
- }
- }
-
- void _sendDone() {
- if (_isClosed) throw new StateError("Already closed.");
- _isClosed = true;
- if (_isSubscribed) {
- _subscription.cancel();
- _subscription = null;
- }
- _onDone();
- }
}
-class _EventOutputSinkWrapper<T> extends EventSink<T> {
- _EventOutputSink _sink;
- _EventOutputSinkWrapper(this._sink);
+class _EventSinkAdapter<T> implements EventSink<T> {
+ _EventSink _sink;
+ _EventSinkAdapter(this._sink);
- void add(T data) { _sink._sendData(data); }
- void addError(error) { _sink._sendError(error); }
- void close() { _sink._sendDone(); }
+ void add(T data) { _sink._add(data); }
+ void addError(error) { _sink._addError(error); }
+ void close() { _sink._close(); }
+}
+
+
+/**
+ * An [Iterable] like interface for the values of a [Stream].
+ *
+ * This wraps a [Stream] and a subscription on the stream. It listens
+ * on the stream, and completes the future returned by [moveNext] when the
+ * next value becomes available.
+ *
+ * NOTICE: This is a tentative design. This class may change.
+ */
+abstract class StreamIterator<T> {
+
+ /** Create a [StreamIterator] on [stream]. */
+ factory StreamIterator(Stream<T> stream)
+ // TODO(lrn): use redirecting factory constructor when type
+ // arguments are supported.
+ => new _StreamIteratorImpl<T>(stream);
+
+ /**
+ * Wait for the next stream value to be available.
+ *
+ * It is not allowed to call this function again until the future has
+ * completed. If the returned future completes with anything except `true`,
+ * the iterator is done, and no new value will ever be available.
+ *
+ * The future may complete with an error, if the stream produces an error.
+ */
+ Future<bool> moveNext();
+
+ /**
+ * The current value of the stream.
+ *
+ * Only valid when the future returned by [moveNext] completes with `true`
+ * as value, and only until the next call to [moveNext].
+ */
+ T get current;
+
+ /**
+ * Cancels the stream iterator (and the underlying stream subscription) early.
+ *
+ * The stream iterator is automatically canceled if the [moveNext] future
+ * completes with either `false` or an error.
+ *
+ * If a [moveNext] call has been made, it will complete with `false` as value,
+ * as will all further calls to [moveNext].
+ *
+ * If you need to stop listening for values before the stream iterator is
+ * automatically closed, you must call [cancel] to ensure that the stream
+ * is properly closed.
+ */
+ void cancel();
}
diff --git a/sdk/lib/async/stream_controller.dart b/sdk/lib/async/stream_controller.dart
index 6ff3ee2..b057565 100644
--- a/sdk/lib/async/stream_controller.dart
+++ b/sdk/lib/async/stream_controller.dart
@@ -46,8 +46,9 @@
* the stream at all, and won't trigger callbacks. From the controller's point
* of view, the stream is completely inert when has completed.
*/
-class StreamController<T> extends EventSink<T> {
- final _StreamImpl<T> stream;
+abstract class StreamController<T> implements EventSink<T> {
+ /** The stream that this controller is controlling. */
+ Stream<T> get stream;
/**
* A controller with a [stream] that supports only one single subscriber.
@@ -59,23 +60,46 @@
* paused. [onResume] is called when the stream resumed.
*
* The [onListen] callback is called when the stream
- * receives its listener. [onCancel] when the listener cancels
+ * receives its listener and [onCancel] when the listener ends
* its subscription.
*
* If the stream is canceled before the controller needs new data the
* [onResume] call might not be executed.
*/
- StreamController({void onListen(),
- void onPause(),
- void onResume(),
- void onCancel()})
- : stream = new _SingleControllerStream<T>(
- onListen, onPause, onResume, onCancel);
+ factory StreamController({void onListen(),
+ void onPause(),
+ void onResume(),
+ void onCancel()})
+ => new _StreamControllerImpl<T>(onListen, onPause, onResume, onCancel);
+
+ /**
+ * A controller where [stream] can be listened to more than once.
+ *
+ * The [Stream] returned by [stream] is a broadcast stream. It can be listened
+ * to more than once.
+ *
+ * The controller distributes any events to all currently subscribed
+ * listeners.
+ * It is not allowed to call [add], [addError], or [close] before a previous
+ * call has returned.
+ *
+ * Each listener is handled independently, and if they pause, only the pausing
+ * listener is affected. A paused listener will buffer events internally until
+ * unpaused or canceled.
+ *
+ * The [onListen] callback is called when the first listener is subscribed,
+ * and the [onCancel] is called when there are no longer any active listeners.
+ * If a listener is added again later, after the [onCancel] was called,
+ * the [onListen] will be called again.
+ */
+ factory StreamController.broadcast({void onListen(), void onCancel()}) {
+ return new _MultiplexStreamController<T>(onListen, onCancel);
+ }
/**
* Returns a view of this object that only exposes the [EventSink] interface.
*/
- EventSink<T> get sink => new _EventSinkView<T>(this);
+ EventSink<T> get sink;
/**
* Whether the stream is closed for adding more events.
@@ -83,71 +107,548 @@
* If true, the "done" event might not have fired yet, but it has been
* scheduled, and it is too late to add more events.
*/
- bool get isClosed => stream._isClosed;
-
- /** Whether one or more active subscribers have requested a pause. */
- bool get isPaused => stream._isInputPaused;
-
- /** Whether there are currently any subscribers on this [Stream]. */
- bool get hasListener => stream._hasListener;
+ bool get isClosed;
/**
- * Send or queue a data event.
+ * Whether the subscription would need to buffer events.
+ *
+ * This is the case if the controller's stream has a listener and it is
+ * paused, or if it has not received a listener yet. In that case, the
+ * controller is considered paused as well.
+ *
+ * A broadcast stream controller is never considered paused. It always
+ * forwards its events to all uncanceled listeners, if any, and let them
+ * handle their own pausing.
*/
- void add(T value) => stream._add(value);
+ bool get isPaused;
+
+ /** Whether there is a subscriber on the [Stream]. */
+ bool get hasListener;
/**
* Send or enqueue an error event.
*
- * If a subscription has requested to be unsubscribed on errors,
- * it will be unsubscribed after receiving this event.
+ * Also allows an objection stack trace object, on top of what [EventSink]
+ * allows.
+ */
+ void addError(Object error, [Object stackTrace]);
+}
+
+
+abstract class _StreamControllerLifecycle<T> {
+ void _recordListen(StreamSubscription<T> subscription) {}
+ void _recordPause(StreamSubscription<T> subscription) {}
+ void _recordResume(StreamSubscription<T> subscription) {}
+ void _recordCancel(StreamSubscription<T> subscription) {}
+}
+
+/**
+ * Default implementation of [StreamController].
+ *
+ * Controls a stream that only supports a single controller.
+ */
+class _StreamControllerImpl<T> implements StreamController<T>,
+ _StreamControllerLifecycle<T> {
+ static const int _STATE_OPEN = 0;
+ static const int _STATE_CANCELLED = 1;
+ static const int _STATE_CLOSED = 2;
+
+ final _NotificationHandler _onListen;
+ final _NotificationHandler _onPause;
+ final _NotificationHandler _onResume;
+ final _NotificationHandler _onCancel;
+ _StreamImpl<T> _stream;
+
+ // An active subscription on the stream, or null if no subscripton is active.
+ _ControllerSubscription<T> _subscription;
+
+ // Whether we have sent a "done" event.
+ int _state = _STATE_OPEN;
+
+ // Events added to the stream before it has an active subscription.
+ _PendingEvents _pendingEvents = null;
+
+ _StreamControllerImpl(this._onListen,
+ this._onPause,
+ this._onResume,
+ this._onCancel) {
+ _stream = new _ControllerStream<T>(this);
+ }
+
+ Stream<T> get stream => _stream;
+
+ /**
+ * Returns a view of this object that only exposes the [EventSink] interface.
+ */
+ EventSink<T> get sink => new _EventSinkView<T>(this);
+
+ /**
+ * Whether a listener has existed and been cancelled.
+ *
+ * After this, adding more events will be ignored.
+ */
+ bool get _isCancelled => (_state & _STATE_CANCELLED) != 0;
+
+ bool get isClosed => (_state & _STATE_CLOSED) != 0;
+
+ bool get isPaused => hasListener ? _subscription._isInputPaused
+ : !_isCancelled;
+
+ bool get hasListener => _subscription != null;
+
+ /**
+ * Send or queue a data event.
+ */
+ void add(T value) {
+ if (isClosed) throw new StateError("Adding event after close");
+ if (_subscription != null) {
+ _subscription._add(value);
+ } else if (!_isCancelled) {
+ _addPendingEvent(new _DelayedData<T>(value));
+ }
+ }
+
+ /**
+ * Send or enqueue an error event.
*/
void addError(Object error, [Object stackTrace]) {
+ if (isClosed) throw new StateError("Adding event after close");
if (stackTrace != null) {
// Force stack trace overwrite. Even if the error already contained
// a stack trace.
_attachStackTrace(error, stackTrace);
}
- stream._addError(error);
+ if (_subscription != null) {
+ _subscription._addError(error);
+ } else if (!_isCancelled) {
+ _addPendingEvent(new _DelayedError(error));
+ }
}
/**
- * Send or enqueue a "done" message.
+ * Closes this controller.
*
- * The "done" message should be sent at most once by a stream, and it
- * should be the last message sent.
+ * After closing, no further events may be added using [add] or [addError].
+ *
+ * You are allowed to close the controller more than once, but only the first
+ * call has any effect.
+ *
+ * The first time a controller is closed, a "done" event is sent to its
+ * stream.
*/
- void close() { stream._close(); }
+ void close() {
+ if (isClosed) return;
+ _state |= _STATE_CLOSED;
+ if (_subscription != null) {
+ _subscription._close();
+ } else if (!_isCancelled) {
+ _addPendingEvent(const _DelayedDone());
+ }
+ }
+
+ void _addPendingEvent(_DelayedEvent event) {
+ if (_isCancelled) return;
+ _StreamImplEvents events = _pendingEvents;
+ if (events == null) {
+ events = _pendingEvents = new _StreamImplEvents();
+ }
+ events.add(event);
+ }
+
+ void _recordListen(_BufferingStreamSubscription<T> subscription) {
+ assert(_subscription == null);
+ _subscription = subscription;
+ subscription._setPendingEvents(_pendingEvents);
+ _pendingEvents = null;
+ subscription._guardCallback(() {
+ _runGuarded(_onListen);
+ });
+ }
+
+ void _recordCancel(StreamSubscription<T> subscription) {
+ assert(identical(_subscription, subscription));
+ _subscription = null;
+ _state |= _STATE_CANCELLED;
+ _runGuarded(_onCancel);
+ }
+
+ void _recordPause(StreamSubscription<T> subscription) {
+ _runGuarded(_onPause);
+ }
+
+ void _recordResume(StreamSubscription<T> subscription) {
+ _runGuarded(_onResume);
+ }
}
typedef void _NotificationHandler();
-class _SingleControllerStream<T> extends _SingleStreamImpl<T> {
- _NotificationHandler _onListen;
- _NotificationHandler _onPause;
- _NotificationHandler _onResume;
- _NotificationHandler _onCancel;
+void _runGuarded(_NotificationHandler notificationHandler) {
+ if (notificationHandler == null) return;
+ try {
+ notificationHandler();
+ } catch (e, s) {
+ _throwDelayed(e, s);
+ }
+}
- // TODO(floitsch): share this code with _MultiControllerStream.
- _runGuarded(_NotificationHandler notificationHandler) {
- if (notificationHandler == null) return;
- try {
- notificationHandler();
- } catch (e, s) {
- _throwDelayed(e, s);
+class _ControllerStream<T> extends _StreamImpl<T> {
+ _StreamControllerLifecycle<T> _controller;
+ bool _hasListener = false;
+
+ _ControllerStream(this._controller);
+
+ StreamSubscription<T> _createSubscription(
+ void onData(T data),
+ void onError(Object error),
+ void onDone(),
+ bool cancelOnError) {
+ if (_hasListener) {
+ throw new StateError("The stream has already been listened to.");
+ }
+ _hasListener = true;
+ return new _ControllerSubscription<T>(
+ _controller, onData, onError, onDone, cancelOnError);
+ }
+
+ void _onListen(_BufferingStreamSubscription subscription) {
+ _controller._recordListen(subscription);
+ }
+}
+
+class _ControllerSubscription<T> extends _BufferingStreamSubscription<T> {
+ final _StreamControllerLifecycle<T> _controller;
+
+ _ControllerSubscription(this._controller,
+ void onData(T data),
+ void onError(Object error),
+ void onDone(),
+ bool cancelOnError)
+ : super(onData, onError, onDone, cancelOnError);
+
+ void _onCancel() {
+ _controller._recordCancel(this);
+ }
+
+ void _onPause() {
+ _controller._recordPause(this);
+ }
+
+ void _onResume() {
+ _controller._recordResume(this);
+ }
+}
+
+class _MultiplexStream<T> extends _StreamImpl<T> {
+ _MultiplexStreamController _controller;
+
+ _MultiplexStream(this._controller);
+
+ bool get isBroadcast => true;
+
+ StreamSubscription<T> _createSubscription(
+ void onData(T data),
+ void onError(Object error),
+ void onDone(),
+ bool cancelOnError) {
+ return new _MultiplexSubscription<T>(
+ _controller, onData, onError, onDone, cancelOnError);
+ }
+
+ void _onListen(_BufferingStreamSubscription subscription) {
+ _controller._recordListen(subscription);
+ }
+}
+
+abstract class _MultiplexSubscriptionLink {
+ _MultiplexSubscriptionLink _next;
+ _MultiplexSubscriptionLink _previous;
+}
+
+class _MultiplexSubscription<T> extends _ControllerSubscription<T>
+ implements _MultiplexSubscriptionLink {
+ static const int _STATE_EVENT_ID = 1;
+ static const int _STATE_FIRING = 2;
+ static const int _STATE_REMOVE_AFTER_FIRING = 4;
+ int _eventState;
+
+ _MultiplexSubscriptionLink _next;
+ _MultiplexSubscriptionLink _previous;
+
+ _MultiplexSubscription(_StreamControllerLifecycle controller,
+ void onData(T data),
+ void onError(Object error),
+ void onDone(),
+ bool cancelOnError)
+ : super(controller, onData, onError, onDone, cancelOnError) {
+ _next = _previous = this;
+ }
+
+ _MultiplexStreamController get _controller => super._controller;
+
+ bool _expectsEvent(int eventId) {
+ return (_eventState & _STATE_EVENT_ID) == eventId;
+ }
+
+ void _toggleEventId() {
+ _eventState ^= _STATE_EVENT_ID;
+ }
+
+ bool get _isFiring => (_eventState & _STATE_FIRING) != 0;
+
+ bool _setRemoveAfterFiring() {
+ assert(_isFiring);
+ _eventState |= _STATE_REMOVE_AFTER_FIRING;
+ }
+
+ bool get _removeAfterFiring =>
+ (_eventState & _STATE_REMOVE_AFTER_FIRING) != 0;
+}
+
+
+class _MultiplexStreamController<T> implements StreamController<T>,
+ _StreamControllerLifecycle<T>,
+ _MultiplexSubscriptionLink {
+ static const int _STATE_INITIAL = 0;
+ static const int _STATE_EVENT_ID = 1;
+ static const int _STATE_FIRING = 2;
+ static const int _STATE_CLOSED = 4;
+
+ final _NotificationHandler _onListen;
+ final _NotificationHandler _onCancel;
+
+ // State of the controller.
+ int _state;
+
+ // Double-linked list of active listeners.
+ _MultiplexSubscriptionLink _next;
+ _MultiplexSubscriptionLink _previous;
+
+ _MultiplexStreamController(this._onListen, this._onCancel)
+ : _state = _STATE_INITIAL {
+ _next = _previous = this;
+ }
+
+ // StreamController interface.
+
+ Stream<T> get stream => new _MultiplexStream<T>(this);
+
+ EventSink<T> get sink => new _EventSinkView<T>(this);
+
+ bool get isClosed => (_state & _STATE_CLOSED) != 0;
+
+ /**
+ * A multiplex controller is never paused.
+ *
+ * Each receiving stream may be paused individually, and they handle their
+ * own buffering.
+ */
+ bool get isPaused => false;
+
+ /** Whether there are currently a subscriber on the [Stream]. */
+ bool get hasListener => !_isEmpty;
+
+ /** Whether an event is being fired (sent to some, but not all, listeners). */
+ bool get _isFiring => (_state & _STATE_FIRING) != 0;
+
+ // Linked list helpers
+
+ bool get _isEmpty => identical(_next, this);
+
+ /** Adds subscription to linked list of active listeners. */
+ void _addListener(_MultiplexSubscription<T> subscription) {
+ _MultiplexSubscriptionLink previous = _previous;
+ previous._next = subscription;
+ _previous = subscription._previous;
+ subscription._previous._next = this;
+ subscription._previous = previous;
+ subscription._eventState = (_state & _STATE_EVENT_ID);
+ }
+
+ void _removeListener(_MultiplexSubscription<T> subscription) {
+ assert(identical(subscription._controller, this));
+ assert(!identical(subscription._next, subscription));
+ subscription._previous._next = subscription._next;
+ subscription._next._previous = subscription._previous;
+ subscription._next = subscription._previous = subscription;
+ }
+
+ // _StreamControllerLifecycle interface.
+
+ void _recordListen(_MultiplexSubscription<T> subscription) {
+ _addListener(subscription);
+ if (identical(_next, _previous)) {
+ // Only one listener, so it must be the first listener.
+ _runGuarded(_onListen);
}
}
- _SingleControllerStream(this._onListen,
- this._onPause,
- this._onResume,
- this._onCancel);
-
- void _onSubscriptionStateChange() {
- _runGuarded(_hasListener ? _onListen : _onCancel);
+ void _recordCancel(_MultiplexSubscription<T> subscription) {
+ if (subscription._isFiring) {
+ subscription._setRemoveAfterFiring();
+ } else {
+ _removeListener(subscription);
+ // If we are currently firing an event, the empty-check is performed at
+ // the end of the listener loop instead of here.
+ if ((_state & _STATE_FIRING) == 0 && _isEmpty) {
+ _callOnCancel();
+ }
+ }
}
- void _onPauseStateChange() {
- _runGuarded(_isPaused ? _onPause : _onResume);
+ void _recordPause(StreamSubscription<T> subscription) {}
+ void _recordResume(StreamSubscription<T> subscription) {}
+
+ // EventSink interface.
+
+ void add(T data) {
+ if (isClosed) {
+ throw new StateError("Cannot add new events after calling close()");
+ }
+ _sendData(data);
+ }
+
+ void addError(Object error, [Object stackTrace]) {
+ if (isClosed) {
+ throw new StateError("Cannot add new events after calling close()");
+ }
+ if (stackTrace != null) _attachStackTrace(error, stackTrace);
+ _sendError(error);
+ }
+
+ void close() {
+ if (isClosed) {
+ throw new StateError("Cannot add new events after calling close()");
+ }
+ _state |= _STATE_CLOSED;
+ _sendDone();
+ }
+
+ // EventDispatch interface.
+
+ void _sendData(T data) {
+ if (_isEmpty) return;
+ _forEachListener((_BufferingStreamSubscription<T> subscription) {
+ subscription._add(data);
+ });
+ }
+
+ void _sendError(Object error) {
+ if (_isEmpty) return;
+ _forEachListener((_BufferingStreamSubscription<T> subscription) {
+ subscription._addError(error);
+ });
+ }
+
+ void _sendDone() {
+ if (_isEmpty) return;
+ _forEachListener((_MultiplexSubscription<T> subscription) {
+ subscription._close();
+ subscription._eventState |=
+ _MultiplexSubscription._STATE_REMOVE_AFTER_FIRING;
+ });
+ }
+
+ void _forEachListener(
+ void action(_BufferingStreamSubscription<T> subscription)) {
+ if (_isFiring) {
+ throw new StateError(
+ "Cannot fire new event. Controller is already firing an event");
+ }
+ if (_isEmpty) return;
+
+ // Get event id of this event.
+ int id = (_state & _STATE_EVENT_ID);
+ // Start firing (set the _STATE_FIRING bit). We don't do [_onCancel]
+ // callbacks while firing, and we prevent reentrancy of this function.
+ //
+ // Set [_state]'s event id to the next event's id.
+ // Any listeners added while firing this event will expect the next event,
+ // not this one, and won't get notified.
+ _state ^= _STATE_EVENT_ID | _STATE_FIRING;
+ _MultiplexSubscriptionLink link = _next;
+ while (!identical(link, this)) {
+ _MultiplexSubscription<T> subscription = link;
+ if (subscription._expectsEvent(id)) {
+ subscription._eventState |= _MultiplexSubscription._STATE_FIRING;
+ action(subscription);
+ subscription._toggleEventId();
+ link = subscription._next;
+ if (subscription._removeAfterFiring) {
+ _removeListener(subscription);
+ }
+ subscription._eventState &= ~_MultiplexSubscription._STATE_FIRING;
+ } else {
+ link = subscription._next;
+ }
+ }
+ _state &= ~_STATE_FIRING;
+
+ if (_isEmpty) {
+ _callOnCancel();
+ }
+ }
+
+ void _callOnCancel() {
+ _runGuarded(_onCancel);
+ }
+}
+
+class _BufferingMultiplexStreamController<T>
+ extends _MultiplexStreamController<T>
+ implements _EventDispatch<T> {
+ _StreamImplEvents _pending;
+
+ _BufferingMultiplexStreamController(void onListen(), void onCancel())
+ : super(onListen, onCancel);
+
+ bool get _hasPending => _pending != null && ! _pending.isEmpty;
+
+ void _addPendingEvent(_DelayedEvent event) {
+ if (_pending == null) {
+ _pending = new _StreamImplEvents();
+ }
+ _pending.add(event);
+ }
+
+ void add(T data) {
+ if (_isFiring) {
+ _addPendingEvent(new _DelayedData<T>(data));
+ return;
+ }
+ super.add(data);
+ while (_hasPending) {
+ _pending.handleNext(this);
+ }
+ }
+
+ void addError(Object error, [StackTrace stackTrace]) {
+ if (_isFiring) {
+ _addPendingEvent(new _DelayedError(error));
+ return;
+ }
+ super.addError(error, stackTrace);
+ while (_hasPending) {
+ _pending.handleNext(this);
+ }
+ }
+
+ void close() {
+ if (_isFiring) {
+ _addPendingEvent(const _DelayedDone());
+ _state |= _STATE_CLOSED;
+ return;
+ }
+ super.close();
+ assert(!_hasPending);
+ }
+
+ void _callOnCancel() {
+ if (_hasPending) {
+ _pending.clear();
+ _pending = null;
+ }
+ super._callOnCancel();
+
}
}
diff --git a/sdk/lib/async/stream_impl.dart b/sdk/lib/async/stream_impl.dart
index 8fa1848..375844c 100644
--- a/sdk/lib/async/stream_impl.dart
+++ b/sdk/lib/async/stream_impl.dart
@@ -4,57 +4,6 @@
part of dart.async;
-// States shared by single/multi stream implementations.
-
-// Completion state of the stream.
-/// Initial and default state where the stream can receive and send events.
-const int _STREAM_OPEN = 0;
-/// The stream has received a request to complete, but hasn't done so yet.
-/// No further events can be added to the stream.
-const int _STREAM_CLOSED = 1;
-/// The stream has completed and will no longer receive or send events.
-/// Also counts as closed. The stream must not be paused when it's completed.
-/// Always used in conjunction with [_STREAM_CLOSED].
-const int _STREAM_COMPLETE = 2;
-
-/// Bit that alternates between events, and listeners are updated to the
-/// current value when they are notified of the event.
-const int _STREAM_EVENT_ID = 4;
-const int _STREAM_EVENT_ID_SHIFT = 2;
-
-// The activity state of the stream: What is it currently doing.
-/// Bit set while firing and clear while not.
-const int _STREAM_FIRING = 8;
-/// Bit set while calling a pause-state or subscription-state change callback.
-const int _STREAM_CALLBACK = 16;
-
-// The pause state of the stream.
-/// Bit set when resuming with pending events. Cleared after all pending events
-/// have been transmitted. Means that the controller still considers the
-/// stream paused, even if the listener doesn't.
-const int _STREAM_PENDING_RESUME = 32;
-/// The count of times a stream has paused is stored in the
-/// state, shifted by this amount.
-const int _STREAM_PAUSE_COUNT_SHIFT = 6;
-
-// States for listeners.
-
-/// The listener is currently not subscribed to its source stream.
-const int _LISTENER_UNSUBSCRIBED = 0;
-/// The listener is actively subscribed to its source stream.
-const int _LISTENER_SUBSCRIBED = 1;
-/// The listener is subscribed until it has been notified of the current event.
-/// This flag bit is always used in conjuction with [_LISTENER_SUBSCRIBED].
-const int _LISTENER_PENDING_UNSUBSCRIBE = 2;
-
-/// Bit that contains the last sent event's "id bit".
-const int _LISTENER_EVENT_ID = 4;
-const int _LISTENER_EVENT_ID_SHIFT = 2;
-
-/// The count of times a listener has paused is stored in the
-/// state, shifted by this amount.
-const int _LISTENER_PAUSE_COUNT_SHIFT = 3;
-
/** Throws the given error in the next cycle. */
_throwDelayed(var error, [Object stackTrace]) {
// We are going to reach the top-level here, but there might be a global
@@ -69,857 +18,135 @@
});
}
-
-// -------------------------------------------------------------------
-// Common base class for single and multi-subscription streams.
-// -------------------------------------------------------------------
-abstract class _StreamImpl<T> extends Stream<T> {
- /** Current state of the stream. */
- int _state = _STREAM_OPEN;
-
- /**
- * List of pending events.
- *
- * If events are added to the stream (using [_add], [_addError] or [_done])
- * while the stream is paused, or while another event is firing, events will
- * stored here.
- * Also supports scheduling the events for later execution.
- */
- _PendingEvents _pendingEvents;
-
- // ------------------------------------------------------------------
- // Stream interface.
-
- StreamSubscription<T> listen(void onData(T data),
- { void onError(error),
- void onDone(),
- bool cancelOnError }) {
- if (_isComplete) {
- return new _DoneSubscription(onDone);
- }
- if (onData == null) onData = _nullDataHandler;
- if (onError == null) onError = _nullErrorHandler;
- if (onDone == null) onDone = _nullDoneHandler;
- cancelOnError = identical(true, cancelOnError);
- _StreamSubscriptionImpl subscription =
- _createSubscription(onData, onError, onDone, cancelOnError);
- _addListener(subscription);
- return subscription;
- }
-
- // ------------------------------------------------------------------
- // EventSink interface-like methods for sending events into the stream.
- // It's the responsibility of the caller to ensure that the stream is not
- // paused when adding events. If the stream is paused, the events will be
- // queued, but it's better to not send events at all.
-
- /**
- * Send or queue a data event.
- */
- void _add(T value) {
- if (_isClosed) throw new StateError("Sending on closed stream");
- if (!_mayFireState) {
- // Not the time to send events.
- _addPendingEvent(new _DelayedData<T>(value));
- return;
- }
- if (_hasPendingEvent) {
- _addPendingEvent(new _DelayedData<T>(value));
- } else {
- _sendData(value);
- }
- _handlePendingEvents();
- }
-
- /**
- * Send or enqueue an error event.
- *
- * If a subscription has requested to be unsubscribed on errors,
- * it will be unsubscribed after receiving this event.
- */
- void _addError(error) {
- if (_isClosed) throw new StateError("Sending on closed stream");
- if (!_mayFireState) {
- // Not the time to send events.
- _addPendingEvent(new _DelayedError(error));
- return;
- }
- if (_hasPendingEvent) {
- _addPendingEvent(new _DelayedError(error));
- } else {
- _sendError(error);
- }
- _handlePendingEvents();
- }
-
- /**
- * Send or enqueue a "done" message.
- *
- * The "done" message should be sent at most once by a stream, and it
- * should be the last message sent.
- */
- void _close() {
- if (_isClosed) return;
- _state |= _STREAM_CLOSED;
- if (!_mayFireState) {
- // Not the time to send events.
- _addPendingEvent(const _DelayedDone());
- return;
- }
- if (_hasPendingEvent) {
- _addPendingEvent(new _DelayedDone());
- _handlePendingEvents();
- } else {
- _sendDone();
- assert(_isComplete);
- assert(!_hasPendingEvent);
- }
- }
-
- // -------------------------------------------------------------------
- // Internal implementation.
-
- // State predicates.
-
- // Lifecycle state.
- /** Whether the stream is in the default, open, state for events. */
- bool get _isOpen => (_state & (_STREAM_CLOSED | _STREAM_COMPLETE)) == 0;
-
- /** Whether the stream has been closed (a done event requested). */
- bool get _isClosed => (_state & _STREAM_CLOSED) != 0;
-
- /** Whether the stream is completed. */
- bool get _isComplete => (_state & _STREAM_COMPLETE) != 0;
-
- // Pause state.
-
- /** Whether one or more active subscribers have requested a pause. */
- bool get _isPaused => _state >= (1 << _STREAM_PAUSE_COUNT_SHIFT);
-
- /** How many times the stream has been paused. */
- int get _pauseCount => _state >> _STREAM_PAUSE_COUNT_SHIFT;
-
- /**
- * Whether a controller thinks the stream is paused.
- *
- * When this changes, a pause-state change callback is performed.
- *
- * It may differ from [_isPaused] if there are pending events
- * in the queue when the listeners resume. The controller won't
- * be informed until all queued events have been fired.
- */
- bool get _isInputPaused => _state >= (_STREAM_PENDING_RESUME);
-
- /** Whether we have a pending resume scheduled. */
- bool get _hasPendingResume => (_state & _STREAM_PENDING_RESUME) != 0;
-
-
- // Action state. If the stream makes a call-out to external code,
- // this state tracks it and avoids reentrancy problems.
-
- /** Whether the stream is not currently firing or calling a callback. */
- bool get _isInactive => (_state & (_STREAM_CALLBACK | _STREAM_FIRING)) == 0;
-
- /** Whether we are currently executing a state-chance callback. */
- bool get _isInCallback => (_state & _STREAM_CALLBACK) != 0;
-
- /** Whether we are currently firing an event. */
- bool get _isFiring => (_state & _STREAM_FIRING) != 0;
-
- /** Check whether the pending event queue is non-empty */
- bool get _hasPendingEvent =>
- _pendingEvents != null && !_pendingEvents.isEmpty;
-
- /**
- * The bit representing the current or last event fired.
- *
- * This bit matches a bit on listeners that have received the corresponding
- * event. It is toggled for each new event being fired.
- */
- int get _currentEventIdBit =>
- (_state & _STREAM_EVENT_ID ) >> _STREAM_EVENT_ID_SHIFT;
-
- /** Whether there is currently a subscriber on this [Stream]. */
- bool get _hasListener;
-
-
- /** Whether the state bits allow firing. */
- bool get _mayFireState {
- // The state allows firing unless:
- // - it's currently firing
- // - it's currently in a callback
- // - it's paused
- const int mask =
- _STREAM_FIRING |
- _STREAM_CALLBACK |
- ~((1 << _STREAM_PAUSE_COUNT_SHIFT) - 1);
- return (_state & mask) == 0;
- }
-
- // State modification.
-
- /** Record an increases in the number of times the listener has paused. */
- void _incrementPauseCount(_StreamListener<T> listener) {
- listener._incrementPauseCount();
- _state &= ~_STREAM_PENDING_RESUME;
- _updatePauseCount(1);
- }
-
- /** Record a decrease in the number of times the listener has paused. */
- void _decrementPauseCount(_StreamListener<T> listener) {
- assert(_isPaused);
- listener._decrementPauseCount();
- _updatePauseCount(-1);
- }
-
- /** Update the stream's own pause count only. */
- void _updatePauseCount(int by) {
- int oldState = _state;
- // We can't just _state += by << _STREAM_PAUSE_COUNT_SHIFT, since dart2js
- // converts the result of the left-shift to a positive number.
- if (by >= 0) {
- _state = oldState + (by << _STREAM_PAUSE_COUNT_SHIFT);
- } else {
- _state = oldState - ((-by) << _STREAM_PAUSE_COUNT_SHIFT);
- }
- assert(_state >= 0);
- assert((_state >> _STREAM_PAUSE_COUNT_SHIFT) ==
- (oldState >> _STREAM_PAUSE_COUNT_SHIFT) + by);
- }
-
- void _setClosed() {
- assert(!_isClosed);
- _state |= _STREAM_CLOSED;
- }
-
- void _setComplete() {
- assert(_isClosed);
- _state = _state |_STREAM_COMPLETE;
- }
-
- void _startFiring() {
- assert(!_isFiring);
- assert(!_isInCallback);
- assert(_hasListener);
- assert(!_isPaused);
- // This sets the _STREAM_FIRING bit and toggles the _STREAM_EVENT_ID
- // bit. All current subscribers will now have a _LISTENER_EVENT_ID
- // that doesn't match _STREAM_EVENT_ID, and they will receive the
- // event being fired.
- _state ^= _STREAM_FIRING | _STREAM_EVENT_ID;
- }
-
- void _endFiring(bool wasInputPaused) {
- assert(_isFiring);
- _state ^= _STREAM_FIRING;
- // Had listeners, or we wouldn't have fired.
- _checkCallbacks(true, wasInputPaused);
- }
-
- /**
- * Record that a listener wants a pause from events.
- *
- * This methods is called from [_StreamListener.pause()].
- * Subclasses can override this method, along with [isPaused] and
- * [createSubscription], if they want to do a different handling of paused
- * subscriptions, e.g., a filtering stream pausing its own source if all its
- * subscribers are paused.
- */
- void _pause(_StreamListener<T> listener, Future resumeSignal) {
- assert(identical(listener._source, this));
- if (!listener._isSubscribed) {
- throw new StateError("Subscription has been canceled.");
- }
- assert(!_isComplete); // There can be no subscribers when complete.
- bool wasInputPaused = _isInputPaused;
- bool wasPaused = _isPaused;
- _incrementPauseCount(listener);
- if (resumeSignal != null) {
- resumeSignal.whenComplete(() { this._resume(listener, true); });
- }
- if (!wasPaused && _hasPendingEvent && _pendingEvents.isScheduled) {
- _pendingEvents.cancelSchedule();
- }
- if (_isInactive && !wasInputPaused) {
- _checkCallbacks(true, false);
- if (!_isPaused && _hasPendingEvent) {
- _schedulePendingEvents();
- }
- }
- }
-
- /** Stops pausing due to one request from the given listener. */
- void _resume(_StreamListener<T> listener, bool fromEvent) {
- if (!listener.isPaused) return;
- assert(listener._isSubscribed);
- assert(_isPaused);
- _decrementPauseCount(listener);
- if (!_isPaused) {
- if (_hasPendingEvent) {
- _state |= _STREAM_PENDING_RESUME;
- // Controller's pause state hasn't changed.
- // If we can fire events now, fire any pending events right away.
- if (_isInactive) {
- if (fromEvent) {
- _handlePendingEvents();
- } else {
- _schedulePendingEvents();
- }
- }
- } else if (_isInactive) {
- _checkCallbacks(true, true);
- if (!_isPaused && _hasPendingEvent) {
- if (fromEvent) {
- _handlePendingEvents();
- } else {
- _schedulePendingEvents();
- }
- }
- }
- }
- }
-
- /** Schedule pending events to be executed. */
- void _schedulePendingEvents() {
- assert(_hasPendingEvent);
- _pendingEvents.schedule(this);
- }
-
- /** Create a subscription object. Called by [subcribe]. */
- _StreamSubscriptionImpl<T> _createSubscription(
- void onData(T data),
- void onError(error),
- void onDone(),
- bool cancelOnError);
-
- /**
- * Adds a listener to this stream.
- */
- void _addListener(_StreamSubscriptionImpl subscription);
-
- /**
- * Handle a cancel requested from a [_StreamSubscriptionImpl].
- *
- * This method is called from [_StreamSubscriptionImpl.cancel].
- *
- * If an event is currently firing, the cancel is delayed
- * until after the subscribers have received the event.
- */
- void _cancel(_StreamSubscriptionImpl subscriber);
-
- /**
- * Iterate over all current subscribers and perform an action on each.
- *
- * Subscribers added during the iteration will not be visited.
- * Subscribers unsubscribed during the iteration will only be removed
- * after they have been acted on.
- *
- * Any change in the pause state is only reported after all subscribers have
- * received the event.
- *
- * The [action] must not throw, or the controller will be left in an
- * invalid state.
- *
- * This method must not be called while [isFiring] is true.
- */
- void _forEachSubscriber(void action(_StreamSubscriptionImpl<T> subscription));
-
- /**
- * Checks whether the subscription/pause state has changed.
- *
- * Calls the appropriate callback if the state has changed from the
- * provided one. Repeats calling callbacks as long as the call changes
- * the state.
- */
- void _checkCallbacks(bool hadListener, bool wasPaused) {
- assert(!_isFiring);
- // Will be handled after the current callback.
- if (_isInCallback) return;
- if (_hasPendingResume && !_hasPendingEvent) {
- _state ^= _STREAM_PENDING_RESUME;
- }
- _state |= _STREAM_CALLBACK;
- while (true) {
- bool hasListener = _hasListener;
- bool isPaused = _isInputPaused;
- if (hadListener != hasListener) {
- _onSubscriptionStateChange();
- } else if (isPaused != wasPaused) {
- _onPauseStateChange();
- } else {
- _state ^= _STREAM_CALLBACK;
- return;
- }
- wasPaused = isPaused;
- hadListener = hasListener;
- }
- }
-
- /**
- * Called when the first subscriber requests a pause or the last a resume.
- *
- * Read [isPaused] to see the new state.
- */
- void _onPauseStateChange() {}
-
- /**
- * Called when the first listener subscribes or the last unsubscribes.
- *
- * Read [hasListener] to see what the new state is.
- */
- void _onSubscriptionStateChange() {}
-
- /**
- * Add a pending event at the end of the pending event queue.
- *
- * Schedules events if currently not paused and inside a callback.
- */
- void _addPendingEvent(_DelayedEvent event) {
- if (_pendingEvents == null) _pendingEvents = new _StreamImplEvents();
- _StreamImplEvents events = _pendingEvents;
- events.add(event);
- if (_isPaused || _isFiring) return;
- if (_isInCallback) {
- _schedulePendingEvents();
- return;
- }
- }
-
- /** Fire any pending events until the pending event queue is empty. */
- void _handlePendingEvents() {
- assert(_isInactive);
- if (!_hasPendingEvent) return;
- _PendingEvents events = _pendingEvents;
- do {
- if (_isPaused) return;
- if (events.isScheduled) events.cancelSchedule();
- events.handleNext(this);
- } while (!events.isEmpty);
- }
-
- /**
- * Send a data event directly to each subscriber.
- */
- _sendData(T value) {
- assert(!_isPaused);
- assert(!_isComplete);
- if (!_hasListener) return;
- _forEachSubscriber((subscriber) {
- try {
- subscriber._sendData(value);
- } catch (e, s) {
- _throwDelayed(e, s);
- }
- });
- }
-
- /**
- * Sends an error event directly to each subscriber.
- */
- void _sendError(error) {
- assert(!_isPaused);
- assert(!_isComplete);
- if (!_hasListener) return;
- _forEachSubscriber((subscriber) {
- try {
- subscriber._sendError(error);
- } catch (e, s) {
- _throwDelayed(e, s);
- }
- });
- }
-
- /**
- * Sends the "done" message directly to each subscriber.
- * This automatically stops further subscription and
- * unsubscribes all subscribers.
- */
- void _sendDone() {
- assert(!_isPaused);
- assert(_isClosed);
- _setComplete();
- if (!_hasListener) return;
- _forEachSubscriber((subscriber) {
- _cancel(subscriber);
- try {
- subscriber._sendDone();
- } catch (e, s) {
- _throwDelayed(e, s);
- }
- });
- assert(!_hasListener);
- }
+/** Abstract and private interface for a place to put events. */
+abstract class _EventSink<T> {
+ void _add(T data);
+ void _addError(Object error);
+ void _close();
}
-// -------------------------------------------------------------------
-// Default implementation of a stream with a single subscriber.
-// -------------------------------------------------------------------
/**
- * Default implementation of stream capable of sending events to one subscriber.
+ * Abstract and private interface for a place to send events.
*
- * Any class needing to implement [Stream] can either directly extend this
- * class, or extend [Stream] and delegate the subscribe method to an instance
- * of this class.
+ * Used by event buffering to finally dispatch the pending event, where
+ * [_EventSink] is where the event first enters the stream subscription,
+ * and may yet be buffered.
+ */
+abstract class _EventDispatch<T> {
+ void _sendData(T data);
+ void _sendError(Object error);
+ void _sendDone();
+}
+
+/**
+ * Default implementation of stream subscription of buffering events.
*
- * The only public methods are those of [Stream], so instances of
- * [_SingleStreamImpl] can be returned directly as a [Stream] without exposing
- * internal functionality.
+ * The only public methods are those of [StreamSubscription], so instances of
+ * [_BufferingStreamSubscription] can be returned directly as a
+ * [StreamSubscription] without exposing internal functionality.
*
- * The [StreamController] is a public facing version of this class, with
- * some methods made public.
+ * The [StreamController] is a public facing version of [Stream] and this class,
+ * with some methods made public.
*
- * The user interface of [_SingleStreamImpl] are the following methods:
+ * The user interface of [_BufferingStreamSubscription] are the following
+ * methods:
* * [_add]: Add a data event to the stream.
* * [_addError]: Add an error event to the stream.
* * [_close]: Request to close the stream.
- * * [_onSubscriberStateChange]: Called when receiving the first subscriber or
- * when losing the last subscriber.
- * * [_onPauseStateChange]: Called when entering or leaving paused mode.
- * * [_hasListener]: Test whether there are currently any subscribers.
- * * [_isInputPaused]: Test whether the stream is currently paused.
- * The user should not add new events while the stream is paused, but if it
- * happens anyway, the stream will enqueue the events just as when new events
- * arrive while still firing an old event.
+ * * [_onCancel]: Called when the subscription will provide no more events,
+ * either due to being actively canceled, or after sending a done event.
+ * * [_onPause]: Called when the subscription wants the event source to pause.
+ * * [_onResume]: Called when allowing new events after a pause.
+ * The user should not add new events when the subscription requests a paused,
+ * but if it happens anyway, the subscription will enqueue the events just as
+ * when new events arrive while still firing an old event.
*/
-class _SingleStreamImpl<T> extends _StreamImpl<T> {
- _StreamListener _subscriber = null;
-
- /** Whether there is currently a subscriber on this [Stream]. */
- bool get _hasListener => _subscriber != null;
-
- // -------------------------------------------------------------------
- // Internal implementation.
-
- _SingleStreamImpl() {
- // Start out paused.
- _updatePauseCount(1);
- }
-
+class _BufferingStreamSubscription<T> implements StreamSubscription<T>,
+ _EventSink<T>,
+ _EventDispatch<T> {
+ /** The `cancelOnError` flag from the `listen` call. */
+ static const int _STATE_CANCEL_ON_ERROR = 1;
/**
- * Create the new subscription object.
+ * Whether the "done" event has been received.
+ * No further events are accepted after this.
*/
- _StreamSubscriptionImpl<T> _createSubscription(
- void onData(T data),
- void onError(error),
- void onDone(),
- bool cancelOnError) {
- return new _StreamSubscriptionImpl<T>(
- this, onData, onError, onDone, cancelOnError);
- }
-
- void _addListener(_StreamListener subscription) {
- assert(!_isComplete);
- if (_hasListener) {
- throw new StateError("Stream already has subscriber.");
- }
- assert(_pauseCount == 1);
- _updatePauseCount(-1);
- _subscriber = subscription;
- subscription._setSubscribed(0);
- if (_isInactive) {
- _checkCallbacks(false, true);
- if (!_isPaused && _hasPendingEvent) {
- _schedulePendingEvents();
- }
- }
- }
-
+ static const int _STATE_CLOSED = 2;
/**
- * Handle a cancel requested from a [_StreamSubscriptionImpl].
+ * Set if the input has been asked not to send events.
*
- * This method is called from [_StreamSubscriptionImpl.cancel].
+ * This is not the same as being paused, since the input will remain paused
+ * after a call to [resume] if there are pending events.
*/
- void _cancel(_StreamListener subscriber) {
- assert(identical(subscriber._source, this));
- // We allow unsubscribing the currently firing subscription during
- // the event firing, because it is indistinguishable from delaying it since
- // that event has already received the event.
- if (!identical(_subscriber, subscriber)) {
- // You may unsubscribe more than once, only the first one counts.
- return;
- }
- _subscriber = null;
- // Unsubscribing a paused subscription also cancels its pauses.
- int resumeCount = subscriber._setUnsubscribed();
- // Keep being paused while there is no subscriber and the stream is not
- // complete.
- _updatePauseCount(_isComplete ? -resumeCount : -resumeCount + 1);
- if (_isInactive) {
- _checkCallbacks(true, resumeCount > 0);
- if (!_isPaused && _hasPendingEvent) {
- _schedulePendingEvents();
- }
- }
- }
-
- void _forEachSubscriber(
- void action(_StreamListener<T> subscription)) {
- assert(!_isPaused);
- bool wasInputPaused = _isInputPaused;
- _StreamListener subscription = _subscriber;
- assert(subscription != null);
- _startFiring();
- action(subscription);
- _endFiring(wasInputPaused);
- }
-}
-
-// -------------------------------------------------------------------
-// Default implementation of a stream with subscribers.
-// -------------------------------------------------------------------
-
-/**
- * Default implementation of stream capable of sending events to subscribers.
- *
- * Any class needing to implement [Stream] can either directly extend this
- * class, or extend [Stream] and delegate the subscribe method to an instance
- * of this class.
- *
- * The only public methods are those of [Stream], so instances of
- * [_MultiStreamImpl] can be returned directly as a [Stream] without exposing
- * internal functionality.
- *
- * The [StreamController] is a public facing version of this class, with
- * some methods made public.
- *
- * The user interface of [_MultiStreamImpl] are the following methods:
- * * [_add]: Add a data event to the stream.
- * * [_addError]: Add an error event to the stream.
- * * [_close]: Request to close the stream.
- * * [_onSubscriptionStateChange]: Called when receiving the first subscriber or
- * when losing the last subscriber.
- * * [_onPauseStateChange]: Called when entering or leaving paused mode.
- * * [_hasListener]: Test whether there are currently any subscribers.
- * * [_isPaused]: Test whether the stream is currently paused.
- * The user should not add new events while the stream is paused, but if it
- * happens anyway, the stream will enqueue the events just as when new events
- * arrive while still firing an old event.
- */
-class _MultiStreamImpl<T> extends _StreamImpl<T>
- implements _InternalLinkList {
- // Link list implementation (mixin when possible).
- _InternalLink _nextLink;
- _InternalLink _previousLink;
-
- _MultiStreamImpl() {
- _nextLink = _previousLink = this;
- }
-
- bool get isBroadcast => true;
-
- Stream<T> asBroadcastStream() => this;
-
- // ------------------------------------------------------------------
- // Helper functions that can be overridden in subclasses.
-
- /** Whether there are currently any subscribers on this [Stream]. */
- bool get _hasListener => !_InternalLinkList.isEmpty(this);
-
+ static const int _STATE_INPUT_PAUSED = 4;
/**
- * Create the new subscription object.
+ * Whether the subscription has been canceled.
+ *
+ * Set by calling [cancel], or by handling a "done" event, or an "error" event
+ * when `cancelOnError` is true.
*/
- _StreamListener<T> _createSubscription(
- void onData(T data),
- void onError(error),
- void onDone(),
- bool cancelOnError) {
- return new _StreamSubscriptionImpl<T>(
- this, onData, onError, onDone, cancelOnError);
- }
+ static const int _STATE_CANCELED = 8;
+ static const int _STATE_IN_CALLBACK = 16;
+ static const int _STATE_HAS_PENDING = 32;
+ static const int _STATE_PAUSE_COUNT = 64;
+ static const int _STATE_PAUSE_COUNT_SHIFT = 6;
- // -------------------------------------------------------------------
- // Internal implementation.
-
- /**
- * Iterate over all current subscribers and perform an action on each.
- *
- * The set of subscribers cannot be modified during this iteration.
- * All attempts to add or unsubscribe subscribers will be delayed until
- * after the iteration is complete.
- *
- * The [action] must not throw, or the controller will be left in an
- * invalid state.
- *
- * This method must not be called while [isFiring] is true.
- */
- void _forEachSubscriber(
- void action(_StreamListener<T> subscription)) {
- assert(!_isFiring);
- if (!_hasListener) return;
- bool wasInputPaused = _isInputPaused;
- _startFiring();
- _InternalLink cursor = this._nextLink;
- while (!identical(cursor, this)) {
- _StreamListener<T> current = cursor;
- if (current._needsEvent(_currentEventIdBit)) {
- action(current);
- // Marks as having received the event.
- current._toggleEventReceived();
- }
- cursor = current._nextLink;
- if (current._isPendingUnsubscribe) {
- _removeListener(current);
- }
- }
- _endFiring(wasInputPaused);
- }
-
- void _addListener(_StreamListener listener) {
- listener._setSubscribed(_currentEventIdBit);
- bool hadListener = _hasListener;
- _InternalLinkList.add(this, listener);
- if (!hadListener && _isInactive) {
- _checkCallbacks(false, false);
- if (!_isPaused && _hasPendingEvent) {
- _schedulePendingEvents();
- }
- }
- }
-
- /**
- * Handle a cancel requested from a [_StreamListener].
- *
- * This method is called from [_StreamListener.cancel].
- *
- * If an event is currently firing, the cancel is delayed
- * until after the subscribers have received the event.
- */
- void _cancel(_StreamListener listener) {
- assert(identical(listener._source, this));
- if (_InternalLink.isUnlinked(listener)) {
- // You may unsubscribe more than once, only the first one counts.
- return;
- }
- if (_isFiring) {
- if (listener._needsEvent(_currentEventIdBit)) {
- assert(listener._isSubscribed);
- listener._setPendingUnsubscribe(_currentEventIdBit);
- } else {
- // The listener has been notified of the event (or don't need to,
- // if it's still pending subscription) so it's safe to remove it.
- _removeListener(listener);
- }
- // Pause and subscription state changes are reported when we end
- // firing.
- } else {
- bool wasInputPaused = _isInputPaused;
- _removeListener(listener);
- if (_isInactive) {
- _checkCallbacks(true, wasInputPaused);
- if (!_isPaused && _hasPendingEvent) {
- _schedulePendingEvents();
- }
- }
- }
- }
-
- /**
- * Removes a listener from this stream and cancels its pauses.
- *
- * This is a low-level action that doesn't call [_onSubscriptionStateChange].
- * or [_callOnPauseStateChange].
- */
- void _removeListener(_StreamListener listener) {
- int pauseCount = listener._setUnsubscribed();
- _InternalLinkList.remove(listener);
- if (pauseCount > 0) {
- _updatePauseCount(-pauseCount);
- if (!_isPaused && _hasPendingEvent) {
- _state |= _STREAM_PENDING_RESUME;
- }
- }
- }
-}
-
-
-/** Stream that generates its own events. */
-class _GeneratedSingleStreamImpl<T> extends _SingleStreamImpl<T> {
- /**
- * Initializes the stream to have only the events provided by [events].
- *
- * A [_PendingEvents] implementation provides events that are handled
- * by calling [_PendingEvents.handleNext] with the [_StreamImpl].
- */
- _GeneratedSingleStreamImpl(_PendingEvents events) {
- _pendingEvents = events;
- _setClosed(); // Closed for input since all events are already pending.
- }
-
- void _add(T value) {
- throw new UnsupportedError("Cannot inject events into generated stream");
- }
-
- void _addError(value) {
- throw new UnsupportedError("Cannot inject events into generated stream");
- }
-
- void _close() {
- throw new UnsupportedError("Cannot inject events into generated stream");
- }
-}
-
-
-/** Pending events object that gets its events from an [Iterable]. */
-class _IterablePendingEvents<T> extends _PendingEvents {
- final Iterator<T> _iterator;
- /**
- * Whether there are no more events to be sent.
- *
- * This starts out as [:false:] since there is always at least
- * a 'done' event to be sent.
- */
- bool _isDone = false;
-
- _IterablePendingEvents(Iterable<T> data) : _iterator = data.iterator;
-
- bool get isEmpty => _isDone;
-
- void handleNext(_StreamImpl<T> stream) {
- if (_isDone) throw new StateError("No events pending.");
- try {
- _isDone = !_iterator.moveNext();
- if (!_isDone) {
- stream._sendData(_iterator.current);
- } else {
- stream._sendDone();
- }
- } catch (e, s) {
- stream._sendError(_asyncError(e, s));
- stream._sendDone();
- _isDone = true;
- }
- }
-}
-
-
-/**
- * The subscription class that the [StreamController] uses.
- *
- * The [_StreamImpl.createSubscription] method should
- * create an object of this type, or another subclass of [_StreamListener].
- * A subclass of [_StreamImpl] can specify which subclass
- * of [_StreamSubscriptionImpl] it uses by overriding
- * [_StreamImpl.createSubscription].
- *
- * The subscription is in one of three states:
- * * Subscribed.
- * * Paused-and-subscribed.
- * * Unsubscribed.
- * Unsubscribing also resumes any pauses started by the subscription.
- */
-class _StreamSubscriptionImpl<T> extends _StreamListener<T>
- implements StreamSubscription<T> {
- final bool _cancelOnError;
- // TODO(ahe): Restore type when feature is implemented in dart2js
- // checked mode. http://dartbug.com/7733
- var /* _DataHandler<T> */ _onData;
+ /* Event handlers provided in constructor. */
+ /* TODO(7733): Fix Function->_DataHandler<T> when dart2js understands
+ * parameterized function types. */
+ Function _onData;
_ErrorHandler _onError;
_DoneHandler _onDone;
- _StreamSubscriptionImpl(_StreamImpl source,
- this._onData,
- this._onError,
- this._onDone,
- this._cancelOnError) : super(source);
+
+ /** Bit vector based on state-constants above. */
+ int _state;
+
+ /**
+ * Queue of pending events.
+ *
+ * Is created when necessary, or set in constructor for preconfigured events.
+ */
+ _PendingEvents _pending;
+
+ _BufferingStreamSubscription(this._onData,
+ this._onError,
+ this._onDone,
+ bool cancelOnError)
+ : _state = (cancelOnError ? _STATE_CANCEL_ON_ERROR : 0) {
+ assert(_onData != null);
+ assert(_onError != null);
+ assert(_onDone != null);
+ }
+
+ /**
+ * Sets the subscription's pending events object.
+ *
+ * This can only be done once. The pending events object is used for the
+ * rest of the subscription's life cycle.
+ */
+ void _setPendingEvents(_PendingEvents pendingEvents) {
+ assert(_pending == null);
+ if (pendingEvents == null) return;
+ _pending = pendingEvents;
+ if (!pendingEvents.isEmpty) {
+ _state |= _STATE_HAS_PENDING;
+ _pending.schedule(this);
+ }
+ }
+
+ /**
+ * Extracts the pending events from a canceled stream.
+ *
+ * This can only be done during the [_onCancel] method call. After that,
+ * any remaining pending events will be cleared.
+ */
+ _PendingEvents _extractPending() {
+ assert(_isCanceled);
+ _PendingEvents events = _pending;
+ _pending = null;
+ return events;
+ }
+
+ // StreamSubscription interface.
void onData(void handleData(T event)) {
if (handleData == null) handleData = _nullDataHandler;
@@ -936,48 +163,381 @@
_onDone = handleDone;
}
- void _sendData(T data) {
- _onData(data);
- }
-
- void _sendError(error) {
- _onError(error);
- if (_cancelOnError) _source._cancel(this);
- }
-
- void _sendDone() {
- _onDone();
- }
-
- void cancel() {
- if (!_isSubscribed) return;
- _source._cancel(this);
- }
-
void pause([Future resumeSignal]) {
- if (!_isSubscribed) return;
- _source._pause(this, resumeSignal);
+ if (_isCanceled) return;
+ bool wasPaused = _isPaused;
+ bool wasInputPaused = _isInputPaused;
+ // Increment pause count and mark input paused (if it isn't already).
+ _state = (_state + _STATE_PAUSE_COUNT) | _STATE_INPUT_PAUSED;
+ if (resumeSignal != null) resumeSignal.whenComplete(resume);
+ if (!wasPaused && _pending != null) _pending.cancelSchedule();
+ if (!wasInputPaused && !_inCallback) _guardCallback(_onPause);
}
void resume() {
- if (!_isSubscribed || !isPaused) return;
- _source._resume(this, false);
+ if (_isCanceled) return;
+ if (_isPaused) {
+ _decrementPauseCount();
+ if (!_isPaused) {
+ if (_hasPending && !_pending.isEmpty) {
+ // Input is still paused.
+ _pending.schedule(this);
+ } else {
+ assert(_mayResumeInput);
+ _state &= ~_STATE_INPUT_PAUSED;
+ if (!_inCallback) _guardCallback(_onResume);
+ }
+ }
+ }
+ }
+
+ void cancel() {
+ if (_isCanceled) return;
+ _cancel();
+ if (!_inCallback) {
+ // otherwise checkState will be called after firing or callback completes.
+ _state |= _STATE_IN_CALLBACK;
+ _onCancel();
+ _pending = null;
+ _state &= ~_STATE_IN_CALLBACK;
+ }
}
Future asFuture([var futureValue]) {
_FutureImpl<T> result = new _FutureImpl<T>();
// Overwrite the onDone and onError handlers.
- onDone(() { result._setValue(futureValue); });
- onError((error) {
+ _onDone = () { result._setValue(futureValue); };
+ _onError = (error) {
cancel();
result._setError(error);
- });
+ };
return result;
}
+
+ // State management.
+
+ bool get _isInputPaused => (_state & _STATE_INPUT_PAUSED) != 0;
+ bool get _isClosed => (_state & _STATE_CLOSED) != 0;
+ bool get _isCanceled => (_state & _STATE_CANCELED) != 0;
+ bool get _inCallback => (_state & _STATE_IN_CALLBACK) != 0;
+ bool get _hasPending => (_state & _STATE_HAS_PENDING) != 0;
+ bool get _isPaused => _state >= _STATE_PAUSE_COUNT;
+ bool get _canFire => _state < _STATE_IN_CALLBACK;
+ bool get _mayResumeInput =>
+ !_isPaused && (_pending == null || _pending.isEmpty);
+ bool get _cancelOnError => (_state & _STATE_CANCEL_ON_ERROR) != 0;
+
+ bool get isPaused => _isPaused;
+
+ void _cancel() {
+ _state |= _STATE_CANCELED;
+ if (_hasPending) {
+ _pending.cancelSchedule();
+ }
+ }
+
+ /**
+ * Increment the pause count.
+ *
+ * Also marks input as paused.
+ */
+ void _incrementPauseCount() {
+ _state = (_state + _STATE_PAUSE_COUNT) | _STATE_INPUT_PAUSED;
+ }
+
+ /**
+ * Decrements the pause count.
+ *
+ * Does not automatically unpause the input (call [_onResume]) when
+ * the pause count reaches zero. This is handled elsewhere, and only
+ * if there are no pending events buffered.
+ */
+ void _decrementPauseCount() {
+ assert(_isPaused);
+ _state -= _STATE_PAUSE_COUNT;
+ }
+
+ // _EventSink interface.
+
+ void _add(T data) {
+ assert(!_isClosed);
+ if (_isCanceled) return;
+ if (_canFire) {
+ _sendData(data);
+ } else {
+ _addPending(new _DelayedData(data));
+ }
+ }
+
+ void _addError(Object error) {
+ if (_isCanceled) return;
+ if (_canFire) {
+ _sendError(error); // Reports cancel after sending.
+ } else {
+ _addPending(new _DelayedError(error));
+ }
+ }
+
+ void _close() {
+ assert(!_isClosed);
+ if (_isCanceled) return;
+ _state |= _STATE_CLOSED;
+ if (_canFire) {
+ _sendDone();
+ } else {
+ _addPending(const _DelayedDone());
+ }
+ }
+
+ // Hooks called when the input is paused, unpaused or canceled.
+ // These must not throw. If overwritten to call user code, include suitable
+ // try/catch wrapping and send any errors to [_throwDelayed].
+ void _onPause() {
+ assert(_isInputPaused);
+ }
+
+ void _onResume() {
+ assert(!_isInputPaused);
+ }
+
+ void _onCancel() {
+ assert(_isCanceled);
+ }
+
+ // Handle pending events.
+
+ /**
+ * Add a pending event.
+ *
+ * If the subscription is not paused, this also schedules a firing
+ * of pending events later (if necessary).
+ */
+ void _addPending(_DelayedEvent event) {
+ _StreamImplEvents pending = _pending;
+ if (_pending == null) pending = _pending = new _StreamImplEvents();
+ pending.add(event);
+ if (!_hasPending) {
+ _state |= _STATE_HAS_PENDING;
+ if (!_isPaused) {
+ _pending.schedule(this);
+ }
+ }
+ }
+
+ /* _EventDispatch interface. */
+
+ void _sendData(T data) {
+ assert(!_isCanceled);
+ assert(!_isPaused);
+ assert(!_inCallback);
+ bool wasInputPaused = _isInputPaused;
+ _state |= _STATE_IN_CALLBACK;
+ try {
+ _onData(data);
+ } catch (e, s) {
+ _throwDelayed(e, s);
+ }
+ _state &= ~_STATE_IN_CALLBACK;
+ _checkState(wasInputPaused);
+ }
+
+ void _sendError(var error) {
+ assert(!_isCanceled);
+ assert(!_isPaused);
+ assert(!_inCallback);
+ bool wasInputPaused = _isInputPaused;
+ _state |= _STATE_IN_CALLBACK;
+ try {
+ _onError(error);
+ } catch (e, s) {
+ _throwDelayed(e, s);
+ }
+ _state &= ~_STATE_IN_CALLBACK;
+ if (_cancelOnError) {
+ _cancel();
+ }
+ _checkState(wasInputPaused);
+ }
+
+ void _sendDone() {
+ assert(!_isCanceled);
+ assert(!_isPaused);
+ assert(!_inCallback);
+ _state |= (_STATE_CANCELED | _STATE_CLOSED | _STATE_IN_CALLBACK);
+ try {
+ _onDone();
+ } catch (e, s) {
+ _throwDelayed(e, s);
+ }
+ _onCancel(); // No checkState after cancel, it is always the last event.
+ _state &= ~_STATE_IN_CALLBACK;
+ }
+
+ /**
+ * Call a hook function.
+ *
+ * The call is properly wrapped in code to avoid other callbacks
+ * during the call, and it checks for state changes after the call
+ * that should cause further callbacks.
+ */
+ void _guardCallback(callback) {
+ assert(!_inCallback);
+ bool wasInputPaused = _isInputPaused;
+ _state |= _STATE_IN_CALLBACK;
+ callback();
+ _state &= ~_STATE_IN_CALLBACK;
+ _checkState(wasInputPaused);
+ }
+
+ /**
+ * Check if the input needs to be informed of state changes.
+ *
+ * State changes are pausing, resuming and canceling.
+ *
+ * After canceling, no further callbacks will happen.
+ *
+ * The cancel callback is called after a user cancel, or after
+ * the final done event is sent.
+ */
+ void _checkState(bool wasInputPaused) {
+ assert(!_inCallback);
+ if (_hasPending && _pending.isEmpty) {
+ _state &= ~_STATE_HAS_PENDING;
+ if (_isInputPaused && _mayResumeInput) {
+ _state &= ~_STATE_INPUT_PAUSED;
+ }
+ }
+ // If the state changes during a callback, we immediately
+ // make a new state-change callback. Loop until the state didn't change.
+ while (true) {
+ if (_isCanceled) {
+ _onCancel();
+ _pending = null;
+ return;
+ }
+ bool isInputPaused = _isInputPaused;
+ if (wasInputPaused == isInputPaused) break;
+ _state ^= _STATE_IN_CALLBACK;
+ if (isInputPaused) {
+ _onPause();
+ } else {
+ _onResume();
+ }
+ _state &= ~_STATE_IN_CALLBACK;
+ wasInputPaused = isInputPaused;
+ }
+ if (_hasPending && !_isPaused) {
+ _pending.schedule(this);
+ }
+ }
}
+// -------------------------------------------------------------------
+// Common base class for single and multi-subscription streams.
+// -------------------------------------------------------------------
+abstract class _StreamImpl<T> extends Stream<T> {
+ // ------------------------------------------------------------------
+ // Stream interface.
+
+ StreamSubscription<T> listen(void onData(T data),
+ { void onError(error),
+ void onDone(),
+ bool cancelOnError }) {
+ if (onData == null) onData = _nullDataHandler;
+ if (onError == null) onError = _nullErrorHandler;
+ if (onDone == null) onDone = _nullDoneHandler;
+ cancelOnError = identical(true, cancelOnError);
+ StreamSubscription subscription =
+ _createSubscription(onData, onError, onDone, cancelOnError);
+ _onListen(subscription);
+ return subscription;
+ }
+
+ // -------------------------------------------------------------------
+ /** Create a subscription object. Called by [subcribe]. */
+ _BufferingStreamSubscription<T> _createSubscription(
+ void onData(T data),
+ void onError(error),
+ void onDone(),
+ bool cancelOnError) {
+ return new _BufferingStreamSubscription<T>(
+ onData, onError, onDone, cancelOnError);
+ }
+
+ /** Hook called when the subscription has been created. */
+ void _onListen(StreamSubscription subscription) {}
+}
+
+typedef _PendingEvents _EventGenerator();
+
+/** Stream that generates its own events. */
+class _GeneratedStreamImpl<T> extends _StreamImpl<T> {
+ final _EventGenerator _pending;
+ /**
+ * Initializes the stream to have only the events provided by a
+ * [_PendingEvents].
+ *
+ * A new [_PendingEvents] must be generated for each listen.
+ */
+ _GeneratedStreamImpl(this._pending);
+
+ StreamSubscription _createSubscription(void onData(T data),
+ void onError(Object error),
+ void onDone(),
+ bool cancelOnError) {
+ _BufferingStreamSubscription<T> subscription =
+ new _BufferingStreamSubscription(
+ onData, onError, onDone, cancelOnError);
+ subscription._setPendingEvents(_pending());
+ return subscription;
+ }
+}
+
+
+/** Pending events object that gets its events from an [Iterable]. */
+class _IterablePendingEvents<T> extends _PendingEvents {
+ // The iterator providing data for data events.
+ // Set to null when iteration has completed.
+ Iterator<T> _iterator;
+
+ _IterablePendingEvents(Iterable<T> data) : _iterator = data.iterator;
+
+ bool get isEmpty => _iterator == null;
+
+ void handleNext(_EventDispatch dispatch) {
+ if (_iterator == null) {
+ throw new StateError("No events pending.");
+ }
+ // Send one event per call to moveNext.
+ // If moveNext returns true, send the current element as data.
+ // If moveNext returns false, send a done event and clear the _iterator.
+ // If moveNext throws an error, send an error and clear the _iterator.
+ // After an error, no further events will be sent.
+ bool isDone;
+ try {
+ isDone = !_iterator.moveNext();
+ } catch (e, s) {
+ _iterator = null;
+ dispatch._sendError(_asyncError(e, s));
+ return;
+ }
+ if (!isDone) {
+ dispatch._sendData(_iterator.current);
+ } else {
+ _iterator = null;
+ dispatch._sendDone();
+ }
+ }
+
+ void clear() {
+ if (isScheduled) cancelSchedule();
+ _iterator = null;
+ }
+}
+
+
// Internal helpers.
// Types of the different handlers on a stream. Types used to type fields.
@@ -998,20 +558,20 @@
void _nullDoneHandler() {}
-/** A delayed event on a stream implementation. */
+/** A delayed event on a buffering stream subscription. */
abstract class _DelayedEvent {
/** Added as a linked list on the [StreamController]. */
_DelayedEvent next;
/** Execute the delayed event on the [StreamController]. */
- void perform(_StreamImpl stream);
+ void perform(_EventDispatch dispatch);
}
/** A delayed data event. */
class _DelayedData<T> extends _DelayedEvent{
final T value;
_DelayedData(this.value);
- void perform(_StreamImpl<T> stream) {
- stream._sendData(value);
+ void perform(_EventDispatch<T> dispatch) {
+ dispatch._sendData(value);
}
}
@@ -1019,16 +579,16 @@
class _DelayedError extends _DelayedEvent {
final error;
_DelayedError(this.error);
- void perform(_StreamImpl stream) {
- stream._sendError(error);
+ void perform(_EventDispatch dispatch) {
+ dispatch._sendError(error);
}
}
/** A delayed done event. */
class _DelayedDone implements _DelayedEvent {
const _DelayedDone();
- void perform(_StreamImpl stream) {
- stream._sendDone();
+ void perform(_EventDispatch dispatch) {
+ dispatch._sendDone();
}
_DelayedEvent get next => null;
@@ -1038,198 +598,66 @@
}
}
-/**
- * Simple internal doubly-linked list implementation.
- *
- * In an internal linked list, the links are in the data objects themselves,
- * instead of in a separate object. That means each element can be in at most
- * one list at a time.
- *
- * All links are always members of an element cycle. At creation it's a
- * singleton cycle.
- */
-abstract class _InternalLink {
- _InternalLink _nextLink;
- _InternalLink _previousLink;
-
- _InternalLink() {
- this._previousLink = this._nextLink = this;
- }
-
- /* Removes a link from any list it may be part of, and links it to itself. */
- static void unlink(_InternalLink element) {
- _InternalLink next = element._nextLink;
- _InternalLink previous = element._previousLink;
- next._previousLink = previous;
- previous._nextLink = next;
- element._nextLink = element._previousLink = element;
- }
-
- /** Check whether an element is unattached to other elements. */
- static bool isUnlinked(_InternalLink element) {
- return identical(element, element._nextLink);
- }
-}
-
-/**
- * Marker interface for "list" links.
- *
- * An "InternalLinkList" is an abstraction on top of a link cycle, where the
- * "list" object itself is not considered an element (it's just a header link
- * created to avoid edge cases).
- * An element is considered part of a list if it is in the list's cycle.
- * There should never be more than one "list" object in a cycle.
- */
-abstract class _InternalLinkList extends _InternalLink {
- /**
- * Adds an element to a list, just before the header link.
- *
- * This effectively adds it at the end of the list.
- */
- static void add(_InternalLinkList list, _InternalLink element) {
- if (!_InternalLink.isUnlinked(element)) _InternalLink.unlink(element);
- _InternalLink listEnd = list._previousLink;
- listEnd._nextLink = element;
- list._previousLink = element;
- element._previousLink = listEnd;
- element._nextLink = list;
- }
-
- /** Removes an element from its list. */
- static void remove(_InternalLink element) {
- _InternalLink.unlink(element);
- }
-
- /** Check whether a list contains no elements, only the header link. */
- static bool isEmpty(_InternalLinkList list) => _InternalLink.isUnlinked(list);
-
- /** Moves all elements from the list [other] to [list]. */
- static void addAll(_InternalLinkList list, _InternalLinkList other) {
- if (isEmpty(other)) return;
- _InternalLink listLast = list._previousLink;
- _InternalLink otherNext = other._nextLink;
- listLast._nextLink = otherNext;
- otherNext._previousLink = listLast;
- _InternalLink otherLast = other._previousLink;
- list._previousLink = otherLast;
- otherLast._nextLink = list;
- // Clean up [other].
- other._nextLink = other._previousLink = other;
- }
-}
-
-/** Abstract type for an internal interface for sending events. */
-abstract class _EventOutputSink<T> {
- _sendData(T data);
- _sendError(error);
- _sendDone();
-}
-
-abstract class _StreamListener<T> extends _InternalLink
- implements _EventOutputSink<T> {
- final _StreamImpl _source;
- int _state = _LISTENER_UNSUBSCRIBED;
-
- _StreamListener(this._source);
-
- bool get isPaused => _state >= (1 << _LISTENER_PAUSE_COUNT_SHIFT);
-
- bool get _isPendingUnsubscribe =>
- (_state & _LISTENER_PENDING_UNSUBSCRIBE) != 0;
-
- bool get _isSubscribed => (_state & _LISTENER_SUBSCRIBED) != 0;
-
- /**
- * Whether the listener still needs to receive the currently firing event.
- *
- * The currently firing event is identified by a single bit, which alternates
- * between events. The [_state] contains the previously sent event's bit in
- * the [_LISTENER_EVENT_ID] bit. If the two don't match, this listener
- * still need the current event.
- */
- bool _needsEvent(int currentEventIdBit) {
- int lastEventIdBit =
- (_state & _LISTENER_EVENT_ID) >> _LISTENER_EVENT_ID_SHIFT;
- return lastEventIdBit != currentEventIdBit;
- }
-
- /// If a subscriber's "firing bit" doesn't match the stream's firing bit,
- /// we are currently firing an event and the subscriber still need to receive
- /// the event.
- void _toggleEventReceived() {
- _state ^= _LISTENER_EVENT_ID;
- }
-
- void _setSubscribed(int eventIdBit) {
- assert(eventIdBit == 0 || eventIdBit == 1);
- _state = _LISTENER_SUBSCRIBED | (eventIdBit << _LISTENER_EVENT_ID_SHIFT);
- }
-
- void _setPendingUnsubscribe(int currentEventIdBit) {
- assert(_isSubscribed);
- // Sets the pending unsubscribe, and ensures that the listener
- // won't get the current event.
- _state |= _LISTENER_PENDING_UNSUBSCRIBE | _LISTENER_EVENT_ID;
- _state ^= (1 ^ currentEventIdBit) << _LISTENER_EVENT_ID_SHIFT;
- assert(!_needsEvent(currentEventIdBit));
- }
-
- /**
- * Marks the listener as unsubscibed.
- *
- * Returns the number of unresumed pauses for the listener.
- */
- int _setUnsubscribed() {
- assert(_isSubscribed);
- int timesPaused = _state >> _LISTENER_PAUSE_COUNT_SHIFT;
- _state = _LISTENER_UNSUBSCRIBED;
- return timesPaused;
- }
-
- void _incrementPauseCount() {
- _state += 1 << _LISTENER_PAUSE_COUNT_SHIFT;
- }
-
- void _decrementPauseCount() {
- assert(isPaused);
- _state -= 1 << _LISTENER_PAUSE_COUNT_SHIFT;
- }
-
- _sendData(T data);
- _sendError(error);
- _sendDone();
-}
-
/** Superclass for provider of pending events. */
abstract class _PendingEvents {
+ // No async event has been scheduled.
+ static const int _STATE_UNSCHEDULED = 0;
+ // An async event has been scheduled to run a function.
+ static const int _STATE_SCHEDULED = 1;
+ // An async event has been scheduled, but it will do nothing when it runs.
+ // Async events can't be preempted.
+ static const int _STATE_CANCELED = 3;
+
/**
- * Timer set when pending events are scheduled for execution.
+ * State of being scheduled.
*
- * When scheduling pending events for execution in a later cycle, the timer
- * is stored here. If pending events are executed earlier than that, e.g.,
- * due to a second event in the current cycle, the timer is canceled again.
+ * Set to [_STATE_SCHEDULED] when pending events are scheduled for
+ * async dispatch. Since we can't cancel a [runAsync] call, if schduling
+ * is "canceled", the _state is simply set to [_STATE_CANCELED] which will
+ * make the async code do nothing except resetting [_state].
+ *
+ * If events are scheduled while the state is [_STATE_CANCELED], it is
+ * merely switched back to [_STATE_SCHEDULED], but no new call to [runAsync]
+ * is performed.
*/
- Timer scheduleTimer = null;
+ int _state = _STATE_UNSCHEDULED;
bool get isEmpty;
- bool get isScheduled => scheduleTimer != null;
+ bool get isScheduled => _state == _STATE_SCHEDULED;
+ bool get _eventScheduled => _state >= _STATE_SCHEDULED;
- void schedule(_StreamImpl stream) {
+ /**
+ * Schedule an event to run later.
+ *
+ * If called more than once, it should be called with the same dispatch as
+ * argument each time. It may reuse an earlier argument in some cases.
+ */
+ void schedule(_EventDispatch dispatch) {
if (isScheduled) return;
- scheduleTimer = new Timer(Duration.ZERO, () {
- scheduleTimer = null;
- stream._handlePendingEvents();
+ assert(!isEmpty);
+ if (_eventScheduled) {
+ assert(_state == _STATE_CANCELED);
+ _state = _STATE_SCHEDULED;
+ return;
+ }
+ runAsync(() {
+ int oldState = _state;
+ _state = _STATE_UNSCHEDULED;
+ if (oldState == _STATE_CANCELED) return;
+ handleNext(dispatch);
});
+ _state = _STATE_SCHEDULED;
}
void cancelSchedule() {
- assert(isScheduled);
- scheduleTimer.cancel();
- scheduleTimer = null;
+ if (isScheduled) _state = _STATE_CANCELED;
}
- void handleNext(_StreamImpl stream);
+ void handleNext(_EventDispatch dispatch);
+
+ /** Throw away any pending events and cancel scheduled events. */
+ void clear();
}
@@ -1242,8 +670,6 @@
bool get isEmpty => lastPendingEvent == null;
- bool get isScheduled => scheduleTimer != null;
-
void add(_DelayedEvent event) {
if (lastPendingEvent == null) {
firstPendingEvent = lastPendingEvent = event;
@@ -1252,122 +678,224 @@
}
}
- void handleNext(_StreamImpl stream) {
+ void handleNext(_EventDispatch dispatch) {
assert(!isScheduled);
_DelayedEvent event = firstPendingEvent;
firstPendingEvent = event.next;
if (firstPendingEvent == null) {
lastPendingEvent = null;
}
- event.perform(stream);
+ event.perform(dispatch);
+ }
+
+ void clear() {
+ if (isScheduled) cancelSchedule();
+ firstPendingEvent = lastPendingEvent = null;
}
}
+class _MultiplexerLinkedList {
+ _MultiplexerLinkedList _next;
+ _MultiplexerLinkedList _previous;
-class _DoneSubscription<T> implements StreamSubscription<T> {
- _DoneHandler _handler;
- Timer _timer;
- int _pauseCount = 0;
-
- _DoneSubscription(this._handler) {
- _delayDone();
+ void _unlink() {
+ _previous._next = _next;
+ _next._previous = _previous;
+ _next = _previous = this;
}
- void _delayDone() {
- assert(_timer == null && _pauseCount == 0);
- _timer = new Timer(Duration.ZERO, () {
- if (_handler != null) _handler();
- });
- }
-
- bool get _isComplete => _timer == null && _pauseCount == 0;
-
- void onData(void handleAction(T value)) {}
-
- void onError(void handleError(error)) {}
-
- void onDone(void handleDone()) {
- _handler = handleDone;
- }
-
- void pause([Future signal]) {
- if (_isComplete) return;
- if (_timer != null) {
- _timer.cancel();
- _timer = null;
- }
- _pauseCount++;
- if (signal != null) signal.whenComplete(resume);
- }
-
- void resume() {
- if (_isComplete) return;
- if (_pauseCount == 0) return;
- _pauseCount--;
- if (_pauseCount == 0) {
- _delayDone();
- }
- }
-
- bool get isPaused => _pauseCount > 0;
-
- void cancel() {
- if (_isComplete) return;
- if (_timer != null) {
- _timer.cancel();
- _timer = null;
- }
- _pauseCount = 0;
- }
-
- Future asFuture([var futureValue]) {
- // TODO(floitsch): share more code.
- _FutureImpl<T> result = new _FutureImpl<T>();
-
- // Overwrite the onDone and onError handlers.
- onDone(() { result._setValue(futureValue); });
- onError((error) {
- cancel();
- result._setError(error);
- });
-
- return result;
+ void _insertBefore(_MultiplexerLinkedList newNext) {
+ _MultiplexerLinkedList newPrevious = newNext._previous;
+ newPrevious._next = this;
+ newNext._previous = _previous;
+ _previous._next = newNext;
+ _previous = newPrevious;
}
}
-class _SingleStreamMultiplexer<T> extends _MultiStreamImpl<T> {
+class _AsBroadcastStream<T> extends Stream<T> {
final Stream<T> _source;
+ _BufferingMultiplexStreamController<T> _controller;
StreamSubscription<T> _subscription;
- _SingleStreamMultiplexer(this._source);
+ _AsBroadcastStream(this._source) {
+ _controller = new _BufferingMultiplexStreamController<T>(null, _onCancel);
+ }
- void _callOnPauseStateChange() {
- if (_isPaused) {
- if (_subscription != null) {
- _subscription.pause();
- }
+ bool get isBroadcast => true;
+
+ StreamSubscription<T> listen(void onData(T data),
+ { void onError(Object error),
+ void onDone(),
+ bool cancelOnError}) {
+ if (_controller == null) {
+ throw new StateError("Source stream has been closed.");
+ }
+ if (_subscription == null) {
+ _subscription = _source.listen(_controller.add,
+ onError: _controller.addError,
+ onDone: _controller.close);
+ }
+ return _controller.stream.listen(onData, onError: onError, onDone: onDone,
+ cancelOnError: cancelOnError);
+ }
+
+ void _onCancel() {
+ // Called by [_controller] when it has no subscribers left.
+ StreamSubscription subscription = _subscription;
+ _subscription = null;
+ _controller = null; // Marks the stream as no longer listenable.
+ subscription.cancel();
+ }
+}
+
+/**
+ * Simple implementation of [StreamIterator].
+ */
+class _StreamIteratorImpl<T> implements StreamIterator<T> {
+ // Internal state of the stream iterator.
+ // At any time, it is in one of these states.
+ // The interpretation of the [_futureOrPrefecth] field depends on the state.
+ // In _STATE_MOVING, the _data field holds the most recently returned
+ // future.
+ // When in one of the _STATE_EXTRA_* states, the it may hold the
+ // next data/error object, and the subscription is paused.
+
+ /// The simple state where [_data] holds the data to return, and [moveNext]
+ /// is allowed. The subscription is actively listening.
+ static const int _STATE_FOUND = 0;
+ /// State set after [moveNext] has returned false or an error,
+ /// or after calling [cancel]. The subscription is always canceled.
+ static const int _STATE_DONE = 1;
+ /// State set after calling [moveNext], but before its returned future has
+ /// completed. Calling [moveNext] again is not allowed in this state.
+ /// The subscription is actively listening.
+ static const int _STATE_MOVING = 2;
+ /// States set when another event occurs while in _STATE_FOUND.
+ /// This extra overflow event is cached until the next call to [moveNext],
+ /// which will complete as if it received the event normally.
+ /// The subscription is paused in these states, so we only ever get one
+ /// event too many.
+ static const int _STATE_EXTRA_DATA = 3;
+ static const int _STATE_EXTRA_ERROR = 4;
+ static const int _STATE_EXTRA_DONE = 5;
+
+ /// Subscription being listened to.
+ StreamSubscription _subscription;
+
+ /// The current element represented by the most recent call to moveNext.
+ ///
+ /// Is null between the time moveNext is called and its future completes.
+ T _current = null;
+
+ /// The future returned by the most recent call to [moveNext].
+ ///
+ /// Also used to store the next value/error in case the stream provides an
+ /// event before [moveNext] is called again. In that case, the stream will
+ /// be paused to prevent further events.
+ var _futureOrPrefetch = null;
+
+ /// The current state.
+ int _state = _STATE_FOUND;
+
+ _StreamIteratorImpl(final Stream<T> stream) {
+ _subscription = stream.listen(_onData,
+ onError: _onError,
+ onDone: _onDone,
+ cancelOnError: true);
+ }
+
+ T get current => _current;
+
+ Future<bool> moveNext() {
+ if (_state == _STATE_DONE) {
+ return new _FutureImpl<bool>.immediate(false);
+ }
+ if (_state == _STATE_MOVING) {
+ throw new StateError("Already waiting for next.");
+ }
+ if (_state == _STATE_FOUND) {
+ _state = _STATE_MOVING;
+ _futureOrPrefetch = new _FutureImpl<bool>();
+ return _futureOrPrefetch;
} else {
- if (_subscription != null) {
- _subscription.resume();
+ assert(_state >= _STATE_EXTRA_DATA);
+ switch (_state) {
+ case _STATE_EXTRA_DATA:
+ _state = _STATE_FOUND;
+ _current = _futureOrPrefetch;
+ _futureOrPrefetch = null;
+ _subscription.resume();
+ return new _FutureImpl<bool>.immediate(true);
+ case _STATE_EXTRA_ERROR:
+ Object prefetch = _futureOrPrefetch;
+ _clear();
+ return new _FutureImpl<bool>.immediateError(prefetch);
+ case _STATE_EXTRA_DONE:
+ _clear();
+ return new _FutureImpl<bool>.immediate(false);
}
}
}
- /**
- * Subscribe or unsubscribe on [_source] depending on whether
- * [_stream] has subscribers.
- */
- void _onSubscriptionStateChange() {
- if (_hasListener) {
- assert(_subscription == null);
- _subscription = _source.listen(this._add,
- onError: this._addError,
- onDone: this._close);
+ /** Clears up the internal state when the iterator ends. */
+ void _clear() {
+ _subscription = null;
+ _futureOrPrefetch = null;
+ _current = null;
+ _state = _STATE_DONE;
+ }
+
+ void cancel() {
+ StreamSubscription subscription = _subscription;
+ if (_state == _STATE_MOVING) {
+ _FutureImpl<bool> hasNext = _futureOrPrefetch;
+ _clear();
+ hasNext._setValue(false);
} else {
- // TODO(lrn): Check why this can happen.
- if (_subscription == null) return;
- _subscription.cancel();
- _subscription = null;
+ _clear();
}
+ subscription.cancel();
+ }
+
+ void _onData(T data) {
+ if (_state == _STATE_MOVING) {
+ _current = data;
+ _FutureImpl<bool> hasNext = _futureOrPrefetch;
+ _futureOrPrefetch = null;
+ _state = _STATE_FOUND;
+ hasNext._setValue(true);
+ return;
+ }
+ _subscription.pause();
+ assert(_futureOrPrefetch == null);
+ _futureOrPrefetch = data;
+ _state = _STATE_EXTRA_DATA;
+ }
+
+ void _onError(Object error) {
+ if (_state == _STATE_MOVING) {
+ _FutureImpl<bool> hasNext = _futureOrPrefetch;
+ // We have cancelOnError: true, so the subscription is canceled.
+ _clear();
+ hasNext._setError(error);
+ return;
+ }
+ _subscription.pause();
+ assert(_futureOrPrefetch == null);
+ _futureOrPrefetch = error;
+ _state = _STATE_EXTRA_ERROR;
+ }
+
+ void _onDone() {
+ if (_state == _STATE_MOVING) {
+ _FutureImpl<bool> hasNext = _futureOrPrefetch;
+ _clear();
+ hasNext._setValue(false);
+ return;
+ }
+ _subscription.pause();
+ _futureOrPrefetch = null;
+ _state = _STATE_EXTRA_DONE;
}
}
diff --git a/sdk/lib/async/stream_pipe.dart b/sdk/lib/async/stream_pipe.dart
index e089f6c..e5aca17 100644
--- a/sdk/lib/async/stream_pipe.dart
+++ b/sdk/lib/async/stream_pipe.dart
@@ -69,84 +69,26 @@
// Override the following methods in subclasses to change the behavior.
- void _handleData(S data, _EventOutputSink<T> sink) {
+ void _handleData(S data, _EventSink<T> sink) {
var outputData = data;
- sink._sendData(outputData);
+ sink._add(outputData);
}
- void _handleError(error, _EventOutputSink<T> sink) {
- sink._sendError(error);
+ void _handleError(error, _EventSink<T> sink) {
+ sink._addError(error);
}
- void _handleDone(_EventOutputSink<T> sink) {
- sink._sendDone();
+ void _handleDone(_EventSink<T> sink) {
+ sink._close();
}
}
/**
- * Common behavior of [StreamSubscription] classes.
- *
- * Stores and allows updating of the event handlers of a [StreamSubscription].
- */
-abstract class _BaseStreamSubscription<T> implements StreamSubscription<T> {
- // TODO(ahe): Restore type when feature is implemented in dart2js
- // checked mode. http://dartbug.com/7733
- var /* _DataHandler<T> */ _onData;
- _ErrorHandler _onError;
- _DoneHandler _onDone;
-
- _BaseStreamSubscription(this._onData,
- this._onError,
- this._onDone) {
- if (_onData == null) _onData = _nullDataHandler;
- if (_onError == null) _onError = _nullErrorHandler;
- if (_onDone == null) _onDone = _nullDoneHandler;
- }
-
- // StreamSubscription interface.
- void onData(void handleData(T event)) {
- if (handleData == null) handleData = _nullDataHandler;
- _onData = handleData;
- }
-
- void onError(void handleError(error)) {
- if (handleError == null) handleError = _nullErrorHandler;
- _onError = handleError;
- }
-
- void onDone(void handleDone()) {
- if (handleDone == null) handleDone = _nullDoneHandler;
- _onDone = handleDone;
- }
-
- void pause([Future resumeSignal]);
-
- void resume();
-
- void cancel();
-
- Future asFuture([var futureValue]) {
- _FutureImpl<T> result = new _FutureImpl<T>();
-
- // Overwrite the onDone and onError handlers.
- onDone(() { result._setValue(futureValue); });
- onError((error) {
- cancel();
- result._setError(error);
- });
-
- return result;
- }
-}
-
-
-/**
* Abstract superclass for subscriptions that forward to other subscriptions.
*/
class _ForwardingStreamSubscription<S, T>
- extends _BaseStreamSubscription<T> implements _EventOutputSink<T> {
+ extends _BufferingStreamSubscription<T> {
final _ForwardingStream<S, T> _stream;
- final bool _cancelOnError;
StreamSubscription<S> _subscription;
@@ -154,62 +96,48 @@
void onData(T data),
void onError(error),
void onDone(),
- this._cancelOnError)
- : super(onData, onError, onDone) {
- // Don't unsubscribe on incoming error, only if we send an error forwards.
+ bool cancelOnError)
+ : super(onData, onError, onDone, cancelOnError) {
_subscription =
_stream._source.listen(_handleData,
onError: _handleError,
onDone: _handleDone);
}
- // StreamSubscription interface.
+ // _StreamSink interface.
+ // Transformers sending more than one event have no way to know if the stream
+ // is canceled or closed after the first, so we just ignore remaining events.
- void pause([Future resumeSignal]) {
- if (_subscription == null) return;
- _subscription.pause(resumeSignal);
+ void _add(T data) {
+ if (_isClosed) return;
+ super._add(data);
}
- void resume() {
+ void _addError(Object error) {
+ if (_isClosed) return;
+ super._addError(error);
+ }
+
+ // StreamSubscription callbacks.
+
+ void _onPause() {
+ if (_subscription == null) return;
+ _subscription.pause();
+ }
+
+ void _onResume() {
if (_subscription == null) return;
_subscription.resume();
}
- bool get isPaused {
- if (_subscription == null) return false;
- return _subscription.isPaused;
- }
-
- void cancel() {
+ void _onCancel() {
if (_subscription != null) {
- _subscription.cancel();
+ StreamSubscription subscription = _subscription;
_subscription = null;
+ subscription.cancel();
}
}
- // _EventOutputSink interface. Sends data to this subscription.
-
- void _sendData(T data) {
- _onData(data);
- }
-
- void _sendError(error) {
- _onError(error);
- if (_cancelOnError) {
- _subscription.cancel();
- _subscription = null;
- }
- }
-
- void _sendDone() {
- // If the transformation sends a done signal, we stop the subscription.
- if (_subscription != null) {
- _subscription.cancel();
- _subscription = null;
- }
- _onDone();
- }
-
// Methods used as listener on source subscription.
// TODO(ahe): Restore type when feature is implemented in dart2js
@@ -241,16 +169,16 @@
_WhereStream(Stream<T> source, bool test(T value))
: _test = test, super(source);
- void _handleData(T inputEvent, _EventOutputSink<T> sink) {
+ void _handleData(T inputEvent, _EventSink<T> sink) {
bool satisfies;
try {
satisfies = _test(inputEvent);
} catch (e, s) {
- sink._sendError(_asyncError(e, s));
+ sink._addError(_asyncError(e, s));
return;
}
if (satisfies) {
- sink._sendData(inputEvent);
+ sink._add(inputEvent);
}
}
}
@@ -267,15 +195,15 @@
_MapStream(Stream<S> source, T transform(S event))
: this._transform = transform, super(source);
- void _handleData(S inputEvent, _EventOutputSink<T> sink) {
+ void _handleData(S inputEvent, _EventSink<T> sink) {
T outputEvent;
try {
outputEvent = _transform(inputEvent);
} catch (e, s) {
- sink._sendError(_asyncError(e, s));
+ sink._addError(_asyncError(e, s));
return;
}
- sink._sendData(outputEvent);
+ sink._add(outputEvent);
}
}
@@ -288,15 +216,15 @@
_ExpandStream(Stream<S> source, Iterable<T> expand(S event))
: this._expand = expand, super(source);
- void _handleData(S inputEvent, _EventOutputSink<T> sink) {
+ void _handleData(S inputEvent, _EventSink<T> sink) {
try {
for (T value in _expand(inputEvent)) {
- sink._sendData(value);
+ sink._add(value);
}
} catch (e, s) {
// If either _expand or iterating the generated iterator throws,
// we abort the iteration.
- sink._sendError(_asyncError(e, s));
+ sink._addError(_asyncError(e, s));
}
}
}
@@ -318,13 +246,13 @@
bool test(error))
: this._transform = transform, this._test = test, super(source);
- void _handleError(Object error, _EventOutputSink<T> sink) {
+ void _handleError(Object error, _EventSink<T> sink) {
bool matches = true;
if (_test != null) {
try {
matches = _test(error);
} catch (e, s) {
- sink._sendError(_asyncError(e, s));
+ sink._addError(_asyncError(e, s));
return;
}
}
@@ -332,11 +260,11 @@
try {
_transform(error);
} catch (e, s) {
- sink._sendError(_asyncError(e, s));
+ sink._addError(_asyncError(e, s));
return;
}
} else {
- sink._sendError(error);
+ sink._addError(error);
}
}
}
@@ -352,14 +280,14 @@
if (count is! int) throw new ArgumentError(count);
}
- void _handleData(T inputEvent, _EventOutputSink<T> sink) {
+ void _handleData(T inputEvent, _EventSink<T> sink) {
if (_remaining > 0) {
- sink._sendData(inputEvent);
+ sink._add(inputEvent);
_remaining -= 1;
if (_remaining == 0) {
// Closing also unsubscribes all subscribers, which unsubscribes
// this from source.
- sink._sendDone();
+ sink._close();
}
}
}
@@ -372,20 +300,20 @@
_TakeWhileStream(Stream<T> source, bool test(T value))
: this._test = test, super(source);
- void _handleData(T inputEvent, _EventOutputSink<T> sink) {
+ void _handleData(T inputEvent, _EventSink<T> sink) {
bool satisfies;
try {
satisfies = _test(inputEvent);
} catch (e, s) {
- sink._sendError(_asyncError(e, s));
+ sink._addError(_asyncError(e, s));
// The test didn't say true. Didn't say false either, but we stop anyway.
- sink._sendDone();
+ sink._close();
return;
}
if (satisfies) {
- sink._sendData(inputEvent);
+ sink._add(inputEvent);
} else {
- sink._sendDone();
+ sink._close();
}
}
}
@@ -400,12 +328,12 @@
if (count is! int || count < 0) throw new ArgumentError(count);
}
- void _handleData(T inputEvent, _EventOutputSink<T> sink) {
+ void _handleData(T inputEvent, _EventSink<T> sink) {
if (_remaining > 0) {
_remaining--;
return;
}
- return sink._sendData(inputEvent);
+ return sink._add(inputEvent);
}
}
@@ -416,23 +344,23 @@
_SkipWhileStream(Stream<T> source, bool test(T value))
: this._test = test, super(source);
- void _handleData(T inputEvent, _EventOutputSink<T> sink) {
+ void _handleData(T inputEvent, _EventSink<T> sink) {
if (_hasFailed) {
- sink._sendData(inputEvent);
+ sink._add(inputEvent);
return;
}
bool satisfies;
try {
satisfies = _test(inputEvent);
} catch (e, s) {
- sink._sendError(_asyncError(e, s));
+ sink._addError(_asyncError(e, s));
// A failure to return a boolean is considered "not matching".
_hasFailed = true;
return;
}
if (!satisfies) {
_hasFailed = true;
- sink._sendData(inputEvent);
+ sink._add(inputEvent);
}
}
}
@@ -448,10 +376,10 @@
_DistinctStream(Stream<T> source, bool equals(T a, T b))
: _equals = equals, super(source);
- void _handleData(T inputEvent, _EventOutputSink<T> sink) {
+ void _handleData(T inputEvent, _EventSink<T> sink) {
if (identical(_previous, _SENTINEL)) {
_previous = inputEvent;
- return sink._sendData(inputEvent);
+ return sink._add(inputEvent);
} else {
bool isEqual;
try {
@@ -461,11 +389,11 @@
isEqual = _equals(_previous, inputEvent);
}
} catch (e, s) {
- sink._sendError(_asyncError(e, s));
+ sink._addError(_asyncError(e, s));
return null;
}
if (!isEqual) {
- sink._sendData(inputEvent);
+ sink._add(inputEvent);
_previous = inputEvent;
}
}
diff --git a/sdk/lib/collection/hash_map.dart b/sdk/lib/collection/hash_map.dart
index f5fcd85..431c89f 100644
--- a/sdk/lib/collection/hash_map.dart
+++ b/sdk/lib/collection/hash_map.dart
@@ -13,6 +13,7 @@
external int get length;
external bool get isEmpty;
+ external bool get isNotEmpty;
external Iterable<K> get keys;
external Iterable<V> get values;
diff --git a/sdk/lib/collection/hash_set.dart b/sdk/lib/collection/hash_set.dart
index c459f99..8d484db 100644
--- a/sdk/lib/collection/hash_set.dart
+++ b/sdk/lib/collection/hash_set.dart
@@ -70,6 +70,8 @@
external bool get isEmpty;
+ external bool get isNotEmpty;
+
external bool contains(Object object);
// Collection.
diff --git a/sdk/lib/collection/iterable.dart b/sdk/lib/collection/iterable.dart
index 2ec143b..a950543 100644
--- a/sdk/lib/collection/iterable.dart
+++ b/sdk/lib/collection/iterable.dart
@@ -95,6 +95,8 @@
bool get isEmpty => !iterator.moveNext();
+ bool get isNotEmpty => !isEmpty;
+
Iterable<E> take(int n) {
return new TakeIterable<E>(this, n);
}
@@ -287,6 +289,8 @@
bool get isEmpty => !iterator.moveNext();
+ bool get isNotEmpty => !isEmpty;
+
Iterable<E> take(int n) {
return new TakeIterable<E>(this, n);
}
diff --git a/sdk/lib/collection/linked_hash_map.dart b/sdk/lib/collection/linked_hash_map.dart
index 431f7fa..d41cb40 100644
--- a/sdk/lib/collection/linked_hash_map.dart
+++ b/sdk/lib/collection/linked_hash_map.dart
@@ -39,5 +39,7 @@
external bool get isEmpty;
+ external bool get isNotEmpty;
+
String toString() => Maps.mapToString(this);
}
diff --git a/sdk/lib/collection/linked_hash_set.dart b/sdk/lib/collection/linked_hash_set.dart
index e866b63..ee9cdb1 100644
--- a/sdk/lib/collection/linked_hash_set.dart
+++ b/sdk/lib/collection/linked_hash_set.dart
@@ -19,6 +19,8 @@
external bool get isEmpty;
+ external bool get isNotEmpty;
+
external bool contains(Object object);
external void forEach(void action(E element));
diff --git a/sdk/lib/collection/list.dart b/sdk/lib/collection/list.dart
index aab99d8..fa1bd50 100644
--- a/sdk/lib/collection/list.dart
+++ b/sdk/lib/collection/list.dart
@@ -45,6 +45,8 @@
bool get isEmpty => length == 0;
+ bool get isNotEmpty => !isEmpty;
+
E get first {
if (length == 0) throw new StateError("No elements");
return this[0];
diff --git a/sdk/lib/collection/maps.dart b/sdk/lib/collection/maps.dart
index b4eef3f..bd7d755 100644
--- a/sdk/lib/collection/maps.dart
+++ b/sdk/lib/collection/maps.dart
@@ -58,6 +58,8 @@
static bool isEmpty(Map map) => map.keys.isEmpty;
+ static bool isNotEmpty(Map map) => map.keys.isNotEmpty;
+
/**
* Returns a string representing the specified map. The returned string
* looks like this: [:'{key0: value0, key1: value1, ... keyN: valueN}':].
diff --git a/sdk/lib/collection/splay_tree.dart b/sdk/lib/collection/splay_tree.dart
index 1461cc6..b959a55 100644
--- a/sdk/lib/collection/splay_tree.dart
+++ b/sdk/lib/collection/splay_tree.dart
@@ -313,6 +313,8 @@
return (_root == null);
}
+ bool get isNotEmpty => !isEmpty;
+
void forEach(void f(K key, V value)) {
Iterator<_SplayTreeNode<K>> nodes =
new _SplayTreeNodeIterator<K>(this);
diff --git a/sdk/lib/core/core.dart b/sdk/lib/core/core.dart
index 391000c..de7fc4a 100644
--- a/sdk/lib/core/core.dart
+++ b/sdk/lib/core/core.dart
@@ -7,6 +7,7 @@
import "dart:collection";
import "dart:_collection-dev" hide Symbol;
import "dart:_collection-dev" as _collection_dev;
+import "dart:utf" show codepointsToUtf8, decodeUtf8;
part "bool.dart";
part "comparable.dart";
@@ -37,3 +38,4 @@
part "string_sink.dart";
part "symbol.dart";
part "type.dart";
+part "uri.dart";
diff --git a/sdk/lib/core/corelib_sources.gypi b/sdk/lib/core/corelib_sources.gypi
index 9d6126fa..faafe0a 100644
--- a/sdk/lib/core/corelib_sources.gypi
+++ b/sdk/lib/core/corelib_sources.gypi
@@ -35,5 +35,6 @@
'string_sink.dart',
'symbol.dart',
'type.dart',
+ 'uri.dart',
],
}
diff --git a/sdk/lib/core/iterable.dart b/sdk/lib/core/iterable.dart
index b802cfd..03127c8 100644
--- a/sdk/lib/core/iterable.dart
+++ b/sdk/lib/core/iterable.dart
@@ -162,6 +162,11 @@
bool get isEmpty;
/**
+ * Returns true if there is at least one element in this collection.
+ */
+ bool get isNotEmpty;
+
+ /**
* Returns an [Iterable] with at most [n] elements.
*
* The returned [Iterable] may contain fewer than [n] elements, if `this`
diff --git a/sdk/lib/core/map.dart b/sdk/lib/core/map.dart
index de3807f..fe68fd8 100644
--- a/sdk/lib/core/map.dart
+++ b/sdk/lib/core/map.dart
@@ -93,4 +93,9 @@
* Returns true if there is no {key, value} pair in the map.
*/
bool get isEmpty;
+
+ /**
+ * Returns true if there is at least one {key, value} pair in the map.
+ */
+ bool get isNotEmpty;
}
diff --git a/sdk/lib/core/string.dart b/sdk/lib/core/string.dart
index 7db20f3..3f0ad31 100644
--- a/sdk/lib/core/string.dart
+++ b/sdk/lib/core/string.dart
@@ -129,6 +129,11 @@
bool get isEmpty;
/**
+ * Returns whether this string is not empty.
+ */
+ bool get isNotEmpty;
+
+ /**
* Creates a new string by concatenating this string with [other].
*
* A sequence of strings can be concatenated by using [Iterable.join]:
diff --git a/sdk/lib/core/string_buffer.dart b/sdk/lib/core/string_buffer.dart
index 8ea4bf1..59d1aa9 100644
--- a/sdk/lib/core/string_buffer.dart
+++ b/sdk/lib/core/string_buffer.dart
@@ -23,6 +23,12 @@
/** Returns whether the buffer is empty. This is a constant-time operation. */
bool get isEmpty => length == 0;
+ /**
+ * Returns whether the buffer is not empty. This is a constant-time
+ * operation.
+ */
+ bool get isNotEmpty => !isEmpty;
+
/// Adds the contents of [obj], converted to a string, to the buffer.
external void write(Object obj);
diff --git a/sdk/lib/core/uri.dart b/sdk/lib/core/uri.dart
new file mode 100644
index 0000000..c8277e7
--- /dev/null
+++ b/sdk/lib/core/uri.dart
@@ -0,0 +1,946 @@
+// 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.
+
+part of dart.core;
+
+/**
+ * A parsed URI, as specified by RFC-3986, http://tools.ietf.org/html/rfc3986.
+ */
+class Uri {
+ int _port;
+
+ /**
+ * Returns the scheme component.
+ *
+ * Returns the empty string if there is no scheme component.
+ */
+ final String scheme;
+
+ /**
+ * Returns the authority component.
+ *
+ * The authority is formatted from the [userInfo], [host] and [port]
+ * parts.
+ *
+ * Returns the empty string if there is no authority component.
+ */
+ String get authority {
+ if (!hasAuthority) return "";
+ var sb = new StringBuffer();
+ _writeAuthority(sb);
+ return sb.toString();
+ }
+
+ /**
+ * Returns the user info part of the authority component.
+ *
+ * Returns the empty string if there is no user info in the
+ * authority component.
+ */
+ final String userInfo;
+
+ /**
+ * Returns the host part of the authority component.
+ *
+ * Returns the empty string if there is no authority component and
+ * hence no host.
+ */
+ final String host;
+
+ /**
+ * Returns the port part of the authority component.
+ *
+ * Returns 0 if there is no port in the authority component.
+ */
+ int get port => _port;
+
+ /**
+ * Returns the path component.
+ *
+ * The returned path is encoded. To get direct access to the decoded
+ * path use [pathSegments].
+ *
+ * Returns the empty string if there is no path component.
+ */
+ final String path;
+
+ /**
+ * Returns the query component. The returned query is encoded. To get
+ * direct access to the decoded query use [queryParameters].
+ *
+ * Returns the empty string if there is no query component.
+ */
+ final String query;
+
+ /**
+ * Returns the fragment identifier component.
+ *
+ * Returns the empty string if there is no fragment identifier
+ * component.
+ */
+ final String fragment;
+
+ /**
+ * Creates a new URI object by parsing a URI string.
+ */
+ static Uri parse(String uri) => new Uri._fromMatch(_splitRe.firstMatch(uri));
+
+ Uri._fromMatch(Match m) :
+ this(scheme: _emptyIfNull(m[_COMPONENT_SCHEME]),
+ userInfo: _emptyIfNull(m[_COMPONENT_USER_INFO]),
+ host: _eitherOf(
+ m[_COMPONENT_HOST], m[_COMPONENT_HOST_IPV6]),
+ port: _parseIntOrZero(m[_COMPONENT_PORT]),
+ path: _emptyIfNull(m[_COMPONENT_PATH]),
+ 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
+ * components can be provided. The default value for the components
+ * not provided is the empry string, except for [port] which has a
+ * default value of 0. The [path] and [query] components can be set
+ * using two different named arguments.
+ *
+ * The scheme component is set through [scheme]. The scheme is
+ * normalized to all lowercase letters.
+ *
+ * The user info part of the authority component is set through
+ * [userInfo].
+ *
+ * The host part of the authority component is set through
+ * [host]. The host can either be a hostname, a IPv4 address or an
+ * IPv6 address, contained in '[' and ']'. If the host contains a
+ * ':' character, the '[' and ']' are added if not already provided.
+ *
+ * The port part of the authority component is set through
+ * [port]. The port is normalized for scheme http and https where
+ * port 80 and port 443 respectively is set.
+ *
+ * The path component is set through either [path] or
+ * [pathSegments]. When [path] is used, the provided string is
+ * expected to be fully percent-encoded, and is used in its literal
+ * form. When [pathSegments] is used, each of the provided segments
+ * is percent-encoded and joined using the forward slash
+ * separator. The percent-encoding of the path segments encodes all
+ * characters except for the unreserved characters and the following
+ * list of characters: `!$&'()*+,;=:@`.
+ *
+ * The query component is set through either [query] or
+ * [queryParameters]. When [query] is used the provided string is
+ * expected to be fully percent-encoded and is used in its literal
+ * form. When [queryParameters] is used the query is built from the
+ * provided map. Each key and value in the map is percent-encoded
+ * and joined using equal and ampersand characters. The
+ * percent-encoding of the keys and values encodes all characters
+ * except for the unreserved characters.
+ *
+ * The fragment component is set through [fragment].
+ */
+ Uri({scheme,
+ this.userInfo: "",
+ this.host: "",
+ port: 0,
+ String path,
+ List<String> pathSegments,
+ String query,
+ Map<String, String> queryParameters,
+ fragment: ""}) :
+ scheme = _makeScheme(scheme),
+ path = _makePath(path, pathSegments),
+ query = _makeQuery(query, queryParameters),
+ fragment = _makeFragment(fragment) {
+ // Perform scheme specific normalization.
+ if (scheme == "http" && port == 80) {
+ _port = 0;
+ } else if (scheme == "https" && port == 443) {
+ _port = 0;
+ } else {
+ _port = port;
+ }
+ }
+
+ /*
+ * 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.
+ */
+ List<String> get pathSegments {
+ if (path == "") return const<String>[];
+ return path.split("/").map(Uri.decodeComponent).toList(growable: false);
+ }
+
+ /*
+ * 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.
+ */
+ Map<String, String> get queryParameters {
+ return query.split("&").fold({}, (map, element) {
+ int index = element.indexOf("=");
+ if (index == -1) {
+ if (!element.isEmpty) map[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;
+ });
+ }
+
+ static String _makeScheme(String scheme) {
+ bool isSchemeLowerCharacter(int ch) {
+ return ch < 128 &&
+ ((_schemeLowerTable[ch >> 4] & (1 << (ch & 0x0f))) != 0);
+ }
+
+ bool isSchemeCharacter(int ch) {
+ return ch < 128 && ((_schemeTable[ch >> 4] & (1 << (ch & 0x0f))) != 0);
+ }
+
+ if (scheme == null) return "";
+ bool allLowercase = true;
+ int length = scheme.length;
+ for (int i = 0; i < length; i++) {
+ int codeUnit = scheme.codeUnitAt(i);
+ if (!isSchemeLowerCharacter(codeUnit)) {
+ if (isSchemeCharacter(codeUnit)) {
+ allLowercase = false;
+ } else {
+ throw new ArgumentError('Illegal scheme: $scheme');
+ }
+ }
+ }
+
+ return allLowercase ? scheme : scheme.toLowerCase();
+ }
+
+ static String _makePath(String path, List<String> pathSegments) {
+ if (path == null && pathSegments == null) return "";
+ if (path != null && pathSegments != null) {
+ throw new ArgumentError('Both path and pathSegments specified');
+ }
+ if (path != null) return _normalize(path);
+
+ return pathSegments.map((s) => _uriEncode(_pathCharTable, s)).join("/");
+ }
+
+ static String _makeQuery(String query, Map<String, String> queryParameters) {
+ if (query == null && queryParameters == null) return "";
+ if (query != null && queryParameters != null) {
+ throw new ArgumentError('Both query and queryParameters specified');
+ }
+ if (query != null) return _normalize(query);
+
+ var result = new StringBuffer();
+ var first = true;
+ queryParameters.forEach((key, value) {
+ if (!first) {
+ result.write("&");
+ }
+ first = false;
+ result.write(Uri.encodeQueryComponent(key));
+ if (value != null && !value.isEmpty) {
+ result.write("=");
+ result.write(Uri.encodeQueryComponent(value));
+ }
+ });
+ return result.toString();
+ }
+
+ static String _makeFragment(String fragment) {
+ if (fragment == null) return "";
+ return _normalize(fragment);
+ }
+
+ static String _normalize(String component) {
+ bool isNormalizedHexDigit(int digit) {
+ return (_ZERO <= digit && digit <= _NINE) ||
+ (_UPPER_CASE_A <= digit && digit <= _UPPER_CASE_F);
+ }
+
+ bool isLowerCaseHexDigit(int digit) {
+ return _LOWER_CASE_A <= digit && digit <= _LOWER_CASE_F;
+ }
+
+ bool isUnreserved(int ch) {
+ return ch < 128 &&
+ ((_unreservedTable[ch >> 4] & (1 << (ch & 0x0f))) != 0);
+ }
+
+ int normalizeHexDigit(int index) {
+ var codeUnit = component.codeUnitAt(index);
+ if (isLowerCaseHexDigit(codeUnit)) {
+ return codeUnit - 0x20;
+ } else if (!isNormalizedHexDigit(codeUnit)) {
+ throw new ArgumentError("Invalid URI component: $component");
+ } else {
+ return codeUnit;
+ }
+ }
+
+ int decodeHexDigitPair(int index) {
+ int byte = 0;
+ for (int i = 0; i < 2; i++) {
+ var codeUnit = component.codeUnitAt(index + i);
+ if (_ZERO <= codeUnit && codeUnit <= _NINE) {
+ byte = byte * 16 + codeUnit - _ZERO;
+ } else {
+ // Check ranges A-F (0x41-0x46) and a-f (0x61-0x66).
+ codeUnit |= 0x20;
+ if (_LOWER_CASE_A <= codeUnit &&
+ codeUnit <= _LOWER_CASE_F) {
+ byte = byte * 16 + codeUnit - _LOWER_CASE_A + 10;
+ } else {
+ throw new ArgumentError(
+ "Invalid percent-encoding in URI component: $component");
+ }
+ }
+ }
+ return byte;
+ }
+
+ // Start building the normalized component string.
+ StringBuffer result;
+ int length = component.length;
+ int index = 0;
+ int prevIndex = 0;
+ while (index < length) {
+
+ // Copy a part of the component string to the result.
+ fillResult() {
+ if (result == null) {
+ assert(prevIndex == 0);
+ result = new StringBuffer(component.substring(prevIndex, index));
+ } else {
+ result.write(component.substring(prevIndex, index));
+ }
+ }
+
+ // Normalize percent encoding to uppercase and don't encode
+ // unreserved characters.
+ if (component.codeUnitAt(index) == _PERCENT) {
+ if (length < index + 2) {
+ throw new ArgumentError(
+ "Invalid percent-encoding in URI component: $component");
+ }
+
+ var codeUnit1 = component.codeUnitAt(index + 1);
+ var codeUnit2 = component.codeUnitAt(index + 2);
+ var decodedCodeUnit = decodeHexDigitPair(index + 1);
+ if (isNormalizedHexDigit(codeUnit1) &&
+ isNormalizedHexDigit(codeUnit2) &&
+ !isUnreserved(decodedCodeUnit)) {
+ index += 3;
+ } else {
+ fillResult();
+ if (isUnreserved(decodedCodeUnit)) {
+ result.writeCharCode(decodedCodeUnit);
+ } else {
+ result.write("%");
+ result.writeCharCode(normalizeHexDigit(index + 1));
+ result.writeCharCode(normalizeHexDigit(index + 2));
+ }
+ index += 3;
+ prevIndex = index;
+ }
+ } else {
+ index++;
+ }
+ }
+ assert(index == length);
+
+ if (result == null) return component;
+ return result.toString();
+ }
+
+ static String _emptyIfNull(String val) => val != null ? val : '';
+
+ static int _parseIntOrZero(String val) {
+ if (val != null && val != '') {
+ return int.parse(val);
+ } else {
+ return 0;
+ }
+ }
+
+ static String _eitherOf(String val1, String val2) {
+ if (val1 != null) return val1;
+ if (val2 != null) return val2;
+ return '';
+ }
+
+ // NOTE: This code was ported from: closure-library/closure/goog/uri/utils.js
+ static final RegExp _splitRe = new RegExp(
+ '^'
+ '(?:'
+ '([^:/?#.]+)' // scheme - ignore special characters
+ // used by other URL parts such as :,
+ // ?, /, #, and .
+ ':)?'
+ '(?://'
+ '(?:([^/?#]*)@)?' // userInfo
+ '(?:'
+ r'([\w\d\-\u0100-\uffff.%]*)'
+ // host - restrict to letters,
+ // digits, dashes, dots, percent
+ // escapes, and unicode characters.
+ '|'
+ // TODO(ajohnsen): Only allow a max number of parts?
+ r'\[([A-Fa-f0-9:.]*)\])'
+ // IPv6 host - restrict to hex,
+ // dot and colon.
+ '(?::([0-9]+))?' // port
+ ')?'
+ r'([^?#[]+)?' // path
+ r'(?:\?([^#]*))?' // query
+ '(?:#(.*))?' // fragment
+ r'$');
+
+ static const _COMPONENT_SCHEME = 1;
+ static const _COMPONENT_USER_INFO = 2;
+ static const _COMPONENT_HOST = 3;
+ static const _COMPONENT_HOST_IPV6 = 4;
+ static const _COMPONENT_PORT = 5;
+ static const _COMPONENT_PATH = 6;
+ static const _COMPONENT_QUERY_DATA = 7;
+ static const _COMPONENT_FRAGMENT = 8;
+
+ /**
+ * Returns whether the URI is absolute.
+ */
+ bool get isAbsolute => scheme != "" && fragment == "";
+
+ String _merge(String base, String reference) {
+ if (base == "") return "/$reference";
+ return "${base.substring(0, base.lastIndexOf("/") + 1)}$reference";
+ }
+
+ bool _hasDotSegments(String path) {
+ if (path.length > 0 && path.codeUnitAt(0) == _COLON) return true;
+ int index = path.indexOf("/.");
+ return index != -1;
+ }
+
+ String _removeDotSegments(String path) {
+ if (!_hasDotSegments(path)) return path;
+ List<String> output = [];
+ bool appendSlash = false;
+ for (String segment in path.split("/")) {
+ appendSlash = false;
+ if (segment == "..") {
+ if (!output.isEmpty &&
+ ((output.length != 1) || (output[0] != ""))) output.removeLast();
+ appendSlash = true;
+ } else if ("." == segment) {
+ appendSlash = true;
+ } else {
+ output.add(segment);
+ }
+ }
+ if (appendSlash) output.add("");
+ return output.join("/");
+ }
+
+ Uri resolve(String uri) {
+ return resolveUri(Uri.parse(uri));
+ }
+
+ Uri resolveUri(Uri reference) {
+ // From RFC 3986.
+ String targetScheme;
+ String targetUserInfo;
+ String targetHost;
+ int targetPort;
+ String targetPath;
+ String targetQuery;
+ if (reference.scheme != "") {
+ targetScheme = reference.scheme;
+ targetUserInfo = reference.userInfo;
+ targetHost = reference.host;
+ targetPort = reference.port;
+ targetPath = _removeDotSegments(reference.path);
+ targetQuery = reference.query;
+ } else {
+ if (reference.hasAuthority) {
+ targetUserInfo = reference.userInfo;
+ targetHost = reference.host;
+ targetPort = reference.port;
+ targetPath = _removeDotSegments(reference.path);
+ targetQuery = reference.query;
+ } else {
+ if (reference.path == "") {
+ targetPath = this.path;
+ if (reference.query != "") {
+ targetQuery = reference.query;
+ } else {
+ targetQuery = this.query;
+ }
+ } else {
+ if (reference.path.startsWith("/")) {
+ targetPath = _removeDotSegments(reference.path);
+ } else {
+ targetPath = _removeDotSegments(_merge(this.path, reference.path));
+ }
+ targetQuery = reference.query;
+ }
+ targetUserInfo = this.userInfo;
+ targetHost = this.host;
+ targetPort = this.port;
+ }
+ targetScheme = this.scheme;
+ }
+ return new Uri(scheme: targetScheme,
+ userInfo: targetUserInfo,
+ host: targetHost,
+ port: targetPort,
+ path: targetPath,
+ query: targetQuery,
+ fragment: reference.fragment);
+ }
+
+ bool get hasAuthority => host != "";
+
+ /**
+ * Returns the origin of the URI in the form scheme://host:port for the
+ * schemes http and https.
+ *
+ * It is an error if the scheme is not "http" or "https".
+ *
+ * See: http://www.w3.org/TR/2011/WD-html5-20110405/origin-0.html#origin
+ */
+ String get origin {
+ if (scheme == "" || host == null || host == "") {
+ throw new StateError("Cannot use origin without a scheme: $this");
+ }
+ if (scheme != "http" && scheme != "https") {
+ throw new StateError(
+ "Origin is only applicable schemes http and https: $this");
+ }
+ if (port == 0) return "$scheme://$host";
+ return "$scheme://$host:$port";
+ }
+
+ void _writeAuthority(StringSink ss) {
+ _addIfNonEmpty(ss, userInfo, userInfo, "@");
+ ss.write(host == null ? "null" :
+ host.contains(':') ? '[$host]' : host);
+ if (port != 0) {
+ ss.write(":");
+ ss.write(port.toString());
+ }
+ }
+
+ String toString() {
+ StringBuffer sb = new StringBuffer();
+ _addIfNonEmpty(sb, scheme, scheme, ':');
+ if (hasAuthority || (scheme == "file")) {
+ sb.write("//");
+ _writeAuthority(sb);
+ }
+ sb.write(path);
+ _addIfNonEmpty(sb, query, "?", query);
+ _addIfNonEmpty(sb, fragment, "#", fragment);
+ return sb.toString();
+ }
+
+ bool operator==(other) {
+ if (other is! Uri) return false;
+ Uri uri = other;
+ return scheme == uri.scheme &&
+ userInfo == uri.userInfo &&
+ host == uri.host &&
+ port == uri.port &&
+ path == uri.path &&
+ query == uri.query &&
+ fragment == uri.fragment;
+ }
+
+ int get hashCode {
+ int combine(part, current) {
+ // The sum is truncated to 30 bits to make sure it fits into a Smi.
+ return (current * 31 + part.hashCode) & 0x3FFFFFFF;
+ }
+ return combine(scheme, combine(userInfo, combine(host, combine(port,
+ combine(path, combine(query, combine(fragment, 1)))))));
+ }
+
+ static void _addIfNonEmpty(StringBuffer sb, String test,
+ String first, String second) {
+ if ("" != test) {
+ sb.write(first);
+ sb.write(second);
+ }
+ }
+
+ /**
+ * Encode the string [component] using percent-encoding to make it
+ * safe for literal use as a URI component.
+ *
+ * All characters except uppercase and lowercase letters, digits and
+ * the characters `!$&'()*+,;=:@` are percent-encoded. This is the
+ * set of characters specified in RFC 2396 and the which is
+ * specified for the encodeUriComponent in ECMA-262 version 5.1.
+ *
+ * When manually encoding path segments or query components remember
+ * to encode each part separately before building the path or query
+ * string.
+ *
+ * For encoding the query part consider using
+ * [encodeQueryComponent].
+ *
+ * To avoid the need for explicitly encoding use the [pathSegments]
+ * and [queryParameters] optional named arguments when constructing
+ * a [Uri].
+ */
+ static String encodeComponent(String component) {
+ 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.
+ *
+ * Spaces will be replaced with plus and all characters except for
+ * uppercase and lowercase letters, decimal digits and the
+ * characters `-._~`. Note that the set of characters encoded is a
+ * superset of what HTML 4.01 says as it refers to RFC 1738 for
+ * reserved characters.
+ *
+ * When manually encoding query components remember to encode each
+ * part separately before building the query string.
+ *
+ * To avoid the need for explicitly encoding the query use the
+ * [queryParameters] optional named arguments when constructing a
+ * [Uri].
+ *
+ * See http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4.2 for more
+ * details.
+ */
+ static String encodeQueryComponent(String component) {
+ return _uriEncode(_unreservedTable, component, spaceToPlus: true);
+ }
+
+ /**
+ * Decodes the percent-encoding in [encodedComponent].
+ *
+ * Note that decoding a URI component might change its meaning as
+ * some of the decoded characters could be characters with are
+ * delimiters for a given URI componene type. Always split a URI
+ * component using the delimiters for the component before decoding
+ * the individual parts.
+ *
+ * For handling the [path] and [query] components consider using
+ * [pathSegments] and [queryParameters] to get the separated and
+ * decoded component.
+ */
+ static String decodeComponent(String encodedComponent) {
+ return _uriDecode(encodedComponent);
+ }
+
+ static String decodeQueryComponent(String encodedComponent) {
+ return _uriDecode(encodedComponent, plusToSpace: true);
+ }
+
+ /**
+ * Encode the string [uri] using percent-encoding to make it
+ * safe for literal use as a full URI.
+ *
+ * All characters except uppercase and lowercase letters, digits and
+ * the characters `!#$&'()*+,-./:;=?@_~` are percent-encoded. This
+ * is the set of characters specified in in ECMA-262 version 5.1 for
+ * the encodeURI function .
+ */
+ static String encodeFull(String uri) {
+ return _uriEncode(_encodeFullTable, uri);
+ }
+
+ /**
+ * Decodes the percent-encoding in [uri].
+ *
+ * Note that decoding a full URI might change its meaning as some of
+ * the decoded characters could be reserved characters. In most
+ * cases an encoded URI should be parsed into components using
+ * [Uri.parse] before decoding the separate components.
+ */
+ static String decodeFull(String uri) {
+ return _uriDecode(uri);
+ }
+
+ // Frequently used character codes.
+ static const int _PERCENT = 0x25;
+ static const int _PLUS = 0x2B;
+ static const int _ZERO = 0x30;
+ static const int _NINE = 0x39;
+ static const int _COLON = 0x3A;
+ static const int _UPPER_CASE_A = 0x41;
+ static const int _UPPER_CASE_F = 0x46;
+ static const int _LOWER_CASE_A = 0x61;
+ static const int _LOWER_CASE_F = 0x66;
+
+ /**
+ * This is the internal implementation of JavaScript's encodeURI function.
+ * It encodes all characters in the string [text] except for those
+ * that appear in [canonicalTable], and returns the escaped string.
+ */
+ static String _uriEncode(List<int> canonicalTable,
+ String text,
+ {bool spaceToPlus: false}) {
+ byteToHex(int v) {
+ final String hex = '0123456789ABCDEF';
+ return '%${hex[v >> 4]}${hex[v & 0x0f]}';
+ }
+
+ StringBuffer result = new StringBuffer();
+ for (int i = 0; i < text.length; i++) {
+ int ch = text.codeUnitAt(i);
+ if (ch < 128 && ((canonicalTable[ch >> 4] & (1 << (ch & 0x0f))) != 0)) {
+ result.write(text[i]);
+ } else if (spaceToPlus && text[i] == " ") {
+ result.write("+");
+ } else {
+ if (ch >= 0xD800 && ch < 0xDC00) {
+ // Low surrogate. We expect a next char high surrogate.
+ ++i;
+ int nextCh = text.length == i ? 0 : text.codeUnitAt(i);
+ if (nextCh >= 0xDC00 && nextCh < 0xE000) {
+ // convert the pair to a U+10000 codepoint
+ ch = 0x10000 + ((ch - 0xD800) << 10) + (nextCh - 0xDC00);
+ } else {
+ throw new ArgumentError('Malformed URI');
+ }
+ }
+ for (int codepoint in codepointsToUtf8([ch])) {
+ result.write(byteToHex(codepoint));
+ }
+ }
+ }
+ return result.toString();
+ }
+
+ /**
+ * Convert a byte (2 character hex sequence) in string [s] starting
+ * at position [pos] to its ordinal value
+ */
+ static int _hexCharPairToByte(String s, int pos) {
+ int byte = 0;
+ for (int i = 0; i < 2; i++) {
+ var charCode = s.codeUnitAt(pos + i);
+ 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");
+ }
+ }
+ }
+ return byte;
+ }
+
+ /**
+ * A JavaScript-like decodeURI function. It unescapes the string [text] and
+ * returns the unescaped string.
+ */
+ static String _uriDecode(String text, {bool plusToSpace: false}) {
+ StringBuffer result = new StringBuffer();
+ List<int> codepoints = new List<int>();
+ for (int i = 0; i < text.length;) {
+ int ch = text.codeUnitAt(i);
+ if (ch != _PERCENT) {
+ if (plusToSpace && ch == _PLUS) {
+ result.write(" ");
+ } else {
+ result.writeCharCode(ch);
+ }
+ i++;
+ } else {
+ codepoints.clear();
+ while (ch == _PERCENT) {
+ if (++i > text.length - 2) {
+ throw new ArgumentError('Truncated URI');
+ }
+ codepoints.add(_hexCharPairToByte(text, i));
+ i += 2;
+ if (i == text.length) break;
+ ch = text.codeUnitAt(i);
+ }
+ result.write(decodeUtf8(codepoints));
+ }
+ }
+ return result.toString();
+ }
+
+ // Tables of char-codes organized as a bit vector of 128 bits where
+ // each bit indicate whether a character code on the 0-127 needs to
+ // be escaped or not.
+
+ // The unreserved characters of RFC 3986.
+ static const _unreservedTable = const [
+ // LSB MSB
+ // | |
+ 0x0000, // 0x00 - 0x0f 0000000000000000
+ 0x0000, // 0x10 - 0x1f 0000000000000000
+ // -.
+ 0x6000, // 0x20 - 0x2f 0000000000000110
+ // 0123456789
+ 0x03ff, // 0x30 - 0x3f 1111111111000000
+ // ABCDEFGHIJKLMNO
+ 0xfffe, // 0x40 - 0x4f 0111111111111111
+ // PQRSTUVWXYZ _
+ 0x87ff, // 0x50 - 0x5f 1111111111100001
+ // abcdefghijklmno
+ 0xfffe, // 0x60 - 0x6f 0111111111111111
+ // pqrstuvwxyz ~
+ 0x47ff]; // 0x70 - 0x7f 1111111111100010
+
+ // The unreserved characters of RFC 2396.
+ static const _unreserved2396Table = const [
+ // LSB MSB
+ // | |
+ 0x0000, // 0x00 - 0x0f 0000000000000000
+ 0x0000, // 0x10 - 0x1f 0000000000000000
+ // ! '()* -.
+ 0x6782, // 0x20 - 0x2f 0100000111100110
+ // 0123456789
+ 0x03ff, // 0x30 - 0x3f 1111111111000000
+ // ABCDEFGHIJKLMNO
+ 0xfffe, // 0x40 - 0x4f 0111111111111111
+ // PQRSTUVWXYZ _
+ 0x87ff, // 0x50 - 0x5f 1111111111100001
+ // abcdefghijklmno
+ 0xfffe, // 0x60 - 0x6f 0111111111111111
+ // pqrstuvwxyz ~
+ 0x47ff]; // 0x70 - 0x7f 1111111111100010
+
+ // Table of reserved characters specified by ECMAScript 5.
+ static const _encodeFullTable = const [
+ // LSB MSB
+ // | |
+ 0x0000, // 0x00 - 0x0f 0000000000000000
+ 0x0000, // 0x10 - 0x1f 0000000000000000
+ // ! #$ &'()*+,-./
+ 0xf7da, // 0x20 - 0x2f 0101101111101111
+ // 0123456789:; = ?
+ 0xafff, // 0x30 - 0x3f 1111111111110101
+ // @ABCDEFGHIJKLMNO
+ 0xffff, // 0x40 - 0x4f 1111111111111111
+ // PQRSTUVWXYZ _
+ 0x87ff, // 0x50 - 0x5f 1111111111100001
+ // abcdefghijklmno
+ 0xfffe, // 0x60 - 0x6f 0111111111111111
+ // pqrstuvwxyz ~
+ 0x47ff]; // 0x70 - 0x7f 1111111111100010
+
+ // Characters allowed in the scheme.
+ static const _schemeTable = const [
+ // LSB MSB
+ // | |
+ 0x0000, // 0x00 - 0x0f 0000000000000000
+ 0x0000, // 0x10 - 0x1f 0000000000000000
+ // + -.
+ 0x6800, // 0x20 - 0x2f 0000000000010110
+ // 0123456789
+ 0x03ff, // 0x30 - 0x3f 1111111111000000
+ // ABCDEFGHIJKLMNO
+ 0xfffe, // 0x40 - 0x4f 0111111111111111
+ // PQRSTUVWXYZ
+ 0x07ff, // 0x50 - 0x5f 1111111111100001
+ // abcdefghijklmno
+ 0xfffe, // 0x60 - 0x6f 0111111111111111
+ // pqrstuvwxyz
+ 0x07ff]; // 0x70 - 0x7f 1111111111100010
+
+ // Characters allowed in scheme except for upper case letters.
+ static const _schemeLowerTable = const [
+ // LSB MSB
+ // | |
+ 0x0000, // 0x00 - 0x0f 0000000000000000
+ 0x0000, // 0x10 - 0x1f 0000000000000000
+ // + -.
+ 0x6800, // 0x20 - 0x2f 0000000000010110
+ // 0123456789
+ 0x03ff, // 0x30 - 0x3f 1111111111000000
+ //
+ 0x0000, // 0x40 - 0x4f 0111111111111111
+ //
+ 0x0000, // 0x50 - 0x5f 1111111111100001
+ // abcdefghijklmno
+ 0xfffe, // 0x60 - 0x6f 0111111111111111
+ // pqrstuvwxyz
+ 0x07ff]; // 0x70 - 0x7f 1111111111100010
+
+ // Sub delimiter characters combined with unreserved as of 3986.
+ // sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
+ // / "*" / "+" / "," / ";" / "="
+ // RFC 3986 section 2.3.
+ // unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
+ static const _subDelimitersTable = const [
+ // LSB MSB
+ // | |
+ 0x0000, // 0x00 - 0x0f 0000000000000000
+ 0x0000, // 0x10 - 0x1f 0000000000000000
+ // ! $ &'()*+,-.
+ 0x7fd2, // 0x20 - 0x2f 0100101111111110
+ // 0123456789 ; =
+ 0x2bff, // 0x30 - 0x3f 1111111111010100
+ // ABCDEFGHIJKLMNO
+ 0xfffe, // 0x40 - 0x4f 0111111111111111
+ // PQRSTUVWXYZ _
+ 0x87ff, // 0x50 - 0x5f 1111111111100001
+ // abcdefghijklmno
+ 0xfffe, // 0x60 - 0x6f 0111111111111111
+ // pqrstuvwxyz ~
+ 0x47ff]; // 0x70 - 0x7f 1111111111100010
+
+ // Characters allowed in the path as of RFC 3986.
+ // RFC 3986 section 3.3.
+ // pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
+ static const _pathCharTable = const [
+ // LSB MSB
+ // | |
+ 0x0000, // 0x00 - 0x0f 0000000000000000
+ 0x0000, // 0x10 - 0x1f 0000000000000000
+ // ! $ &'()*+,-.
+ 0x7fd2, // 0x20 - 0x2f 0100101111111110
+ // 0123456789:; =
+ 0x2fff, // 0x30 - 0x3f 1111111111110100
+ // @ABCDEFGHIJKLMNO
+ 0xffff, // 0x40 - 0x4f 1111111111111111
+ // PQRSTUVWXYZ _
+ 0x87ff, // 0x50 - 0x5f 1111111111100001
+ // abcdefghijklmno
+ 0xfffe, // 0x60 - 0x6f 0111111111111111
+ // pqrstuvwxyz ~
+ 0x47ff]; // 0x70 - 0x7f 1111111111100010
+
+ // Characters allowed in the query as of RFC 3986.
+ // RFC 3986 section 3.4.
+ // query = *( pchar / "/" / "?" )
+ static const _queryCharTable = const [
+ // LSB MSB
+ // | |
+ 0x0000, // 0x00 - 0x0f 0000000000000000
+ 0x0000, // 0x10 - 0x1f 0000000000000000
+ // ! $ &'()*+,-./
+ 0xffd2, // 0x20 - 0x2f 0100101111111111
+ // 0123456789:; = ?
+ 0xafff, // 0x30 - 0x3f 1111111111110101
+ // @ABCDEFGHIJKLMNO
+ 0xffff, // 0x40 - 0x4f 1111111111111111
+ // PQRSTUVWXYZ _
+ 0x87ff, // 0x50 - 0x5f 1111111111100001
+ // abcdefghijklmno
+ 0xfffe, // 0x60 - 0x6f 0111111111111111
+ // pqrstuvwxyz ~
+ 0x47ff]; // 0x70 - 0x7f 1111111111100010
+}
diff --git a/sdk/lib/html/dart2js/html_dart2js.dart b/sdk/lib/html/dart2js/html_dart2js.dart
index 8e53e7f..021a3ca 100644
--- a/sdk/lib/html/dart2js/html_dart2js.dart
+++ b/sdk/lib/html/dart2js/html_dart2js.dart
@@ -45,7 +45,7 @@
HtmlDocument get document => JS('HtmlDocument', 'document');
Element query(String selector) => document.query(selector);
-List<Element> queryAll(String selector) => document.queryAll(selector);
+ElementList queryAll(String selector) => document.queryAll(selector);
// Workaround for tags like <cite> that lack their own Element subclass --
// Dart issue 1990.
@@ -11415,12 +11415,12 @@
*
* var request = new HttpRequest();
* request.open('GET', 'http://dartlang.org')
- * request.on.load.add((event) => print('Request complete'));
+ * request.onLoad.add((event) => print('Request complete'));
*
* is the (more verbose) equivalent of
*
- * var request = new HttpRequest.get('http://dartlang.org',
- * (event) => print('Request complete'));
+ * HttpRequest.getString('http://dartlang.org').then(
+ * (result) => print('Request complete: $result'));
*/
@DomName('XMLHttpRequest.XMLHttpRequest')
@DocsEditable
@@ -17864,9 +17864,15 @@
@SupportedBrowser(SupportedBrowser.CHROME)
@Experimental
// http://dev.w3.org/2011/webrtc/editor/webrtc.html#idl-def-RTCIceCandidate
-class RtcIceCandidate native "RTCIceCandidate" {
+class RtcIceCandidate native "RTCIceCandidate,mozRTCIceCandidate" {
factory RtcIceCandidate(Map dictionary) {
- return JS('RtcIceCandidate', 'new RTCIceCandidate(#)',
+ // TODO(efortuna): Remove this check if when you can actually construct with
+ // the unprefixed RTCIceCandidate in Firefox (currently both are defined,
+ // but one can't be used as a constructor).
+ var constructorName = JS('', 'window[#]',
+ Device.isFirefox ? '${Device.propertyPrefix}RTCIceCandidate' :
+ 'RTCIceCandidate');
+ return JS('RtcIceCandidate', 'new #(#)', constructorName,
convertDartToNative_SerializedScriptValue(dictionary));
}
@@ -17907,7 +17913,7 @@
@SupportedBrowser(SupportedBrowser.CHROME)
@Experimental
// http://dev.w3.org/2011/webrtc/editor/webrtc.html#idl-def-RTCPeerConnection
-class RtcPeerConnection extends EventTarget native "RTCPeerConnection" {
+class RtcPeerConnection extends EventTarget native "RTCPeerConnection,mozRTCPeerConnection" {
factory RtcPeerConnection(Map rtcIceServers, [Map mediaConstraints]) {
var constructorName = JS('RtcPeerConnection', 'window[#]',
'${Device.propertyPrefix}RTCPeerConnection');
@@ -17929,11 +17935,12 @@
// Currently in Firefox some of the RTC elements are defined but throw an
// error unless the user has specifically enabled them in their
// about:config. So we have to construct an element to actually test if RTC
- // is supported at at the given time.
+ // is supported at the given time.
try {
- var c = new RtcPeerConnection({"iceServers": [ {"url":"stun:foo.com"}]});
- return c is RtcPeerConnection;
- } catch (_) {}
+ new RtcPeerConnection(
+ {"iceServers": [ {"url":"stun:localhost"}]});
+ return true;
+ } catch (_) { return false;}
return false;
}
Future<RtcSessionDescription> createOffer([Map mediaConstraints]) {
@@ -18216,8 +18223,6 @@
Stream<Event> get onSignalingStateChange => signalingStateChangeEvent.forTarget(this);
}
-
-
// 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.
@@ -18227,9 +18232,16 @@
@SupportedBrowser(SupportedBrowser.CHROME)
@Experimental
// http://dev.w3.org/2011/webrtc/editor/webrtc.html#idl-def-RTCSessionDescription
-class RtcSessionDescription native "RTCSessionDescription" {
+class RtcSessionDescription native "RTCSessionDescription,mozRTCSessionDescription" {
factory RtcSessionDescription(Map dictionary) {
- return JS('RtcSessionDescription', 'new RTCSessionDescription(#)',
+ // TODO(efortuna): Remove this check if when you can actually construct with
+ // the unprefixed RTCIceCandidate in Firefox (currently both are defined,
+ // but one can't be used as a constructor).
+ var constructorName = JS('', 'window[#]',
+ Device.isFirefox ? '${Device.propertyPrefix}RTCSessionDescription' :
+ 'RTCSessionDescription');
+ return JS('RtcSessionDescription',
+ 'new #(#)', constructorName,
convertDartToNative_SerializedScriptValue(dictionary));
}
@@ -19771,6 +19783,8 @@
bool get isEmpty => $dom_key(0) == null;
+ bool get isNotEmpty => !isEmpty;
+
@JSName('length')
@DomName('Storage.length')
@DocsEditable
@@ -24869,6 +24883,11 @@
}
/**
+ * Returns true if there is at least one {key, value} pair in the map.
+ */
+ bool get isNotEmpty => !isEmpty;
+
+ /**
* Checks to see if the node should be included in this map.
*/
bool _matches(Node node);
@@ -25015,6 +25034,8 @@
// TODO: Use lazy iterator when it is available on Map.
bool get isEmpty => length == 0;
+ bool get isNotEmpty => !isEmpty;
+
// Helpers.
String _attr(String key) => 'data-$key';
bool _matches(String key) => key.startsWith('data-');
@@ -25460,6 +25481,9 @@
/**
* Gets a [Stream] for this event type, on the specified target.
*
+ * This will always return a broadcast stream so multiple listeners can be
+ * used simultaneously.
+ *
* This may be used to capture DOM events:
*
* Element.keyDownEvent.forTarget(element, useCapture: true).listen(...);
@@ -26825,7 +26849,8 @@
// TODO(jmesserly): if the path is empty, or the object is! Observable, we
// can optimize the PathObserver to be more lightweight.
- _values = new StreamController(onListen: _observe, onCancel: _unobserve);
+ _values = new StreamController.broadcast(onListen: _observe,
+ onCancel: _unobserve);
if (_isValid) {
var segments = [];
diff --git a/sdk/lib/html/dartium/html_dartium.dart b/sdk/lib/html/dartium/html_dartium.dart
index a0b6278..0d36c93 100644
--- a/sdk/lib/html/dartium/html_dartium.dart
+++ b/sdk/lib/html/dartium/html_dartium.dart
@@ -52,7 +52,7 @@
Element query(String selector) => document.query(selector);
-List<Element> queryAll(String selector) => document.queryAll(selector);
+ElementList queryAll(String selector) => document.queryAll(selector);
int _getNewIsolateId() => _Utils._getNewIsolateId();
@@ -682,6 +682,9 @@
@DomName('Blob')
class Blob extends NativeFieldWrapperClass1 {
Blob.internal();
+
+ @DomName('Blob.Blob')
+ @DocsEditable
factory Blob(List blobParts, [String type, String endings]) => _create(blobParts, type, endings);
@DocsEditable
@@ -10818,6 +10821,9 @@
@SupportedBrowser(SupportedBrowser.SAFARI)
class FormData extends NativeFieldWrapperClass1 {
FormData.internal();
+
+ @DomName('FormData.DOMFormData')
+ @DocsEditable
factory FormData([FormElement form]) => _create(form);
@DocsEditable
@@ -11858,6 +11864,23 @@
@DomName('XMLHttpRequest.readystatechangeEvent')
@DocsEditable
static const EventStreamProvider<ProgressEvent> readyStateChangeEvent = const EventStreamProvider<ProgressEvent>('readystatechange');
+
+ /**
+ * General constructor for any type of request (GET, POST, etc).
+ *
+ * This call is used in conjunction with [open]:
+ *
+ * var request = new HttpRequest();
+ * request.open('GET', 'http://dartlang.org')
+ * request.onLoad.add((event) => print('Request complete'));
+ *
+ * is the (more verbose) equivalent of
+ *
+ * HttpRequest.getString('http://dartlang.org').then(
+ * (result) => print('Request complete: $result'));
+ */
+ @DomName('XMLHttpRequest.XMLHttpRequest')
+ @DocsEditable
factory HttpRequest() => _create();
@DocsEditable
@@ -15439,6 +15462,9 @@
@Unstable
class MessageChannel extends NativeFieldWrapperClass1 {
MessageChannel.internal();
+
+ @DomName('MessageChannel.MessageChannel')
+ @DocsEditable
factory MessageChannel() => _create();
@DocsEditable
@@ -16181,6 +16207,9 @@
@Experimental
class MutationObserver extends NativeFieldWrapperClass1 {
MutationObserver.internal();
+
+ @DomName('MutationObserver.MutationObserver')
+ @DocsEditable
factory MutationObserver(MutationCallback callback) => _create(callback);
@DocsEditable
@@ -19400,8 +19429,6 @@
Stream<Event> get onSignalingStateChange => signalingStateChangeEvent.forTarget(this);
}
-
-
// 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.
@@ -21245,6 +21272,8 @@
int get length => $dom_length;
bool get isEmpty => $dom_key(0) == null;
+
+ bool get isNotEmpty => !isEmpty;
Storage.internal();
@DomName('Storage.length')
@@ -25582,6 +25611,9 @@
@Experimental // non-standard
class _DomPoint extends NativeFieldWrapperClass1 {
_DomPoint.internal();
+
+ @DomName('WebKitPoint.DOMPoint')
+ @DocsEditable
factory _DomPoint(num x, num y) => _create(x, y);
@DocsEditable
@@ -26725,6 +26757,11 @@
}
/**
+ * Returns true if there is at least one {key, value} pair in the map.
+ */
+ bool get isNotEmpty => !isEmpty;
+
+ /**
* Checks to see if the node should be included in this map.
*/
bool _matches(Node node);
@@ -26871,6 +26908,8 @@
// TODO: Use lazy iterator when it is available on Map.
bool get isEmpty => length == 0;
+ bool get isNotEmpty => !isEmpty;
+
// Helpers.
String _attr(String key) => 'data-$key';
bool _matches(String key) => key.startsWith('data-');
@@ -27316,6 +27355,9 @@
/**
* Gets a [Stream] for this event type, on the specified target.
*
+ * This will always return a broadcast stream so multiple listeners can be
+ * used simultaneously.
+ *
* This may be used to capture DOM events:
*
* Element.keyDownEvent.forTarget(element, useCapture: true).listen(...);
@@ -28681,7 +28723,8 @@
// TODO(jmesserly): if the path is empty, or the object is! Observable, we
// can optimize the PathObserver to be more lightweight.
- _values = new StreamController(onListen: _observe, onCancel: _unobserve);
+ _values = new StreamController.broadcast(onListen: _observe,
+ onCancel: _unobserve);
if (_isValid) {
var segments = [];
@@ -31037,6 +31080,7 @@
Iterable<String> get values => Maps.getValues(this);
int get length => Maps.length(this);
bool get isEmpty => Maps.isEmpty(this);
+ bool get isNotEmpty => Maps.isNotEmpty(this);
}
final Future<SendPort> __HELPER_ISOLATE_PORT =
diff --git a/sdk/lib/html/html_common/css_class_set.dart b/sdk/lib/html/html_common/css_class_set.dart
index df50d62..ab17d10 100644
--- a/sdk/lib/html/html_common/css_class_set.dart
+++ b/sdk/lib/html/html_common/css_class_set.dart
@@ -56,6 +56,8 @@
bool get isEmpty => readClasses().isEmpty;
+ bool get isNotEmpty => readClasses().isNotEmpty;
+
int get length => readClasses().length;
String reduce(String combine(String value, String element)) {
diff --git a/sdk/lib/indexed_db/dart2js/indexed_db_dart2js.dart b/sdk/lib/indexed_db/dart2js/indexed_db_dart2js.dart
index b8427c5..99346e1 100644
--- a/sdk/lib/indexed_db/dart2js/indexed_db_dart2js.dart
+++ b/sdk/lib/indexed_db/dart2js/indexed_db_dart2js.dart
@@ -404,7 +404,14 @@
if (onBlocked != null) {
request.onBlocked.listen(onBlocked);
}
- return _completeRequest(request);
+ var completer = new Completer.sync();
+ request.onSuccess.listen((e) {
+ completer.complete(this);
+ });
+ request.onError.listen((e) {
+ completer.completeError(e);
+ });
+ return completer.future;
} catch (e, stacktrace) {
return new Future.error(e, stacktrace);
}
@@ -911,7 +918,7 @@
List keyPath_1 = convertDartToNative_StringArray(keyPath);
return _$dom_createIndex_1(name, keyPath_1);
}
- if ((keyPath is List<String> || keyPath == null)) {
+ if ((keyPath is List<String> || keyPath == null) && ?options) {
List keyPath_2 = convertDartToNative_StringArray(keyPath);
var options_3 = convertDartToNative_Dictionary(options);
return _$dom_createIndex_2(name, keyPath_2, options_3);
@@ -919,7 +926,7 @@
if ((keyPath is String || keyPath == null) && !?options) {
return _$dom_createIndex_3(name, keyPath);
}
- if ((keyPath is String || keyPath == null)) {
+ if ((keyPath is String || keyPath == null) && ?options) {
var options_4 = convertDartToNative_Dictionary(options);
return _$dom_createIndex_4(name, keyPath, options_4);
}
diff --git a/sdk/lib/indexed_db/dartium/indexed_db_dartium.dart b/sdk/lib/indexed_db/dartium/indexed_db_dartium.dart
index 15076fb..1a539d9 100644
--- a/sdk/lib/indexed_db/dartium/indexed_db_dartium.dart
+++ b/sdk/lib/indexed_db/dartium/indexed_db_dartium.dart
@@ -279,7 +279,14 @@
if (onBlocked != null) {
request.onBlocked.listen(onBlocked);
}
- return _completeRequest(request);
+ var completer = new Completer.sync();
+ request.onSuccess.listen((e) {
+ completer.complete(this);
+ });
+ request.onError.listen((e) {
+ completer.completeError(e);
+ });
+ return completer.future;
} catch (e, stacktrace) {
return new Future.error(e, stacktrace);
}
diff --git a/sdk/lib/io/buffer_list.dart b/sdk/lib/io/buffer_list.dart
index c61710f..eab260b 100644
--- a/sdk/lib/io/buffer_list.dart
+++ b/sdk/lib/io/buffer_list.dart
@@ -83,6 +83,11 @@
bool get isEmpty => _length == 0;
/**
+ * Returns whether the buffer list is not empty.
+ */
+ bool get isNotEmpty => !isEmpty;
+
+ /**
* Clears the content of the buffer list.
*/
void clear() {
diff --git a/sdk/lib/io/crypto.dart b/sdk/lib/io/crypto.dart
new file mode 100644
index 0000000..35bd01c
--- /dev/null
+++ b/sdk/lib/io/crypto.dart
@@ -0,0 +1,448 @@
+// 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.
+
+part of dart.io;
+
+class _CryptoUtils {
+ static String bytesToHex(List<int> bytes) {
+ var result = new StringBuffer();
+ for (var part in bytes) {
+ result.write('${part < 16 ? '0' : ''}${part.toRadixString(16)}');
+ }
+ return result.toString();
+ }
+
+ static const int PAD = 61; // '='
+ static const int CR = 13; // '\r'
+ static const int LF = 10; // '\n'
+ static const int LINE_LENGTH = 76;
+
+ static const String _encodeTable =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+ static const String _encodeTableUrlSafe =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
+
+ // Lookup table used for finding Base 64 alphabet index of a given byte.
+ // -2 : Outside Base 64 alphabet.
+ // -1 : '\r' or '\n'
+ // 0 : = (Padding character).
+ // >0 : Base 64 alphabet index of given byte.
+ static const List<int> _decodeTable =
+ const [ -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -1, -2, -2, -1, -2, -2,
+ -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
+ -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, 62, -2, 62, -2, 63,
+ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -2, -2, -2, 0, -2, -2,
+ -2, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -2, -2, -2, -2, 63,
+ -2, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -2, -2, -2, -2, -2,
+ -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
+ -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
+ -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
+ -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
+ -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
+ -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
+ -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
+ -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2 ];
+
+ static String bytesToBase64(List<int> bytes,
+ [bool urlSafe = false,
+ bool addLineSeparator = false]) {
+ int len = bytes.length;
+ if (len == 0) {
+ return "";
+ }
+ final String lookup = urlSafe ? _encodeTableUrlSafe : _encodeTable;
+ // Size of 24 bit chunks.
+ final int remainderLength = len.remainder(3);
+ final int chunkLength = len - remainderLength;
+ // Size of base output.
+ int outputLen = ((len ~/ 3) * 4) + ((remainderLength > 0) ? 4 : 0);
+ // Add extra for line separators.
+ if (addLineSeparator) {
+ outputLen += ((outputLen - 1) ~/ LINE_LENGTH) << 1;
+ }
+ List<int> out = new List<int>(outputLen);
+
+ // Encode 24 bit chunks.
+ int j = 0, i = 0, c = 0;
+ while (i < chunkLength) {
+ int x = ((bytes[i++] << 16) & 0xFFFFFF) |
+ ((bytes[i++] << 8) & 0xFFFFFF) |
+ bytes[i++];
+ out[j++] = lookup.codeUnitAt(x >> 18);
+ out[j++] = lookup.codeUnitAt((x >> 12) & 0x3F);
+ out[j++] = lookup.codeUnitAt((x >> 6) & 0x3F);
+ out[j++] = lookup.codeUnitAt(x & 0x3f);
+ // Add optional line separator for each 76 char output.
+ if (addLineSeparator && ++c == 19 && j < outputLen - 2) {
+ out[j++] = CR;
+ out[j++] = LF;
+ c = 0;
+ }
+ }
+
+ // If input length if not a multiple of 3, encode remaining bytes and
+ // add padding.
+ if (remainderLength == 1) {
+ int x = bytes[i];
+ out[j++] = lookup.codeUnitAt(x >> 2);
+ out[j++] = lookup.codeUnitAt((x << 4) & 0x3F);
+ out[j++] = PAD;
+ out[j++] = PAD;
+ } else if (remainderLength == 2) {
+ int x = bytes[i];
+ int y = bytes[i + 1];
+ out[j++] = lookup.codeUnitAt(x >> 2);
+ out[j++] = lookup.codeUnitAt(((x << 4) | (y >> 4)) & 0x3F);
+ out[j++] = lookup.codeUnitAt((y << 2) & 0x3F);
+ out[j++] = PAD;
+ }
+
+ return new String.fromCharCodes(out);
+ }
+
+ static List<int> base64StringToBytes(String input,
+ [bool ignoreInvalidCharacters = true]) {
+ int len = input.length;
+ if (len == 0) {
+ return new List<int>(0);
+ }
+
+ // Count '\r', '\n' and illegal characters, For illegal characters,
+ // if [ignoreInvalidCharacters] is false, throw an exception.
+ int extrasLen = 0;
+ for (int i = 0; i < len; i++) {
+ int c = _decodeTable[input.codeUnitAt(i)];
+ if (c < 0) {
+ extrasLen++;
+ if(c == -2 && !ignoreInvalidCharacters) {
+ throw new FormatException('Invalid character: ${input[i]}');
+ }
+ }
+ }
+
+ if ((len - extrasLen) % 4 != 0) {
+ throw new FormatException('''Size of Base 64 characters in Input
+ must be a multiple of 4. Input: $input''');
+ }
+
+ // Count pad characters, ignore illegal characters at the end.
+ int padLength = 0;
+ for (int i = len - 1; i >= 0; i--) {
+ int currentCodeUnit = input.codeUnitAt(i);
+ if (_decodeTable[currentCodeUnit] > 0) break;
+ if (currentCodeUnit == PAD) padLength++;
+ }
+ int outputLen = (((len - extrasLen) * 6) >> 3) - padLength;
+ List<int> out = new List<int>(outputLen);
+
+ for (int i = 0, o = 0; o < outputLen;) {
+ // Accumulate 4 valid 6 bit Base 64 characters into an int.
+ int x = 0;
+ for (int j = 4; j > 0;) {
+ int c = _decodeTable[input.codeUnitAt(i++)];
+ if (c >= 0) {
+ x = ((x << 6) & 0xFFFFFF) | c;
+ j--;
+ }
+ }
+ out[o++] = x >> 16;
+ if (o < outputLen) {
+ out[o++] = (x >> 8) & 0xFF;
+ if (o < outputLen) out[o++] = x & 0xFF;
+ }
+ }
+ return out;
+ }
+
+}
+
+// Constants.
+const _MASK_8 = 0xff;
+const _MASK_32 = 0xffffffff;
+const _BITS_PER_BYTE = 8;
+const _BYTES_PER_WORD = 4;
+
+// Base class encapsulating common behavior for cryptographic hash
+// functions.
+abstract class _HashBase {
+ _HashBase(int this._chunkSizeInWords,
+ int this._digestSizeInWords,
+ bool this._bigEndianWords)
+ : _pendingData = [] {
+ _currentChunk = new List(_chunkSizeInWords);
+ _h = new List(_digestSizeInWords);
+ }
+
+ // Update the hasher with more data.
+ add(List<int> data) {
+ if (_digestCalled) {
+ throw new StateError(
+ 'Hash update method called after digest was retrieved');
+ }
+ _lengthInBytes += data.length;
+ _pendingData.addAll(data);
+ _iterate();
+ }
+
+ // Finish the hash computation and return the digest string.
+ List<int> close() {
+ if (_digestCalled) {
+ return _resultAsBytes();
+ }
+ _digestCalled = true;
+ _finalizeData();
+ _iterate();
+ assert(_pendingData.length == 0);
+ return _resultAsBytes();
+ }
+
+ // Returns the block size of the hash in bytes.
+ int get blockSize {
+ return _chunkSizeInWords * _BYTES_PER_WORD;
+ }
+
+ // Create a fresh instance of this Hash.
+ newInstance();
+
+ // One round of the hash computation.
+ _updateHash(List<int> m);
+
+ // Helper methods.
+ _add32(x, y) => (x + y) & _MASK_32;
+ _roundUp(val, n) => (val + n - 1) & -n;
+
+ // Rotate left limiting to unsigned 32-bit values.
+ int _rotl32(int val, int shift) {
+ var mod_shift = shift & 31;
+ return ((val << mod_shift) & _MASK_32) |
+ ((val & _MASK_32) >> (32 - mod_shift));
+ }
+
+
+ // Compute the final result as a list of bytes from the hash words.
+ _resultAsBytes() {
+ var result = [];
+ for (var i = 0; i < _h.length; i++) {
+ result.addAll(_wordToBytes(_h[i]));
+ }
+ return result;
+ }
+
+ // Converts a list of bytes to a chunk of 32-bit words.
+ _bytesToChunk(List<int> data, int dataIndex) {
+ assert((data.length - dataIndex) >= (_chunkSizeInWords * _BYTES_PER_WORD));
+
+ for (var wordIndex = 0; wordIndex < _chunkSizeInWords; wordIndex++) {
+ var w3 = _bigEndianWords ? data[dataIndex] : data[dataIndex + 3];
+ var w2 = _bigEndianWords ? data[dataIndex + 1] : data[dataIndex + 2];
+ var w1 = _bigEndianWords ? data[dataIndex + 2] : data[dataIndex + 1];
+ var w0 = _bigEndianWords ? data[dataIndex + 3] : data[dataIndex];
+ dataIndex += 4;
+ var word = (w3 & 0xff) << 24;
+ word |= (w2 & _MASK_8) << 16;
+ word |= (w1 & _MASK_8) << 8;
+ word |= (w0 & _MASK_8);
+ _currentChunk[wordIndex] = word;
+ }
+ }
+
+ // Convert a 32-bit word to four bytes.
+ _wordToBytes(int word) {
+ List<int> bytes = new List(_BYTES_PER_WORD);
+ bytes[0] = (word >> (_bigEndianWords ? 24 : 0)) & _MASK_8;
+ bytes[1] = (word >> (_bigEndianWords ? 16 : 8)) & _MASK_8;
+ bytes[2] = (word >> (_bigEndianWords ? 8 : 16)) & _MASK_8;
+ bytes[3] = (word >> (_bigEndianWords ? 0 : 24)) & _MASK_8;
+ return bytes;
+ }
+
+ // Iterate through data updating the hash computation for each
+ // chunk.
+ _iterate() {
+ var len = _pendingData.length;
+ var chunkSizeInBytes = _chunkSizeInWords * _BYTES_PER_WORD;
+ if (len >= chunkSizeInBytes) {
+ var index = 0;
+ for (; (len - index) >= chunkSizeInBytes; index += chunkSizeInBytes) {
+ _bytesToChunk(_pendingData, index);
+ _updateHash(_currentChunk);
+ }
+ _pendingData = _pendingData.sublist(index, len);
+ }
+ }
+
+ // Finalize the data. Add a 1 bit to the end of the message. Expand with
+ // 0 bits and add the length of the message.
+ _finalizeData() {
+ _pendingData.add(0x80);
+ var contentsLength = _lengthInBytes + 9;
+ var chunkSizeInBytes = _chunkSizeInWords * _BYTES_PER_WORD;
+ var finalizedLength = _roundUp(contentsLength, chunkSizeInBytes);
+ var zeroPadding = finalizedLength - contentsLength;
+ for (var i = 0; i < zeroPadding; i++) {
+ _pendingData.add(0);
+ }
+ var lengthInBits = _lengthInBytes * _BITS_PER_BYTE;
+ assert(lengthInBits < pow(2, 32));
+ if (_bigEndianWords) {
+ _pendingData.addAll(_wordToBytes(0));
+ _pendingData.addAll(_wordToBytes(lengthInBits & _MASK_32));
+ } else {
+ _pendingData.addAll(_wordToBytes(lengthInBits & _MASK_32));
+ _pendingData.addAll(_wordToBytes(0));
+ }
+ }
+
+ // Hasher state.
+ final int _chunkSizeInWords;
+ final int _digestSizeInWords;
+ final bool _bigEndianWords;
+ int _lengthInBytes = 0;
+ List<int> _pendingData;
+ List<int> _currentChunk;
+ List<int> _h;
+ bool _digestCalled = false;
+}
+
+// The MD5 hasher is used to compute an MD5 message digest.
+class _MD5 extends _HashBase {
+ _MD5() : super(16, 4, false) {
+ _h[0] = 0x67452301;
+ _h[1] = 0xefcdab89;
+ _h[2] = 0x98badcfe;
+ _h[3] = 0x10325476;
+ }
+
+ // Returns a new instance of this Hash.
+ _MD5 newInstance() {
+ return new _MD5();
+ }
+
+ static const _k = const [
+ 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a,
+ 0xa8304613, 0xfd469501, 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
+ 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, 0xf61e2562, 0xc040b340,
+ 0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
+ 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8,
+ 0x676f02d9, 0x8d2a4c8a, 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
+ 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, 0x289b7ec6, 0xeaa127fa,
+ 0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
+ 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92,
+ 0xffeff47d, 0x85845dd1, 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
+ 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 ];
+
+ static const _r = const [
+ 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 5, 9, 14,
+ 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 4, 11, 16, 23, 4, 11,
+ 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 6, 10, 15, 21, 6, 10, 15, 21, 6,
+ 10, 15, 21, 6, 10, 15, 21 ];
+
+ // Compute one iteration of the MD5 algorithm with a chunk of
+ // 16 32-bit pieces.
+ void _updateHash(List<int> m) {
+ assert(m.length == 16);
+
+ var a = _h[0];
+ var b = _h[1];
+ var c = _h[2];
+ var d = _h[3];
+
+ var t0;
+ var t1;
+
+ for (var i = 0; i < 64; i++) {
+ if (i < 16) {
+ t0 = (b & c) | ((~b & _MASK_32) & d);
+ t1 = i;
+ } else if (i < 32) {
+ t0 = (d & b) | ((~d & _MASK_32) & c);
+ t1 = ((5 * i) + 1) % 16;
+ } else if (i < 48) {
+ t0 = b ^ c ^ d;
+ t1 = ((3 * i) + 5) % 16;
+ } else {
+ t0 = c ^ (b | (~d & _MASK_32));
+ t1 = (7 * i) % 16;
+ }
+
+ var temp = d;
+ d = c;
+ c = b;
+ b = _add32(b, _rotl32(_add32(_add32(a, t0),
+ _add32(_k[i], m[t1])),
+ _r[i]));
+ a = temp;
+ }
+
+ _h[0] = _add32(a, _h[0]);
+ _h[1] = _add32(b, _h[1]);
+ _h[2] = _add32(c, _h[2]);
+ _h[3] = _add32(d, _h[3]);
+ }
+}
+
+// The SHA1 hasher is used to compute an SHA1 message digest.
+class _SHA1 extends _HashBase {
+ // Construct a SHA1 hasher object.
+ _SHA1() : _w = new List(80), super(16, 5, true) {
+ _h[0] = 0x67452301;
+ _h[1] = 0xEFCDAB89;
+ _h[2] = 0x98BADCFE;
+ _h[3] = 0x10325476;
+ _h[4] = 0xC3D2E1F0;
+ }
+
+ // Returns a new instance of this Hash.
+ _SHA1 newInstance() {
+ return new _SHA1();
+ }
+
+ // Compute one iteration of the SHA1 algorithm with a chunk of
+ // 16 32-bit pieces.
+ void _updateHash(List<int> m) {
+ assert(m.length == 16);
+
+ var a = _h[0];
+ var b = _h[1];
+ var c = _h[2];
+ var d = _h[3];
+ var e = _h[4];
+
+ for (var i = 0; i < 80; i++) {
+ if (i < 16) {
+ _w[i] = m[i];
+ } else {
+ var n = _w[i - 3] ^ _w[i - 8] ^ _w[i - 14] ^ _w[i - 16];
+ _w[i] = _rotl32(n, 1);
+ }
+ var t = _add32(_add32(_rotl32(a, 5), e), _w[i]);
+ if (i < 20) {
+ t = _add32(_add32(t, (b & c) | (~b & d)), 0x5A827999);
+ } else if (i < 40) {
+ t = _add32(_add32(t, (b ^ c ^ d)), 0x6ED9EBA1);
+ } else if (i < 60) {
+ t = _add32(_add32(t, (b & c) | (b & d) | (c & d)), 0x8F1BBCDC);
+ } else {
+ t = _add32(_add32(t, b ^ c ^ d), 0xCA62C1D6);
+ }
+
+ e = d;
+ d = c;
+ c = _rotl32(b, 30);
+ b = a;
+ a = t & _MASK_32;
+ }
+
+ _h[0] = _add32(a, _h[0]);
+ _h[1] = _add32(b, _h[1]);
+ _h[2] = _add32(c, _h[2]);
+ _h[3] = _add32(d, _h[3]);
+ _h[4] = _add32(e, _h[4]);
+ }
+
+ List<int> _w;
+}
diff --git a/sdk/lib/io/file_impl.dart b/sdk/lib/io/file_impl.dart
index fb6b272..29b93dc 100644
--- a/sdk/lib/io/file_impl.dart
+++ b/sdk/lib/io/file_impl.dart
@@ -534,7 +534,7 @@
IOSink sink = openWrite(mode: mode);
sink.add(bytes);
sink.close();
- return sink.done.then((_) => this);;
+ return sink.done.then((_) => this);
} catch (e) {
return new Future.error(e);
}
diff --git a/sdk/lib/io/http.dart b/sdk/lib/io/http.dart
index 5dc5738..913ab8f 100644
--- a/sdk/lib/io/http.dart
+++ b/sdk/lib/io/http.dart
@@ -721,6 +721,10 @@
/**
* Gets the [HttpResponse] object, used for sending back the response to the
* client.
+ *
+ * If the [contentLength] of the body isn't 0, and the body isn't being read,
+ * any write calls on the [HttpResponse] will automatically drain the request
+ * body.
*/
HttpResponse get response;
}
diff --git a/sdk/lib/io/http_impl.dart b/sdk/lib/io/http_impl.dart
index dec3633..b27441b 100644
--- a/sdk/lib/io/http_impl.dart
+++ b/sdk/lib/io/http_impl.dart
@@ -23,6 +23,8 @@
String method;
Uri uri;
+ bool hasSubscriber = false;
+
// The transfer length if the length of the message body as it
// appears in the message (RFC 2616 section 4.4). This can be -1 if
// the length of the massage body is not known due to transfer
@@ -38,6 +40,7 @@
{void onError(error),
void onDone(),
bool cancelOnError}) {
+ hasSubscriber = true;
return _stream.listen(onData,
onError: onError,
onDone: onDone,
@@ -49,6 +52,7 @@
void close(bool closing) {
fullBodyRead = true;
+ hasSubscriber = true;
_dataCompleter.complete(closing);
}
}
@@ -274,7 +278,7 @@
Future<HttpClientResponse> _authenticate(bool proxyAuth) {
Future<HttpClientResponse> retry() {
// Drain body and retry.
- return fold(null, (x, y) {}).then((_) {
+ return drain().then((_) {
return _httpClient._openUrlFromRequest(_httpRequest.method,
_httpRequest.uri,
_httpRequest)
@@ -470,45 +474,56 @@
Future<T> get done => _dataSink.done;
- void _writeHeaders() {
- if (_headersWritten) return;
+ Future _writeHeaders({drainRequest: true}) {
+ if (_headersWritten) return new Future.value();
_headersWritten = true;
headers._synchronize(); // Be sure the 'chunked' option is updated.
bool isServerSide = this is _HttpResponse;
- if (isServerSide && headers.chunkedTransferEncoding) {
+ if (isServerSide) {
var response = this;
- List acceptEncodings =
- response._httpRequest.headers[HttpHeaders.ACCEPT_ENCODING];
- List contentEncoding = headers[HttpHeaders.CONTENT_ENCODING];
- if (acceptEncodings != null &&
- acceptEncodings
- .expand((list) => list.split(","))
- .any((encoding) => encoding.trim().toLowerCase() == "gzip") &&
- contentEncoding == null) {
- headers.set(HttpHeaders.CONTENT_ENCODING, "gzip");
- _asGZip = true;
+ if (headers.chunkedTransferEncoding) {
+ List acceptEncodings =
+ response._httpRequest.headers[HttpHeaders.ACCEPT_ENCODING];
+ List contentEncoding = headers[HttpHeaders.CONTENT_ENCODING];
+ if (acceptEncodings != null &&
+ acceptEncodings
+ .expand((list) => list.split(","))
+ .any((encoding) => encoding.trim().toLowerCase() == "gzip") &&
+ contentEncoding == null) {
+ headers.set(HttpHeaders.CONTENT_ENCODING, "gzip");
+ _asGZip = true;
+ }
+ }
+ if (drainRequest && !response._httpRequest._incoming.hasSubscriber) {
+ return response._httpRequest.drain()
+ // TODO(ajohnsen): Timeout on drain?
+ .catchError((_) {}) // Ignore errors.
+ .then((_) => _writeHeader());
}
}
- _writeHeader();
+ return new Future.sync(_writeHeader);
}
Future _addStream(Stream<List<int>> stream) {
- _writeHeaders();
- int contentLength = headers.contentLength;
- if (_ignoreBody) {
- stream.fold(null, (x, y) {}).catchError((_) {});
- return _headersSink.close();
- }
- stream = stream.transform(new _BufferTransformer());
- if (headers.chunkedTransferEncoding) {
- if (_asGZip) {
- stream = stream.transform(new ZLibDeflater(gzip: true, level: 6));
- }
- stream = stream.transform(new _ChunkedTransformer());
- } else if (contentLength >= 0) {
- stream = stream.transform(new _ContentLengthValidator(contentLength));
- }
- return _headersSink.addStream(stream);
+ return _writeHeaders()
+ .then((_) {
+ int contentLength = headers.contentLength;
+ if (_ignoreBody) {
+ stream.drain().catchError((_) {});
+ return _headersSink.close();
+ }
+ stream = stream.transform(new _BufferTransformer());
+ if (headers.chunkedTransferEncoding) {
+ if (_asGZip) {
+ stream = stream.transform(new ZLibDeflater(gzip: true, level: 6));
+ }
+ stream = stream.transform(new _ChunkedTransformer());
+ } else if (contentLength >= 0) {
+ stream = stream.transform(
+ new _ContentLengthValidator(contentLength));
+ }
+ return _headersSink.addStream(stream);
+ });
}
Future _close() {
@@ -528,8 +543,7 @@
" than 0: ${headers.contentLength}."));
}
}
- _writeHeaders();
- return _headersSink.close();
+ return _writeHeaders().then((_) => _headersSink.close());
}
void _writeHeader(); // TODO(ajohnsen): Better name.
@@ -548,7 +562,9 @@
void _cancel() {
if (_subscription != null) {
- _subscription.cancel();
+ StreamSubscription subscription = _subscription;
+ _subscription = null;
+ subscription.cancel();
}
}
@@ -556,6 +572,7 @@
if (_controller != null) return;
_controller = new StreamController(onPause: () => _subscription.pause(),
onResume: () => _subscription.resume(),
+ onListen: () => _subscription.resume(),
onCancel: _cancel);
_outbound._addStream(_controller.stream)
.then((_) {
@@ -608,6 +625,8 @@
_done(error);
},
cancelOnError: true);
+ // Pause the first request.
+ if (_controller == null) _subscription.pause();
_ensureController();
return _completer.future;
}
@@ -682,8 +701,8 @@
Future<Socket> detachSocket() {
if (_headersWritten) throw new StateError("Headers already sent");
- _writeHeaders();
var future = _httpRequest._httpConnection.detachSocket();
+ _writeHeaders(drainRequest: false).then((_) => close());
// Close connection so the socket is 'free'.
close();
done.catchError((_) {
@@ -878,11 +897,11 @@
if (followRedirects && response.isRedirect) {
if (response.redirects.length < maxRedirects) {
// Redirect and drain response.
- future = response.fold(null, (x, y) {})
+ future = response.drain()
.then((_) => response.redirect());
} else {
// End with exception, too many redirects.
- future = response.fold(null, (x, y) {})
+ future = response.drain()
.then((_) => new Future.error(
new RedirectLimitExceededException(response.redirects)));
}
@@ -927,7 +946,7 @@
// For the connect method the request URI is the host:port of
// the requested destination of the tunnel (see RFC 2817
// section 5.2)
- return "${uri.domain}:${uri.port}";
+ return "${uri.host}:${uri.port}";
} else {
if (_httpClientConnection._proxyTunnel) {
return uriStartingFromPath();
@@ -1136,13 +1155,13 @@
proxy,
_httpClient,
this);
- request.headers.host = uri.domain;
+ request.headers.host = uri.host;
request.headers.port = port;
request.headers.set(HttpHeaders.ACCEPT_ENCODING, "gzip");
if (proxy.isAuthenticated) {
// If the proxy configuration contains user information use that
// for proxy basic authorization.
- String auth = CryptoUtils.bytesToBase64(
+ String auth = _CryptoUtils.bytesToBase64(
_encodeString("${proxy.username}:${proxy.password}"));
request.headers.set(HttpHeaders.PROXY_AUTHORIZATION, "Basic $auth");
} else if (!proxy.isDirect && _httpClient._proxyCredentials.length > 0) {
@@ -1155,7 +1174,7 @@
// If the URL contains user information use that for basic
// authorization.
String auth =
- CryptoUtils.bytesToBase64(_encodeString(uri.userInfo));
+ _CryptoUtils.bytesToBase64(_encodeString(uri.userInfo));
request.headers.set(HttpHeaders.AUTHORIZATION, "Basic $auth");
} else {
// Look for credentials.
@@ -1259,14 +1278,14 @@
Future<_HttpClientConnection> createProxyTunnel(host, port, proxy) {
_HttpClientRequest request =
- send(new Uri.fromComponents(domain: host, port: port),
+ send(new Uri(host: host, port: port),
port,
"CONNECT",
proxy);
if (proxy.isAuthenticated) {
// If the proxy configuration contains user information use that
// for proxy basic authorization.
- String auth = CryptoUtils.bytesToBase64(
+ String auth = _CryptoUtils.bytesToBase64(
_encodeString("${proxy.username}:${proxy.password}"));
request.headers.set(HttpHeaders.PROXY_AUTHORIZATION, "Basic $auth");
}
@@ -1352,8 +1371,8 @@
String path) {
// TODO(sgjesse): The path set here can contain both query and
// fragment. They should be cracked and set correctly.
- return _openUrl(method, new Uri.fromComponents(
- scheme: "http", domain: host, port: port, path: path));
+ return _openUrl(method, new Uri(
+ scheme: "http", host: host, port: port, path: path));
}
Future<HttpClientRequest> openUrl(String method, Uri url) {
@@ -1430,7 +1449,7 @@
throw new ArgumentError(method);
}
if (method != "CONNECT") {
- if (uri.domain.isEmpty ||
+ if (uri.host.isEmpty ||
(uri.scheme != "http" && uri.scheme != "https")) {
throw new ArgumentError("Unsupported scheme '${uri.scheme}' in $uri");
}
@@ -1454,7 +1473,7 @@
return new Future.error(error, stackTrace);
}
}
- return _getConnection(uri.domain, port, proxyConf, isSecure)
+ return _getConnection(uri.host, port, proxyConf, isSecure)
.then((info) {
send(info) {
return info.connection.send(uri,
@@ -1465,7 +1484,7 @@
// If the connection was closed before the request was sent, create
// and use another connection.
if (info.connection.closed) {
- return _getConnection(uri.domain, port, proxyConf, isSecure)
+ return _getConnection(uri.host, port, proxyConf, isSecure)
.then(send);
}
return send(info);
@@ -1478,19 +1497,19 @@
// If the new URI is relative (to either '/' or some sub-path),
// construct a full URI from the previous one.
// See http://tools.ietf.org/html/rfc3986#section-4.2
- replaceComponents({scheme, domain, port, path}) {
- uri = new Uri.fromComponents(
+ replaceComponents({scheme, host, port, path}) {
+ uri = new Uri(
scheme: scheme != null ? scheme : uri.scheme,
- domain: domain != null ? domain : uri.domain,
+ host: host != null ? host : uri.host,
port: port != null ? port : uri.port,
path: path != null ? path : uri.path,
query: uri.query,
fragment: uri.fragment);
}
- if (uri.domain == '') {
- replaceComponents(domain: previous.uri.domain, port: previous.uri.port);
+ if (uri.host.isEmpty) {
+ replaceComponents(host: previous.uri.host, port: previous.uri.port);
}
- if (uri.scheme == '') {
+ if (uri.scheme.isEmpty) {
replaceComponents(scheme: previous.uri.scheme);
}
if (!uri.path.startsWith('/') && previous.uri.path.startsWith('/')) {
@@ -1657,7 +1676,7 @@
if (option == null) return null;
Iterator<String> names = option.split(",").map((s) => s.trim()).iterator;
while (names.moveNext()) {
- if (url.domain.endsWith(names.current)) {
+ if (url.host.endsWith(names.current)) {
return "DIRECT";
}
}
@@ -2130,13 +2149,13 @@
// http://tools.ietf.org/html/draft-reschke-basicauth-enc-06. For
// now always use UTF-8 encoding.
_HttpClientDigestCredentials creds = credentials;
- var hasher = new MD5();
+ var hasher = new _MD5();
hasher.add(_encodeString(creds.username));
hasher.add([_CharCode.COLON]);
hasher.add(realm.codeUnits);
hasher.add([_CharCode.COLON]);
hasher.add(_encodeString(creds.password));
- ha1 = CryptoUtils.bytesToHex(hasher.close());
+ ha1 = _CryptoUtils.bytesToHex(hasher.close());
}
}
@@ -2153,7 +2172,7 @@
bool applies(Uri uri, _AuthenticationScheme scheme) {
if (scheme != null && credentials.scheme != scheme) return false;
- if (uri.domain != this.uri.domain) return false;
+ if (uri.host != this.uri.host) return false;
int thisPort =
this.uri.port == 0 ? HttpClient.DEFAULT_HTTP_PORT : this.uri.port;
int otherPort = uri.port == 0 ? HttpClient.DEFAULT_HTTP_PORT : uri.port;
@@ -2224,7 +2243,7 @@
// http://tools.ietf.org/html/draft-reschke-basicauth-enc-06. For
// now always use UTF-8 encoding.
String auth =
- CryptoUtils.bytesToBase64(_encodeString("$username:$password"));
+ _CryptoUtils.bytesToBase64(_encodeString("$username:$password"));
return "Basic $auth";
}
@@ -2251,22 +2270,22 @@
String authorization(_Credentials credentials, _HttpClientRequest request) {
String requestUri = request._requestUri();
- MD5 hasher = new MD5();
+ _MD5 hasher = new _MD5();
hasher.add(request.method.codeUnits);
hasher.add([_CharCode.COLON]);
hasher.add(requestUri.codeUnits);
- var ha2 = CryptoUtils.bytesToHex(hasher.close());
+ var ha2 = _CryptoUtils.bytesToHex(hasher.close());
String qop;
String cnonce;
String nc;
var x;
- hasher = new MD5();
+ hasher = new _MD5();
hasher.add(credentials.ha1.codeUnits);
hasher.add([_CharCode.COLON]);
if (credentials.qop == "auth") {
qop = credentials.qop;
- cnonce = CryptoUtils.bytesToHex(_IOCrypto.getRandomBytes(4));
+ cnonce = _CryptoUtils.bytesToHex(_IOCrypto.getRandomBytes(4));
++credentials.nonceCount;
nc = credentials.nonceCount.toRadixString(16);
nc = "00000000".substring(0, 8 - nc.length + 1) + nc;
@@ -2284,7 +2303,7 @@
hasher.add([_CharCode.COLON]);
hasher.add(ha2.codeUnits);
}
- var response = CryptoUtils.bytesToHex(hasher.close());
+ var response = _CryptoUtils.bytesToHex(hasher.close());
StringBuffer buffer = new StringBuffer();
buffer.write('Digest ');
diff --git a/sdk/lib/io/http_parser.dart b/sdk/lib/io/http_parser.dart
index 58622cf..b7aabd2 100644
--- a/sdk/lib/io/http_parser.dart
+++ b/sdk/lib/io/http_parser.dart
@@ -578,7 +578,9 @@
if (_connectionUpgrade) {
_incoming.upgraded = true;
_parserCalled = false;
- _controller.add(_incoming);
+ var tmp = _incoming;
+ _closeIncoming();
+ _controller.add(tmp);
return;
}
if (_transferLength == 0 ||
@@ -928,14 +930,6 @@
}
void _pauseStateChanged() {
- void update(bool pause) {
- if (pause && !_socketSubscription.isPaused) {
- _socketSubscription.pause();
- } else if (!pause && _socketSubscription.isPaused) {
- _socketSubscription.resume();
- }
- }
-
if (_incoming != null) {
if (!_bodyPaused && !_parserCalled) {
_parse();
diff --git a/sdk/lib/io/http_session.dart b/sdk/lib/io/http_session.dart
index 2b7e164..deeebd0 100644
--- a/sdk/lib/io/http_session.dart
+++ b/sdk/lib/io/http_session.dart
@@ -60,6 +60,7 @@
Iterable get values => _data.values;
int get length => _data.length;
bool get isEmpty => _data.isEmpty;
+ bool get isNotEmpty => _data.isNotEmpty;
}
// Private class used to manage all the active sessions. The sessions are stored
@@ -73,7 +74,7 @@
String createSessionId() {
const int _KEY_LENGTH = 16; // 128 bits.
var data = _IOCrypto.getRandomBytes(_KEY_LENGTH);
- return CryptoUtils.bytesToHex(data);
+ return _CryptoUtils.bytesToHex(data);
}
_HttpSession getSession(String id) {
diff --git a/sdk/lib/io/io.dart b/sdk/lib/io/io.dart
index c44f6ba..6c1d699 100644
--- a/sdk/lib/io/io.dart
+++ b/sdk/lib/io/io.dart
@@ -17,16 +17,15 @@
LinkedHashSet,
DoubleLinkedQueue,
DoubleLinkedQueueEntry;
-import 'dart:crypto';
import 'dart:isolate';
import 'dart:json' as JSON;
import 'dart:math';
-import 'dart:uri';
import 'dart:utf';
import 'dart:typed_data';
part 'buffer_list.dart';
part 'common.dart';
+part 'crypto.dart';
part 'data_transformer.dart';
part 'directory.dart';
part 'directory_impl.dart';
diff --git a/sdk/lib/io/iolib_sources.gypi b/sdk/lib/io/iolib_sources.gypi
index 5225dc1..b10f218 100644
--- a/sdk/lib/io/iolib_sources.gypi
+++ b/sdk/lib/io/iolib_sources.gypi
@@ -6,6 +6,7 @@
'sources': [
'buffer_list.dart',
'common.dart',
+ 'crypto.dart',
'data_transformer.dart',
'directory.dart',
'directory_impl.dart',
diff --git a/sdk/lib/io/mime_multipart_parser.dart b/sdk/lib/io/mime_multipart_parser.dart
index 4bfbebe..dc3f206 100644
--- a/sdk/lib/io/mime_multipart_parser.dart
+++ b/sdk/lib/io/mime_multipart_parser.dart
@@ -101,11 +101,10 @@
Stream<MimeMultipart> bind(Stream<List<int>> stream) {
_controller = new StreamController(
- onPause: () {
- _pauseStream();
- },
- onResume: () {
- _resumeStream();
+ onPause: _pauseStream,
+ onResume:_resumeStream,
+ onCancel: () {
+ _subscription.cancel();
},
onListen: () {
_subscription = stream.listen(
@@ -126,9 +125,6 @@
onError: (error) {
_controller.addError(error);
});
- },
- onCancel: () {
- _subscription.cancel();
});
return _controller.stream;
}
diff --git a/sdk/lib/io/platform_impl.dart b/sdk/lib/io/platform_impl.dart
index 8b858c9..cee4e38 100644
--- a/sdk/lib/io/platform_impl.dart
+++ b/sdk/lib/io/platform_impl.dart
@@ -87,6 +87,7 @@
Iterable<V> get values => _map.values;
int get length => _map.length;
bool get isEmpty => _map.isEmpty;
+ bool get isNotEmpty => _map.isNotEmpty;
Map<String, V> _map;
}
diff --git a/sdk/lib/io/timer_impl.dart b/sdk/lib/io/timer_impl.dart
index 107daba..3072f5c 100644
--- a/sdk/lib/io/timer_impl.dart
+++ b/sdk/lib/io/timer_impl.dart
@@ -158,8 +158,8 @@
}
} finally {
_handling_callbacks = false;
+ _notifyEventHandler();
}
- _notifyEventHandler();
}
if(_receivePort == null) {
diff --git a/sdk/lib/io/websocket_impl.dart b/sdk/lib/io/websocket_impl.dart
index 3cef0ad..77c3456 100644
--- a/sdk/lib/io/websocket_impl.dart
+++ b/sdk/lib/io/websocket_impl.dart
@@ -406,9 +406,9 @@
response.headers.add(HttpHeaders.CONNECTION, "Upgrade");
response.headers.add(HttpHeaders.UPGRADE, "websocket");
String key = request.headers.value("Sec-WebSocket-Key");
- SHA1 sha1 = new SHA1();
+ _SHA1 sha1 = new _SHA1();
sha1.add("$key$_webSocketGUID".codeUnits);
- String accept = CryptoUtils.bytesToBase64(sha1.close());
+ String accept = _CryptoUtils.bytesToBase64(sha1.close());
response.headers.add("Sec-WebSocket-Accept", accept);
response.headers.contentLength = 0;
return response.detachSocket()
@@ -658,15 +658,15 @@
for (int i = 0; i < 16; i++) {
nonceData[i] = random.nextInt(256);
}
- String nonce = CryptoUtils.bytesToBase64(nonceData);
+ String nonce = _CryptoUtils.bytesToBase64(nonceData);
- uri = new Uri.fromComponents(scheme: uri.scheme == "wss" ? "https" : "http",
- userInfo: uri.userInfo,
- domain: uri.domain,
- port: uri.port,
- path: uri.path,
- query: uri.query,
- fragment: uri.fragment);
+ uri = new Uri(scheme: uri.scheme == "wss" ? "https" : "http",
+ userInfo: uri.userInfo,
+ host: uri.host,
+ port: uri.port,
+ path: uri.path,
+ query: uri.query,
+ fragment: uri.fragment);
return _httpClient.openUrl("GET", uri)
.then((request) {
// Setup the initial handshake.
@@ -696,10 +696,10 @@
if (accept == null) {
error("Response did not contain a 'Sec-WebSocket-Accept' header");
}
- SHA1 sha1 = new SHA1();
+ _SHA1 sha1 = new _SHA1();
sha1.add("$nonce$_webSocketGUID".codeUnits);
List<int> expectedAccept = sha1.close();
- List<int> receivedAccept = CryptoUtils.base64StringToBytes(accept);
+ List<int> receivedAccept = _CryptoUtils.base64StringToBytes(accept);
if (expectedAccept.length != receivedAccept.length) {
error("Reasponse header 'Sec-WebSocket-Accept' is the wrong length");
}
diff --git a/sdk/lib/mdv_observe_impl/mdv_observe_impl.dart b/sdk/lib/mdv_observe_impl/mdv_observe_impl.dart
index e56554b..577f0b8 100644
--- a/sdk/lib/mdv_observe_impl/mdv_observe_impl.dart
+++ b/sdk/lib/mdv_observe_impl/mdv_observe_impl.dart
@@ -63,16 +63,15 @@
* call [notifyPropertyChange]. See that method for an example.
*/
abstract class ObservableMixin implements Observable {
- StreamController<List<ChangeRecord>> _observers;
- Stream<List<ChangeRecord>> _stream;
+ StreamController _multiplexController;
List<ChangeRecord> _changes;
Stream<List<ChangeRecord>> get changes {
- if (_observers == null) {
- _observers = new StreamController<List<ChangeRecord>>();
- _stream = _observers.stream.asBroadcastStream();
+ if (_multiplexController == null) {
+ _multiplexController =
+ new StreamController<List<ChangeRecord>>.broadcast();
}
- return _stream;
+ return _multiplexController.stream;
}
void _deliverChanges() {
@@ -80,7 +79,7 @@
_changes = null;
if (hasObservers && changes != null) {
// TODO(jmesserly): make "changes" immutable
- _observers.add(changes);
+ _multiplexController.add(changes);
}
}
@@ -88,7 +87,8 @@
* True if this object has any observers, and should call
* [notifyPropertyChange] for changes.
*/
- bool get hasObservers => _observers != null && _observers.hasListener;
+ bool get hasObservers => _multiplexController != null &&
+ _multiplexController.hasListener;
/**
* Notify that the field [name] of this object has been changed.
diff --git a/sdk/lib/mirrors/mirrors.dart b/sdk/lib/mirrors/mirrors.dart
index 86bbce1..1e9377e 100644
--- a/sdk/lib/mirrors/mirrors.dart
+++ b/sdk/lib/mirrors/mirrors.dart
@@ -16,7 +16,6 @@
import 'dart:async';
import 'dart:isolate';
-import 'dart:uri';
/**
* A [MirrorSystem] is the main interface used to reflect on a set of
diff --git a/sdk/lib/typed_data/dart2js/typed_data_dart2js.dart b/sdk/lib/typed_data/dart2js/typed_data_dart2js.dart
index d6e5f43..d7afeed 100644
--- a/sdk/lib/typed_data/dart2js/typed_data_dart2js.dart
+++ b/sdk/lib/typed_data/dart2js/typed_data_dart2js.dart
@@ -314,6 +314,8 @@
bool get isEmpty => this.length == 0;
+ bool get isNotEmpty => !isEmpty;
+
Iterable<num> take(int n) => IterableMixinWorkaround.takeList(this, n);
Iterable<num> takeWhile(bool test(num value)) {
@@ -534,6 +536,8 @@
bool get isEmpty => this.length == 0;
+ bool get isNotEmpty => !isEmpty;
+
Iterable<num> take(int n) => IterableMixinWorkaround.takeList(this, n);
Iterable<num> takeWhile(bool test(num value)) {
@@ -754,6 +758,8 @@
bool get isEmpty => this.length == 0;
+ bool get isNotEmpty => !isEmpty;
+
Iterable<int> take(int n) => IterableMixinWorkaround.takeList(this, n);
Iterable<int> takeWhile(bool test(int value)) {
@@ -974,6 +980,8 @@
bool get isEmpty => this.length == 0;
+ bool get isNotEmpty => !isEmpty;
+
Iterable<int> take(int n) => IterableMixinWorkaround.takeList(this, n);
Iterable<int> takeWhile(bool test(int value)) {
@@ -1194,6 +1202,8 @@
bool get isEmpty => this.length == 0;
+ bool get isNotEmpty => !isEmpty;
+
Iterable<int> take(int n) => IterableMixinWorkaround.takeList(this, n);
Iterable<int> takeWhile(bool test(int value)) {
@@ -1414,6 +1424,8 @@
bool get isEmpty => this.length == 0;
+ bool get isNotEmpty => !isEmpty;
+
Iterable<int> take(int n) => IterableMixinWorkaround.takeList(this, n);
Iterable<int> takeWhile(bool test(int value)) {
@@ -1634,6 +1646,8 @@
bool get isEmpty => this.length == 0;
+ bool get isNotEmpty => !isEmpty;
+
Iterable<int> take(int n) => IterableMixinWorkaround.takeList(this, n);
Iterable<int> takeWhile(bool test(int value)) {
@@ -1853,6 +1867,8 @@
bool get isEmpty => this.length == 0;
+ bool get isNotEmpty => !isEmpty;
+
Iterable<int> take(int n) => IterableMixinWorkaround.takeList(this, n);
Iterable<int> takeWhile(bool test(int value)) {
@@ -2073,6 +2089,8 @@
bool get isEmpty => this.length == 0;
+ bool get isNotEmpty => !isEmpty;
+
Iterable<int> take(int n) => IterableMixinWorkaround.takeList(this, n);
Iterable<int> takeWhile(bool test(int value)) {
diff --git a/sdk/lib/uri/encode_decode.dart b/sdk/lib/uri/encode_decode.dart
deleted file mode 100644
index 6cddcc0..0000000
--- a/sdk/lib/uri/encode_decode.dart
+++ /dev/null
@@ -1,198 +0,0 @@
-// 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.uri;
-
-/**
- * Javascript-like URI encode/decode functions.
- * The documentation here borrows heavily from the original Javascript
- * doumentation on MDN at:
- * https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects
- */
-
-/**
- * A JavaScript-like URI encoder. Encodes Uniform Resource Identifier [uri]
- * by replacing each instance of certain characters by one, two, three, or four
- * escape sequences representing the UTF-8 encoding of the character (will
- * only be four escape sequences for characters composed of two "surrogate"
- * characters). This assumes that [uri] is a complete URI, so does not encode
- * reserved characters that have special meaning in the URI: [:#;,/?:@&=+\$:]
- * It returns the escaped URI.
- */
-String encodeUri(String uri) {
- // Bit vector of 128 bits where each bit indicate whether a
- // character code on the 0-127 needs to be escaped or not.
- const canonicalTable = const [
- // LSB MSB
- // | |
- 0x0000, // 0x00 - 0x0f 0000000000000000
- 0x0000, // 0x10 - 0x1f 0000000000000000
- // ! #$ &'()*+,-./
- 0xf7da, // 0x20 - 0x2f 0101101111101111
- // 0123456789:; = ?
- 0xafff, // 0x30 - 0x3f 1111111111110101
- // @ABCDEFGHIJKLMNO
- 0xffff, // 0x40 - 0x4f 1111111111111111
- // PQRSTUVWXYZ _
- 0x87ff, // 0x50 - 0x5f 1111111111100001
- // abcdefghijklmno
- 0xfffe, // 0x60 - 0x6f 0111111111111111
- // pqrstuvwxyz ~
- 0x47ff]; // 0x70 - 0x7f 1111111111100010
- return _uriEncode(canonicalTable, uri);
-}
-
-/**
- * An implementation of JavaScript's decodeURIComponent function.
- * Decodes a Uniform Resource Identifier [uri] previously created by
- * encodeURI or by a similar routine. It replaces each escape sequence
- * in [uri] with the character that it represents. It does not decode
- * escape sequences that could not have been introduced by encodeURI.
- * It returns the unescaped URI.
- */
-String decodeUri(String uri) {
- return _uriDecode(uri);
-}
-
-/**
- * A javaScript-like URI component encoder, this encodes a URI
- * [component] by replacing each instance of certain characters by one,
- * two, three, or four escape sequences representing the UTF-8 encoding of
- * the character (will only be four escape sequences for characters composed
- * of two "surrogate" characters).
- * To avoid unexpected requests to the server, you should call
- * encodeURIComponent on any user-entered parameters that will be passed as
- * part of a URI. For example, a user could type "Thyme &time=again" for a
- * variable comment. Not using encodeURIComponent on this variable will give
- * comment=Thyme%20&time=again. Note that the ampersand and the equal sign
- * mark a new key and value pair. So instead of having a POST comment key
- * equal to "Thyme &time=again", you have two POST keys, one equal to "Thyme "
- * and another (time) equal to again.
- * It returns the escaped string.
- */
-String encodeUriComponent(String component) {
- // Bit vector of 128 bits where each bit indicate whether a
- // character code on the 0-127 needs to be escaped or not.
- const canonicalTable = const [
- // LSB MSB
- // | |
- 0x0000, // 0x00 - 0x0f 0000000000000000
- 0x0000, // 0x10 - 0x1f 0000000000000000
- // ! '()* -.
- 0x6782, // 0x20 - 0x2f 0100000111100110
- // 0123456789
- 0x03ff, // 0x30 - 0x3f 1111111111000000
- // @ABCDEFGHIJKLMNO
- 0xfffe, // 0x40 - 0x4f 0111111111111111
- // PQRSTUVWXYZ _
- 0x87ff, // 0x50 - 0x5f 1111111111100001
- // abcdefghijklmno
- 0xfffe, // 0x60 - 0x6f 0111111111111111
- // pqrstuvwxyz ~
- 0x47ff]; // 0x70 - 0x7f 1111111111100010
- return _uriEncode(canonicalTable, component);
-}
-
-/**
- * An implementation of JavaScript's decodeURIComponent function.
- * Decodes a Uniform Resource Identifier (URI) [component] previously
- * created by encodeURIComponent or by a similar routine.
- * It returns the unescaped string.
- */
-String decodeUriComponent(String encodedComponent) {
- return _uriDecode(encodedComponent);
-}
-
-/**
- * This is the internal implementation of JavaScript's encodeURI function.
- * It encodes all characters in the string [text] except for those
- * that appear in [canonicalTable], and returns the escaped string.
- */
-String _uriEncode(List<int> canonicalTable, String text) {
- final String hex = '0123456789ABCDEF';
- var byteToHex = (int v) => '%${hex[v >> 4]}${hex[v & 0x0f]}';
- StringBuffer result = new StringBuffer();
- for (int i = 0; i < text.length; i++) {
- int ch = text.codeUnitAt(i);
- if (ch < 128 && ((canonicalTable[ch >> 4] & (1 << (ch & 0x0f))) != 0)) {
- result.write(text[i]);
- } else if (text[i] == " ") {
- result.write("+");
- } else {
- if (ch >= 0xD800 && ch < 0xDC00) {
- // Low surrogate. We expect a next char high surrogate.
- ++i;
- int nextCh = text.length == i ? 0 : text.codeUnitAt(i);
- if (nextCh >= 0xDC00 && nextCh < 0xE000) {
- // convert the pair to a U+10000 codepoint
- ch = 0x10000 + ((ch - 0xD800) << 10) + (nextCh - 0xDC00);
- } else {
- throw new ArgumentError('Malformed URI');
- }
- }
- for (int codepoint in codepointsToUtf8([ch])) {
- result.write(byteToHex(codepoint));
- }
- }
- }
- return result.toString();
-}
-
-/**
- * Convert a byte (2 character hex sequence) in string [s] starting
- * at position [pos] to its ordinal value
- */
-int _hexCharPairToByte(String s, int pos) {
- int byte = 0;
- for (int i = 0; i < 2; i++) {
- var charCode = s.codeUnitAt(pos + i);
- 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");
- }
- }
- }
- return byte;
-}
-
-/**
- * A JavaScript-like decodeURI function. It unescapes the string [text] and
- * returns the unescaped string.
- */
-String _uriDecode(String text) {
- StringBuffer result = new StringBuffer();
- List<int> codepoints = new List<int>();
- for (int i = 0; i < text.length;) {
- String ch = text[i];
- if (ch != '%') {
- if (ch == '+') {
- result.write(" ");
- } else {
- result.write(ch);
- }
- i++;
- } else {
- codepoints.clear();
- while (ch == '%') {
- if (++i > text.length - 2) {
- throw new ArgumentError('Truncated URI');
- }
- codepoints.add(_hexCharPairToByte(text, i));
- i += 2;
- if (i == text.length)
- break;
- ch = text[i];
- }
- result.write(decodeUtf8(codepoints));
- }
- }
- return result.toString();
-}
-
diff --git a/sdk/lib/uri/helpers.dart b/sdk/lib/uri/helpers.dart
deleted file mode 100644
index 2a16a47..0000000
--- a/sdk/lib/uri/helpers.dart
+++ /dev/null
@@ -1,29 +0,0 @@
-// 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.
-
-part of dart.uri;
-
-String merge(String base, String reference) {
- if (base == "") return "/$reference";
- return "${base.substring(0, base.lastIndexOf("/") + 1)}$reference";
-}
-
-String removeDotSegments(String path) {
- List<String> output = [];
- bool appendSlash = false;
- for (String segment in path.split("/")) {
- appendSlash = false;
- if (segment == "..") {
- if (!output.isEmpty &&
- ((output.length != 1) || (output[0] != ""))) output.removeLast();
- appendSlash = true;
- } else if ("." == segment) {
- appendSlash = true;
- } else {
- output.add(segment);
- }
- }
- if (appendSlash) output.add("");
- return output.join("/");
-}
diff --git a/sdk/lib/uri/uri.dart b/sdk/lib/uri/uri.dart
deleted file mode 100644
index 967e9a3..0000000
--- a/sdk/lib/uri/uri.dart
+++ /dev/null
@@ -1,280 +0,0 @@
-// 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.
-
-library dart.uri;
-
-import 'dart:math';
-import 'dart:utf';
-
-part 'encode_decode.dart';
-part 'helpers.dart';
-
-/**
- * A parsed URI, inspired by Closure's [URI][] class. Implements [RFC-3986][].
- * The domain component can either be a hostname, a IPv4 address or an IPv6
- * address, contained in '[' and ']', following [RFC-2732][]. If the domain
- * component contains a ':', the String returned from [toString] will have
- * '[' and ']' around the domain part.
- * [URI]: http://closure-library.googlecode.com/svn/docs/class_goog_Uri.html
- * [RFC-3986]: http://tools.ietf.org/html/rfc3986#section-4.3)
- * [RFC-2732]: http://www.ietf.org/rfc/rfc2732.txt
- */
-class Uri {
- final String scheme;
- final String userInfo;
- final String domain;
- final int port;
- final String path;
- final String query;
- final String fragment;
-
- static Uri parse(String uri) => new Uri._fromMatch(_splitRe.firstMatch(uri));
-
- Uri._fromMatch(Match m) :
- this.fromComponents(scheme: _emptyIfNull(m[_COMPONENT_SCHEME]),
- userInfo: _emptyIfNull(m[_COMPONENT_USER_INFO]),
- domain: _eitherOf(
- m[_COMPONENT_DOMAIN], m[_COMPONENT_DOMAIN_IPV6]),
- port: _parseIntOrZero(m[_COMPONENT_PORT]),
- path: _emptyIfNull(m[_COMPONENT_PATH]),
- query: _emptyIfNull(m[_COMPONENT_QUERY_DATA]),
- fragment: _emptyIfNull(m[_COMPONENT_FRAGMENT]));
-
- const Uri.fromComponents({this.scheme: "",
- this.userInfo: "",
- this.domain: "",
- this.port: 0,
- this.path: "",
- this.query: "",
- this.fragment: ""});
-
- Uri(String uri) : this._fromMatch(_splitRe.firstMatch(uri));
-
- static String _emptyIfNull(String val) => val != null ? val : '';
-
- static int _parseIntOrZero(String val) {
- if (val != null && val != '') {
- return int.parse(val);
- } else {
- return 0;
- }
- }
-
- static String _eitherOf(String val1, String val2) {
- if (val1 != null) return val1;
- if (val2 != null) return val2;
- return '';
- }
-
- // NOTE: This code was ported from: closure-library/closure/goog/uri/utils.js
- static final RegExp _splitRe = new RegExp(
- '^'
- '(?:'
- '([^:/?#.]+)' // scheme - ignore special characters
- // used by other URL parts such as :,
- // ?, /, #, and .
- ':)?'
- '(?://'
- '(?:([^/?#]*)@)?' // userInfo
- '(?:'
- r'([\w\d\-\u0100-\uffff.%]*)'
- // domain - restrict to letters,
- // digits, dashes, dots, percent
- // escapes, and unicode characters.
- '|'
- // TODO(ajohnsen): Only allow a max number of parts?
- r'\[([A-Fa-f0-9:.]*)\])'
- // IPv6 domain - restrict to hex,
- // dot and colon.
- '(?::([0-9]+))?' // port
- ')?'
- r'([^?#[]+)?' // path
- r'(?:\?([^#]*))?' // query
- '(?:#(.*))?' // fragment
- r'$');
-
- static const _COMPONENT_SCHEME = 1;
- static const _COMPONENT_USER_INFO = 2;
- static const _COMPONENT_DOMAIN = 3;
- static const _COMPONENT_DOMAIN_IPV6 = 4;
- static const _COMPONENT_PORT = 5;
- static const _COMPONENT_PATH = 6;
- static const _COMPONENT_QUERY_DATA = 7;
- static const _COMPONENT_FRAGMENT = 8;
-
- /**
- * Returns `true` if the URI is absolute.
- */
- bool get isAbsolute {
- if ("" == scheme) return false;
- if ("" != fragment) return false;
- return true;
-
- /* absolute-URI = scheme ":" hier-part [ "?" query ]
- * hier-part = "//" authority path-abempty
- * / path-absolute
- * / path-rootless
- * / path-empty
- *
- * path = path-abempty ; begins with "/" or is empty
- * / path-absolute ; begins with "/" but not "//"
- * / path-noscheme ; begins with a non-colon segment
- * / path-rootless ; begins with a segment
- * / path-empty ; zero characters
- *
- * path-abempty = *( "/" segment )
- * path-absolute = "/" [ segment-nz *( "/" segment ) ]
- * path-noscheme = segment-nz-nc *( "/" segment )
- * path-rootless = segment-nz *( "/" segment )
- * path-empty = 0<pchar>
- * segment = *pchar
- * segment-nz = 1*pchar
- * segment-nz-nc = 1*( unreserved / pct-encoded / sub-delims / "@" )
- * ; non-zero-length segment without any colon ":"
- *
- * pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
- */
- }
-
- Uri resolve(String uri) {
- return resolveUri(Uri.parse(uri));
- }
-
- Uri resolveUri(Uri reference) {
- // From RFC 3986.
- String targetScheme;
- String targetUserInfo;
- String targetDomain;
- int targetPort;
- String targetPath;
- String targetQuery;
- if (reference.scheme != "") {
- targetScheme = reference.scheme;
- targetUserInfo = reference.userInfo;
- targetDomain = reference.domain;
- targetPort = reference.port;
- targetPath = removeDotSegments(reference.path);
- targetQuery = reference.query;
- } else {
- if (reference.hasAuthority) {
- targetUserInfo = reference.userInfo;
- targetDomain = reference.domain;
- targetPort = reference.port;
- targetPath = removeDotSegments(reference.path);
- targetQuery = reference.query;
- } else {
- if (reference.path == "") {
- targetPath = this.path;
- if (reference.query != "") {
- targetQuery = reference.query;
- } else {
- targetQuery = this.query;
- }
- } else {
- if (reference.path.startsWith("/")) {
- targetPath = removeDotSegments(reference.path);
- } else {
- targetPath = removeDotSegments(merge(this.path, reference.path));
- }
- targetQuery = reference.query;
- }
- targetUserInfo = this.userInfo;
- targetDomain = this.domain;
- targetPort = this.port;
- }
- targetScheme = this.scheme;
- }
- return new Uri.fromComponents(scheme: targetScheme,
- userInfo: targetUserInfo,
- domain: targetDomain,
- port: targetPort,
- path: targetPath,
- query: targetQuery,
- fragment: reference.fragment);
- }
-
- bool get hasAuthority {
- return (userInfo != "") || (domain != "") || (port != 0);
- }
-
- /**
- * For http/https schemes returns URI's [origin][] - scheme://domain:port.
- * For all other schemes throws ArgumentError.
- * [origin]: http://www.w3.org/TR/2011/WD-html5-20110405/origin-0.html#origin
- */
- String get origin {
- if (scheme == "") {
- // TODO(aprelev@gmail.com): Use StateException instead
- throw new ArgumentError("Cannot use origin without a scheme");
- }
- if (scheme != "http" && scheme != "https") {
- // TODO(aprelev@gmail.com): Use StateException instead
- throw new ArgumentError(
- "origin is applicable to http/https schemes only. Not \'$scheme\'");
- }
- StringBuffer sb = new StringBuffer();
- sb.write(scheme);
- sb.write(":");
- if (domain == null || domain == "") {
- // TODO(aprelev@gmail.com): Use StateException instead
- throw new ArgumentError("Cannot use origin without a domain");
- }
-
- sb.write("//");
- sb.write(domain);
- if (port != 0) {
- sb.write(":");
- sb.write(port);
- }
- return sb.toString();
- }
-
- String toString() {
- StringBuffer sb = new StringBuffer();
- _addIfNonEmpty(sb, scheme, scheme, ':');
- if (hasAuthority || (scheme == "file")) {
- sb.write("//");
- _addIfNonEmpty(sb, userInfo, userInfo, "@");
- sb.write(domain == null ? "null" :
- domain.contains(':') ? '[$domain]' : domain);
- if (port != 0) {
- sb.write(":");
- sb.write(port.toString());
- }
- }
- sb.write(path == null ? "null" : path);
- _addIfNonEmpty(sb, query, "?", query);
- _addIfNonEmpty(sb, fragment, "#", fragment);
- return sb.toString();
- }
-
- bool operator==(other) {
- if (other is! Uri) return false;
- Uri uri = other;
- return scheme == uri.scheme &&
- userInfo == uri.userInfo &&
- domain == uri.domain &&
- port == uri.port &&
- path == uri.path &&
- query == uri.query &&
- fragment == uri.fragment;
- }
-
- int get hashCode {
- int combine(part, current) {
- // The sum is truncated to 30 bits to make sure it fits into a Smi.
- return (current * 31 + part.hashCode) & 0x3FFFFFFF;
- }
- return combine(scheme, combine(userInfo, combine(domain, combine(port,
- combine(path, combine(query, combine(fragment, 1)))))));
- }
-
- static void _addIfNonEmpty(StringBuffer sb, String test,
- String first, String second) {
- if ("" != test) {
- sb.write(first == null ? "null" : first);
- sb.write(second == null ? "null" : second);
- }
- }
-}
diff --git a/sdk/lib/uri/uri_sources.gypi b/sdk/lib/uri/uri_sources.gypi
deleted file mode 100644
index 09f54fc..0000000
--- a/sdk/lib/uri/uri_sources.gypi
+++ /dev/null
@@ -1,13 +0,0 @@
-# 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.
-
-# This file contains all sources for the dart:uri library.
-{
- 'sources': [
- 'uri.dart',
- # The above file needs to be first as it lists the parts below.
- 'helpers.dart',
- 'encode_decode.dart',
- ],
-}
diff --git a/sdk/lib/utf/utf_stream.dart b/sdk/lib/utf/utf_stream.dart
index 7d72118..8440313 100644
--- a/sdk/lib/utf/utf_stream.dart
+++ b/sdk/lib/utf/utf_stream.dart
@@ -4,16 +4,6 @@
part of dart.utf;
-class _HelperStreamController<T> extends StreamController<T> {
- final Function onPauseChanged;
-
- _HelperStreamController(this.onPauseChanged);
-
- void onPauseStateChange() {
- onPauseChanged();
- }
-}
-
abstract class _StringDecoder
extends StreamEventTransformer<List<int>, String> {
List<int> _carry;
diff --git a/sdk/lib/web_audio/dartium/web_audio_dartium.dart b/sdk/lib/web_audio/dartium/web_audio_dartium.dart
index 6c60ae1..786b08d 100644
--- a/sdk/lib/web_audio/dartium/web_audio_dartium.dart
+++ b/sdk/lib/web_audio/dartium/web_audio_dartium.dart
@@ -260,6 +260,9 @@
@DomName('AudioContext.completeEvent')
@DocsEditable
static const EventStreamProvider<Event> completeEvent = const EventStreamProvider<Event>('complete');
+
+ @DomName('AudioContext.AudioContext')
+ @DocsEditable
factory AudioContext() => _create();
@DocsEditable
diff --git a/tests/co19/co19-analyzer.status b/tests/co19/co19-analyzer.status
index 63668be..f037e57 100644
--- a/tests/co19/co19-analyzer.status
+++ b/tests/co19/co19-analyzer.status
@@ -68,12 +68,6 @@
Language/11_Expressions/06_Lists_A03_t01: fail
Language/11_Expressions/06_Lists_A06_t01: fail
Language/11_Expressions/07_Maps_A02_t02: fail
-Language/11_Expressions/08_Throw_A06_t01: fail
-Language/11_Expressions/08_Throw_A06_t02: fail
-Language/11_Expressions/08_Throw_A06_t03: fail
-Language/11_Expressions/08_Throw_A06_t04: fail
-Language/11_Expressions/08_Throw_A06_t05: fail
-Language/11_Expressions/08_Throw_A06_t06: fail
Language/11_Expressions/11_Instance_Creation/1_New_A13_t02: fail
Language/11_Expressions/11_Instance_Creation/2_Const_A06_t01: fail
Language/11_Expressions/11_Instance_Creation/2_Const_A06_t02: fail
@@ -198,6 +192,10 @@
Language/03_Overview/1_Scoping_A02_t12: fail, OK
Language/03_Overview/1_Scoping_A02_t16: fail, OK
+# co19 issue #420, 'throw' without exception; deprecated; rethrow should be used
+Language/11_Expressions/08_Throw_A05_t01: fail, OK
+Language/11_Expressions/08_Throw_A05_t02: fail, OK
+Language/11_Expressions/08_Throw_A05_t03: fail, OK
[ $runtime == drt && $compiler == none ]
diff --git a/tests/co19/co19-dart2dart.status b/tests/co19/co19-dart2dart.status
index d9e50ce..e639cac 100644
--- a/tests/co19/co19-dart2dart.status
+++ b/tests/co19/co19-dart2dart.status
@@ -85,7 +85,6 @@
Language/03_Overview/1_Scoping_A02_t05: Fail # Inherited from dart2js
Language/03_Overview/1_Scoping_A02_t06: Fail # inherited from dart2js
Language/03_Overview/1_Scoping_A02_t07: Fail # inherited from dart2js
-Language/03_Overview/1_Scoping_A02_t12: Fail # inherited from dart2js
Language/03_Overview/2_Privacy_A01_t06: Fail # New import syntax
Language/05_Variables/05_Variables_A01_t04: Fail # http://dartbug.com/5519
Language/05_Variables/05_Variables_A01_t05: Fail # http://dartbug.com/5519
diff --git a/tests/co19/co19-dart2js.status b/tests/co19/co19-dart2js.status
index 4cf42f1..48de78a 100644
--- a/tests/co19/co19-dart2js.status
+++ b/tests/co19/co19-dart2js.status
@@ -165,8 +165,6 @@
Language/07_Classes/6_Constructors/2_Factories_A01_t05: Fail # Partially implemented rediriecting constructors makes this fail.
-Language/09_Generics/09_Generics_A04_t03: Fail # dart2js does not treat 2.0 as a double; dartbug.com/1533
-
[ $compiler == dart2js && $runtime == ie9 ]
Language/11_Expressions/03_Numbers_A01_t06: Fail # Issue: 8920
Language/11_Expressions/03_Numbers_A01_t09: Fail # Issue: 8920
@@ -273,9 +271,6 @@
Language/14_Types/3_Type_Declarations/1_Typedef_A01_t01: Fail # http://dartbug.com/5022
-LibTest/core/List/operator_subscript_A03_t01: Fail # http://dartbug.com/9228
-LibTest/core/List/operator_subscripted_assignment_A03_t01: Fail # http://dartbug.com/9228
-Language/09_Generics/09_Generics_A04_t01: Fail, OK # 1.0 is an int in dart2js; dartbug.com/1533.
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_t03: Fail, OK # co19 issue 405
@@ -611,7 +606,6 @@
Language/07_Classes/6_Constructors/1_Generative_Constructors_A13_t01: Fail # compiler cancelled: cannot resolve type T
Language/03_Overview/1_Scoping_A02_t07: Fail # duplicate definition of f(var f){f();}
-Language/03_Overview/1_Scoping_A02_t12: Fail # duplicate definition of x=42
Language/03_Overview/2_Privacy_A01_t06: Fail # cannot resolve type _inaccessibleFuncType
Language/11_Expressions/01_Constants_A12_t01: Fail # internal error: CompileTimeConstantEvaluator not implemented
diff --git a/tests/co19/co19-runtime.status b/tests/co19/co19-runtime.status
index 850976f..79111bd 100644
--- a/tests/co19/co19-runtime.status
+++ b/tests/co19/co19-runtime.status
@@ -514,10 +514,6 @@
*: Skip
-[ $compiler == none && $arch == arm ]
-*: Skip
-
-
[ $compiler == none && $arch == simmips ]
*: Skip
diff --git a/tests/compiler/dart2js/analyze_all_test.dart b/tests/compiler/dart2js/analyze_all_test.dart
index 439019d..2a7fcc7 100644
--- a/tests/compiler/dart2js/analyze_all_test.dart
+++ b/tests/compiler/dart2js/analyze_all_test.dart
@@ -27,7 +27,7 @@
""";
main() {
- Uri uri = new Uri('test:code');
+ Uri uri = Uri.parse('test:code');
var compiler = compilerFor(SOURCE, uri, analyzeAll: false);
compiler.runCompiler(uri);
Expect.isFalse(compiler.compilationFailed);
diff --git a/tests/compiler/dart2js/analyze_api_test.dart b/tests/compiler/dart2js/analyze_api_test.dart
index 4e75440..a4cca28 100644
--- a/tests/compiler/dart2js/analyze_api_test.dart
+++ b/tests/compiler/dart2js/analyze_api_test.dart
@@ -5,15 +5,8 @@
library analyze_api;
import "package:expect/expect.dart";
-import 'dart:uri';
-import 'dart:io';
-import '../../../sdk/lib/_internal/compiler/compiler.dart' as api;
-import '../../../sdk/lib/_internal/compiler/implementation/apiimpl.dart';
-import '../../../sdk/lib/_internal/compiler/implementation/dart2jslib.dart'
- hide Compiler;
-import '../../../sdk/lib/_internal/compiler/implementation/filenames.dart';
-import '../../../sdk/lib/_internal/compiler/implementation/source_file_provider.dart';
import '../../../sdk/lib/_internal/libraries.dart';
+import 'analyze_helper.dart';
/**
* Map of white-listed warnings and errors.
@@ -26,7 +19,7 @@
*/
// TODO(johnniwinther): Support canonical URIs as keys and message kinds as
// values.
-const Map<String,List<String>> WHITE_LIST = const {
+const Map<String, List<String>> WHITE_LIST = const {
'html_dart2js.dart':
const ['Warning: Using "new Symbol"', // Issue 10565.
// Issue 10688:
@@ -35,105 +28,12 @@
"Warning: no operator [] in class Iterable"],
};
-class CollectingDiagnosticHandler extends FormattingDiagnosticHandler {
- bool hasWarnings = false;
- bool hasErrors = false;
-
- Map<String,Map<String,int>> whiteListMap = new Map<String,Map<String,int>>();
-
- CollectingDiagnosticHandler(SourceFileProvider provider) : super(provider) {
- WHITE_LIST.forEach((String file, List<String> messageParts) {
- var useMap = new Map<String,int>();
- for (String messagePart in messageParts) {
- useMap[messagePart] = 0;
- }
- whiteListMap[file] = useMap;
- });
- }
-
- bool checkWhiteListUse() {
- bool allUsed = true;
- for (String file in whiteListMap.keys) {
- for (String messagePart in whiteListMap[file].keys) {
- if (whiteListMap[file][messagePart] == 0) {
- print("White-listing '$messagePart' is unused in '$file'. "
- "Remove the white-listing from the WHITE_LIST map.");
- allUsed = false;
- }
- }
- }
- return allUsed;
- }
-
- void reportWhiteListUse() {
- for (String file in whiteListMap.keys) {
- for (String messagePart in whiteListMap[file].keys) {
- int useCount = whiteListMap[file][messagePart];
- print("White-listed message '$messagePart' suppressed $useCount "
- "time(s) in '$file'.");
- }
- }
- }
-
- bool checkWhiteList(Uri uri, String message) {
- if (uri == null) {
- return false;
- }
- String path = uri.path;
- for (String file in whiteListMap.keys) {
- if (path.endsWith(file)) {
- for (String messagePart in whiteListMap[file].keys) {
- if (message.contains(messagePart)) {
- whiteListMap[file][messagePart]++;
- return true;
- }
- }
- }
- }
- return false;
- }
-
- void diagnosticHandler(Uri uri, int begin, int end, String message,
- api.Diagnostic kind) {
- if (kind == api.Diagnostic.WARNING) {
- if (checkWhiteList(uri, message)) {
- // Suppress white listed warnings.
- return;
- }
- hasWarnings = true;
- }
- if (kind == api.Diagnostic.ERROR) {
- if (checkWhiteList(uri, message)) {
- // Suppress white listed warnings.
- return;
- }
- hasErrors = true;
- }
- super.diagnosticHandler(uri, begin, end, message, kind);
- }
-}
-
void main() {
- var libraryRoot = currentDirectory.resolve('sdk/');
var uriList = new List<Uri>();
LIBRARIES.forEach((String name, LibraryInfo info) {
if (info.documented) {
- uriList.add(new Uri.fromComponents(scheme: 'dart', path: name));
+ uriList.add(new Uri(scheme: 'dart', path: name));
}
});
- var provider = new SourceFileProvider();
- var handler = new CollectingDiagnosticHandler(provider);
- var compiler = new Compiler(
- provider.readStringFromUri,
- null,
- handler.diagnosticHandler,
- libraryRoot, libraryRoot,
- <String>['--analyze-only', '--analyze-all',
- '--categories=Client,Server']);
- compiler.librariesToAnalyzeWhenRun = uriList;
- compiler.run(null);
- Expect.isFalse(handler.hasWarnings);
- Expect.isFalse(handler.hasErrors);
- Expect.isTrue(handler.checkWhiteListUse());
- handler.reportWhiteListUse();
+ analyze(uriList, WHITE_LIST);
}
diff --git a/tests/compiler/dart2js/analyze_dart2js_test.dart b/tests/compiler/dart2js/analyze_dart2js_test.dart
new file mode 100644
index 0000000..cb66fdf
--- /dev/null
+++ b/tests/compiler/dart2js/analyze_dart2js_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.
+
+library analyze_api;
+
+import "package:expect/expect.dart";
+import '../../../sdk/lib/_internal/compiler/implementation/filenames.dart';
+import 'analyze_helper.dart';
+
+/**
+ * Map of white-listed warnings and errors.
+ *
+ * Only add a white-listing together with a bug report to dartbug.com and add
+ * the bug issue number as a comment on the white-listing.
+ *
+ * Use an identifiable suffix of the file uri as key. Use a fixed substring of
+ * the error/warning message in the list of white-listings for each file.
+ */
+// TODO(johnniwinther): Support canonical URIs as keys and message kinds as
+// values.
+const Map<String,List<String>> WHITE_LIST = const {
+};
+
+void main() {
+ var uri = currentDirectory.resolve(
+ 'sdk/lib/_internal/compiler/implementation/dart2js.dart');
+ analyze([uri], WHITE_LIST);
+}
diff --git a/tests/compiler/dart2js/analyze_helper.dart b/tests/compiler/dart2js/analyze_helper.dart
new file mode 100644
index 0000000..c3e6729
--- /dev/null
+++ b/tests/compiler/dart2js/analyze_helper.dart
@@ -0,0 +1,130 @@
+// 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 analyze_helper;
+
+import "package:expect/expect.dart";
+import 'dart:io';
+import '../../../sdk/lib/_internal/compiler/compiler.dart' as api;
+import '../../../sdk/lib/_internal/compiler/implementation/apiimpl.dart';
+import '../../../sdk/lib/_internal/compiler/implementation/dart2jslib.dart'
+ hide Compiler;
+import '../../../sdk/lib/_internal/compiler/implementation/filenames.dart';
+import '../../../sdk/lib/_internal/compiler/implementation/source_file_provider.dart';
+
+/**
+ * Map of white-listed warnings and errors.
+ *
+ * Only add a white-listing together with a bug report to dartbug.com and add
+ * the bug issue number as a comment on the white-listing.
+ *
+ * Use an identifiable suffix of the file uri as key. Use a fixed substring of
+ * the error/warning message in the list of white-listings for each file.
+ */
+// TODO(johnniwinther): Support canonical URIs as keys and message kinds as
+// values.
+
+class CollectingDiagnosticHandler extends FormattingDiagnosticHandler {
+ bool hasWarnings = false;
+ bool hasErrors = false;
+
+ Map<String, Map<String, int>> whiteListMap
+ = new Map<String, Map<String, int>>();
+
+ CollectingDiagnosticHandler(Map<String, List<String>> whiteList,
+ SourceFileProvider provider)
+ : super(provider) {
+ whiteList.forEach((String file, List<String> messageParts) {
+ var useMap = new Map<String,int>();
+ for (String messagePart in messageParts) {
+ useMap[messagePart] = 0;
+ }
+ whiteListMap[file] = useMap;
+ });
+ }
+
+ void checkResults() {
+ Expect.isFalse(hasWarnings);
+ Expect.isFalse(hasErrors);
+ Expect.isTrue(checkWhiteListUse());
+ reportWhiteListUse();
+ }
+
+ bool checkWhiteListUse() {
+ bool allUsed = true;
+ for (String file in whiteListMap.keys) {
+ for (String messagePart in whiteListMap[file].keys) {
+ if (whiteListMap[file][messagePart] == 0) {
+ print("White-listing '$messagePart' is unused in '$file'. "
+ "Remove the white-listing from the white list map.");
+ allUsed = false;
+ }
+ }
+ }
+ return allUsed;
+ }
+
+ void reportWhiteListUse() {
+ for (String file in whiteListMap.keys) {
+ for (String messagePart in whiteListMap[file].keys) {
+ int useCount = whiteListMap[file][messagePart];
+ print("White-listed message '$messagePart' suppressed $useCount "
+ "time(s) in '$file'.");
+ }
+ }
+ }
+
+ bool checkWhiteList(Uri uri, String message) {
+ if (uri == null) {
+ return false;
+ }
+ String path = uri.path;
+ for (String file in whiteListMap.keys) {
+ if (path.endsWith(file)) {
+ for (String messagePart in whiteListMap[file].keys) {
+ if (message.contains(messagePart)) {
+ whiteListMap[file][messagePart]++;
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ void diagnosticHandler(Uri uri, int begin, int end, String message,
+ api.Diagnostic kind) {
+ if (kind == api.Diagnostic.WARNING) {
+ if (checkWhiteList(uri, message)) {
+ // Suppress white listed warnings.
+ return;
+ }
+ hasWarnings = true;
+ }
+ if (kind == api.Diagnostic.ERROR) {
+ if (checkWhiteList(uri, message)) {
+ // Suppress white listed warnings.
+ return;
+ }
+ hasErrors = true;
+ }
+ super.diagnosticHandler(uri, begin, end, message, kind);
+ }
+}
+
+void analyze(List<Uri> uriList, Map<String, List<String>> whiteList) {
+ var libraryRoot = currentDirectory.resolve('sdk/');
+ var provider = new SourceFileProvider();
+ var handler = new CollectingDiagnosticHandler(whiteList, provider);
+ var compiler = new Compiler(
+ provider.readStringFromUri,
+ null,
+ handler.diagnosticHandler,
+ libraryRoot, libraryRoot,
+ <String>['--analyze-only', '--analyze-all',
+ '--categories=Client,Server']);
+ compiler.librariesToAnalyzeWhenRun = uriList;
+ compiler.run(null);
+ handler.checkResults();
+}
diff --git a/tests/compiler/dart2js/analyze_only_test.dart b/tests/compiler/dart2js/analyze_only_test.dart
index c890e85..34e52c7 100644
--- a/tests/compiler/dart2js/analyze_only_test.dart
+++ b/tests/compiler/dart2js/analyze_only_test.dart
@@ -7,7 +7,6 @@
import "package:expect/expect.dart";
import 'dart:async';
-import 'dart:uri';
import '../../utils/dummy_compiler_test.dart' as dummy;
import '../../../sdk/lib/_internal/compiler/compiler.dart';
@@ -36,9 +35,9 @@
print('main source:\n$main');
print('options: $options\n');
Future<String> result =
- compile(new Uri.fromComponents(scheme: 'main'),
- new Uri.fromComponents(scheme: 'lib', path: '/'),
- new Uri.fromComponents(scheme: 'package', path: '/'),
+ compile(new Uri(scheme: 'main'),
+ new Uri(scheme: 'lib', path: '/'),
+ new Uri(scheme: 'package', path: '/'),
localProvider, localHandler, options);
result.then((String code) {
onValue(code, errors, warnings);
diff --git a/tests/compiler/dart2js/backend_htype_list_test.dart b/tests/compiler/dart2js/backend_htype_list_test.dart
index 7b44059..67acff3 100644
--- a/tests/compiler/dart2js/backend_htype_list_test.dart
+++ b/tests/compiler/dart2js/backend_htype_list_test.dart
@@ -29,7 +29,7 @@
FunctionSignature compileAndFindSignature(String code,
String className,
String memberName) {
- Uri uri = new Uri.fromComponents(scheme: 'source');
+ Uri uri = new Uri(scheme: 'source');
var compiler = compilerFor(code, uri);
compiler.runCompiler(uri);
var cls = findElement(compiler, className);
diff --git a/tests/compiler/dart2js/bad_loop_test.dart b/tests/compiler/dart2js/bad_loop_test.dart
index 5705095..dbf8795 100644
--- a/tests/compiler/dart2js/bad_loop_test.dart
+++ b/tests/compiler/dart2js/bad_loop_test.dart
@@ -37,7 +37,7 @@
libraryRoot,
packageRoot,
['--analyze-only']);
- compiler.run(new Uri('memory:main.dart'));
+ compiler.run(Uri.parse('memory:main.dart'));
Expect.isTrue(compiler.compilationFailed);
Expect.equals(5, errorCount);
Expect.equals(1, warningCount);
diff --git a/tests/compiler/dart2js/call_site_simple_type_inferer_test.dart b/tests/compiler/dart2js/call_site_simple_type_inferer_test.dart
index 8ff09c7..d3fd545 100644
--- a/tests/compiler/dart2js/call_site_simple_type_inferer_test.dart
+++ b/tests/compiler/dart2js/call_site_simple_type_inferer_test.dart
@@ -14,7 +14,7 @@
String memberName,
bool disableInlining,
check(compiler, element)) {
- Uri uri = new Uri.fromComponents(scheme: 'source');
+ Uri uri = new Uri(scheme: 'source');
var compiler = compilerFor(code, uri);
compiler.disableInlining = disableInlining;
compiler.runCompiler(uri);
diff --git a/tests/compiler/dart2js/call_site_type_inferer_static_test.dart b/tests/compiler/dart2js/call_site_type_inferer_static_test.dart
index 5a77227..e8a1f0b 100644
--- a/tests/compiler/dart2js/call_site_type_inferer_static_test.dart
+++ b/tests/compiler/dart2js/call_site_type_inferer_static_test.dart
@@ -13,7 +13,7 @@
String functionName,
bool disableInlining,
check(compiler, element)) {
- Uri uri = new Uri.fromComponents(scheme: 'source');
+ Uri uri = new Uri(scheme: 'source');
var compiler = compilerFor(code, uri);
compiler.disableInlining = disableInlining;
compiler.runCompiler(uri);
diff --git a/tests/compiler/dart2js/call_site_type_inferer_test.dart b/tests/compiler/dart2js/call_site_type_inferer_test.dart
index bad589f..7e75dd1 100644
--- a/tests/compiler/dart2js/call_site_type_inferer_test.dart
+++ b/tests/compiler/dart2js/call_site_type_inferer_test.dart
@@ -14,7 +14,7 @@
String memberName,
bool disableInlining,
check(compiler, element)) {
- Uri uri = new Uri.fromComponents(scheme: 'source');
+ Uri uri = new Uri(scheme: 'source');
var compiler = compilerFor(code, uri);
compiler.disableInlining = disableInlining;
compiler.runCompiler(uri);
diff --git a/tests/compiler/dart2js/codegen_helper.dart b/tests/compiler/dart2js/codegen_helper.dart
index f89a80b..23884da 100644
--- a/tests/compiler/dart2js/codegen_helper.dart
+++ b/tests/compiler/dart2js/codegen_helper.dart
@@ -23,7 +23,7 @@
libraryRoot,
packageRoot,
options);
- Uri uri = new Uri('memory:main.dart');
+ Uri uri = Uri.parse('memory:main.dart');
Expect.isTrue(compiler.run(uri));
Map<String, String> result = new Map<String, String>();
for (var element in compiler.backend.generatedCode.keys) {
diff --git a/tests/compiler/dart2js/compiler_helper.dart b/tests/compiler/dart2js/compiler_helper.dart
index e602004..8c72e42 100644
--- a/tests/compiler/dart2js/compiler_helper.dart
+++ b/tests/compiler/dart2js/compiler_helper.dart
@@ -6,8 +6,6 @@
library compiler_helper;
import "package:expect/expect.dart";
-import 'dart:uri';
-export 'dart:uri' show Uri;
import '../../../sdk/lib/_internal/compiler/implementation/elements/elements.dart'
as lego;
@@ -90,7 +88,7 @@
}
String compileAll(String code, {String coreSource: DEFAULT_CORELIB}) {
- Uri uri = new Uri.fromComponents(scheme: 'source');
+ Uri uri = new Uri(scheme: 'source');
MockCompiler compiler = compilerFor(code, uri, coreSource: coreSource);
compiler.runCompiler(uri);
Expect.isFalse(compiler.compilationFailed,
@@ -101,7 +99,7 @@
dynamic compileAndCheck(String code,
String name,
check(MockCompiler compiler, lego.Element element)) {
- Uri uri = new Uri.fromComponents(scheme: 'source');
+ Uri uri = new Uri(scheme: 'source');
MockCompiler compiler = compilerFor(code, uri);
compiler.runCompiler(uri);
lego.Element element = findElement(compiler, name);
@@ -110,7 +108,7 @@
compileSources(Map<String, String> sources,
check(MockCompiler compiler)) {
- Uri base = new Uri.fromComponents(scheme: 'source');
+ Uri base = new Uri(scheme: 'source');
Uri mainUri = base.resolve('main.dart');
String mainCode = sources['main.dart'];
Expect.isNotNull(mainCode, 'No source code found for "main.dart"');
diff --git a/tests/compiler/dart2js/concrete_type_inference_test.dart b/tests/compiler/dart2js/concrete_type_inference_test.dart
index 6a748c6..c801442 100644
--- a/tests/compiler/dart2js/concrete_type_inference_test.dart
+++ b/tests/compiler/dart2js/concrete_type_inference_test.dart
@@ -8,7 +8,7 @@
void compileAndFind(String code, String name,
check(compiler, element)) {
- Uri uri = new Uri.fromComponents(scheme: 'source');
+ Uri uri = new Uri(scheme: 'source');
var compiler = compilerFor(code, uri);
compiler.runCompiler(uri);
var element = findElement(compiler, name);
diff --git a/tests/compiler/dart2js/cpa_inference_test.dart b/tests/compiler/dart2js/cpa_inference_test.dart
index 5a53ec9..2e69408 100644
--- a/tests/compiler/dart2js/cpa_inference_test.dart
+++ b/tests/compiler/dart2js/cpa_inference_test.dart
@@ -167,11 +167,12 @@
class Closure {}
class Null {}
class Type {}
+ class StackTrace {}
class Dynamic_ {}
bool identical(Object a, Object b) {}''';
AnalysisResult analyze(String code, {int maxConcreteTypeSize: 1000}) {
- Uri uri = new Uri.fromComponents(scheme: 'source');
+ Uri uri = new Uri(scheme: 'source');
MockCompiler compiler = new MockCompiler(
coreSource: CORELIB,
enableConcreteTypeInference: true,
diff --git a/tests/compiler/dart2js/dart_backend_test.dart b/tests/compiler/dart2js/dart_backend_test.dart
index 0b5f109..59fe13f 100644
--- a/tests/compiler/dart2js/dart_backend_test.dart
+++ b/tests/compiler/dart2js/dart_backend_test.dart
@@ -4,7 +4,6 @@
import "package:expect/expect.dart";
import 'dart:async';
-import 'dart:uri';
import 'parser_helper.dart';
import 'mock_compiler.dart';
import '../../../sdk/lib/_internal/compiler/compiler.dart';
@@ -29,6 +28,7 @@
class Null {}
class TypeError {}
class Type {}
+class StackTrace {}
class LinkedHashMap {}
class Math {
static double parseDouble(String s) => 1.0;
@@ -87,7 +87,7 @@
String srcMain, String srcLibrary,
{void continuation(String s), bool minify: false,
bool stripTypes: false}) {
- fileUri(path) => new Uri.fromComponents(scheme: 'file', path: path);
+ fileUri(path) => new Uri(scheme: 'file', path: path);
final scriptUri = fileUri('script.dart');
final libUri = fileUri('mylib.dart');
diff --git a/tests/compiler/dart2js/dead_code_test.dart b/tests/compiler/dart2js/dead_code_test.dart
new file mode 100644
index 0000000..993d7e950
--- /dev/null
+++ b/tests/compiler/dart2js/dead_code_test.dart
@@ -0,0 +1,21 @@
+// 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:expect/expect.dart";
+import 'compiler_helper.dart';
+
+String TEST = r'''
+main() {
+ foo(null);
+}
+foo(a) {
+ if (a != null) return 42;
+ return 54;
+}
+''';
+
+main() {
+ String generated = compileAll(TEST);
+ Expect.isFalse(generated.contains('return 42'), 'dead code not eliminated');
+}
diff --git a/tests/compiler/dart2js/deferred_load_graph_segmentation_test.dart b/tests/compiler/dart2js/deferred_load_graph_segmentation_test.dart
index b05ead8..eec688a 100644
--- a/tests/compiler/dart2js/deferred_load_graph_segmentation_test.dart
+++ b/tests/compiler/dart2js/deferred_load_graph_segmentation_test.dart
@@ -27,7 +27,7 @@
libraryRoot,
packageRoot,
['--analyze-only']);
- compiler.run(new Uri('memory:main.dart'));
+ compiler.run(Uri.parse('memory:main.dart'));
var main = compiler.mainApp.find(dart2js.Compiler.MAIN);
Expect.isNotNull(main, 'Could not find "main"');
compiler.deferredLoadTask.onResolutionComplete(main);
diff --git a/tests/compiler/dart2js/deprecated_features_test.dart b/tests/compiler/dart2js/deprecated_features_test.dart
index 3ca046e..3d0a12e 100644
--- a/tests/compiler/dart2js/deprecated_features_test.dart
+++ b/tests/compiler/dart2js/deprecated_features_test.dart
@@ -6,7 +6,6 @@
import "package:expect/expect.dart";
import 'dart:async';
-import 'dart:uri';
import '../../../sdk/lib/_internal/compiler/compiler.dart';
import '../../utils/dummy_compiler_test.dart' as dummy;
@@ -35,9 +34,9 @@
}
String code = deprecatedFutureValue(
- compile(new Uri.fromComponents(scheme: 'main'),
- new Uri.fromComponents(scheme: 'lib', path: '/'),
- new Uri.fromComponents(scheme: 'package', path: '/'),
+ compile(new Uri(scheme: 'main'),
+ new Uri(scheme: 'lib', path: '/'),
+ new Uri(scheme: 'package', path: '/'),
provider, handler));
if (code == null) {
throw 'Compilation failed: ${messages}';
diff --git a/tests/compiler/dart2js/field_type_inferer_test.dart b/tests/compiler/dart2js/field_type_inferer_test.dart
index 59db184..ee2b5fb 100644
--- a/tests/compiler/dart2js/field_type_inferer_test.dart
+++ b/tests/compiler/dart2js/field_type_inferer_test.dart
@@ -15,7 +15,7 @@
String memberName,
bool disableInlining,
check(compiler, element)) {
- Uri uri = new Uri.fromComponents(scheme: 'source');
+ Uri uri = new Uri(scheme: 'source');
var compiler = compilerFor(code, uri);
compiler.runCompiler(uri);
compiler.disableInlining = disableInlining;
diff --git a/tests/compiler/dart2js/field_type_simple_inferer_test.dart b/tests/compiler/dart2js/field_type_simple_inferer_test.dart
index 7422b80..1e25741 100644
--- a/tests/compiler/dart2js/field_type_simple_inferer_test.dart
+++ b/tests/compiler/dart2js/field_type_simple_inferer_test.dart
@@ -14,7 +14,7 @@
String memberName,
bool disableInlining,
check(compiler, element)) {
- Uri uri = new Uri.fromComponents(scheme: 'source');
+ Uri uri = new Uri(scheme: 'source');
var compiler = compilerFor(code, uri);
compiler.runCompiler(uri);
compiler.disableInlining = disableInlining;
@@ -334,11 +334,13 @@
const String TEST_20 = r"""
class A {
var f;
- A(x) {
- for (var i in this) {
+ A() {
+ for (f in this) {
}
- f = 42;
}
+ get iterator => this;
+ get current => 42;
+ bool moveNext() => false;
}
main() {
new A();
@@ -508,7 +510,7 @@
runTest(TEST_19, {'f1': (inferrer) => inferrer.intType,
'f2': (inferrer) => inferrer.stringType,
'f3': (inferrer) => inferrer.dynamicType});
- runTest(TEST_20, {'f': (inferrer) => inferrer.intType});
+ runTest(TEST_20, {'f': (inferrer) => inferrer.intType.nullable()});
runTest(TEST_21, {'f': (inferrer) => inferrer.intType.nullable()});
runTest(TEST_22, {'f1': (inferrer) => inferrer.intType,
diff --git a/tests/compiler/dart2js/gvn_dynamic_field_get_test.dart b/tests/compiler/dart2js/gvn_dynamic_field_get_test.dart
index 739645b..c1a784a 100644
--- a/tests/compiler/dart2js/gvn_dynamic_field_get_test.dart
+++ b/tests/compiler/dart2js/gvn_dynamic_field_get_test.dart
@@ -22,7 +22,7 @@
""";
main() {
- Uri uri = new Uri.fromComponents(scheme: 'source');
+ Uri uri = new Uri(scheme: 'source');
var compiler = compilerFor(TEST, uri);
compiler.runCompiler(uri);
String generated = compiler.assembledCode;
diff --git a/tests/compiler/dart2js/memory_source_file_helper.dart b/tests/compiler/dart2js/memory_source_file_helper.dart
index db1c4f0..10f3102 100644
--- a/tests/compiler/dart2js/memory_source_file_helper.dart
+++ b/tests/compiler/dart2js/memory_source_file_helper.dart
@@ -5,8 +5,6 @@
library dart2js.test.memory_source_file_helper;
import 'dart:async' show Future;
-import 'dart:uri' show Uri;
-export 'dart:uri' show Uri;
import 'dart:io';
export 'dart:io' show Options;
diff --git a/tests/compiler/dart2js/metadata_test.dart b/tests/compiler/dart2js/metadata_test.dart
index c40d9a7..0e3b20b 100644
--- a/tests/compiler/dart2js/metadata_test.dart
+++ b/tests/compiler/dart2js/metadata_test.dart
@@ -143,15 +143,15 @@
void compileAndCheckLibrary(
String source,
Link<MetadataAnnotation> extractMetadata(LibraryElement element)) {
- Uri partUri = new Uri.fromComponents(scheme: 'source', path: 'part.dart');
+ Uri partUri = new Uri(scheme: 'source', path: 'part.dart');
String partSource = '@native part of foo;';
- Uri libUri = new Uri.fromComponents(scheme: 'source', path: 'lib.dart');
+ Uri libUri = new Uri(scheme: 'source', path: 'lib.dart');
String libSource = 'library lib;';
- Uri uri = new Uri.fromComponents(scheme: 'source', path: 'main.dart');
+ Uri uri = new Uri(scheme: 'source', path: 'main.dart');
- Uri async = new Uri.fromComponents(scheme: 'dart', path: 'async');
+ Uri async = new Uri(scheme: 'dart', path: 'async');
var compiler = compilerFor(source, uri)
..registerSource(partUri, partSource)
diff --git a/tests/compiler/dart2js/mirrors_metadata_test.dart b/tests/compiler/dart2js/mirrors_metadata_test.dart
index c52c744..22b0c81 100644
--- a/tests/compiler/dart2js/mirrors_metadata_test.dart
+++ b/tests/compiler/dart2js/mirrors_metadata_test.dart
@@ -5,7 +5,6 @@
import 'package:expect/expect.dart';
import 'dart:async';
import 'dart:io';
-import 'dart:uri';
import '../../../sdk/lib/_internal/compiler/implementation/filenames.dart';
import '../../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors.dart';
import '../../../sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirror.dart';
@@ -13,7 +12,7 @@
import 'mock_compiler.dart';
const String SOURCE = 'source';
-const Uri SOURCE_URI = const Uri.fromComponents(scheme: SOURCE, path: SOURCE);
+Uri SOURCE_URI = new Uri(scheme: SOURCE, path: SOURCE);
MirrorSystem createMirrorSystem(String source) {
MockCompiler compiler = new MockCompiler(
diff --git a/tests/compiler/dart2js/mirrors_test.dart b/tests/compiler/dart2js/mirrors_test.dart
index 38ceef2..6fc2094 100644
--- a/tests/compiler/dart2js/mirrors_test.dart
+++ b/tests/compiler/dart2js/mirrors_test.dart
@@ -11,10 +11,8 @@
import '../../../sdk/lib/_internal/compiler/implementation/source_file_provider.dart';
import 'dart:io';
-import 'dart:uri';
-const Uri DART_MIRRORS_URI =
- const Uri.fromComponents(scheme: 'dart', path: 'mirrors');
+final Uri DART_MIRRORS_URI = new Uri(scheme: 'dart', path: 'mirrors');
int count(Iterable iterable) {
var count = 0;
diff --git a/tests/compiler/dart2js/mock_compiler.dart b/tests/compiler/dart2js/mock_compiler.dart
index 63e8492..d0c1089 100644
--- a/tests/compiler/dart2js/mock_compiler.dart
+++ b/tests/compiler/dart2js/mock_compiler.dart
@@ -6,7 +6,6 @@
import "package:expect/expect.dart";
import 'dart:collection';
-import 'dart:uri';
import '../../../sdk/lib/_internal/compiler/compiler.dart' as api;
import '../../../sdk/lib/_internal/compiler/implementation/elements/elements.dart';
@@ -160,6 +159,7 @@
String toString() { return null; }
noSuchMethod(im) { throw im; }
}
+ abstract class StackTrace {}
class Type {}
class Function {}
class List<E> {}
@@ -246,7 +246,7 @@
* is fixed to export its top-level declarations.
*/
LibraryElement createLibrary(String name, String source) {
- Uri uri = new Uri.fromComponents(scheme: "dart", path: name);
+ Uri uri = new Uri(scheme: "dart", path: name);
var script = new Script(uri, new MockFile(source));
var library = new LibraryElementX(script);
parseScript(source, library);
@@ -401,7 +401,7 @@
}
LibraryElement mockLibrary(Compiler compiler, String source) {
- Uri uri = new Uri.fromComponents(scheme: "source");
+ Uri uri = new Uri(scheme: "source");
var library = new LibraryElementX(new Script(uri, new MockFile(source)));
importLibrary(library, compiler.coreLibrary, compiler);
return library;
diff --git a/tests/compiler/dart2js/parser_helper.dart b/tests/compiler/dart2js/parser_helper.dart
index 3ba38e9..4b4c762 100644
--- a/tests/compiler/dart2js/parser_helper.dart
+++ b/tests/compiler/dart2js/parser_helper.dart
@@ -5,7 +5,6 @@
library parser_helper;
import "package:expect/expect.dart";
-import "dart:uri";
import "../../../sdk/lib/_internal/compiler/implementation/elements/elements.dart";
import "../../../sdk/lib/_internal/compiler/implementation/tree/tree.dart";
@@ -43,7 +42,7 @@
if (diagnosticHandler == null) diagnosticHandler = new LoggerCanceler();
Script script =
new Script(
- new Uri.fromComponents(scheme: "source"),
+ new Uri(scheme: "source"),
new MockFile(text));
LibraryElement library = new LibraryElementX(script);
library.canUseNative = true;
@@ -84,8 +83,7 @@
LibraryElement library,
[void registerSource(Uri uri, String source)]) {
Token tokens = scan(text);
- Uri uri =
- new Uri.fromComponents(scheme: "source", path: '${++sourceCounter}');
+ Uri uri = new Uri(scheme: "source", path: '${++sourceCounter}');
if (registerSource != null) {
registerSource(uri, text);
}
diff --git a/tests/compiler/dart2js/part_of_test.dart b/tests/compiler/dart2js/part_of_test.dart
index aec3c73..629c267 100644
--- a/tests/compiler/dart2js/part_of_test.dart
+++ b/tests/compiler/dart2js/part_of_test.dart
@@ -5,18 +5,17 @@
library part_of_test;
import "package:expect/expect.dart";
-import 'dart:uri';
import 'mock_compiler.dart';
import '../../../sdk/lib/_internal/compiler/implementation/dart2jslib.dart'
show MessageKind;
-final libraryUri = new Uri('test:library.dart');
+final libraryUri = Uri.parse('test:library.dart');
const String LIBRARY_SOURCE = '''
library foo;
part 'part.dart';
''';
-final partUri = new Uri('test:part.dart');
+final partUri = Uri.parse('test:part.dart');
const String PART_SOURCE = '''
part of bar;
''';
diff --git a/tests/compiler/dart2js/patch_test.dart b/tests/compiler/dart2js/patch_test.dart
index 1d33715..3cf4b46 100644
--- a/tests/compiler/dart2js/patch_test.dart
+++ b/tests/compiler/dart2js/patch_test.dart
@@ -9,12 +9,11 @@
import "../../../sdk/lib/_internal/compiler/implementation/util/util.dart";
import "mock_compiler.dart";
import "parser_helper.dart";
-import "dart:uri";
Compiler applyPatch(String script, String patch) {
String core = "$DEFAULT_CORELIB\n$script";
MockCompiler compiler = new MockCompiler(coreSource: core);
- var uri = new Uri("core.dartp");
+ var uri = Uri.parse("core.dartp");
compiler.sourceFiles[uri.toString()] = new MockFile(patch);
var handler = new LibraryDependencyHandler(compiler);
compiler.patchParser.patchLibrary(handler, uri, compiler.coreLibrary);
diff --git a/tests/compiler/dart2js/reexport_handled_test.dart b/tests/compiler/dart2js/reexport_handled_test.dart
index 8a1ca82..d309fcd 100644
--- a/tests/compiler/dart2js/reexport_handled_test.dart
+++ b/tests/compiler/dart2js/reexport_handled_test.dart
@@ -5,19 +5,18 @@
library reexport_handled_test;
import "package:expect/expect.dart";
-import 'dart:uri';
import 'mock_compiler.dart';
import '../../../sdk/lib/_internal/compiler/implementation/elements/elements.dart'
show Element,
LibraryElement;
-final exportingLibraryUri = new Uri('exporting.dart');
+final exportingLibraryUri = Uri.parse('exporting.dart');
const String EXPORTING_LIBRARY_SOURCE = '''
library exporting;
var foo;
''';
-final reexportingLibraryUri = new Uri('reexporting.dart');
+final reexportingLibraryUri = Uri.parse('reexporting.dart');
const String REEXPORTING_LIBRARY_SOURCE = '''
library reexporting;
export 'exporting.dart';
@@ -51,4 +50,4 @@
}
}
return null;
-}
\ No newline at end of file
+}
diff --git a/tests/compiler/dart2js/resolution_test.dart b/tests/compiler/dart2js/resolution_test.dart
index c1a327f..32f5945 100644
--- a/tests/compiler/dart2js/resolution_test.dart
+++ b/tests/compiler/dart2js/resolution_test.dart
@@ -92,7 +92,7 @@
""";
void test(String code, void check(Compiler compiler)) {
- Uri uri = new Uri.fromComponents(scheme: 'source');
+ Uri uri = new Uri(scheme: 'source');
var compiler = compilerFor(code, uri);
compiler.runCompiler(uri);
check(compiler);
diff --git a/tests/compiler/dart2js/resolver_test.dart b/tests/compiler/dart2js/resolver_test.dart
index a1d6ad3..dcdcc07 100644
--- a/tests/compiler/dart2js/resolver_test.dart
+++ b/tests/compiler/dart2js/resolver_test.dart
@@ -759,6 +759,7 @@
class Map {}
class Closure {}
class Null {}
+ class StackTrace {}
class Dynamic_ {}
class Type {}
class Object { Object() : super(); }''';
@@ -783,7 +784,7 @@
}
compileScript(String source) {
- Uri uri = new Uri.fromComponents(scheme: 'source');
+ Uri uri = new Uri(scheme: 'source');
MockCompiler compiler = compilerFor(source, uri);
compiler.runCompiler(uri);
return compiler;
diff --git a/tests/compiler/dart2js/simple_inferrer_and_or_test.dart b/tests/compiler/dart2js/simple_inferrer_and_or_test.dart
index 40c01a5..eccf849 100644
--- a/tests/compiler/dart2js/simple_inferrer_and_or_test.dart
+++ b/tests/compiler/dart2js/simple_inferrer_and_or_test.dart
@@ -55,7 +55,7 @@
void main() {
- Uri uri = new Uri.fromComponents(scheme: 'source');
+ Uri uri = new Uri(scheme: 'source');
var compiler = compilerFor(TEST, uri);
compiler.runCompiler(uri);
var typesInferrer = compiler.typesTask.typesInferrer;
diff --git a/tests/compiler/dart2js/simple_inferrer_closure_test.dart b/tests/compiler/dart2js/simple_inferrer_closure_test.dart
index f731839..23d6db0 100644
--- a/tests/compiler/dart2js/simple_inferrer_closure_test.dart
+++ b/tests/compiler/dart2js/simple_inferrer_closure_test.dart
@@ -80,7 +80,7 @@
void main() {
- Uri uri = new Uri.fromComponents(scheme: 'source');
+ Uri uri = new Uri(scheme: 'source');
var compiler = compilerFor(TEST, uri);
compiler.runCompiler(uri);
var typesInferrer = compiler.typesTask.typesInferrer;
diff --git a/tests/compiler/dart2js/simple_inferrer_final_field2_test.dart b/tests/compiler/dart2js/simple_inferrer_final_field2_test.dart
index a374e9c..e03c4f3 100644
--- a/tests/compiler/dart2js/simple_inferrer_final_field2_test.dart
+++ b/tests/compiler/dart2js/simple_inferrer_final_field2_test.dart
@@ -24,7 +24,7 @@
""";
void main() {
- Uri uri = new Uri.fromComponents(scheme: 'source');
+ Uri uri = new Uri(scheme: 'source');
var compiler = compilerFor(TEST, uri);
compiler.runCompiler(uri);
var typesInferrer = compiler.typesTask.typesInferrer;
diff --git a/tests/compiler/dart2js/simple_inferrer_final_field3_test.dart b/tests/compiler/dart2js/simple_inferrer_final_field3_test.dart
index b43693e..058187b 100644
--- a/tests/compiler/dart2js/simple_inferrer_final_field3_test.dart
+++ b/tests/compiler/dart2js/simple_inferrer_final_field3_test.dart
@@ -23,7 +23,7 @@
""";
void main() {
- Uri uri = new Uri.fromComponents(scheme: 'source');
+ Uri uri = new Uri(scheme: 'source');
var compiler = compilerFor(TEST, uri);
compiler.runCompiler(uri);
var typesInferrer = compiler.typesTask.typesInferrer;
diff --git a/tests/compiler/dart2js/simple_inferrer_final_field_test.dart b/tests/compiler/dart2js/simple_inferrer_final_field_test.dart
index 2e3cc4c..3108608 100644
--- a/tests/compiler/dart2js/simple_inferrer_final_field_test.dart
+++ b/tests/compiler/dart2js/simple_inferrer_final_field_test.dart
@@ -26,7 +26,7 @@
""";
void main() {
- Uri uri = new Uri.fromComponents(scheme: 'source');
+ Uri uri = new Uri(scheme: 'source');
var compiler = compilerFor(TEST, uri);
compiler.runCompiler(uri);
var typesInferrer = compiler.typesTask.typesInferrer;
diff --git a/tests/compiler/dart2js/simple_inferrer_no_such_method_test.dart b/tests/compiler/dart2js/simple_inferrer_no_such_method_test.dart
index 91fb20d..400c0f8 100644
--- a/tests/compiler/dart2js/simple_inferrer_no_such_method_test.dart
+++ b/tests/compiler/dart2js/simple_inferrer_no_such_method_test.dart
@@ -93,7 +93,7 @@
""";
main() {
- Uri uri = new Uri.fromComponents(scheme: 'source');
+ Uri uri = new Uri(scheme: 'source');
var compiler = compilerFor(TEST1, uri);
compiler.runCompiler(uri);
diff --git a/tests/compiler/dart2js/simple_inferrer_postfix_prefix_test.dart b/tests/compiler/dart2js/simple_inferrer_postfix_prefix_test.dart
index 3c9aaa1..cfae3a7 100644
--- a/tests/compiler/dart2js/simple_inferrer_postfix_prefix_test.dart
+++ b/tests/compiler/dart2js/simple_inferrer_postfix_prefix_test.dart
@@ -61,7 +61,7 @@
""";
void main() {
- Uri uri = new Uri.fromComponents(scheme: 'source');
+ Uri uri = new Uri(scheme: 'source');
var compiler = compilerFor(TEST, uri);
compiler.runCompiler(uri);
var typesInferrer = compiler.typesTask.typesInferrer;
diff --git a/tests/compiler/dart2js/simple_inferrer_test.dart b/tests/compiler/dart2js/simple_inferrer_test.dart
index 2c8f602..c9776bb 100644
--- a/tests/compiler/dart2js/simple_inferrer_test.dart
+++ b/tests/compiler/dart2js/simple_inferrer_test.dart
@@ -457,7 +457,7 @@
""";
void main() {
- Uri uri = new Uri.fromComponents(scheme: 'source');
+ Uri uri = new Uri(scheme: 'source');
var compiler = compilerFor(TEST, uri);
compiler.runCompiler(uri);
var typesInferrer = compiler.typesTask.typesInferrer;
diff --git a/tests/compiler/dart2js/simple_inferrer_try_catch_test.dart b/tests/compiler/dart2js/simple_inferrer_try_catch_test.dart
index 2b6ebef..917ffe9 100644
--- a/tests/compiler/dart2js/simple_inferrer_try_catch_test.dart
+++ b/tests/compiler/dart2js/simple_inferrer_try_catch_test.dart
@@ -154,7 +154,7 @@
void main() {
- Uri uri = new Uri.fromComponents(scheme: 'source');
+ Uri uri = new Uri(scheme: 'source');
var compiler = compilerFor(TEST, uri);
compiler.runCompiler(uri);
var typesInferrer = compiler.typesTask.typesInferrer;
diff --git a/tests/compiler/dart2js/simple_inferrer_unregister_call_test.dart b/tests/compiler/dart2js/simple_inferrer_unregister_call_test.dart
index b277c2b..0341df4 100644
--- a/tests/compiler/dart2js/simple_inferrer_unregister_call_test.dart
+++ b/tests/compiler/dart2js/simple_inferrer_unregister_call_test.dart
@@ -30,7 +30,7 @@
void main() {
- Uri uri = new Uri.fromComponents(scheme: 'source');
+ Uri uri = new Uri(scheme: 'source');
var compiler = compilerFor(TEST, uri);
compiler.runCompiler(uri);
var typesInferrer = compiler.typesTask.typesInferrer;
diff --git a/tests/compiler/dart2js/size_test.dart b/tests/compiler/dart2js/size_test.dart
index cfc318c..3d6fd7b 100644
--- a/tests/compiler/dart2js/size_test.dart
+++ b/tests/compiler/dart2js/size_test.dart
@@ -18,6 +18,7 @@
class Function {}
class Type {}
class Map {}
+ class StackTrace {}
identical(a, b) => true;
''';
diff --git a/tests/compiler/dart2js/source_mapping_test.dart b/tests/compiler/dart2js/source_mapping_test.dart
index 6b47737..3cccbbd 100644
--- a/tests/compiler/dart2js/source_mapping_test.dart
+++ b/tests/compiler/dart2js/source_mapping_test.dart
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
import "package:expect/expect.dart";
-import 'dart:uri';
import "../../../sdk/lib/_internal/compiler/implementation/dart2jslib.dart";
import '../../../sdk/lib/_internal/compiler/implementation/source_file.dart';
@@ -12,7 +11,7 @@
CodeBuffer compileAll(SourceFile sourceFile) {
MockCompiler compiler = new MockCompiler();
- Uri uri = new Uri.fromComponents(path: sourceFile.filename);
+ Uri uri = new Uri(path: sourceFile.filename);
compiler.sourceFiles[uri.toString()] = sourceFile;
compiler.runCompiler(uri);
return compiler.backend.emitter.mainBuffer;
diff --git a/tests/compiler/dart2js/type_checker_test.dart b/tests/compiler/dart2js/type_checker_test.dart
index 6b813b0..1a6bc16 100644
--- a/tests/compiler/dart2js/type_checker_test.dart
+++ b/tests/compiler/dart2js/type_checker_test.dart
@@ -31,6 +31,7 @@
testReturn,
testFor,
testWhile,
+ testTry,
testOperators,
testConstructorInvocationArgumentCount,
testConstructorInvocationArgumentTypes,
@@ -107,6 +108,21 @@
analyze("do { int i = 0.5; } while (null);", MessageKind.NOT_ASSIGNABLE);
}
+testTry() {
+ analyze("try {} finally {}");
+ analyze("try {} catch (e) { int i = e;} finally {}");
+ analyze("try {} catch (e, s) { int i = e; StackTrace j = s; } finally {}");
+ analyze("try {} on String catch (e) {} finally {}");
+ analyze("try { int i = ''; } finally {}", MessageKind.NOT_ASSIGNABLE);
+ analyze("try {} finally { int i = ''; }", MessageKind.NOT_ASSIGNABLE);
+ analyze("try {} on String catch (e) { int i = e; } finally {}",
+ MessageKind.NOT_ASSIGNABLE);
+ analyze("try {} catch (e, s) { int i = e; int j = s; } finally {}",
+ MessageKind.NOT_ASSIGNABLE);
+ analyze("try {} on String catch (e, s) { int i = e; int j = s; } finally {}",
+ [MessageKind.NOT_ASSIGNABLE, MessageKind.NOT_ASSIGNABLE]);
+}
+
testOperators() {
// TODO(karlklose): add the DartC tests for operators when we can parse
// classes with operators.
@@ -186,209 +202,224 @@
void testMethodInvocationArgumentCount() {
compiler.parseScript(CLASS_WITH_METHODS);
- final String header = "{ ClassWithMethods c; ";
- analyze("${header}c.untypedNoArgumentMethod(1); }",
- MessageKind.ADDITIONAL_ARGUMENT);
- analyze("${header}c.untypedOneArgumentMethod(); }",
- MessageKind.MISSING_ARGUMENT);
- analyze("${header}c.untypedOneArgumentMethod(1, 1); }",
- MessageKind.ADDITIONAL_ARGUMENT);
- analyze("${header}c.untypedTwoArgumentMethod(); }",
- MessageKind.MISSING_ARGUMENT);
- analyze("${header}c.untypedTwoArgumentMethod(1, 2, 3); }",
- MessageKind.ADDITIONAL_ARGUMENT);
- analyze("${header}c.intNoArgumentMethod(1); }",
- MessageKind.ADDITIONAL_ARGUMENT);
- analyze("${header}c.intOneArgumentMethod(); }",
- MessageKind.MISSING_ARGUMENT);
- analyze("${header}c.intOneArgumentMethod(1, 1); }",
- MessageKind.ADDITIONAL_ARGUMENT);
- analyze("${header}c.intTwoArgumentMethod(); }",
- MessageKind.MISSING_ARGUMENT);
- analyze("${header}c.intTwoArgumentMethod(1, 2, 3); }",
- MessageKind.ADDITIONAL_ARGUMENT);
- // analyze("${header}c.untypedField(); }");
- analyze("${header}c.intOneArgumentOneOptionalMethod(); }",
- [MessageKind.MISSING_ARGUMENT]);
- analyze("${header}c.intOneArgumentOneOptionalMethod(0); }");
- analyze("${header}c.intOneArgumentOneOptionalMethod(0, 1); }");
- analyze("${header}c.intOneArgumentOneOptionalMethod(0, 1, 2); }",
- [MessageKind.ADDITIONAL_ARGUMENT]);
- analyze("${header}c.intOneArgumentOneOptionalMethod(0, 1, c: 2); }",
- [MessageKind.NAMED_ARGUMENT_NOT_FOUND]);
- analyze("${header}c.intOneArgumentOneOptionalMethod(0, b: 1); }",
- [MessageKind.NAMED_ARGUMENT_NOT_FOUND]);
- analyze("${header}c.intOneArgumentOneOptionalMethod(a: 0, b: 1); }",
- [MessageKind.NAMED_ARGUMENT_NOT_FOUND,
- MessageKind.NAMED_ARGUMENT_NOT_FOUND,
- MessageKind.MISSING_ARGUMENT]);
+ check(String text, [expectedWarnings]) {
+ analyze("{ ClassWithMethods c; $text }", expectedWarnings);
+ }
- analyze("${header}c.intTwoOptionalMethod(); }");
- analyze("${header}c.intTwoOptionalMethod(0); }");
- analyze("${header}c.intTwoOptionalMethod(0, 1); }");
- analyze("${header}c.intTwoOptionalMethod(0, 1, 2); }",
- [MessageKind.ADDITIONAL_ARGUMENT]);
- analyze("${header}c.intTwoOptionalMethod(a: 0); }",
- [MessageKind.NAMED_ARGUMENT_NOT_FOUND]);
- analyze("${header}c.intTwoOptionalMethod(0, b: 1); }",
- [MessageKind.NAMED_ARGUMENT_NOT_FOUND]);
+ check("c.untypedNoArgumentMethod(1);", MessageKind.ADDITIONAL_ARGUMENT);
+ check("c.untypedOneArgumentMethod();", MessageKind.MISSING_ARGUMENT);
+ check("c.untypedOneArgumentMethod(1, 1);", MessageKind.ADDITIONAL_ARGUMENT);
+ check("c.untypedTwoArgumentMethod();", MessageKind.MISSING_ARGUMENT);
+ check("c.untypedTwoArgumentMethod(1, 2, 3);",
+ MessageKind.ADDITIONAL_ARGUMENT);
+ check("c.intNoArgumentMethod(1);", MessageKind.ADDITIONAL_ARGUMENT);
+ check("c.intOneArgumentMethod();", MessageKind.MISSING_ARGUMENT);
+ check("c.intOneArgumentMethod(1, 1);", MessageKind.ADDITIONAL_ARGUMENT);
+ check("c.intTwoArgumentMethod();", MessageKind.MISSING_ARGUMENT);
+ check("c.intTwoArgumentMethod(1, 2, 3);", MessageKind.ADDITIONAL_ARGUMENT);
+ // check("c.untypedField();");
- analyze("${header}c.intOneArgumentOneNamedMethod(); }",
- [MessageKind.MISSING_ARGUMENT]);
- analyze("${header}c.intOneArgumentOneNamedMethod(0); }");
- analyze("${header}c.intOneArgumentOneNamedMethod(0, b: 1); }");
- analyze("${header}c.intOneArgumentOneNamedMethod(b: 1); }",
- [MessageKind.MISSING_ARGUMENT]);
- analyze("${header}c.intOneArgumentOneNamedMethod(0, b: 1, c: 2); }",
- [MessageKind.NAMED_ARGUMENT_NOT_FOUND]);
- analyze("${header}c.intOneArgumentOneNamedMethod(0, 1); }",
- [MessageKind.ADDITIONAL_ARGUMENT]);
- analyze("${header}c.intOneArgumentOneNamedMethod(0, 1, c: 2); }",
- [MessageKind.ADDITIONAL_ARGUMENT,
- MessageKind.NAMED_ARGUMENT_NOT_FOUND]);
- analyze("${header}c.intOneArgumentOneNamedMethod(a: 1, b: 1); }",
- [MessageKind.NAMED_ARGUMENT_NOT_FOUND,
- MessageKind.MISSING_ARGUMENT]);
+ check("c.intOneArgumentOneOptionalMethod();", [MessageKind.MISSING_ARGUMENT]);
+ check("c.intOneArgumentOneOptionalMethod(0);");
+ check("c.intOneArgumentOneOptionalMethod(0, 1);");
+ check("c.intOneArgumentOneOptionalMethod(0, 1, 2);",
+ [MessageKind.ADDITIONAL_ARGUMENT]);
+ check("c.intOneArgumentOneOptionalMethod(0, 1, c: 2);",
+ [MessageKind.NAMED_ARGUMENT_NOT_FOUND]);
+ check("c.intOneArgumentOneOptionalMethod(0, b: 1);",
+ [MessageKind.NAMED_ARGUMENT_NOT_FOUND]);
+ check("c.intOneArgumentOneOptionalMethod(a: 0, b: 1);",
+ [MessageKind.NAMED_ARGUMENT_NOT_FOUND,
+ MessageKind.NAMED_ARGUMENT_NOT_FOUND,
+ MessageKind.MISSING_ARGUMENT]);
- analyze("${header}c.intTwoNamedMethod(); }");
- analyze("${header}c.intTwoNamedMethod(a: 0); }");
- analyze("${header}c.intTwoNamedMethod(b: 1); }");
- analyze("${header}c.intTwoNamedMethod(a: 0, b: 1); }");
- analyze("${header}c.intTwoNamedMethod(b: 1, a: 0); }");
- analyze("${header}c.intTwoNamedMethod(0); }",
- [MessageKind.ADDITIONAL_ARGUMENT]);
- analyze("${header}c.intTwoNamedMethod(c: 2); }",
- [MessageKind.NAMED_ARGUMENT_NOT_FOUND]);
- analyze("${header}c.intTwoNamedMethod(a: 0, c: 2); }",
- [MessageKind.NAMED_ARGUMENT_NOT_FOUND]);
- analyze("${header}c.intTwoNamedMethod(a: 0, b: 1, c: 2); }",
- [MessageKind.NAMED_ARGUMENT_NOT_FOUND]);
- analyze("${header}c.intTwoNamedMethod(c: 2, b: 1, a: 0); }",
- [MessageKind.NAMED_ARGUMENT_NOT_FOUND]);
- analyze("${header}c.intTwoNamedMethod(0, b: 1); }",
- [MessageKind.ADDITIONAL_ARGUMENT]);
- analyze("${header}c.intTwoNamedMethod(0, 1); }",
- [MessageKind.ADDITIONAL_ARGUMENT,
- MessageKind.ADDITIONAL_ARGUMENT]);
- analyze("${header}c.intTwoNamedMethod(0, c: 2); }",
- [MessageKind.ADDITIONAL_ARGUMENT,
- MessageKind.NAMED_ARGUMENT_NOT_FOUND]);
+ check("c.intTwoOptionalMethod();");
+ check("c.intTwoOptionalMethod(0);");
+ check("c.intTwoOptionalMethod(0, 1);");
+ check("c.intTwoOptionalMethod(0, 1, 2);", [MessageKind.ADDITIONAL_ARGUMENT]);
+ check("c.intTwoOptionalMethod(a: 0);",
+ [MessageKind.NAMED_ARGUMENT_NOT_FOUND]);
+ check("c.intTwoOptionalMethod(0, b: 1);",
+ [MessageKind.NAMED_ARGUMENT_NOT_FOUND]);
+ check("c.intOneArgumentOneNamedMethod();", [MessageKind.MISSING_ARGUMENT]);
+ check("c.intOneArgumentOneNamedMethod(0);");
+ check("c.intOneArgumentOneNamedMethod(0, b: 1);");
+ check("c.intOneArgumentOneNamedMethod(b: 1);",
+ [MessageKind.MISSING_ARGUMENT]);
+ check("c.intOneArgumentOneNamedMethod(0, b: 1, c: 2);",
+ [MessageKind.NAMED_ARGUMENT_NOT_FOUND]);
+ check("c.intOneArgumentOneNamedMethod(0, 1);",
+ [MessageKind.ADDITIONAL_ARGUMENT]);
+ check("c.intOneArgumentOneNamedMethod(0, 1, c: 2);",
+ [MessageKind.ADDITIONAL_ARGUMENT,
+ MessageKind.NAMED_ARGUMENT_NOT_FOUND]);
+ check("c.intOneArgumentOneNamedMethod(a: 1, b: 1);",
+ [MessageKind.NAMED_ARGUMENT_NOT_FOUND,
+ MessageKind.MISSING_ARGUMENT]);
+
+ check("c.intTwoNamedMethod();");
+ check("c.intTwoNamedMethod(a: 0);");
+ check("c.intTwoNamedMethod(b: 1);");
+ check("c.intTwoNamedMethod(a: 0, b: 1);");
+ check("c.intTwoNamedMethod(b: 1, a: 0);");
+ check("c.intTwoNamedMethod(0);", [MessageKind.ADDITIONAL_ARGUMENT]);
+ check("c.intTwoNamedMethod(c: 2);", [MessageKind.NAMED_ARGUMENT_NOT_FOUND]);
+ check("c.intTwoNamedMethod(a: 0, c: 2);",
+ [MessageKind.NAMED_ARGUMENT_NOT_FOUND]);
+ check("c.intTwoNamedMethod(a: 0, b: 1, c: 2);",
+ [MessageKind.NAMED_ARGUMENT_NOT_FOUND]);
+ check("c.intTwoNamedMethod(c: 2, b: 1, a: 0);",
+ [MessageKind.NAMED_ARGUMENT_NOT_FOUND]);
+ check("c.intTwoNamedMethod(0, b: 1);", [MessageKind.ADDITIONAL_ARGUMENT]);
+ check("c.intTwoNamedMethod(0, 1);",
+ [MessageKind.ADDITIONAL_ARGUMENT,
+ MessageKind.ADDITIONAL_ARGUMENT]);
+ check("c.intTwoNamedMethod(0, c: 2);",
+ [MessageKind.ADDITIONAL_ARGUMENT,
+ MessageKind.NAMED_ARGUMENT_NOT_FOUND]);
}
void testMethodInvocations() {
compiler.parseScript(CLASS_WITH_METHODS);
- final String header = """{
- ClassWithMethods c;
- SubClass d;
- var e;
- int i;
- int j;
- int localMethod(String str) { return 0; }
- """;
- analyze("${header}int k = c.untypedNoArgumentMethod(); }");
- analyze("${header}ClassWithMethods x = c.untypedNoArgumentMethod(); }");
- analyze("${header}ClassWithMethods x = d.untypedNoArgumentMethod(); }");
- analyze("${header}int k = d.intMethod(); }");
- analyze("${header}int k = c.untypedOneArgumentMethod(c); }");
- analyze("${header}ClassWithMethods x = c.untypedOneArgumentMethod(1); }");
- analyze("${header}int k = c.untypedOneArgumentMethod('string'); }");
- analyze("${header}int k = c.untypedOneArgumentMethod(i); }");
- analyze("${header}int k = d.untypedOneArgumentMethod(d); }");
- analyze("${header}ClassWithMethods x = d.untypedOneArgumentMethod(1); }");
- analyze("${header}int k = d.untypedOneArgumentMethod('string'); }");
- analyze("${header}int k = d.untypedOneArgumentMethod(i); }");
+ check(String text, [expectedWarnings]){
+ analyze("""{
+ ClassWithMethods c;
+ SubClass d;
+ var e;
+ int i;
+ int j;
+ int localMethod(String str) { return 0; }
+ $text
+ }
+ """, expectedWarnings);
+ }
- analyze("${header}int k = c.untypedTwoArgumentMethod(1, 'string'); }");
- analyze("${header}int k = c.untypedTwoArgumentMethod(i, j); }");
- analyze("${header}ClassWithMethods x = c.untypedTwoArgumentMethod(i, c); }");
- analyze("${header}int k = d.untypedTwoArgumentMethod(1, 'string'); }");
- analyze("${header}int k = d.untypedTwoArgumentMethod(i, j); }");
- analyze("${header}ClassWithMethods x = d.untypedTwoArgumentMethod(i, d); }");
+ check("int k = c.untypedNoArgumentMethod();");
+ check("ClassWithMethods x = c.untypedNoArgumentMethod();");
+ check("ClassWithMethods x = d.untypedNoArgumentMethod();");
+ check("int k = d.intMethod();");
+ check("int k = c.untypedOneArgumentMethod(c);");
+ check("ClassWithMethods x = c.untypedOneArgumentMethod(1);");
+ check("int k = c.untypedOneArgumentMethod('string');");
+ check("int k = c.untypedOneArgumentMethod(i);");
+ check("int k = d.untypedOneArgumentMethod(d);");
+ check("ClassWithMethods x = d.untypedOneArgumentMethod(1);");
+ check("int k = d.untypedOneArgumentMethod('string');");
+ check("int k = d.untypedOneArgumentMethod(i);");
- analyze("${header}int k = c.intNoArgumentMethod(); }");
- analyze("${header}ClassWithMethods x = c.intNoArgumentMethod(); }",
- MessageKind.NOT_ASSIGNABLE);
+ check("int k = c.untypedTwoArgumentMethod(1, 'string');");
+ check("int k = c.untypedTwoArgumentMethod(i, j);");
+ check("ClassWithMethods x = c.untypedTwoArgumentMethod(i, c);");
+ check("int k = d.untypedTwoArgumentMethod(1, 'string');");
+ check("int k = d.untypedTwoArgumentMethod(i, j);");
+ check("ClassWithMethods x = d.untypedTwoArgumentMethod(i, d);");
- analyze("${header}int k = c.intOneArgumentMethod(c); }",
- MessageKind.NOT_ASSIGNABLE);
- analyze("${header}ClassWithMethods x = c.intOneArgumentMethod(1); }",
- MessageKind.NOT_ASSIGNABLE);
- analyze("${header}int k = c.intOneArgumentMethod('string'); }",
- MessageKind.NOT_ASSIGNABLE);
- analyze("${header}int k = c.intOneArgumentMethod(i); }");
+ check("int k = c.intNoArgumentMethod();");
+ check("ClassWithMethods x = c.intNoArgumentMethod();",
+ MessageKind.NOT_ASSIGNABLE);
- analyze("${header}int k = c.intTwoArgumentMethod(1, 'string'); }",
- MessageKind.NOT_ASSIGNABLE);
- analyze("${header}int k = c.intTwoArgumentMethod(i, j); }");
- analyze("${header}ClassWithMethods x = c.intTwoArgumentMethod(i, j); }",
- MessageKind.NOT_ASSIGNABLE);
+ check("int k = c.intOneArgumentMethod(c);", MessageKind.NOT_ASSIGNABLE);
+ check("ClassWithMethods x = c.intOneArgumentMethod(1);",
+ MessageKind.NOT_ASSIGNABLE);
+ check("int k = c.intOneArgumentMethod('string');",
+ MessageKind.NOT_ASSIGNABLE);
+ check("int k = c.intOneArgumentMethod(i);");
- analyze("${header}c.functionField(); }");
- analyze("${header}d.functionField(); }");
- analyze("${header}c.functionField(1); }");
- analyze("${header}d.functionField('string'); }");
+ check("int k = c.intTwoArgumentMethod(1, 'string');",
+ MessageKind.NOT_ASSIGNABLE);
+ check("int k = c.intTwoArgumentMethod(i, j);");
+ check("ClassWithMethods x = c.intTwoArgumentMethod(i, j);",
+ MessageKind.NOT_ASSIGNABLE);
- analyze("${header}c.intField(); }", MessageKind.NOT_CALLABLE);
- analyze("${header}d.intField(); }", MessageKind.NOT_CALLABLE);
+ check("c.functionField();");
+ check("d.functionField();");
+ check("c.functionField(1);");
+ check("d.functionField('string');");
- analyze("${header}c.untypedField(); }");
- analyze("${header}d.untypedField(); }");
- analyze("${header}c.untypedField(1); }");
- analyze("${header}d.untypedField('string'); }");
+ check("c.intField();", MessageKind.NOT_CALLABLE);
+ check("d.intField();", MessageKind.NOT_CALLABLE);
+
+ check("c.untypedField();");
+ check("d.untypedField();");
+ check("c.untypedField(1);");
+ check("d.untypedField('string');");
+
+
+ check("c.intOneArgumentOneOptionalMethod('');",
+ MessageKind.NOT_ASSIGNABLE);
+ check("c.intOneArgumentOneOptionalMethod('', '');",
+ [MessageKind.NOT_ASSIGNABLE, MessageKind.NOT_ASSIGNABLE]);
+
+ check("c.intTwoOptionalMethod('');", MessageKind.NOT_ASSIGNABLE);
+ check("c.intTwoOptionalMethod('', '');",
+ [MessageKind.NOT_ASSIGNABLE, MessageKind.NOT_ASSIGNABLE]);
+
+ check("c.intOneArgumentOneNamedMethod('');",
+ MessageKind.NOT_ASSIGNABLE);
+ check("c.intOneArgumentOneNamedMethod('', b: '');",
+ [MessageKind.NOT_ASSIGNABLE, MessageKind.NOT_ASSIGNABLE]);
+
+ check("c.intTwoNamedMethod(a: '');", MessageKind.NOT_ASSIGNABLE);
+ check("c.intTwoNamedMethod(b: '');", MessageKind.NOT_ASSIGNABLE);
+ check("c.intTwoNamedMethod(a: '', b: '');",
+ [MessageKind.NOT_ASSIGNABLE, MessageKind.NOT_ASSIGNABLE]);
+ check("c.intTwoNamedMethod(b: '', a: '');",
+ [MessageKind.NOT_ASSIGNABLE, MessageKind.NOT_ASSIGNABLE]);
// Invocation of dynamic variable.
- analyze("${header}e(); }");
- analyze("${header}e(1); }");
- analyze("${header}e('string'); }");
+ check("e();");
+ check("e(1);");
+ check("e('string');");
// Invocation on local method.
- analyze("${header}localMethod(); }", MessageKind.MISSING_ARGUMENT);
- analyze("${header}localMethod(1); }", MessageKind.NOT_ASSIGNABLE);
- analyze("${header}localMethod('string'); }");
- analyze("${header}int k = localMethod('string'); }");
- analyze("${header}String k = localMethod('string'); }",
- MessageKind.NOT_ASSIGNABLE);
+ check("localMethod();", MessageKind.MISSING_ARGUMENT);
+ check("localMethod(1);", MessageKind.NOT_ASSIGNABLE);
+ check("localMethod('string');");
+ check("int k = localMethod('string');");
+ check("String k = localMethod('string');", MessageKind.NOT_ASSIGNABLE);
// Invocation on parenthesized expressions.
- analyze("${header}(e)(); }");
- analyze("${header}(e)(1); }");
- analyze("${header}(e)('string'); }");
- analyze("${header}(foo)(); }");
- analyze("${header}(foo)(1); }");
- analyze("${header}(foo)('string'); }");
+ check("(e)();");
+ check("(e)(1);");
+ check("(e)('string');");
+ check("(foo)();");
+ check("(foo)(1);");
+ check("(foo)('string');");
// Invocations on function expressions.
- analyze("${header}(foo){}(); }", MessageKind.MISSING_ARGUMENT);
- analyze("${header}(foo){}(1); }");
- analyze("${header}(foo){}('string'); }");
- analyze("${header}(int foo){}('string'); }", MessageKind.NOT_ASSIGNABLE);
- analyze("${header}(String foo){}('string'); }");
- analyze("${header}int k = int bar(String foo){ return 0; }('string'); }");
- analyze("${header}int k = String bar(String foo){ return foo; }('string'); }",
- MessageKind.NOT_ASSIGNABLE);
+ check("(foo){}();", MessageKind.MISSING_ARGUMENT);
+ check("(foo){}(1);");
+ check("(foo){}('string');");
+ check("(int foo){}('string');", MessageKind.NOT_ASSIGNABLE);
+ check("(String foo){}('string');");
+ check("int k = int bar(String foo){ return 0; }('string');");
+ check("int k = String bar(String foo){ return foo; }('string');",
+ MessageKind.NOT_ASSIGNABLE);
// Static invocations.
- analyze("${header}ClassWithMethods.staticMethod(); }",
- MessageKind.MISSING_ARGUMENT);
- analyze("${header}ClassWithMethods.staticMethod(1); }",
- MessageKind.NOT_ASSIGNABLE);
- analyze("${header}ClassWithMethods.staticMethod('string'); }");
- analyze("${header}int k = ClassWithMethods.staticMethod('string'); }");
- analyze("${header}String k = ClassWithMethods.staticMethod('string'); }",
- MessageKind.NOT_ASSIGNABLE);
+ check("ClassWithMethods.staticMethod();",
+ MessageKind.MISSING_ARGUMENT);
+ check("ClassWithMethods.staticMethod(1);",
+ MessageKind.NOT_ASSIGNABLE);
+ check("ClassWithMethods.staticMethod('string');");
+ check("int k = ClassWithMethods.staticMethod('string');");
+ check("String k = ClassWithMethods.staticMethod('string');",
+ MessageKind.NOT_ASSIGNABLE);
// Invocation on dynamic variable.
- analyze("${header}e.foo(); }");
- analyze("${header}e.foo(1); }");
- analyze("${header}e.foo('string'); }");
+ check("e.foo();");
+ check("e.foo(1);");
+ check("e.foo('string');");
// Invocation on unresolved variable.
- analyze("${header}foo(); }");
- analyze("${header}foo(1); }");
- analyze("${header}foo('string'); }");
+ check("foo();");
+ check("foo(1);");
+ check("foo('string');");
+ check("foo(a: 'string');");
+ check("foo(a: localMethod(1));", MessageKind.NOT_ASSIGNABLE);
// TODO(johnniwinther): Add tests of invocations using implicit this.
}
diff --git a/tests/compiler/dart2js/type_equals_test.dart b/tests/compiler/dart2js/type_equals_test.dart
index adf43c0..0c283db 100644
--- a/tests/compiler/dart2js/type_equals_test.dart
+++ b/tests/compiler/dart2js/type_equals_test.dart
@@ -50,7 +50,7 @@
}
void main() {
- var uri = new Uri.fromComponents(scheme: 'source');
+ var uri = new Uri(scheme: 'source');
var compiler = compilerFor(
r"""
typedef int Typedef1<X,Y>(String s1);
diff --git a/tests/compiler/dart2js/type_test_helper.dart b/tests/compiler/dart2js/type_test_helper.dart
index 7f1eaa22..db1a43f 100644
--- a/tests/compiler/dart2js/type_test_helper.dart
+++ b/tests/compiler/dart2js/type_test_helper.dart
@@ -23,7 +23,7 @@
final MockCompiler compiler;
factory TypeEnvironment(String source) {
- var uri = new Uri.fromComponents(scheme: 'source');
+ var uri = new Uri(scheme: 'source');
MockCompiler compiler = compilerFor('''
main() {}
$source''',
diff --git a/tests/compiler/dart2js/type_variable_bound_test.dart b/tests/compiler/dart2js/type_variable_bound_test.dart
index 6dd38a8..01761c4 100644
--- a/tests/compiler/dart2js/type_variable_bound_test.dart
+++ b/tests/compiler/dart2js/type_variable_bound_test.dart
@@ -6,7 +6,7 @@
import "package:expect/expect.dart";
compile(String source) {
- Uri uri = new Uri('test:code');
+ Uri uri = Uri.parse('test:code');
var compiler = compilerFor(source, uri);
compiler.runCompiler(uri);
return compiler;
diff --git a/tests/compiler/dart2js/unparser_test.dart b/tests/compiler/dart2js/unparser_test.dart
index 936b60e..d470b3f 100644
--- a/tests/compiler/dart2js/unparser_test.dart
+++ b/tests/compiler/dart2js/unparser_test.dart
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
import "package:expect/expect.dart";
-import 'dart:uri';
import 'parser_helper.dart';
import 'mock_compiler.dart';
import '../../../sdk/lib/_internal/compiler/implementation/tree/tree.dart';
diff --git a/tests/compiler/dart2js/uri_extras_test.dart b/tests/compiler/dart2js/uri_extras_test.dart
index 0d224bc0..7045384 100644
--- a/tests/compiler/dart2js/uri_extras_test.dart
+++ b/tests/compiler/dart2js/uri_extras_test.dart
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
import "package:expect/expect.dart";
-import 'dart:uri';
import '../../../sdk/lib/_internal/compiler/implementation/util/uri_extras.dart';
diff --git a/tests/compiler/dart2js/value_range_test.dart b/tests/compiler/dart2js/value_range_test.dart
index f623ced..474d2a1 100644
--- a/tests/compiler/dart2js/value_range_test.dart
+++ b/tests/compiler/dart2js/value_range_test.dart
@@ -219,6 +219,7 @@
class Closure {}
class Null {}
class Dynamic_ {}
+ class StackTrace {}
bool identical(Object a, Object b) {}''';
const String INTERCEPTORSLIB_WITH_MEMBERS = r'''
diff --git a/tests/corelib/collection_length_test.dart b/tests/corelib/collection_length_test.dart
index 01a8061..3259ab2 100644
--- a/tests/corelib/collection_length_test.dart
+++ b/tests/corelib/collection_length_test.dart
@@ -52,12 +52,13 @@
void testLength(var lengthable, int size) {
print(lengthable.runtimeType); // Show what hangs the test.
int length = 0;
- // If length or isEmpty is not a constant-time (or very fast) operation,
- // this will timeout.
+ // If length, isEmpty or isNotEmpty is not a constant-time (or very fast)
+ // operation, this will timeout.
for (int i = 0; i < 100000; i++) {
if (!lengthable.isEmpty) length += lengthable.length;
+ if (lengthable.isNotEmpty) length += lengthable.length;
}
- if (length != size * 100000) throw "Bad length: $length / size: $size";
+ if (length != size * 200000) throw "Bad length: $length / size: $size";
}
diff --git a/tests/corelib/core_runtime_types_test.dart b/tests/corelib/core_runtime_types_test.dart
index a86b800..ee91954 100644
--- a/tests/corelib/core_runtime_types_test.dart
+++ b/tests/corelib/core_runtime_types_test.dart
@@ -167,6 +167,7 @@
static testStringMethods() {
var s = "abcdef";
assertEquals(s.isEmpty, false);
+ assertEquals(s.isNotEmpty, true);
assertEquals(s.startsWith("abc"), true);
assertEquals(s.endsWith("def"), true);
assertEquals(s.startsWith("aa"), false);
diff --git a/tests/corelib/corelib.status b/tests/corelib/corelib.status
index 3d21fe2..7e3010d 100644
--- a/tests/corelib/corelib.status
+++ b/tests/corelib/corelib.status
@@ -97,9 +97,6 @@
list_insert_test: fail
list_removeat_test: fail
-[ $arch == arm ]
-*: Skip
-
[ $arch == simarm ]
*: Skip
diff --git a/tests/corelib/list_test.dart b/tests/corelib/list_test.dart
index 28629a9..395cc57 100644
--- a/tests/corelib/list_test.dart
+++ b/tests/corelib/list_test.dart
@@ -49,6 +49,7 @@
void testLength(int length, List list) {
Expect.equals(length, list.length);
(length == 0 ? Expect.isTrue : Expect.isFalse)(list.isEmpty);
+ (length != 0 ? Expect.isTrue : Expect.isFalse)(list.isNotEmpty);
}
void testTypedLengthInvariantOperations(List list) {
diff --git a/tests/corelib/map_test.dart b/tests/corelib/map_test.dart
index a5bbbda7f..05afcf6 100644
--- a/tests/corelib/map_test.dart
+++ b/tests/corelib/map_test.dart
@@ -47,7 +47,7 @@
Expect.equals(false, map.containsKey(1));
map[1] = 1;
map[1] = 2;
- Expect.equals(1, map.length);
+ testLength(1, map);
}
void testMap(Map map, key1, key2, key3, key4, key5, key6, key7, key8) {
@@ -60,20 +60,20 @@
int value7 = 70;
int value8 = 80;
- Expect.equals(0, map.length);
+ testLength(0, map);
map[key1] = value1;
Expect.equals(value1, map[key1]);
map[key1] = value2;
Expect.equals(false, map.containsKey(key2));
- Expect.equals(1, map.length);
+ testLength(1, map);
map[key1] = value1;
Expect.equals(value1, map[key1]);
// Add enough entries to make sure the table grows.
map[key2] = value2;
Expect.equals(value2, map[key2]);
- Expect.equals(2, map.length);
+ testLength(2, map);
map[key3] = value3;
Expect.equals(value2, map[key2]);
Expect.equals(value3, map[key3]);
@@ -98,15 +98,15 @@
Expect.equals(value6, map[key6]);
Expect.equals(value7, map[key7]);
Expect.equals(value8, map[key8]);
- Expect.equals(8, map.length);
+ testLength(8, map);
map.remove(key4);
Expect.equals(false, map.containsKey(key4));
- Expect.equals(7, map.length);
+ testLength(7, map);
// Test clearing the table.
map.clear();
- Expect.equals(0, map.length);
+ testLength(0, map);
Expect.equals(false, map.containsKey(key1));
Expect.equals(false, map.containsKey(key2));
Expect.equals(false, map.containsKey(key3));
@@ -119,34 +119,34 @@
// Test adding and removing again.
map[key1] = value1;
Expect.equals(value1, map[key1]);
- Expect.equals(1, map.length);
+ testLength(1, map);
map[key2] = value2;
Expect.equals(value2, map[key2]);
- Expect.equals(2, map.length);
+ testLength(2, map);
map[key3] = value3;
Expect.equals(value3, map[key3]);
map.remove(key3);
- Expect.equals(2, map.length);
+ testLength(2, map);
map[key4] = value4;
Expect.equals(value4, map[key4]);
map.remove(key4);
- Expect.equals(2, map.length);
+ testLength(2, map);
map[key5] = value5;
Expect.equals(value5, map[key5]);
map.remove(key5);
- Expect.equals(2, map.length);
+ testLength(2, map);
map[key6] = value6;
Expect.equals(value6, map[key6]);
map.remove(key6);
- Expect.equals(2, map.length);
+ testLength(2, map);
map[key7] = value7;
Expect.equals(value7, map[key7]);
map.remove(key7);
- Expect.equals(2, map.length);
+ testLength(2, map);
map[key8] = value8;
Expect.equals(value8, map[key8]);
map.remove(key8);
- Expect.equals(2, map.length);
+ testLength(2, map);
Expect.equals(true, map.containsKey(key1));
Expect.equals(true, map.containsValue(value1));
@@ -213,11 +213,11 @@
map.clear();
for (int i = 0; i < 100; i++) {
map[1] = 2;
- Expect.equals(1, map.length);
+ testLength(1, map);
map.remove(1);
- Expect.equals(0, map.length);
+ testLength(0, map);
}
- Expect.equals(0, map.length);
+ testLength(0, map);
}
void testMapLiteral() {
@@ -347,15 +347,15 @@
map[nan] = 'value:0';
Expect.isFalse(map.containsKey(nan));
Expect.equals(null, map[nan]);
- Expect.equals(1, map.length);
+ testLength(1, map);
map[nan] = 'value:1';
Expect.isFalse(map.containsKey(nan));
Expect.equals(null, map[nan]);
- Expect.equals(2, map.length);
+ testLength(2, map);
Expect.equals(null, map.remove(nan));
- Expect.equals(2, map.length);
+ testLength(2, map);
var count = 0;
map.forEach((key, value) {
@@ -366,3 +366,9 @@
map.clear();
Expect.isTrue(map.isEmpty);
}
+
+void testLength(int length, Map map) {
+ Expect.equals(length, map.length);
+ (length == 0 ? Expect.isTrue : Expect.isFalse)(map.isEmpty);
+ (length != 0 ? Expect.isTrue : Expect.isFalse)(map.isNotEmpty);
+}
diff --git a/tests/corelib/queue_test.dart b/tests/corelib/queue_test.dart
index 6e5a0d77..3cf139f 100644
--- a/tests/corelib/queue_test.dart
+++ b/tests/corelib/queue_test.dart
@@ -124,7 +124,7 @@
}
void checkQueue(Queue queue, int expectedSize, int expectedSum) {
- Expect.equals(expectedSize, queue.length);
+ testLength(expectedSize, queue);
int sum = 0;
void sumElements(int value) {
sum += value;
@@ -136,6 +136,7 @@
testLength(int length, Queue queue) {
Expect.equals(length, queue.length);
((length == 0) ? Expect.isTrue : Expect.isFalse)(queue.isEmpty);
+ ((length != 0) ? Expect.isTrue : Expect.isFalse)(queue.isNotEmpty);
}
void testAddAll() {
diff --git a/tests/corelib/set_test.dart b/tests/corelib/set_test.dart
index 5acb8a5..f085835 100644
--- a/tests/corelib/set_test.dart
+++ b/tests/corelib/set_test.dart
@@ -10,29 +10,29 @@
void testMain(Set create()) {
Set set = create();
- Expect.equals(0, set.length);
+ testLength(0, set);
set.add(1);
- Expect.equals(1, set.length);
+ testLength(1, set);
Expect.isTrue(set.contains(1));
set.add(1);
- Expect.equals(1, set.length);
+ testLength(1, set);
Expect.isTrue(set.contains(1));
set.remove(1);
- Expect.equals(0, set.length);
+ testLength(0, set);
Expect.isFalse(set.contains(1));
for (int i = 0; i < 10; i++) {
set.add(i);
}
- Expect.equals(10, set.length);
+ testLength(10, set);
for (int i = 0; i < 10; i++) {
Expect.isTrue(set.contains(i));
}
- Expect.equals(10, set.length);
+ testLength(10, set);
for (int i = 10; i < 20; i++) {
Expect.isFalse(set.contains(i));
@@ -160,14 +160,14 @@
list[i] = i + 10;
}
set.addAll(list);
- Expect.equals(20, set.length);
+ testLength(20, set);
for (int i = 0; i < 20; i++) {
Expect.isTrue(set.contains(i));
}
// Test Set.removeAll
set.removeAll(list);
- Expect.equals(10, set.length);
+ testLength(10, set);
for (int i = 0; i < 10; i++) {
Expect.isTrue(set.contains(i));
}
@@ -177,9 +177,15 @@
// Test Set.clear.
set.clear();
- Expect.equals(0, set.length);
+ testLength(0, set);
set.add(11);
- Expect.equals(1, set.length);
+ testLength(1, set);
+}
+
+void testLength(int length, Set set) {
+ Expect.equals(length, set.length);
+ (length == 0 ? Expect.isTrue : Expect.isFalse)(set.isEmpty);
+ (length != 0 ? Expect.isTrue : Expect.isFalse)(set.isNotEmpty);
}
main() {
diff --git a/tests/corelib/string_buffer_test.dart b/tests/corelib/string_buffer_test.dart
index 093c7ad..2c556f7 100644
--- a/tests/corelib/string_buffer_test.dart
+++ b/tests/corelib/string_buffer_test.dart
@@ -8,10 +8,10 @@
void testConstructor() {
StringBuffer bf = new StringBuffer("");
- Expect.equals(true, bf.isEmpty);
+ testBufferLength(0, bf);
bf = new StringBuffer("abc");
- Expect.equals(3, bf.length);
+ testBufferLength(3, bf);
Expect.equals("abc", bf.toString());
bf = new StringBuffer("\x00");
@@ -22,7 +22,7 @@
Expect.equals(true, bf.isEmpty);
bf.write("a");
- Expect.equals(1, bf.length);
+ testBufferLength(1, bf);
Expect.equals("a", bf.toString());
bf = new StringBuffer("");
@@ -70,13 +70,13 @@
void testLength() {
StringBuffer bf = new StringBuffer("");
- Expect.equals(0, bf.length);
+ testBufferLength(0, bf);
bf.write("foo");
- Expect.equals(3, bf.length);
+ testBufferLength(3, bf);
bf.write("bar");
- Expect.equals(6, bf.length);
+ testBufferLength(6, bf);
bf.write("");
- Expect.equals(6, bf.length);
+ testBufferLength(6, bf);
}
void testIsEmpty() {
@@ -103,14 +103,14 @@
bf.write("foo");
bf.clear();
Expect.equals("", bf.toString());
- Expect.equals(0, bf.length);
+ testBufferLength(0, bf);
bf.write("bar");
Expect.equals("bar", bf.toString());
- Expect.equals(3, bf.length);
+ testBufferLength(3, bf);
bf.clear();
Expect.equals("", bf.toString());
- Expect.equals(0, bf.length);
+ testBufferLength(0, bf);
}
void testToString() {
@@ -172,6 +172,12 @@
Expect.throws(() { bf2.writeCharCode(0x110000); });
}
+void testBufferLength(int length, StringBuffer bf) {
+ Expect.equals(length, bf.length);
+ (length == 0 ? Expect.isTrue : Expect.isFalse)(bf.isEmpty);
+ (length != 0 ? Expect.isTrue : Expect.isFalse)(bf.isNotEmpty);
+}
+
void main() {
testToString();
testConstructor();
diff --git a/tests/corelib/string_test.dart b/tests/corelib/string_test.dart
index fd73fea..dbcd630 100644
--- a/tests/corelib/string_test.dart
+++ b/tests/corelib/string_test.dart
@@ -24,6 +24,14 @@
testCharCodes();
}
+ static void testLength() {
+ String str = "";
+ for (var i = 0; i < 20; i++) {
+ testStringLength(i, str);
+ str += " ";
+ }
+ }
+
static void testOutOfRange() {
String a = "Hello";
bool exception_caught = false;
@@ -53,7 +61,7 @@
String str = "string";
for (int i = 0; i < str.length; i++) {
Expect.equals(true, str[i] is String);
- Expect.equals(1, str[i].length);
+ testStringLength(1, str[i]);
}
}
@@ -68,7 +76,7 @@
var a = "One";
var b = "Four";
var c = a + b;
- Expect.equals(7, c.length);
+ testStringLength(7, c);
Expect.equals("OneFour", c);
}
@@ -286,6 +294,12 @@
}
}
+void testStringLength(int length, String str) {
+ Expect.equals(length, str.length);
+ (length == 0 ? Expect.isTrue : Expect.isFalse)(str.isEmpty);
+ (length != 0 ? Expect.isTrue : Expect.isFalse)(str.isNotEmpty);
+}
+
main() {
StringTest.testMain();
}
diff --git a/tests/corelib/uri_ipv6_test.dart b/tests/corelib/uri_ipv6_test.dart
new file mode 100644
index 0000000..1ec9d57
--- /dev/null
+++ b/tests/corelib/uri_ipv6_test.dart
@@ -0,0 +1,113 @@
+// 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';
+
+
+void testValidIpv6Uri() {
+ var path = 'http://[::1]:1234/path?query=5#now';
+ var uri = Uri.parse(path);
+ Expect.equals('http', uri.scheme);
+ Expect.equals('::1', uri.host);
+ Expect.equals(1234, uri.port);
+ Expect.equals('/path', uri.path);
+ Expect.equals('query=5', uri.query);
+ Expect.equals('now', uri.fragment);
+ Expect.equals(path, uri.toString());
+
+ path = 'http://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:8080/index.html';
+ uri = Uri.parse(path);
+ Expect.equals('http', uri.scheme);
+ Expect.equals('FEDC:BA98:7654:3210:FEDC:BA98:7654:3210', uri.host);
+ Expect.equals(8080, uri.port);
+ Expect.equals('/index.html', uri.path);
+ Expect.equals(path, uri.toString());
+
+ path = 'http://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:80/index.html';
+ uri = Uri.parse(path);
+ Expect.equals('http', uri.scheme);
+ Expect.equals('FEDC:BA98:7654:3210:FEDC:BA98:7654:3210', uri.host);
+ Expect.equals(0, uri.port);
+ Expect.equals('/index.html', uri.path);
+ Expect.equals('http://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]/index.html',
+ uri.toString());
+
+ path = 'https://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:443/index.html';
+ uri = Uri.parse(path);
+ Expect.equals('https', uri.scheme);
+ Expect.equals('FEDC:BA98:7654:3210:FEDC:BA98:7654:3210', uri.host);
+ Expect.equals(0, uri.port);
+ Expect.equals('/index.html', uri.path);
+ Expect.equals('https://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]/index.html',
+ uri.toString());
+
+ path = 'http://[1080:0:0:0:8:800:200C:417A]/index.html';
+ uri = Uri.parse(path);
+ Expect.equals('http', uri.scheme);
+ Expect.equals('1080:0:0:0:8:800:200C:417A', uri.host);
+ Expect.equals(0, uri.port);
+ Expect.equals('/index.html', uri.path);
+ Expect.equals(path, uri.toString());
+
+ path = 'http://[3ffe:2a00:100:7031::1]';
+ uri = Uri.parse(path);
+ Expect.equals('http', uri.scheme);
+ Expect.equals('3ffe:2a00:100:7031::1', uri.host);
+ Expect.equals(0, uri.port);
+ Expect.equals('', uri.path);
+ Expect.equals(path, uri.toString());
+
+ path = 'http://[1080::8:800:200C:417A]/foo';
+ uri = Uri.parse(path);
+ Expect.equals('http', uri.scheme);
+ Expect.equals('1080::8:800:200C:417A', uri.host);
+ Expect.equals(0, uri.port);
+ Expect.equals('/foo', uri.path);
+ Expect.equals(path, uri.toString());
+
+ path = 'http://[::192.9.5.5]/ipng';
+ uri = Uri.parse(path);
+ Expect.equals('http', uri.scheme);
+ Expect.equals('::192.9.5.5', uri.host);
+ Expect.equals(0, uri.port);
+ Expect.equals('/ipng', uri.path);
+ Expect.equals(path, uri.toString());
+
+ path = 'http://[::FFFF:129.144.52.38]:8080/index.html';
+ uri = Uri.parse(path);
+ Expect.equals('http', uri.scheme);
+ Expect.equals('::FFFF:129.144.52.38', uri.host);
+ Expect.equals(8080, uri.port);
+ Expect.equals('/index.html', uri.path);
+ Expect.equals(path, uri.toString());
+
+ path = 'http://[::FFFF:129.144.52.38]:80/index.html';
+ uri = Uri.parse(path);
+ Expect.equals('http', uri.scheme);
+ Expect.equals('::FFFF:129.144.52.38', uri.host);
+ Expect.equals(0, uri.port);
+ Expect.equals('/index.html', uri.path);
+ Expect.equals('http://[::FFFF:129.144.52.38]/index.html', uri.toString());
+
+ path = 'https://[::FFFF:129.144.52.38]:443/index.html';
+ uri = Uri.parse(path);
+ Expect.equals('https', uri.scheme);
+ Expect.equals('::FFFF:129.144.52.38', uri.host);
+ Expect.equals(0, uri.port);
+ Expect.equals('/index.html', uri.path);
+ Expect.equals('https://[::FFFF:129.144.52.38]/index.html', uri.toString());
+
+ path = 'http://[2010:836B:4179::836B:4179]';
+ uri = Uri.parse(path);
+ Expect.equals('http', uri.scheme);
+ Expect.equals('2010:836B:4179::836B:4179', uri.host);
+ Expect.equals(0, uri.port);
+ Expect.equals('', uri.path);
+ Expect.equals(path, uri.toString());
+}
+
+void main() {
+ testValidIpv6Uri();
+}
+
diff --git a/tests/corelib/uri_normalize_test.dart b/tests/corelib/uri_normalize_test.dart
new file mode 100644
index 0000000..91bbe10
--- /dev/null
+++ b/tests/corelib/uri_normalize_test.dart
@@ -0,0 +1,42 @@
+// 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:expect/expect.dart";
+
+testNormalizePath() {
+ test(String expected, String path) {
+ var uri = new Uri(path: path);
+ Expect.equals(expected, uri.path);
+ Expect.equals(expected, uri.toString());
+ }
+
+ var unreserved = "-._~0123456789"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz";
+
+ test("A", "%41");
+ test("AB", "%41%42");
+ test("%40AB", "%40%41%42");
+ test("a", "%61");
+ test("ab", "%61%62");
+ test("%60ab", "%60%61%62");
+ test(unreserved, unreserved);
+
+ var x = new StringBuffer();
+ for (int i = 32; i < 128; i++) {
+ if (unreserved.indexOf(new String.fromCharCode(i)) != -1) {
+ x.writeCharCode(i);
+ } else {
+ x.write("%");
+ x.write(i.toRadixString(16));
+ }
+ }
+ print(x.toString().toUpperCase());
+ Expect.equals(x.toString().toUpperCase(),
+ new Uri(path: x.toString()).toString().toUpperCase());
+}
+
+main() {
+ testNormalizePath();
+}
diff --git a/tests/corelib/uri_path_test.dart b/tests/corelib/uri_path_test.dart
new file mode 100644
index 0000000..bc62d3e
--- /dev/null
+++ b/tests/corelib/uri_path_test.dart
@@ -0,0 +1,83 @@
+// 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:expect/expect.dart";
+
+void testInvalidArguments() {
+}
+
+void testPath() {
+ test(s, uri) {
+ Expect.equals(s, uri.toString());
+ Expect.equals(uri, Uri.parse(s));
+ }
+
+ test("urn:", new Uri(scheme: "urn"));
+ test("urn:xxx", new Uri(scheme: "urn", path: "xxx"));
+ test("urn:xxx:yyy", new Uri(scheme: "urn", path: "xxx:yyy"));
+}
+
+void testPathSegments() {
+ test(String path, List<String> segments) {
+ void check(uri) {
+ Expect.equals(path, uri.path);
+ Expect.equals(path, uri.toString());
+ Expect.listEquals(segments, uri.pathSegments);
+ }
+
+ var uri1 = new Uri(pathSegments: segments);
+ var uri2 = new Uri(path: path);
+ var uri3 = Uri.parse(path);
+ check(uri1);
+ check(uri2);
+ check(uri3);
+ Expect.equals(uri1, uri3);
+ Expect.equals(uri2, uri3);
+ }
+
+ test("", []);
+ test("%20", [" "]);
+ test("%20/%20%20", [" ", " "]);
+ test("A", ["A"]);
+ test("%C3%B8", ["ø"]);
+ test("%C3%B8/%C3%A5", ["ø", "å"]);
+ test("%C8%A4/%E5%B9%B3%E4%BB%AE%E5%90%8D", ["Ȥ", "平仮名"]);
+ test("A/b", ["A", "b"]);
+ test("A/%25", ["A", "%"]);
+ test("%2F/a%2Fb", ["/", "a/b"]);
+ test("name;v=1.1", ["name;v=1.1"]);
+ test("name,v=1.1", ["name,v=1.1"]);
+ test("name;v=1.1/name,v=1.1", ["name;v=1.1", "name,v=1.1"]);
+
+ var unreserved = "-._~0123456789"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz";
+ var subDelimiters = r"!$&'()*+,;=";
+ var additionalPathChars = ":@";
+ var pchar = unreserved + subDelimiters + additionalPathChars;
+
+ var encoded = new StringBuffer();
+ var unencoded = new StringBuffer();
+ for (int i = 32; i < 128; i++) {
+ if (pchar.indexOf(new String.fromCharCode(i)) != -1) {
+ encoded.writeCharCode(i);
+ } else {
+ encoded.write("%");
+ encoded.write(i.toRadixString(16).toUpperCase());
+ }
+ unencoded.writeCharCode(i);
+ }
+ encoded = encoded.toString();
+ unencoded = unencoded.toString();
+ print(encoded);
+ print(unencoded);
+ test(encoded, [unencoded]);
+ test(encoded + "/" + encoded, [unencoded, unencoded]);
+}
+
+main() {
+ testInvalidArguments();
+ testPath();
+ testPathSegments();
+}
diff --git a/tests/corelib/uri_query_test.dart b/tests/corelib/uri_query_test.dart
new file mode 100644
index 0000000..acbe9d8
--- /dev/null
+++ b/tests/corelib/uri_query_test.dart
@@ -0,0 +1,121 @@
+// 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:expect/expect.dart";
+
+void testInvalidArguments() {
+}
+
+void testEncodeQueryComponent() {
+ // This exact data is from posting a form in Chrome 26 with the one
+ // exception that * is encoded as %30 and ~ is not encoded as %7E.
+ Expect.equals(
+ "%21%22%23%24%25%26%27%28%29%2A%2B%2C-.%2F%"
+ "3A%3B%3C%3D%3E%3F%40%5B%5C%5D%5E_%60%7B%7C%7D~",
+ Uri.encodeQueryComponent("!\"#\$%&'()*+,-./:;<=>?@[\\]^_`{|}~"));
+ Expect.equals("+%2B+", Uri.encodeQueryComponent(" + "));
+ Expect.equals("%2B+%2B", Uri.encodeQueryComponent("+ +"));
+}
+
+void testQueryParameters() {
+ test(String query, Map<String, String> parameters) {
+ check(uri) {
+ Expect.equals(query, uri.query);
+ if (query.isEmpty) {
+ Expect.equals(query, uri.toString());
+ } else {
+ Expect.equals("?$query", uri.toString());
+ }
+ if (parameters.containsValue(null)) {
+ } else {
+ Expect.mapEquals(parameters, uri.queryParameters);
+ }
+ }
+
+ var uri1 = new Uri(queryParameters: parameters);
+ var uri2 = new Uri(query: query);
+ var uri3 = Uri.parse("?$query");
+ check(uri1);
+ check(uri2);
+ check(uri3);
+ Expect.equals(uri1, uri3);
+ Expect.equals(uri2, uri3);
+ }
+
+ test("", {});
+ test("A", {"A": null});
+ test("A", {"A": ""});
+ test("A=a", {"A": "a"});
+ test("A=+", {"A": " "});
+ test("A=%2B", {"A": "+"});
+ test("A=a&B", {"A": "a", "B": null});
+ test("A=a&B", {"A": "a", "B": ""});
+ test("A=a&B=b", {"A": "a", "B": "b"});
+
+ var unreserved = "-._~0123456789"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz";
+ var encoded = new StringBuffer();
+ var unencoded = new StringBuffer();
+ for (int i = 32; i < 128; i++) {
+ if (i == 32) {
+ encoded.write("+");
+ } else if (unreserved.indexOf(new String.fromCharCode(i)) != -1) {
+ encoded.writeCharCode(i);
+ } else {
+ encoded.write("%");
+ encoded.write(i.toRadixString(16).toUpperCase());
+ }
+ unencoded.writeCharCode(i);
+ }
+ encoded = encoded.toString();
+ unencoded = unencoded.toString();
+ print(encoded);
+ print(unencoded);
+ test("a=$encoded", {"a": unencoded});
+ test("a=$encoded&b=$encoded", {"a": unencoded, "b": unencoded});
+
+ var map = new Map();
+ map[unencoded] = unencoded;
+ test("$encoded=$encoded", map);
+}
+
+testInvalidQueryParameters() {
+ test(String query, Map<String, String> parameters) {
+ check(uri) {
+ Expect.equals(query, uri.query);
+ if (query.isEmpty) {
+ Expect.equals(query, uri.toString());
+ } else {
+ Expect.equals("?$query", uri.toString());
+ }
+ if (parameters.containsValue(null)) {
+ } else {
+ Expect.mapEquals(parameters, uri.queryParameters);
+ }
+ }
+
+ var uri1 = new Uri(query: query);
+ var uri2 = Uri.parse("?$query");
+ check(uri1);
+ check(uri2);
+ Expect.equals(uri1, uri2);
+ }
+
+ test("=", {});
+ test("=xxx", {});
+ test("===", {});
+ test("=xxx=yyy=zzz", {});
+ test("=&=&=", {});
+ test("=xxx&=yyy&=zzz", {});
+ test("&=&=&", {});
+ test("&=xxx&=xxx&", {});
+}
+
+main() {
+ testInvalidArguments();
+ testEncodeQueryComponent();
+ testQueryParameters();
+ testInvalidQueryParameters();
+}
diff --git a/tests/corelib/uri_scheme_test.dart b/tests/corelib/uri_scheme_test.dart
new file mode 100644
index 0000000..2a7fd76
--- /dev/null
+++ b/tests/corelib/uri_scheme_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 "package:expect/expect.dart";
+
+void testInvalidArguments() {
+ Expect.throws(() => new Uri(scheme: "_"), (e) => e is ArgumentError);
+ Expect.throws(() => new Uri(scheme: "http_s"), (e) => e is ArgumentError);
+}
+
+void testScheme() {
+ test(String expectedScheme, String expectedUri, String scheme) {
+ var uri = new Uri(scheme: scheme);
+ Expect.equals(expectedScheme, uri.scheme);
+ Expect.equals(expectedUri, uri.toString());
+ }
+
+ test("http", "http:", "http");
+ test("http", "http:", "HTTP");
+ test("http+ssl", "http+ssl:", "HTTP+ssl");
+ test("urn", "urn:", "urn");
+ test("urn", "urn:", "UrN");
+}
+
+main() {
+ testInvalidArguments();
+ testScheme();
+}
diff --git a/tests/utils/uri_test.dart b/tests/corelib/uri_test.dart
similarity index 74%
rename from tests/utils/uri_test.dart
rename to tests/corelib/uri_test.dart
index 3653d2a..0d671b7 100644
--- a/tests/utils/uri_test.dart
+++ b/tests/corelib/uri_test.dart
@@ -6,30 +6,34 @@
import "package:expect/expect.dart";
import 'dart:utf';
-import 'dart:uri';
testUri(String uri, bool isAbsolute) {
Expect.equals(isAbsolute, Uri.parse(uri).isAbsolute);
- Expect.equals(isAbsolute, new Uri(uri).isAbsolute);
Expect.stringEquals(uri, Uri.parse(uri).toString());
- Expect.stringEquals(uri, new Uri(uri).toString());
// Test equals and hashCode members.
- Expect.equals(new Uri(uri), new Uri(uri));
- Expect.equals(new Uri(uri).hashCode, new Uri(uri).hashCode);
+ Expect.equals(Uri.parse(uri), Uri.parse(uri));
+ Expect.equals(Uri.parse(uri).hashCode, Uri.parse(uri).hashCode);
}
testEncodeDecode(String orig, String encoded) {
- var e = encodeUri(orig);
+ var e = Uri.encodeFull(orig);
Expect.stringEquals(encoded, e);
- var d = decodeUri(encoded);
+ var d = Uri.decodeFull(encoded);
Expect.stringEquals(orig, d);
}
testEncodeDecodeComponent(String orig, String encoded) {
- var e = encodeUriComponent(orig);
+ var e = Uri.encodeComponent(orig);
Expect.stringEquals(encoded, e);
- var d = decodeUriComponent(encoded);
+ var d = Uri.decodeComponent(encoded);
+ Expect.stringEquals(orig, d);
+}
+
+testEncodeDecodeQueryComponent(String orig, String encoded) {
+ var e = Uri.encodeQueryComponent(orig);
+ Expect.stringEquals(encoded, e);
+ var d = Uri.decodeQueryComponent(encoded);
Expect.stringEquals(orig, d);
}
@@ -89,48 +93,56 @@
base.resolve("../g;p/h;s").toString());
}
+void testResolvePath(String expected, String path) {
+ Expect.equals(expected, new Uri().resolveUri(new Uri(path: path)).path);
+ Expect.equals(
+ "http://localhost$expected",
+ Uri.parse("http://localhost").resolveUri(new Uri(path: path)).toString());
+}
+
main() {
testUri("http:", true);
testUri("file://", true);
testUri("file", false);
- testUri("http://user@example.com:80/fisk?query=89&hest=silas", true);
- testUri("http://user@example.com:80/fisk?query=89&hest=silas#fragment",
+ testUri("http://user@example.com:8080/fisk?query=89&hest=silas", true);
+ testUri("http://user@example.com:8080/fisk?query=89&hest=silas#fragment",
false);
- Expect.stringEquals("http://user@example.com:80/a/b/c?query#fragment",
- const Uri.fromComponents(
+ Expect.stringEquals("http://user@example.com/a/b/c?query#fragment",
+ new Uri(
scheme: "http",
userInfo: "user",
- domain: "example.com",
+ host: "example.com",
port: 80,
path: "/a/b/c",
query: "query",
fragment: "fragment").toString());
- Expect.stringEquals("null://null@null/a/b/c/?null#null",
- const Uri.fromComponents(
+ Expect.stringEquals("//null@null/a/b/c/",
+ new Uri(
scheme: null,
userInfo: null,
- domain: null,
+ host: null,
port: 0,
path: "/a/b/c/",
query: null,
fragment: null).toString());
Expect.stringEquals("file://", Uri.parse("file:").toString());
- Expect.stringEquals("file://", new Uri("file:").toString());
- Expect.stringEquals("/a/g", removeDotSegments("/a/b/c/./../../g"));
- Expect.stringEquals("mid/6", removeDotSegments("mid/content=5/../6"));
- Expect.stringEquals("a/b/e", removeDotSegments("a/b/c/d/../../e"));
- Expect.stringEquals("a/b/e", removeDotSegments("../a/b/c/d/../../e"));
- Expect.stringEquals("a/b/e", removeDotSegments("./a/b/c/d/../../e"));
- Expect.stringEquals("a/b/e", removeDotSegments("../a/b/./c/d/../../e"));
- Expect.stringEquals("a/b/e", removeDotSegments("./a/b/./c/d/../../e"));
- Expect.stringEquals("a/b/e/", removeDotSegments("./a/b/./c/d/../../e/."));
- Expect.stringEquals("a/b/e/", removeDotSegments("./a/b/./c/d/../../e/./."));
- Expect.stringEquals("a/b/e/", removeDotSegments("./a/b/./c/d/../../e/././."));
+
+ testResolvePath("/a/g", "/a/b/c/./../../g");
+ testResolvePath("/a/g", "/a/b/c/./../../g");
+ testResolvePath("/mid/6", "mid/content=5/../6");
+ testResolvePath("/a/b/e", "a/b/c/d/../../e");
+ testResolvePath("/a/b/e", "../a/b/c/d/../../e");
+ testResolvePath("/a/b/e", "./a/b/c/d/../../e");
+ testResolvePath("/a/b/e", "../a/b/./c/d/../../e");
+ testResolvePath("/a/b/e", "./a/b/./c/d/../../e");
+ testResolvePath("/a/b/e/", "./a/b/./c/d/../../e/.");
+ testResolvePath("/a/b/e/", "./a/b/./c/d/../../e/./.");
+ testResolvePath("/a/b/e/", "./a/b/./c/d/../../e/././.");
final urisSample = "http://a/b/c/d;p?q";
Uri baseFromString = Uri.parse(urisSample);
testUriPerRFCs(baseFromString);
- Uri base = new Uri(urisSample);
+ Uri base = Uri.parse(urisSample);
testUriPerRFCs(base);
Expect.stringEquals(
@@ -147,48 +159,48 @@
Uri.parse("https://example.com:1234/a/b/c").origin);
Expect.throws(
() => Uri.parse("http:").origin,
- (e) { return e is ArgumentError; },
- "origin for uri with empty domain should fail");
+ (e) { return e is StateError; },
+ "origin for uri with empty host should fail");
Expect.throws(
- () => const Uri.fromComponents(
+ () => new Uri(
scheme: "http",
userInfo: null,
- domain: "",
+ host: "",
port: 80,
path: "/a/b/c",
query: "query",
fragment: "fragment").origin,
- (e) { return e is ArgumentError; },
- "origin for uri with empty domain should fail");
+ (e) { return e is StateError; },
+ "origin for uri with empty host should fail");
Expect.throws(
- () => const Uri.fromComponents(
+ () => new Uri(
scheme: null,
userInfo: null,
- domain: "",
+ host: "",
port: 80,
path: "/a/b/c",
query: "query",
fragment: "fragment").origin,
- (e) { return e is ArgumentError; },
+ (e) { return e is StateError; },
"origin for uri with empty scheme should fail");
Expect.throws(
- () => const Uri.fromComponents(
+ () => new Uri(
scheme: "http",
userInfo: null,
- domain: null,
+ host: null,
port: 80,
path: "/a/b/c",
query: "query",
fragment: "fragment").origin,
- (e) { return e is ArgumentError; },
- "origin for uri with empty domain should fail");
+ (e) { return e is StateError; },
+ "origin for uri with empty host should fail");
Expect.throws(
() => Uri.parse("http://:80").origin,
- (e) { return e is ArgumentError; },
- "origin for uri with empty domain should fail");
+ (e) { return e is StateError; },
+ "origin for uri with empty host should fail");
Expect.throws(
() => Uri.parse("file://localhost/test.txt").origin,
- (e) { return e is ArgumentError; },
+ (e) { return e is StateError; },
"origin for non-http/https uri should fail");
// URI encode tests
@@ -197,7 +209,7 @@
Expect.stringEquals("\u{10000}", s);
- testEncodeDecode("A + B", "A+%2B+B");
+ testEncodeDecode("A + B", "A%20%2B%20B");
testEncodeDecode("\uFFFE", "%EF%BF%BE");
testEncodeDecode("\uFFFF", "%EF%BF%BF");
testEncodeDecode("\uFFFE", "%EF%BF%BE");
@@ -207,6 +219,7 @@
testEncodeDecode("\u0800", "%E0%A0%80");
testEncodeDecode(":/@',;?&=+\$", ":/@',;?&=%2B\$");
testEncodeDecode(s, "%F0%90%80%80");
+ testEncodeDecodeComponent("A + B", "A%20%2B%20B");
testEncodeDecodeComponent("\uFFFE", "%EF%BF%BE");
testEncodeDecodeComponent("\uFFFF", "%EF%BF%BF");
testEncodeDecodeComponent("\uFFFE", "%EF%BF%BE");
@@ -216,4 +229,5 @@
testEncodeDecodeComponent("\u0800", "%E0%A0%80");
testEncodeDecodeComponent(":/@',;?&=+\$", "%3A%2F%40'%2C%3B%3F%26%3D%2B%24");
testEncodeDecodeComponent(s, "%F0%90%80%80");
+ testEncodeDecodeQueryComponent("A + B", "A+%2B+B");
}
diff --git a/tests/html/custom_element_bindings_test.dart b/tests/html/custom_element_bindings_test.dart
index c80c5fb..3b9d6a9 100644
--- a/tests/html/custom_element_bindings_test.dart
+++ b/tests/html/custom_element_bindings_test.dart
@@ -283,4 +283,5 @@
Iterable<V> get values => _map.values;
int get length => _map.length;
bool get isEmpty => _map.isEmpty;
+ bool get isNotEmpty => _map.isNotEmpty;
}
diff --git a/tests/html/form_data_test.dart b/tests/html/form_data_test.dart
index 75dedce..3017810 100644
--- a/tests/html/form_data_test.dart
+++ b/tests/html/form_data_test.dart
@@ -7,7 +7,6 @@
import '../../pkg/unittest/lib/unittest.dart';
import '../../pkg/unittest/lib/html_individual_config.dart';
import 'dart:html';
-import 'dart:uri';
void fail(message) {
guardAsync(() {
diff --git a/tests/html/location_test.dart b/tests/html/location_test.dart
index 88e3f2d..d5c8e5e 100644
--- a/tests/html/location_test.dart
+++ b/tests/html/location_test.dart
@@ -2,7 +2,6 @@
import '../../pkg/unittest/lib/unittest.dart';
import '../../pkg/unittest/lib/html_config.dart';
import 'dart:html';
-import 'dart:uri';
main() {
useHtmlConfiguration();
@@ -23,8 +22,8 @@
var origin = window.location.origin;
// We build up the origin from Uri, then make sure that it matches.
- var uri = new Uri(window.location.href);
- var reconstructedOrigin = '${uri.scheme}://${uri.domain}';
+ var uri = Uri.parse(window.location.href);
+ var reconstructedOrigin = '${uri.scheme}://${uri.host}';
if (uri.port != 0) {
reconstructedOrigin = '$reconstructedOrigin:${uri.port}';
}
diff --git a/tests/html/rtc_test.dart b/tests/html/rtc_test.dart
index d5cf9aa..df096ab0 100644
--- a/tests/html/rtc_test.dart
+++ b/tests/html/rtc_test.dart
@@ -17,16 +17,20 @@
});
group('functionality', () {
- // TODO(efortuna): More thorough testing of this API requires the user to
+ // More thorough testing of this API requires the user to
// explicitly click "allow this site to access my camera and/or microphone."
// or particularly allow that site to always have those permission on each
- // computer the test is run. Contact WebKit and/or Chrome people to
- // determine how they test with this issue.
+ // computer the test is run. For more through tests, see
+ // interactive_test.dart.
if (RtcPeerConnection.supported) {
test('peer connection', () {
var pc = new RtcPeerConnection(
- {'iceServers': [ {'url':'stun:foo.com:19302'}]});
+ {'iceServers': [ {'url':'stun:216.93.246.18:3478'}]});
expect(pc is RtcPeerConnection, isTrue);
+ // TODO(efortuna): Uncomment this test when RTCPeerConnection correctly
+ // implements EventListener in Firefox (works correctly in nightly, so
+ // it's coming!).
+ //pc.onIceCandidate.listen((candidate) {});
});
test('ice candidate', () {
diff --git a/tests/html/shadow_dom_layout_test.dart b/tests/html/shadow_dom_layout_test.dart
deleted file mode 100644
index 82705bc..0000000
--- a/tests/html/shadow_dom_layout_test.dart
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library ShadowDOMTest;
-
-import 'dart:html';
-
-// Test that children of a shadow host get distributed properly to the
-// insertion points of a shadow subtree. Output should be three boxes,
-// ordered blue, red, green down the page.
-main() {
- var div = new DivElement();
- document.body.children.add(div);
-
- // build some DOM elements
- var bluebox = _colorBox('blue', 40, 20);
- bluebox.classes.add('foo');
- var redbox = _colorBox('red', 30, 30);
- var greenbox = _colorBox('green', 60, 10);
-
- // assemble DOM
- var sRoot = div.createShadowRoot();
- sRoot.append(new Element.html('<content select=".foo"></content>'));
- sRoot.append(redbox);
- sRoot.append(new Element.tag('content'));
-
- div.append(bluebox);
- div.append(greenbox);
-}
-
-DivElement _colorBox(String color, int width, int height) {
- var style = ('background-color:$color; '
- 'width:${width}px; height:${height}px;');
- return new Element.html('<div style="$style"></div>');
-}
diff --git a/tests/html/shadow_dom_layout_test.txt b/tests/html/shadow_dom_layout_test.txt
deleted file mode 100644
index 382a2f5..0000000
--- a/tests/html/shadow_dom_layout_test.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-Content-Type: text/plain
-layer at (0,0) size 800x600
- RenderView at (0,0) size 800x600
-layer at (0,0) size 800x76
- RenderBlock {HTML} at (0,0) size 800x76
- RenderBody {BODY} at (8,8) size 784x60
- RenderBlock {DIV} at (0,0) size 784x60
- RenderBlock {DIV} at (0,0) size 40x20 [bgcolor=#0000FF]
- RenderBlock {DIV} at (0,20) size 30x30 [bgcolor=#FF0000]
- RenderBlock {DIV} at (0,50) size 60x10 [bgcolor=#008000]
-#EOF
diff --git a/tests/isolate/isolate.status b/tests/isolate/isolate.status
index e45b9ed..1937b48 100644
--- a/tests/isolate/isolate.status
+++ b/tests/isolate/isolate.status
@@ -11,8 +11,6 @@
compute_this_script_browser_stream_test: Skip # browser specific test
ports_compilation_browser_test: Skip # browser specific test
unresolved_ports_negative_test: Skip # See Issue 6839
-global_error_handler_test: Fail, Pass # See Issue 9013.
-global_error_handler_stream_test: Fail # See Issue 9013.
isolate_stress_test: Fail # TODO(ahe): This should be able to pass when we have wrapper-less tests.
@@ -47,6 +45,10 @@
spawn_uri_vm_negative_test: fail
unresolved_ports_negative_test: fail
+# test issue 10888
+global_error_handler_stream_test: fail, OK
+global_error_handler_test: fail, OK
+
[ $compiler == dart2js && ($runtime == d8 || $jscl) ]
illegal_msg_stream_test: Fail # Issue 6750
typed_data_message_test: Fail, OK # DataView only supported in browsers.
@@ -127,9 +129,6 @@
[ $compiler == dart2js && ( $runtime == ff || $runtime == safari ) ]
isolate_stress_test: Pass, Timeout # http://dartbug.com/10697
-[ $arch == arm ]
-*: Skip
-
[ $arch == simarm ]
*: Skip
diff --git a/tests/language/field1_negative_test.dart b/tests/language/field1_negative_test.dart
index e10f754..a860b3d 100644
--- a/tests/language/field1_negative_test.dart
+++ b/tests/language/field1_negative_test.dart
@@ -4,7 +4,6 @@
// Dart test to catch error reporting bugs in class fields declarations.
// Should be an error because we have setter/getter functions and fields
// in the class.
-// VMOptions=--compile_all
class C {
var a;
@@ -27,6 +26,7 @@
class Field1NegativeTest {
static testMain() {
+ var c = new C();
}
}
diff --git a/tests/language/field2_negative_test.dart b/tests/language/field2_negative_test.dart
index f37d307..26cb3c8 100644
--- a/tests/language/field2_negative_test.dart
+++ b/tests/language/field2_negative_test.dart
@@ -4,7 +4,6 @@
// Dart test to catch error reporting bugs in class fields declarations.
// Should be an error because we have setter/getter functions and fields
// in the class.
-// VMOptions=--compile_all
class C {
get a {
@@ -27,6 +26,7 @@
class Field2NegativeTest {
static testMain() {
+ var c = new C();
}
}
diff --git a/tests/language/field4_negative_test.dart b/tests/language/field4_negative_test.dart
index 426fc0f..2f00c26 100644
--- a/tests/language/field4_negative_test.dart
+++ b/tests/language/field4_negative_test.dart
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
// Dart test to catch error reporting bugs in class fields declarations.
// Should be an error because we have a field overriding a function name.
-// VMOptions=--compile_all
class A {
int a() {
@@ -14,6 +13,7 @@
class Field4NegativeTest {
static testMain() {
+ var a = new A();
}
}
diff --git a/tests/language/field5_negative_test.dart b/tests/language/field5_negative_test.dart
index 9e6da06..3ba641b 100644
--- a/tests/language/field5_negative_test.dart
+++ b/tests/language/field5_negative_test.dart
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
// Dart test to catch error reporting bugs in class fields declarations.
// Should be an error because we have a function overriding a field name.
-// VMOptions=--compile_all
class A {
var a;
@@ -14,6 +13,7 @@
class Field5NegativeTest {
static testMain() {
+ var a = new A();
}
}
diff --git a/tests/language/field6_negative_test.dart b/tests/language/field6_negative_test.dart
index d841bbd..c9a9931 100644
--- a/tests/language/field6_negative_test.dart
+++ b/tests/language/field6_negative_test.dart
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
// Dart test to catch error reporting bugs in class fields declarations.
// Should be an error because we have a getter overriding a function name.
-// VMOptions=--compile_all
class A {
int a() {
@@ -16,6 +15,7 @@
class Field6NegativeTest {
static testMain() {
+ var a = new A();
}
}
diff --git a/tests/language/field6a_negative_test.dart b/tests/language/field6a_negative_test.dart
index 8d8ac44..d2e540a 100644
--- a/tests/language/field6a_negative_test.dart
+++ b/tests/language/field6a_negative_test.dart
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
// Dart test to catch error reporting bugs in class fields declarations.
// Should be an error because we have a function overriding a getter.
-// VMOptions=--compile_all
class A {
int get a {
@@ -16,6 +15,7 @@
class Field6aNegativeTest {
static testMain() {
+ var a = new A();
}
}
diff --git a/tests/language/field_inference_test.dart b/tests/language/field_inference_test.dart
new file mode 100644
index 0000000..5996610
--- /dev/null
+++ b/tests/language/field_inference_test.dart
@@ -0,0 +1,50 @@
+// 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 and its SsaConstructionFieldTypes
+// phase.
+
+import "package:expect/expect.dart";
+
+class A {
+ var _field;
+ final other;
+ get field => _field;
+ A(this._field) : other = null;
+ A.fromOther(this.other) {
+ _field = other.field;
+ }
+}
+
+class B {
+ var a;
+ B() {
+ try { // Defeat inlining.
+ // An inlined generative constructor call used to confuse
+ // dart2js.
+ a = new A(42);
+ } catch (e) {
+ rethrow;
+ }
+ }
+}
+
+var array = [new A(42), new B()];
+
+main() {
+ // Surround the call to [analyzeAfterB] by two [: new B() :] calls
+ // to ensure the [B] constructor will be analyzed first.
+ new B();
+ var a = analyzeAfterB();
+ new B();
+ Expect.equals(42, a._field);
+}
+
+analyzeAfterB() {
+ try { // Defeat inlining.
+ return new A.fromOther(array[0]);
+ } catch (e) {
+ rethrow;
+ }
+}
diff --git a/tests/language/for_in_side_effects_test.dart b/tests/language/for_in_side_effects_test.dart
new file mode 100644
index 0000000..385dc24
--- /dev/null
+++ b/tests/language/for_in_side_effects_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.
+
+// Regression test for dart2js that used to not see side effects of
+// iterator calls made in a "for in".
+
+import "package:expect/expect.dart";
+
+var global = 42;
+var array = [new A()];
+
+class A {
+ get iterator {
+ global = 54;
+ return this;
+ }
+ moveNext() => false;
+
+ bar(a) {
+ for (var a in this) {
+ }
+ }
+}
+
+main() {
+ array[0].bar(global);
+ Expect.equals(54, global);
+}
diff --git a/tests/language/for_inlining_test.dart b/tests/language/for_inlining_test.dart
new file mode 100644
index 0000000..6615c1e
--- /dev/null
+++ b/tests/language/for_inlining_test.dart
@@ -0,0 +1,20 @@
+// 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 emit an invalid JS
+// variable declaration initializer in a for initializer.
+
+import "package:expect/expect.dart";
+
+var global;
+
+inlineMe() {
+ global = 42;
+ return 54;
+}
+
+main() {
+ for (var t = inlineMe(); t < 42; t++) {}
+ Expect.equals(42, global);
+}
diff --git a/tests/language/inline_in_for_initializer_and_bailout_test.dart b/tests/language/inline_in_for_initializer_and_bailout_test.dart
new file mode 100644
index 0000000..53689f5
--- /dev/null
+++ b/tests/language/inline_in_for_initializer_and_bailout_test.dart
@@ -0,0 +1,24 @@
+// 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:expect/expect.dart";
+
+var a = 42;
+
+inlineMe() {
+ // Add control flow to confuse the compiler.
+ if (a is int) {
+ print('a is int');
+ }
+ return a[0];
+}
+
+main() {
+ a = [42];
+ // Make [main] recursive to force a bailout version.
+ if (false) main();
+ int i = 0;
+ for (i = inlineMe(); i < 42; i++);
+ Expect.equals(42, i);
+}
diff --git a/tests/language/interface_static_method_negative_test.dart b/tests/language/interface_static_method_negative_test.dart
index ef1925e..5e8a83c 100644
--- a/tests/language/interface_static_method_negative_test.dart
+++ b/tests/language/interface_static_method_negative_test.dart
@@ -1,7 +1,6 @@
// 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.
-// VMOptions=--compile_all
abstract class A {
static void foo();
@@ -10,6 +9,7 @@
class InterfaceStaticMethodNegativeTest {
static testMain() {
+ var a = new A();
}
}
diff --git a/tests/language/language.status b/tests/language/language.status
index b61389a..bd59fc9 100644
--- a/tests/language/language.status
+++ b/tests/language/language.status
@@ -34,7 +34,6 @@
closure_type_variable_test: Fail # Type variable used as expression (dartbug.com/6282)
built_in_identifier_prefix_test: Fail # http://dartbug.com/6970
library_juxtaposition_test: Fail # Issue 6877
-gc_test: Pass, Fail # Issue 1487
pseudo_kw_illegal_test/14: Fail # Issue 356
method_override2_test/00: Fail # Issue 7076.
method_override2_test/02: Fail # Issue 7076.
@@ -87,12 +86,6 @@
execute_finally10_test: Fail # Issue 430
execute_finally11_test: Fail # Issue 430
-[ $compiler == none && ($system == macos || $system == linux) && $arch == ia32 && $checked ]
-gc_test: Skip # Issue 1487, flaky.
-
-[ $compiler == none && $mode == debug ]
-gc_test: Skip # Takes too long.
-
[ $compiler == none && $unchecked ]
# Only checked mode reports an error on type assignment
@@ -311,15 +304,6 @@
final_variable_assignment_test/02: Fail
final_variable_assignment_test/03: Fail
final_variable_assignment_test/04: Fail
-gc_test: Skip # Issue 1487
-field5_negative_test: Fail # Issue 10839
-field4_negative_test: Fail # Issue 10839
-field6_negative_test: Fail # Issue 10839
-non_const_super_negative_test: Fail # Issue 10839
-field2_negative_test: Fail # Issue 10839
-interface_static_method_negative_test: Fail # Issue 10839
-field1_negative_test: Fail # Issue 10839
-field6a_negative_test: Fail # Issue 10839
[ $runtime == dartium ]
@@ -344,17 +328,12 @@
[ $compiler == dart2dart ]
built_in_identifier_prefix_test: Fail # Inherited from dart2js.
-const_factory_redirection_test: Fail # http://dartbug.com/6894
-compile_time_constant_h_test: Fail
constructor_redirect2_test/03: Fail
constructor_initializer_test: Fail # VM issue
-factory_implementation_test/none: Fail
-factory_implementation_test/00:Fail
factory2_test: Fail
factory3_test: Fail
factory5_test/none: Fail
factory5_test/00: Fail
-factory_implementation_test/00: Fail
type_checks_in_factory_method_test: Fail
default_factory2_test/01: Fail # type arguments on redirecting factory not implemented
default_factory3_test: Fail # type arguments on redirecting factory not implemented
@@ -438,8 +417,6 @@
const_var_test: Pass, Fail # Map literals take 2 type arguments.
map_literal3_test: Fail # Map literals take 2 type arguments.
class_cycle_negative_test: Fail, OK # Bad test: assumes eager loading.
-field1_negative_test: Fail, OK # Bad test: assumes eager loading.
-field6_negative_test: Fail, OK # Bad test: assumes eager loading.
interface_cycle_negative_test: Fail, OK # Bad test: assumes eager loading.
# Common problems with dart2js. In illegal family, invalid
# declarations are simply not parsed. In pseudo kw dart2js
@@ -456,13 +433,7 @@
duplicate_implements_test/02: Fail
duplicate_implements_test/03: Fail
duplicate_implements_test/04: Fail
-field2_negative_test: Fail
-field4_negative_test: Fail
-field5_negative_test: Fail
-field6a_negative_test: Fail
interface_factory_constructor_negative_test: Fail
-interface_static_method_negative_test: Fail
-non_const_super_negative_test: Fail
method_override2_test/00: Fail
method_override2_test/02: Fail
method_override2_test/03: Fail
@@ -485,7 +456,6 @@
function_type_alias5_test/01: Fail
function_type_alias5_test/02: Fail
function_type_alias7_test/00: Fail
-implicit_scope_test: Fail
instanceof3_test: Fail
parameter_initializer6_negative_test: Fail # Issue 3502
syntax_test/47: Fail
@@ -493,7 +463,6 @@
constructor5_test: Fail
constructor6_test: Fail
closure_in_initializer_test: Fail
-gc_test: Pass,Fail
super_first_constructor_test: Fail
# VM specific tests.
disable_privacy_test: Pass, Fail, Ok
@@ -592,23 +561,6 @@
class_cycle_test/00: fail
class_cycle_test/01: fail
class_cycle_test/03: fail
-class_literal_test/02: fail
-class_literal_test/05: fail
-class_literal_test/07: fail
-class_literal_test/10: fail
-class_literal_test/11: fail
-class_literal_test/12: fail
-class_literal_test/14: fail
-class_literal_test/17: fail
-class_literal_test/18: fail
-class_literal_test/19: fail
-class_literal_test/22: fail
-class_literal_test/23: fail
-class_literal_test/24: fail
-class_literal_test/27: fail
-class_literal_test/28: fail
-class_literal_test/29: fail
-class_literal_test/none: fail
closure_call_wrong_argument_count_negative_test: fail
compile_time_constant10_test/none: fail
compile_time_constant8_test: fail
@@ -620,17 +572,13 @@
compile_time_constant_b_test: fail
compile_time_constant_c_test/01: fail
compile_time_constant_c_test/02: fail
-compile_time_constant_checked2_test/01: fail
compile_time_constant_checked2_test/02: fail
compile_time_constant_checked2_test/03: fail
compile_time_constant_checked2_test/04: fail
-compile_time_constant_checked2_test/05: fail
compile_time_constant_checked2_test/06: fail
-compile_time_constant_checked3_test/01: fail
compile_time_constant_checked3_test/02: fail
compile_time_constant_checked3_test/03: fail
compile_time_constant_checked3_test/04: fail
-compile_time_constant_checked3_test/05: fail
compile_time_constant_checked3_test/06: fail
compile_time_constant_d_test: fail
compile_time_constant_e_test: fail
@@ -778,11 +726,6 @@
syntax_test/33: fail
ternary_test: fail
throw7_negative_test: fail
-try_catch_on_syntax_test/01: fail
-try_catch_on_syntax_test/07: fail
-try_catch_syntax_test/08: fail
-try_catch_syntax_test/16: fail
-try_catch_syntax_test/17: fail
type_error_test: fail
type_parameter_test/01: fail
type_parameter_test/02: fail
@@ -812,14 +755,67 @@
unresolved_top_level_var_negative_test: fail
# test issue 10683, It is a compile-time error if e refers to the name v or the name v=.
-block_scope_test: fail
-lazy_static3_test: fail
+block_scope_test: fail, OK
+lazy_static3_test: fail, OK
# test issue 10752, there are 'implicit' scopes for 'if', 'while' and 'do-while'
implicit_scope_test: fail, OK
-[ $arch == arm ]
-*: Skip
+# test issue 10889, "throw" requires expression, "rethrow" should be used instead
+execute_finally10_test: fail, OK
+execute_finally11_test: fail, OK
+final_used_in_try_test: fail, OK
+full_stacktrace2_test: fail, OK
+stack_trace_test: fail, OK
+throw3_test: fail, OK
+try_catch3_test: fail, OK
+
+# test issue 10890; on-catch UnknownType is a static warning, not error
+try_catch_on_syntax_test/01: fail, OK
+try_catch_on_syntax_test/07: fail, OK
+try_catch_syntax_test/08: fail, OK
+
+# test issue 10899; it is static warning, not error, to call methods of class literal
+class_literal_test/02: fail, OK
+class_literal_test/05: fail, OK
+class_literal_test/07: fail, OK
+class_literal_test/10: fail, OK
+class_literal_test/11: fail, OK
+class_literal_test/12: fail, OK
+class_literal_test/14: fail, OK
+class_literal_test/17: fail, OK
+class_literal_test/18: fail, OK
+class_literal_test/19: fail, OK
+class_literal_test/22: fail, OK
+class_literal_test/23: fail, OK
+class_literal_test/24: fail, OK
+class_literal_test/27: fail, OK
+class_literal_test/28: fail, OK
+class_literal_test/29: fail, OK
+class_literal_test/none: fail, OK
+
+[ $compiler == dartanalyzer && $checked ]
+factory1_test/00: fail
+factory1_test/01: fail
+field_type_check2_test/01: fail
+factory_implementation_test/00: fail
+factory_redirection_test/08: fail
+factory_redirection_test/09: fail
+factory_redirection_test/10: fail
+factory_redirection_test/11: fail
+factory_redirection_test/12: fail
+factory_redirection_test/13: fail
+factory_redirection_test/14: fail
+getters_setters2_test/03: fail
+type_variable_bounds3_test/00: fail
+type_variable_bounds2_test/05: fail
+type_variable_scope_test/00: fail
+type_variable_scope_test/01: fail
+type_variable_scope_test/02: fail
+type_variable_scope_test/03: fail
+type_variable_scope_test/04: fail
+type_variable_scope_test/05: fail
+
[ $arch == simarm ]
*: Skip
diff --git a/tests/language/language_dart2js.status b/tests/language/language_dart2js.status
index 541b3c9..0b6a3c9 100644
--- a/tests/language/language_dart2js.status
+++ b/tests/language/language_dart2js.status
@@ -174,7 +174,6 @@
get_set_syntax_test/14: Fail # Fixed by https://chromiumcodereview.appspot.com/10915111
get_set_syntax_test/15: Fail # Fixed by https://chromiumcodereview.appspot.com/10915111
get_set_syntax_test/16: Fail # Fixed by https://chromiumcodereview.appspot.com/10915111
-implicit_scope_test: Fail # duplicate definition of a="bar"
method_binding_test: Fail # internal error: super property read not implemented.
method_override_test: Fail # cannot resolve type GetKeysFunctionType
method_override2_test/00: Fail # accepts illegal override
@@ -227,8 +226,6 @@
class_cycle_negative_test: Fail, OK # Bad test: assumes eager loading.
external_test/16: Fail, OK # Bad test: assumes eager loading.
-field1_negative_test: Fail, OK # Bad test: assumes eager loading.
-field6_negative_test: Fail, OK # Bad test: assumes eager loading.
interface_cycle_negative_test: Fail, OK # Bad test: assumes eager loading.
syntax_test/47: Fail, OK # Bad test: assumes eager loading.
@@ -253,21 +250,15 @@
duplicate_implements_test/02: Fail # Negative language test.
duplicate_implements_test/03: Fail # Negative language test.
duplicate_implements_test/04: Fail # Negative language test.
-field2_negative_test: Fail # Negative language test.
field3_negative_test: Fail # Negative language test.
-field4_negative_test: Fail # Negative language test.
-field5_negative_test: Fail # Negative language test.
-field6a_negative_test: Fail # Negative language test.
final_for_in_variable_test/01: Fail # Negative language test
instantiate_type_variable_negative_test: Pass # For the wrong reason.
interface_factory3_negative_test: Fail # Negative language test.
interface_factory_constructor_negative_test: Fail # Negative language test.
-interface_static_method_negative_test: Fail # Negative language test.
list_literal1_negative_test: Fail # Negative language test.
list_literal2_negative_test: Fail # Negative language test.
map_literal1_negative_test: Fail # Negative language test.
map_literal2_negative_test: Fail # Negative language test.
-non_const_super_negative_test: Fail # Negative language test.
number_identifier_negative_test: Fail # Negative language test.
operator1_negative_test: Fail # Negative language test.
prefix23_negative_test: Fail # Negative language test.
diff --git a/tests/language/non_const_super_negative_test.dart b/tests/language/non_const_super_negative_test.dart
index 17f3d5a..32742e2 100644
--- a/tests/language/non_const_super_negative_test.dart
+++ b/tests/language/non_const_super_negative_test.dart
@@ -2,7 +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.
// Check fails because const class extends from non const class.
-// VMOptions=--compile_all
class Base {
Base() {}
@@ -15,6 +14,7 @@
class NonConstSuperNegativeTest {
static testMain() {
+ var a = new Sub();
}
}
diff --git a/tests/language/super_abstract_method_test.dart b/tests/language/super_abstract_method_test.dart
new file mode 100644
index 0000000..fbb3648
--- /dev/null
+++ b/tests/language/super_abstract_method_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.
+
+// Test that a method overridden by an abstract method is called at
+// runtime.
+
+import "package:expect/expect.dart";
+
+class Base {
+ foo() => 42;
+}
+
+abstract class A extends Base {
+ foo();
+}
+
+class B extends A {
+ testSuperCall() => super.foo();
+}
+
+main() {
+ Expect.equals(42, new B().foo());
+ Expect.equals(42, new B().testSuperCall());
+}
diff --git a/tests/lib/analyzer/analyze_tests.status b/tests/lib/analyzer/analyze_tests.status
index 949fd4f..90d7b8b 100644
--- a/tests/lib/analyzer/analyze_tests.status
+++ b/tests/lib/analyzer/analyze_tests.status
@@ -21,8 +21,8 @@
standalone/io/raw_secure_server_socket_argument_test: Fail
# Test runner does not use the latest VM.
-standalone/io/test_runner_test: Fail
-standalone/io/skipping_dart2js_compilations_test: Fail
+standalone/io/test_runner_test: Skip
+standalone/io/skipping_dart2js_compilations_test: Skip
# Implicit downcast.
standalone/typed_data_view_test: Fail
diff --git a/tests/lib/async/run_async6_test.dart b/tests/lib/async/run_async6_test.dart
new file mode 100644
index 0000000..e89bc03
--- /dev/null
+++ b/tests/lib/async/run_async6_test.dart
@@ -0,0 +1,22 @@
+// 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 run_async_test;
+
+import 'dart:async';
+import '../../../pkg/unittest/lib/unittest.dart';
+
+bool _unhandledExceptionCallback(exception) => true;
+
+main() {
+ test('run async test', () {
+ var callback = expectAsync0(() {});
+ runAsync(() {
+ runAsync(() {
+ callback();
+ });
+ throw new Exception('exception');
+ });
+ });
+}
diff --git a/tests/lib/async/stream_controller_async_test.dart b/tests/lib/async/stream_controller_async_test.dart
index e2aab21..65e658f 100644
--- a/tests/lib/async/stream_controller_async_test.dart
+++ b/tests/lib/async/stream_controller_async_test.dart
@@ -53,28 +53,6 @@
c.add(42);
});
- test("Single-subscription StreamController subscription changes", () {
- StreamController c = new StreamController();
- EventSink sink = c.sink;
- Stream stream = c.stream;
- int counter = 0;
- var subscription;
- subscription = stream.listen((data) {
- counter += data;
- Expect.throws(() => stream.listen(null), (e) => e is StateError);
- subscription.cancel();
- stream.listen((data) {
- counter += data * 10;
- },
- onDone: expectAsync0(() {
- Expect.equals(1 + 20, counter);
- }));
- });
- sink.add(1);
- sink.add(2);
- sink.close();
- });
-
test("Single-subscription StreamController events are buffered when"
" there is no subscriber",
() {
@@ -93,33 +71,6 @@
Expect.equals(3, counter);
}));
});
-
- // Test subscription changes while firing.
- test("Single-subscription StreamController subscription changes while firing",
- () {
- StreamController c = new StreamController();
- EventSink sink = c.sink;
- Stream stream = c.stream;
- int counter = 0;
- var subscription = stream.listen(null);
- subscription.onData(expectAsync1((data) {
- counter += data;
- subscription.cancel();
- stream.listen((data) {
- counter += 10 * data;
- },
- onDone: expectAsync0(() {
- Expect.equals(1 + 20 + 30 + 40 + 50, counter);
- }));
- Expect.throws(() => stream.listen(null), (e) => e is StateError);
- }));
- sink.add(1); // seen by stream 1
- sink.add(2); // seen by stream 10 and 100
- sink.add(3); // -"-
- sink.add(4); // -"-
- sink.add(5); // seen by stream 10
- sink.close();
- });
}
testExtraMethods() {
@@ -478,10 +429,85 @@
testFuture("drain", (s, act) => s.drain().then(act));
}
+void testBroadcastController() {
+ test("broadcast-controller-basic", () {
+ StreamController<int> c = new StreamController.broadcast(
+ onListen: expectAsync0(() {}),
+ onCancel: expectAsync0(() {})
+ );
+ Stream<int> s = c.stream;
+ s.listen(expectAsync1((x) { expect(x, equals(42)); }));
+ c.add(42);
+ c.close();
+ });
+
+ test("broadcast-controller-listen-twice", () {
+ StreamController<int> c = new StreamController.broadcast(
+ onListen: expectAsync0(() {}),
+ onCancel: expectAsync0(() {})
+ );
+ c.stream.listen(expectAsync1((x) { expect(x, equals(42)); }, count: 2));
+ c.add(42);
+ c.stream.listen(expectAsync1((x) { expect(x, equals(42)); }));
+ c.add(42);
+ c.close();
+ });
+
+ test("broadcast-controller-listen-twice-non-overlap", () {
+ StreamController<int> c = new StreamController.broadcast(
+ onListen: expectAsync0(() {}, count: 2),
+ onCancel: expectAsync0(() {}, count: 2)
+ );
+ var sub = c.stream.listen(expectAsync1((x) { expect(x, equals(42)); }));
+ c.add(42);
+ sub.cancel();
+ c.stream.listen(expectAsync1((x) { expect(x, equals(42)); }));
+ c.add(42);
+ c.close();
+ });
+
+ test("broadcast-controller-individual-pause", () {
+ StreamController<int> c = new StreamController.broadcast(
+ onListen: expectAsync0(() {}),
+ onCancel: expectAsync0(() {})
+ );
+ var sub1 = c.stream.listen(expectAsync1((x) { expect(x, equals(42)); }));
+ var sub2 = c.stream.listen(expectAsync1((x) { expect(x, equals(42)); },
+ count: 3));
+ c.add(42);
+ sub1.pause();
+ c.add(42);
+ sub1.cancel();
+ var sub3 = c.stream.listen(expectAsync1((x) { expect(x, equals(42)); }));
+ c.add(42);
+ c.close();
+ });
+
+ test("broadcast-controller-add-in-callback", () {
+ StreamController<int> c;
+ c = new StreamController(
+ onListen: expectAsync0(() {}),
+ onCancel: expectAsync0(() {
+ c.add(42);
+ })
+ );
+ var sub;
+ sub = c.stream.asBroadcastStream().listen(expectAsync1((v) {
+ Expect.equals(37, v);
+ c.add(21);
+ sub.cancel();
+ }));
+ c.add(37); // Triggers listener, which adds 21 and removes itself.
+ // Removing listener triggers onCancel which adds another 42.
+ // Both 21 and 42 are lost because there are no listeners.
+ });
+}
+
main() {
testController();
testSingleController();
testExtraMethods();
testPause();
testRethrow();
+ testBroadcastController();
}
diff --git a/tests/lib/async/stream_periodic4_test.dart b/tests/lib/async/stream_periodic4_test.dart
index 5b6eda3..779947b 100644
--- a/tests/lib/async/stream_periodic4_test.dart
+++ b/tests/lib/async/stream_periodic4_test.dart
@@ -8,13 +8,7 @@
import "dart:async";
import '../../../pkg/unittest/lib/unittest.dart';
-int iteration = 0;
-
void runTest(period, maxElapsed, pauseDuration) {
- print("Iteration: $iteration");
- var myIteration = iteration;
- iteration++;
-
Function done = expectAsync0(() { });
Stopwatch watch = new Stopwatch()..start();
@@ -29,10 +23,8 @@
expect(true, false);
} else {
subscription.cancel();
- print("Cancelling subscription of iteration: $myIteration");
// Call 'done' ourself, since it won't be invoked in the onDone handler.
runTest(period * 2, maxElapsed * 2, pauseDuration * 2);
- print("Invoking done of iteration inside listener: $myIteration");
done();
return;
}
@@ -46,10 +38,7 @@
subscription.resume();
});
}
- }, onDone: () {
- print("Invoking done of iteration: $myIteration");
- done();
- });
+ }, onDone: done);
}
main() {
diff --git a/tests/lib/async/stream_state_helper.dart b/tests/lib/async/stream_state_helper.dart
index dbc645a..c433e39 100644
--- a/tests/lib/async/stream_state_helper.dart
+++ b/tests/lib/async/stream_state_helper.dart
@@ -9,6 +9,7 @@
import "dart:collection";
class StreamProtocolTest {
+ bool trace = false;
StreamController _controller;
Stream _controllerStream;
StreamSubscription _subscription;
@@ -20,9 +21,8 @@
_controller = new StreamController(
onListen: _onSubcription,
onPause: _onPause,
- onResume: _onPause,
- onCancel: _onSubcription);
- // TODO(lrn): Make it work with multiple subscribers too.
+ onResume: _onResume,
+ onCancel: _onCancel);
if (broadcast) {
_controllerStream = _controller.stream.asBroadcastStream();
} else {
@@ -54,7 +54,7 @@
_subscription.pause(resumeSignal);
}
- void resume([Future resumeSignal]) {
+ void resume() {
if (_subscription == null) throw new StateError("Not subscribed");
_subscription.resume();
}
@@ -67,6 +67,7 @@
// Handling of stream events.
void _onData(var data) {
+ if (trace) print("[Data : $data]");
_withNextExpectation((Event expect) {
if (!expect.matchData(data)) {
_fail("Expected: $expect\n"
@@ -76,15 +77,17 @@
}
void _onError(error) {
+ if (trace) print("[Error : $error]");
_withNextExpectation((Event expect) {
if (!expect.matchError(error)) {
_fail("Expected: $expect\n"
- "Found : [Data: ${error}]");
+ "Found : [Error: ${error}]");
}
});
}
void _onDone() {
+ if (trace) print("[Done]");
_subscription = null;
_withNextExpectation((Event expect) {
if (!expect.matchDone()) {
@@ -95,20 +98,41 @@
}
void _onPause() {
+ if (trace) print("[Pause]");
_withNextExpectation((Event expect) {
- if (!expect.matchPauseChange(_controller)) {
+ if (!expect.matchPause()) {
_fail("Expected: $expect\n"
- "Found : [Paused:${_controller.isPaused}]");
+ "Found : [Paused]");
+ }
+ });
+ }
+
+ void _onResume() {
+ if (trace) print("[Resumed]");
+ _withNextExpectation((Event expect) {
+ if (!expect.matchResume()) {
+ _fail("Expected: $expect\n"
+ "Found : [Resumed]");
}
});
}
void _onSubcription() {
+ if (trace) print("[Subscribed]");
_withNextExpectation((Event expect) {
- if (!expect.matchSubscriptionChange(_controller)) {
+ if (!expect.matchSubscribe()) {
_fail("Expected: $expect\n"
- "Found: [Has listener:${_controller.hasListener}, "
- "Paused:${_controller.isPaused}]");
+ "Found: [Subscribed]");
+ }
+ });
+ }
+
+ void _onCancel() {
+ if (trace) print("[Cancelled]");
+ _withNextExpectation((Event expect) {
+ if (!expect.matchCancel()) {
+ _fail("Expected: $expect\n"
+ "Found: [Cancelled]");
}
});
}
@@ -117,9 +141,10 @@
if (_nextExpectationIndex == _expectations.length) {
action(new MismatchEvent());
} else {
- Event next = _expectations[_nextExpectationIndex++];
+ Event next = _expectations[_nextExpectationIndex];
action(next);
}
+ _nextExpectationIndex++;
_checkDone();
}
@@ -155,18 +180,31 @@
}
_expectations.add(new DoneEvent(action));
}
- void expectPause(bool isPaused, [void action()]) {
+ void expectPause([void action()]) {
if (_onComplete == null) {
_fail("Adding expectation after completing");
}
- _expectations.add(new PauseCallbackEvent(isPaused, action));
+ _expectations.add(new PauseCallbackEvent(action));
}
- void expectSubscription(bool hasListener, bool isPaused, [void action()]) {
+ void expectResume([void action()]) {
+ if (_onComplete == null) {
+ _fail("Adding expectation after completing");
+ }
+ _expectations.add(new ResumeCallbackEvent(action));
+ }
+ void expectSubscription([void action()]) {
if (_onComplete == null) {
_fail("Adding expectation after completing");
}
_expectations.add(
- new SubscriptionCallbackEvent(hasListener, isPaused, action));
+ new SubscriptionCallbackEvent(action));
+ }
+ void expectCancel([void action()]) {
+ if (_onComplete == null) {
+ _fail("Adding expectation after completing");
+ }
+ _expectations.add(
+ new CancelCallbackEvent(action));
}
void _fail(String message) {
@@ -178,11 +216,6 @@
}
}
-class EventCollector {
- final Queue<Event> events = new Queue<Event>();
-
-}
-
class Event {
Function _action;
Event(void this._action());
@@ -202,13 +235,23 @@
if (_action != null) _action();
return true;
}
- bool matchPauseChange(StreamController c) {
- if (!_testPause(c)) return false;
+ bool matchPause() {
+ if (!_testPause()) return false;
if (_action != null) _action();
return true;
}
- bool matchSubscriptionChange(StreamController c) {
- if (!_testSubscribe(c)) return false;
+ bool matchResume() {
+ if (!_testResume()) return false;
+ if (_action != null) _action();
+ return true;
+ }
+ bool matchSubscribe() {
+ if (!_testSubscribe()) return false;
+ if (_action != null) _action();
+ return true;
+ }
+ bool matchCancel() {
+ if (!_testCancel()) return false;
if (_action != null) _action();
return true;
}
@@ -216,8 +259,10 @@
bool _testData(_) => false;
bool _testError(_) => false;
bool _testDone() => false;
- bool _testPause(_) => false;
- bool _testSubscribe(_) => false;
+ bool _testPause() => false;
+ bool _testResume() => false;
+ bool _testSubscribe() => false;
+ bool _testCancel() => false;
}
class MismatchEvent extends Event {
@@ -246,22 +291,27 @@
}
class PauseCallbackEvent extends Event {
- final bool isPaused;
- PauseCallbackEvent(this.isPaused, void action())
- : super(action);
- bool _testPause(StreamController c) => isPaused == c.isPaused;
- String toString() => "[Paused:$isPaused]";
+ PauseCallbackEvent(void action()) : super(action);
+ bool _testPause() => true;
+ String toString() => "[Paused]";
+}
+
+class ResumeCallbackEvent extends Event {
+ ResumeCallbackEvent(void action()) : super(action);
+ bool _testResume() => true;
+ String toString() => "[Resumed]";
}
class SubscriptionCallbackEvent extends Event {
- final bool hasListener;
- final bool isPaused;
- SubscriptionCallbackEvent(this.hasListener, this.isPaused, void action())
- : super(action);
- bool _testSubscribe(StreamController c) {
- return hasListener == c.hasListener && isPaused == c.isPaused;
- }
- String toString() => "[Has listener:$hasListener, Paused:$isPaused]";
+ SubscriptionCallbackEvent(void action()) : super(action);
+ bool _testSubscribe() => true;
+ String toString() => "[Subscribed]";
+}
+
+class CancelCallbackEvent extends Event {
+ CancelCallbackEvent(void action()) : super(action);
+ bool _testCancel() => true;
+ String toString() => "[Cancelled]";
}
@@ -280,12 +330,20 @@
_actual = "*[Done]";
return true;
}
- bool _testPause(StreamController c) {
- _actual = "*[Paused:${c.isPaused}]";
+ bool _testPause() {
+ _actual = "*[Paused]";
return true;
}
- bool _testSubcribe(StreamController c) {
- _actual = "*[Has listener:${c.hasListener}, Paused:${c.isPaused}]";
+ bool _testResume() {
+ _actual = "*[Resumed]";
+ return true;
+ }
+ bool _testSubcribe() {
+ _actual = "*[Subscribed]";
+ return true;
+ }
+ bool _testCancel() {
+ _actual = "*[Cancelled]";
return true;
}
diff --git a/tests/lib/async/stream_state_nonzero_timer_test.dart b/tests/lib/async/stream_state_nonzero_timer_test.dart
index 868f760..0beff6f 100644
--- a/tests/lib/async/stream_state_nonzero_timer_test.dart
+++ b/tests/lib/async/stream_state_nonzero_timer_test.dart
@@ -24,28 +24,28 @@
test("$p-sub-data/pause/resume/pause/resume-done", () {
var t = new StreamProtocolTest(broadcast);
- t..expectSubscription(true, false)
+ t..expectSubscription()
..expectData(42, () {
t.pause();
})
- ..expectPause(true, () { t.resume(); })
- ..expectPause(false, () { t.pause(); })
- ..expectPause(true, () { t.resume(); })
- ..expectPause(false, () { t.close(); })
+ ..expectPause(() { t.resume(); })
+ ..expectResume(() { t.pause(); })
+ ..expectPause(() { t.resume(); })
+ ..expectResume(() { t.close(); })
..expectDone()
- ..expectSubscription(false, false);
+ ..expectCancel();
t..subscribe()..add(42);
});
test("$p-sub-data/pause-done", () {
var t = new StreamProtocolTest(broadcast);
- t..expectSubscription(true, false)
+ t..expectSubscription()
..expectData(42, () {
t.pause(new Future.delayed(ms5, () => null));
})
- ..expectPause(true)
+ ..expectPause()
..expectDone()
- ..expectSubscription(false, false);
+ ..expectCancel();
// We are calling "close" while the controller is actually paused,
// and it will stay paused until the pending events are sent.
t..subscribe()..add(42)..close();
@@ -53,20 +53,20 @@
test("$p-sub-data/pause-resume/done", () {
var t = new StreamProtocolTest(broadcast);
- t..expectSubscription(true, false)
+ t..expectSubscription()
..expectData(42, () {
t.pause(new Future.delayed(ms5, () => null));
})
- ..expectPause(true)
- ..expectPause(false, () { t.close(); })
+ ..expectPause()
+ ..expectResume(t.close)
..expectDone()
- ..expectSubscription(false, false);
+ ..expectCancel();
t..subscribe()..add(42);
});
test("$p-sub-data/data+pause-data-resume-done", () {
var t = new StreamProtocolTest(broadcast);
- t..expectSubscription(true, false)
+ t..expectSubscription()
..expectData(42, () {
t.add(43);
t.pause(new Future.delayed(ms5, () => null));
@@ -74,30 +74,30 @@
// After that, the controller stays paused until the pending queue
// is empty.
})
- ..expectPause(true)
+ ..expectPause()
..expectData(43)
- ..expectPause(false, () { t.close(); })
+ ..expectResume(t.close)
..expectDone()
- ..expectSubscription(false, false);
+ ..expectCancel();
t..subscribe()..add(42);
});
-
+return;
test("$p-pause-during-callback", () {
var t = new StreamProtocolTest(broadcast);
- t..expectSubscription(true, false)
+ t..expectSubscription()
..expectData(42, () {
t.pause();
})
- ..expectPause(true, () {
+ ..expectPause(() {
t.resume();
})
- ..expectPause(false, () {
+ ..expectResume(() {
t.pause();
t.resume();
t.close();
})
..expectDone()
- ..expectSubscription(false, false);
+ ..expectCancel();
t..subscribe()
..add(42);
});
diff --git a/tests/lib/async/stream_state_test.dart b/tests/lib/async/stream_state_test.dart
index d6d873f..08cb7a1 100644
--- a/tests/lib/async/stream_state_test.dart
+++ b/tests/lib/async/stream_state_test.dart
@@ -20,10 +20,10 @@
var p = broadcast ? "BC" : "SC";
test("$p-sub-data-done", () {
var t = new StreamProtocolTest(broadcast);
- t..expectSubscription(true, false)
+ t..expectSubscription()
..expectData(42)
..expectDone()
- ..expectSubscription(false, false);
+ ..expectCancel();
t..subscribe()..add(42)..close();
});
@@ -32,33 +32,33 @@
if (broadcast) {
t..expectDone();
} else {
- t..expectSubscription(true, false)
+ t..expectSubscription()
..expectData(42)
..expectDone()
- ..expectSubscription(false, false);
+ ..expectCancel();
}
t..add(42)..close()..subscribe();
});
test("$p-sub-data/pause+resume-done", () {
var t = new StreamProtocolTest(broadcast);
- t..expectSubscription(true, false)
+ t..expectSubscription()
..expectData(42, () {
t.pause();
t.resume();
t.close();
})
..expectDone()
- ..expectSubscription(false, false);
+ ..expectCancel();
t..subscribe()..add(42);
});
test("$p-sub-data-unsubonerror", () {
var t = new StreamProtocolTest(broadcast);
- t..expectSubscription(true, false)
+ t..expectSubscription()
..expectData(42)
..expectError("bad")
- ..expectSubscription(false, !broadcast);
+ ..expectCancel();
t..subscribe(cancelOnError: true)
..add(42)
..error("bad")
@@ -68,12 +68,12 @@
test("$p-sub-data-no-unsubonerror", () {
var t = new StreamProtocolTest(broadcast);
- t..expectSubscription(true, false)
+ t..expectSubscription()
..expectData(42)
..expectError("bad")
..expectData(43)
..expectDone()
- ..expectSubscription(false, false);
+ ..expectCancel();
t..subscribe(cancelOnError: false)
..add(42)
..error("bad")
@@ -83,62 +83,15 @@
test("$p-pause-resume-during-event", () {
var t = new StreamProtocolTest(broadcast);
- t..expectSubscription(true, false)
+ t..expectSubscription()
..expectData(42, () {
t.pause();
t.resume();
})
..expectDone()
- ..expectSubscription(false, false);
+ ..expectCancel();
t..subscribe()
..add(42)
..close();
});
-
- test("$p-cancel-sub-during-event", () {
- var t = new StreamProtocolTest(broadcast);
- t..expectSubscription(true, false)
- ..expectData(42, () {
- t.cancel();
- t.subscribe();
- })
- ..expectData(43)
- ..expectDone()
- ..expectSubscription(false, false);
- t..subscribe()
- ..add(42)
- ..add(43)
- ..close();
- });
-
- test("$p-cancel-sub-during-callback", () {
- var t = new StreamProtocolTest(broadcast);
- t..expectSubscription(true, false)
- ..expectData(42, () {
- t.pause();
- })
- ..expectPause(true, () {
- t.cancel(); // Cancels pause
- t.subscribe();
- })
- ..expectPause(false)
- ..expectData(43)
- ..expectDone()
- ..expectSubscription(false, false);
- t..subscribe()
- ..add(42)
- ..add(43)
- ..close();
- });
-
- test("$p-sub-after-done-is-done", () {
- var t = new StreamProtocolTest(broadcast);
- t..expectSubscription(true, false)
- ..expectDone()
- ..expectSubscription(false, false)
- ..expectDone();
- t..subscribe()
- ..close()
- ..subscribe(); // Subscribe after done does not cause callbacks at all.
- });
}
diff --git a/tests/lib/crypto/base64_test.dart b/tests/lib/crypto/base64_test.dart
index 663e067..efc438e 100644
--- a/tests/lib/crypto/base64_test.dart
+++ b/tests/lib/crypto/base64_test.dart
@@ -6,7 +6,7 @@
library base64_test;
import "package:expect/expect.dart";
-import 'dart:crypto';
+import "package:crypto/crypto.dart";
import 'dart:math';
// Data from http://tools.ietf.org/html/rfc4648.
diff --git a/tests/lib/crypto/hmac_md5_test.dart b/tests/lib/crypto/hmac_md5_test.dart
index 8f9e768..2d717b9 100644
--- a/tests/lib/crypto/hmac_md5_test.dart
+++ b/tests/lib/crypto/hmac_md5_test.dart
@@ -6,7 +6,7 @@
library hmac_md5_test;
import "package:expect/expect.dart";
-import 'dart:crypto';
+import "package:crypto/crypto.dart";
// Data from http://tools.ietf.org/html/rfc2202.
var hmac_md5_inputs =
diff --git a/tests/lib/crypto/hmac_sha1_test.dart b/tests/lib/crypto/hmac_sha1_test.dart
index 12e0c00..de79470 100644
--- a/tests/lib/crypto/hmac_sha1_test.dart
+++ b/tests/lib/crypto/hmac_sha1_test.dart
@@ -6,7 +6,7 @@
library hmac_sha1_test;
import "package:expect/expect.dart";
-import 'dart:crypto';
+import "package:crypto/crypto.dart";
part 'hmac_sha1_test_vectors.dart';
diff --git a/tests/lib/crypto/hmac_sha256_test.dart b/tests/lib/crypto/hmac_sha256_test.dart
index 1d52efd..73fa561 100644
--- a/tests/lib/crypto/hmac_sha256_test.dart
+++ b/tests/lib/crypto/hmac_sha256_test.dart
@@ -6,7 +6,7 @@
library hmac_sha256_test;
import "package:expect/expect.dart";
-import 'dart:crypto';
+import "package:crypto/crypto.dart";
part 'hmac_sha256_test_vectors.dart';
diff --git a/tests/lib/crypto/sha1_test.dart b/tests/lib/crypto/sha1_test.dart
index 1254dc8..24a7271 100644
--- a/tests/lib/crypto/sha1_test.dart
+++ b/tests/lib/crypto/sha1_test.dart
@@ -6,7 +6,7 @@
library sha1_test;
import "package:expect/expect.dart";
-import 'dart:crypto';
+import "package:crypto/crypto.dart";
part 'sha1_long_test_vectors.dart';
part 'sha1_short_test_vectors.dart';
diff --git a/tests/lib/crypto/sha256_test.dart b/tests/lib/crypto/sha256_test.dart
index f42a3f2..528c831 100644
--- a/tests/lib/crypto/sha256_test.dart
+++ b/tests/lib/crypto/sha256_test.dart
@@ -6,7 +6,7 @@
library sha256_test;
import "package:expect/expect.dart";
-import 'dart:crypto';
+import "package:crypto/crypto.dart";
part 'sha256_long_test_vectors.dart';
part 'sha256_short_test_vectors.dart';
diff --git a/tests/lib/lib.status b/tests/lib/lib.status
index 097a374..f905060 100644
--- a/tests/lib/lib.status
+++ b/tests/lib/lib.status
@@ -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.
-async/stream_periodic4_test: Fail, Pass # floitsch: Marking as flaky while collection debug information. http://dartbug.com/9619
-
# The typed_data library is not supported by dart2js or dart2dart yet.
[ $compiler == dart2js || $compiler == dart2dart ]
typed_data/*: Fail
@@ -18,9 +16,15 @@
math/*: Skip
mirrors/mirrors_test: Fail # TODO(ahe): I'm working on fixing this.
mirrors/library_uri_io_test: Skip # Not intended for dart2js as it uses dart:io.
-mirrors/library_uri_package_test: Fail # dart:mirrors not fully implemented.
async/run_async3_test: Fail # _enqueueImmediate runs after Timer. http://dartbug.com/9002
async/run_async4_test: Pass, Fail # no global exception handler in isolates. http://dartbug.com/9012
+async/run_async6_test: Fail # global error handling is not supported. http://dartbug.com/5958
+
+[ $compiler == dart2js && $minified ]
+mirrors/mirrors_resolve_fields_test: Fail # Issue 6490
+
+[ $csp ]
+mirrors/library_uri_package_test: Fail, Pass # Issue 6490
[ $compiler == dart2js && $checked ]
async/stream_event_transform_test: Fail # Issue 7733.
@@ -84,16 +88,13 @@
[ $runtime == vm || ($compiler == none && $runtime == drt) ]
async/run_async3_test: Fail # _enqueueImmediate runs after Timer. http://dartbug.com/9001.
-async/run_async4_test: Pass, Fail # http://dartbug.com/9013
[ $compiler == none && $runtime == drt ]
async/timer_isolate_test: Skip # See Issue 4997
async/timer_not_available_test: Skip # only meant to test when there is no way to
# implement timer (currently only in d8)
mirrors/library_uri_io_test: Skip # Not intended for drt as it uses dart:io.
-
-[ $arch == arm ]
-*: Skip
+async/run_async6_test: Fail # Issue 10910
[ $arch == simarm ]
*: Skip
diff --git a/tests/lib/math/coin_test.dart b/tests/lib/math/coin_test.dart
index 0da9aed..1ca2261 100644
--- a/tests/lib/math/coin_test.dart
+++ b/tests/lib/math/coin_test.dart
@@ -27,4 +27,36 @@
"Tails: $tails\n"
"Ratio: ${heads/tails}\n");
Expect.approxEquals(1.0, heads/tails, 0.1);
+
+ heads = 0;
+ tails = 0;
+ for (var i = 0; i < 10000; i++) {
+ rnd = new Random(i);
+ if (rnd.nextBool()) {
+ heads++;
+ } else {
+ tails++;
+ }
+ }
+ print("Heads: $heads\n"
+ "Tails: $tails\n"
+ "Ratio: ${heads/tails}\n");
+ Expect.approxEquals(1.0, heads/tails, 0.1);
+
+ // A sequence of newly allocated Random number generators should have fair
+ // initial tosses.
+ heads = 0;
+ tails = 0;
+ for (var i = 0; i < 10000; i++) {
+ rnd = new Random();
+ if (rnd.nextBool()) {
+ heads++;
+ } else {
+ tails++;
+ }
+ }
+ print("Heads: $heads\n"
+ "Tails: $tails\n"
+ "Ratio: ${heads/tails}\n");
+ Expect.approxEquals(1.0, heads/tails, 0.1);
}
\ No newline at end of file
diff --git a/tests/lib/math/random_test.dart b/tests/lib/math/random_test.dart
index f06fa2b..d1e02bc 100644
--- a/tests/lib/math/random_test.dart
+++ b/tests/lib/math/random_test.dart
@@ -14,38 +14,38 @@
var rnd = new Random(20130307);
// Make sure we do not break the random number generation.
var i = 0;
- Expect.equals( 0, rnd.nextInt(1 << ++i));
- Expect.equals( 2, rnd.nextInt(1 << ++i));
- Expect.equals( 7, rnd.nextInt(1 << ++i));
- Expect.equals( 8, rnd.nextInt(1 << ++i));
Expect.equals( 1, rnd.nextInt(1 << ++i));
- Expect.equals( 61, rnd.nextInt(1 << ++i));
- Expect.equals( 31, rnd.nextInt(1 << ++i));
- Expect.equals( 230, rnd.nextInt(1 << ++i));
- Expect.equals( 390, rnd.nextInt(1 << ++i));
- Expect.equals( 443, rnd.nextInt(1 << ++i));
- Expect.equals( 1931, rnd.nextInt(1 << ++i));
- Expect.equals( 3028, rnd.nextInt(1 << ++i));
- Expect.equals( 5649, rnd.nextInt(1 << ++i));
- Expect.equals( 4603, rnd.nextInt(1 << ++i));
- Expect.equals( 27684, rnd.nextInt(1 << ++i));
- Expect.equals( 54139, rnd.nextInt(1 << ++i));
- Expect.equals( 83454, rnd.nextInt(1 << ++i));
- Expect.equals( 106708, rnd.nextInt(1 << ++i));
- Expect.equals( 112143, rnd.nextInt(1 << ++i));
- Expect.equals( 875266, rnd.nextInt(1 << ++i));
- Expect.equals( 971126, rnd.nextInt(1 << ++i));
- Expect.equals( 1254573, rnd.nextInt(1 << ++i));
- Expect.equals( 4063839, rnd.nextInt(1 << ++i));
- Expect.equals( 7854646, rnd.nextInt(1 << ++i));
- Expect.equals( 29593843, rnd.nextInt(1 << ++i));
- Expect.equals( 17672573, rnd.nextInt(1 << ++i));
- Expect.equals( 80223657, rnd.nextInt(1 << ++i));
- Expect.equals( 142194155, rnd.nextInt(1 << ++i));
+ Expect.equals( 1, rnd.nextInt(1 << ++i));
+ Expect.equals( 7, rnd.nextInt(1 << ++i));
+ Expect.equals( 6, rnd.nextInt(1 << ++i));
+ Expect.equals( 6, rnd.nextInt(1 << ++i));
+ Expect.equals( 59, rnd.nextInt(1 << ++i));
+ Expect.equals( 11, rnd.nextInt(1 << ++i));
+ Expect.equals( 212, rnd.nextInt(1 << ++i));
+ Expect.equals( 17, rnd.nextInt(1 << ++i));
+ Expect.equals( 507, rnd.nextInt(1 << ++i));
+ Expect.equals( 1060, rnd.nextInt(1 << ++i));
+ Expect.equals( 891, rnd.nextInt(1 << ++i));
+ Expect.equals( 1534, rnd.nextInt(1 << ++i));
+ Expect.equals( 8404, rnd.nextInt(1 << ++i));
+ Expect.equals( 13839, rnd.nextInt(1 << ++i));
+ Expect.equals( 23298, rnd.nextInt(1 << ++i));
+ Expect.equals( 53622, rnd.nextInt(1 << ++i));
+ Expect.equals( 205997, rnd.nextInt(1 << ++i));
+ Expect.equals( 393823, rnd.nextInt(1 << ++i));
+ Expect.equals( 514614, rnd.nextInt(1 << ++i));
+ Expect.equals( 233715, rnd.nextInt(1 << ++i));
+ Expect.equals( 895357, rnd.nextInt(1 << ++i));
+ Expect.equals( 4726185, rnd.nextInt(1 << ++i));
+ Expect.equals( 7976427, rnd.nextInt(1 << ++i));
Expect.equals( 31792146, rnd.nextInt(1 << ++i));
- Expect.equals(1042196170, rnd.nextInt(1 << ++i));
- Expect.equals(1589656273, rnd.nextInt(1 << ++i));
- Expect.equals(1547294578, rnd.nextInt(1 << ++i));
+ Expect.equals( 35563210, rnd.nextInt(1 << ++i));
+ Expect.equals( 113261265, rnd.nextInt(1 << ++i));
+ Expect.equals( 205117298, rnd.nextInt(1 << ++i));
+ Expect.equals( 447729735, rnd.nextInt(1 << ++i));
+ Expect.equals(1072507596, rnd.nextInt(1 << ++i));
+ Expect.equals(2134030067, rnd.nextInt(1 << ++i));
+ Expect.equals(721180690, rnd.nextInt(1 << ++i));
Expect.equals(32, i);
// If max is too large expect an ArgumentError.
Expect.throws(() => rnd.nextInt((1 << i)+1), (e) => e is ArgumentError);
diff --git a/tests/lib/mirrors/library_uri_io_test.dart b/tests/lib/mirrors/library_uri_io_test.dart
index beddc40..add283d 100644
--- a/tests/lib/mirrors/library_uri_io_test.dart
+++ b/tests/lib/mirrors/library_uri_io_test.dart
@@ -8,7 +8,6 @@
import 'dart:mirrors';
import 'dart:io';
-import 'dart:uri';
import '../../../pkg/unittest/lib/unittest.dart';
class Class {
@@ -25,7 +24,7 @@
var mirrors = currentMirrorSystem();
test("Test current library uri", () {
String appendSlash(String path) => path.endsWith('/') ? path : '$path/';
- Uri cwd = new Uri.fromComponents(
+ Uri cwd = new Uri(
scheme: 'file',
path: appendSlash(new Path(new File('.').fullPathSync()).toString()));
Uri uri = cwd.resolve(new Path(new Options().script).toString());
diff --git a/tests/lib/mirrors/library_uri_package_test.dart b/tests/lib/mirrors/library_uri_package_test.dart
index bcd1085..db1ceea 100644
--- a/tests/lib/mirrors/library_uri_package_test.dart
+++ b/tests/lib/mirrors/library_uri_package_test.dart
@@ -7,7 +7,6 @@
library MirrorsTest;
import 'dart:mirrors';
-import 'dart:uri';
import 'package:args/args.dart';
import '../../../pkg/unittest/lib/unittest.dart';
diff --git a/tests/lib/mirrors/mirrors_resolve_fields_test.dart b/tests/lib/mirrors/mirrors_resolve_fields_test.dart
new file mode 100644
index 0000000..f513ae2
--- /dev/null
+++ b/tests/lib/mirrors/mirrors_resolve_fields_test.dart
@@ -0,0 +1,22 @@
+// 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 not resolve instance
+// fields when a class is only instantiated through mirrors.
+
+import "package:expect/expect.dart";
+import 'dart:mirrors';
+
+class A {
+ static const int _STATE_INITIAL = 0;
+ int _state = _STATE_INITIAL;
+ A();
+}
+
+main() {
+ var mirrors = currentMirrorSystem();
+ var classMirror = reflectClass(A);
+ var instanceMirror = classMirror.newInstance(const Symbol(''),[]);
+ Expect.equals(A._STATE_INITIAL, instanceMirror.reflectee._state);
+}
diff --git a/tests/lib/mirrors/mirrors_test.dart b/tests/lib/mirrors/mirrors_test.dart
index 3c5164d..695ee778 100644
--- a/tests/lib/mirrors/mirrors_test.dart
+++ b/tests/lib/mirrors/mirrors_test.dart
@@ -8,7 +8,6 @@
library MirrorsTest;
import "dart:mirrors";
import "../../../pkg/unittest/lib/unittest.dart";
-import 'dart:uri';
var topLevelField;
@@ -161,7 +160,7 @@
expect(objectMirror.reflectee.field, equals(1234));
}
-testNames(mirrors) {
+testNames(mirrors, isDart2js) {
var libMirror = mirrors.findLibrary(const Symbol("MirrorsTest")).single;
var classMirror = libMirror.classes[const Symbol('Class')];
var typedefMirror = libMirror.members[const Symbol('Typedef')];
@@ -174,14 +173,16 @@
expect(classMirror.simpleName, equals(const Symbol('Class')));
expect(classMirror.qualifiedName, equals(const Symbol('MirrorsTest.Class')));
- TypeVariableMirror typeVariable = classMirror.typeVariables.values.single;
- expect(typeVariable.simpleName, equals(const Symbol('T')));
- expect(typeVariable.qualifiedName,
- equals(const Symbol('MirrorsTest.Class.T')));
+ if (!isDart2js) { // TODO(ahe): Implement this in dart2js.
+ TypeVariableMirror typeVariable = classMirror.typeVariables.values.single;
+ expect(typeVariable.simpleName, equals(const Symbol('T')));
+ expect(typeVariable.qualifiedName,
+ equals(const Symbol('MirrorsTest.Class.T')));
- expect(typedefMirror.simpleName, equals(const Symbol('Typedef')));
- expect(typedefMirror.qualifiedName,
- equals(const Symbol('MirrorsTest.Typedef')));
+ expect(typedefMirror.simpleName, equals(const Symbol('Typedef')));
+ expect(typedefMirror.qualifiedName,
+ equals(const Symbol('MirrorsTest.Typedef')));
+ }
expect(methodMirror.simpleName, equals(const Symbol('testNames')));
expect(methodMirror.qualifiedName,
@@ -207,9 +208,6 @@
test("Test field access", () { testFieldAccess(mirrors); });
test("Test closure mirrors", () { testClosureMirrors(mirrors); });
test("Test invoke constructor", () { testInvokeConstructor(mirrors); });
- if (isDart2js) return;
- test("Test reflect type", () { testReflectClass(mirrors); });
- test("Test simple and qualifiedName", () { testNames(mirrors); });
test("Test current library uri", () {
testLibraryUri(new Class(),
(Uri uri) => uri.path.endsWith('/mirrors_test.dart'));
@@ -217,6 +215,9 @@
test("Test dart library uri", () {
testLibraryUri("test", (Uri uri) => uri == Uri.parse('dart:core'));
});
+ test("Test simple and qualifiedName", () { testNames(mirrors, isDart2js); });
+ if (isDart2js) return; // TODO(ahe): Remove this line.
+ test("Test reflect type", () { testReflectClass(mirrors); });
}
main() {
diff --git a/tests/lib/uri/uri_ipv6_test.dart b/tests/lib/uri/uri_ipv6_test.dart
deleted file mode 100644
index 1b69cf9..0000000
--- a/tests/lib/uri/uri_ipv6_test.dart
+++ /dev/null
@@ -1,80 +0,0 @@
-// 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:uri';
-
-
-void testValidIpv6Uri() {
- var path = 'http://[::1]:1234/path?query=5#now';
- var uri = Uri.parse(path);
- Expect.equals('http', uri.scheme);
- Expect.equals('::1', uri.domain);
- Expect.equals(1234, uri.port);
- Expect.equals('/path', uri.path);
- Expect.equals('query=5', uri.query);
- Expect.equals('now', uri.fragment);
- Expect.equals(path, uri.toString());
-
- path = 'http://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:80/index.html';
- uri = Uri.parse(path);
- Expect.equals('http', uri.scheme);
- Expect.equals('FEDC:BA98:7654:3210:FEDC:BA98:7654:3210', uri.domain);
- Expect.equals(80, uri.port);
- Expect.equals('/index.html', uri.path);
- Expect.equals(path, uri.toString());
-
- path = 'http://[1080:0:0:0:8:800:200C:417A]/index.html';
- uri = Uri.parse(path);
- Expect.equals('http', uri.scheme);
- Expect.equals('1080:0:0:0:8:800:200C:417A', uri.domain);
- Expect.equals(0, uri.port);
- Expect.equals('/index.html', uri.path);
- Expect.equals(path, uri.toString());
-
- path = 'http://[3ffe:2a00:100:7031::1]';
- uri = Uri.parse(path);
- Expect.equals('http', uri.scheme);
- Expect.equals('3ffe:2a00:100:7031::1', uri.domain);
- Expect.equals(0, uri.port);
- Expect.equals('', uri.path);
- Expect.equals(path, uri.toString());
-
- path = 'http://[1080::8:800:200C:417A]/foo';
- uri = Uri.parse(path);
- Expect.equals('http', uri.scheme);
- Expect.equals('1080::8:800:200C:417A', uri.domain);
- Expect.equals(0, uri.port);
- Expect.equals('/foo', uri.path);
- Expect.equals(path, uri.toString());
-
- path = 'http://[::192.9.5.5]/ipng';
- uri = Uri.parse(path);
- Expect.equals('http', uri.scheme);
- Expect.equals('::192.9.5.5', uri.domain);
- Expect.equals(0, uri.port);
- Expect.equals('/ipng', uri.path);
- Expect.equals(path, uri.toString());
-
- path = 'http://[::FFFF:129.144.52.38]:80/index.html';
- uri = Uri.parse(path);
- Expect.equals('http', uri.scheme);
- Expect.equals('::FFFF:129.144.52.38', uri.domain);
- Expect.equals(80, uri.port);
- Expect.equals('/index.html', uri.path);
- Expect.equals(path, uri.toString());
-
- path = 'http://[2010:836B:4179::836B:4179]';
- uri = Uri.parse(path);
- Expect.equals('http', uri.scheme);
- Expect.equals('2010:836B:4179::836B:4179', uri.domain);
- Expect.equals(0, uri.port);
- Expect.equals('', uri.path);
- Expect.equals(path, uri.toString());
-}
-
-void main() {
- testValidIpv6Uri();
-}
-
diff --git a/tests/standalone/io/http_auth_digest_test.dart b/tests/standalone/io/http_auth_digest_test.dart
index 74e9d93..2a3828d 100644
--- a/tests/standalone/io/http_auth_digest_test.dart
+++ b/tests/standalone/io/http_auth_digest_test.dart
@@ -2,12 +2,11 @@
// 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:crypto/crypto.dart";
import "package:expect/expect.dart";
import 'dart:async';
-import 'dart:crypto';
import 'dart:io';
import 'dart:isolate';
-import 'dart:uri';
import 'dart:utf';
class Server {
diff --git a/tests/standalone/io/http_auth_test.dart b/tests/standalone/io/http_auth_test.dart
index f0a9733..9869a94 100644
--- a/tests/standalone/io/http_auth_test.dart
+++ b/tests/standalone/io/http_auth_test.dart
@@ -2,12 +2,11 @@
// 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:crypto/crypto.dart";
import "package:expect/expect.dart";
import 'dart:async';
-import 'dart:crypto';
import 'dart:io';
import 'dart:isolate';
-import 'dart:uri';
import 'dart:utf';
class Server {
diff --git a/tests/standalone/io/http_client_exception_test.dart b/tests/standalone/io/http_client_exception_test.dart
index 0d2f1e3..9028b6d 100644
--- a/tests/standalone/io/http_client_exception_test.dart
+++ b/tests/standalone/io/http_client_exception_test.dart
@@ -6,7 +6,6 @@
import "package:expect/expect.dart";
import "dart:io";
import "dart:isolate";
-import "dart:uri";
void testInvalidUrl() {
HttpClient client = new HttpClient();
diff --git a/tests/standalone/io/http_connection_close_test.dart b/tests/standalone/io/http_connection_close_test.dart
index c56ef39..70fbda0 100644
--- a/tests/standalone/io/http_connection_close_test.dart
+++ b/tests/standalone/io/http_connection_close_test.dart
@@ -6,7 +6,6 @@
import "package:expect/expect.dart";
import "dart:async";
import "dart:io";
-import "dart:uri";
void testHttp10Close(bool closeRequest) {
HttpServer.bind("127.0.0.1", 0).then((server) {
diff --git a/tests/standalone/io/http_multipart_test.dart b/tests/standalone/io/http_multipart_test.dart
index d564fc9..45cdec9 100644
--- a/tests/standalone/io/http_multipart_test.dart
+++ b/tests/standalone/io/http_multipart_test.dart
@@ -116,7 +116,6 @@
'Content of file',
contentType: 'text/plain',
filename: 'file1.txt')]);
-
// Similar test using Chrome posting.
message = [
45, 45, 45, 45, 45, 45, 87, 101, 98, 75, 105, 116, 70, 111, 114, 109, 66,
diff --git a/tests/standalone/io/http_parser_test.dart b/tests/standalone/io/http_parser_test.dart
index c0d4e1e..dbd9564 100644
--- a/tests/standalone/io/http_parser_test.dart
+++ b/tests/standalone/io/http_parser_test.dart
@@ -7,7 +7,6 @@
import 'dart:math';
import 'dart:typed_data';
import 'dart:isolate';
-import 'dart:uri';
part '../../../sdk/lib/io/io_sink.dart';
part '../../../sdk/lib/io/http.dart';
@@ -74,7 +73,6 @@
bytesReceived += data.length;
},
onDone: () {
- Expect.isFalse(upgraded);
port2.close();
Expect.equals(expectedMethod, method);
Expect.stringEquals(expectedUri, uri.toString());
@@ -101,7 +99,6 @@
incoming.dataDone.then((_) {
port1.close();
- Expect.isFalse(upgraded);
});
});
@@ -204,6 +201,24 @@
controller = new StreamController();
var port = new ReceivePort();
controller.stream.pipe(httpParser);
+ int doneCallCount = 0;
+ // Called when done parsing entire message and done parsing body.
+ // Only executed when both are done.
+ void whenDone() {
+ doneCallCount++;
+ if (doneCallCount < 2) return;
+ Expect.equals(expectedVersion, headers.protocolVersion);
+ Expect.equals(expectedStatusCode, statusCode);
+ Expect.equals(expectedReasonPhrase, reasonPhrase);
+ Expect.isTrue(headersCompleteCalled);
+ Expect.equals(expectedBytesReceived, bytesReceived);
+ if (!upgrade) {
+ Expect.isTrue(dataEndCalled);
+ if (close) Expect.isTrue(dataEndClose);
+ Expect.equals(dataEndClose, connectionClose);
+ }
+ };
+
var subscription = httpParser.listen((incoming) {
port.close();
statusCode = incoming.statusCode;
@@ -230,21 +245,9 @@
onDone: () {
dataEndCalled = true;
dataEndClose = close;
+ whenDone();
});
- });
-
- subscription.onDone(() {
- Expect.equals(expectedVersion, headers.protocolVersion);
- Expect.equals(expectedStatusCode, statusCode);
- Expect.equals(expectedReasonPhrase, reasonPhrase);
- Expect.isTrue(headersCompleteCalled);
- Expect.equals(expectedBytesReceived, bytesReceived);
- if (!upgrade) {
- Expect.isTrue(dataEndCalled);
- if (close) Expect.isTrue(dataEndClose);
- Expect.equals(dataEndClose, connectionClose);
- }
- });
+ }, onDone: whenDone);
headersCompleteCalled = false;
dataEndCalled = false;
diff --git a/tests/standalone/io/http_proxy_configuration_test.dart b/tests/standalone/io/http_proxy_configuration_test.dart
index 829a080..4bff020 100644
--- a/tests/standalone/io/http_proxy_configuration_test.dart
+++ b/tests/standalone/io/http_proxy_configuration_test.dart
@@ -4,7 +4,6 @@
import "package:expect/expect.dart";
import "dart:io";
-import "dart:uri";
expect(expected, String uri, environment) {
Expect.equals(expected,
diff --git a/tests/standalone/io/http_proxy_test.dart b/tests/standalone/io/http_proxy_test.dart
index abab0bb..5e7bfe1 100644
--- a/tests/standalone/io/http_proxy_test.dart
+++ b/tests/standalone/io/http_proxy_test.dart
@@ -2,11 +2,10 @@
// 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:crypto/crypto.dart";
import "package:expect/expect.dart";
import "dart:async";
-import 'dart:crypto';
import "dart:io";
-import "dart:uri";
import 'dart:utf';
class Server {
diff --git a/tests/standalone/io/http_redirect_test.dart b/tests/standalone/io/http_redirect_test.dart
index b3caef5..f67ff751 100644
--- a/tests/standalone/io/http_redirect_test.dart
+++ b/tests/standalone/io/http_redirect_test.dart
@@ -6,7 +6,6 @@
import "package:expect/expect.dart";
import "dart:async";
import "dart:io";
-import "dart:uri";
Future<HttpServer> setupServer() {
Completer completer = new Completer();
@@ -197,15 +196,11 @@
(HttpRequest request, HttpResponse response) {
request.listen((_) {}, onDone: () {
Expect.equals("POST", request.method);
- request.listen(
- (_) {},
- onDone: () {
- response.headers.set(
- HttpHeaders.LOCATION,
- "http://127.0.0.1:${server.port}/303target");
- response.statusCode = HttpStatus.SEE_OTHER;
- response.close();
- });
+ response.headers.set(
+ HttpHeaders.LOCATION,
+ "http://127.0.0.1:${server.port}/303target");
+ response.statusCode = HttpStatus.SEE_OTHER;
+ response.close();
});
});
addRequestHandler(
diff --git a/tests/standalone/io/http_request_pipeling_test.dart b/tests/standalone/io/http_request_pipeling_test.dart
index 682c592..0da43df 100644
--- a/tests/standalone/io/http_request_pipeling_test.dart
+++ b/tests/standalone/io/http_request_pipeling_test.dart
@@ -9,7 +9,6 @@
import "package:expect/expect.dart";
import "dart:io";
-import "dart:uri";
void main() {
final int REQUEST_COUNT = 100;
diff --git a/tests/standalone/io/http_server_response_test.dart b/tests/standalone/io/http_server_response_test.dart
index 0e75d34..5b0a525 100644
--- a/tests/standalone/io/http_server_response_test.dart
+++ b/tests/standalone/io/http_server_response_test.dart
@@ -243,6 +243,34 @@
}
+void testIgnoreRequestData() {
+ HttpServer.bind("127.0.0.1", 0)
+ .then((server) {
+ server.listen((request) {
+ // Ignore request data.
+ request.response.write("all-okay");
+ request.response.close();
+ });
+
+ var client = new HttpClient();
+ client.get("127.0.0.1", server.port, "/")
+ .then((request) {
+ request.contentLength = 1024 * 1024;
+ request.add(new Uint8List(1024 * 1024));
+ return request.close();
+ })
+ .then((response) {
+ response
+ .fold(0, (s, b) => s + b.length)
+ .then((bytes) {
+ Expect.equals(8, bytes);
+ server.close();
+ });
+ });
+ });
+}
+
+
void main() {
testResponseDone();
testResponseAddStream();
@@ -250,4 +278,5 @@
testResponseAddClosed();
testBadResponseAdd();
testBadResponseClose();
+ testIgnoreRequestData();
}
diff --git a/tests/standalone/io/http_session_test.dart b/tests/standalone/io/http_session_test.dart
index 4fe3d9d..a3141c8 100644
--- a/tests/standalone/io/http_session_test.dart
+++ b/tests/standalone/io/http_session_test.dart
@@ -68,7 +68,7 @@
void testTimeout(int sessionCount) {
var client = new HttpClient();
HttpServer.bind("127.0.0.1", 0).then((server) {
- server.sessionTimeout = 0;
+ server.sessionTimeout = 1;
var timeouts = [];
server.listen((request) {
var c = new Completer();
diff --git a/tests/standalone/io/http_stream_close_test.dart b/tests/standalone/io/http_stream_close_test.dart
index b47209e..f5d4aeb 100644
--- a/tests/standalone/io/http_stream_close_test.dart
+++ b/tests/standalone/io/http_stream_close_test.dart
@@ -4,7 +4,6 @@
//
import "dart:io";
-import "dart:uri";
main() {
bool serverOnClosed = false;
diff --git a/tests/standalone/io/https_client_certificate_test.dart b/tests/standalone/io/https_client_certificate_test.dart
index fea97ef..141470a 100644
--- a/tests/standalone/io/https_client_certificate_test.dart
+++ b/tests/standalone/io/https_client_certificate_test.dart
@@ -5,7 +5,6 @@
import "package:expect/expect.dart";
import "dart:async";
import "dart:io";
-import "dart:uri";
import "dart:isolate";
const HOST_NAME = "localhost";
diff --git a/tests/standalone/io/https_client_exception_test.dart b/tests/standalone/io/https_client_exception_test.dart
index 8acac41..6994e05 100644
--- a/tests/standalone/io/https_client_exception_test.dart
+++ b/tests/standalone/io/https_client_exception_test.dart
@@ -5,7 +5,6 @@
import "package:expect/expect.dart";
import "dart:io";
import "dart:isolate";
-import "dart:uri";
void testBadHostName() {
HttpClient client = new HttpClient();
diff --git a/tests/standalone/io/https_server_test.dart b/tests/standalone/io/https_server_test.dart
index 08fec0c..2e0b2a0 100644
--- a/tests/standalone/io/https_server_test.dart
+++ b/tests/standalone/io/https_server_test.dart
@@ -5,7 +5,6 @@
import "package:expect/expect.dart";
import "dart:async";
import "dart:io";
-import "dart:uri";
import "dart:isolate";
const HOST_NAME = "localhost";
diff --git a/tests/standalone/io/pipe_server_test.dart b/tests/standalone/io/pipe_server_test.dart
index d86e5f5..90bfb5e 100644
--- a/tests/standalone/io/pipe_server_test.dart
+++ b/tests/standalone/io/pipe_server_test.dart
@@ -51,7 +51,6 @@
String srcFileName =
getDataFilename("tests/standalone/io/readline_test1.dat");
Stream fileInput = new File(srcFileName).openRead();
-
fileInput.pipe(_socket).then((_) {
var tempDir = new Directory('').createTempSync();
var dstFileName = tempDir.path + "/readline_test1.dat";
diff --git a/tests/standalone/io/regress_8828_test.dart b/tests/standalone/io/regress_8828_test.dart
index c33a56d..b801545 100644
--- a/tests/standalone/io/regress_8828_test.dart
+++ b/tests/standalone/io/regress_8828_test.dart
@@ -26,7 +26,7 @@
return request.close();
})
.then((HttpClientResponse response) {
- List<int> body = new List();
+ List<int> body = new List();
response.listen(body.addAll,
onDone: () {
Expect.equals("first line\nsecond line\n",
diff --git a/tests/standalone/io/secure_builtin_roots_database_test.dart b/tests/standalone/io/secure_builtin_roots_database_test.dart
index 3966032..6b55c71 100644
--- a/tests/standalone/io/secure_builtin_roots_database_test.dart
+++ b/tests/standalone/io/secure_builtin_roots_database_test.dart
@@ -4,7 +4,6 @@
import "package:expect/expect.dart";
import "dart:io";
-import "dart:uri";
import "dart:isolate";
import "dart:async";
diff --git a/tests/standalone/io/secure_builtin_roots_test.dart b/tests/standalone/io/secure_builtin_roots_test.dart
index edfffad..32609a8 100644
--- a/tests/standalone/io/secure_builtin_roots_test.dart
+++ b/tests/standalone/io/secure_builtin_roots_test.dart
@@ -4,7 +4,6 @@
import "package:expect/expect.dart";
import "dart:io";
-import "dart:uri";
import "dart:isolate";
import "dart:async";
diff --git a/tests/standalone/io/secure_no_builtin_roots_database_test.dart b/tests/standalone/io/secure_no_builtin_roots_database_test.dart
index 8c647d0..dcdb2be 100644
--- a/tests/standalone/io/secure_no_builtin_roots_database_test.dart
+++ b/tests/standalone/io/secure_no_builtin_roots_database_test.dart
@@ -4,7 +4,6 @@
import "package:expect/expect.dart";
import "dart:io";
-import "dart:uri";
import "dart:isolate";
import "dart:async";
diff --git a/tests/standalone/io/secure_no_builtin_roots_test.dart b/tests/standalone/io/secure_no_builtin_roots_test.dart
index c411e62..a71c5fc 100644
--- a/tests/standalone/io/secure_no_builtin_roots_test.dart
+++ b/tests/standalone/io/secure_no_builtin_roots_test.dart
@@ -4,7 +4,6 @@
import "package:expect/expect.dart";
import "dart:io";
-import "dart:uri";
import "dart:isolate";
import "dart:async";
diff --git a/tests/standalone/io/skipping_dart2js_compilations_test.dart b/tests/standalone/io/skipping_dart2js_compilations_test.dart
index 2dd7bf2..d018541 100644
--- a/tests/standalone/io/skipping_dart2js_compilations_test.dart
+++ b/tests/standalone/io/skipping_dart2js_compilations_test.dart
@@ -17,7 +17,6 @@
import 'package:expect/expect.dart';
import 'dart:async';
import 'dart:io';
-import 'dart:uri';
import '../../../tools/testing/dart/test_suite.dart' as suite;
import '../../../tools/testing/dart/test_runner.dart' as runner;
import '../../../tools/testing/dart/test_options.dart' as options;
@@ -153,7 +152,7 @@
var executable = new Options().executable;
var arguments = [createFileScript, fileUtils.scriptOutputPath.toNativePath()];
var bootstrapDeps = [
- new Uri("file://${fileUtils.testSnapshotFilePath}")];
+ Uri.parse("file://${fileUtils.testSnapshotFilePath}")];
var commands = [new runner.CompilationCommand(
fileUtils.testJsFilePath.toNativePath(),
false,
diff --git a/tests/standalone/io/web_socket_test.dart b/tests/standalone/io/web_socket_test.dart
index 4e5df10..cd72efa 100644
--- a/tests/standalone/io/web_socket_test.dart
+++ b/tests/standalone/io/web_socket_test.dart
@@ -12,7 +12,6 @@
import "dart:io";
import "dart:isolate";
import "dart:typed_data";
-import "dart:uri";
const String CERT_NAME = 'localhost_cert';
const String HOST_NAME = 'localhost';
diff --git a/tests/standalone/standalone.status b/tests/standalone/standalone.status
index 10e39ba..6027974 100644
--- a/tests/standalone/standalone.status
+++ b/tests/standalone/standalone.status
@@ -4,12 +4,6 @@
package/invalid_uri_test: Fail, OK # Fails intentionally
-[ $runtime == vm && $system == macos ]
-debugger/basic_debugger_test: Pass, Crash # Issue 10488.
-
-[ $runtime == vm && $system == windows ]
-debugger/*: Skip # Issue: 10791
-
[ $runtime == vm ]
# Fails because checked-in dart executable is not up to date.
io/test_runner_test: Fail
@@ -17,6 +11,8 @@
# Skip this because it is leaving temp directories behind when it fails.
io/skipping_dart2js_compilations_test: Skip
+io/http_content_length_test: Pass, Fail # Issue 10934
+
[ $runtime == vm && ( $system == windows ) ]
io/raw_socket_test: Pass, Fail # Issue 8901
@@ -66,6 +62,8 @@
# package test issue 7392
package/package1_test: Fail
package/package_test: Fail
+io/test_runner_test: Fail # Library dart:uri removed.
+io/skipping_dart2js_compilations_test: Skip # Library dart:uri removed.
# The dart:io library is created at build time from separate files, and
@@ -110,6 +108,8 @@
debugger/*: Skip # Do not run standalone vm debugger tests with dart2js.
left_shift_bit_and_op_test: Skip # Integers exceed dart2js precision.
pow_test: Skip # Precision > 53 bits.
+io/test_runner_test: Fail # Library dart:uri removed.
+io/skipping_dart2js_compilations_test: Skip # Library dart:uri removed.
[ $compiler == dart2js && $jscl ]
assert_test: Fail, OK # Assumes unspecified fields on the AssertionError.
@@ -117,7 +117,6 @@
deoptimization_test: Fail, OK # Requires bigint.
out_of_memory_test: Fail, OK # d8 handles much larger arrays than Dart VM.
io/options_test: Fail, OK # Cannot pass options to d8.
-io/http_parser_test: Fail, OK # Cancelling a Timer not implemented in d8/jsshell.
[ $compiler == dart2js && $runtime == none ]
io/options_test: Fail
@@ -134,9 +133,6 @@
# Skip until we stabilize language tests.
*: Skip
-[ $arch == arm ]
-*: Skip
-
[ $arch == simarm ]
*: Skip
diff --git a/tests/utils/dummy_compiler_test.dart b/tests/utils/dummy_compiler_test.dart
index ae44c27..50ab451 100644
--- a/tests/utils/dummy_compiler_test.dart
+++ b/tests/utils/dummy_compiler_test.dart
@@ -6,7 +6,6 @@
library dummy_compiler;
import 'dart:async';
-import 'dart:uri';
import '../../sdk/lib/_internal/compiler/compiler.dart';
@@ -32,6 +31,7 @@
class Closure {}
class Dynamic_ {}
class Null {}
+ class StackTrace {}
class LinkedHashMap {}
identical(a, b) => true;
getRuntimeTypeInfo(o) {}
@@ -93,9 +93,9 @@
main() {
Future<String> result =
- compile(new Uri.fromComponents(scheme: 'main'),
- new Uri.fromComponents(scheme: 'lib', path: '/'),
- new Uri.fromComponents(scheme: 'package', path: '/'),
+ compile(new Uri(scheme: 'main'),
+ new Uri(scheme: 'lib', path: '/'),
+ new Uri(scheme: 'package', path: '/'),
provider, handler);
result.then((String code) {
if (code == null) {
diff --git a/tests/utils/recursive_import_test.dart b/tests/utils/recursive_import_test.dart
index d411707..59aade0 100644
--- a/tests/utils/recursive_import_test.dart
+++ b/tests/utils/recursive_import_test.dart
@@ -7,7 +7,6 @@
import "package:expect/expect.dart";
import 'dart:async';
import '../../sdk/lib/_internal/compiler/compiler.dart';
-import 'dart:uri';
const CORE_LIB = """
library core;
@@ -26,6 +25,7 @@
class Dynamic_ {}
class Type {}
class Null {}
+class StackTrace {}
class LinkedHashMap {}
getRuntimeTypeInfo(o) {}
setRuntimeTypeInfo(o, i) {}
@@ -103,9 +103,9 @@
}
Future<String> result =
- compile(new Uri.fromComponents(scheme: 'main'),
- new Uri.fromComponents(scheme: 'lib', path: '/'),
- new Uri.fromComponents(scheme: 'package', path: '/'),
+ compile(new Uri(scheme: 'main'),
+ new Uri(scheme: 'lib', path: '/'),
+ new Uri(scheme: 'package', path: '/'),
provider, handler);
result.then((String code) {
Expect.isNull(code);
diff --git a/tests/utils/utils.status b/tests/utils/utils.status
index c1aab5a..d8a3a34 100644
--- a/tests/utils/utils.status
+++ b/tests/utils/utils.status
@@ -23,9 +23,6 @@
# Skip until we stabilize language tests.
*: Skip
-[ $arch == arm ]
-*: Skip
-
[ $arch == simarm ]
*: Skip
diff --git a/tools/VERSION b/tools/VERSION
index 2be690f..0a54219 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -1,4 +1,4 @@
MAJOR 0
MINOR 5
-BUILD 11
-PATCH 1
+BUILD 12
+PATCH 0
diff --git a/tools/bots/compiler.py b/tools/bots/compiler.py
index fd34ac6..38c116b 100644
--- a/tools/bots/compiler.py
+++ b/tools/bots/compiler.py
@@ -23,7 +23,7 @@
DART2JS_BUILDER = (
r'dart2js-(linux|mac|windows)(-(jsshell))?-(debug|release)(-(checked|host-checked))?(-(host-checked))?(-(minified))?-?(\d*)-?(\d*)')
WEB_BUILDER = (
- r'dart2js-(ie9|ie10|ff|safari|chrome|chromeOnAndroid|opera)-(win7|win8|mac10\.8|mac10\.7|linux)(-(all|html))?(-(csp))?(-(\d+)-(\d+))?')
+ r'dart2js-(ie9|ie10|ff|safari|chrome|chromeOnAndroid|opera|drt)-(win7|win8|mac10\.8|mac10\.7|linux)(-(all|html))?(-(csp))?(-(\d+)-(\d+))?')
def GetBuildInfo(builder_name, is_buildbot):
@@ -80,14 +80,15 @@
else :
return None
- if system == 'windows':
- system = 'win7'
+ # We have both win7 and win8 bots, functionality is the same.
+ if system.startswith('win'):
+ system = 'windows'
# We have both 10.8 and 10.7 bots, functionality is the same.
if system == 'mac10.8' or system == 'mac10.7':
system = 'mac'
- if (system == 'win7' and platform.system() != 'Windows') or (
+ if (system == 'windows' and platform.system() != 'Windows') or (
system == 'mac' and platform.system() != 'Darwin') or (
system == 'linux' and platform.system() != 'Linux'):
print ('Error: You cannot emulate a buildbot with a platform different '
@@ -108,6 +109,31 @@
flags = [x for x in flags if not '=' in x]
return ('%s tests %s' % (name, ' '.join(flags))).strip()
+# TODO(ricow): remove this once we have browser controller drivers for all
+# supported platforms.
+def UseBrowserController(runtime, system):
+ supported_platforms = {
+ 'linux': ['ff', 'chromeOnAndroid', 'chrome'],
+ 'mac': [],
+ 'windows': []
+ }
+ # Platforms that we run on the fyi waterfall only.
+ fyi_supported_platforms = {
+ 'linux': [],
+ 'mac': ['safari'],
+ 'windows': []
+ }
+
+ if (runtime in supported_platforms[system]):
+ return True
+
+ if (os.environ.get('BUILDBOT_SCHEDULER') == "fyi-main" and
+ runtime in fyi_supported_platforms[system]):
+ return True
+
+ return False
+
+
IsFirstTestStepCall = True
def TestStep(name, mode, system, compiler, runtime, targets, flags):
step_name = TestStepName(name, flags)
@@ -120,10 +146,6 @@
user_test = os.environ.get('USER_TEST', 'no')
- # TODO(ricow): temporary hack to run on fyi with --use_browser_controller
- if os.environ.get('BUILDBOT_SCHEDULER') == "fyi-main" and runtime == 'drt':
- runtime = 'chrome'
-
cmd.extend([sys.executable,
os.path.join(os.curdir, 'tools', 'test.py'),
'--step_name=' + step_name,
@@ -135,18 +157,12 @@
'--report',
'--write-debug-log'])
- # TODO(ricow/kustermann): Issue 7339
- if runtime == "safari":
- cmd.append('--nobatch')
-
if user_test == 'yes':
cmd.append('--progress=color')
else:
cmd.extend(['--progress=buildbot', '-v'])
- # TODO(ricow): temporary hack to run on fyi with --use_browser_controller
- if (os.environ.get('BUILDBOT_SCHEDULER') == "fyi-main" and
- runtime in ['chrome', 'ff', 'chromeOnAndroid']):
+ if UseBrowserController(runtime, system):
cmd.append('--use_browser_controller')
global IsFirstTestStepCall
@@ -168,7 +184,7 @@
Args:
- runtime: either 'd8', 'jsshell', or one of the browsers, see GetBuildInfo
- mode: either 'debug' or 'release'
- - system: either 'linux', 'mac', 'win7', or 'win8'
+ - system: either 'linux', 'mac', 'windows'
- flags: extra flags to pass to test.dart
- is_buildbot: true if we are running on a real buildbot instead of
emulating one.
@@ -194,16 +210,13 @@
'Local', 'Google', 'Chrome', 'Application', 'chrome.exe')}
return path_dict[runtime]
- if system == 'linux' and runtime == 'chrome':
- # TODO(ngeoffray): We should install selenium on the buildbot.
- runtime = 'drt'
- elif (runtime == 'ff' or runtime == 'chrome') and is_buildbot:
+ if (runtime == 'ff' or runtime == 'chrome') and is_buildbot:
# Print out browser version numbers if we're running on the buildbot (where
# we know the paths to these browser installations).
version_query_string = '"%s" --version' % GetPath(runtime)
- if runtime == 'ff' and system.startswith('win'):
+ if runtime == 'ff' and system == 'windows':
version_query_string += '| more'
- elif runtime == 'chrome' and system.startswith('win'):
+ elif runtime == 'chrome' and system == 'windows':
version_query_string = ('''reg query "HKCU\\Software\\Microsoft\\''' +
'''Windows\\CurrentVersion\\Uninstall\\Google Chrome" /v Version''')
p = subprocess.Popen(version_query_string,
@@ -226,7 +239,7 @@
TestStep("dart2js_unit", mode, system, 'none', 'vm', ['dart2js'],
unit_test_flags)
- if system.startswith('win') and runtime.startswith('ie10'):
+ if system == 'windows' and runtime == 'ie10':
TestStep("dart2js", mode, system, 'dart2js', runtime, ['html'], flags)
else:
# Run the default set of test suites.
@@ -268,10 +281,10 @@
behavior has not been reproduced outside of the buildbots.
Args:
- - system: either 'linux', 'mac', 'win7', or 'win8'
+ - system: either 'linux', 'mac', 'windows'
- browser: one of the browsers, see GetBuildInfo
"""
- if system.startswith('win'):
+ if system == 'windows':
temp_dir = 'C:\\Users\\chrome-bot\\AppData\\Local\\Temp'
for name in os.listdir(temp_dir):
fullname = os.path.join(temp_dir, name)
@@ -290,7 +303,7 @@
# on the slow (all) IE windows bots. This is a hack and we should use the
# normal sharding and checked splitting functionality when we get more
# vms for testing this.
- if (build_info.system == 'linux' and build_info.runtime == 'chrome'):
+ if (build_info.system == 'linux' and build_info.runtime == 'drt'):
return True
if build_info.runtime.startswith('ie') and build_info.test_set == 'all':
return True
diff --git a/tools/bots/cross-vm.py b/tools/bots/cross-vm.py
index e58c6c0..54d43c1 100644
--- a/tools/bots/cross-vm.py
+++ b/tools/bots/cross-vm.py
@@ -7,7 +7,6 @@
import re
import shutil
import sys
-import tempfile
import bot
@@ -26,64 +25,134 @@
sys.stdout.flush()
bot.RunProcess(args)
-def main():
- name, is_buildbot = bot.GetBotName()
+def tarball_name(arch, mode):
+ return 'cross_build_%s_%s.tar.bz2' % (arch, mode)
+
+def record_names(name, arch, mode):
+ return ('record_%s_%s_%s.json' % (name, arch, mode),
+ 'record_output_%s_%s_%s.json' % (name, arch, mode))
+
+def cross_compiling_builder(arch, mode):
build_py = os.path.join('tools', 'build.py')
test_py = os.path.join('tools', 'test.py')
+ test_args = [sys.executable, test_py, '--progress=line', '--report',
+ '--time', '--compiler=none', '--runtime=vm', '--write-debug-log']
+
+ tarball = tarball_name(arch, mode)
+ (recording, recording_out) = record_names('tests', arch, mode)
+ (checked_recording, checked_recording_out) = record_names(
+ 'checked_tests', arch, mode)
+
+ temporary_files = [tarball, recording, recording_out, checked_recording,
+ checked_recording_out]
+ bot.Clobber()
+ try:
+ num_run = int(os.environ['BUILDBOT_ANNOTATED_STEPS_RUN'])
+ if num_run == 1:
+ with bot.BuildStep('Build %s %s' % (arch, mode)):
+ args = [sys.executable, build_py,
+ '-m%s' % mode, '--arch=%s' % arch, 'runtime']
+
+ run(args)
+ with bot.BuildStep('Create build tarball'):
+ run(['tar', '-cjf', tarball, '--exclude=**/obj',
+ '--exclude=**/obj.host', '--exclude=**/obj.target',
+ '--exclude=**/*analyzer*', '--exclude=**/*IA32', 'out/'])
+
+ with bot.BuildStep('Upload build tarball'):
+ uri = "%s/%s" % (GCS_BUCKET, tarball)
+ run([GSUTIL, 'cp', tarball, uri])
+ run([GSUTIL, 'setacl', 'public-read', uri])
+
+ with bot.BuildStep('prepare tests'):
+ uri = "%s/%s" % (GCS_BUCKET, recording)
+ run(test_args + ['--mode=' + mode, '--arch=' + arch,
+ '--record_to_file=' + recording])
+ run([GSUTIL, 'cp', recording, uri])
+ run([GSUTIL, 'setacl', 'public-read', uri])
+
+ with bot.BuildStep('prepare checked_tests'):
+ uri = "%s/%s" % (GCS_BUCKET, checked_recording)
+ run(test_args + ['--mode=' + mode, '--arch=' + arch, '--checked',
+ '--record_to_file=' + checked_recording])
+ run([GSUTIL, 'cp', checked_recording, uri])
+ run([GSUTIL, 'setacl', 'public-read', uri])
+ elif num_run == 2:
+ with bot.BuildStep('tests'):
+ uri = "%s/%s" % (GCS_BUCKET, recording_out)
+ run([GSUTIL, 'cp', uri, recording_out])
+ run(test_args + ['--mode=' + mode, '--arch=' + arch,
+ '--replay_from_file=' + recording_out])
+
+ with bot.BuildStep('checked_tests'):
+ uri = "%s/%s" % (GCS_BUCKET, checked_recording_out)
+ run([GSUTIL, 'cp', uri, checked_recording_out])
+ run(test_args + ['--mode=' + mode, '--arch=' + arch, '--checked',
+ '--replay_from_file=' + checked_recording_out])
+ else:
+ raise Exception("Invalid annotated steps run")
+ finally:
+ for path in temporary_files:
+ if os.path.exists(path):
+ os.remove(path)
+
+def target_builder(arch, mode):
+ execute_testcases_py = os.path.join('tools', 'execute_recorded_testcases.py')
+
+ tarball = tarball_name(arch, mode)
+ (recording, recording_out) = record_names('tests', arch, mode)
+ (checked_recording, checked_recording_out) = record_names(
+ 'checked_tests', arch, mode)
+
+ temporary_files = [tarball, recording, recording_out, checked_recording,
+ checked_recording_out]
+ bot.Clobber()
+ try:
+ with bot.BuildStep('Fetch build tarball'):
+ run([GSUTIL, 'cp', "%s/%s" % (GCS_BUCKET, tarball), tarball])
+
+ with bot.BuildStep('Unpack build tarball'):
+ run(['tar', '-xjf', tarball])
+
+ with bot.BuildStep('execute tests'):
+ uri = "%s/%s" % (GCS_BUCKET, recording)
+ uri_out = "%s/%s" % (GCS_BUCKET, recording_out)
+ run([GSUTIL, 'cp', uri, recording])
+ run(['python', execute_testcases_py, recording, recording_out])
+ run([GSUTIL, 'cp', recording_out, uri_out])
+ run([GSUTIL, 'setacl', 'public-read', uri_out])
+
+ with bot.BuildStep('execute checked_tests'):
+ uri = "%s/%s" % (GCS_BUCKET, checked_recording)
+ uri_out = "%s/%s" % (GCS_BUCKET, checked_recording_out)
+ run([GSUTIL, 'cp', uri, checked_recording])
+ run(['python', execute_testcases_py, checked_recording,
+ checked_recording_out])
+ run([GSUTIL, 'cp', recording_out, uri_out])
+ run([GSUTIL, 'setacl', 'public-read', uri_out])
+ finally:
+ for path in temporary_files:
+ if os.path.exists(path):
+ os.remove(path)
+
+def main():
+ name, is_buildbot = bot.GetBotName()
cross_vm_pattern_match = re.match(CROSS_VM, name)
target_vm_pattern_match = re.match(TARGET_VM, name)
if cross_vm_pattern_match:
arch = cross_vm_pattern_match.group(1)
mode = cross_vm_pattern_match.group(2)
-
- bot.Clobber()
- with bot.BuildStep('Build %s %s' % (arch, mode)):
- args = [sys.executable, build_py,
- '-m%s' % mode, '--arch=%s' % arch, 'runtime']
- run(args)
-
- tarball = 'cross_build_%s_%s.tar.bz2' % (arch, mode)
- try:
- with bot.BuildStep('Create build tarball'):
- run(['tar', '-cjf', tarball, '--exclude=**/obj',
- '--exclude=**/obj.host', '--exclude=**/obj.target',
- '--exclude=**/*analyzer*', 'out/'])
-
- with bot.BuildStep('Upload build tarball'):
- uri = "%s/%s" % (GCS_BUCKET, tarball)
- run([GSUTIL, 'cp', tarball, uri])
- run([GSUTIL, 'setacl', 'public-read', uri])
- finally:
- if os.path.exists(tarball):
- os.remove(tarball)
+ cross_compiling_builder(arch, mode)
elif target_vm_pattern_match:
arch = target_vm_pattern_match.group(1)
mode = target_vm_pattern_match.group(2)
-
- bot.Clobber()
- tarball = 'cross_build_%s_%s.tar.bz2' % (arch, mode)
- try:
- test_args = [sys.executable, test_py, '--progress=line', '--report',
- '--time', '--mode=' + mode, '--arch=' + arch, '--compiler=none',
- '--runtime=vm', '--write-debug-log']
-
- with bot.BuildStep('Fetch build tarball'):
- run([GSUTIL, 'cp', "%s/%s" % (GCS_BUCKET, tarball), tarball])
-
- with bot.BuildStep('Unpack build tarball'):
- run(['tar', '-xjf', tarball])
-
- with bot.BuildStep('tests'):
- run(test_args)
-
- with bot.BuildStep('checked_tests'):
- run(test_args + ['--checked'])
- finally:
- if os.path.exists(tarball):
- os.remove(tarball)
+ target_builder(arch, mode)
else:
raise Exception("Unknown builder name %s" % name)
if __name__ == '__main__':
- sys.exit(main())
+ try:
+ sys.exit(main())
+ except OSError as e:
+ sys.exit(e.errno)
diff --git a/tools/create_sdk.py b/tools/create_sdk.py
index c2c5cd0..d157268 100755
--- a/tools/create_sdk.py
+++ b/tools/create_sdk.py
@@ -38,7 +38,6 @@
# ......math/
# ......mdv_observe_impl/
# ......mirrors/
-# ......uri/
# ......utf/
# ......typed_data/
# ....packages/
@@ -205,7 +204,7 @@
os.makedirs(LIB)
#
- # Create and populate lib/{core, crypto, isolate, json, uri, utf, ...}.
+ # Create and populate lib/{core, crypto, isolate, json, utf, ...}.
#
os.makedirs(join(LIB, 'html'))
@@ -221,7 +220,7 @@
join('indexed_db', 'dart2js'), join('indexed_db', 'dartium'),
'json', 'math', 'mdv_observe_impl', 'mirrors', 'typed_data',
join('svg', 'dart2js'), join('svg', 'dartium'),
- 'uri', 'utf',
+ 'utf',
join('web_audio', 'dart2js'), join('web_audio', 'dartium'),
join('web_gl', 'dart2js'), join('web_gl', 'dartium'),
join('web_sql', 'dart2js'), join('web_sql', 'dartium')]:
diff --git a/tools/dom/docs/docs.json b/tools/dom/docs/docs.json
index 4a34c77..3ba329e 100644
--- a/tools/dom/docs/docs.json
+++ b/tools/dom/docs/docs.json
@@ -590,12 +590,12 @@
" *",
" * var request = new HttpRequest();",
" * request.open('GET', 'http://dartlang.org')",
- " * request.on.load.add((event) => print('Request complete'));",
+ " * request.onLoad.add((event) => print('Request complete'));",
" *",
" * is the (more verbose) equivalent of",
" *",
- " * var request = new HttpRequest.get('http://dartlang.org',",
- " * (event) => print('Request complete'));",
+ " * HttpRequest.getString('http://dartlang.org').then(",
+ " * (result) => print('Request complete: $result'));",
" */"
]
}
diff --git a/tools/dom/dom.json b/tools/dom/dom.json
index 4c2dc62..c01a78f 100644
--- a/tools/dom/dom.json
+++ b/tools/dom/dom.json
@@ -115,6 +115,7 @@
"AudioContext": {
"comment": "https://dvcs.w3.org/hg/audio/raw-file/tip/webaudio/specification.html#AudioContext-section",
"members": {
+ "AudioContext": {},
"activeSourceCount": {},
"createAnalyser": {},
"createBiquadFilter": {},
@@ -280,6 +281,7 @@
"Blob": {
"comment": "http://www.w3.org/TR/FileAPI/#dfn-Blob",
"members": {
+ "Blob": {},
"size": {},
"slice": {},
"type": {}
@@ -1062,6 +1064,9 @@
"comment": "http://www.w3.org/TR/XMLHttpRequest2/#interface-formdata",
"members": {
"DOMFormData": {},
+ "FormData": {
+ "support_level": "untriaged"
+ },
"append": {}
},
"support_level": "stable"
@@ -1151,6 +1156,9 @@
"comment": "http://developer.apple.com/library/safari/#documentation/DataManagement/Reference/DOMWindowAdditionsReference/DOMWindowAdditions/DOMWindowAdditions.html",
"members": {
"DOMPoint": {},
+ "_DomPoint": {
+ "support_level": "untriaged"
+ },
"x": {},
"y": {}
},
@@ -5653,6 +5661,7 @@
"MutationObserver": {
"comment": "http://www.w3.org/TR/domcore/#interface-mutationobserver",
"members": {
+ "MutationObserver": {},
"_observe": {},
"disconnect": {},
"observe": {},
@@ -11593,6 +11602,9 @@
"members": {
"DONE": {},
"HEADERS_RECEIVED": {},
+ "HttpRequest": {
+ "support_level": "untriaged"
+ },
"LOADING": {},
"OPENED": {},
"UNSENT": {},
diff --git a/tools/dom/dom.py b/tools/dom/dom.py
index 793764c..f4a5c85 100755
--- a/tools/dom/dom.py
+++ b/tools/dom/dom.py
@@ -183,7 +183,8 @@
'test_docs': [test_docs, 'Tests docs.dart'],
'test_chrome': [test_chrome, 'Run tests in checked mode in Chrome.\n'
'\t\tOptionally provide name of test to run.'],
- 'test_drt': [test_drt, 'Run tests in checked mode in DumpRenderTree.\n'
+ # TODO(antonm): fix option name.
+ 'test_drt': [test_drt, 'Run tests in checked mode in content shell.\n'
'\t\tOptionally provide name of test to run.'],
'test_ff': [test_ff, 'Run tests in checked mode in Firefox.\n'
'\t\tOptionally provide name of test to run.'],
diff --git a/tools/dom/scripts/generator.py b/tools/dom/scripts/generator.py
index 17db760..73bf90e 100644
--- a/tools/dom/scripts/generator.py
+++ b/tools/dom/scripts/generator.py
@@ -84,6 +84,12 @@
'NodeList': 'NodeList,RadioNodeList',
+ 'RTCPeerConnection': 'RTCPeerConnection,mozRTCPeerConnection',
+
+ 'RTCIceCandidate': 'RTCIceCandidate,mozRTCIceCandidate',
+
+ 'RTCSessionDescription': 'RTCSessionDescription,mozRTCSessionDescription',
+
'TransitionEvent': 'TransitionEvent,WebKitTransitionEvent',
'WheelEvent': 'WheelEvent,MouseWheelEvent,MouseScrollEvent',
@@ -357,6 +363,12 @@
right_bracket)
return ', '.join(argtexts)
+ def NumberOfRequiredInDart(self):
+ """ Returns a number of required arguments in Dart declaration of
+ the operation.
+ """
+ return len(filter(lambda i: not i.is_optional, self.param_infos))
+
def ParametersAsArgumentList(self, parameter_count=None):
"""Returns a string of the parameter names suitable for passing the
parameters as arguments.
diff --git a/tools/dom/scripts/htmldartgenerator.py b/tools/dom/scripts/htmldartgenerator.py
index 266bc20..26aab5a 100644
--- a/tools/dom/scripts/htmldartgenerator.py
+++ b/tools/dom/scripts/htmldartgenerator.py
@@ -198,14 +198,17 @@
self.EmitOperation(info, method_name)
def _GenerateOverloadDispatcher(self,
+ info,
signatures,
is_void,
- parameter_names,
declaration,
generate_call,
is_optional,
can_omit_type_check=lambda type, pos: False):
+ parameter_names = [p.name for p in info.param_infos]
+ number_of_required_in_dart = info.NumberOfRequiredInDart()
+
body_emitter = self._members_emitter.Emit(
'\n'
' $DECLARATION {\n'
@@ -246,13 +249,8 @@
elif not can_omit_type_check(test_type, i):
checks.append('(%s is %s || %s == null)' % (
parameter_name, test_type, parameter_name))
- else:
- for signature in signatures:
- if (len(signature) <= i or signature[i].id not in
- parameter_name.split('_OR_')):
-
- checks.append('?%s' % parameter_name)
- break
+ elif i >= number_of_required_in_dart:
+ checks.append('?%s' % parameter_name)
# There can be multiple presence checks. We need them all since a later
# optional argument could have been passed by name, leaving 'holes'.
@@ -307,8 +305,8 @@
GenerateCall(0, argument_count, [])
def _GenerateDispatcherBody(self,
+ info,
operations,
- parameter_names,
declaration,
generate_call,
is_optional,
@@ -324,9 +322,9 @@
return is_optional(operations[signature_index], argument)
self._GenerateOverloadDispatcher(
+ info,
[operation.arguments for operation in operations],
operations[0].type.id == 'void',
- parameter_names,
declaration,
GenerateCall,
IsOptional,
@@ -437,9 +435,9 @@
constructor_full_name = constructor_info._ConstructorFullName(
self._DartType)
self._GenerateOverloadDispatcher(
+ constructor_info,
constructor_info.idl_args,
False,
- [info.name for info in constructor_info.param_infos],
emitter.Format('$(METADATA)$FACTORY_KEYWORD $CTOR($PARAMS)',
FACTORY_KEYWORD=('factory' if not custom_factory_ctr else
'static %s' % constructor_full_name),
diff --git a/tools/dom/scripts/systemhtml.py b/tools/dom/scripts/systemhtml.py
index ada9609..9c75488 100644
--- a/tools/dom/scripts/systemhtml.py
+++ b/tools/dom/scripts/systemhtml.py
@@ -1012,8 +1012,8 @@
html_name,
info.ParametersDeclaration(InputType))
self._GenerateDispatcherBody(
+ info,
operations,
- parameter_names,
declaration,
GenerateCall,
lambda _, argument: IsOptional(argument),
diff --git a/tools/dom/scripts/systemnative.py b/tools/dom/scripts/systemnative.py
index fb659f4..9b4b677 100644
--- a/tools/dom/scripts/systemnative.py
+++ b/tools/dom/scripts/systemnative.py
@@ -241,8 +241,12 @@
if 'CustomConstructor' not in self._interface.ext_attrs:
return False
+ annotations = self._metadata.GetFormattedMetadata(self._library_name,
+ self._interface, self._interface.id, ' ')
+
self._members_emitter.Emit(
- ' factory $CTOR($PARAMS) => _create($FACTORY_PARAMS);\n',
+ '\n $(ANNOTATIONS)factory $CTOR($PARAMS) => _create($FACTORY_PARAMS);\n',
+ ANNOTATIONS=annotations,
CTOR=constructor_info._ConstructorFullName(self._DartType),
PARAMS=constructor_info.ParametersDeclaration(self._DartType),
FACTORY_PARAMS= \
@@ -557,14 +561,15 @@
if not is_custom:
self._GenerateOperationNativeCallback(operation, operation.arguments, cpp_callback_name)
else:
- self._GenerateDispatcher(info.operations, dart_declaration, [info.name for info in info.param_infos])
+ self._GenerateDispatcher(info, info.operations, dart_declaration)
- def _GenerateDispatcher(self, operations, dart_declaration, parameter_names):
+ def _GenerateDispatcher(self, info, operations, dart_declaration):
def GenerateCall(
stmts_emitter, call_emitter, version, operation, argument_count):
overload_name = '_%s_%s' % (operation.id, version)
- argument_list = ', '.join(parameter_names[:argument_count])
+ argument_list = ', '.join(
+ [p.name for p in info.param_infos[:argument_count]])
call_emitter.Emit('$NAME($ARGS)', NAME=overload_name, ARGS=argument_list)
dart_declaration = '%s%s %s(%s)' % (
@@ -577,8 +582,8 @@
self._GenerateOperationNativeCallback(operation, operation.arguments[:argument_count], cpp_callback_name)
self._GenerateDispatcherBody(
+ info,
operations,
- parameter_names,
dart_declaration,
GenerateCall,
self._IsArgumentOptionalInWebCore)
diff --git a/tools/dom/src/AttributeMap.dart b/tools/dom/src/AttributeMap.dart
index 6c96bc9..b0cb0cc 100644
--- a/tools/dom/src/AttributeMap.dart
+++ b/tools/dom/src/AttributeMap.dart
@@ -70,6 +70,11 @@
}
/**
+ * Returns true if there is at least one {key, value} pair in the map.
+ */
+ bool get isNotEmpty => !isEmpty;
+
+ /**
* Checks to see if the node should be included in this map.
*/
bool _matches(Node node);
@@ -216,6 +221,8 @@
// TODO: Use lazy iterator when it is available on Map.
bool get isEmpty => length == 0;
+ bool get isNotEmpty => !isEmpty;
+
// Helpers.
String _attr(String key) => 'data-$key';
bool _matches(String key) => key.startsWith('data-');
diff --git a/tools/dom/src/EventStreamProvider.dart b/tools/dom/src/EventStreamProvider.dart
index 303a4e8..d19ab14 100644
--- a/tools/dom/src/EventStreamProvider.dart
+++ b/tools/dom/src/EventStreamProvider.dart
@@ -117,6 +117,9 @@
/**
* Gets a [Stream] for this event type, on the specified target.
*
+ * This will always return a broadcast stream so multiple listeners can be
+ * used simultaneously.
+ *
* This may be used to capture DOM events:
*
* Element.keyDownEvent.forTarget(element, useCapture: true).listen(...);
diff --git a/tools/dom/src/PathObserver.dart b/tools/dom/src/PathObserver.dart
index bf687cb..b0eda5f 100644
--- a/tools/dom/src/PathObserver.dart
+++ b/tools/dom/src/PathObserver.dart
@@ -72,7 +72,8 @@
// TODO(jmesserly): if the path is empty, or the object is! Observable, we
// can optimize the PathObserver to be more lightweight.
- _values = new StreamController(onListen: _observe, onCancel: _unobserve);
+ _values = new StreamController.broadcast(onListen: _observe,
+ onCancel: _unobserve);
if (_isValid) {
var segments = [];
diff --git a/tools/dom/src/native_DOMImplementation.dart b/tools/dom/src/native_DOMImplementation.dart
index 9b1233b..65c918e 100644
--- a/tools/dom/src/native_DOMImplementation.dart
+++ b/tools/dom/src/native_DOMImplementation.dart
@@ -139,6 +139,7 @@
Iterable<String> get values => Maps.getValues(this);
int get length => Maps.length(this);
bool get isEmpty => Maps.isEmpty(this);
+ bool get isNotEmpty => Maps.isNotEmpty(this);
}
final Future<SendPort> __HELPER_ISOLATE_PORT =
diff --git a/tools/dom/templates/html/dart2js/html_dart2js.darttemplate b/tools/dom/templates/html/dart2js/html_dart2js.darttemplate
index 2a20d31..64629ed 100644
--- a/tools/dom/templates/html/dart2js/html_dart2js.darttemplate
+++ b/tools/dom/templates/html/dart2js/html_dart2js.darttemplate
@@ -74,7 +74,7 @@
HtmlDocument get document => JS('HtmlDocument', 'document');
Element query(String selector) => document.query(selector);
-List<Element> queryAll(String selector) => document.queryAll(selector);
+ElementList queryAll(String selector) => document.queryAll(selector);
// Workaround for tags like <cite> that lack their own Element subclass --
// Dart issue 1990.
diff --git a/tools/dom/templates/html/dart2js/impl_RTCIceCandidate.darttemplate b/tools/dom/templates/html/dart2js/impl_RTCIceCandidate.darttemplate
index ce3ebd7..6090f90 100644
--- a/tools/dom/templates/html/dart2js/impl_RTCIceCandidate.darttemplate
+++ b/tools/dom/templates/html/dart2js/impl_RTCIceCandidate.darttemplate
@@ -6,7 +6,13 @@
$(ANNOTATIONS)class $CLASSNAME$EXTENDS$IMPLEMENTS$NATIVESPEC {
factory $CLASSNAME(Map dictionary) {
- return JS('RtcIceCandidate', 'new RTCIceCandidate(#)',
+ // TODO(efortuna): Remove this check if when you can actually construct with
+ // the unprefixed RTCIceCandidate in Firefox (currently both are defined,
+ // but one can't be used as a constructor).
+ var constructorName = JS('', 'window[#]',
+ Device.isFirefox ? '${Device.propertyPrefix}RTCIceCandidate' :
+ 'RTCIceCandidate');
+ return JS('RtcIceCandidate', 'new #(#)', constructorName,
convertDartToNative_SerializedScriptValue(dictionary));
}
$!MEMBERS
diff --git a/tools/dom/templates/html/dart2js/impl_RTCSessionDescription.darttemplate b/tools/dom/templates/html/dart2js/impl_RTCSessionDescription.darttemplate
index f9b879e..6dd65b4 100644
--- a/tools/dom/templates/html/dart2js/impl_RTCSessionDescription.darttemplate
+++ b/tools/dom/templates/html/dart2js/impl_RTCSessionDescription.darttemplate
@@ -6,7 +6,14 @@
$(ANNOTATIONS)class $CLASSNAME$EXTENDS$IMPLEMENTS$NATIVESPEC {
factory $CLASSNAME(Map dictionary) {
- return JS('RtcSessionDescription', 'new RTCSessionDescription(#)',
+ // TODO(efortuna): Remove this check if when you can actually construct with
+ // the unprefixed RTCIceCandidate in Firefox (currently both are defined,
+ // but one can't be used as a constructor).
+ var constructorName = JS('', 'window[#]',
+ Device.isFirefox ? '${Device.propertyPrefix}RTCSessionDescription' :
+ 'RTCSessionDescription');
+ return JS('RtcSessionDescription',
+ 'new #(#)', constructorName,
convertDartToNative_SerializedScriptValue(dictionary));
}
$!MEMBERS
diff --git a/tools/dom/templates/html/dartium/html_dartium.darttemplate b/tools/dom/templates/html/dartium/html_dartium.darttemplate
index 3e020a0..24323cb 100644
--- a/tools/dom/templates/html/dartium/html_dartium.darttemplate
+++ b/tools/dom/templates/html/dartium/html_dartium.darttemplate
@@ -80,7 +80,7 @@
Element query(String selector) => document.query(selector);
-List<Element> queryAll(String selector) => document.queryAll(selector);
+ElementList queryAll(String selector) => document.queryAll(selector);
int _getNewIsolateId() => _Utils._getNewIsolateId();
diff --git a/tools/dom/templates/html/impl/impl_IDBFactory.darttemplate b/tools/dom/templates/html/impl/impl_IDBFactory.darttemplate
index 842b6f4..6b2501b 100644
--- a/tools/dom/templates/html/impl/impl_IDBFactory.darttemplate
+++ b/tools/dom/templates/html/impl/impl_IDBFactory.darttemplate
@@ -56,7 +56,14 @@
if (onBlocked != null) {
request.onBlocked.listen(onBlocked);
}
- return _completeRequest(request);
+ var completer = new Completer.sync();
+ request.onSuccess.listen((e) {
+ completer.complete(this);
+ });
+ request.onError.listen((e) {
+ completer.completeError(e);
+ });
+ return completer.future;
} catch (e, stacktrace) {
return new Future.error(e, stacktrace);
}
diff --git a/tools/dom/templates/html/impl/impl_RTCPeerConnection.darttemplate b/tools/dom/templates/html/impl/impl_RTCPeerConnection.darttemplate
index 46dcc37..1184bd0 100644
--- a/tools/dom/templates/html/impl/impl_RTCPeerConnection.darttemplate
+++ b/tools/dom/templates/html/impl/impl_RTCPeerConnection.darttemplate
@@ -29,11 +29,12 @@
// Currently in Firefox some of the RTC elements are defined but throw an
// error unless the user has specifically enabled them in their
// about:config. So we have to construct an element to actually test if RTC
- // is supported at at the given time.
+ // is supported at the given time.
try {
- var c = new RtcPeerConnection({"iceServers": [ {"url":"stun:foo.com"}]});
- return c is RtcPeerConnection;
- } catch (_) {}
+ new RtcPeerConnection(
+ {"iceServers": [ {"url":"stun:localhost"}]});
+ return true;
+ } catch (_) { return false;}
return false;
}
$else
@@ -56,5 +57,3 @@
}
$!MEMBERS
}
-
-
diff --git a/tools/dom/templates/html/impl/impl_Storage.darttemplate b/tools/dom/templates/html/impl/impl_Storage.darttemplate
index d043abe..b454b53 100644
--- a/tools/dom/templates/html/impl/impl_Storage.darttemplate
+++ b/tools/dom/templates/html/impl/impl_Storage.darttemplate
@@ -78,5 +78,7 @@
int get length => $dom_length;
bool get isEmpty => $dom_key(0) == null;
+
+ bool get isNotEmpty => !isEmpty;
$!MEMBERS
}
diff --git a/tools/execute_recorded_testcases.py b/tools/execute_recorded_testcases.py
new file mode 100755
index 0000000..f307277
--- /dev/null
+++ b/tools/execute_recorded_testcases.py
@@ -0,0 +1,67 @@
+#!/usr/bin/env python
+
+import sys
+import json
+import subprocess
+import time
+import threading
+
+def run_command(name, executable, arguments, timeout_in_seconds):
+ print "Running %s: '%s'" % (name, [executable] + arguments)
+
+ # The timeout_handler will set this to True if the command times out.
+ timeout_value = {'did_timeout' : False}
+
+ start = time.time()
+
+ process = subprocess.Popen([executable] + arguments,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+ def timeout_handler():
+ timeout_value['did_timeout'] = True
+ process.kill()
+ timer = threading.Timer(timeout_in_seconds, timeout_handler)
+ timer.start()
+
+ stdout, stderr = process.communicate()
+ exit_code = process.wait()
+ timer.cancel()
+
+ end = time.time()
+
+ return (exit_code, stdout, stderr, end - start, timeout_value['did_timeout'])
+
+def main(args):
+ recording_file = args[0]
+ result_file = args[1]
+
+ with open(recording_file) as fd:
+ test_cases = json.load(fd)
+
+ for test_case in test_cases:
+ name = test_case['name']
+ command = test_case['command']
+ executable = command['executable']
+ arguments = command['arguments']
+ timeout_limit = command['timeout_limit']
+
+ exit_code, stdout, stderr, duration, did_timeout = (
+ run_command(name, executable, arguments, timeout_limit))
+
+ test_case['command_output'] = {
+ 'exit_code' : exit_code,
+ 'stdout' : stdout,
+ 'stderr' : stderr,
+ 'duration' : duration,
+ 'did_timeout' : did_timeout,
+ }
+ with open(result_file, 'w') as fd:
+ json.dump(test_cases, fd)
+
+if __name__ == '__main__':
+ if len(sys.argv) != 3:
+ print >> sys.stderr, ("Usage: %s <input-file.json> <output-file.json>"
+ % sys.argv[0])
+ sys.exit(1)
+ sys.exit(main(sys.argv[1:]))
+
diff --git a/tools/get_archive.py b/tools/get_archive.py
index e919267..e7ab03d 100755
--- a/tools/get_archive.py
+++ b/tools/get_archive.py
@@ -4,7 +4,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.
-# Gets or updates a DumpRenderTree (a nearly headless build of chrome). This is
+# Gets or updates a content shell (a nearly headless build of chrome). This is
# used for running browser tests of client applications.
import json
@@ -113,7 +113,7 @@
if not HasBotoConfig():
print >>sys.stderr, '''
*******************************************************************************
-* WARNING: Can't download DumpRenderTree! This is required to test client apps.
+* WARNING: Can't download content shell! This is required to test client apps.
* You need to do a one-time configuration step to access Google Storage.
* Please run this command and follow the instructions:
* %s config
@@ -347,7 +347,7 @@
GetSdkRevision('sdk', SDK_DIR, SDK_VERSION, SDK_LATEST_PATTERN,
SDK_PERMANENT, args.revision)
elif positional[0] == 'drt':
- GetDartiumRevision('DumpRenderTree', DRT_DIR, DRT_VERSION,
+ GetDartiumRevision('content_shell', DRT_DIR, DRT_VERSION,
DRT_LATEST_PATTERN, DRT_PERMANENT_PATTERN,
args.revision)
CopyDrtFont(DRT_DIR)
diff --git a/tools/test.dart b/tools/test.dart
index 089a721..781ae2c 100755
--- a/tools/test.dart
+++ b/tools/test.dart
@@ -26,11 +26,12 @@
import "dart:async";
import "dart:io";
-import "testing/dart/test_runner.dart";
-import "testing/dart/test_options.dart";
-import "testing/dart/test_suite.dart";
-import "testing/dart/test_progress.dart";
import "testing/dart/http_server.dart";
+import "testing/dart/record_and_replay.dart";
+import "testing/dart/test_options.dart";
+import "testing/dart/test_progress.dart";
+import "testing/dart/test_runner.dart";
+import "testing/dart/test_suite.dart";
import "testing/dart/utils.dart";
import "../compiler/tests/dartc/test_config.dart";
@@ -87,6 +88,27 @@
var printTiming = firstConf['time'];
var listTests = firstConf['list'];
+ var recordingPath = firstConf['record_to_file'];
+ var recordingOutputPath = firstConf['replay_from_file'];
+
+ if (recordingPath != null && recordingOutputPath != null) {
+ print("Fatal: Can't have the '--record_to_file' and '--replay_from_file'"
+ "at the same time. Exiting ...");
+ exit(1);
+ }
+
+ var testCaseRecorder;
+ if (recordingPath != null) {
+ testCaseRecorder = new TestCaseRecorder(new Path(recordingPath));
+ }
+
+ var testCaseOutputArchive;
+ if (recordingOutputPath != null) {
+ testCaseOutputArchive = new TestCaseOutputArchive();
+ testCaseOutputArchive.loadFromPath(new Path(recordingOutputPath));
+ }
+
+
if (!firstConf['append_logs']) {
var file = new File(TestUtils.flakyFileName());
if (file.existsSync()) {
@@ -145,9 +167,16 @@
if (key == 'co19') {
testSuites.add(new Co19TestSuite(conf));
} else if (conf['runtime'] == 'vm' && key == 'vm') {
- // vm tests contain both cc tests (added here) and dart tests (added in
- // [TEST_SUITE_DIRECTORIES]).
- testSuites.add(new VMTestSuite(conf));
+ // TODO(kustermann): Currently we don't support running VM unittest
+ // tests (i.e. run_vm_tests) on ARM because:
+ // a) we currently use record&replay [test.dart cannot be used on ARM]
+ // b) we cannot easily determine all the VM test names
+ // [we would need to run 'run_vm_tests --list' on ARM]
+ if (!['arm', 'mips'].contains(conf['arch'])) {
+ // vm tests contain both cc tests (added here) and dart tests (added
+ // in [TEST_SUITE_DIRECTORIES]).
+ testSuites.add(new VMTestSuite(conf));
+ }
} else if (conf['analyzer']) {
if (key == 'dartc' && conf['compiler'] == 'dartc') {
testSuites.add(new JUnitDartcTestSuite(conf));
@@ -216,6 +245,7 @@
}
eventListener.add(new ExitCodeSetter());
+
void startProcessQueue() {
// Start process queue.
new ProcessQueue(maxProcesses,
@@ -225,7 +255,9 @@
eventListener,
allTestsFinished,
verbose,
- listTests);
+ listTests,
+ testCaseRecorder,
+ testCaseOutputArchive);
}
// Start all the HTTP servers required before starting the process queue.
diff --git a/tools/testing/dart/browser_controller.dart b/tools/testing/dart/browser_controller.dart
index 911d86d..9b5e966 100644
--- a/tools/testing/dart/browser_controller.dart
+++ b/tools/testing/dart/browser_controller.dart
@@ -37,6 +37,8 @@
*/
Process process;
+ Function logger;
+
/**
* Id of the browser
*/
@@ -46,11 +48,15 @@
Function onClose;
/** Print everything (stdout, stderr, usageLog) whenever we add to it */
- bool debugPrint = true;
+ bool debugPrint = false;
+
+ // We use this to gracefully handle double calls to close.
+ bool underTermination = false;
void _logEvent(String event) {
String toLog = "$this ($id) - ${new DateTime.now()}: $event \n";
if (debugPrint) print("usageLog: $toLog");
+ if (logger != null) logger(toLog);
_usageLog.write(toLog);
}
@@ -119,6 +125,11 @@
/** Close the browser */
Future<bool> close() {
_logEvent("Close called on browser");
+ if (underTermination) {
+ _logEvent("Browser already under termination.");
+ return new Future.immediate(true);
+ }
+ underTermination = true;
if (process == null) {
_logEvent("No process open, nothing to kill.");
return new Future.immediate(true);
@@ -178,6 +189,102 @@
Future<bool> start(String url);
}
+class Safari extends Browser {
+ /**
+ * The binary used to run safari - changing this can be nececcary for
+ * testing or using non standard safari installation.
+ */
+ const String binary = "/Applications/Safari.app/Contents/MacOS/Safari";
+
+ /**
+ * We get the safari version by parsing a version file
+ */
+ const String versionFile = "/Applications/Safari.app/Contents/version.plist";
+
+
+ Future<bool> allowPopUps() {
+ var command = "defaults";
+ var args = ["write", "com.apple.safari",
+ "com.apple.Safari.ContentPageGroupIdentifier."
+ "WebKit2JavaScriptCanOpenWindowsAutomatically",
+ "1"];
+ return Process.run(command, args).then((result) {
+ if (result.exitCode != 0) {
+ _logEvent("Could not disable pop-up blocking for safari");
+ return false;
+ }
+ return true;
+ });
+ }
+
+ Future<String> getVersion() {
+ /**
+ * Example of the file:
+ * <?xml version="1.0" encoding="UTF-8"?>
+ * <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+ * <plist version="1.0">
+ * <dict>
+ * <key>BuildVersion</key>
+ * <string>2</string>
+ * <key>CFBundleShortVersionString</key>
+ * <string>6.0.4</string>
+ * <key>CFBundleVersion</key>
+ * <string>8536.29.13</string>
+ * <key>ProjectName</key>
+ * <string>WebBrowser</string>
+ * <key>SourceVersion</key>
+ * <string>7536029013000000</string>
+ * </dict>
+ * </plist>
+ */
+ File f = new File(versionFile);
+ return f.readAsLines().then((content) {
+ bool versionOnNextLine = false;
+ for (var line in content) {
+ if (versionOnNextLine) return line;
+ if (line.contains("CFBundleShortVersionString")) {
+ versionOnNextLine = true;
+ }
+ }
+ return null;
+ });
+ }
+
+ void _createLaunchHTML(var path, var url) {
+ var file = new File("${path}/launch.html");
+ var randomFile = file.openSync(FileMode.WRITE);
+ var content = '<script language="JavaScript">location = "$url"</script>';
+ randomFile.writeStringSync(content);
+ randomFile.close();
+ }
+
+ Future<bool> start(String url) {
+ _logEvent("Starting Safari browser on: $url");
+ // Get the version and log that.
+ return allowPopUps().then((success) {
+ if (!success) {
+ return new Future.immediate(false);
+ }
+ return getVersion().then((version) {
+ _logEvent("Got version: $version");
+ var args = ["'$url'"];
+ return new Directory('').createTemp().then((userDir) {
+ _cleanup = () { userDir.delete(recursive: true); };
+ _createLaunchHTML(userDir.path, url);
+ var args = ["${userDir.path}/launch.html"];
+ return startBrowser(binary, args);
+ });
+ }).catchError((e) {
+ _logEvent("Running $binary --version failed with $e");
+ return false;
+ });
+ });
+ }
+
+ String toString() => "Safari";
+}
+
+
class Chrome extends Browser {
/**
* The binary used to run chrome - changing this can be nececcary for
@@ -235,21 +342,11 @@
var turnScreenOnIntent =
new Intent(mainAction, turnScreenOnPackage, '.Main');
- // FIXME(kustermann): Remove this hack as soon as we've got a v8 mirror in
- // golo
var testing_resources_dir =
new Path('third_party/android_testing_resources');
- var testing_resources_dir_tmp =
- new Path('/tmp/android_testing_resources');
if (!new Directory.fromPath(testing_resources_dir).existsSync()) {
- DebugLogger.warning("$testing_resources_dir doesn't exist, "
- "trying to use $testing_resources_dir_tmp");
- testing_resources_dir = testing_resources_dir_tmp;
- if (!new Directory.fromPath(testing_resources_dir).existsSync()) {
- DebugLogger.error("$testing_resources_dir_tmp doesn't exist either. "
- " This is a fatal error. Exiting now.");
- exit(1);
- }
+ DebugLogger.error("$testing_resources_dir doesn't exist. Exiting now.");
+ exit(1);
}
var chromeAPK = testing_resources_dir.append('com.android.chrome-1.apk');
@@ -392,6 +489,8 @@
String local_ip;
String browserName;
int maxNumBrowsers;
+ // Used to send back logs from the browser (start, stop etc)
+ Function logger;
bool underTermination = false;
@@ -518,6 +617,9 @@
print("could not kill browser $id");
return;
}
+ // We don't want to start a new browser if we are terminating.
+ if (underTermination) return;
+
var browser;
if (browserName == 'chromeOnAndroid') {
browser = new AndroidChrome(adbDeviceMapping[id]);
@@ -607,13 +709,18 @@
}
Browser getInstance() {
+ var browser;
if (browserName == "chrome") {
- return new Chrome();
+ browser = new Chrome();
} else if (browserName == "ff") {
- return new Firefox();
+ browser = new Firefox();
+ } else if (browserName == "safari") {
+ browser = new Safari();
} else {
throw "Non supported browser for browser controller";
}
+ browser.logger = logger;
+ return browser;
}
}
@@ -673,11 +780,11 @@
request.response.write(textResponse);
request.listen((_) {}, onDone: request.response.close);
request.response.done.catchError((error) {
- if (!underTermination) {
- print("URI ${request.uri}");
- print("Textresponse $textResponse");
- throw("Error returning content to browser: $error");
- }
+ if (!underTermination) {
+ print("URI ${request.uri}");
+ print("Textresponse $textResponse");
+ throw "Error returning content to browser: $error";
+ }
});
}
void errorHandler(e) {
diff --git a/tools/testing/dart/drt_updater.dart b/tools/testing/dart/drt_updater.dart
index 67e1716..ea86b4a 100644
--- a/tools/testing/dart/drt_updater.dart
+++ b/tools/testing/dart/drt_updater.dart
@@ -2,6 +2,8 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+// TODO(antonm): rename to something like test_runner_updater.
+
library drt_updater;
import "dart:async";
@@ -60,18 +62,18 @@
}
}
-_DartiumUpdater _dumpRenderTreeUpdater;
+_DartiumUpdater _contentShellUpdater;
_DartiumUpdater _dartiumUpdater;
_DartiumUpdater runtimeUpdater(Map configuration) {
String runtime = configuration['runtime'];
if (runtime == 'drt' && configuration['drt'] == '') {
- // Download the default DumpRenderTree from Google Storage.
- if (_dumpRenderTreeUpdater == null) {
- _dumpRenderTreeUpdater = new _DartiumUpdater('DumpRenderTree',
- 'get_archive.py', 'drt');
+ // Download the default content shell from Google Storage.
+ if (_contentShellUpdater == null) {
+ _contentShellUpdater = new _DartiumUpdater('Content Shell',
+ 'get_archive.py', 'drt');
}
- return _dumpRenderTreeUpdater;
+ return _contentShellUpdater;
} else if (runtime == 'dartium' && configuration['dartium'] == '') {
// Download the default Dartium from Google Storage.
if (_dartiumUpdater == null) {
diff --git a/tools/testing/dart/record_and_replay.dart b/tools/testing/dart/record_and_replay.dart
new file mode 100644
index 0000000..fd5df68
--- /dev/null
+++ b/tools/testing/dart/record_and_replay.dart
@@ -0,0 +1,126 @@
+// 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.
+
+library record_and_replay;
+
+import 'dart:io';
+import 'dart:json' as json;
+import 'dart:utf';
+
+import 'test_runner.dart';
+
+/*
+ * Json files look like this:
+ *
+ * [
+ * {
+ * 'name' : '...',
+ * 'configuration' : '...',
+ * 'command' : {
+ * 'timeout_limit' : 60,
+ * 'executable' : '...',
+ * 'arguments' : ['arg1, 'arg2', '...'],
+ * },
+ * 'command_output' : {
+ * 'exit_code' : 42,
+ * 'stdout' : '...',
+ * 'stderr' : '...',
+ * 'duration' : 1.5,
+ * 'did_timeout' : false,
+ * },
+ * },
+ * ....
+ * ]
+ */
+
+
+class TestCaseRecorder {
+ Path _outputPath;
+ List<Map> _recordedCommandInvocations = [];
+ var _cwd;
+
+ TestCaseRecorder(this._outputPath) {
+ _cwd = new Directory.current().path;
+ }
+
+ void nextTestCase(TestCase testCase) {
+ assert(testCase.commands.length == 1);
+
+ var command = testCase.commands[0];
+ assert(command.environment == null);
+
+ var arguments = [];
+ for (var rawArgument in command.arguments) {
+ if (rawArgument.startsWith(_cwd)) {
+ var relative = new Path(rawArgument).relativeTo(new Path(_cwd));
+ arguments.add(relative.toNativePath());
+ } else {
+ arguments.add(rawArgument);
+ }
+ }
+
+ var commandExecution = {
+ 'name' : testCase.displayName,
+ 'configuration' : testCase.configurationString,
+ 'command' : {
+ 'timeout_limit' : testCase.timeout,
+ 'executable' : command.executable,
+ 'arguments' : arguments,
+ },
+ };
+ _recordedCommandInvocations.add(commandExecution);
+ }
+
+ void finish() {
+ var file = new File.fromPath(_outputPath);
+ var jsonString = json.stringify(_recordedCommandInvocations);
+ file.writeAsStringSync(jsonString);
+ print("TestCaseRecorder: written all TestCases to ${_outputPath}");
+ }
+}
+
+class TestCaseOutputArchive {
+ Map<String, Map> _testCaseOutputRecords;
+
+ void loadFromPath(Path recordingPath) {
+ var file = new File.fromPath(recordingPath);
+ var testCases = json.parse(file.readAsStringSync());
+ _testCaseOutputRecords = {};
+ for (var testCase in testCases) {
+ var key = _indexKey(testCase['configuration'], testCase['name']);
+ _testCaseOutputRecords[key] = testCase['command_output'];
+ }
+ }
+
+ CommandOutput outputOf(TestCase testCase) {
+ var key = _indexKey(testCase.configurationString, testCase.displayName);
+ var command_output = _testCaseOutputRecords[key];
+ if (command_output == null) {
+ print("Sorry, but there is no command output for "
+ "${testCase.displayName}");
+
+ exit(42);
+ }
+
+ double seconds = command_output['duration'];
+ var duration = new Duration(seconds: seconds.round(),
+ milliseconds: (seconds/1000).round());
+ var commandOutput = new CommandOutput.fromCase(
+ testCase,
+ testCase.commands.first,
+ command_output['exit_code'],
+ false,
+ command_output['did_timeout'],
+ encodeUtf8(command_output['stdout']),
+ encodeUtf8(command_output['stderr']),
+ duration,
+ false);
+ return commandOutput;
+ }
+
+ String _indexKey(String configuration, String name) {
+ return "${configuration}__$name";
+ }
+}
+
diff --git a/tools/testing/dart/test_options.dart b/tools/testing/dart/test_options.dart
index bda38e0..b04f731 100644
--- a/tools/testing/dart/test_options.dart
+++ b/tools/testing/dart/test_options.dart
@@ -85,6 +85,7 @@
['-c', '--compiler'],
['none', 'dart2dart', 'dart2js', 'dartc', 'dartanalyzer'],
'none'),
+ // TODO(antonm): fix the option drt.
new _TestOptionSpecification(
'runtime',
'''Where the tests should be run.
@@ -95,7 +96,7 @@
jsshell: Run JavaScript from the command line using firefox js-shell.
drt: Run Dart or JavaScript in the headless version of Chrome,
- DumpRenderTree.
+ Content shell.
dartium: Run Dart or JavaScript in Dartium.
@@ -113,7 +114,7 @@
'arch',
'The architecture to run tests for',
['-a', '--arch'],
- ['all', 'ia32', 'x64', 'simarm', 'simmips'],
+ ['all', 'ia32', 'x64', 'simarm', 'simmips', 'arm'],
'ia32'),
new _TestOptionSpecification(
'system',
@@ -252,8 +253,8 @@
[],
''),
new _TestOptionSpecification(
- 'drt',
- 'Path to DumpRenderTree executable',
+ 'drt', // TODO(antonm): fix the option name.
+ 'Path to content shell executable',
['--drt'],
[],
''),
@@ -318,7 +319,21 @@
'This address is also used for browsers to connect.',
['--local_ip'],
[],
- '127.0.0.1'),];
+ '127.0.0.1'),
+ new _TestOptionSpecification(
+ 'record_to_file',
+ 'Records all the commands that need to be executed and writes it '
+ 'out to a file.',
+ ['--record_to_file'],
+ [],
+ null),
+ new _TestOptionSpecification(
+ 'replay_from_file',
+ 'Records all the commands that need to be executed and writes it '
+ 'out to a file.',
+ ['--replay_from_file'],
+ [],
+ null),];
}
diff --git a/tools/testing/dart/test_progress.dart b/tools/testing/dart/test_progress.dart
index 0c6b7a7..b9ce10b 100644
--- a/tools/testing/dart/test_progress.dart
+++ b/tools/testing/dart/test_progress.dart
@@ -309,6 +309,9 @@
(FileSystemEntity fse) {
if (fse is Directory) count++;
},
+ onError: (error) {
+ DebugLogger.warning("Could not list temp directories, got: $error");
+ },
onDone: () {
if (count > MIN_NUMBER_OF_TEMP_DIRS) {
DebugLogger.warning("There are ${count} directories "
diff --git a/tools/testing/dart/test_runner.dart b/tools/testing/dart/test_runner.dart
index 93c38e9..9169a83 100644
--- a/tools/testing/dart/test_runner.dart
+++ b/tools/testing/dart/test_runner.dart
@@ -24,6 +24,7 @@
import "test_progress.dart";
import "test_suite.dart";
import "utils.dart";
+import 'record_and_replay.dart';
const int NO_TIMEOUT = 0;
const int SLOW_TIMEOUT_MULTIPLIER = 4;
@@ -180,20 +181,20 @@
}
}
-class DumpRenderTreeCommand extends Command {
+class ContentShellCommand extends Command {
/**
- * If [expectedOutputPath] is set, the output of DumpRenderTree is compared
+ * If [expectedOutputPath] is set, the output of content shell is compared
* with the content of [expectedOutputPath].
* This is used for example for pixel tests, where [expectedOutputPath] points
* to a *png file.
*/
io.Path expectedOutputPath;
- DumpRenderTreeCommand(String executable,
- String htmlFile,
- List<String> options,
- List<String> dartFlags,
- io.Path this.expectedOutputPath)
+ ContentShellCommand(String executable,
+ String htmlFile,
+ List<String> options,
+ List<String> dartFlags,
+ io.Path this.expectedOutputPath)
: super(executable,
_getArguments(options, htmlFile),
_getEnvironment(dartFlags));
@@ -392,7 +393,8 @@
List<BrowserTestCase> observers;
BrowserTestCase(displayName, commands, configuration, completedHandler,
- expectedOutcomes, info, isNegative, [this.waitingForOtherTest = false])
+ expectedOutcomes, info, isNegative, this._testingUrl,
+ [this.waitingForOtherTest = false])
: super(displayName, commands, configuration, completedHandler,
expectedOutcomes, isNegative: isNegative, info: info) {
numRetries = 2; // Allow two retries to compensate for flaky browser tests.
@@ -405,6 +407,8 @@
List<String> get batchTestArguments => _lastArguments.sublist(1);
+ String _testingUrl;
+
/** Add a test case to listen for when this current test has completed. */
void addObserver(BrowserTestCase testCase) {
observers.add(testCase);
@@ -419,6 +423,8 @@
testCase.waitingForOtherTest = false;
}
}
+
+ String get testingUrl => _testingUrl;
}
@@ -645,7 +651,7 @@
}
if (command.expectedOutputFile != null) {
- // We are either doing a pixel test or a layout test with DumpRenderTree
+ // We are either doing a pixel test or a layout test with content shell
return _failedBecauseOfUnexpectedDRTOutput;
}
return _browserTestFailure;
@@ -653,10 +659,10 @@
bool get _failedBecauseOfMissingXDisplay {
// Browser case:
- // If the browser test failed, it may have been because DumpRenderTree
- // and the virtual framebuffer X server didn't hook up, or DRT crashed with
- // a core dump. Sometimes DRT crashes after it has set the stdout to PASS,
- // so we have to do this check first.
+ // If the browser test failed, it may have been because content shell
+ // and the virtual framebuffer X server didn't hook up, or it crashed with
+ // a core dump. Sometimes content shell crashes after it has set the stdout
+ // to PASS, so we have to do this check first.
var stderrLines = decodeUtf8(super.stderr).split("\n");
for (String line in stderrLines) {
// TODO(kustermann,ricow): Issue: 7564
@@ -677,7 +683,7 @@
bool get _failedBecauseOfUnexpectedDRTOutput {
/*
- * The output of DumpRenderTree is different for pixel tests than for
+ * The output of content shell is different for pixel tests than for
* layout tests.
*
* On a pixel test, the DRT output has the following format
@@ -1337,6 +1343,10 @@
int _numFailedTests = 0;
bool _allTestsWereEnqueued = false;
+ // Support for recording and replaying test commands.
+ TestCaseRecorder _testCaseRecorder;
+ TestCaseOutputArchive _testCaseOutputArchive;
+
/** The number of tests we allow to actually fail before we stop retrying. */
int _MAX_FAILED_NO_RETRY = 4;
bool _verbose;
@@ -1380,7 +1390,9 @@
this._eventListener,
this._allDone,
[bool verbose = false,
- bool listTests = false])
+ bool listTests = false,
+ this._testCaseRecorder,
+ this._testCaseOutputArchive])
: _verbose = verbose,
_listTests = listTests,
_tests = new Queue<TestCase>(),
@@ -1411,6 +1423,47 @@
}
void _runTests(List<TestSuite> testSuites) {
+ var newTest;
+ var allTestsKnown;
+
+ if (_testCaseRecorder != null) {
+ // Mode: recording.
+ newTest = _testCaseRecorder.nextTestCase;
+ allTestsKnown = () {
+ // We don't call any event*() methods, so test_progress.dart will not be
+ // notified (that's fine, since we're not running any tests).
+ _testCaseRecorder.finish();
+ _allDone();
+ };
+ } else {
+ if (_testCaseOutputArchive != null) {
+ // Mode: replaying.
+ newTest = (TestCase testCase) {
+ // We're doing this asynchronously to emulate the normal behaviour.
+ eventTestAdded(testCase);
+ Timer.run(() {
+ var output = _testCaseOutputArchive.outputOf(testCase);
+ testCase.completed();
+ eventFinishedTestCase(testCase);
+ });
+ };
+ allTestsKnown = () {
+ // If we're replaying commands, we need to call [_cleanupAndMarkDone]
+ // manually. We're putting it at the end of the event queue to make
+ // sure all the previous events were fired.
+ Timer.run(() => _cleanupAndMarkDone());
+ };
+ } else {
+ // Mode: none (we're not recording/replaying).
+ newTest = (TestCase testCase) {
+ _tests.add(testCase);
+ eventTestAdded(testCase);
+ _runTest(testCase);
+ };
+ allTestsKnown = _checkDone;
+ }
+ }
+
// FIXME: For some reason we cannot call this method on all test suites
// in parallel.
// If we do, not all tests get enqueued (if --arch=all was specified,
@@ -1420,10 +1473,10 @@
void enqueueNextSuite() {
if (!iterator.moveNext()) {
_allTestsWereEnqueued = true;
+ allTestsKnown();
eventAllTestsKnown();
- _checkDone();
} else {
- iterator.current.forEachTest(_runTest, _testCache, enqueueNextSuite);
+ iterator.current.forEachTest(newTest, _testCache, enqueueNextSuite);
}
}
enqueueNextSuite();
@@ -1495,8 +1548,6 @@
browserUsed = test.configuration['runtime'];
if (_needsSelenium) _ensureSeleniumServerRunning();
}
- eventTestAdded(test);
- _tests.add(test);
_tryRunTest();
}
@@ -1598,10 +1649,11 @@
Future<BrowserTestRunner> _getBrowserTestRunner(TestCase test) {
var local_ip = test.configuration['local_ip'];
var runtime = test.configuration['runtime'];
- var num_browsers = test.configuration['tasks'];
+ var num_browsers = 1;//test.configuration['tasks'];
if (_browserTestRunners[runtime] == null) {
var testRunner =
new BrowserTestRunner(local_ip, runtime, num_browsers);
+ testRunner.logger = DebugLogger.info;
_browserTestRunners[runtime] = testRunner;
return testRunner.start().then((started) {
if (started) {
@@ -1615,13 +1667,8 @@
}
void _startBrowserControllerTest(var test) {
- // Get the url.
- // TODO(ricow): This is not needed when we have eliminated selenium.
- var nextCommandIndex = test.commandOutputs.keys.length;
- var url = test.commands[nextCommandIndex].toString().split("--out=")[1];
- // Remove trailing "
- url = url.split('"')[0];
var callback = (var output) {
+ var nextCommandIndex = test.commandOutputs.keys.length;
new CommandOutput.fromCase(test,
test.commands[nextCommandIndex],
0,
@@ -1633,7 +1680,9 @@
false);
test.completedHandler(test);
};
- BrowserTest browserTest = new BrowserTest(url, callback, test.timeout);
+ BrowserTest browserTest = new BrowserTest(test.testingUrl,
+ callback,
+ test.timeout);
_getBrowserTestRunner(test).then((testRunner) {
testRunner.queueTest(browserTest);
});
@@ -1654,7 +1703,9 @@
print(fields.join('\t'));
return;
}
- if (test.usesWebDriver && _needsSelenium && !_isSeleniumAvailable ||
+
+ if (test.usesWebDriver && _needsSelenium && !test.usesBrowserController
+ && !_isSeleniumAvailable ||
(test is BrowserTestCase && test.waitingForOtherTest)) {
// The test is not yet ready to run. Put the test back in
// the queue. Avoid spin-polling by using a timeout.
diff --git a/tools/testing/dart/test_suite.dart b/tools/testing/dart/test_suite.dart
index 38fd5ee..2a6fa18 100644
--- a/tools/testing/dart/test_suite.dart
+++ b/tools/testing/dart/test_suite.dart
@@ -517,7 +517,7 @@
}
/**
- * If DumpRenderTree/Dartium is required, and not yet updated, waits for
+ * If Content shell/Dartium is required, and not yet updated, waits for
* the update then completes. Otherwise completes immediately.
*/
Future updateDartium() {
@@ -997,6 +997,7 @@
subtestNames, subtestIndex);
List<String> args = <String>[];
+
if (TestUtils.usesWebDriver(runtime)) {
args = [
dartDir.append('tools/testing/run_selenium.py').toNativePath(),
@@ -1018,9 +1019,10 @@
}
var dartFlags = [];
- var dumpRenderTreeOptions = [];
+ var contentShellOptions = [];
- dumpRenderTreeOptions.add('--no-timeout');
+ contentShellOptions.add('--no-timeout');
+ contentShellOptions.add('--dump-render-tree');
if (compiler == 'none' || compiler == 'dart2dart') {
dartFlags.add('--ignore-unrecognized-flags');
@@ -1034,15 +1036,15 @@
if (expectedOutput != null) {
if (expectedOutput.toNativePath().endsWith('.png')) {
// pixel tests are specified by running DRT "foo.html'-p"
- dumpRenderTreeOptions.add('--notree');
+ contentShellOptions.add('--notree');
fullHtmlPath = "${fullHtmlPath}'-p";
}
}
- commandSet.add(new DumpRenderTreeCommand(dumpRenderTreeFilename,
- fullHtmlPath,
- dumpRenderTreeOptions,
- dartFlags,
- expectedOutput));
+ commandSet.add(new ContentShellCommand(contentShellFilename,
+ fullHtmlPath,
+ contentShellOptions,
+ dartFlags,
+ expectedOutput));
}
// Create BrowserTestCase and queue it.
@@ -1053,18 +1055,20 @@
testCase = new BrowserTestCase(testDisplayName,
commandSet, configuration, completeHandler,
expectations['$testName/${subtestNames[subtestIndex]}'],
- info, info.hasCompileError || info.hasRuntimeError,
+ info, info.hasCompileError || info.hasRuntimeError, fullHtmlPath,
subtestIndex != 0);
} else {
testCase = new BrowserTestCase(testDisplayName,
commandSet, configuration, completeHandler, expectations,
- info, info.hasCompileError || info.hasRuntimeError, false);
+ info, info.hasCompileError || info.hasRuntimeError, fullHtmlPath,
+ false);
}
if (subtestIndex == 0) {
multitestParentTest = testCase;
} else {
multitestParentTest.addObserver(testCase);
}
+
doTest(testCase);
subtestIndex++;
} while(subtestIndex < subtestNames.length);
@@ -1172,15 +1176,15 @@
}
}
- String get dumpRenderTreeFilename {
+ String get contentShellFilename {
if (configuration['drt'] != '') {
return configuration['drt'];
}
if (Platform.operatingSystem == 'macos') {
- return dartDir.append('/client/tests/drt/DumpRenderTree.app/Contents/'
- 'MacOS/DumpRenderTree').toNativePath();
+ return dartDir.append('/client/tests/drt/Content Shell.app/Contents/'
+ 'MacOS/Content Shell').toNativePath();
}
- return dartDir.append('client/tests/drt/DumpRenderTree').toNativePath();
+ return dartDir.append('client/tests/drt/content_shell').toNativePath();
}
String get dartiumFilename {
diff --git a/tools/testing/drt-trampoline.py b/tools/testing/drt-trampoline.py
deleted file mode 100644
index ac5b23d69..0000000
--- a/tools/testing/drt-trampoline.py
+++ /dev/null
@@ -1,147 +0,0 @@
-# Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
-# for details. All rights reserved. Use of this source code is governed by a
-# BSD-style license that can be found in the LICENSE file.
-#
-# For now we have to use this trampoline to turn --dart-flags command line
-# switch into env variable DART_FLAGS. Eventually, DumpRenderTree should
-# support --dart-flags and this hack may go away.
-#
-# Expected invocation: python drt-trampoline.py <path to DRT> <DRT command line>
-
-import optparse
-import os
-import signal
-import subprocess
-import sys
-
-def parse_options(argv):
- parser = optparse.OptionParser()
- parser.add_option('--dart-flags',
- metavar='FLAGS',
- dest='dart_flags')
- parser.add_option('--out-expectation',
- metavar='FILE',
- dest='out_expected_file')
- parser.add_option('--package-root',
- metavar='DIRECTORY',
- dest='dart_package_root')
- parser.add_option('--no-timeout',
- action='store_true')
- return parser.parse_args(args=argv)
-
-
-def main(argv):
- drt_path = argv[1]
- (options, arguments) = parse_options(argv[2:])
-
- cmd = [drt_path]
-
- env = None
- test_file = None
- dart_flags = options.dart_flags
- out_expected_file = options.out_expected_file
- dart_package_root = options.dart_package_root
- is_png = False
-
- if dart_flags:
- if not env:
- env = dict(os.environ.items())
- env['DART_FLAGS'] = dart_flags
-
- if dart_package_root:
- if not env:
- env = dict(os.environ.items())
- absolute_path = os.path.abspath(dart_package_root)
- absolute_path = absolute_path.replace(os.path.sep, '/')
- if not absolute_path.startswith('/'):
- # Happens on Windows for C:\packages
- absolute_path = '/%s' % absolute_path
- env['DART_PACKAGE_ROOT'] = 'file://%s' % absolute_path
-
- if out_expected_file:
- if out_expected_file.endswith('.png'):
- cmd.append('--notree')
- is_png = True
- elif not out_expected_file.endswith('.txt'):
- raise Exception(
- 'Bad file expectation (%s) please specify either a .txt or a .png file'
- % out_expected_file)
-
- if options.no_timeout:
- cmd.append('--no-timeout')
-
- for arg in arguments:
- if '.html' in arg:
- test_file = arg
- else:
- cmd.append(arg)
-
- if is_png:
- # pixel tests are specified by running DRT "foo.html'-p"
- cmd.append(test_file + "'-p")
- else:
- cmd.append(test_file)
-
- stdout = subprocess.PIPE if out_expected_file else None
- p = subprocess.Popen(cmd, env=env, stdout=stdout)
-
- def signal_handler(signal, frame):
- p.terminate()
- sys.exit(0)
-
- # SIGINT is Ctrl-C.
- signal.signal(signal.SIGINT, signal_handler)
- # SIGTERM is sent by test.dart when a process times out.
- signal.signal(signal.SIGTERM, signal_handler)
- output, error = p.communicate()
- signal.signal(signal.SIGINT, signal.SIG_DFL)
- signal.signal(signal.SIGTERM, signal.SIG_DFL)
-
- if p.returncode != 0:
- raise Exception('Failed to run command. return code=%s' % p.returncode)
-
- if out_expected_file:
- # Compare output to the given expectation file.
- expectation = None
- if is_png:
- # DRT prints the image to STDOUT, but includes extra text that we trim:
- # - several header lines until a line saying 'Content-Length:'
- # - a '#EOF\n' at the end
- last_header_line = output.find('Content-Length:')
- start_pos = output.find('\n', last_header_line) + 1
- output = output[start_pos : -len('#EOF\n')]
- if os.path.exists(out_expected_file):
- with open(out_expected_file, 'r') as f:
- expectation = f.read()
- else:
- # Instructions on how to create the expectation will be printed below
- # (outout != expectation)
- print 'File %s was not found' % out_expected_file
- expectation = None
-
- # Report test status using the format test.dart expects to see from DRT.
- print 'Content-Type: text/plain'
- if expectation == output:
- print 'PASS'
- print 'Expectation matches'
- else:
- # Generate a temporary file in the same place as the .html file:
- out_file = test_file[:test_file.rfind('.html')] + out_expected_file[-4:]
- with open(out_file, 'w') as f:
- f.write(output)
- print 'FAIL'
- print 'Expectation didn\'t match.\n'
- if len(output) == 0:
- print ('\033[31mERROR\033[0m: DumpRenderTree generated an empty pixel '
- 'output! This is commonly an error in executing DumpRenderTree, and'
- ' not that expectations are out of date.\n')
- print 'You can update expectations by running:\n'
- print 'cp %s %s\n' % (out_file, out_expected_file)
- print '#EOF'
-
-if __name__ == '__main__':
- try:
- sys.exit(main(sys.argv))
- except StandardError as e:
- print 'Fail: ' + str(e)
- sys.exit(1)
diff --git a/tools/testing/legpad/example.dart b/tools/testing/legpad/example.dart
deleted file mode 100644
index 5134f16..0000000
--- a/tools/testing/legpad/example.dart
+++ /dev/null
@@ -1,6 +0,0 @@
-void main() {
- for (int i = 0; i < 5; i++) {
- print("i is $i");
- }
- print("done");
-}
\ No newline at end of file
diff --git a/tools/testing/legpad/example.sh b/tools/testing/legpad/example.sh
deleted file mode 100755
index 96cb79f..0000000
--- a/tools/testing/legpad/example.sh
+++ /dev/null
@@ -1,10 +0,0 @@
-# Sample script showing how to use legpad.
-
-# First compile "legpad.dart" to "legpad.dart.js" usung dart2js.
-set -x
-DART_DIR="../../.."
-$DART_DIR/out/Release_ia32/dart2js --out=legpad.dart.js legpad.dart
-
-# Now run legpad to generate an html page that can be used to compile
-# example.dart
-python legpad.py example.dart
diff --git a/tools/testing/legpad/legpad.dart b/tools/testing/legpad/legpad.dart
deleted file mode 100644
index b6acfe7..0000000
--- a/tools/testing/legpad/legpad.dart
+++ /dev/null
@@ -1,136 +0,0 @@
-// 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("dart:html", prefix:"html");
-#import('../../../lib/compiler/compiler.dart', prefix: "compiler_lib");
-#import('../../../lib/uri/uri.dart', prefix:"uri_lib");
-
-/**
- * This is the entrypoint for a version of the leg compiler that
- * runs in the browser.
- *
- * Because this is running in the browser, we do not access
- * the file system. Instead, we assume that all necessary files
- * have been placed in inert <script> elements somewhere on the html page.
- *
- * (See legpad.py for more details on how the html page is constructed.)
- */
-void main() {
- new Legpad().run();
-}
-
-class Legpad {
- // id of script element containing name of the main dart file
- // to compile
- static const String MAIN_ID = "main_id";
-
- Legpad() : warnings = new StringBuffer();
-
- // accumulates diagnostic messages emitted by the leg compiler
- StringBuffer warnings;
-
- // the generated javascript
- String output;
-
- String readAll(String filename) {
- String text = getText(idOfFilename(filename));
- print("read $filename (${text.length} bytes)");
- return text;
- }
-
- void diagnosticHandler(uri_lib.Uri uri, int begin, int end,
- String message, bool fatal) {
- warnings.add(message);
- if (uri != null) {
- warnings.add(" ($uri: $begin, $end)");
- }
- if (fatal) {
- warnings.add(" (fatal)");
- }
- warnings.add("\n");
- }
-
- Future<String> readUriFromString(uri_lib.Uri uri) {
- Completer<String> completer = new Completer<String>();
- completer.complete(readAll(uri.toString()));
- return completer.future;
- }
-
- /**
- * Returns the id of the <script> element that contains
- * the contents of this file. (Replace all slashes
- * and dots in the file name with underscores.)
- */
- String idOfFilename(String filename) {
- return filename.replaceAll("/", "_").replaceAll(".", "_");
- }
-
- void run() {
- String mainFile = getText(MAIN_ID);
- setText("input", readAll(mainFile));
- Stopwatch stopwatch = new Stopwatch()..start();
- runLeg();
- int elapsedMillis = stopwatch.elapsedMilliseconds;
- if (output == null) {
- output = "throw 'dart2js compilation error';\n";
- }
-
- setText("output", output);
- setText("warnings", warnings.toString());
- int lineCount = lineCount(output);
- String timing = "generated $lineCount lines "
- "(${output.length} characters) in "
- "${((elapsedMillis) / 1000).toStringAsPrecision(3)} seconds";
- setText("timing", timing);
- }
-
- static int lineCount(String s) {
- Iterable<Match> matches = "\n".allMatches(s);
- int n = 0;
- for (Match m in matches) {
- n++;
- }
- return n;
- }
-
- void runLeg() {
- uri_lib.Uri mainUri = new uri_lib.Uri.fromString(getText(MAIN_ID));
- uri_lib.Uri libraryRoot = new uri_lib.Uri.fromString("dartdir/");
- List<String> compilerArgs = [
- "--enable_type_checks",
- "--enable_asserts"
- ];
-
- // TODO(mattsh): dart2js api should be synchronous
- Future<String> futureJavascript = compiler_lib.compile(mainUri,
- libraryRoot, readUriFromString, diagnosticHandler, compilerArgs);
-
- if (futureJavascript == null) {
- return;
- }
- output = futureJavascript.value;
- }
-
- void setText(String id, String text) {
- html.Element element = html.document.query("#$id");
- if (element == null) {
- throw new Exception("Can't find element $id");
- }
- element.innerHTML = htmlEscape(text);
- }
-
- String getText(String id) {
- html.Element element = html.document.query("#$id");
- if (element == null) {
- throw new Exception("Can't find element $id");
- }
- return element.text.trim();
- }
-
- // TODO(mattsh): should exist in standard lib somewhere
- static String htmlEscape(String text) {
- return text.replaceAll('&', '&').replaceAll(
- '>', '>').replaceAll('<', '<');
- }
-}
diff --git a/tools/testing/legpad/legpad.py b/tools/testing/legpad/legpad.py
deleted file mode 100644
index 1a4aa55..0000000
--- a/tools/testing/legpad/legpad.py
+++ /dev/null
@@ -1,367 +0,0 @@
-#!/usr/bin/env python
-
-# 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.
-
-"""
-Legpad is used to compile .dart files to javascript, using the dart2js compiler.
-
-This is accomplished by creating an html file (usually called
-<something>.legpad.html) that executes the dart2js compiler when the page
-is loaded by a web browser (or DumpRenderTree).
-
-The <something>.legpad.html file contains:
-
- 1. all the dart files that compose a user's dart program
- 2. all the dart files of dart:core and other standard dart libraries
- (or any other symbol that can follow "dart:" in an import statement
- 3. legpad.dart (compiled to javascript)
-
-The contents of each dart file is placed in a separate <script> tag.
-
-When the html page is loaded by a browser, the leg compiler is invoked
-and the dart program is compiled to javascript. The generated javascript is
-placed in a <pre> element with id "output".
-
-When the html page is passed to DumpRenderTree, the dumped output will
-have the generated javascript.
-
-See 'example.sh' for an example of how to run legpad.
-"""
-
-import logging
-import optparse
-import os.path
-import platform
-import re
-import subprocess
-import sys
-
-
-class FileNotFoundException(Exception):
- def __init__(self, file_name):
- self._name = file_name
-
- def __str__(self):
- return self._name
-
-
-class CommandFailedException(Exception):
- def __init__(self, message):
- self._message = message
-
- def GetMessage(self):
- return self._message
-
-
-# Template for the legpad.html page we're going to generate.
-HTML = """<!DOCTYPE html>
-<html>
-<head>
- <style type="text/css">
- textarea {
- width: 100%;
- height: 200px;
- }
- .label {
- margin-top: 5px;
- }
- pre {
- border: 2px solid black;
- }
- </style>
- {{script_tags}}
- <script type="text/javascript">
- if (window.layoutTestController) {
- layoutTestController.dumpAsText();
- }
- </script>
-</head>
-<body>
- <h1>Legpad</h1>
- <div class="label">Input:</div>
- <textarea id="input"></textarea>
- <div class="label">Compiler Messages:</div>
- <pre id="warnings"></pre>
- <div class="label">Timing:</div>
- <pre id="timing"></pre>
- <div class="label">Output:</div>
- <pre id="output"></pre>
- <script type="text/javascript">
- {{LEGPAD_JS}}
- </script>
-</body>
-</html>
-"""
-
-# This finds everything after the word "Output:" in the html page.
-# (Note, because the javascript we're fishing out spans multiple lines
-# we need to use the DOTALL switch here.)
-OUTPUT_JAVASCRIPT_REGEX = re.compile(".*\nOutput:\n(.*)\n#EOF", re.DOTALL)
-
-# If the legpad.dart encounters a compilation error, the generated
-# javascript will contains the words "dart2js compilation error".
-COMPILATION_ERROR_REGEX = re.compile(".*dart2js compilation error.*", re.DOTALL)
-
-# We use "application/inert" here to make the browser ignore the
-# these script tags. (legpad.dart will fish out the contents as needed.)
-#
-SCRIPT_TAG = """<script type="application/inert" id="{{id}}">
-{{contents}}
-</script>
-"""
-
-# Regex that finds #import, #source and #native directives in .dart files.
-# match.group(1) = "import", "source" or "native"
-# match.group(2) = url of file being imported
-DIRECTIVE_RE = re.compile(r"^#(import|source|native)\([\"']([^\"']*)[\"']")
-
-# id of script tag that holds name of the top dart file to be compiled,
-# (This file name passed will be passed to the leg compiler by legpad.dart.)
-MAIN_ID = "main_id"
-
-# TODO(mattsh): read this from some config file once ahe/zundel create it
-DART_LIBRARIES = {
- "core": "lib/compiler/implementation/lib/core.dart",
- "_js_helper": "lib/compiler/implementation/lib/js_helper.dart",
- "_interceptors": "lib/compiler/implementation/lib/interceptors.dart",
- "dom": "lib/dom/frog/dom_frog.dart",
- "html": "lib/html/frog/html_frog.dart",
- "io": "lib/compiler/implementation/lib/io.dart",
- "isolate": "lib/isolate/isolate_leg.dart",
- "json": "lib/json/json.dart",
- "uri": "lib/uri/uri.dart",
- "utf": "lib/utf/utf.dart",
-}
-
-class Pad(object):
- """
- Accumulates all source files that are needed to compile a dart program,
- and places them in <script> tags on an html page.
- """
-
- def __init__(self, argv):
- parser = optparse.OptionParser(usage=
- "%prog [options] file_to_compile.dart"
- )
- parser.add_option("-o", "--out",
- help="name of javascript output file")
- parser.add_option("-v", "--verbose", action="store_true",
- help="more verbose logging")
- (options, args) = parser.parse_args(argv)
-
- log_level = logging.INFO
- if options.verbose:
- log_level = logging.DEBUG
- logging.basicConfig(level=log_level)
-
- if len(args) < 2:
- parser.print_help()
- sys.exit(1)
-
- self.main_file = os.path.abspath(args[1])
-
- # directory of this script
- self.legpad_dir = os.path.abspath(os.path.dirname(argv[0]))
-
- # root of dart source repo
- self.dart_dir = os.path.dirname(os.path.dirname(os.path.dirname(
- self.legpad_dir)))
-
- logging.debug("dart_dir: '%s'" % self.dart_dir)
-
- if options.out:
- # user has specified an output file name
- self.js_file = os.path.abspath(options.out)
- else:
- # User didn't specify an output file, so use the input
- # file name as the base of the output file name.
- self.js_file = self.main_file + ".legpad.js"
-
- logging.debug("js_file: '%s" % self.js_file)
-
- # this is the html file that we pass to DumpRenderTree
- self.html_file = self.main_file + ".legpad.html"
- logging.debug("html_file: '%s'" % self.html_file)
-
- # map from file name to File object (contains entries for all corelib
- # and all other dart files needed to compile main_file)
- self.name_to_file = {}
-
- # map from script tag id to File object
- self.id_to_file = {}
-
- self.load_libraries()
- self.load_file(self.main_file)
-
- html = self.generate_html()
- write_file(self.html_file, html)
-
- js = self.generate_js()
- write_file(self.js_file, js)
-
- line_count = len(js.splitlines())
- logging.debug("generated '%s' (%d lines)", self.js_file, line_count)
-
- match = COMPILATION_ERROR_REGEX.match(js)
- if match:
- sys.exit(1)
-
- def generate_html(self):
- tags = []
- for f in self.id_to_file.values():
- tags.append(self._create_tag(f.id, f.contents))
- tags.append(self._create_tag(MAIN_ID, self.shorten(self.main_file)))
- html = HTML.replace("{{script_tags}}", "".join(tags))
-
- legpad_js = os.path.join(self.legpad_dir, "legpad.dart.js")
- check_exists(legpad_js)
-
- html = html.replace("{{LEGPAD_JS}}", read_file(legpad_js))
- return html
-
- def generate_js(self):
- drt = os.path.join(self.dart_dir, "client/tests/drt/DumpRenderTree")
- if platform.system() == 'Darwin':
- drt += ".app"
- elif platform.system() == 'Windows':
- raise Exception("legpad does not run on Windows")
-
- check_exists(drt)
- args = []
- args.append(drt)
- args.append(self.html_file)
-
- stdout = run_command(args)
- match = OUTPUT_JAVASCRIPT_REGEX.match(stdout)
- if not match:
- raise Exception("can't find regex in DumpRenderTree output")
- return match.group(1)
-
- @staticmethod
- def _create_tag(id, contents):
- s = SCRIPT_TAG
- s = s.replace("{{id}}", id)
- # TODO(mattsh) - need to html escape here
- s = s.replace("{{contents}}", contents)
- return s
-
- def dart_library(self, name):
- path = DART_LIBRARIES[name]
- if not path:
- raise Exception("unrecognized 'dart:%s'", name)
- return os.path.join(self.dart_dir, path)
-
- def load_libraries(self):
- for name in DART_LIBRARIES:
- self.load_file(self.dart_library(name))
-
- def load_file(self, name):
- name = os.path.abspath(name)
- if name in self.name_to_file:
- return
- f = File(self, name)
- self.name_to_file[f.name] = f
- if f.id in self.id_to_file:
- raise Exception("ambiguous id '%s'" % f.id)
- self.id_to_file[f.id] = f
- f.directives()
-
- def shorten(self, name):
- """
- Change that full path of the dart svn repo to simply "dartdir"
- """
- return name.replace(self.dart_dir, "dartdir")
-
- def make_id(self, name):
- """
- Generates an id (based on the file name) for the <script> tag that will
- hold the contents of this file.
- """
- return self.shorten(name).replace("/", "_").replace(".", "_")
-
-
-class File(object):
- def __init__(self, pad, name):
- self.pad = pad
- self.name = name
- self.id = pad.make_id(name)
- self.contents = read_file(name)
-
- def directives(self):
- """Load files referenced by #source, #import and #native directives."""
- lines = self.contents.split("\n")
- self.line_number = 0
- for line in lines:
- self.line_number += 1
- self._directive(line)
-
- def _directive(self, line):
- match = DIRECTIVE_RE.match(line)
- if not match:
- return
- url = match.group(2)
- if url.startswith("dart:"):
- path = self.pad.dart_library(url[len("dart:"):])
- else:
- path = os.path.join(os.path.dirname(self.name), url)
- self.pad.load_file(path)
-
-
-def read_file(file_name):
- check_exists(file_name)
- with open(file_name, "r") as input:
- contents = input.read()
- logging.debug("read_file '%s' (%d bytes)" % (file_name, len(contents)))
- return contents
-
-
-def write_file(file_name, contents):
- with open(file_name, "w") as output:
- output.write(contents)
-
- check_exists(file_name)
- logging.debug("write_file '%s' (%d bytes)" % (file_name, len(contents)))
-
-
-def check_exists(file_name):
- if not os.path.exists(file_name):
- raise FileNotFoundException(file_name)
-
-
-def format_command(args):
- return ' '.join(args)
-
-
-def run_command(args):
- """
- Args:
- command: comamnd with arguments to exec
- Returns:
- all output that this command sent to stdout
- """
-
- command = format_command(args)
- logging.info("RUNNING: '%s'" % command)
- child = subprocess.Popen(args,
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE,
- close_fds=True)
- (stdout, stderr) = child.communicate()
- exit_code = child.wait()
- if exit_code:
- for line in stderr.splitlines():
- logging.info(line)
- msg = "FAILURE (exit_code=%d): '%s'" % (exit_code, command)
- logging.error(msg)
- raise CommandFailedException(msg)
- logging.debug("SUCCEEDED (%d bytes)" % len(stdout))
- return stdout
-
-
-def main(argv):
- Pad(argv)
-
-if __name__ == "__main__":
- sys.exit(main(sys.argv))
diff --git a/utils/apidoc/apidoc.dart b/utils/apidoc/apidoc.dart
index 753f8b2..bc20887c 100644
--- a/utils/apidoc/apidoc.dart
+++ b/utils/apidoc/apidoc.dart
@@ -17,7 +17,6 @@
import 'dart:async';
import 'dart:io';
import 'dart:json' as json;
-import 'dart:uri';
import 'html_diff.dart';
diff --git a/utils/apidoc/html_diff.dart b/utils/apidoc/html_diff.dart
index fd8e0a2..1bb8069e 100644
--- a/utils/apidoc/html_diff.dart
+++ b/utils/apidoc/html_diff.dart
@@ -10,7 +10,6 @@
import 'dart:async';
import 'dart:io';
-import 'dart:uri';
import 'lib/metadata.dart';
@@ -25,11 +24,11 @@
// TODO(amouravski): There is currently magic that looks at dart:* libraries
// rather than the declared library names. This changed due to recent syntax
// changes. We should only need to look at the library 'html'.
-const List<Uri> HTML_LIBRARY_URIS = const [
- const Uri.fromComponents(scheme: 'dart', path: 'html'),
- const Uri.fromComponents(scheme: 'dart', path: 'indexed_db'),
- const Uri.fromComponents(scheme: 'dart', path: 'svg'),
- const Uri.fromComponents(scheme: 'dart', path: 'web_audio')];
+final List<Uri> HTML_LIBRARY_URIS = [
+ new Uri(scheme: 'dart', path: 'html'),
+ new Uri(scheme: 'dart', path: 'indexed_db'),
+ new Uri(scheme: 'dart', path: 'svg'),
+ new Uri(scheme: 'dart', path: 'web_audio')];
/**
* A class for computing a many-to-many mapping between the types and
diff --git a/utils/apidoc/mdn/extractRunner.js b/utils/apidoc/mdn/extractRunner.js
index 8e84d0b..6a95a2e 100644
--- a/utils/apidoc/mdn/extractRunner.js
+++ b/utils/apidoc/mdn/extractRunner.js
@@ -116,11 +116,11 @@
/*
// TODO(jacobr): Make this run on platforms other than OS X.
- var cmd = '../../../client/tests/drt/DumpRenderTree.app/Contents/MacOS/' +
- 'DumpRenderTree ' + absoluteDumpFileName;
+ var cmd = '../../../client/tests/drt/Content Shell.app/Contents/MacOS/' +
+ Content Shell' + absoluteDumpFileName;
*/
// TODO(eub): Make this run on platforms other than Linux.
- var cmd = '../../../client/tests/drt/DumpRenderTree ' + absoluteDumpFileName;
+ var cmd = '../../../client/tests/drt/content_shell ' + absoluteDumpFileName;
console.log(cmd);
exec(cmd,
function (error, stdout, stderr) {
diff --git a/utils/testrunner/options.dart b/utils/testrunner/options.dart
index 0e736be..3d5714f 100644
--- a/utils/testrunner/options.dart
+++ b/utils/testrunner/options.dart
@@ -16,10 +16,12 @@
allowed: ['vm', 'drt-dart', 'drt-js'],
allowedHelp: {
'vm': 'Run Dart code natively on the standalone dart vm.',
+ // TODO(antonm): fix option name.
'drt-dart': 'Run Dart code natively in the headless version of\n'
- 'Chrome, DumpRenderTree.',
+ 'Chrome, Content shell.',
+ // TODO(antonm): fix option name.
'drt-js': 'Run Dart compiled to JavaScript in the headless version\n'
- 'of Chrome, DumpRenderTree.'
+ 'of Chrome, Content shell.'
});
parser.addFlag('checked', defaultsTo: false,
diff --git a/utils/testrunner/run_pipeline.dart b/utils/testrunner/run_pipeline.dart
index 5fc1446..f1de2d3 100644
--- a/utils/testrunner/run_pipeline.dart
+++ b/utils/testrunner/run_pipeline.dart
@@ -157,7 +157,6 @@
import 'dart:async';
import 'dart:io';
import 'dart:math';
-import 'dart:uri';
part '${normalizePath('${config["runnerDir"]}/layout_test_controller.dart')}';
''';
extras = '''
@@ -241,7 +240,6 @@
import 'dart:math';
import 'dart:isolate';
import 'dart:html';
-import 'dart:uri';
import 'package:unittest/unittest.dart' as unittest;
import '${normalizePath('$testFile')}' as test;
part '${normalizePath('${config["runnerDir"]}/layout_test_runner.dart')}';
diff --git a/utils/testrunner/testrunner.dart b/utils/testrunner/testrunner.dart
index dda5e31..7ecf8ac 100755
--- a/utils/testrunner/testrunner.dart
+++ b/utils/testrunner/testrunner.dart
@@ -41,16 +41,18 @@
* The three runtimes are:
*
* vm - run native Dart in the VM; i.e. using $DARTSDK/dart-sdk/bin/dart.
- * drt-dart - run native Dart in DumpRenderTree, the headless version of
- * Dartium, which is located in $DARTSDK/chromium/DumpRenderTree, if
+ * TODO(antonm): fix the option name.
+ * drt-dart - run native Dart in content shell, the headless version of
+ * Dartium, which is located in $DARTSDK/chromium/content_shell, if
* you installed the SDK that is bundled with the editor, or available
* from http://gsdview.appspot.com/dartium-archive/continuous/
* otherwise.
*
- * drt-js - run Dart compiled to Javascript in DumpRenderTree.
+ * TODO(antonm): fix the option name.
+ * drt-js - run Dart compiled to Javascript in content shell.
*
* testrunner supports simple DOM render tests. These can use expected values
- * for the render output from DumpRenderTree, either are textual DOM
+ * for the render output from content shell, either are textual DOM
* descriptions (`--layout-tests`) or pixel renderings (`--pixel-tests`).
* When running layout tests, testrunner will see if there is a file with
* a .png or a .txt extension in a directory with the same name as the
@@ -357,19 +359,19 @@
config['dart'] = '$dartsdk${pathSep}dart-sdk${pathSep}bin${pathSep}dart';
config['pub'] = '$dartsdk${pathSep}dart-sdk${pathSep}bin${pathSep}pub';
config['drt'] =
- '$dartsdk/chromium/DumpRenderTree.app/Contents/MacOS/DumpRenderTree';
+ '$dartsdk/chromium/Content Shell.app/Contents/MacOS/Content Shell';
} else if (Platform.operatingSystem == 'linux') {
config['dart2js'] =
'$dartsdk${pathSep}dart-sdk${pathSep}bin${pathSep}dart2js';
config['dart'] = '$dartsdk${pathSep}dart-sdk${pathSep}bin${pathSep}dart';
config['pub'] = '$dartsdk${pathSep}dart-sdk${pathSep}bin${pathSep}pub';
- config['drt'] = '$dartsdk${pathSep}chromium${pathSep}DumpRenderTree';
+ config['drt'] = '$dartsdk${pathSep}chromium${pathSep}content_shell';
} else {
config['dart2js'] =
'$dartsdk${pathSep}dart-sdk${pathSep}bin${pathSep}dart2js.bat';
config['dart'] = '$dartsdk${pathSep}dart-sdk${pathSep}bin${pathSep}dart.exe';
config['pub'] = '$dartsdk${pathSep}dart-sdk${pathSep}bin${pathSep}pub.bat';
- config['drt'] = '$dartsdk${pathSep}chromium${pathSep}DumpRenderTree.exe';
+ config['drt'] = '$dartsdk${pathSep}chromium${pathSep}content_shell.exe';
}
for (var prog in [ 'drt', 'dart', 'pub', 'dart2js' ]) {
diff --git a/utils/tests/testrunner/http_client_tests/http_client_test.dart b/utils/tests/testrunner/http_client_tests/http_client_test.dart
index b46745a..0016ce4 100644
--- a/utils/tests/testrunner/http_client_tests/http_client_test.dart
+++ b/utils/tests/testrunner/http_client_tests/http_client_test.dart
@@ -6,7 +6,6 @@
import 'dart:async';
import 'dart:io';
-import 'dart:uri';
import 'package:unittest/unittest.dart';
main() {