Version 0.6.6.0 .
svn merge -r 25013:25115 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
git-svn-id: http://dart.googlecode.com/svn/trunk@25119 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/pkg/analyzer_experimental/lib/src/generated/java_io.dart b/pkg/analyzer_experimental/lib/src/generated/java_io.dart
index d186c47..41c2e24 100644
--- a/pkg/analyzer_experimental/lib/src/generated/java_io.dart
+++ b/pkg/analyzer_experimental/lib/src/generated/java_io.dart
@@ -1,6 +1,7 @@
library java.io;
import "dart:io";
+import 'package:path/path.dart' as pathos;
class JavaSystemIO {
static Map<String, String> _properties = new Map();
@@ -33,14 +34,14 @@
String sdkPath;
// may be "xcodebuild/ReleaseIA32/dart" with "dart-sdk" sibling
{
- sdkPath = new Path(exec).directoryPath.append("dart-sdk").toNativePath();
+ sdkPath = pathos.join(pathos.dirname(exec), "dart-sdk");
if (new Directory(sdkPath).existsSync()) {
_properties[name] = sdkPath;
return sdkPath;
}
}
// probably be "dart-sdk/bin/dart"
- sdkPath = new Path(exec).directoryPath.directoryPath.toString();
+ sdkPath = pathos.dirname(pathos.dirname(exec));
_properties[name] = sdkPath;
return sdkPath;
}
@@ -58,26 +59,27 @@
class JavaFile {
static final String separator = Platform.pathSeparator;
static final int separatorChar = Platform.pathSeparator.codeUnitAt(0);
- Path _path;
+ String _path;
JavaFile(String path) {
- this._path = new Path(path);
+ _path = pathos.normalize(path);
}
JavaFile.relative(JavaFile base, String child) {
if (child.isEmpty) {
this._path = base._path;
} else {
- this._path = base._path.join(new Path(child));
+ this._path = pathos.join(base._path, child);
}
}
- JavaFile.fromUri(Uri uri) : this(uri.path);
+ JavaFile.fromUri(Uri uri) : this(pathos.fromUri(uri));
+ String toString() => _path.toString();
int get hashCode => _path.hashCode;
bool operator ==(other) {
- return other is JavaFile && other._path.toNativePath() == _path.toNativePath();
+ return other is JavaFile && other._path == _path;
}
- String getPath() => _path.toNativePath();
- String getName() => _path.filename;
+ String getPath() => _path;
+ String getName() => pathos.basename(_path);
String getParent() {
- var result = _path.directoryPath.toNativePath();
+ var result = pathos.dirname(_path);
// "." or "/" or "C:\"
if (result.length < 4) return null;
return result;
@@ -87,8 +89,8 @@
if (parent == null) return null;
return new JavaFile(parent);
}
- String getAbsolutePath() => _path.canonicalize().toNativePath();
- String getCanonicalPath() => _path.canonicalize().toNativePath();
+ String getAbsolutePath() => pathos.absolute(_path);
+ String getCanonicalPath() => _newFile().fullPathSync();
JavaFile getAbsoluteFile() => new JavaFile(getAbsolutePath());
JavaFile getCanonicalFile() => new JavaFile(getCanonicalPath());
bool exists() {
@@ -103,7 +105,7 @@
bool isDirectory() {
return _newDirectory().existsSync();
}
- Uri toURI() => new Uri(path: _path.toString());
+ Uri toURI() => pathos.toUri(_path);
String readAsStringSync() => _newFile().readAsStringSync();
int lastModified() {
if (!_newFile().existsSync()) return 0;
@@ -111,13 +113,13 @@
}
List<JavaFile> listFiles() {
- List<JavaFile> files = [];
- List<FileSystemEntity> entities = _newDirectory().listSync();
+ var files = <JavaFile>[];
+ var entities = _newDirectory().listSync();
for (FileSystemEntity entity in entities) {
files.add(new JavaFile(entity.path));
}
return files;
}
- File _newFile() => new File.fromPath(_path);
- Directory _newDirectory() => new Directory.fromPath(_path);
+ File _newFile() => new File(_path);
+ Directory _newDirectory() => new Directory(_path);
}
diff --git a/pkg/barback/lib/barback.dart b/pkg/barback/lib/barback.dart
index 8c3928e..eb0e1e8 100644
--- a/pkg/barback/lib/barback.dart
+++ b/pkg/barback/lib/barback.dart
@@ -6,7 +6,7 @@
export 'src/asset.dart';
export 'src/asset_id.dart';
-export 'src/asset_provider.dart';
export 'src/errors.dart';
+export 'src/package_provider.dart';
export 'src/transform.dart' show Transform;
export 'src/transformer.dart';
\ No newline at end of file
diff --git a/pkg/barback/lib/src/asset_graph.dart b/pkg/barback/lib/src/asset_cascade.dart
similarity index 78%
rename from pkg/barback/lib/src/asset_graph.dart
rename to pkg/barback/lib/src/asset_cascade.dart
index 5682fb1..0e8893a 100644
--- a/pkg/barback/lib/src/asset_graph.dart
+++ b/pkg/barback/lib/src/asset_cascade.dart
@@ -2,26 +2,39 @@
// 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 barback.asset_graph;
+library barback.asset_cascade;
import 'dart:async';
import 'dart:collection';
import 'asset.dart';
import 'asset_id.dart';
-import 'asset_provider.dart';
import 'asset_set.dart';
import 'errors.dart';
import 'change_batch.dart';
+import 'package_graph.dart';
import 'phase.dart';
import 'transformer.dart';
+import 'utils.dart';
-/// The main build dependency manager.
+/// The asset cascade for an individual package.
///
-/// For any given input file, it can tell which output files are affected by
-/// it, and vice versa.
-class AssetGraph {
- final AssetProvider _provider;
+/// This keeps track of which [Transformer]s are applied to which assets, and
+/// re-runs those transformers when their dependencies change. The transformed
+/// assets are accessible via [getAssetById].
+///
+/// A cascade consists of one or more [Phases], each of which has one or more
+/// [Transformer]s that run in parallel, potentially on the same inputs. The
+/// inputs of the first phase are the source assets for this cascade's package.
+/// The inputs of each successive phase are the outputs of the previous phase,
+/// as well as any assets that haven't yet been transformed.
+class AssetCascade {
+ /// The name of the package whose assets are managed.
+ final String package;
+
+ /// The [PackageGraph] that tracks all [AssetCascade]s for all dependencies of
+ /// the current app.
+ final PackageGraph _graph;
final _phases = <Phase>[];
@@ -33,10 +46,10 @@
Stream<BuildResult> get results => _resultsController.stream;
final _resultsController = new StreamController<BuildResult>.broadcast();
- /// A stream that emits any errors from the asset graph or the transformers.
+ /// A stream that emits any errors from the cascade or the transformers.
///
/// This emits errors as they're detected. If an error occurs in one part of
- /// the asset graph, unrelated parts will continue building.
+ /// the cascade, unrelated parts will continue building.
///
/// This will not emit programming errors from barback itself. Those will be
/// emitted through the [results] stream's error channel.
@@ -55,12 +68,12 @@
ChangeBatch _sourceChanges;
- /// Creates a new [AssetGraph].
+ /// Creates a new [AssetCascade].
///
- /// It loads source assets using [provider] and then uses [transformerPhases]
- /// to generate output files from them.
+ /// It loads source assets within [package] using [provider] and then uses
+ /// [transformerPhases] to generate output files from them.
//TODO(rnystrom): Better way of specifying transformers and their ordering.
- AssetGraph(this._provider,
+ AssetCascade(this._graph, this.package,
Iterable<Iterable<Transformer>> transformerPhases) {
// Flatten the phases to a list so we can traverse backwards to wire up
// each phase to its next.
@@ -84,6 +97,8 @@
/// it has been created and return it. If the asset cannot be found, throws
/// [AssetNotFoundException].
Future<Asset> getAssetById(AssetId id) {
+ assert(id.package == package);
+
// TODO(rnystrom): Waiting for the entire build to complete is unnecessary
// in some cases. Should optimize:
// * [id] may be generated before the compilation is finished. We should
@@ -95,7 +110,7 @@
// * If [id] has never been generated and all active transformers provide
// metadata about the file names of assets it can emit, we can prove that
// none of them can emit [id] and fail early.
- return _waitForProcess().then((_) {
+ return (_processDone == null ? new Future.value() : _processDone).then((_) {
// Each phase's inputs are the outputs of the previous phase. Find the
// last phase that contains the asset. Since the last phase has no
// transformers, this will find the latest output for that id.
@@ -126,6 +141,7 @@
/// transforms that use it will be re-applied.
void updateSources(Iterable<AssetId> sources) {
if (_sourceChanges == null) _sourceChanges = new ChangeBatch();
+ assert(sources.every((id) => id.package == package));
_sourceChanges.update(sources);
_waitForProcess();
@@ -134,6 +150,7 @@
/// Removes [removed] from the graph's known set of source assets.
void removeSources(Iterable<AssetId> removed) {
if (_sourceChanges == null) _sourceChanges = new ChangeBatch();
+ assert(removed.every((id) => id.package == package));
_sourceChanges.remove(removed);
_waitForProcess();
@@ -218,7 +235,7 @@
var futures = [];
for (var id in changes.updated) {
// TODO(rnystrom): Catch all errors from provider and route to results.
- futures.add(_provider.getAsset(id).then((asset) {
+ futures.add(_graph.provider.getAsset(id).then((asset) {
updated.add(asset);
}).catchError((error) {
if (error is AssetNotFoundException) {
@@ -238,7 +255,7 @@
}
}
-/// An event indicating that the asset graph has finished building.
+/// An event indicating that the cascade has finished building all assets.
///
/// A build can end either in success or failure. If there were no errors during
/// the build, it's considered to be a success; any errors render it a failure,
@@ -252,4 +269,28 @@
BuildResult(Iterable errors)
: errors = errors.toList();
+
+ /// Creates a build result indicating a successful build.
+ ///
+ /// This equivalent to a build result with no errors.
+ BuildResult.success()
+ : this([]);
+
+ String toString() {
+ if (succeeded) return "success";
+
+ return "errors:\n" + errors.map((error) {
+ var stackTrace = getAttachedStackTrace(error);
+ if (stackTrace != null) stackTrace = new Trace.from(stackTrace);
+
+ var msg = new StringBuffer();
+ msg.write(prefixLines(error.toString()));
+ if (stackTrace != null) {
+ msg.write("\n\n");
+ msg.write("Stack trace:\n");
+ msg.write(prefixLines(stackTrace.toString()));
+ }
+ return msg.toString();
+ }).join("\n\n");
+ }
}
diff --git a/pkg/barback/lib/src/asset_node.dart b/pkg/barback/lib/src/asset_node.dart
index 7bef7a0..ae2b70e 100644
--- a/pkg/barback/lib/src/asset_node.dart
+++ b/pkg/barback/lib/src/asset_node.dart
@@ -7,7 +7,6 @@
import 'dart:async';
import 'asset.dart';
-import 'asset_graph.dart';
import 'asset_id.dart';
import 'phase.dart';
import 'transform_node.dart';
diff --git a/pkg/barback/lib/src/errors.dart b/pkg/barback/lib/src/errors.dart
index 65dcad6..9ebca8e 100644
--- a/pkg/barback/lib/src/errors.dart
+++ b/pkg/barback/lib/src/errors.dart
@@ -36,3 +36,14 @@
String toString() => "Missing input $id.";
}
+
+/// Error thrown when a transformer outputs an asset with the wrong package
+/// name.
+class InvalidOutputException implements Exception {
+ final String package;
+ final AssetId id;
+
+ InvalidOutputException(this.package, this.id);
+
+ String toString() => "Invalid output $id: must be in package $package.";
+}
diff --git a/pkg/barback/lib/src/package_graph.dart b/pkg/barback/lib/src/package_graph.dart
new file mode 100644
index 0000000..4dc2719
--- /dev/null
+++ b/pkg/barback/lib/src/package_graph.dart
@@ -0,0 +1,119 @@
+// 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 barback.package_graph;
+
+import 'dart:async';
+
+import 'package:stack_trace/stack_trace.dart';
+
+import 'asset.dart';
+import 'asset_cascade.dart';
+import 'asset_id.dart';
+import 'errors.dart';
+import 'package_provider.dart';
+import 'utils.dart';
+
+/// The collection of [AssetCascade]s for an entire application.
+///
+/// This tracks each package's [AssetCascade] and routes asset requests between
+/// them.
+class PackageGraph {
+ /// The provider that exposes asset and package information.
+ final PackageProvider provider;
+
+ /// The [AssetCascade] for each package.
+ final _cascades = <String, AssetCascade>{};
+
+ /// The current [BuildResult] for each package's [AssetCascade].
+ ///
+ /// The result for a given package will be `null` if that [AssetCascade] is
+ /// actively building.
+ final _cascadeResults = <String, BuildResult>{};
+
+ /// A stream that emits a [BuildResult] each time the build is completed,
+ /// whether or not it succeeded.
+ ///
+ /// This will emit a result only once every package's [AssetCascade] has
+ /// finished building.
+ ///
+ /// If an unexpected error in barback itself occurs, it will be emitted
+ /// through this stream's error channel.
+ Stream<BuildResult> get results => _resultsController.stream;
+ final _resultsController = new StreamController<BuildResult>.broadcast();
+
+ /// A stream that emits any errors from the graph or the transformers.
+ ///
+ /// This emits errors as they're detected. If an error occurs in one part of
+ /// the graph, unrelated parts will continue building.
+ ///
+ /// This will not emit programming errors from barback itself. Those will be
+ /// emitted through the [results] stream's error channel.
+ Stream get errors => _errors;
+ Stream _errors;
+
+ /// Creates a new [PackageGraph] that will transform assets in all packages
+ /// made available by [provider].
+ PackageGraph(this.provider) {
+ for (var package in provider.packages) {
+ var cascade = new AssetCascade(this, package,
+ provider.getTransformers(package));
+ // The initial result for each cascade is "success" since the cascade
+ // doesn't start building until some source in that graph is updated.
+ _cascadeResults[package] = new BuildResult.success();
+ _cascades[package] = cascade;
+
+ cascade.results.listen((result) {
+ _cascadeResults[cascade.package] = result;
+ // If any cascade hasn't yet finished, the overall build isn't finished
+ // either.
+ if (_cascadeResults.values.any((result) => result == null)) return;
+
+ // Include all build errors for all cascades. If no cascades have
+ // errors, the result will automatically be considered a success.
+ _resultsController.add(new BuildResult(flatten(
+ _cascadeResults.values.map((result) => result.errors))));
+ }, onError: _resultsController.addError);
+ }
+
+ _errors = mergeStreams(_cascades.values.map((cascade) => cascade.errors));
+ }
+
+ /// Gets the asset identified by [id].
+ ///
+ /// If [id] is for a generated or transformed asset, this will wait until
+ /// it has been created and return it. If the asset cannot be found, throws
+ /// [AssetNotFoundException].
+ Future<Asset> getAssetById(AssetId id) {
+ var cascade = _cascades[id.package];
+ if (cascade != null) return cascade.getAssetById(id);
+ return new Future.error(
+ new AssetNotFoundException(id),
+ new Trace.current().vmTrace);
+ }
+
+ /// Adds [sources] to the graph's known set of source assets.
+ ///
+ /// Begins applying any transforms that can consume any of the sources. If a
+ /// given source is already known, it is considered modified and all
+ /// transforms that use it will be re-applied.
+ void updateSources(Iterable<AssetId> sources) {
+ groupBy(sources, (id) => id.package).forEach((package, ids) {
+ var cascade = _cascades[package];
+ if (cascade == null) throw new ArgumentError("Unknown package $package.");
+ _cascadeResults[package] = null;
+ cascade.updateSources(ids);
+ });
+ }
+
+ /// Removes [removed] from the graph's known set of source assets.
+ void removeSources(Iterable<AssetId> sources) {
+ groupBy(sources, (id) => id.package).forEach((package, ids) {
+ var cascade = _cascades[package];
+ if (cascade == null) throw new ArgumentError("Unknown package $package.");
+ _cascadeResults[package] = null;
+ cascade.removeSources(ids);
+ });
+ }
+}
diff --git a/pkg/barback/lib/src/asset_provider.dart b/pkg/barback/lib/src/package_provider.dart
similarity index 72%
rename from pkg/barback/lib/src/asset_provider.dart
rename to pkg/barback/lib/src/package_provider.dart
index 565e5ac..8506d14 100644
--- a/pkg/barback/lib/src/asset_provider.dart
+++ b/pkg/barback/lib/src/package_provider.dart
@@ -2,18 +2,19 @@
// 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 barback.asset_provider;
+library barback.package_provider;
import 'dart:async';
import 'asset.dart';
import 'asset_id.dart';
+import 'transformer.dart';
/// API for locating and accessing packages on disk.
///
/// Implemented by pub and provided to barback so that it isn't coupled
/// directly to pub.
-abstract class AssetProvider {
+abstract class PackageProvider {
/// The names of all packages that can be provided by this provider.
///
/// This is equal to the transitive closure of the entrypoint package
@@ -28,5 +29,11 @@
/// within the package, to only return the files within that subdirectory.
List<AssetId> listAssets(String package, {String within});
+ /// Returns the list of transformer phases that are applicable to [package].
+ ///
+ /// The phases will be run in sequence, with the outputs of one pipelined into
+ /// the next. All [Transformer]s in a single phase will be run in parallel.
+ Iterable<Iterable<Transformer>> getTransformers(String package);
+
Future<Asset> getAsset(AssetId id);
}
diff --git a/pkg/barback/lib/src/phase.dart b/pkg/barback/lib/src/phase.dart
index 26d64da..b4efbc7 100644
--- a/pkg/barback/lib/src/phase.dart
+++ b/pkg/barback/lib/src/phase.dart
@@ -7,7 +7,7 @@
import 'dart:async';
import 'asset.dart';
-import 'asset_graph.dart';
+import 'asset_cascade.dart';
import 'asset_id.dart';
import 'asset_node.dart';
import 'asset_set.dart';
@@ -15,7 +15,7 @@
import 'transform_node.dart';
import 'transformer.dart';
-/// One phase in the ordered series of transformations in an [AssetGraph].
+/// One phase in the ordered series of transformations in an [AssetCascade].
///
/// Each phase can access outputs from previous phases and can in turn pass
/// outputs to later phases. Phases are processed strictly serially. All
@@ -28,8 +28,8 @@
/// goes to advance to phase 3, it will see that modification and start the
/// waterfall from the beginning again.
class Phase {
- /// The graph that owns this phase.
- final AssetGraph graph;
+ /// The cascade that owns this phase.
+ final AssetCascade cascade;
/// This phase's position relative to the other phases. Zero-based.
final int _index;
@@ -64,7 +64,7 @@
/// Outputs from this phase will be passed to it.
final Phase _next;
- Phase(this.graph, this._index, this._transformers, this._next);
+ Phase(this.cascade, this._index, this._transformers, this._next);
/// Updates the phase's inputs with [updated] and removes [removed].
///
@@ -177,7 +177,7 @@
collisions = collisions.toList();
collisions.sort((a, b) => a.toString().compareTo(b.toString()));
for (var collision in collisions) {
- graph.reportError(new AssetCollisionException(collision));
+ cascade.reportError(new AssetCollisionException(collision));
// TODO(rnystrom): Define what happens after a collision occurs.
}
diff --git a/pkg/barback/lib/src/transform_node.dart b/pkg/barback/lib/src/transform_node.dart
index 194f073..b17c9a5 100644
--- a/pkg/barback/lib/src/transform_node.dart
+++ b/pkg/barback/lib/src/transform_node.dart
@@ -7,7 +7,6 @@
import 'dart:async';
import 'asset.dart';
-import 'asset_graph.dart';
import 'asset_id.dart';
import 'asset_node.dart';
import 'asset_set.dart';
@@ -62,9 +61,9 @@
var newOutputs = new AssetSet();
var transform = createTransform(this, newInputs, newOutputs);
return _transformer.apply(transform).catchError((error) {
- // Catch all transformer errors and pipe them to the results stream.
- // This is so a broken transformer doesn't take down the whole graph.
- phase.graph.reportError(error);
+ // Catch all transformer errors and pipe them to the results stream. This
+ // is so a broken transformer doesn't take down the whole graph.
+ phase.cascade.reportError(error);
// Don't allow partial results from a failed transform.
newOutputs.clear();
@@ -86,6 +85,16 @@
// See which outputs are missing from the last run.
var outputIds = newOutputs.map((asset) => asset.id).toSet();
+ var invalidIds = outputIds
+ .where((id) => id.package != phase.cascade.package).toSet();
+ outputIds.removeAll(invalidIds);
+
+ for (var id in invalidIds) {
+ // TODO(nweiz): report this as a warning rather than a failing error.
+ phase.cascade.reportError(
+ new InvalidOutputException(phase.cascade.package, id));
+ }
+
var removed = _outputs.difference(outputIds);
_outputs = outputIds;
diff --git a/pkg/barback/lib/src/utils.dart b/pkg/barback/lib/src/utils.dart
index c4ab3a3..9da4b0e 100644
--- a/pkg/barback/lib/src/utils.dart
+++ b/pkg/barback/lib/src/utils.dart
@@ -4,6 +4,8 @@
library barback.utils;
+import 'dart:async';
+
/// Converts a number in the range [0-255] to a two digit hex string.
///
/// For example, given `255`, returns `ff`.
@@ -12,4 +14,90 @@
const DIGITS = "0123456789abcdef";
return DIGITS[(byte ~/ 16) % 16] + DIGITS[byte % 16];
-}
\ No newline at end of file
+}
+
+/// Group the elements in [iter] by the value returned by [fn].
+///
+/// This returns a map whose keys are the return values of [fn] and whose values
+/// are lists of each element in [iter] for which [fn] returned that key.
+Map groupBy(Iterable iter, fn(element)) {
+ var map = {};
+ for (var element in iter) {
+ var list = map.putIfAbsent(fn(element), () => []);
+ list.add(element);
+ }
+ return map;
+}
+
+/// Flattens nested lists inside an iterable into a single list containing only
+/// non-list elements.
+List flatten(Iterable nested) {
+ var result = [];
+ helper(list) {
+ for (var element in list) {
+ if (element is List) {
+ helper(element);
+ } else {
+ result.add(element);
+ }
+ }
+ }
+ helper(nested);
+ return result;
+}
+
+/// Passes each key/value pair in [map] to [fn] and returns a new [Map] whose
+/// values are the return values of [fn].
+Map mapMapValues(Map map, fn(key, value)) =>
+ new Map.fromIterable(map.keys, value: (key) => fn(key, map[key]));
+
+/// Merges [streams] into a single stream that emits events from all sources.
+Stream mergeStreams(Iterable<Stream> streams) {
+ streams = streams.toList();
+ var doneCount = 0;
+ // Use a sync stream to preserve the synchrony behavior of the input streams.
+ // If the inputs are sync, then this will be sync as well; if the inputs are
+ // async, then the events we receive will also be async, and forwarding them
+ // sync won't change that.
+ var controller = new StreamController(sync: true);
+
+ for (var stream in streams) {
+ stream.listen((value) {
+ controller.add(value);
+ }, onError: (error) {
+ controller.addError(error);
+ }, onDone: () {
+ doneCount++;
+ if (doneCount == streams.length) controller.close();
+ });
+ }
+
+ return controller.stream;
+}
+
+/// Prepends each line in [text] with [prefix]. If [firstPrefix] is passed, the
+/// first line is prefixed with that instead.
+String prefixLines(String text, {String prefix: '| ', String firstPrefix}) {
+ var lines = text.split('\n');
+ if (firstPrefix == null) {
+ return lines.map((line) => '$prefix$line').join('\n');
+ }
+
+ var firstLine = "$firstPrefix${lines.first}";
+ lines = lines.skip(1).map((line) => '$prefix$line').toList();
+ lines.insert(0, firstLine);
+ return lines.join('\n');
+}
+
+/// Returns a [Future] that completes after pumping the event queue [times]
+/// times. By default, this should pump the event queue enough times to allow
+/// any code to run, as long as it's not waiting on some external event.
+Future pumpEventQueue([int times=20]) {
+ if (times == 0) return new Future.value();
+ // We use a delayed future to allow runAsync events to finish. The
+ // Future.value or Future() constructors use runAsync themselves and would
+ // therefore not wait for runAsync callbacks that are scheduled after invoking
+ // this method.
+ return new Future.delayed(Duration.ZERO, () => pumpEventQueue(times - 1));
+}
+
diff --git a/pkg/barback/pubspec.yaml b/pkg/barback/pubspec.yaml
index dcb2061..e0786a8 100644
--- a/pkg/barback/pubspec.yaml
+++ b/pkg/barback/pubspec.yaml
@@ -13,6 +13,7 @@
responsiveness.
dependencies:
path: any
+ stack_trace: any
dev_dependencies:
scheduled_test: any
unittest: any
diff --git a/pkg/barback/test/asset_graph/errors_test.dart b/pkg/barback/test/package_graph/errors_test.dart
similarity index 62%
rename from pkg/barback/test/asset_graph/errors_test.dart
rename to pkg/barback/test/package_graph/errors_test.dart
index 75e16bf..0653022 100644
--- a/pkg/barback/test/asset_graph/errors_test.dart
+++ b/pkg/barback/test/package_graph/errors_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.
-library barback.test.asset_graph.source_test;
+library barback.test.package_graph.source_test;
import 'dart:async';
import 'package:barback/barback.dart';
-import 'package:barback/src/asset_graph.dart';
import 'package:scheduled_test/scheduled_test.dart';
import '../utils.dart';
@@ -16,35 +15,43 @@
initConfig();
test("errors if two transformers output the same file", () {
- initGraph(["app|foo.a"], [
+ initGraph(["app|foo.a"], {"app": [
[
new RewriteTransformer("a", "b"),
new RewriteTransformer("a", "b")
]
- ]);
+ ]});
updateSources(["app|foo.a"]);
buildShouldFail([isAssetCollisionException("app|foo.b")]);
});
test("does not report asset not found errors in results", () {
- initGraph();
+ initGraph(["app|bar.txt"]);
+
+ // Trigger a build.
+ updateSources(["app|bar.txt"]);
expectNoAsset("app|foo.txt");
buildShouldSucceed();
});
- test("reports an error for an unprovided source", () {
+ test("reports an error for an unprovided package", () {
initGraph();
+ expect(() => updateSources(["unknown|foo.txt"]), throwsArgumentError);
+ });
+
+ test("reports an error for an unprovided source", () {
+ initGraph(["app|known.txt"]);
updateSources(["app|unknown.txt"]);
buildShouldFail([isAssetNotFoundException("app|unknown.txt")]);
});
test("reports missing input errors in results", () {
- initGraph({"app|a.txt": "a.inc"}, [
+ initGraph({"app|a.txt": "a.inc"}, {"app": [
[new ManyToOneTransformer("txt")]
- ]);
+ ]});
buildShouldFail([isMissingInputException("app|a.inc")]);
@@ -53,15 +60,26 @@
expectNoAsset("app|a.out");
});
+ test("reports an error if a transformer emits an asset for another package",
+ () {
+ initGraph(["app|foo.txt"], {
+ "app": [[new CreateAssetTransformer("wrong|foo.txt")]]
+ });
+
+ buildShouldFail([isInvalidOutputException("app", "wrong|foo.txt")]);
+
+ updateSources(["app|foo.txt"]);
+ });
+
test("fails if a non-primary input is removed", () {
initGraph({
"app|a.txt": "a.inc,b.inc,c.inc",
"app|a.inc": "a",
"app|b.inc": "b",
"app|c.inc": "c"
- }, [
+ }, {"app": [
[new ManyToOneTransformer("txt")]
- ]);
+ ]});
updateSources(["app|a.txt", "app|a.inc", "app|b.inc", "app|c.inc"]);
expectAsset("app|a.out", "abc");
@@ -76,9 +94,9 @@
});
test("catches transformer exceptions and reports them", () {
- initGraph(["app|foo.txt"], [
+ initGraph(["app|foo.txt"], {"app": [
[new BadTransformer(["app|foo.out"])]
- ]);
+ ]});
schedule(() {
updateSources(["app|foo.txt"]);
@@ -92,9 +110,9 @@
// TODO(rnystrom): Is this the behavior we expect? If a transformer fails
// to transform a file, should we just skip past it to the source?
test("yields a source if a transform fails on it", () {
- initGraph(["app|foo.txt"], [
+ initGraph(["app|foo.txt"], {"app": [
[new BadTransformer(["app|foo.txt"])]
- ]);
+ ]});
schedule(() {
updateSources(["app|foo.txt"]);
@@ -104,7 +122,7 @@
});
test("catches errors even if nothing is waiting for process results", () {
- initGraph(["app|foo.txt"], [[new BadTransformer([])]]);
+ initGraph(["app|foo.txt"], {"app": [[new BadTransformer([])]]});
schedule(() {
updateSources(["app|foo.txt"]);
@@ -116,9 +134,9 @@
});
test("discards outputs from failed transforms", () {
- initGraph(["app|foo.txt"], [
+ initGraph(["app|foo.txt"], {"app": [
[new BadTransformer(["a.out", "b.out"])]
- ]);
+ ]});
schedule(() {
updateSources(["app|foo.txt"]);
@@ -126,4 +144,32 @@
expectNoAsset("app|a.out");
});
+
+ test("fails if only one package fails", () {
+ initGraph(["pkg1|foo.txt", "pkg2|foo.txt"],
+ {"pkg1": [[new BadTransformer([])]]});
+
+ schedule(() {
+ updateSources(["pkg1|foo.txt", "pkg2|foo.txt"]);
+ });
+
+ expectAsset("pkg2|foo.txt", "foo");
+ buildShouldFail([equals(BadTransformer.ERROR)]);
+ });
+
+ test("emits multiple failures if multiple packages fail", () {
+ initGraph(["pkg1|foo.txt", "pkg2|foo.txt"], {
+ "pkg1": [[new BadTransformer([])]],
+ "pkg2": [[new BadTransformer([])]]
+ });
+
+ schedule(() {
+ updateSources(["pkg1|foo.txt", "pkg2|foo.txt"]);
+ });
+
+ buildShouldFail([
+ equals(BadTransformer.ERROR),
+ equals(BadTransformer.ERROR)
+ ]);
+ });
}
diff --git a/pkg/barback/test/asset_graph/source_test.dart b/pkg/barback/test/package_graph/source_test.dart
similarity index 92%
rename from pkg/barback/test/asset_graph/source_test.dart
rename to pkg/barback/test/package_graph/source_test.dart
index 8227edb..0367d88 100644
--- a/pkg/barback/test/asset_graph/source_test.dart
+++ b/pkg/barback/test/package_graph/source_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.
-library barback.test.asset_graph.source_test;
+library barback.test.package_graph.source_test;
import 'dart:async';
import 'package:barback/barback.dart';
-import 'package:barback/src/asset_graph.dart';
import 'package:scheduled_test/scheduled_test.dart';
import '../utils.dart';
@@ -44,9 +43,9 @@
});
test("gets a source asset if not transformed", () {
- initGraph(["app|foo.txt"], [
+ initGraph(["app|foo.txt"], {"app": [
[new RewriteTransformer("nottxt", "whatever")]
- ]);
+ ]});
updateSources(["app|foo.txt"]);
expectAsset("app|foo.txt");
@@ -67,7 +66,7 @@
test("collapses redundant updates", () {
var transformer = new RewriteTransformer("blub", "blab");
- initGraph(["app|foo.blub"], [[transformer]]);
+ initGraph(["app|foo.blub"], {"app": [[transformer]]});
schedule(() {
// Make a bunch of synchronous update calls.
@@ -108,7 +107,7 @@
test("restarts a build if a source is updated while sources are loading", () {
var transformer = new RewriteTransformer("txt", "out");
- initGraph(["app|foo.txt", "app|other.bar"], [[transformer]]);
+ initGraph(["app|foo.txt", "app|other.bar"], {"app": [[transformer]]});
// Run the whole graph so all nodes are clean.
updateSources(["app|foo.txt", "app|other.bar"]);
diff --git a/pkg/barback/test/asset_graph/transform_test.dart b/pkg/barback/test/package_graph/transform_test.dart
similarity index 75%
rename from pkg/barback/test/asset_graph/transform_test.dart
rename to pkg/barback/test/package_graph/transform_test.dart
index 64d506f..ceabe21 100644
--- a/pkg/barback/test/asset_graph/transform_test.dart
+++ b/pkg/barback/test/package_graph/transform_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.
-library barback.test.asset_graph.transform_test;
+library barback.test.package_graph.transform_test;
import 'dart:async';
import 'package:barback/barback.dart';
-import 'package:barback/src/asset_graph.dart';
import 'package:scheduled_test/scheduled_test.dart';
import '../utils.dart';
@@ -15,57 +14,57 @@
main() {
initConfig();
test("gets a transformed asset with a different path", () {
- initGraph(["app|foo.blub"], [
+ initGraph(["app|foo.blub"], {"app": [
[new RewriteTransformer("blub", "blab")]
- ]);
+ ]});
updateSources(["app|foo.blub"]);
expectAsset("app|foo.blab", "foo.blab");
});
test("gets a transformed asset with the same path", () {
- initGraph(["app|foo.blub"], [
+ initGraph(["app|foo.blub"], {"app": [
[new RewriteTransformer("blub", "blub")]
- ]);
+ ]});
updateSources(["app|foo.blub"]);
expectAsset("app|foo.blub", "foo.blub");
});
test("doesn't find an output from a later phase", () {
- initGraph(["app|foo.a"], [
+ initGraph(["app|foo.a"], {"app": [
[new RewriteTransformer("b", "c")],
[new RewriteTransformer("a", "b")]
- ]);
+ ]});
updateSources(["app|foo.a"]);
expectNoAsset("app|foo.c");
});
test("doesn't find an output from the same phase", () {
- initGraph(["app|foo.a"], [
+ initGraph(["app|foo.a"], {"app": [
[
new RewriteTransformer("a", "b"),
new RewriteTransformer("b", "c")
]
- ]);
+ ]});
updateSources(["app|foo.a"]);
expectAsset("app|foo.b", "foo.b");
expectNoAsset("app|foo.c");
});
test("finds the latest output before the transformer's phase", () {
- initGraph(["app|foo.blub"], [
+ initGraph(["app|foo.blub"], {"app": [
[new RewriteTransformer("blub", "blub")],
[
new RewriteTransformer("blub", "blub"),
new RewriteTransformer("blub", "done")
],
[new RewriteTransformer("blub", "blub")]
- ]);
+ ]});
updateSources(["app|foo.blub"]);
expectAsset("app|foo.done", "foo.blub.done");
});
test("applies multiple transformations to an asset", () {
- initGraph(["app|foo.a"], [
+ initGraph(["app|foo.a"], {"app": [
[new RewriteTransformer("a", "b")],
[new RewriteTransformer("b", "c")],
[new RewriteTransformer("c", "d")],
@@ -76,14 +75,14 @@
[new RewriteTransformer("h", "i")],
[new RewriteTransformer("i", "j")],
[new RewriteTransformer("j", "k")],
- ]);
+ ]});
updateSources(["app|foo.a"]);
expectAsset("app|foo.k", "foo.b.c.d.e.f.g.h.i.j.k");
});
test("only runs a transform once for all of its outputs", () {
var transformer = new RewriteTransformer("blub", "a b c");
- initGraph(["app|foo.blub"], [[transformer]]);
+ initGraph(["app|foo.blub"], {"app": [[transformer]]});
updateSources(["app|foo.blub"]);
expectAsset("app|foo.a", "foo.a");
expectAsset("app|foo.b", "foo.b");
@@ -96,7 +95,7 @@
test("runs transforms in the same phase in parallel", () {
var transformerA = new RewriteTransformer("txt", "a");
var transformerB = new RewriteTransformer("txt", "b");
- initGraph(["app|foo.txt"], [[transformerA, transformerB]]);
+ initGraph(["app|foo.txt"], {"app": [[transformerA, transformerB]]});
transformerA.wait();
transformerB.wait();
@@ -123,7 +122,7 @@
test("does not reapply transform when inputs are not modified", () {
var transformer = new RewriteTransformer("blub", "blab");
- initGraph(["app|foo.blub"], [[transformer]]);
+ initGraph(["app|foo.blub"], {"app": [[transformer]]});
updateSources(["app|foo.blub"]);
expectAsset("app|foo.blab", "foo.blab");
expectAsset("app|foo.blab", "foo.blab");
@@ -136,7 +135,7 @@
test("reapplies a transform when its input is modified", () {
var transformer = new RewriteTransformer("blub", "blab");
- initGraph(["app|foo.blub"], [[transformer]]);
+ initGraph(["app|foo.blub"], {"app": [[transformer]]});
schedule(() {
updateSources(["app|foo.blub"]);
@@ -167,7 +166,7 @@
"app|a.txt": "a.inc,b.inc",
"app|a.inc": "a",
"app|b.inc": "b"
- }, [[transformer]]);
+ }, {"app": [[transformer]]});
updateSources(["app|a.txt", "app|a.inc", "app|b.inc"]);
@@ -195,9 +194,9 @@
});
test("allows a transform to generate multiple outputs", () {
- initGraph({"app|foo.txt": "a.out,b.out"}, [
+ initGraph({"app|foo.txt": "a.out,b.out"}, {"app": [
[new OneToManyTransformer("txt")]
- ]);
+ ]});
updateSources(["app|foo.txt"]);
@@ -210,10 +209,10 @@
var aa = new RewriteTransformer("aa", "aaa");
var b = new RewriteTransformer("b", "bb");
var bb = new RewriteTransformer("bb", "bbb");
- initGraph(["app|foo.a", "app|foo.b"], [
+ initGraph(["app|foo.a", "app|foo.b"], {"app": [
[a, b],
[aa, bb],
- ]);
+ ]});
updateSources(["app|foo.a"]);
updateSources(["app|foo.b"]);
@@ -236,9 +235,9 @@
test("doesn't get an output from a transform whose primary input is removed",
() {
- initGraph(["app|foo.txt"], [
+ initGraph(["app|foo.txt"], {"app": [
[new RewriteTransformer("txt", "out")]
- ]);
+ ]});
updateSources(["app|foo.txt"]);
expectAsset("app|foo.out", "foo.out");
@@ -254,7 +253,7 @@
initGraph({
"app|a.txt": "a.inc",
"app|a.inc": "a"
- }, [[new ManyToOneTransformer("txt")]]);
+ }, {"app": [[new ManyToOneTransformer("txt")]]});
updateSources(["app|a.txt", "app|a.inc"]);
expectAsset("app|a.out", "a");
@@ -269,7 +268,7 @@
test("restarts processing if a change occurs during processing", () {
var transformer = new RewriteTransformer("txt", "out");
- initGraph(["app|foo.txt"], [[transformer]]);
+ initGraph(["app|foo.txt"], {"app": [[transformer]]});
transformer.wait();
@@ -301,9 +300,9 @@
initGraph({
"app|a.a": "a.out,shared.out",
"app|b.b": "b.out"
- }, [
+ }, {"app": [
[new OneToManyTransformer("a"), new OneToManyTransformer("b")]
- ]);
+ ]});
updateSources(["app|a.a", "app|b.b"]);
@@ -327,7 +326,8 @@
test("restarts before finishing later phases when a change occurs", () {
var txtToInt = new RewriteTransformer("txt", "int");
var intToOut = new RewriteTransformer("int", "out");
- initGraph(["app|foo.txt", "app|bar.txt"], [[txtToInt], [intToOut]]);
+ initGraph(["app|foo.txt", "app|bar.txt"],
+ {"app": [[txtToInt], [intToOut]]});
txtToInt.wait();
@@ -356,4 +356,55 @@
expect(intToOut.numRuns, equals(2));
});
});
+
+ test("applies transforms to the correct packages", () {
+ var rewrite1 = new RewriteTransformer("txt", "out1");
+ var rewrite2 = new RewriteTransformer("txt", "out2");
+ initGraph([
+ "pkg1|foo.txt",
+ "pkg2|foo.txt"
+ ], {"pkg1": [[rewrite1]], "pkg2": [[rewrite2]]});
+
+ updateSources(["pkg1|foo.txt", "pkg2|foo.txt"]);
+ expectAsset("pkg1|foo.out1", "foo.out1");
+ expectAsset("pkg2|foo.out2", "foo.out2");
+ buildShouldSucceed();
+ });
+
+ test("transforms don't see generated assets in other packages", () {
+ var fooToBar = new RewriteTransformer("foo", "bar");
+ var barToBaz = new RewriteTransformer("bar", "baz");
+ initGraph(["pkg1|file.foo"], {"pkg1": [[fooToBar]], "pkg2": [[barToBaz]]});
+
+ updateSources(["pkg1|file.foo"]);
+ expectAsset("pkg1|file.bar", "file.bar");
+ expectNoAsset("pkg2|file.baz");
+ buildShouldSucceed();
+ });
+
+ test("doesn't emit a result until all builds are finished", () {
+ var rewrite = new RewriteTransformer("txt", "out");
+ initGraph([
+ "pkg1|foo.txt",
+ "pkg2|foo.txt"
+ ], {"pkg1": [[rewrite]], "pkg2": [[rewrite]]});
+
+ // First, run both packages' transformers so both packages are successful.
+ updateSources(["pkg1|foo.txt", "pkg2|foo.txt"]);
+ expectAsset("pkg1|foo.out", "foo.out");
+ expectAsset("pkg2|foo.out", "foo.out");
+ buildShouldSucceed();
+
+ // pkg1 is still successful, but pkg2 is waiting on the provider, so the
+ // overall build shouldn't finish.
+ pauseProvider();
+ schedule(() => updateSources(["pkg2|foo.txt"]));
+ expectAsset("pkg1|foo.out", "foo.out");
+ buildShouldNotBeDone();
+
+ // Now that the provider is unpaused, pkg2's transforms finish and the
+ // overall build succeeds.
+ resumeProvider();
+ buildShouldSucceed();
+ });
}
diff --git a/pkg/barback/test/utils.dart b/pkg/barback/test/utils.dart
index 0641a57..1dda697 100644
--- a/pkg/barback/test/utils.dart
+++ b/pkg/barback/test/utils.dart
@@ -9,15 +9,18 @@
import 'dart:io';
import 'package:barback/barback.dart';
-import 'package:barback/src/asset_graph.dart';
+import 'package:barback/src/asset_cascade.dart';
+import 'package:barback/src/package_graph.dart';
+import 'package:barback/src/utils.dart';
import 'package:path/path.dart' as pathos;
import 'package:scheduled_test/scheduled_test.dart';
+import 'package:stack_trace/stack_trace.dart';
import 'package:unittest/compact_vm_config.dart';
var _configured = false;
MockProvider _provider;
-AssetGraph _graph;
+PackageGraph _graph;
/// Calls to [buildShouldSucceed] and [buildShouldFail] set expectations on
/// successive [BuildResult]s from [_graph]. This keeps track of how many calls
@@ -30,8 +33,8 @@
useCompactVMConfiguration();
}
-/// Creates a new [AssetProvider] and [AssetGraph] with the given [assets] and
-/// [transformers].
+/// Creates a new [PackageProvider] and [PackageGraph] with the given [assets]
+/// and [transformers].
///
/// This graph is used internally by most of the other functions in this
/// library so you must call it in the test before calling any of the other
@@ -42,16 +45,20 @@
/// one. If it's a [Map], each key should be a string that can be parsed to an
/// [AssetId] and the value should be a string defining the contents of that
/// asset.
-void initGraph([assets, Iterable<Iterable<Transformer>> transformers]) {
+///
+/// [transformers] is a map from package names to the transformers for each
+/// package.
+void initGraph([assets,
+ Map<String, Iterable<Iterable<Transformer>>> transformers]) {
if (assets == null) assets = [];
- if (transformers == null) transformers = [];
+ if (transformers == null) transformers = {};
- _provider = new MockProvider(assets);
- _graph = new AssetGraph(_provider, transformers);
+ _provider = new MockProvider(assets, transformers);
+ _graph = new PackageGraph(_provider);
_nextBuildResult = 0;
}
-/// Updates [assets] in the current [AssetProvider].
+/// Updates [assets] in the current [PackageProvider].
///
/// Each item in the list may either be an [AssetId] or a string that can be
/// parsed as one. Note that this method is not automatically scheduled.
@@ -65,7 +72,7 @@
_graph.updateSources(assets);
}
-/// Removes [assets] from the current [AssetProvider].
+/// Removes [assets] from the current [PackageProvider].
///
/// Each item in the list may either be an [AssetId] or a string that can be
/// parsed as one. Note that this method is not automatically scheduled.
@@ -89,12 +96,12 @@
}, "modify asset $name");
}
-/// Schedules a pause of the internally created [AssetProvider].
+/// Schedules a pause of the internally created [PackageProvider].
///
-/// All asset requests that the [AssetGraph] makes to the provider after this
+/// All asset requests that the [PackageGraph] makes to the provider after this
/// will not complete until [resumeProvider] is called.
void pauseProvider() {
- schedule(() =>_provider._pause(), "pause provider");
+ schedule(() => _provider._pause(), "pause provider");
}
/// Schedules an unpause of the provider after a call to [pauseProvider] and
@@ -103,9 +110,38 @@
schedule(() => _provider._resume(), "resume provider");
}
+/// Asserts that the current build step shouldn't have finished by this point in
+/// the schedule.
+///
+/// This uses the same build counter as [buildShouldSucceed] and
+/// [buildShouldFail], so those can be used to validate build results before and
+/// after this.
+void buildShouldNotBeDone() {
+ var resultAllowed = false;
+ var trace = new Trace.current();
+ _graph.results.elementAt(_nextBuildResult).then((result) {
+ if (resultAllowed) return;
+
+ currentSchedule.signalError(
+ new Exception("Expected build not to terminate "
+ "here, but it terminated with result: $result"), trace);
+ }).catchError((error) {
+ if (resultAllowed) return;
+ currentSchedule.signalError(error);
+ });
+
+ schedule(() {
+ // Pump the event queue in case the build completes out-of-band after we get
+ // here. If it does, we want to signal an error.
+ return pumpEventQueue().then((_) {
+ resultAllowed = true;
+ });
+ }, "ensuring build doesn't terminate");
+}
+
/// Expects that the next [BuildResult] is a build success.
void buildShouldSucceed() {
- expect(_graph.results.elementAt(_nextBuildResult++).then((result) {
+ expect(_getNextBuildResult().then((result) {
expect(result.succeeded, isTrue);
}), completes);
}
@@ -116,7 +152,7 @@
/// build to fail. Every matcher is expected to match an error, but the order of
/// matchers is unimportant.
void buildShouldFail(List matchers) {
- expect(_graph.results.elementAt(_nextBuildResult++).then((result) {
+ expect(_getNextBuildResult().then((result) {
expect(result.succeeded, isFalse);
expect(result.errors.length, equals(matchers.length));
for (var matcher in matchers) {
@@ -125,6 +161,9 @@
}), completes);
}
+Future<BuildResult> _getNextBuildResult() =>
+ _graph.results.elementAt(_nextBuildResult++);
+
/// Pauses the schedule until the currently running build completes.
///
/// Validates that the build completed successfully.
@@ -174,22 +213,6 @@
}, "get asset $name");
}
-/// Schedules an expectation that [graph] will have an error on an asset
-/// matching [name] for missing [input].
-Future expectMissingInput(AssetGraph graph, String name, String input) {
- var missing = new AssetId.parse(input);
-
- // Make sure the future gets the error.
- schedule(() {
- return graph.getAssetById(new AssetId.parse(name)).then((asset) {
- fail("Should have thrown error but got $asset.");
- }).catchError((error) {
- expect(error, new isInstanceOf<MissingInputException>());
- expect(error.id, equals(missing));
- });
- }, "get missing input on $name");
-}
-
/// Returns a matcher for an [AssetNotFoundException] with the given [id].
Matcher isAssetNotFoundException(String name) {
var id = new AssetId.parse(name);
@@ -214,11 +237,21 @@
predicate((error) => error.id == id, 'id is $name'));
}
+/// Returns a matcher for an [InvalidOutputException] with the given id and
+/// package name.
+Matcher isInvalidOutputException(String package, String name) {
+ var id = new AssetId.parse(name);
+ return allOf(
+ new isInstanceOf<InvalidOutputException>(),
+ predicate((error) => error.package == package, 'package is $package'),
+ predicate((error) => error.id == id, 'id is $name'));
+}
+
/// An [AssetProvider] that provides the given set of assets.
-class MockProvider implements AssetProvider {
+class MockProvider implements PackageProvider {
Iterable<String> get packages => _packages.keys;
- final _packages = new Map<String, List<MockAsset>>();
+ Map<String, _MockPackage> _packages;
/// The completer that [getAsset()] is waiting on to complete when paused.
///
@@ -238,26 +271,38 @@
_pauseCompleter = null;
}
- MockProvider(assets) {
+ MockProvider(assets,
+ Map<String, Iterable<Iterable<Transformer>>> transformers) {
+ var assetList;
if (assets is Map) {
- assets.forEach((asset, contents) {
+ assetList = assets.keys.map((asset) {
var id = new AssetId.parse(asset);
- var package = _packages.putIfAbsent(id.package, () => []);
- package.add(new MockAsset(id, contents));
+ return new MockAsset(id, assets[asset]);
});
} else if (assets is Iterable) {
- for (var asset in assets) {
+ assetList = assets.map((asset) {
var id = new AssetId.parse(asset);
- var package = _packages.putIfAbsent(id.package, () => []);
var contents = pathos.basenameWithoutExtension(id.path);
- package.add(new MockAsset(id, contents));
- }
+ return new MockAsset(id, contents);
+ });
}
+
+ _packages = mapMapValues(groupBy(assetList, (asset) => asset.id.package),
+ (package, assets) {
+ var packageTransformers = transformers[package];
+ if (packageTransformers == null) packageTransformers = [];
+ return new _MockPackage(assets, packageTransformers.toList());
+ });
+
+ // If there are no assets or transformers, add a dummy package. This better
+ // simulates the real world, where there'll always be at least the
+ // entrypoint package.
+ if (_packages.isEmpty) _packages = {"app": new _MockPackage([], [])};
}
void _modifyAsset(String name, String contents) {
var id = new AssetId.parse(name);
- var asset = _packages[id.package].firstWhere((a) => a.id == id);
+ var asset = _packages[id.package].assets.firstWhere((a) => a.id == id);
asset.contents = contents;
}
@@ -266,7 +311,15 @@
throw new UnimplementedError("Doesn't handle 'within' yet.");
}
- return _packages[package].map((asset) => asset.id);
+ return _packages[package].assets.map((asset) => asset.id);
+ }
+
+ Iterable<Iterable<Transformer>> getTransformers(String package) {
+ var mockPackage = _packages[package];
+ if (mockPackage == null) {
+ throw new ArgumentError("No package named $package.");
+ }
+ return mockPackage.transformers;
}
Future<Asset> getAsset(AssetId id) {
@@ -281,12 +334,22 @@
var package = _packages[id.package];
if (package == null) throw new AssetNotFoundException(id);
- return package.firstWhere((asset) => asset.id == id,
+ return package.assets.firstWhere((asset) => asset.id == id,
orElse: () => throw new AssetNotFoundException(id));
});
}
}
+/// Used by [MockProvider] to keep track of which assets and transformers exist
+/// for each package.
+class _MockPackage {
+ final List<MockAsset> assets;
+ final List<List<Transformer>> transformers;
+
+ _MockPackage(this.assets, Iterable<Iterable<Transformer>> transformers)
+ : transformers = transformers.map((phase) => phase.toList()).toList();
+}
+
/// A [Transformer] that takes assets ending with one extension and generates
/// assets with a given extension.
///
@@ -466,6 +529,21 @@
}
}
+/// A transformer that outputs an asset with the given id.
+class CreateAssetTransformer extends Transformer {
+ final String output;
+
+ CreateAssetTransformer(this.output);
+
+ Future<bool> isPrimary(Asset asset) => new Future.value(true);
+
+ Future apply(Transform transform) {
+ return new Future(() {
+ transform.addOutput(new MockAsset(new AssetId.parse(output), output));
+ });
+ }
+}
+
/// An implementation of [Asset] that never hits the file system.
class MockAsset implements Asset {
final AssetId id;
diff --git a/pkg/browser/lib/interop.js b/pkg/browser/lib/interop.js
index 52cc966..40e1700 100644
--- a/pkg/browser/lib/interop.js
+++ b/pkg/browser/lib/interop.js
@@ -13,6 +13,11 @@
ReceivePortSync.map[this.id] = this;
}
+// Type for remote proxies to Dart objects with dart2js.
+function DartProxy(o) {
+ this.o = o;
+}
+
(function() {
// Serialize the following types as follows:
// - primitives / null: unchanged
@@ -215,3 +220,320 @@
return deserialize(result);
}
})();
+
+(function() {
+ // Proxy support for js.dart.
+
+ var globalContext = window;
+
+ // Table for local objects and functions that are proxied.
+ function ProxiedObjectTable() {
+ // Name for debugging.
+ this.name = 'js-ref';
+
+ // Table from IDs to JS objects.
+ this.map = {};
+
+ // Generator for new IDs.
+ this._nextId = 0;
+
+ // Ports for managing communication to proxies.
+ this.port = new ReceivePortSync();
+ this.sendPort = this.port.toSendPort();
+ }
+
+ // Number of valid IDs. This is the number of objects (global and local)
+ // kept alive by this table.
+ ProxiedObjectTable.prototype.count = function () {
+ return Object.keys(this.map).length;
+ }
+
+ // Adds an object to the table and return an ID for serialization.
+ ProxiedObjectTable.prototype.add = function (obj) {
+ for (var ref in this.map) {
+ var o = this.map[ref];
+ if (o === obj) {
+ return ref;
+ }
+ }
+ var ref = this.name + '-' + this._nextId++;
+ this.map[ref] = obj;
+ return ref;
+ }
+
+ // Gets the object or function corresponding to this ID.
+ ProxiedObjectTable.prototype.get = function (id) {
+ if (!this.map.hasOwnProperty(id)) {
+ throw 'Proxy ' + id + ' has been invalidated.'
+ }
+ return this.map[id];
+ }
+
+ ProxiedObjectTable.prototype._initialize = function () {
+ // Configure this table's port to forward methods, getters, and setters
+ // from the remote proxy to the local object.
+ var table = this;
+
+ this.port.receive(function (message) {
+ // TODO(vsm): Support a mechanism to register a handler here.
+ try {
+ var receiver = table.get(message[0]);
+ var member = message[1];
+ var kind = message[2];
+ var args = message[3].map(deserialize);
+ if (kind == 'get') {
+ // Getter.
+ var field = member;
+ if (field in receiver && args.length == 0) {
+ return [ 'return', serialize(receiver[field]) ];
+ }
+ } else if (kind == 'set') {
+ // Setter.
+ var field = member;
+ if (args.length == 1) {
+ return [ 'return', serialize(receiver[field] = args[0]) ];
+ }
+ } else if (kind == 'hasProperty') {
+ var field = member;
+ return [ 'return', field in receiver ];
+ } else if (kind == 'apply') {
+ // Direct function invocation.
+ return [ 'return',
+ serialize(receiver.apply(args[0], args.slice(1))) ];
+ } else if (member == '[]' && args.length == 1) {
+ // Index getter.
+ return [ 'return', serialize(receiver[args[0]]) ];
+ } else if (member == '[]=' && args.length == 2) {
+ // Index setter.
+ return [ 'return', serialize(receiver[args[0]] = args[1]) ];
+ } else {
+ // Member function invocation.
+ var f = receiver[member];
+ if (f) {
+ var result = f.apply(receiver, args);
+ return [ 'return', serialize(result) ];
+ }
+ }
+ return [ 'none' ];
+ } catch (e) {
+ return [ 'throws', e.toString() ];
+ }
+ });
+ }
+
+ // Singleton for local proxied objects.
+ var proxiedObjectTable = new ProxiedObjectTable();
+ proxiedObjectTable._initialize()
+
+ // Type for remote proxies to Dart objects.
+ function DartProxy(id, sendPort) {
+ this.id = id;
+ this.port = sendPort;
+ }
+
+ // Serializes JS types to SendPortSync format:
+ // - primitives -> primitives
+ // - sendport -> sendport
+ // - Function -> [ 'funcref', function-id, sendport ]
+ // - Object -> [ 'objref', object-id, sendport ]
+ function serialize(message) {
+ if (message == null) {
+ return null; // Convert undefined to null.
+ } else if (typeof(message) == 'string' ||
+ typeof(message) == 'number' ||
+ typeof(message) == 'boolean') {
+ // Primitives are passed directly through.
+ return message;
+ } else if (message instanceof SendPortSync) {
+ // Non-proxied objects are serialized.
+ return message;
+ } else if (typeof(message) == 'function') {
+ if ('_dart_id' in message) {
+ // Remote function proxy.
+ var remoteId = message._dart_id;
+ var remoteSendPort = message._dart_port;
+ return [ 'funcref', remoteId, remoteSendPort ];
+ } else {
+ // Local function proxy.
+ return [ 'funcref',
+ proxiedObjectTable.add(message),
+ proxiedObjectTable.sendPort ];
+ }
+ } else if (message instanceof DartProxy) {
+ // Remote object proxy.
+ return [ 'objref', message.id, message.port ];
+ } else {
+ // Local object proxy.
+ return [ 'objref',
+ proxiedObjectTable.add(message),
+ proxiedObjectTable.sendPort ];
+ }
+ }
+
+ function deserialize(message) {
+ if (message == null) {
+ return null; // Convert undefined to null.
+ } else if (typeof(message) == 'string' ||
+ typeof(message) == 'number' ||
+ typeof(message) == 'boolean') {
+ // Primitives are passed directly through.
+ return message;
+ } else if (message instanceof SendPortSync) {
+ // Serialized type.
+ return message;
+ }
+ var tag = message[0];
+ switch (tag) {
+ case 'funcref': return deserializeFunction(message);
+ case 'objref': return deserializeObject(message);
+ }
+ throw 'Unsupported serialized data: ' + message;
+ }
+
+ // Create a local function that forwards to the remote function.
+ function deserializeFunction(message) {
+ var id = message[1];
+ var port = message[2];
+ // TODO(vsm): Add a more robust check for a local SendPortSync.
+ if ("receivePort" in port) {
+ // Local function.
+ return proxiedObjectTable.get(id);
+ } else {
+ // Remote function. Forward to its port.
+ var f = function () {
+ var args = Array.prototype.slice.apply(arguments);
+ args.splice(0, 0, this);
+ args = args.map(serialize);
+ var result = port.callSync([id, '#call', args]);
+ if (result[0] == 'throws') throw deserialize(result[1]);
+ return deserialize(result[1]);
+ };
+ // Cache the remote id and port.
+ f._dart_id = id;
+ f._dart_port = port;
+ return f;
+ }
+ }
+
+ // Creates a DartProxy to forwards to the remote object.
+ function deserializeObject(message) {
+ var id = message[1];
+ var port = message[2];
+ // TODO(vsm): Add a more robust check for a local SendPortSync.
+ if ("receivePort" in port) {
+ // Local object.
+ return proxiedObjectTable.get(id);
+ } else {
+ // Remote object.
+ return new DartProxy(id, port);
+ }
+ }
+
+ // Remote handler to construct a new JavaScript object given its
+ // serialized constructor and arguments.
+ function construct(args) {
+ args = args.map(deserialize);
+ var constructor = args[0];
+ args = Array.prototype.slice.call(args, 1);
+
+ // Until 10 args, the 'new' operator is used. With more arguments we use a
+ // generic way that may not work, particularly when the constructor does not
+ // have an "apply" method.
+ var ret = null;
+ if (args.length === 0) {
+ ret = new constructor();
+ } else if (args.length === 1) {
+ ret = new constructor(args[0]);
+ } else if (args.length === 2) {
+ ret = new constructor(args[0], args[1]);
+ } else if (args.length === 3) {
+ ret = new constructor(args[0], args[1], args[2]);
+ } else if (args.length === 4) {
+ ret = new constructor(args[0], args[1], args[2], args[3]);
+ } else if (args.length === 5) {
+ ret = new constructor(args[0], args[1], args[2], args[3], args[4]);
+ } else if (args.length === 6) {
+ ret = new constructor(args[0], args[1], args[2], args[3], args[4],
+ args[5]);
+ } else if (args.length === 7) {
+ ret = new constructor(args[0], args[1], args[2], args[3], args[4],
+ args[5], args[6]);
+ } else if (args.length === 8) {
+ ret = new constructor(args[0], args[1], args[2], args[3], args[4],
+ args[5], args[6], args[7]);
+ } else if (args.length === 9) {
+ ret = new constructor(args[0], args[1], args[2], args[3], args[4],
+ args[5], args[6], args[7], args[8]);
+ } else if (args.length === 10) {
+ ret = new constructor(args[0], args[1], args[2], args[3], args[4],
+ args[5], args[6], args[7], args[8], args[9]);
+ } else {
+ // Dummy Type with correct constructor.
+ var Type = function(){};
+ Type.prototype = constructor.prototype;
+
+ // Create a new instance
+ var instance = new Type();
+
+ // Call the original constructor.
+ ret = constructor.apply(instance, args);
+ ret = Object(ret) === ret ? ret : instance;
+ }
+ return serialize(ret);
+ }
+
+ // Remote handler to return the top-level JavaScript context.
+ function context(data) {
+ return serialize(globalContext);
+ }
+
+ // Return true if a JavaScript proxy is instance of a given type (instanceof).
+ function proxyInstanceof(args) {
+ var obj = deserialize(args[0]);
+ var type = deserialize(args[1]);
+ return obj instanceof type;
+ }
+
+ // Return true if a JavaScript proxy is instance of a given type (instanceof).
+ function proxyDeleteProperty(args) {
+ var obj = deserialize(args[0]);
+ var member = deserialize(args[1]);
+ delete obj[member];
+ }
+
+ function proxyConvert(args) {
+ return serialize(deserializeDataTree(args));
+ }
+
+ function deserializeDataTree(data) {
+ var type = data[0];
+ var value = data[1];
+ if (type === 'map') {
+ var obj = {};
+ for (var i = 0; i < value.length; i++) {
+ obj[value[i][0]] = deserializeDataTree(value[i][1]);
+ }
+ return obj;
+ } else if (type === 'list') {
+ var list = [];
+ for (var i = 0; i < value.length; i++) {
+ list.push(deserializeDataTree(value[i]));
+ }
+ return list;
+ } else /* 'simple' */ {
+ return deserialize(value);
+ }
+ }
+
+ function makeGlobalPort(name, f) {
+ var port = new ReceivePortSync();
+ port.receive(f);
+ window.registerPort(name, port.toSendPort());
+ }
+
+ makeGlobalPort('dart-js-context', context);
+ makeGlobalPort('dart-js-create', construct);
+ makeGlobalPort('dart-js-instanceof', proxyInstanceof);
+ makeGlobalPort('dart-js-delete-property', proxyDeleteProperty);
+ makeGlobalPort('dart-js-convert', proxyConvert);
+})();
diff --git a/pkg/docgen/README.md b/pkg/docgen/README.md
index a26d1e9..0e3b3da 100644
--- a/pkg/docgen/README.md
+++ b/pkg/docgen/README.md
@@ -1,11 +1,65 @@
+docgen
+======
+
A documentation generator for Dart.
+- - -
+The docgen tool takes in a file or directory as input and produces documentation
+for all `.dart` file it finds as YAML or JSON files. This outputs information
+about all classes, variables, functions, and methods defined in the library and
+its imported libraries.
-The docgen tool takes in a library as input and produces documentation
-for it as well as all libraries it imports and uses.
+### Generating Files & Uploading to Cloud Storage
-This outputs information about all classes, variables, functions, and
-methods defined in the library and its imported libraries.
+The viewer uses YAML files generated by the docgen package as the data
+being displayed. These files are stored in Google Cloud Storage.
-## USAGE
+ - Run `python upload_docgen.py` to generate these files and upload them to
+ Cloud Storage as a new version.
+- - -
+These tasks can be done separately if necessary:
- dart docgen.dart path/to/file.dart
\ No newline at end of file
+#####
+
+#### Generating YAML Files
+
+YAML files can be generated using the docgen package in the dart repository.
+
+###### Usage
+
+Run `dart docgen.dart [OPTIONS] <path to directory or file>`
+
+###### Options available
+
+- `-h`, `--help` Prints help and usage information.
+- `-v`, `--verbose` Output more logging information.
+- `-j`, `--[no-]json` Outputs to JSON. Files are outputted to YAML by default.
+- `--include-private` Flag to include private declarations.
+- `--include-sdk` Flag to parse SDK Library files imported.
+- `--parse-sdk` Parses the SDK libraries only. (Ignores the path passed in.)
+- `--package-root` Sets the package root of the library being analyzed.
+
+###### Output Directory
+Documented libraries will be located at bin/docs in either YAML or JSON format
+depending on options specified. There will also be a library_list.txt,
+containing a list of all the libraries inside the docs folder.
+
+To get more information on how to use the outputted documentation with
+dartdoc-viewer, please take a look at the
+[dartdoc-viewer documentation][dartdoc-viewer].
+
+[dartdoc-viewer]: https://github.com/dart-lang/dartdoc-viewer "Dartdoc-Viewer"
+
+#### Uploading to Cloud Storage
+
+To push new files to Google Cloud Storage for use by the viewer, use the
+`gsutil` tool located at third_party/gsutil/gsutil in the Dart repository.
+
+ - Run `python gsutil -m cp -q -a public-read -r <folder> gs://dartlang-docgen`
+ to upload the specified folder to the viewer's bucket. Be sure to also upload
+ a new VERSION file if the uploaded folder is to be used.**
+
+**Note that the bucket contains several numbered folders for each version of
+the documentation. Run `python gsutil ls gs://dartlang-docgen` to see the file
+layout. Follow this convention and update a new VERSION file when uploading
+a new version of documentation. You can see the format of the VERSION file
+by running `python gsutil cat gs://dartlang-docgen/VERSION`.
diff --git a/pkg/docgen/lib/dart2yaml.dart b/pkg/docgen/lib/dart2yaml.dart
index a481aca..cccb8eb 100644
--- a/pkg/docgen/lib/dart2yaml.dart
+++ b/pkg/docgen/lib/dart2yaml.dart
@@ -52,8 +52,11 @@
* Returns an escaped String form of the inputted element.
*/
String _processElement(var element) {
- return "\"${element.toString().replaceAll('\\', '\\\\')
- .replaceAll("\"", "\\\"")}\"\n";
+ var contents = element.toString()
+ .replaceAll('\\', r'\\')
+ .replaceAll('"', r'\"')
+ .replaceAll('\n', r'\n');
+ return '"$contents"\n';
}
/**
diff --git a/pkg/docgen/lib/docgen.dart b/pkg/docgen/lib/docgen.dart
index 357fe96..f88df54 100644
--- a/pkg/docgen/lib/docgen.dart
+++ b/pkg/docgen/lib/docgen.dart
@@ -266,9 +266,9 @@
}
}
});
- commentText = commentText == null ? '' :
- markdown.markdownToHtml(commentText.trim(), linkResolver: linkResolver)
- .replaceAll('\n', ' ');
+
+ commentText = commentText == null ? '' :
+ markdown.markdownToHtml(commentText.trim(), linkResolver: linkResolver);
return commentText;
}
@@ -300,9 +300,9 @@
mirrorMap.forEach((String mirrorName, VariableMirror mirror) {
if (includePrivate || !mirror.isPrivate) {
_currentMember = mirror;
- data[mirrorName] = new Variable(mirrorName, mirror.qualifiedName,
- mirror.isFinal, mirror.isStatic, mirror.type.qualifiedName,
- _getComment(mirror), _getAnnotations(mirror));
+ data[mirrorName] = new Variable(mirrorName, mirror.isFinal,
+ mirror.isStatic, mirror.type.qualifiedName, _getComment(mirror),
+ _getAnnotations(mirror));
}
});
return data;
@@ -311,21 +311,42 @@
/**
* Returns a map of [Method] objects constructed from inputted mirrors.
*/
-Map<String, Method> _getMethods(Map<String, MethodMirror> mirrorMap,
- bool includePrivate) {
- var data = {};
+Map<String, Map<String, Method>> _getMethods
+ (Map<String, MethodMirror> mirrorMap, bool includePrivate) {
+
+ var setters = {};
+ var getters = {};
+ var constructors = {};
+ var operators = {};
+ var methods = {};
+
mirrorMap.forEach((String mirrorName, MethodMirror mirror) {
if (includePrivate || !mirror.isPrivate) {
+ var method = new Method(mirrorName, mirror.isStatic,
+ mirror.returnType.qualifiedName, _getComment(mirror),
+ _getParameters(mirror.parameters), _getAnnotations(mirror));
_currentMember = mirror;
- data[mirrorName] = new Method(mirrorName, mirror.qualifiedName,
- mirror.isSetter, mirror.isGetter, mirror.isConstructor,
- mirror.isOperator, mirror.isStatic, mirror.returnType.qualifiedName,
- _getComment(mirror), _getParameters(mirror.parameters),
- _getAnnotations(mirror));
+ if (mirror.isSetter) {
+ setters[mirrorName] = method;
+ } else if (mirror.isGetter) {
+ getters[mirrorName] = method;
+ } else if (mirror.isConstructor) {
+ constructors[mirrorName] = method;
+ } else if (mirror.isOperator) {
+ operators[mirrorName] = method;
+ } else if (mirror.isRegularMethod) {
+ methods[mirrorName] = method;
+ } else {
+ throw new StateError('${mirror.qualifiedName} - no method type match');
+ }
}
});
- return data;
-}
+ return {'setters' : setters,
+ 'getters' : getters,
+ 'constructors' : constructors,
+ 'operators' : operators,
+ 'methods' : methods};
+}
/**
* Returns a map of [Class] objects constructed from inputted mirrors.
@@ -340,9 +361,8 @@
mirror.superclass.qualifiedName : '';
var interfaces =
mirror.superinterfaces.map((interface) => interface.qualifiedName);
- data[mirrorName] = new Class(mirrorName, mirror.qualifiedName,
- superclass, mirror.isAbstract, mirror.isTypedef,
- _getComment(mirror), interfaces.toList(),
+ data[mirrorName] = new Class(mirrorName, superclass, mirror.isAbstract,
+ mirror.isTypedef, _getComment(mirror), interfaces.toList(),
_getVariables(mirror.variables, includePrivate),
_getMethods(mirror.methods, includePrivate),
_getAnnotations(mirror));
@@ -358,10 +378,10 @@
var data = {};
mirrorList.forEach((ParameterMirror mirror) {
_currentMember = mirror;
- data[mirror.simpleName] = new Parameter(mirror.simpleName,
- mirror.qualifiedName, mirror.isOptional, mirror.isNamed,
- mirror.hasDefaultValue, mirror.type.qualifiedName,
- mirror.defaultValue, _getAnnotations(mirror));
+ data[mirror.simpleName] = new Parameter(mirror.simpleName,
+ mirror.isOptional, mirror.isNamed, mirror.hasDefaultValue,
+ mirror.type.qualifiedName, mirror.defaultValue,
+ _getAnnotations(mirror));
});
return data;
}
@@ -388,7 +408,11 @@
Map recurseMap(Map inputMap) {
var outputMap = {};
inputMap.forEach((key, value) {
- outputMap[key] = value.toMap();
+ if (value is Map) {
+ outputMap[key] = recurseMap(value);
+ } else {
+ outputMap[key] = value.toMap();
+ }
});
return outputMap;
}
@@ -405,8 +429,8 @@
Map<String, Variable> variables;
/// Top-level functions in the library.
- Map<String, Method> functions;
-
+ Map<String, Map<String, Method>> functions;
+
/// Classes defined within the library
Map<String, Class> classes;
@@ -443,26 +467,24 @@
Map<String, Variable> variables;
/// Methods in the class.
- Map<String, Method> methods;
-
+ Map<String, Map<String, Method>> methods;
+
String name;
- String qualifiedName;
String superclass;
bool isAbstract;
bool isTypedef;
/// List of the meta annotations on the class.
List<String> annotations;
-
- Class(this.name, this.qualifiedName, this.superclass, this.isAbstract,
- this.isTypedef, this.comment, this.interfaces, this.variables,
- this.methods, this.annotations);
+
+ Class(this.name, this.superclass, this.isAbstract, this.isTypedef,
+ this.comment, this.interfaces, this.variables, this.methods,
+ this.annotations);
/// Generates a map describing the [Class] object.
Map toMap() {
var classMap = {};
classMap['name'] = name;
- classMap['qualifiedname'] = qualifiedName;
classMap['comment'] = comment;
classMap['superclass'] = superclass;
classMap['abstract'] = isAbstract.toString();
@@ -484,22 +506,20 @@
String comment;
String name;
- String qualifiedName;
bool isFinal;
bool isStatic;
String type;
/// List of the meta annotations on the variable.
List<String> annotations;
-
- Variable(this.name, this.qualifiedName, this.isFinal, this.isStatic,
- this.type, this.comment, this.annotations);
-
+
+ Variable(this.name, this.isFinal, this.isStatic, this.type, this.comment,
+ this.annotations);
+
/// Generates a map describing the [Variable] object.
Map toMap() {
var variableMap = {};
variableMap['name'] = name;
- variableMap['qualifiedname'] = qualifiedName;
variableMap['comment'] = comment;
variableMap['final'] = isFinal.toString();
variableMap['static'] = isStatic.toString();
@@ -521,29 +541,20 @@
Map<String, Parameter> parameters;
String name;
- String qualifiedName;
- bool isSetter;
- bool isGetter;
- bool isConstructor;
- bool isOperator;
bool isStatic;
String returnType;
/// List of the meta annotations on the method.
List<String> annotations;
-
- Method(this.name, this.qualifiedName, this.isSetter, this.isGetter,
- this.isConstructor, this.isOperator, this.isStatic, this.returnType,
- this.comment, this.parameters, this.annotations);
-
+
+ Method(this.name, this.isStatic, this.returnType, this.comment,
+ this.parameters, this.annotations);
+
/// Generates a map describing the [Method] object.
Map toMap() {
var methodMap = {};
methodMap['name'] = name;
- methodMap['qualifiedname'] = qualifiedName;
methodMap['comment'] = comment;
- methodMap['type'] = isSetter ? 'setter' : isGetter ? 'getter' :
- isOperator ? 'operator' : isConstructor ? 'constructor' : 'method';
methodMap['static'] = isStatic.toString();
methodMap['return'] = returnType;
methodMap['parameters'] = recurseMap(parameters);
@@ -558,7 +569,6 @@
class Parameter {
String name;
- String qualifiedName;
bool isOptional;
bool isNamed;
bool hasDefaultValue;
@@ -567,15 +577,14 @@
/// List of the meta annotations on the parameter.
List<String> annotations;
-
- Parameter(this.name, this.qualifiedName, this.isOptional, this.isNamed,
- this.hasDefaultValue, this.type, this.defaultValue, this.annotations);
-
+
+ Parameter(this.name, this.isOptional, this.isNamed, this.hasDefaultValue,
+ this.type, this.defaultValue, this.annotations);
+
/// Generates a map describing the [Parameter] object.
Map toMap() {
var parameterMap = {};
parameterMap['name'] = name;
- parameterMap['qualifiedname'] = qualifiedName;
parameterMap['optional'] = isOptional.toString();
parameterMap['named'] = isNamed.toString();
parameterMap['default'] = hasDefaultValue.toString();
diff --git a/pkg/docgen/test/single_library_test.dart b/pkg/docgen/test/single_library_test.dart
index e92c857..f00ddc4 100644
--- a/pkg/docgen/test/single_library_test.dart
+++ b/pkg/docgen/test/single_library_test.dart
@@ -57,8 +57,12 @@
var classes = library.classes.values;
expect(classes.every((e) => e is Class), isTrue);
+ var classMethodTypes = [];
+ classes.forEach((e) => classMethodTypes.addAll(e.methods.values));
+ expect(classMethodTypes.every((e) => e is Map), isTrue);
+
var classMethods = [];
- classes.forEach((e) => classMethods.addAll(e.methods.values));
+ classMethodTypes.forEach((e) => classMethods.addAll(e.values));
expect(classMethods.every((e) => e is Method), isTrue);
var methodParameters = [];
@@ -67,7 +71,11 @@
});
expect(methodParameters.every((e) => e is Parameter), isTrue);
- var functions = library.functions.values;
+ var functionTypes = library.functions.values;
+ expect(functionTypes.every((e) => e is Map), isTrue);
+
+ var functions = [];
+ functionTypes.forEach((e) => functions.addAll(e.values));
expect(functions.every((e) => e is Method), isTrue);
var functionParameters = [];
diff --git a/pkg/path/lib/path.dart b/pkg/path/lib/path.dart
index b425124..25ce0e6 100644
--- a/pkg/path/lib/path.dart
+++ b/pkg/path/lib/path.dart
@@ -525,7 +525,7 @@
var needsSeparator = false;
var isAbsoluteAndNotRootRelative = false;
- for (var part in parts) {
+ for (var part in parts.where((part) => part != '')) {
if (this.isRootRelative(part) && isAbsoluteAndNotRootRelative) {
// If the new part is root-relative, it preserves the previous root but
// replaces the path after it.
diff --git a/pkg/path/test/posix_test.dart b/pkg/path/test/posix_test.dart
index f3232bc..c26a5ba 100644
--- a/pkg/path/test/posix_test.dart
+++ b/pkg/path/test/posix_test.dart
@@ -153,6 +153,14 @@
expect(builder.join('a', 'b', 'c', null, null), equals('a/b/c'));
});
+ test('ignores empty strings', () {
+ expect(builder.join(''), '');
+ expect(builder.join('', ''), '');
+ expect(builder.join('', 'a'), 'a');
+ expect(builder.join('a', '', 'b', '', '', '', 'c'), 'a/b/c');
+ expect(builder.join('a', 'b', ''), 'a/b');
+ });
+
test('disallows intermediate nulls', () {
expect(() => builder.join('a', null, 'b'), throwsArgumentError);
expect(() => builder.join(null, 'a'), throwsArgumentError);
diff --git a/pkg/path/test/url_test.dart b/pkg/path/test/url_test.dart
index 3e03d50..d040a59 100644
--- a/pkg/path/test/url_test.dart
+++ b/pkg/path/test/url_test.dart
@@ -223,6 +223,14 @@
expect(builder.join('a', 'b', 'c', null, null), equals('a/b/c'));
});
+ test('ignores empty strings', () {
+ expect(builder.join(''), '');
+ expect(builder.join('', ''), '');
+ expect(builder.join('', 'a'), 'a');
+ expect(builder.join('a', '', 'b', '', '', '', 'c'), 'a/b/c');
+ expect(builder.join('a', 'b', ''), 'a/b');
+ });
+
test('disallows intermediate nulls', () {
expect(() => builder.join('a', null, 'b'), throwsArgumentError);
expect(() => builder.join(null, 'a'), throwsArgumentError);
diff --git a/pkg/path/test/windows_test.dart b/pkg/path/test/windows_test.dart
index 7b3cf60..7409439 100644
--- a/pkg/path/test/windows_test.dart
+++ b/pkg/path/test/windows_test.dart
@@ -172,6 +172,14 @@
expect(builder.join('a', 'b', 'c', null, null), equals(r'a\b\c'));
});
+ test('ignores empty strings', () {
+ expect(builder.join(''), '');
+ expect(builder.join('', ''), '');
+ expect(builder.join('', 'a'), 'a');
+ expect(builder.join('a', '', 'b', '', '', '', 'c'), r'a\b\c');
+ expect(builder.join('a', 'b', ''), r'a\b');
+ });
+
test('disallows intermediate nulls', () {
expect(() => builder.join('a', null, 'b'), throwsArgumentError);
expect(() => builder.join(null, 'a'), throwsArgumentError);
diff --git a/pkg/pkg.status b/pkg/pkg.status
index 2b17cfc..0a89418 100644
--- a/pkg/pkg.status
+++ b/pkg/pkg.status
@@ -92,17 +92,11 @@
serialization/test/no_library_test: Fail # Issue 6490
[ $compiler == dart2js && $minified ]
-serialization/test/serialization_test: Fail # Issue 6490
-serialization/test/no_library_test: Fail # Issue 6490
-
# The unminified unittest tests test that the real names of Dart types are
# printed. Minified versions of these tests exist that test the behavior when
# minified.
unittest/test/*_unminified_test: Skip # DO NOT COPY THIS UNLESS YOU WORK ON DART2JS
-[ $compiler == dart2js && $unchecked && ($runtime == d8 || $runtime == chrome || $runtime == drt) ]
-crypto/test/sha1_test: Fail # V8 bug: https://code.google.com/p/v8/issues/detail?id=2692
-
[ $compiler == dart2js && $browser ]
path/test/dartium_test: Fail # Issue 6490
stack_trace/test/vm_test: Fail, OK # VM-specific traces
diff --git a/pkg/source_maps/lib/span.dart b/pkg/source_maps/lib/span.dart
index 7ca0ca9..1d2152d 100644
--- a/pkg/source_maps/lib/span.dart
+++ b/pkg/source_maps/lib/span.dart
@@ -69,6 +69,8 @@
bool operator ==(Span other) =>
sourceUrl == other.sourceUrl && start == other.start && end == other.end;
+ int get hashCode => sourceUrl.hashCode + start + (31 * (end - start));
+
String toString() => '<$runtimeType: $start $end $formatLocation $text>';
}
diff --git a/runtime/bin/bin.gypi b/runtime/bin/bin.gypi
index 731342a..d33f9ac 100644
--- a/runtime/bin/bin.gypi
+++ b/runtime/bin/bin.gypi
@@ -337,7 +337,7 @@
'type': 'none',
'toolsets':['host'],
'includes': [
- 'resources_sources.gypi'
+ 'resources_sources.gypi',
],
'actions': [
{
@@ -381,6 +381,9 @@
'builtin.h',
'io_natives.h',
'resources.h',
+ 'vmservice.h',
+ 'vmservice_impl.cc',
+ 'vmservice_impl.h',
'<(snapshot_cc_file)',
'<(resources_cc_file)',
],
@@ -442,6 +445,9 @@
'builtin.h',
'io_natives.h',
'resources.h',
+ 'vmservice.h',
+ 'vmservice_impl.cc',
+ 'vmservice_impl.h',
# Include generated source files.
'<(builtin_cc_file)',
'<(io_cc_file)',
diff --git a/runtime/bin/eventhandler.cc b/runtime/bin/eventhandler.cc
index 94f0778..3cb5456 100644
--- a/runtime/bin/eventhandler.cc
+++ b/runtime/bin/eventhandler.cc
@@ -5,6 +5,7 @@
#include "bin/dartutils.h"
#include "bin/eventhandler.h"
#include "bin/socket.h"
+#include "bin/thread.h"
#include "include/dart_api.h"
@@ -12,33 +13,61 @@
namespace dart {
namespace bin {
-static const int kNativeEventHandlerFieldIndex = 0;
static const intptr_t kTimerId = -1;
static const intptr_t kInvalidId = -2;
-/*
- * Returns the reference of the EventHandler stored in the native field.
- */
-static EventHandler* GetEventHandler(Dart_Handle handle) {
- intptr_t value = 0;
- Dart_Handle result = Dart_GetNativeInstanceField(
- handle, kNativeEventHandlerFieldIndex, &value);
- if (Dart_IsError(result)) {
- Dart_PropagateError(result);
+static EventHandler* event_handler = NULL;
+// TODO(ajohnsen): Consider removing mutex_ if we can enforce an invariant
+// that eventhandler is kept alive untill all isolates are closed.
+static dart::Mutex* mutex_ = new dart::Mutex();
+
+
+void TimeoutQueue::UpdateTimeout(Dart_Port port, int64_t timeout) {
+ // Find port if present.
+ Timeout* last = NULL;
+ Timeout* current = timeouts_;
+ while (current != NULL) {
+ if (current->port() == port) {
+ // Found.
+ if (timeout < 0) {
+ // Remove from list and delete existing.
+ if (last != NULL) {
+ last->set_next(current->next());
+ } else {
+ timeouts_ = current->next();
+ }
+ delete current;
+ } else {
+ // Update timeout.
+ current->set_timeout(timeout);
+ }
+ break;
+ }
+ last = current;
+ current = current->next();
}
- EventHandler* event_handler = reinterpret_cast<EventHandler*>(value);
- ASSERT(event_handler != NULL);
- return event_handler;
+ if (current == NULL && timeout >= 0) {
+ // Not found, create a new.
+ timeouts_ = new Timeout(port, timeout, timeouts_);
+ }
+ // Clear and find next timeout.
+ next_timeout_ = NULL;
+ current = timeouts_;
+ while (current != NULL) {
+ if (next_timeout_ == NULL ||
+ current->timeout() < next_timeout_->timeout()) {
+ next_timeout_ = current;
+ }
+ current = current->next();
+ }
}
-/*
- * Sets the reference of the EventHandler in the native field.
- */
-static void SetEventHandler(Dart_Handle handle, EventHandler* event_handler) {
- Dart_SetNativeInstanceField(handle,
- kNativeEventHandlerFieldIndex,
- reinterpret_cast<intptr_t>(event_handler));
+void EventHandler::Stop() {
+ MutexLocker locker(mutex_);
+ if (event_handler == NULL) return;
+ event_handler->Shutdown();
+ event_handler = NULL;
}
@@ -48,11 +77,9 @@
* object.
*/
void FUNCTION_NAME(EventHandler_Start)(Dart_NativeArguments args) {
- Dart_EnterScope();
- Dart_Handle handle = Dart_GetNativeArgument(args, 0);
- EventHandler* event_handler = EventHandler::Start();
- SetEventHandler(handle, event_handler);
- Dart_ExitScope();
+ MutexLocker locker(mutex_);
+ if (event_handler != NULL) return;
+ event_handler = EventHandler::Start();
}
@@ -63,8 +90,6 @@
*/
void FUNCTION_NAME(EventHandler_SendData)(Dart_NativeArguments args) {
Dart_EnterScope();
- Dart_Handle handle = Dart_GetNativeArgument(args, 0);
- EventHandler* event_handler = GetEventHandler(handle);
Dart_Handle sender = Dart_GetNativeArgument(args, 1);
intptr_t id = kInvalidId;
if (Dart_IsNull(sender)) {
@@ -72,11 +97,18 @@
} else {
Socket::GetSocketIdNativeField(sender, &id);
}
- handle = Dart_GetNativeArgument(args, 2);
+ Dart_Handle handle = Dart_GetNativeArgument(args, 2);
Dart_Port dart_port =
DartUtils::GetIntegerField(handle, DartUtils::kIdFieldName);
int64_t data = DartUtils::GetIntegerValue(Dart_GetNativeArgument(args, 3));
- event_handler->SendData(id, dart_port, data);
+ {
+ MutexLocker locker(mutex_);
+ // Only send if the event_handler is not NULL. This means that the handler
+ // shut down, and a message is send later on.
+ if (event_handler != NULL) {
+ event_handler->SendData(id, dart_port, data);
+ }
+ }
Dart_ExitScope();
}
diff --git a/runtime/bin/eventhandler.h b/runtime/bin/eventhandler.h
index 5d7832e..e75250f 100644
--- a/runtime/bin/eventhandler.h
+++ b/runtime/bin/eventhandler.h
@@ -27,6 +27,61 @@
kPipe = 17,
};
+
+class TimeoutQueue {
+ private:
+ class Timeout {
+ public:
+ Timeout(Dart_Port port, int64_t timeout, Timeout* next)
+ : port_(port), timeout_(timeout), next_(next) {}
+
+ Dart_Port port() const { return port_; }
+
+ int64_t timeout() const { return timeout_; }
+ void set_timeout(int64_t timeout) {
+ ASSERT(timeout >= 0);
+ timeout_ = timeout;
+ }
+
+ Timeout* next() const { return next_; }
+ void set_next(Timeout* next) {
+ next_ = next;
+ }
+
+ private:
+ Dart_Port port_;
+ int64_t timeout_;
+ Timeout* next_;
+ };
+
+ public:
+ TimeoutQueue() : next_timeout_(NULL), timeouts_(NULL) {}
+
+ ~TimeoutQueue() {
+ while (HasTimeout()) RemoveCurrent();
+ }
+
+ bool HasTimeout() const { return next_timeout_ != NULL; }
+
+ int64_t CurrentTimeout() const {
+ return next_timeout_->timeout();
+ }
+
+ Dart_Port CurrentPort() const {
+ return next_timeout_->port();
+ }
+
+ void RemoveCurrent() {
+ UpdateTimeout(CurrentPort(), -1);
+ }
+
+ void UpdateTimeout(Dart_Port port, int64_t timeout);
+
+ private:
+ Timeout* next_timeout_;
+ Timeout* timeouts_;
+};
+
} // namespace bin
} // namespace dart
@@ -59,12 +114,11 @@
static EventHandler* Start() {
EventHandler* handler = new EventHandler();
handler->delegate_.Start(handler);
- IsolateData* isolate_data =
- reinterpret_cast<IsolateData*>(Dart_CurrentIsolateData());
- isolate_data->event_handler = handler;
return handler;
}
+ static void Stop();
+
private:
friend class EventHandlerImplementation;
EventHandlerImplementation delegate_;
diff --git a/runtime/bin/eventhandler_android.cc b/runtime/bin/eventhandler_android.cc
index 74fb5da..594a6db 100644
--- a/runtime/bin/eventhandler_android.cc
+++ b/runtime/bin/eventhandler_android.cc
@@ -104,8 +104,6 @@
FDUtils::SetNonBlocking(interrupt_fds_[0]);
FDUtils::SetCloseOnExec(interrupt_fds_[0]);
FDUtils::SetCloseOnExec(interrupt_fds_[1]);
- timeout_ = kInfinityTimeout;
- timeout_port_ = 0;
shutdown_ = false;
// The initial size passed to epoll_create is ignore on newer (>=
// 2.6.8) Linux versions
@@ -194,8 +192,7 @@
InterruptMessage msg;
while (GetInterruptMessage(&msg)) {
if (msg.id == kTimerId) {
- timeout_ = msg.data;
- timeout_port_ = msg.dart_port;
+ timeout_queue_.UpdateTimeout(msg.dart_port, msg.data);
} else if (msg.id == kShutdownId) {
shutdown_ = true;
} else {
@@ -360,21 +357,22 @@
int64_t EventHandlerImplementation::GetTimeout() {
- if (timeout_ == kInfinityTimeout) {
+ if (!timeout_queue_.HasTimeout()) {
return kInfinityTimeout;
}
- int64_t millis = timeout_ - TimerUtils::GetCurrentTimeMilliseconds();
+ int64_t millis = timeout_queue_.CurrentTimeout() -
+ TimerUtils::GetCurrentTimeMilliseconds();
return (millis < 0) ? 0 : millis;
}
void EventHandlerImplementation::HandleTimeout() {
- if (timeout_ != kInfinityTimeout) {
- int64_t millis = timeout_ - TimerUtils::GetCurrentTimeMilliseconds();
+ if (timeout_queue_.HasTimeout()) {
+ int64_t millis = timeout_queue_.CurrentTimeout() -
+ TimerUtils::GetCurrentTimeMilliseconds();
if (millis <= 0) {
- DartUtils::PostNull(timeout_port_);
- timeout_ = kInfinityTimeout;
- timeout_port_ = 0;
+ DartUtils::PostNull(timeout_queue_.CurrentPort());
+ timeout_queue_.RemoveCurrent();
}
}
}
diff --git a/runtime/bin/eventhandler_android.h b/runtime/bin/eventhandler_android.h
index f127d6d..212193a 100644
--- a/runtime/bin/eventhandler_android.h
+++ b/runtime/bin/eventhandler_android.h
@@ -116,8 +116,7 @@
static uint32_t GetHashmapHashFromFd(intptr_t fd);
HashMap socket_map_;
- int64_t timeout_; // Time for next timeout.
- Dart_Port timeout_port_;
+ TimeoutQueue timeout_queue_;
bool shutdown_;
int interrupt_fds_[2];
int epoll_fd_;
diff --git a/runtime/bin/eventhandler_linux.cc b/runtime/bin/eventhandler_linux.cc
index 9ed591a..2b62391 100644
--- a/runtime/bin/eventhandler_linux.cc
+++ b/runtime/bin/eventhandler_linux.cc
@@ -111,8 +111,6 @@
FDUtils::SetNonBlocking(interrupt_fds_[0]);
FDUtils::SetCloseOnExec(interrupt_fds_[0]);
FDUtils::SetCloseOnExec(interrupt_fds_[1]);
- timeout_ = kInfinityTimeout;
- timeout_port_ = 0;
shutdown_ = false;
// The initial size passed to epoll_create is ignore on newer (>=
// 2.6.8) Linux versions
@@ -198,12 +196,12 @@
return (total_read == kInterruptMessageSize) ? true : false;
}
+
void EventHandlerImplementation::HandleInterruptFd() {
InterruptMessage msg;
while (GetInterruptMessage(&msg)) {
if (msg.id == kTimerId) {
- timeout_ = msg.data;
- timeout_port_ = msg.dart_port;
+ timeout_queue_.UpdateTimeout(msg.dart_port, msg.data);
} else if (msg.id == kShutdownId) {
shutdown_ = true;
} else {
@@ -365,21 +363,23 @@
int64_t EventHandlerImplementation::GetTimeout() {
- if (timeout_ == kInfinityTimeout) {
+ if (!timeout_queue_.HasTimeout()) {
return kInfinityTimeout;
}
- int64_t millis = timeout_ - TimerUtils::GetCurrentTimeMilliseconds();
+ int64_t millis = timeout_queue_.CurrentTimeout() -
+ TimerUtils::GetCurrentTimeMilliseconds();
return (millis < 0) ? 0 : millis;
}
void EventHandlerImplementation::HandleTimeout() {
- if (timeout_ != kInfinityTimeout) {
- int64_t millis = timeout_ - TimerUtils::GetCurrentTimeMilliseconds();
+ if (timeout_queue_.HasTimeout()) {
+ int64_t millis = timeout_queue_.CurrentTimeout() -
+ TimerUtils::GetCurrentTimeMilliseconds();
if (millis <= 0) {
- DartUtils::PostNull(timeout_port_);
- timeout_ = kInfinityTimeout;
- timeout_port_ = 0;
+ DartUtils::PostNull(timeout_queue_.CurrentPort());
+ // Remove current from queue.
+ timeout_queue_.RemoveCurrent();
}
}
}
diff --git a/runtime/bin/eventhandler_linux.h b/runtime/bin/eventhandler_linux.h
index d8fc509..3a2fe83 100644
--- a/runtime/bin/eventhandler_linux.h
+++ b/runtime/bin/eventhandler_linux.h
@@ -115,8 +115,7 @@
static uint32_t GetHashmapHashFromFd(intptr_t fd);
HashMap socket_map_;
- int64_t timeout_; // Time for next timeout.
- Dart_Port timeout_port_;
+ TimeoutQueue timeout_queue_;
bool shutdown_;
int interrupt_fds_[2];
int epoll_fd_;
diff --git a/runtime/bin/eventhandler_macos.cc b/runtime/bin/eventhandler_macos.cc
index 826e600..9a60d6f 100644
--- a/runtime/bin/eventhandler_macos.cc
+++ b/runtime/bin/eventhandler_macos.cc
@@ -130,8 +130,6 @@
FDUtils::SetNonBlocking(interrupt_fds_[0]);
FDUtils::SetCloseOnExec(interrupt_fds_[0]);
FDUtils::SetCloseOnExec(interrupt_fds_[1]);
- timeout_ = kInfinityTimeout;
- timeout_port_ = 0;
shutdown_ = false;
kqueue_fd_ = TEMP_FAILURE_RETRY(kqueue());
@@ -215,8 +213,7 @@
InterruptMessage msg;
while (GetInterruptMessage(&msg)) {
if (msg.id == kTimerId) {
- timeout_ = msg.data;
- timeout_port_ = msg.dart_port;
+ timeout_queue_.UpdateTimeout(msg.dart_port, msg.data);
} else if (msg.id == kShutdownId) {
shutdown_ = true;
} else {
@@ -360,21 +357,22 @@
int64_t EventHandlerImplementation::GetTimeout() {
- if (timeout_ == kInfinityTimeout) {
+ if (!timeout_queue_.HasTimeout()) {
return kInfinityTimeout;
}
- int64_t millis = timeout_ - TimerUtils::GetCurrentTimeMilliseconds();
+ int64_t millis = timeout_queue_.CurrentTimeout() -
+ TimerUtils::GetCurrentTimeMilliseconds();
return (millis < 0) ? 0 : millis;
}
void EventHandlerImplementation::HandleTimeout() {
- if (timeout_ != kInfinityTimeout) {
- int64_t millis = timeout_ - TimerUtils::GetCurrentTimeMilliseconds();
+ if (timeout_queue_.HasTimeout()) {
+ int64_t millis = timeout_queue_.CurrentTimeout() -
+ TimerUtils::GetCurrentTimeMilliseconds();
if (millis <= 0) {
- DartUtils::PostNull(timeout_port_);
- timeout_ = kInfinityTimeout;
- timeout_port_ = 0;
+ DartUtils::PostNull(timeout_queue_.CurrentPort());
+ timeout_queue_.RemoveCurrent();
}
}
}
diff --git a/runtime/bin/eventhandler_macos.h b/runtime/bin/eventhandler_macos.h
index 6bf4d61..0a17ed6 100644
--- a/runtime/bin/eventhandler_macos.h
+++ b/runtime/bin/eventhandler_macos.h
@@ -128,8 +128,7 @@
static uint32_t GetHashmapHashFromFd(intptr_t fd);
HashMap socket_map_;
- int64_t timeout_; // Time for next timeout.
- Dart_Port timeout_port_;
+ TimeoutQueue timeout_queue_;
bool shutdown_;
int interrupt_fds_[2];
int kqueue_fd_;
diff --git a/runtime/bin/eventhandler_patch.dart b/runtime/bin/eventhandler_patch.dart
index 1027708..46c1e3d 100644
--- a/runtime/bin/eventhandler_patch.dart
+++ b/runtime/bin/eventhandler_patch.dart
@@ -24,7 +24,7 @@
}
-class _EventHandlerImpl extends NativeFieldWrapperClass1 {
+class _EventHandlerImpl {
_EventHandlerImpl() { }
void _start() native "EventHandler_Start";
void _sendData(Object sender, ReceivePort receivePort, int data)
diff --git a/runtime/bin/eventhandler_win.cc b/runtime/bin/eventhandler_win.cc
index f1257c3..332f80f 100644
--- a/runtime/bin/eventhandler_win.cc
+++ b/runtime/bin/eventhandler_win.cc
@@ -670,8 +670,7 @@
if (msg->id == kTimeoutId) {
// Change of timeout request. Just set the new timeout and port as the
// completion thread will use the new timeout value for its next wait.
- timeout_ = msg->data;
- timeout_port_ = msg->dart_port;
+ timeout_queue_.UpdateTimeout(msg->dart_port, msg->data);
} else if (msg->id == kShutdownId) {
shutdown_ = true;
} else {
@@ -864,10 +863,9 @@
}
void EventHandlerImplementation::HandleTimeout() {
- // TODO(sgjesse) check if there actually is a timeout.
- DartUtils::PostNull(timeout_port_);
- timeout_ = kInfinityTimeout;
- timeout_port_ = 0;
+ if (!timeout_queue_.HasTimeout()) return;
+ DartUtils::PostNull(timeout_queue_.CurrentPort());
+ timeout_queue_.RemoveCurrent();
}
@@ -909,8 +907,6 @@
if (completion_port_ == NULL) {
FATAL("Completion port creation failed");
}
- timeout_ = kInfinityTimeout;
- timeout_port_ = 0;
shutdown_ = false;
}
@@ -921,10 +917,11 @@
int64_t EventHandlerImplementation::GetTimeout() {
- if (timeout_ == kInfinityTimeout) {
+ if (!timeout_queue_.HasTimeout()) {
return kInfinityTimeout;
}
- int64_t millis = timeout_ - TimerUtils::GetCurrentTimeMilliseconds();
+ int64_t millis = timeout_queue_.CurrentTimeout() -
+ TimerUtils::GetCurrentTimeMilliseconds();
return (millis < 0) ? 0 : millis;
}
diff --git a/runtime/bin/eventhandler_win.h b/runtime/bin/eventhandler_win.h
index 73e8917..280175c 100644
--- a/runtime/bin/eventhandler_win.h
+++ b/runtime/bin/eventhandler_win.h
@@ -390,8 +390,7 @@
private:
ClientSocket* client_sockets_head_;
- int64_t timeout_; // Time for next timeout.
- Dart_Port timeout_port_;
+ TimeoutQueue timeout_queue_; // Time for next timeout.
bool shutdown_;
HANDLE completion_port_;
};
diff --git a/runtime/bin/isolate_data.h b/runtime/bin/isolate_data.h
index 2992a08..df76864 100644
--- a/runtime/bin/isolate_data.h
+++ b/runtime/bin/isolate_data.h
@@ -21,11 +21,10 @@
class IsolateData {
public:
IsolateData()
- : event_handler(NULL), object_array_class(NULL),
+ : object_array_class(NULL),
growable_object_array_class(NULL), immutable_array_class(NULL) {
}
- EventHandler* event_handler;
Dart_PersistentHandle object_array_class;
Dart_PersistentHandle growable_object_array_class;
Dart_PersistentHandle immutable_array_class;
diff --git a/runtime/bin/main.cc b/runtime/bin/main.cc
index af29300..c749000 100644
--- a/runtime/bin/main.cc
+++ b/runtime/bin/main.cc
@@ -20,6 +20,7 @@
#include "bin/log.h"
#include "bin/platform.h"
#include "bin/process.h"
+#include "bin/vmservice_impl.h"
#include "platform/globals.h"
namespace dart {
@@ -66,6 +67,12 @@
static bool has_print_script = false;
+// VM Service options.
+static bool start_vm_service = false;
+static int vm_service_server_port = -1;
+static const int DEFAULT_VM_SERVICE_SERVER_PORT = 8181;
+
+
static bool IsValidFlag(const char* name,
const char* prefix,
intptr_t prefix_length) {
@@ -199,6 +206,25 @@
}
+static bool ProcessEnableVmServiceOption(const char* port) {
+ ASSERT(port != NULL);
+ vm_service_server_port = -1;
+ if (*port == '\0') {
+ vm_service_server_port = DEFAULT_VM_SERVICE_SERVER_PORT;
+ } else {
+ if ((*port == '=') || (*port == ':')) {
+ vm_service_server_port = atoi(port + 1);
+ }
+ }
+ if (vm_service_server_port < 0) {
+ Log::PrintErr("unrecognized --enable-vm-service option syntax. "
+ "Use --enable-vm-service[:<port number>]\n");
+ return false;
+ }
+ start_vm_service = true;
+ return true;
+}
+
static struct {
const char* option_name;
bool (*process)(const char* option);
@@ -217,6 +243,7 @@
{ "--snapshot=", ProcessGenScriptSnapshotOption },
{ "--print-script", ProcessPrintScriptOption },
{ "--check-function-fingerprints", ProcessFingerprintedFunctions },
+ { "--enable-vm-service", ProcessEnableVmServiceOption },
{ NULL, NULL }
};
@@ -549,6 +576,10 @@
"--print-script\n"
" generates Dart source code back and prints it after parsing a Dart script\n"
"\n"
+"--enable-vm-service[:<port number>]\n"
+" enables the VM service and listens on specified port for connections\n"
+" (default port number is 8181)\n"
+"\n"
"The following options are only used for VM development and may\n"
"be changed in any future version:\n");
const char* print_flags = "--print_flags";
@@ -593,10 +624,14 @@
}
-static const int kErrorExitCode = 255; // Indicates we encountered an error.
+// Exit code indicating a compilation error.
+static const int kCompilationErrorExitCode = 254;
+
+// Exit code indicating an unhandled error that is not a compilation error.
+static const int kErrorExitCode = 255;
-static int ErrorExit(const char* format, ...) {
+static int ErrorExit(int exit_code, const char* format, ...) {
va_list arguments;
va_start(arguments, format);
Log::VPrintErr(format, arguments);
@@ -606,14 +641,19 @@
Dart_ExitScope();
Dart_ShutdownIsolate();
- return kErrorExitCode;
+ return exit_code;
+}
+
+
+static int DartErrorExit(Dart_Handle error) {
+ const int exit_code = Dart_IsCompilationError(error) ?
+ kCompilationErrorExitCode : kErrorExitCode;
+ return ErrorExit(exit_code, "%s\n", Dart_GetError(error));
}
static void ShutdownIsolate(void* callback_data) {
IsolateData* isolate_data = reinterpret_cast<IsolateData*>(callback_data);
- EventHandler* handler = isolate_data->event_handler;
- if (handler != NULL) handler->Shutdown();
delete isolate_data;
}
@@ -720,6 +760,16 @@
}
}
+ // Start the VM service isolate, if necessary.
+ if (start_vm_service) {
+ ASSERT(vm_service_server_port >= 0);
+ bool r = VmService::Start(vm_service_server_port);
+ if (!r) {
+ Log::PrintErr("Could not start VM Service isolate %s",
+ VmService::GetErrorMessage());
+ }
+ }
+
// Call CreateIsolateAndSetup which creates an isolate and loads up
// the specified application script.
char* error = NULL;
@@ -767,14 +817,14 @@
if (has_compile_all) {
result = Dart_CompileAll();
if (Dart_IsError(result)) {
- return ErrorExit("%s\n", Dart_GetError(result));
+ return DartErrorExit(result);
}
}
if (has_check_function_fingerprints) {
result = Dart_CheckFunctionFingerprints();
if (Dart_IsError(result)) {
- return ErrorExit("%s\n", Dart_GetError(result));
+ return DartErrorExit(result);
}
}
@@ -782,19 +832,21 @@
Dart_Handle options_result =
SetupRuntimeOptions(&dart_options, executable_name, script_name);
if (Dart_IsError(options_result)) {
- return ErrorExit("%s\n", Dart_GetError(options_result));
+ return DartErrorExit(options_result);
}
// Lookup the library of the root script.
Dart_Handle library = Dart_RootLibrary();
if (Dart_IsNull(library)) {
- return ErrorExit("Unable to find root library for '%s'\n",
+ return ErrorExit(kErrorExitCode,
+ "Unable to find root library for '%s'\n",
script_name);
}
// Set debug breakpoint if specified on the command line.
if (breakpoint_at != NULL) {
result = SetBreakpoint(breakpoint_at, library);
if (Dart_IsError(result)) {
- return ErrorExit("Error setting breakpoint at '%s': %s\n",
+ return ErrorExit(kErrorExitCode,
+ "Error setting breakpoint at '%s': %s\n",
breakpoint_at,
Dart_GetError(result));
}
@@ -802,19 +854,19 @@
if (has_print_script) {
result = GenerateScriptSource();
if (Dart_IsError(result)) {
- return ErrorExit("%s\n", Dart_GetError(result));
+ return DartErrorExit(result);
}
} else {
// Lookup and invoke the top level main function.
result = Dart_Invoke(library, DartUtils::NewString("main"), 0, NULL);
if (Dart_IsError(result)) {
- return ErrorExit("%s\n", Dart_GetError(result));
+ return DartErrorExit(result);
}
// Keep handling messages until the last active receive port is closed.
result = Dart_RunLoop();
if (Dart_IsError(result)) {
- return ErrorExit("%s\n", Dart_GetError(result));
+ return DartErrorExit(result);
}
}
}
@@ -824,6 +876,8 @@
Dart_ShutdownIsolate();
// Terminate process exit-code handler.
Process::TerminateExitCodeHandler();
+ EventHandler::Stop();
+
// Free copied argument strings if converted.
if (argv_converted) {
for (int i = 0; i < argc; i++) free(argv[i]);
diff --git a/runtime/bin/resources.h b/runtime/bin/resources.h
index 0f3f7c3..6ee066a 100644
--- a/runtime/bin/resources.h
+++ b/runtime/bin/resources.h
@@ -30,6 +30,14 @@
return kNoSuchInstance;
}
+ static intptr_t get_resource_count() {
+ return builtin_resources_count_;
+ }
+
+ static const char* get_resource_path(intptr_t i) {
+ return get_resource(i)->path_;
+ }
+
private:
struct resource_map_entry {
const char* path_;
@@ -46,9 +54,6 @@
return &builtin_resources_[i];
}
- static intptr_t get_resource_count() {
- return builtin_resources_count_; }
-
DISALLOW_ALLOCATION();
DISALLOW_IMPLICIT_CONSTRUCTORS(Resources);
};
diff --git a/runtime/bin/resources_sources.gypi b/runtime/bin/resources_sources.gypi
index e48b460..1f9bb71 100644
--- a/runtime/bin/resources_sources.gypi
+++ b/runtime/bin/resources_sources.gypi
@@ -2,9 +2,8 @@
# BSD-style license that can be found in the LICENSE file.
# This file contains all sources for the Resources table.
-# Currently this is unused but at least one source file is needed to build.
{
'sources': [
- 'common_patch.dart'
+ 'vmservice/vmservice.dart',
],
}
diff --git a/runtime/bin/secure_socket_unsupported.cc b/runtime/bin/secure_socket_unsupported.cc
index 99e5e3b..de97dc8 100644
--- a/runtime/bin/secure_socket_unsupported.cc
+++ b/runtime/bin/secure_socket_unsupported.cc
@@ -95,6 +95,14 @@
}
+void FUNCTION_NAME(SecureSocket_Renegotiate)(Dart_NativeArguments args) {
+ Dart_EnterScope();
+ Dart_ThrowException(DartUtils::NewDartArgumentError(
+ "Secure Sockets unsupported on this platform"));
+ Dart_ExitScope();
+}
+
+
void FUNCTION_NAME(SecureSocket_NewServicePort)(Dart_NativeArguments args) {
Dart_EnterScope();
Dart_ThrowException(DartUtils::NewDartArgumentError(
diff --git a/runtime/bin/vmservice.h b/runtime/bin/vmservice.h
new file mode 100644
index 0000000..4dcf93f
--- /dev/null
+++ b/runtime/bin/vmservice.h
@@ -0,0 +1,17 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#ifndef BIN_VMSERVICE_H_
+#define BIN_VMSERVICE_H_
+
+#include "include/dart_api.h"
+
+namespace dart {
+namespace bin {
+
+
+} // namespace bin
+} // namespace dart
+
+#endif // BIN_VMSERVICE_H_
diff --git a/runtime/bin/vmservice/vmservice.dart b/runtime/bin/vmservice/vmservice.dart
new file mode 100644
index 0000000..e074e9a
--- /dev/null
+++ b/runtime/bin/vmservice/vmservice.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.
+
+library vmservice;
+
+import 'dart:async';
+import 'dart:json' as JSON;
+import 'dart:io';
+import 'dart:isolate';
+import 'dart:typed_data';
+import 'dart:utf' as UTF;
+
+
+void messageHandler(message, SendPort replyTo) {
+}
+
+
+main() {
+ port.receive(messageHandler);
+}
diff --git a/runtime/bin/vmservice_impl.cc b/runtime/bin/vmservice_impl.cc
new file mode 100644
index 0000000..c31544a
--- /dev/null
+++ b/runtime/bin/vmservice_impl.cc
@@ -0,0 +1,338 @@
+// 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/vmservice_impl.h"
+
+#include "include/dart_api.h"
+
+#include "bin/builtin.h"
+#include "bin/dartutils.h"
+#include "bin/resources.h"
+#include "bin/thread.h"
+#include "bin/isolate_data.h"
+
+
+namespace dart {
+namespace bin {
+
+// snapshot_buffer points to a snapshot if we link in a snapshot otherwise
+// it is initialized to NULL.
+extern const uint8_t* snapshot_buffer;
+#define RETURN_ERROR_HANDLE(handle) \
+ if (Dart_IsError(handle)) { \
+ return handle; \
+ }
+
+#define SHUTDOWN_ON_ERROR(handle) \
+ if (Dart_IsError(handle)) { \
+ error_msg_ = strdup(Dart_GetError(handle)); \
+ Dart_ExitScope(); \
+ Dart_ShutdownIsolate(); \
+ return false; \
+ }
+
+#define kLibraryResourceNamePrefix "/vmservice"
+static const char* kLibraryScriptResourceName =
+ kLibraryResourceNamePrefix "/vmservice.dart";
+static const char* kLibrarySourceResourceNames[] = {
+ NULL
+};
+
+#define kClientResourceNamePrefix "/client/web/out"
+
+Dart_Isolate VmService::isolate_ = NULL;
+Dart_Port VmService::port_ = ILLEGAL_PORT;
+dart::Monitor* VmService::monitor_ = NULL;
+const char* VmService::error_msg_ = NULL;
+
+// These must be kept in sync with vmservice/constants.dart
+#define VM_SERVICE_ISOLATE_STARTUP_MESSAGE_ID 1
+#define VM_SERVICE_ISOLATE_SHUTDOWN_MESSAGE_ID 2
+
+
+bool VmService::Start(intptr_t server_port) {
+ monitor_ = new dart::Monitor();
+ ASSERT(monitor_ != NULL);
+ error_msg_ = NULL;
+
+
+ {
+ // Take lock before spawning new thread.
+ MonitorLocker ml(monitor_);
+ // Spawn new thread.
+ dart::Thread::Start(ThreadMain, server_port);
+ // Wait until service is running on spawned thread.
+ ml.Wait();
+ }
+ return port_ != ILLEGAL_PORT;
+}
+
+
+bool VmService::_Start(intptr_t server_port) {
+ ASSERT(isolate_ == NULL);
+ char* error = NULL;
+ isolate_ = Dart_CreateIsolate("vmservice:", "main", snapshot_buffer,
+ new IsolateData(),
+ &error);
+ if (isolate_ == NULL) {
+ error_msg_ = error;
+ return false;
+ }
+
+ Dart_EnterScope();
+
+ if (snapshot_buffer != NULL) {
+ // Setup the native resolver as the snapshot does not carry it.
+ Builtin::SetNativeResolver(Builtin::kBuiltinLibrary);
+ Builtin::SetNativeResolver(Builtin::kIOLibrary);
+ }
+
+ // Set up the library tag handler for this isolate.
+ Dart_Handle result = Dart_SetLibraryTagHandler(DartUtils::LibraryTagHandler);
+ SHUTDOWN_ON_ERROR(result);
+
+ // Load the specified application script into the newly created isolate.
+
+ // 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 builtin_lib =
+ Builtin::LoadAndCheckLibrary(Builtin::kBuiltinLibrary);
+ SHUTDOWN_ON_ERROR(builtin_lib);
+
+ // Prepare for script loading by setting up the 'print' and 'timer'
+ // closures and setting up 'package root' for URI resolution.
+ result = DartUtils::PrepareForScriptLoading("", builtin_lib);
+ SHUTDOWN_ON_ERROR(result);
+
+ {
+ // Load source into service isolate.
+ Dart_Handle library = LoadScript(kLibraryScriptResourceName);
+ SHUTDOWN_ON_ERROR(library);
+ result = LoadSources(library, kLibrarySourceResourceNames);
+ SHUTDOWN_ON_ERROR(result);
+ }
+
+ // Make the isolate runnable so that it is ready to handle messages.
+ Dart_ExitScope();
+ Dart_ExitIsolate();
+
+ bool retval = Dart_IsolateMakeRunnable(isolate_);
+ if (!retval) {
+ Dart_EnterIsolate(isolate_);
+ Dart_ShutdownIsolate();
+ error_msg_ = "Invalid isolate state - Unable to make it runnable.";
+ return false;
+ }
+
+ Dart_EnterIsolate(isolate_);
+ Dart_EnterScope();
+
+ Dart_Handle library = Dart_RootLibrary();
+ result = Dart_Invoke(library, DartUtils::NewString("main"), 0, NULL);
+ SHUTDOWN_ON_ERROR(result);
+
+ result = LoadResources(library);
+ SHUTDOWN_ON_ERROR(result);
+
+ port_ = Dart_GetMainPortId();
+
+ Dart_ExitScope();
+ Dart_ExitIsolate();
+
+ return true;
+}
+
+
+void VmService::_Stop() {
+ port_ = ILLEGAL_PORT;
+}
+
+
+const char* VmService::GetErrorMessage() {
+ return error_msg_ == NULL ? "No error." : error_msg_;
+}
+
+
+Dart_Port VmService::port() {
+ return port_;
+}
+
+
+bool VmService::IsRunning() {
+ return port_ != ILLEGAL_PORT;
+}
+
+
+Dart_Handle VmService::LoadScript(const char* name) {
+ Dart_Handle url = Dart_NewStringFromCString(name);
+ const char* vmservice_source = NULL;
+ int r = Resources::ResourceLookup(name, &vmservice_source);
+ ASSERT(r != Resources::kNoSuchInstance);
+ Dart_Handle source = Dart_NewStringFromCString(vmservice_source);
+ return Dart_LoadScript(url, source, 0, 0);
+}
+
+
+Dart_Handle VmService::LoadSource(Dart_Handle library, const char* name) {
+ Dart_Handle url = Dart_NewStringFromCString(name);
+ const char* vmservice_source = NULL;
+ int r = Resources::ResourceLookup(name, &vmservice_source);
+ if (r == Resources::kNoSuchInstance) {
+ printf("Can't find %s\n", name);
+ }
+ ASSERT(r != Resources::kNoSuchInstance);
+ Dart_Handle source = Dart_NewStringFromCString(vmservice_source);
+ return Dart_LoadSource(library, url, source);
+}
+
+
+Dart_Handle VmService::LoadSources(Dart_Handle library, const char* names[]) {
+ Dart_Handle result = Dart_Null();
+ for (int i = 0; names[i] != NULL; i++) {
+ result = LoadSource(library, names[i]);
+ if (Dart_IsError(result)) {
+ break;
+ }
+ }
+ return result;
+}
+
+
+Dart_Handle VmService::LoadResource(Dart_Handle library,
+ const char* resource_name,
+ const char* prefix) {
+ intptr_t prefix_len = strlen(prefix);
+ // Prepare for invoke call.
+ Dart_Handle name = Dart_NewStringFromCString(resource_name+prefix_len);
+ RETURN_ERROR_HANDLE(name);
+ const char* data_buffer = NULL;
+ int data_buffer_length = Resources::ResourceLookup(resource_name,
+ &data_buffer);
+ if (data_buffer_length == Resources::kNoSuchInstance) {
+ printf("Could not find %s %s\n", resource_name, resource_name+prefix_len);
+ }
+ ASSERT(data_buffer_length != Resources::kNoSuchInstance);
+ Dart_Handle data_list = Dart_NewTypedData(Dart_TypedData_kUint8,
+ data_buffer_length);
+ RETURN_ERROR_HANDLE(data_list);
+ Dart_TypedData_Type type = Dart_TypedData_kInvalid;
+ void* data_list_buffer = NULL;
+ intptr_t data_list_buffer_length = 0;
+ Dart_Handle result = Dart_TypedDataAcquireData(data_list, &type,
+ &data_list_buffer,
+ &data_list_buffer_length);
+ RETURN_ERROR_HANDLE(result);
+ ASSERT(data_buffer_length == data_list_buffer_length);
+ ASSERT(data_list_buffer != NULL);
+ ASSERT(type = Dart_TypedData_kUint8);
+ memmove(data_list_buffer, &data_buffer[0], data_buffer_length);
+ result = Dart_TypedDataReleaseData(data_list);
+ RETURN_ERROR_HANDLE(result);
+
+ // Make invoke call.
+ const intptr_t kNumArgs = 2;
+ Dart_Handle args[kNumArgs] = { name, data_list };
+ result = Dart_Invoke(library, Dart_NewStringFromCString("_addResource"),
+ kNumArgs, args);
+ return result;
+}
+
+
+Dart_Handle VmService::LoadResources(Dart_Handle library) {
+ Dart_Handle result = Dart_Null();
+ intptr_t prefixLen = strlen(kClientResourceNamePrefix);
+ for (intptr_t i = 0; i < Resources::get_resource_count(); i++) {
+ const char* path = Resources::get_resource_path(i);
+ if (!strncmp(path, kClientResourceNamePrefix, prefixLen)) {
+ result = LoadResource(library, path, kClientResourceNamePrefix);
+ if (Dart_IsError(result)) {
+ break;
+ }
+ }
+ }
+ return result;
+}
+
+
+void VmService::ThreadMain(uword parameters) {
+ ASSERT(Dart_CurrentIsolate() == NULL);
+ ASSERT(isolate_ == NULL);
+
+ intptr_t server_port = static_cast<intptr_t>(parameters);
+ ASSERT(server_port >= 0);
+
+ // Lock scope.
+ {
+ MonitorLocker ml(monitor_);
+ bool r = _Start(server_port);
+ if (!r) {
+ port_ = ILLEGAL_PORT;
+ monitor_->Notify();
+ return;
+ }
+
+ Dart_EnterIsolate(isolate_);
+ Dart_EnterScope();
+
+ Dart_Handle receievePort = Dart_GetReceivePort(port_);
+ ASSERT(!Dart_IsError(receievePort));
+ monitor_->Notify();
+ }
+
+ // Keep handling messages until the last active receive port is closed.
+ Dart_Handle result = Dart_RunLoop();
+ if (Dart_IsError(result)) {
+ printf("VmService error %s\n", Dart_GetError(result));
+ }
+
+ _Stop();
+
+ Dart_ExitScope();
+ Dart_ExitIsolate();
+}
+
+
+
+
+static Dart_Handle MakeServiceControlMessage(Dart_Port port) {
+ Dart_Handle list = Dart_NewList(2);
+ ASSERT(!Dart_IsError(list));
+ Dart_Handle sendPort = Dart_NewSendPort(port);
+ ASSERT(!Dart_IsError(sendPort));
+ Dart_ListSetAt(list, 1, sendPort);
+ return list;
+}
+
+
+bool VmService::SendIsolateStartupMessage(Dart_Port port) {
+ if (!IsRunning()) {
+ return false;
+ }
+ Dart_Isolate isolate = Dart_CurrentIsolate();
+ ASSERT(isolate != NULL);
+ ASSERT(Dart_GetMainPortId() == port);
+ Dart_Handle list = MakeServiceControlMessage(port);
+ Dart_ListSetAt(list, 0,
+ Dart_NewInteger(VM_SERVICE_ISOLATE_STARTUP_MESSAGE_ID));
+ return Dart_Post(port_, list);
+}
+
+
+bool VmService::SendIsolateShutdownMessage(Dart_Port port) {
+ if (!IsRunning()) {
+ return false;
+ }
+ Dart_Isolate isolate = Dart_CurrentIsolate();
+ ASSERT(isolate != NULL);
+ ASSERT(Dart_GetMainPortId() == port);
+ Dart_Handle list = MakeServiceControlMessage(port);
+ Dart_ListSetAt(list, 0,
+ Dart_NewInteger(VM_SERVICE_ISOLATE_SHUTDOWN_MESSAGE_ID));
+ return Dart_Post(port_, list);
+}
+
+
+} // namespace bin
+} // namespace dart
diff --git a/runtime/bin/vmservice_impl.h b/runtime/bin/vmservice_impl.h
new file mode 100644
index 0000000..2807627
--- /dev/null
+++ b/runtime/bin/vmservice_impl.h
@@ -0,0 +1,54 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#ifndef BIN_VMSERVICE_IMPL_H_
+#define BIN_VMSERVICE_IMPL_H_
+
+#include "bin/vmservice.h"
+#include "platform/thread.h"
+
+
+namespace dart {
+namespace bin {
+
+class VmService {
+ public:
+ // Returns false if service could not be started.
+ static bool Start(intptr_t server_port);
+ // Error message if startup failed.
+ static const char* GetErrorMessage();
+
+ static Dart_Port port();
+
+ static bool IsRunning();
+
+ static bool SendIsolateStartupMessage(Dart_Port port);
+ static bool SendIsolateShutdownMessage(Dart_Port port);
+
+ private:
+ static bool _Start(intptr_t server_port);
+ static void _Stop();
+ static Dart_Handle LoadScript(const char* name);
+ static Dart_Handle LoadSources(Dart_Handle library, const char** names);
+ static Dart_Handle LoadSource(Dart_Handle library, const char* name);
+ static Dart_Handle LoadResources(Dart_Handle library);
+ static Dart_Handle LoadResource(Dart_Handle library, const char* name,
+ const char* prefix);
+
+ static void ThreadMain(uword parameters);
+
+ static Dart_Isolate isolate_;
+ static Dart_Port port_;
+ static const char* error_msg_;
+ static dart::Monitor* monitor_;
+
+ DISALLOW_ALLOCATION();
+ DISALLOW_IMPLICIT_CONSTRUCTORS(VmService);
+};
+
+
+} // namespace bin
+} // namespace dart
+
+#endif // BIN_VMSERVICE_IMPL_H_
diff --git a/runtime/lib/expando_patch.dart b/runtime/lib/expando_patch.dart
index 5de84c4..07ed0b7 100644
--- a/runtime/lib/expando_patch.dart
+++ b/runtime/lib/expando_patch.dart
@@ -114,8 +114,14 @@
for (var i = 0; i < old_data.length; i++) {
var entry = old_data[i];
- if ((entry != null) && (entry.key != null)) {
- this[entry.key] = entry.value;
+ if (entry != null) {
+ // Ensure that the entry.key is not cleared between checking for it and
+ // inserting it into the new table.
+ var val = entry.value;
+ var key = entry.key;
+ if (key != null) {
+ this[key] = val;
+ }
}
}
}
diff --git a/runtime/lib/invocation_mirror.cc b/runtime/lib/invocation_mirror.cc
index a8c70b3..913dcf4 100644
--- a/runtime/lib/invocation_mirror.cc
+++ b/runtime/lib/invocation_mirror.cc
@@ -35,8 +35,7 @@
const Function& function = Function::Handle(
Resolver::ResolveDynamic(receiver,
fun_name,
- args_desc.Count(),
- args_desc.NamedCount()));
+ args_desc));
Object& result = Object::Handle();
if (function.IsNull()) {
result = DartEntry::InvokeNoSuchMethod(receiver,
diff --git a/runtime/lib/mirrors.cc b/runtime/lib/mirrors.cc
index 3cb8690..1cb1c74 100644
--- a/runtime/lib/mirrors.cc
+++ b/runtime/lib/mirrors.cc
@@ -13,6 +13,7 @@
#include "vm/message.h"
#include "vm/port.h"
#include "vm/resolver.h"
+#include "vm/symbols.h"
namespace dart {
@@ -68,19 +69,6 @@
}
-static Dart_Handle IsMirror(Dart_Handle object, bool* is_mirror) {
- Dart_Handle cls_name = NewString("Mirror");
- Dart_Handle type = Dart_GetType(MirrorLib(), cls_name, 0, NULL);
- if (Dart_IsError(type)) {
- return type;
- }
- Dart_Handle result = Dart_ObjectIsType(object, type, is_mirror);
- if (Dart_IsError(result)) {
- return result;
- }
- return Dart_True(); // Indicates success. Result is in is_mirror.
-}
-
static Dart_Handle IsMethodMirror(Dart_Handle object, bool* is_mirror) {
Dart_Handle cls_name = NewString("MethodMirror");
Dart_Handle type = Dart_GetType(MirrorLib(), cls_name, 0, NULL);
@@ -108,14 +96,6 @@
}
-static bool IsSimpleValue(Dart_Handle object) {
- return (Dart_IsNull(object) ||
- Dart_IsNumber(object) ||
- Dart_IsString(object) ||
- Dart_IsBoolean(object));
-}
-
-
static void FreeVMReference(Dart_WeakPersistentHandle weak_ref, void* data) {
Dart_PersistentHandle perm_handle =
reinterpret_cast<Dart_PersistentHandle>(data);
@@ -282,58 +262,6 @@
// will return nonsense if mirror is not an ObjectMirror
}
-static Dart_Handle UnwrapArg(Dart_Handle arg) {
- if (Dart_IsError(arg)) {
- return arg;
- }
- bool is_mirror = false;
- Dart_Handle result = IsMirror(arg, &is_mirror);
- if (Dart_IsError(result)) {
- return result;
- }
- if (is_mirror) {
- return UnwrapMirror(arg);
- } else {
- // Simple value.
- ASSERT(IsSimpleValue(arg));
- return arg;
- }
-}
-
-static Dart_Handle UnwrapArgList(Dart_Handle arg_list,
- GrowableArray<Dart_Handle>* arg_array) {
- intptr_t len = 0;
- Dart_Handle result = Dart_ListLength(arg_list, &len);
- if (Dart_IsError(result)) {
- return result;
- }
- for (intptr_t i = 0; i < len; i++) {
- Dart_Handle arg = Dart_ListGetAt(arg_list, i);
- Dart_Handle unwrapped_arg = UnwrapArg(arg);
- if (Dart_IsError(unwrapped_arg)) {
- return unwrapped_arg;
- }
- arg_array->Add(unwrapped_arg);
- }
- return Dart_True();
-}
-
-static Dart_Handle UnpackLocalArgList(Dart_Handle arg_list,
- GrowableArray<Dart_Handle>* arg_array) {
- intptr_t len = 0;
- Dart_Handle result = Dart_ListLength(arg_list, &len);
- if (Dart_IsError(result)) {
- return result;
- }
- for (intptr_t i = 0; i < len; i++) {
- Dart_Handle arg = Dart_ListGetAt(arg_list, i);
- if (Dart_IsError(arg)) {
- return arg;
- }
- arg_array->Add(arg);
- }
- return Dart_True();
-}
static Dart_Handle CreateLazyMirror(Dart_Handle target);
@@ -631,69 +559,37 @@
static Dart_Handle CreateMethodMirror(Dart_Handle func,
Dart_Handle owner_mirror) {
- ASSERT(Dart_IsFunction(func));
+ // TODO(11742): Unwrapping is needed until the whole method is converted.
+ Isolate* isolate = Isolate::Current();
+ DARTSCOPE(isolate);
+ const Function& func_obj = Api::UnwrapFunctionHandle(isolate, func);
+
Dart_Handle mirror_cls_name = NewString("_LocalMethodMirrorImpl");
Dart_Handle mirror_type = Dart_GetType(MirrorLib(), mirror_cls_name, 0, NULL);
if (Dart_IsError(mirror_type)) {
return mirror_type;
}
- bool is_static = false;
- bool is_abstract = false;
- bool is_getter = false;
- bool is_setter = false;
- bool is_constructor = false;
-
- Dart_Handle result = Dart_FunctionIsStatic(func, &is_static);
- if (Dart_IsError(result)) {
- return result;
- }
- result = Dart_FunctionIsAbstract(func, &is_abstract);
- if (Dart_IsError(result)) {
- return result;
- }
- result = Dart_FunctionIsGetter(func, &is_getter);
- if (Dart_IsError(result)) {
- return result;
- }
- result = Dart_FunctionIsSetter(func, &is_setter);
- if (Dart_IsError(result)) {
- return result;
- }
- result = Dart_FunctionIsConstructor(func, &is_constructor);
- if (Dart_IsError(result)) {
- return result;
- }
-
Dart_Handle return_type = Dart_FunctionReturnType(func);
if (Dart_IsError(return_type)) {
return return_type;
}
- int64_t fixed_param_count;
- int64_t opt_param_count;
- result = Dart_FunctionParameterCounts(func,
- &fixed_param_count,
- &opt_param_count);
- if (Dart_IsError(result)) {
- return result;
- }
-
// TODO(turnidge): Implement constructor kinds (arguments 7 - 10).
Dart_Handle args[] = {
CreateMirrorReference(func),
owner_mirror,
CreateParameterMirrorList(func),
CreateLazyMirror(return_type),
- Dart_NewBoolean(is_static),
- Dart_NewBoolean(is_abstract),
- Dart_NewBoolean(is_getter),
- Dart_NewBoolean(is_setter),
- Dart_NewBoolean(is_constructor),
- Dart_False(),
- Dart_False(),
- Dart_False(),
- Dart_False(),
+ func_obj.is_static() ? Api::True() : Api::False(),
+ func_obj.is_abstract() ? Api::True() : Api::False(),
+ func_obj.IsGetterFunction() ? Api::True() : Api::False(),
+ func_obj.IsSetterFunction() ? Api::True() : Api::False(),
+ func_obj.IsConstructor() ? Api::True() : Api::False(),
+ Api::False(),
+ Api::False(),
+ Api::False(),
+ Api::False()
};
Dart_Handle mirror =
Dart_New(mirror_type, Dart_Null(), ARRAY_SIZE(args), args);
@@ -952,6 +848,7 @@
return member_map;
}
Dart_Handle args[] = {
+ CreateMirrorReference(lib),
CreateVMReference(lib),
Dart_LibraryName(lib),
Dart_LibraryUrl(lib),
@@ -1121,51 +1018,6 @@
}
-static Dart_Handle CreateMirroredError(Dart_Handle error) {
- ASSERT(Dart_IsError(error));
- if (Dart_IsUnhandledExceptionError(error)) {
- Dart_Handle exc = Dart_ErrorGetException(error);
- if (Dart_IsError(exc)) {
- return exc;
- }
- Dart_Handle exc_string = Dart_ToString(exc);
- if (Dart_IsError(exc_string)) {
- // Only propagate fatal errors from exc.toString(). Ignore the rest.
- if (Dart_IsFatalError(exc_string)) {
- return exc_string;
- }
- exc_string = Dart_Null();
- }
-
- Dart_Handle stack = Dart_ErrorGetStacktrace(error);
- if (Dart_IsError(stack)) {
- return stack;
- }
- Dart_Handle cls_name = NewString("MirroredUncaughtExceptionError");
- Dart_Handle type = Dart_GetType(MirrorLib(), cls_name, 0, NULL);
- Dart_Handle args[] = {
- CreateInstanceMirror(exc),
- exc_string,
- stack,
- };
- Dart_Handle mirrored_exc =
- Dart_New(type, Dart_Null(), ARRAY_SIZE(args), args);
- return Dart_NewUnhandledExceptionError(mirrored_exc);
- } else if (Dart_IsApiError(error) ||
- Dart_IsCompilationError(error)) {
- Dart_Handle cls_name = NewString("MirroredCompilationError");
- Dart_Handle type = Dart_GetType(MirrorLib(), cls_name, 0, NULL);
- Dart_Handle args[] = { NewString(Dart_GetError(error)) };
- Dart_Handle mirrored_exc =
- Dart_New(type, Dart_Null(), ARRAY_SIZE(args), args);
- return Dart_NewUnhandledExceptionError(mirrored_exc);
- } else {
- ASSERT(Dart_IsFatalError(error));
- return error;
- }
-}
-
-
void NATIVE_ENTRY_FUNCTION(Mirrors_makeLocalMirrorSystem)(
Dart_NativeArguments args) {
Dart_EnterScope();
@@ -1242,176 +1094,6 @@
Dart_ExitScope();
}
-void NATIVE_ENTRY_FUNCTION(LocalObjectMirrorImpl_invoke)(
- Dart_NativeArguments args) {
- Dart_EnterScope();
- Dart_Handle mirror = Dart_GetNativeArgument(args, 0);
- Dart_Handle member_name = Dart_GetNativeArgument(args, 1);
- // The arguments are either simple values or instance mirrors.
- Dart_Handle positional_arguments = Dart_GetNativeArgument(args, 2);
- Dart_Handle async = Dart_GetNativeArgument(args, 3);
-
- Dart_Handle reflectee = UnwrapMirror(mirror);
- Dart_Handle result;
- GrowableArray<Dart_Handle> invoke_args;
- if (Dart_IdentityEquals(async, Dart_True())) {
- result = UnwrapArgList(positional_arguments, &invoke_args);
- } else {
- result = UnpackLocalArgList(positional_arguments, &invoke_args);
- }
- if (Dart_IsError(result)) {
- Dart_PropagateError(result);
- }
- result = Dart_Invoke(reflectee,
- member_name,
- invoke_args.length(),
- invoke_args.data());
- if (Dart_IsError(result)) {
- // Instead of propagating the error from an invoke directly, we
- // provide reflective access to the error.
- Dart_PropagateError(CreateMirroredError(result));
- }
-
- Dart_Handle wrapped_result = CreateInstanceMirror(result);
- if (Dart_IsError(wrapped_result)) {
- Dart_PropagateError(wrapped_result);
- }
- Dart_SetReturnValue(args, wrapped_result);
- Dart_ExitScope();
-}
-
-
-void NATIVE_ENTRY_FUNCTION(LocalObjectMirrorImpl_getField)(
- Dart_NativeArguments args) {
- Dart_EnterScope();
- Dart_Handle mirror = Dart_GetNativeArgument(args, 0);
- Dart_Handle fieldName = Dart_GetNativeArgument(args, 1);
-
- Dart_Handle reflectee = UnwrapMirror(mirror);
- Dart_Handle result = Dart_GetField(reflectee, fieldName);
- if (Dart_IsError(result)) {
- // Instead of propagating the error from a GetField directly, we
- // provide reflective access to the error.
- Dart_PropagateError(CreateMirroredError(result));
- }
-
- Dart_Handle wrapped_result = CreateInstanceMirror(result);
- if (Dart_IsError(wrapped_result)) {
- Dart_PropagateError(wrapped_result);
- }
- Dart_SetReturnValue(args, wrapped_result);
- Dart_ExitScope();
-}
-
-
-void NATIVE_ENTRY_FUNCTION(LocalObjectMirrorImpl_setField)(
- Dart_NativeArguments args) {
- Dart_EnterScope();
- Dart_Handle mirror = Dart_GetNativeArgument(args, 0);
- Dart_Handle fieldName = Dart_GetNativeArgument(args, 1);
- Dart_Handle value = Dart_GetNativeArgument(args, 2);
- Dart_Handle async = Dart_GetNativeArgument(args, 3);
-
- Dart_Handle reflectee = UnwrapMirror(mirror);
- Dart_Handle set_arg;
- if (Dart_IdentityEquals(async, Dart_True())) {
- set_arg = UnwrapArg(value);
- } else {
- set_arg = value;
- }
- if (Dart_IsError(set_arg)) {
- Dart_PropagateError(set_arg);
- }
- Dart_Handle result = Dart_SetField(reflectee, fieldName, set_arg);
- if (Dart_IsError(result)) {
- // Instead of propagating the error from a SetField directly, we
- // provide reflective access to the error.
- Dart_PropagateError(CreateMirroredError(result));
- }
-
- Dart_Handle wrapped_result = CreateInstanceMirror(result);
- if (Dart_IsError(wrapped_result)) {
- Dart_PropagateError(wrapped_result);
- }
- Dart_SetReturnValue(args, wrapped_result);
- Dart_ExitScope();
-}
-
-
-void NATIVE_ENTRY_FUNCTION(LocalClosureMirrorImpl_apply)(
- Dart_NativeArguments args) {
- Dart_EnterScope();
- Dart_Handle mirror = Dart_GetNativeArgument(args, 0);
- // The arguments are either simple values or instance mirrors.
- Dart_Handle positional_arguments = Dart_GetNativeArgument(args, 1);
- Dart_Handle async = Dart_GetNativeArgument(args, 2);
-
- Dart_Handle reflectee = UnwrapMirror(mirror);
- GrowableArray<Dart_Handle> invoke_args;
- Dart_Handle result;
- if (Dart_IdentityEquals(async, Dart_True())) {
- result = UnwrapArgList(positional_arguments, &invoke_args);
- } else {
- result = UnpackLocalArgList(positional_arguments, &invoke_args);
- }
- if (Dart_IsError(result)) {
- Dart_PropagateError(result);
- }
- result =
- Dart_InvokeClosure(reflectee, invoke_args.length(), invoke_args.data());
- if (Dart_IsError(result)) {
- // Instead of propagating the error from an apply directly, we
- // provide reflective access to the error.
- Dart_PropagateError(CreateMirroredError(result));
- }
-
- Dart_Handle wrapped_result = CreateInstanceMirror(result);
- if (Dart_IsError(wrapped_result)) {
- Dart_PropagateError(wrapped_result);
- }
- Dart_SetReturnValue(args, wrapped_result);
- Dart_ExitScope();
-}
-
-
-void NATIVE_ENTRY_FUNCTION(LocalClassMirrorImpl_invokeConstructor)(
- Dart_NativeArguments args) {
- Dart_EnterScope();
- Dart_Handle klass_mirror = Dart_GetNativeArgument(args, 0);
- Dart_Handle constructor_name = Dart_GetNativeArgument(args, 1);
- // The arguments are either simple values or instance mirrors.
- Dart_Handle positional_arguments = Dart_GetNativeArgument(args, 2);
- Dart_Handle async = Dart_GetNativeArgument(args, 3);
-
- Dart_Handle klass = UnwrapMirror(klass_mirror);
- GrowableArray<Dart_Handle> invoke_args;
- Dart_Handle result;
- if (Dart_IdentityEquals(async, Dart_True())) {
- result = UnwrapArgList(positional_arguments, &invoke_args);
- } else {
- result = UnpackLocalArgList(positional_arguments, &invoke_args);
- }
- if (Dart_IsError(result)) {
- Dart_PropagateError(result);
- }
- result = Dart_New(klass,
- constructor_name,
- invoke_args.length(),
- invoke_args.data());
- if (Dart_IsError(result)) {
- // Instead of propagating the error from an invoke directly, we
- // provide reflective access to the error.
- Dart_PropagateError(CreateMirroredError(result));
- }
-
- Dart_Handle wrapped_result = CreateInstanceMirror(result);
- if (Dart_IsError(wrapped_result)) {
- Dart_PropagateError(wrapped_result);
- }
- Dart_SetReturnValue(args, wrapped_result);
- Dart_ExitScope();
-}
-
void HandleMirrorsMessage(Isolate* isolate,
Dart_Port reply_port,
@@ -1420,6 +1102,130 @@
}
+// TODO(11742): This is transitional.
+static RawInstance* Reflect(const Instance& reflectee) {
+ Isolate* isolate = Isolate::Current();
+ DARTSCOPE(isolate);
+ return Instance::RawCast(
+ Api::UnwrapHandle(
+ CreateInstanceMirror(
+ Api::NewHandle(isolate, reflectee.raw()))));
+}
+
+
+static void ThrowMirroredUnhandledError(const Error& original_error) {
+ const UnhandledException& unhandled_ex =
+ UnhandledException::Cast(original_error);
+ Instance& exc = Instance::Handle(unhandled_ex.exception());
+ Instance& stack = Instance::Handle(unhandled_ex.stacktrace());
+
+ Object& exc_string_or_error =
+ Object::Handle(DartLibraryCalls::ToString(exc));
+ String& exc_string = String::Handle();
+ // Ignore any errors that might occur in toString.
+ if (exc_string_or_error.IsString()) {
+ exc_string ^= exc_string_or_error.raw();
+ }
+
+ Instance& mirror_on_exc = Instance::Handle(Reflect(exc));
+
+ Array& args = Array::Handle(Array::New(3));
+ args.SetAt(0, mirror_on_exc);
+ args.SetAt(1, exc_string);
+ args.SetAt(2, stack);
+
+ Exceptions::ThrowByType(Exceptions::kMirroredUncaughtExceptionError, args);
+ UNREACHABLE();
+}
+
+
+static void ThrowMirroredCompilationError(const String& message) {
+ Array& args = Array::Handle(Array::New(1));
+ args.SetAt(0, message);
+
+ Exceptions::ThrowByType(Exceptions::kMirroredCompilationError, args);
+ UNREACHABLE();
+}
+
+
+static void ThrowInvokeError(const Error& error) {
+ if (error.IsUnhandledException()) {
+ // An ordinary runtime error.
+ ThrowMirroredUnhandledError(error);
+ }
+ if (error.IsLanguageError()) {
+ // A compilation error that was delayed by lazy compilation.
+ const LanguageError& compilation_error = LanguageError::Cast(error);
+ String& message = String::Handle(compilation_error.message());
+ ThrowMirroredCompilationError(message);
+ }
+ UNREACHABLE();
+}
+
+
+static RawFunction* ResolveConstructor(const char* current_func,
+ const Class& cls,
+ const String& class_name,
+ const String& constr_name,
+ int num_args) {
+ // The constructor must be present in the interface.
+ const Function& constructor =
+ Function::Handle(cls.LookupFunctionAllowPrivate(constr_name));
+ if (constructor.IsNull() ||
+ (!constructor.IsConstructor() && !constructor.IsFactory())) {
+ const String& lookup_class_name = String::Handle(cls.Name());
+ if (!class_name.Equals(lookup_class_name)) {
+ // When the class name used to build the constructor name is
+ // different than the name of the class in which we are doing
+ // the lookup, it can be confusing to the user to figure out
+ // what's going on. Be a little more explicit for these error
+ // messages.
+ const String& message = String::Handle(
+ String::NewFormatted(
+ "%s: could not find factory '%s' in class '%s'.",
+ current_func,
+ constr_name.ToCString(),
+ lookup_class_name.ToCString()));
+ ThrowMirroredCompilationError(message);
+ UNREACHABLE();
+ } else {
+ const String& message = String::Handle(
+ String::NewFormatted("%s: could not find constructor '%s'.",
+ current_func, constr_name.ToCString()));
+ ThrowMirroredCompilationError(message);
+ UNREACHABLE();
+ }
+ }
+ int extra_args = (constructor.IsConstructor() ? 2 : 1);
+ String& error_message = String::Handle();
+ if (!constructor.AreValidArgumentCounts(num_args + extra_args,
+ 0,
+ &error_message)) {
+ const String& message = String::Handle(
+ String::NewFormatted("%s: wrong argument count for "
+ "constructor '%s': %s.",
+ current_func,
+ constr_name.ToCString(),
+ error_message.ToCString()));
+ ThrowMirroredCompilationError(message);
+ UNREACHABLE();
+ }
+ return constructor.raw();
+}
+
+
+static bool FieldIsUninitialized(const Field& field) {
+ ASSERT(!field.IsNull());
+
+ // Return getter method for uninitialized fields, rather than the
+ // field object, since the value in the field object will not be
+ // initialized until the first time the getter is invoked.
+ const Instance& value = Instance::Handle(field.value());
+ ASSERT(value.raw() != Object::transition_sentinel().raw());
+ return value.raw() == Object::sentinel().raw();
+}
+
+
DEFINE_NATIVE_ENTRY(ClassMirror_name, 1) {
const MirrorReference& klass_ref =
MirrorReference::CheckedHandle(arguments->NativeArgAt(0));
@@ -1428,6 +1234,555 @@
return klass.Name();
}
+
+// Invoke the function, or noSuchMethod if it is null. Propagate any unhandled
+// exceptions. Wrap and propagate any compilation errors.
+static RawObject* ReflectivelyInvokeDynamicFunction(const Instance& receiver,
+ const Function& function,
+ const String& target_name,
+ const Array& arguments) {
+ // Note "arguments" is already the internal arguments with the receiver as
+ // the first element.
+ Object& result = Object::Handle();
+ if (function.IsNull()) {
+ const Array& arguments_descriptor =
+ Array::Handle(ArgumentsDescriptor::New(arguments.Length()));
+ result = DartEntry::InvokeNoSuchMethod(receiver,
+ target_name,
+ arguments,
+ arguments_descriptor);
+ } else {
+ result = DartEntry::InvokeFunction(function, arguments);
+ }
+
+ if (result.IsError()) {
+ ThrowInvokeError(Error::Cast(result));
+ UNREACHABLE();
+ }
+ return result.raw();
+}
+
+
+DEFINE_NATIVE_ENTRY(InstanceMirror_invoke, 4) {
+ // Argument 0 is the mirror, which is unused by the native. It exists
+ // because this native is an instance method in order to be polymorphic
+ // with its cousins.
+
+ const Instance& reflectee =
+ Instance::CheckedHandle(arguments->NativeArgAt(1));
+
+ const String& function_name =
+ String::CheckedHandle(arguments->NativeArgAt(2));
+
+ const Array& positional_args =
+ Array::CheckedHandle(arguments->NativeArgAt(3));
+ intptr_t number_of_arguments = positional_args.Length();
+
+ const Array& args =
+ Array::Handle(Array::New(number_of_arguments + 1)); // Plus receiver.
+ Object& arg = Object::Handle();
+ args.SetAt(0, reflectee);
+ for (int i = 0; i < number_of_arguments; i++) {
+ arg = positional_args.At(i);
+ args.SetAt(i + 1, arg); // Plus receiver.
+ }
+
+ ArgumentsDescriptor args_desc(
+ Array::Handle(ArgumentsDescriptor::New(args.Length())));
+ // TODO(11771): This won't find private members.
+ const Function& function = Function::Handle(
+ Resolver::ResolveDynamic(reflectee,
+ function_name,
+ args_desc));
+
+ return ReflectivelyInvokeDynamicFunction(reflectee,
+ function,
+ function_name,
+ args);
+}
+
+
+DEFINE_NATIVE_ENTRY(InstanceMirror_invokeGetter, 3) {
+ // Argument 0 is the mirror, which is unused by the native. It exists
+ // because this native is an instance method in order to be polymorphic
+ // with its cousins.
+
+ const Instance& reflectee =
+ Instance::CheckedHandle(arguments->NativeArgAt(1));
+
+ const String& getter_name =
+ String::CheckedHandle(arguments->NativeArgAt(2));
+
+ // Every instance field has a getter Function. Try to find the
+ // getter in any superclass and use that function to access the
+ // field.
+ // NB: We do not use Resolver::ResolveDynamic because we want to find private
+ // members.
+ Class& klass = Class::Handle(reflectee.clazz());
+ String& internal_getter_name = String::Handle(Field::GetterName(getter_name));
+ Function& getter = Function::Handle();
+ while (!klass.IsNull()) {
+ getter = klass.LookupDynamicFunctionAllowPrivate(internal_getter_name);
+ if (!getter.IsNull()) {
+ break;
+ }
+ klass = klass.SuperClass();
+ }
+
+ const int kNumArgs = 1;
+ const Array& args = Array::Handle(Array::New(kNumArgs));
+ args.SetAt(0, reflectee);
+
+ return ReflectivelyInvokeDynamicFunction(reflectee,
+ getter,
+ internal_getter_name,
+ args);
+}
+
+
+DEFINE_NATIVE_ENTRY(InstanceMirror_invokeSetter, 4) {
+ // Argument 0 is the mirror, which is unused by the native. It exists
+ // because this native is an instance method in order to be polymorphic
+ // with its cousins.
+
+ const Instance& reflectee =
+ Instance::CheckedHandle(arguments->NativeArgAt(1));
+
+ const String& setter_name =
+ String::CheckedHandle(arguments->NativeArgAt(2));
+
+ const Instance& value = Instance::CheckedHandle(arguments->NativeArgAt(3));
+
+ String& internal_setter_name =
+ String::Handle(Field::SetterName(setter_name));
+ Function& setter = Function::Handle();
+
+ Class& klass = Class::Handle(reflectee.clazz());
+ Field& field = Field::Handle();
+
+ while (!klass.IsNull()) {
+ field = klass.LookupInstanceField(setter_name);
+ if (!field.IsNull() && field.is_final()) {
+ const String& message = String::Handle(
+ String::NewFormatted("%s: cannot set final field '%s'.",
+ "InstanceMirror_invokeSetter",
+ setter_name.ToCString()));
+ ThrowMirroredCompilationError(message);
+ UNREACHABLE();
+ }
+ setter = klass.LookupDynamicFunctionAllowPrivate(internal_setter_name);
+ if (!setter.IsNull()) {
+ break;
+ }
+ klass = klass.SuperClass();
+ }
+
+ // Invoke the setter and return the result.
+ const int kNumArgs = 2;
+ const Array& args = Array::Handle(Array::New(kNumArgs));
+ args.SetAt(0, reflectee);
+ args.SetAt(1, value);
+
+ return ReflectivelyInvokeDynamicFunction(reflectee,
+ setter,
+ internal_setter_name,
+ args);
+}
+
+
+DEFINE_NATIVE_ENTRY(ClosureMirror_apply, 2) {
+ const Instance& closure = Instance::CheckedHandle(arguments->NativeArgAt(0));
+ ASSERT(!closure.IsNull() && closure.IsCallable(NULL, NULL));
+
+ const Array& positional_args =
+ Array::CheckedHandle(arguments->NativeArgAt(1));
+ intptr_t number_of_arguments = positional_args.Length();
+
+ // Set up arguments to include the closure as the first argument.
+ const Array& args = Array::Handle(Array::New(number_of_arguments + 1));
+ Object& obj = Object::Handle();
+ args.SetAt(0, closure);
+ for (int i = 0; i < number_of_arguments; i++) {
+ obj = positional_args.At(i);
+ args.SetAt(i + 1, obj);
+ }
+
+ obj = DartEntry::InvokeClosure(args);
+ if (obj.IsError()) {
+ ThrowInvokeError(Error::Cast(obj));
+ UNREACHABLE();
+ }
+ return obj.raw();
+}
+
+
+DEFINE_NATIVE_ENTRY(ClassMirror_invoke, 4) {
+ // Argument 0 is the mirror, which is unused by the native. It exists
+ // because this native is an instance method in order to be polymorphic
+ // with its cousins.
+
+ const MirrorReference& klass_ref =
+ MirrorReference::CheckedHandle(arguments->NativeArgAt(1));
+ Class& klass = Class::Handle();
+ klass ^= klass_ref.referent();
+
+ const String& function_name =
+ String::CheckedHandle(arguments->NativeArgAt(2));
+
+ const Array& positional_args =
+ Array::CheckedHandle(arguments->NativeArgAt(3));
+ intptr_t number_of_arguments = positional_args.Length();
+
+ // TODO(11771): This won't find private members.
+ const Function& function = Function::Handle(
+ Resolver::ResolveStatic(klass,
+ function_name,
+ number_of_arguments,
+ Object::empty_array(),
+ Resolver::kIsQualified));
+ if (function.IsNull()) {
+ const String& klass_name = String::Handle(klass.Name());
+ const String& message = String::Handle(
+ String::NewFormatted("%s: did not find static method '%s.%s'.",
+ "ClassMirror_invoke",
+ klass_name.ToCString(),
+ function_name.ToCString()));
+ ThrowMirroredCompilationError(message);
+ UNREACHABLE();
+ }
+ Object& result = Object::Handle(DartEntry::InvokeFunction(function,
+ positional_args));
+ if (result.IsError()) {
+ ThrowInvokeError(Error::Cast(result));
+ UNREACHABLE();
+ }
+ return result.raw();
+}
+
+
+DEFINE_NATIVE_ENTRY(ClassMirror_invokeGetter, 3) {
+ // Argument 0 is the mirror, which is unused by the native. It exists
+ // because this native is an instance method in order to be polymorphic
+ // with its cousins.
+
+ const MirrorReference& klass_ref =
+ MirrorReference::CheckedHandle(arguments->NativeArgAt(1));
+ Class& klass = Class::Handle();
+ klass ^= klass_ref.referent();
+
+ const String& getter_name =
+ String::CheckedHandle(arguments->NativeArgAt(2));
+
+ // Note static fields do not have implicit getters.
+ const Field& field = Field::Handle(klass.LookupStaticField(getter_name));
+ if (field.IsNull() || FieldIsUninitialized(field)) {
+ const String& internal_getter_name = String::Handle(
+ Field::GetterName(getter_name));
+ const Function& getter = Function::Handle(
+ klass.LookupStaticFunctionAllowPrivate(internal_getter_name));
+
+ if (getter.IsNull()) {
+ const String& message = String::Handle(
+ String::NewFormatted("%s: did not find static getter '%s'.",
+ "ClassMirror_invokeGetter",
+ getter_name.ToCString()));
+ ThrowMirroredCompilationError(message);
+ UNREACHABLE();
+ }
+
+ // Invoke the getter and return the result.
+ Object& result = Object::Handle(
+ DartEntry::InvokeFunction(getter, Object::empty_array()));
+ if (result.IsError()) {
+ ThrowInvokeError(Error::Cast(result));
+ UNREACHABLE();
+ }
+ return result.raw();
+ }
+ return field.value();
+}
+
+
+DEFINE_NATIVE_ENTRY(ClassMirror_invokeSetter, 4) {
+ // Argument 0 is the mirror, which is unused by the native. It exists
+ // because this native is an instance method in order to be polymorphic
+ // with its cousins.
+
+ const MirrorReference& klass_ref =
+ MirrorReference::CheckedHandle(arguments->NativeArgAt(1));
+ Class& klass = Class::Handle();
+ klass ^= klass_ref.referent();
+
+ const String& setter_name =
+ String::CheckedHandle(arguments->NativeArgAt(2));
+
+ const Instance& value = Instance::CheckedHandle(arguments->NativeArgAt(3));
+
+ // Check for real fields and user-defined setters.
+ const Field& field = Field::Handle(klass.LookupStaticField(setter_name));
+ if (field.IsNull()) {
+ const String& internal_setter_name = String::Handle(
+ Field::SetterName(setter_name));
+ const Function& setter = Function::Handle(
+ klass.LookupStaticFunctionAllowPrivate(internal_setter_name));
+
+ if (setter.IsNull()) {
+ const String& message = String::Handle(
+ String::NewFormatted("%s: did not find static setter '%s'.",
+ "ClassMirror_invokeSetter",
+ setter_name.ToCString()));
+ ThrowMirroredCompilationError(message);
+ UNREACHABLE();
+ }
+
+ // Invoke the setter and return the result.
+ const int kNumArgs = 1;
+ const Array& args = Array::Handle(Array::New(kNumArgs));
+ args.SetAt(0, value);
+
+ Object& result = Object::Handle(
+ DartEntry::InvokeFunction(setter, args));
+ if (result.IsError()) {
+ ThrowInvokeError(Error::Cast(result));
+ UNREACHABLE();
+ }
+ return result.raw();
+ }
+
+ if (field.is_final()) {
+ const String& message = String::Handle(
+ String::NewFormatted("%s: cannot set final field '%s'.",
+ "ClassMirror_invokeSetter",
+ setter_name.ToCString()));
+ ThrowMirroredCompilationError(message);
+ UNREACHABLE();
+ }
+
+ field.set_value(value);
+ return value.raw();
+}
+
+
+DEFINE_NATIVE_ENTRY(ClassMirror_invokeConstructor, 3) {
+ const MirrorReference& klass_ref =
+ MirrorReference::CheckedHandle(arguments->NativeArgAt(0));
+ Class& klass = Class::Handle();
+ klass ^= klass_ref.referent();
+
+ const String& constructor_name =
+ String::CheckedHandle(arguments->NativeArgAt(1));
+
+ const Array& positional_args =
+ Array::CheckedHandle(arguments->NativeArgAt(2));
+
+ intptr_t number_of_arguments = positional_args.Length();
+
+ // By convention, the static function implementing a named constructor 'C'
+ // for class 'A' is labeled 'A.C', and the static function implementing the
+ // unnamed constructor for class 'A' is labeled 'A.'.
+ // This convention prevents users from explicitly calling constructors.
+ const String& klass_name = String::Handle(klass.Name());
+ String& internal_constructor_name =
+ String::Handle(String::Concat(klass_name, Symbols::Dot()));
+ if (!constructor_name.IsNull()) {
+ internal_constructor_name =
+ String::Concat(internal_constructor_name, constructor_name);
+ }
+
+ const Function& constructor =
+ Function::Handle(ResolveConstructor("ClassMirror_invokeConstructor",
+ klass,
+ klass_name,
+ internal_constructor_name,
+ number_of_arguments));
+
+ const Object& result =
+ Object::Handle(DartEntry::InvokeConstructor(klass,
+ constructor,
+ positional_args));
+ if (result.IsError()) {
+ ThrowInvokeError(Error::Cast(result));
+ UNREACHABLE();
+ }
+ // Factories may return null.
+ ASSERT(result.IsInstance() || result.IsNull());
+ return result.raw();
+}
+
+
+DEFINE_NATIVE_ENTRY(LibraryMirror_invoke, 4) {
+ // Argument 0 is the mirror, which is unused by the native. It exists
+ // because this native is an instance method in order to be polymorphic
+ // with its cousins.
+
+ const MirrorReference& library_ref =
+ MirrorReference::CheckedHandle(arguments->NativeArgAt(1));
+ Library& library = Library::Handle();
+ library ^= library_ref.referent();
+
+ const String& function_name =
+ String::CheckedHandle(arguments->NativeArgAt(2));
+
+ const Array& positional_args =
+ Array::CheckedHandle(arguments->NativeArgAt(3));
+ intptr_t number_of_arguments = positional_args.Length();
+
+
+ const Function& function = Function::Handle(
+ library.LookupFunctionAllowPrivate(function_name));
+
+ if (function.IsNull()) {
+ const String& message = String::Handle(
+ String::NewFormatted("%s: did not find top-level function '%s'.",
+ "LibraryMirror_invoke",
+ function_name.ToCString()));
+ ThrowMirroredCompilationError(message);
+ UNREACHABLE();
+ }
+
+ // LookupFunctionAllowPrivate does not check argument arity, so we
+ // do it here.
+ String& error_message = String::Handle();
+ if (!function.AreValidArgumentCounts(number_of_arguments,
+ /* num_named_args */ 0,
+ &error_message)) {
+ const String& message = String::Handle(
+ String::NewFormatted("%s: wrong argument count for function '%s': %s.",
+ "LibraryMirror_invoke",
+ function_name.ToCString(),
+ error_message.ToCString()));
+ ThrowMirroredCompilationError(message);
+ UNREACHABLE();
+ }
+
+ const Object& result = Object::Handle(
+ DartEntry::InvokeFunction(function, positional_args));
+ if (result.IsError()) {
+ ThrowInvokeError(Error::Cast(result));
+ UNREACHABLE();
+ }
+ return result.raw();
+}
+
+
+DEFINE_NATIVE_ENTRY(LibraryMirror_invokeGetter, 3) {
+ // Argument 0 is the mirror, which is unused by the native. It exists
+ // because this native is an instance method in order to be polymorphic
+ // with its cousins.
+
+ const MirrorReference& library_ref =
+ MirrorReference::CheckedHandle(arguments->NativeArgAt(1));
+ Library& library = Library::Handle();
+ library ^= library_ref.referent();
+
+ const String& getter_name =
+ String::CheckedHandle(arguments->NativeArgAt(2));
+
+ // To access a top-level we may need to use the Field or the
+ // getter Function. The getter function may either be in the
+ // library or in the field's owner class, depending.
+ const Field& field =
+ Field::Handle(library.LookupFieldAllowPrivate(getter_name));
+ Function& getter = Function::Handle();
+ if (field.IsNull()) {
+ // No field found. Check for a getter in the lib.
+ const String& internal_getter_name =
+ String::Handle(Field::GetterName(getter_name));
+ getter = library.LookupFunctionAllowPrivate(internal_getter_name);
+ } else if (FieldIsUninitialized(field)) {
+ // A field was found. Check for a getter in the field's owner classs.
+ const Class& klass = Class::Handle(field.owner());
+ const String& internal_getter_name =
+ String::Handle(Field::GetterName(getter_name));
+ getter = klass.LookupStaticFunctionAllowPrivate(internal_getter_name);
+ }
+
+ if (!getter.IsNull()) {
+ // Invoke the getter and return the result.
+ const Object& result = Object::Handle(
+ DartEntry::InvokeFunction(getter, Object::empty_array()));
+ if (result.IsError()) {
+ ThrowInvokeError(Error::Cast(result));
+ UNREACHABLE();
+ }
+ return result.raw();
+ } else if (!field.IsNull()) {
+ return field.value();
+ } else {
+ const String& message = String::Handle(
+ String::NewFormatted("%s: did not find top-level variable '%s'.",
+ "LibraryMirror_invokeGetter",
+ getter_name.ToCString()));
+ ThrowMirroredCompilationError(message);
+ UNREACHABLE();
+ return Instance::null();
+ }
+}
+
+
+DEFINE_NATIVE_ENTRY(LibraryMirror_invokeSetter, 4) {
+ // Argument 0 is the mirror, which is unused by the native. It exists
+ // because this native is an instance method in order to be polymorphic
+ // with its cousins.
+
+ const MirrorReference& library_ref =
+ MirrorReference::CheckedHandle(arguments->NativeArgAt(1));
+ Library& library = Library::Handle();
+ library ^= library_ref.referent();
+
+ const String& setter_name =
+ String::CheckedHandle(arguments->NativeArgAt(2));
+
+ const Instance& value = Instance::CheckedHandle(arguments->NativeArgAt(3));
+
+ // To access a top-level we may need to use the Field or the
+ // setter Function. The setter function may either be in the
+ // library or in the field's owner class, depending.
+ const Field& field =
+ Field::Handle(library.LookupFieldAllowPrivate(setter_name));
+
+ if (field.IsNull()) {
+ const String& internal_setter_name =
+ String::Handle(Field::SetterName(setter_name));
+ const Function& setter = Function::Handle(
+ library.LookupFunctionAllowPrivate(internal_setter_name));
+
+ if (setter.IsNull()) {
+ const String& message = String::Handle(
+ String::NewFormatted("%s: did not find top-level variable '%s'.",
+ "LibraryMirror_invokeSetter",
+ setter_name.ToCString()));
+ ThrowMirroredCompilationError(message);
+ UNREACHABLE();
+ }
+
+ // Invoke the setter and return the result.
+ const int kNumArgs = 1;
+ const Array& args = Array::Handle(Array::New(kNumArgs));
+ args.SetAt(0, value);
+ const Object& result = Object::Handle(
+ DartEntry::InvokeFunction(setter, args));
+ if (result.IsError()) {
+ ThrowInvokeError(Error::Cast(result));
+ UNREACHABLE();
+ }
+ return result.raw();
+ }
+
+ if (field.is_final()) {
+ const String& message = String::Handle(
+ String::NewFormatted("%s: cannot set final top-level variable '%s'.",
+ "LibraryMirror_invokeSetter",
+ setter_name.ToCString()));
+ ThrowMirroredCompilationError(message);
+ UNREACHABLE();
+ }
+
+ field.set_value(value);
+ return value.raw();
+}
+
+
DEFINE_NATIVE_ENTRY(MethodMirror_name, 1) {
const MirrorReference& func_ref =
MirrorReference::CheckedHandle(arguments->NativeArgAt(0));
diff --git a/runtime/lib/mirrors_impl.dart b/runtime/lib/mirrors_impl.dart
index 16e9286..838af66 100644
--- a/runtime/lib/mirrors_impl.dart
+++ b/runtime/lib/mirrors_impl.dart
@@ -73,6 +73,22 @@
List<InstanceMirror> _metadata(mirror)
native 'Mirrors_metadata';
+// This will verify the argument types, unwrap them, and ensure we have a fixed
+// array.
+List _unwarpAsyncPositionals(wrappedArgs){
+ List unwrappedArgs = new List(wrappedArgs.length);
+ for(int i = 0; i < wrappedArgs.length; i++){
+ var wrappedArg = wrappedArgs[i];
+ if(_isSimpleValue(wrappedArg)) {
+ unwrappedArgs[i] = wrappedArg;
+ } else if(wrappedArg is InstanceMirror) {
+ unwrappedArgs[i] = wrappedArg._reflectee;
+ } else {
+ throw "positional argument $i ($arg) was not a simple value or InstanceMirror";
+ }
+ }
+ return unwrappedArgs;
+}
class _LocalMirrorSystemImpl extends MirrorSystem {
// Change parameter back to "this.libraries" when native code is changed.
@@ -165,7 +181,9 @@
abstract class _LocalObjectMirrorImpl extends _LocalVMObjectMirrorImpl
implements ObjectMirror {
- _LocalObjectMirrorImpl(ref) : super(ref) {}
+ _LocalObjectMirrorImpl(this._reflectee, ref) : super(ref) {}
+
+ final _reflectee; // May be a MirrorReference or an ordinary object.
InstanceMirror invoke(Symbol memberName,
List positionalArguments,
@@ -174,15 +192,20 @@
throw new UnimplementedError(
'named argument support is not implemented');
}
- return _invoke(this, _n(memberName), positionalArguments, false);
+ return reflect(this._invoke(_reflectee,
+ _n(memberName),
+ positionalArguments.toList(growable:false)));
}
- InstanceMirror getField(Symbol fieldName) {
- return _getField(this, _n(fieldName));
+ InstanceMirror getField(Symbol memberName) {
+ return reflect(this._invokeGetter(_reflectee,
+ _n(memberName)));
}
- InstanceMirror setField(Symbol fieldName, Object arg) {
- return _setField(this, _n(fieldName), arg, false);
+ InstanceMirror setField(Symbol memberName, Object value) {
+ return reflect(this._invokeSetter(_reflectee,
+ _n(memberName),
+ value));
}
Future<InstanceMirror> invokeAsync(Symbol memberName,
@@ -192,35 +215,44 @@
throw new UnimplementedError(
'named argument support is not implemented');
}
- // Walk the arguments and make sure they are legal.
- for (int i = 0; i < positionalArguments.length; i++) {
- var arg = positionalArguments[i];
- _validateArgument(i, arg);
- }
+
try {
- return new Future<InstanceMirror>.value(
- _invoke(this, _n(memberName), positionalArguments, true));
- } catch (exception, s) {
- return new Future<InstanceMirror>.error(exception, s);
+ var result = this._invoke(_reflectee,
+ _n(memberName),
+ _unwarpAsyncPositionals(positionalArguments));
+ return new Future.value(reflect(result));
+ } on MirroredError catch(e) {
+ return new Future.error(e);
}
}
- Future<InstanceMirror> getFieldAsync(Symbol fieldName) {
- try {
- return new Future<InstanceMirror>.value(_getField(this, _n(fieldName)));
- } catch (exception, s) {
- return new Future<InstanceMirror>.error(exception, s);
+ Future<InstanceMirror> getFieldAsync(Symbol memberName) {
+ try {
+ var result = this._invokeGetter(_reflectee,
+ _n(memberName));
+ return new Future.value(reflect(result));
+ } on MirroredError catch(e) {
+ return new Future.error(e);
}
}
- Future<InstanceMirror> setFieldAsync(Symbol fieldName, Object arg) {
- _validateArgument(0, arg);
-
+ Future<InstanceMirror> setFieldAsync(Symbol memberName, Object value) {
try {
- return new Future<InstanceMirror>.value(
- _setField(this, _n(fieldName), arg, true));
- } catch (exception, s) {
- return new Future<InstanceMirror>.error(exception, s);
+ var unwrappedValue;
+ if(_isSimpleValue(value)) {
+ unwrappedValue = value;
+ } else if(wrappedArg is InstanceMirror) {
+ unwrappedValue = value._reflectee;
+ } else {
+ throw "setter argument ($value) must be a simple value or InstanceMirror";
+ }
+
+ var result = this._invokeSetter(_reflectee,
+ _n(memberName),
+ unwrappedValue);
+ return new Future.value(reflect(result));
+ } on MirroredError catch(e) {
+ return new Future.error(e);
}
}
@@ -236,15 +268,6 @@
'positional argument $i ($arg) was not a simple value');
}
}
-
- static _invoke(ref, memberName, positionalArguments, async)
- native 'LocalObjectMirrorImpl_invoke';
-
- static _getField(ref, fieldName) // same for sync and async versions
- native 'LocalObjectMirrorImpl_getField';
-
- static _setField(ref, fieldName, value, async)
- native 'LocalObjectMirrorImpl_setField';
}
class _LocalInstanceMirrorImpl extends _LocalObjectMirrorImpl
@@ -254,7 +277,7 @@
_LocalInstanceMirrorImpl(ref,
this._type,
- this._reflectee) : super(ref) {}
+ reflectee) : super(reflectee, ref) {}
var _type;
ClassMirror get type {
@@ -267,7 +290,6 @@
// LocalInstanceMirrors always reflect local instances
bool hasReflectee = true;
- var _reflectee;
get reflectee => _reflectee;
delegate(Invocation invocation) {
@@ -276,16 +298,25 @@
// system to access a private field in a different library. For
// some reason, that works. On the other hand, calling a
// private method does not work.
+
_LocalInstanceMirrorImpl mirror =
_Mirrors.makeLocalInstanceMirror(invocation);
_invokeOnClosure =
- _LocalObjectMirrorImpl._getField(mirror.type, '_invokeOnClosure')
- .reflectee;
+ reflectClass(invocation.runtimeType).getField(const Symbol('_invokeOnClosure')).reflectee;
}
return _invokeOnClosure(reflectee, invocation);
}
String toString() => 'InstanceMirror on ${Error.safeToString(_reflectee)}';
+
+ _invoke(reflectee, functionName, positionalArguments)
+ native 'InstanceMirror_invoke';
+
+ _invokeGetter(reflectee, getterName)
+ native 'InstanceMirror_invokeGetter';
+
+ _invokeSetter(reflectee, setterName, value)
+ native 'InstanceMirror_invokeSetter';
}
class _LocalClosureMirrorImpl extends _LocalInstanceMirrorImpl
@@ -308,35 +339,37 @@
throw new UnimplementedError(
'named argument support is not implemented');
}
- return _apply(this, positionalArguments, false);
+ // It is tempting to implement this in terms of Function.apply, but then
+ // lazy compilation errors would be fatal.
+ return reflect(_apply(_reflectee,
+ positionalArguments.toList(growable:false)));
}
- Future<InstanceMirror> applyAsync(List<Object> positionalArguments,
- [Map<Symbol, Object> namedArguments]) {
+ Future<InstanceMirror> applyAsync(List positionalArguments,
+ [Map<Symbol, dynamic> namedArguments]) {
if (namedArguments != null) {
throw new UnimplementedError(
'named argument support is not implemented');
}
- // Walk the arguments and make sure they are legal.
- for (int i = 0; i < positionalArguments.length; i++) {
- var arg = positionalArguments[i];
- _LocalObjectMirrorImpl._validateArgument(i, arg);
- }
+
try {
- return new Future<InstanceMirror>.value(
- _apply(this, positionalArguments, true));
- } catch (exception) {
- return new Future<InstanceMirror>.error(exception);
+ var result = _apply(_reflectee,
+ _unwarpAsyncPositionals(positionalArguments));
+ return new Future.value(reflect(result));
+ } on MirroredError catch(e) {
+ return new Future.error(e);
}
}
+
+
Future<InstanceMirror> findInContext(Symbol name) {
throw new UnimplementedError(
'ClosureMirror.findInContext() is not implemented');
}
- static _apply(ref, positionalArguments, async)
- native 'LocalClosureMirrorImpl_apply';
+ static _apply(reflectee, positionalArguments)
+ native 'ClosureMirror_apply';
String toString() => "ClosureMirror on '${Error.safeToString(_reflectee)}'";
}
@@ -370,7 +403,7 @@
class _LocalClassMirrorImpl extends _LocalObjectMirrorImpl
implements ClassMirror {
- _LocalClassMirrorImpl(this._reflectee,
+ _LocalClassMirrorImpl(reflectee,
ref,
String simpleName,
this.isClass,
@@ -385,16 +418,14 @@
this.members = _convertStringToSymbolMap(members),
this.constructors = _convertStringToSymbolMap(constructors),
this.typeVariables = _convertStringToSymbolMap(typeVariables),
- super(ref);
-
- final _MirrorReference _reflectee;
+ super(reflectee, ref);
Symbol _simpleName;
Symbol get simpleName {
// dynamic, void and the function types have their names set eagerly in the
// constructor.
if(_simpleName == null) {
- _simpleName = _s(_ClassMirror_name(_reflectee));
+ _simpleName = _s(_name(_reflectee));
}
return _simpleName;
}
@@ -528,10 +559,9 @@
throw new UnimplementedError(
'named argument support is not implemented');
}
- return _invokeConstructor(this,
- _n(constructorName),
- positionalArguments,
- false);
+ return reflect(_invokeConstructor(_reflectee,
+ _n(constructorName),
+ positionalArguments.toList(growable:false)));
}
Future<InstanceMirror> newInstanceAsync(Symbol constructorName,
@@ -541,19 +571,14 @@
throw new UnimplementedError(
'named argument support is not implemented');
}
- // Walk the arguments and make sure they are legal.
- for (int i = 0; i < positionalArguments.length; i++) {
- var arg = positionalArguments[i];
- _LocalObjectMirrorImpl._validateArgument(i, arg);
- }
+
try {
- return new Future<InstanceMirror>.value(
- _invokeConstructor(this,
- _n(constructorName),
- positionalArguments,
- true));
- } catch (exception) {
- return new Future<InstanceMirror>.error(exception);
+ var result = _invokeConstructor(_reflectee,
+ _n(constructorName),
+ _unwarpAsyncPositionals(positionalArguments));
+ return new Future.value(reflect(result));
+ } on MirroredError catch(e) {
+ return new Future.error(e);
}
}
@@ -561,11 +586,21 @@
// reflect() and then make them into a Dart list
List<InstanceMirror> get metadata => _metadata(this).map(reflect).toList();
- static _invokeConstructor(ref, constructorName, positionalArguments, async)
- native 'LocalClassMirrorImpl_invokeConstructor';
- static String _ClassMirror_name(reflectee)
+ static _name(reflectee)
native "ClassMirror_name";
+
+ _invoke(reflectee, memberName, positionalArguments)
+ native 'ClassMirror_invoke';
+
+ _invokeGetter(reflectee, getterName)
+ native 'ClassMirror_invokeGetter';
+
+ _invokeSetter(reflectee, setterName, value)
+ native 'ClassMirror_invokeSetter';
+
+ static _invokeConstructor(reflectee, constructorName, positionalArguments)
+ native 'ClassMirror_invokeConstructor';
}
class _LazyFunctionTypeMirror {
@@ -733,14 +768,15 @@
class _LocalLibraryMirrorImpl extends _LocalObjectMirrorImpl
implements LibraryMirror {
- _LocalLibraryMirrorImpl(ref,
+ _LocalLibraryMirrorImpl(reflectee,
+ ref,
String simpleName,
String url,
Map<String, Mirror> members)
: this.simpleName = _s(simpleName),
this.members = _convertStringToSymbolMap(members),
this.uri = Uri.parse(url),
- super(ref);
+ super(reflectee, ref);
final Symbol simpleName;
@@ -815,6 +851,15 @@
List<InstanceMirror> get metadata => _metadata(this).map(reflect).toList();
String toString() => "LibraryMirror on '${_n(simpleName)}'";
+
+ _invoke(reflectee, memberName, positionalArguments)
+ native 'LibraryMirror_invoke';
+
+ _invokeGetter(reflectee, getterName)
+ native 'LibraryMirror_invokeGetter';
+
+ _invokeSetter(reflectee, setterName, value)
+ native 'LibraryMirror_invokeSetter';
}
class _LocalMethodMirrorImpl extends _LocalMirrorImpl
diff --git a/runtime/vm/assembler_arm.cc b/runtime/vm/assembler_arm.cc
index aa3a33d..8faef96 100644
--- a/runtime/vm/assembler_arm.cc
+++ b/runtime/vm/assembler_arm.cc
@@ -1219,8 +1219,35 @@
}
-void Assembler::EmitSIMDqqq(int32_t opcode, int sz,
+static inline int ShiftOfOperandSize(OperandSize size) {
+ switch (size) {
+ case kByte:
+ case kUnsignedByte:
+ return 0;
+ case kHalfword:
+ case kUnsignedHalfword:
+ return 1;
+ case kWord:
+ case kUnsignedWord:
+ return 2;
+ case kWordPair:
+ return 3;
+ case kSWord:
+ case kDWord:
+ return 0;
+ default:
+ UNREACHABLE();
+ break;
+ }
+
+ UNREACHABLE();
+ return -1;
+}
+
+
+void Assembler::EmitSIMDqqq(int32_t opcode, OperandSize size,
QRegister qd, QRegister qn, QRegister qm) {
+ int sz = ShiftOfOperandSize(size);
int32_t encoding =
(static_cast<int32_t>(kSpecialCondition) << kConditionShift) |
B25 | B6 |
@@ -1235,14 +1262,59 @@
}
-void Assembler::vaddqi(int sz, QRegister qd, QRegister qn, QRegister qm) {
- ASSERT((sz >= 0) && (sz <= 3));
+void Assembler::EmitSIMDddd(int32_t opcode, OperandSize size,
+ DRegister dd, DRegister dn, DRegister dm) {
+ int sz = ShiftOfOperandSize(size);
+ int32_t encoding =
+ (static_cast<int32_t>(kSpecialCondition) << kConditionShift) |
+ B25 |
+ opcode | ((sz & 0x3) * B20) |
+ ((static_cast<int32_t>(dd) >> 4)*B22) |
+ ((static_cast<int32_t>(dn) & 0xf)*B16) |
+ ((static_cast<int32_t>(dd) & 0xf)*B12) |
+ ((static_cast<int32_t>(dn) >> 4)*B7) |
+ ((static_cast<int32_t>(dm) >> 4)*B5) |
+ (static_cast<int32_t>(dm) & 0xf);
+ Emit(encoding);
+}
+
+
+void Assembler::vaddqi(OperandSize sz,
+ QRegister qd, QRegister qn, QRegister qm) {
EmitSIMDqqq(B11, sz, qd, qn, qm);
}
void Assembler::vaddqs(QRegister qd, QRegister qn, QRegister qm) {
- EmitSIMDqqq(B11 | B10 | B8, 0, qd, qn, qm);
+ EmitSIMDqqq(B11 | B10 | B8, kSWord, qd, qn, qm);
+}
+
+
+void Assembler::vsubqi(OperandSize sz,
+ QRegister qd, QRegister qn, QRegister qm) {
+ EmitSIMDqqq(B24 | B11, sz, qd, qn, qm);
+}
+
+
+void Assembler::vsubqs(QRegister qd, QRegister qn, QRegister qm) {
+ EmitSIMDqqq(B21 | B11 | B10 | B8, kSWord, qd, qn, qm);
+}
+
+
+void Assembler::vmulqi(OperandSize sz,
+ QRegister qd, QRegister qn, QRegister qm) {
+ EmitSIMDqqq(B11 | B8 | B4, sz, qd, qn, qm);
+}
+
+
+void Assembler::vmulqs(QRegister qd, QRegister qn, QRegister qm) {
+ EmitSIMDqqq(B24 | B11 | B10 | B8 | B4, kSWord, qd, qn, qm);
+}
+
+
+void Assembler::vtbl(DRegister dd, DRegister dn, int len, DRegister dm) {
+ ASSERT((len >= 1) && (len <= 4));
+ EmitSIMDddd(B24 | B23 | B11 | ((len - 1) * B8), kWordPair, dd, dn, dm);
}
@@ -1315,7 +1387,7 @@
Condition cond) {
ASSERT(rd != PP);
int32_t offset_mask = 0;
- if (Address::CanHoldLoadOffset(kLoadWord, offset, &offset_mask)) {
+ if (Address::CanHoldLoadOffset(kWord, offset, &offset_mask)) {
ldr(rd, Address(PP, offset), cond);
} else {
int32_t offset_hi = offset & ~offset_mask; // signed
@@ -1341,7 +1413,7 @@
const intptr_t object_pool_pc_dist =
Instructions::HeaderSize() - Instructions::object_pool_offset() +
CodeSize() + Instr::kPCReadOffset;
- LoadFromOffset(kLoadWord, PP, PC, -object_pool_pc_dist);
+ LoadFromOffset(kWord, PP, PC, -object_pool_pc_dist);
}
@@ -1477,7 +1549,7 @@
ldr(result, FieldAddress(CTX, Context::isolate_offset()));
const intptr_t table_offset_in_isolate =
Isolate::class_table_offset() + ClassTable::table_offset();
- LoadFromOffset(kLoadWord, result, result, table_offset_in_isolate);
+ LoadFromOffset(kWord, result, result, table_offset_in_isolate);
ldr(result, Address(result, class_id, LSL, 2));
}
@@ -1489,7 +1561,7 @@
ldr(result, FieldAddress(CTX, Context::isolate_offset()));
const intptr_t table_offset_in_isolate =
Isolate::class_table_offset() + ClassTable::table_offset();
- LoadFromOffset(kLoadWord, result, result, table_offset_in_isolate);
+ LoadFromOffset(kWord, result, result, table_offset_in_isolate);
ldr(result, Address(result, scratch, LSL, 2));
}
@@ -1516,24 +1588,24 @@
}
-bool Address::CanHoldLoadOffset(LoadOperandType type,
+bool Address::CanHoldLoadOffset(OperandSize type,
int32_t offset,
int32_t* offset_mask) {
switch (type) {
- case kLoadSignedByte:
- case kLoadSignedHalfword:
- case kLoadUnsignedHalfword:
- case kLoadWordPair: {
+ case kByte:
+ case kHalfword:
+ case kUnsignedHalfword:
+ case kWordPair: {
*offset_mask = 0xff;
return Utils::IsAbsoluteUint(8, offset); // Addressing mode 3.
}
- case kLoadUnsignedByte:
- case kLoadWord: {
+ case kUnsignedByte:
+ case kWord: {
*offset_mask = 0xfff;
return Utils::IsAbsoluteUint(12, offset); // Addressing mode 2.
}
- case kLoadSWord:
- case kLoadDWord: {
+ case kSWord:
+ case kDWord: {
*offset_mask = 0x3fc; // Multiple of 4.
// VFP addressing mode.
return (Utils::IsAbsoluteUint(10, offset) && Utils::IsAligned(offset, 4));
@@ -1546,22 +1618,22 @@
}
-bool Address::CanHoldStoreOffset(StoreOperandType type,
+bool Address::CanHoldStoreOffset(OperandSize type,
int32_t offset,
int32_t* offset_mask) {
switch (type) {
- case kStoreHalfword:
- case kStoreWordPair: {
+ case kHalfword:
+ case kWordPair: {
*offset_mask = 0xff;
return Utils::IsAbsoluteUint(8, offset); // Addressing mode 3.
}
- case kStoreByte:
- case kStoreWord: {
+ case kByte:
+ case kWord: {
*offset_mask = 0xfff;
return Utils::IsAbsoluteUint(12, offset); // Addressing mode 2.
}
- case kStoreSWord:
- case kStoreDWord: {
+ case kSWord:
+ case kDWord: {
*offset_mask = 0x3fc; // Multiple of 4.
// VFP addressing mode.
return (Utils::IsAbsoluteUint(10, offset) && Utils::IsAligned(offset, 4));
@@ -1702,7 +1774,7 @@
void Assembler::BranchLinkOffset(Register base, int32_t offset) {
ASSERT(base != PC);
ASSERT(base != IP);
- LoadFromOffset(kLoadWord, IP, base, offset);
+ LoadFromOffset(kWord, IP, base, offset);
blx(IP); // Use blx instruction so that the return branch prediction works.
}
@@ -1749,7 +1821,7 @@
}
-void Assembler::LoadFromOffset(LoadOperandType type,
+void Assembler::LoadFromOffset(OperandSize type,
Register reg,
Register base,
int32_t offset,
@@ -1762,22 +1834,22 @@
offset = offset & offset_mask;
}
switch (type) {
- case kLoadSignedByte:
+ case kByte:
ldrsb(reg, Address(base, offset), cond);
break;
- case kLoadUnsignedByte:
+ case kUnsignedByte:
ldrb(reg, Address(base, offset), cond);
break;
- case kLoadSignedHalfword:
+ case kHalfword:
ldrsh(reg, Address(base, offset), cond);
break;
- case kLoadUnsignedHalfword:
+ case kUnsignedHalfword:
ldrh(reg, Address(base, offset), cond);
break;
- case kLoadWord:
+ case kWord:
ldr(reg, Address(base, offset), cond);
break;
- case kLoadWordPair:
+ case kWordPair:
ldrd(reg, Address(base, offset), cond);
break;
default:
@@ -1786,7 +1858,7 @@
}
-void Assembler::StoreToOffset(StoreOperandType type,
+void Assembler::StoreToOffset(OperandSize type,
Register reg,
Register base,
int32_t offset,
@@ -1800,16 +1872,16 @@
offset = offset & offset_mask;
}
switch (type) {
- case kStoreByte:
+ case kByte:
strb(reg, Address(base, offset), cond);
break;
- case kStoreHalfword:
+ case kHalfword:
strh(reg, Address(base, offset), cond);
break;
- case kStoreWord:
+ case kWord:
str(reg, Address(base, offset), cond);
break;
- case kStoreWordPair:
+ case kWordPair:
strd(reg, Address(base, offset), cond);
break;
default:
@@ -1823,7 +1895,7 @@
int32_t offset,
Condition cond) {
int32_t offset_mask = 0;
- if (!Address::CanHoldLoadOffset(kLoadSWord, offset, &offset_mask)) {
+ if (!Address::CanHoldLoadOffset(kSWord, offset, &offset_mask)) {
ASSERT(base != IP);
AddImmediate(IP, base, offset & ~offset_mask, cond);
base = IP;
@@ -1838,7 +1910,7 @@
int32_t offset,
Condition cond) {
int32_t offset_mask = 0;
- if (!Address::CanHoldStoreOffset(kStoreSWord, offset, &offset_mask)) {
+ if (!Address::CanHoldStoreOffset(kSWord, offset, &offset_mask)) {
ASSERT(base != IP);
AddImmediate(IP, base, offset & ~offset_mask, cond);
base = IP;
@@ -1853,7 +1925,7 @@
int32_t offset,
Condition cond) {
int32_t offset_mask = 0;
- if (!Address::CanHoldLoadOffset(kLoadDWord, offset, &offset_mask)) {
+ if (!Address::CanHoldLoadOffset(kDWord, offset, &offset_mask)) {
ASSERT(base != IP);
AddImmediate(IP, base, offset & ~offset_mask, cond);
base = IP;
@@ -1868,7 +1940,7 @@
int32_t offset,
Condition cond) {
int32_t offset_mask = 0;
- if (!Address::CanHoldStoreOffset(kStoreDWord, offset, &offset_mask)) {
+ if (!Address::CanHoldStoreOffset(kDWord, offset, &offset_mask)) {
ASSERT(base != IP);
AddImmediate(IP, base, offset & ~offset_mask, cond);
base = IP;
diff --git a/runtime/vm/assembler_arm.h b/runtime/vm/assembler_arm.h
index 55168ff..e07eab0 100644
--- a/runtime/vm/assembler_arm.h
+++ b/runtime/vm/assembler_arm.h
@@ -176,25 +176,16 @@
};
-enum LoadOperandType {
- kLoadSignedByte,
- kLoadUnsignedByte,
- kLoadSignedHalfword,
- kLoadUnsignedHalfword,
- kLoadWord,
- kLoadWordPair,
- kLoadSWord,
- kLoadDWord
-};
-
-
-enum StoreOperandType {
- kStoreByte,
- kStoreHalfword,
- kStoreWord,
- kStoreWordPair,
- kStoreSWord,
- kStoreDWord
+enum OperandSize {
+ kByte,
+ kUnsignedByte,
+ kHalfword,
+ kUnsignedHalfword,
+ kWord,
+ kUnsignedWord,
+ kWordPair,
+ kSWord,
+ kDWord,
};
@@ -268,10 +259,10 @@
return (encoding_ == other.encoding_) && (kind_ == other.kind_);
}
- static bool CanHoldLoadOffset(LoadOperandType type,
+ static bool CanHoldLoadOffset(OperandSize type,
int32_t offset,
int32_t* offset_mask);
- static bool CanHoldStoreOffset(StoreOperandType type,
+ static bool CanHoldStoreOffset(OperandSize type,
int32_t offset,
int32_t* offset_mask);
@@ -479,12 +470,16 @@
void vadds(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL);
void vaddd(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL);
- void vaddqi(int sz, QRegister qd, QRegister qn, QRegister qm);
+ void vaddqi(OperandSize sz, QRegister qd, QRegister qn, QRegister qm);
void vaddqs(QRegister qd, QRegister qn, QRegister qm);
void vsubs(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL);
void vsubd(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL);
+ void vsubqi(OperandSize sz, QRegister qd, QRegister qn, QRegister qm);
+ void vsubqs(QRegister qd, QRegister qn, QRegister qm);
void vmuls(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL);
void vmuld(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL);
+ void vmulqi(OperandSize sz, QRegister qd, QRegister qn, QRegister qm);
+ void vmulqs(QRegister qd, QRegister qn, QRegister qm);
void vmlas(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL);
void vmlad(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL);
void vmlss(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL);
@@ -516,6 +511,10 @@
void vcmpdz(DRegister dd, Condition cond = AL);
void vmstat(Condition cond = AL); // VMRS APSR_nzcv, FPSCR
+ // Each byte of dm is an index into the table of bytes formed by concatenating
+ // a list of 'length' registers starting with dn. The result is placed in dd.
+ void vtbl(DRegister dd, DRegister dn, int length, DRegister dm);
+
// Branch instructions.
void b(Label* label, Condition cond = AL);
void bl(Label* label, Condition cond = AL);
@@ -595,12 +594,12 @@
void CompareClassId(Register object, intptr_t class_id, Register scratch);
void LoadWordFromPoolOffset(Register rd, int32_t offset, Condition cond = AL);
- void LoadFromOffset(LoadOperandType type,
+ void LoadFromOffset(OperandSize type,
Register reg,
Register base,
int32_t offset,
Condition cond = AL);
- void StoreToOffset(StoreOperandType type,
+ void StoreToOffset(OperandSize type,
Register reg,
Register base,
int32_t offset,
@@ -809,9 +808,12 @@
DRegister dd,
SRegister sm);
- void EmitSIMDqqq(int32_t opcode, int sz,
+ void EmitSIMDqqq(int32_t opcode, OperandSize sz,
QRegister qd, QRegister qn, QRegister qm);
+ void EmitSIMDddd(int32_t opcode, OperandSize sz,
+ DRegister dd, DRegister dn, DRegister dm);
+
void EmitBranch(Condition cond, Label* label, bool link);
static int32_t EncodeBranchOffset(int32_t offset, int32_t inst);
static int DecodeBranchOffset(int32_t inst);
diff --git a/runtime/vm/assembler_arm_test.cc b/runtime/vm/assembler_arm_test.cc
index ff50865..d1d5b03 100644
--- a/runtime/vm/assembler_arm_test.cc
+++ b/runtime/vm/assembler_arm_test.cc
@@ -1600,15 +1600,22 @@
if (CPUFeatures::neon_supported()) {
__ mov(R0, ShifterOperand(1));
__ vmovsr(S0, R0);
+ __ mov(R0, ShifterOperand(2));
__ vmovsr(S1, R0);
+ __ mov(R0, ShifterOperand(3));
__ vmovsr(S2, R0);
+ __ mov(R0, ShifterOperand(4));
__ vmovsr(S3, R0);
+ __ mov(R0, ShifterOperand(5));
__ vmovsr(S4, R0);
+ __ mov(R0, ShifterOperand(6));
__ vmovsr(S5, R0);
+ __ mov(R0, ShifterOperand(7));
__ vmovsr(S6, R0);
+ __ mov(R0, ShifterOperand(8));
__ vmovsr(S7, R0);
- __ vaddqi(0, Q2, Q0, Q1);
+ __ vaddqi(kByte, Q2, Q0, Q1);
__ vmovrs(R0, S8);
__ vmovrs(R1, S9);
@@ -1620,7 +1627,7 @@
__ add(R0, R0, ShifterOperand(R3));
__ bx(LR);
} else {
- __ LoadImmediate(R0, 8);
+ __ LoadImmediate(R0, 36);
__ bx(LR);
}
}
@@ -1629,7 +1636,7 @@
ASSEMBLER_TEST_RUN(Vaddqi8, test) {
EXPECT(test != NULL);
typedef int (*Tst)();
- EXPECT_EQ(8, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ EXPECT_EQ(36, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
}
@@ -1637,15 +1644,22 @@
if (CPUFeatures::neon_supported()) {
__ mov(R0, ShifterOperand(1));
__ vmovsr(S0, R0);
+ __ mov(R0, ShifterOperand(2));
__ vmovsr(S1, R0);
+ __ mov(R0, ShifterOperand(3));
__ vmovsr(S2, R0);
+ __ mov(R0, ShifterOperand(4));
__ vmovsr(S3, R0);
+ __ mov(R0, ShifterOperand(5));
__ vmovsr(S4, R0);
+ __ mov(R0, ShifterOperand(6));
__ vmovsr(S5, R0);
+ __ mov(R0, ShifterOperand(7));
__ vmovsr(S6, R0);
+ __ mov(R0, ShifterOperand(8));
__ vmovsr(S7, R0);
- __ vaddqi(1, Q2, Q0, Q1);
+ __ vaddqi(kHalfword, Q2, Q0, Q1);
__ vmovrs(R0, S8);
__ vmovrs(R1, S9);
@@ -1657,7 +1671,7 @@
__ add(R0, R0, ShifterOperand(R3));
__ bx(LR);
} else {
- __ LoadImmediate(R0, 8);
+ __ LoadImmediate(R0, 36);
__ bx(LR);
}
}
@@ -1666,7 +1680,7 @@
ASSEMBLER_TEST_RUN(Vaddqi16, test) {
EXPECT(test != NULL);
typedef int (*Tst)();
- EXPECT_EQ(8, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ EXPECT_EQ(36, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
}
@@ -1674,15 +1688,22 @@
if (CPUFeatures::neon_supported()) {
__ mov(R0, ShifterOperand(1));
__ vmovsr(S0, R0);
+ __ mov(R0, ShifterOperand(2));
__ vmovsr(S1, R0);
+ __ mov(R0, ShifterOperand(3));
__ vmovsr(S2, R0);
+ __ mov(R0, ShifterOperand(4));
__ vmovsr(S3, R0);
+ __ mov(R0, ShifterOperand(5));
__ vmovsr(S4, R0);
+ __ mov(R0, ShifterOperand(6));
__ vmovsr(S5, R0);
+ __ mov(R0, ShifterOperand(7));
__ vmovsr(S6, R0);
+ __ mov(R0, ShifterOperand(8));
__ vmovsr(S7, R0);
- __ vaddqi(2, Q2, Q0, Q1);
+ __ vaddqi(kWord, Q2, Q0, Q1);
__ vmovrs(R0, S8);
__ vmovrs(R1, S9);
@@ -1694,7 +1715,7 @@
__ add(R0, R0, ShifterOperand(R3));
__ bx(LR);
} else {
- __ LoadImmediate(R0, 8);
+ __ LoadImmediate(R0, 36);
__ bx(LR);
}
}
@@ -1703,7 +1724,7 @@
ASSEMBLER_TEST_RUN(Vaddqi32, test) {
EXPECT(test != NULL);
typedef int (*Tst)();
- EXPECT_EQ(8, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ EXPECT_EQ(36, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
}
@@ -1711,11 +1732,14 @@
if (CPUFeatures::neon_supported()) {
__ mov(R0, ShifterOperand(1));
__ vmovsr(S0, R0);
+ __ mov(R0, ShifterOperand(2));
__ vmovsr(S2, R0);
+ __ mov(R0, ShifterOperand(3));
__ vmovsr(S4, R0);
+ __ mov(R0, ShifterOperand(4));
__ vmovsr(S6, R0);
- __ vaddqi(3, Q2, Q0, Q1);
+ __ vaddqi(kWordPair, Q2, Q0, Q1);
__ vmovrs(R0, S8);
__ vmovrs(R2, S10);
@@ -1723,7 +1747,7 @@
__ add(R0, R0, ShifterOperand(R2));
__ bx(LR);
} else {
- __ LoadImmediate(R0, 4);
+ __ LoadImmediate(R0, 10);
__ bx(LR);
}
}
@@ -1732,20 +1756,316 @@
ASSEMBLER_TEST_RUN(Vaddqi64, test) {
EXPECT(test != NULL);
typedef int (*Tst)();
- EXPECT_EQ(4, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ EXPECT_EQ(10, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(Vsubqi8, assembler) {
+ if (CPUFeatures::neon_supported()) {
+ __ mov(R0, ShifterOperand(1));
+ __ vmovsr(S0, R0);
+ __ mov(R0, ShifterOperand(2));
+ __ vmovsr(S1, R0);
+ __ mov(R0, ShifterOperand(3));
+ __ vmovsr(S2, R0);
+ __ mov(R0, ShifterOperand(4));
+ __ vmovsr(S3, R0);
+ __ mov(R0, ShifterOperand(2));
+ __ vmovsr(S4, R0);
+ __ mov(R0, ShifterOperand(4));
+ __ vmovsr(S5, R0);
+ __ mov(R0, ShifterOperand(6));
+ __ vmovsr(S6, R0);
+ __ mov(R0, ShifterOperand(8));
+ __ vmovsr(S7, R0);
+
+ __ vsubqi(kByte, Q2, Q1, Q0);
+
+ __ vmovrs(R0, S8);
+ __ vmovrs(R1, S9);
+ __ vmovrs(R2, S10);
+ __ vmovrs(R3, S11);
+
+ __ add(R0, R0, ShifterOperand(R1));
+ __ add(R0, R0, ShifterOperand(R2));
+ __ add(R0, R0, ShifterOperand(R3));
+ __ bx(LR);
+ } else {
+ __ LoadImmediate(R0, 10);
+ __ bx(LR);
+ }
+}
+
+
+ASSEMBLER_TEST_RUN(Vsubqi8, test) {
+ EXPECT(test != NULL);
+ typedef int (*Tst)();
+ EXPECT_EQ(10, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(Vsubqi16, assembler) {
+ if (CPUFeatures::neon_supported()) {
+ __ mov(R0, ShifterOperand(1));
+ __ vmovsr(S0, R0);
+ __ mov(R0, ShifterOperand(2));
+ __ vmovsr(S1, R0);
+ __ mov(R0, ShifterOperand(3));
+ __ vmovsr(S2, R0);
+ __ mov(R0, ShifterOperand(4));
+ __ vmovsr(S3, R0);
+ __ mov(R0, ShifterOperand(2));
+ __ vmovsr(S4, R0);
+ __ mov(R0, ShifterOperand(4));
+ __ vmovsr(S5, R0);
+ __ mov(R0, ShifterOperand(6));
+ __ vmovsr(S6, R0);
+ __ mov(R0, ShifterOperand(8));
+ __ vmovsr(S7, R0);
+
+ __ vsubqi(kHalfword, Q2, Q1, Q0);
+
+ __ vmovrs(R0, S8);
+ __ vmovrs(R1, S9);
+ __ vmovrs(R2, S10);
+ __ vmovrs(R3, S11);
+
+ __ add(R0, R0, ShifterOperand(R1));
+ __ add(R0, R0, ShifterOperand(R2));
+ __ add(R0, R0, ShifterOperand(R3));
+ __ bx(LR);
+ } else {
+ __ LoadImmediate(R0, 10);
+ __ bx(LR);
+ }
+}
+
+
+ASSEMBLER_TEST_RUN(Vsubqi16, test) {
+ EXPECT(test != NULL);
+ typedef int (*Tst)();
+ EXPECT_EQ(10, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(Vsubqi32, assembler) {
+ if (CPUFeatures::neon_supported()) {
+ __ mov(R0, ShifterOperand(1));
+ __ vmovsr(S0, R0);
+ __ mov(R0, ShifterOperand(2));
+ __ vmovsr(S1, R0);
+ __ mov(R0, ShifterOperand(3));
+ __ vmovsr(S2, R0);
+ __ mov(R0, ShifterOperand(4));
+ __ vmovsr(S3, R0);
+ __ mov(R0, ShifterOperand(2));
+ __ vmovsr(S4, R0);
+ __ mov(R0, ShifterOperand(4));
+ __ vmovsr(S5, R0);
+ __ mov(R0, ShifterOperand(6));
+ __ vmovsr(S6, R0);
+ __ mov(R0, ShifterOperand(8));
+ __ vmovsr(S7, R0);
+
+ __ vsubqi(kWord, Q2, Q1, Q0);
+
+ __ vmovrs(R0, S8);
+ __ vmovrs(R1, S9);
+ __ vmovrs(R2, S10);
+ __ vmovrs(R3, S11);
+
+ __ add(R0, R0, ShifterOperand(R1));
+ __ add(R0, R0, ShifterOperand(R2));
+ __ add(R0, R0, ShifterOperand(R3));
+ __ bx(LR);
+ } else {
+ __ LoadImmediate(R0, 10);
+ __ bx(LR);
+ }
+}
+
+
+ASSEMBLER_TEST_RUN(Vsubqi32, test) {
+ EXPECT(test != NULL);
+ typedef int (*Tst)();
+ EXPECT_EQ(10, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(Vsubqi64, assembler) {
+ if (CPUFeatures::neon_supported()) {
+ __ mov(R0, ShifterOperand(1));
+ __ vmovsr(S0, R0);
+ __ mov(R0, ShifterOperand(2));
+ __ vmovsr(S2, R0);
+ __ mov(R0, ShifterOperand(2));
+ __ vmovsr(S4, R0);
+ __ mov(R0, ShifterOperand(4));
+ __ vmovsr(S6, R0);
+
+ __ vsubqi(kWordPair, Q2, Q1, Q0);
+
+ __ vmovrs(R0, S8);
+ __ vmovrs(R2, S10);
+
+ __ add(R0, R0, ShifterOperand(R2));
+ __ bx(LR);
+ } else {
+ __ LoadImmediate(R0, 3);
+ __ bx(LR);
+ }
+}
+
+
+ASSEMBLER_TEST_RUN(Vsubqi64, test) {
+ EXPECT(test != NULL);
+ typedef int (*Tst)();
+ EXPECT_EQ(3, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(Vmulqi8, assembler) {
+ if (CPUFeatures::neon_supported()) {
+ __ mov(R0, ShifterOperand(1));
+ __ vmovsr(S0, R0);
+ __ mov(R0, ShifterOperand(2));
+ __ vmovsr(S1, R0);
+ __ mov(R0, ShifterOperand(3));
+ __ vmovsr(S2, R0);
+ __ mov(R0, ShifterOperand(4));
+ __ vmovsr(S3, R0);
+ __ mov(R0, ShifterOperand(5));
+ __ vmovsr(S4, R0);
+ __ mov(R0, ShifterOperand(6));
+ __ vmovsr(S5, R0);
+ __ mov(R0, ShifterOperand(7));
+ __ vmovsr(S6, R0);
+ __ mov(R0, ShifterOperand(8));
+ __ vmovsr(S7, R0);
+
+ __ vmulqi(kByte, Q2, Q1, Q0);
+
+ __ vmovrs(R0, S8);
+ __ vmovrs(R1, S9);
+ __ vmovrs(R2, S10);
+ __ vmovrs(R3, S11);
+
+ __ add(R0, R0, ShifterOperand(R1));
+ __ add(R0, R0, ShifterOperand(R2));
+ __ add(R0, R0, ShifterOperand(R3));
+ __ bx(LR);
+ } else {
+ __ LoadImmediate(R0, 70);
+ __ bx(LR);
+ }
+}
+
+
+ASSEMBLER_TEST_RUN(Vmulqi8, test) {
+ EXPECT(test != NULL);
+ typedef int (*Tst)();
+ EXPECT_EQ(70, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(Vmulqi16, assembler) {
+ if (CPUFeatures::neon_supported()) {
+ __ mov(R0, ShifterOperand(1));
+ __ vmovsr(S0, R0);
+ __ mov(R0, ShifterOperand(2));
+ __ vmovsr(S1, R0);
+ __ mov(R0, ShifterOperand(3));
+ __ vmovsr(S2, R0);
+ __ mov(R0, ShifterOperand(4));
+ __ vmovsr(S3, R0);
+ __ mov(R0, ShifterOperand(5));
+ __ vmovsr(S4, R0);
+ __ mov(R0, ShifterOperand(6));
+ __ vmovsr(S5, R0);
+ __ mov(R0, ShifterOperand(7));
+ __ vmovsr(S6, R0);
+ __ mov(R0, ShifterOperand(8));
+ __ vmovsr(S7, R0);
+
+ __ vmulqi(kHalfword, Q2, Q1, Q0);
+
+ __ vmovrs(R0, S8);
+ __ vmovrs(R1, S9);
+ __ vmovrs(R2, S10);
+ __ vmovrs(R3, S11);
+
+ __ add(R0, R0, ShifterOperand(R1));
+ __ add(R0, R0, ShifterOperand(R2));
+ __ add(R0, R0, ShifterOperand(R3));
+ __ bx(LR);
+ } else {
+ __ LoadImmediate(R0, 70);
+ __ bx(LR);
+ }
+}
+
+
+ASSEMBLER_TEST_RUN(Vmulqi16, test) {
+ EXPECT(test != NULL);
+ typedef int (*Tst)();
+ EXPECT_EQ(70, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(Vmulqi32, assembler) {
+ if (CPUFeatures::neon_supported()) {
+ __ mov(R0, ShifterOperand(1));
+ __ vmovsr(S0, R0);
+ __ mov(R0, ShifterOperand(2));
+ __ vmovsr(S1, R0);
+ __ mov(R0, ShifterOperand(3));
+ __ vmovsr(S2, R0);
+ __ mov(R0, ShifterOperand(4));
+ __ vmovsr(S3, R0);
+ __ mov(R0, ShifterOperand(5));
+ __ vmovsr(S4, R0);
+ __ mov(R0, ShifterOperand(6));
+ __ vmovsr(S5, R0);
+ __ mov(R0, ShifterOperand(7));
+ __ vmovsr(S6, R0);
+ __ mov(R0, ShifterOperand(8));
+ __ vmovsr(S7, R0);
+
+ __ vmulqi(kWord, Q2, Q1, Q0);
+
+ __ vmovrs(R0, S8);
+ __ vmovrs(R1, S9);
+ __ vmovrs(R2, S10);
+ __ vmovrs(R3, S11);
+
+ __ add(R0, R0, ShifterOperand(R1));
+ __ add(R0, R0, ShifterOperand(R2));
+ __ add(R0, R0, ShifterOperand(R3));
+ __ bx(LR);
+ } else {
+ __ LoadImmediate(R0, 70);
+ __ bx(LR);
+ }
+}
+
+
+ASSEMBLER_TEST_RUN(Vmulqi32, test) {
+ EXPECT(test != NULL);
+ typedef int (*Tst)();
+ EXPECT_EQ(70, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
}
ASSEMBLER_TEST_GENERATE(Vaddqs, assembler) {
if (CPUFeatures::neon_supported()) {
__ LoadSImmediate(S0, 1.0);
- __ vmovs(S1, S0);
- __ vmovs(S2, S0);
- __ vmovs(S3, S0);
- __ vmovs(S4, S0);
- __ vmovs(S5, S0);
- __ vmovs(S6, S0);
- __ vmovs(S7, S0);
+ __ LoadSImmediate(S1, 2.0);
+ __ LoadSImmediate(S2, 3.0);
+ __ LoadSImmediate(S3, 4.0);
+ __ LoadSImmediate(S4, 5.0);
+ __ LoadSImmediate(S5, 6.0);
+ __ LoadSImmediate(S6, 7.0);
+ __ LoadSImmediate(S7, 8.0);
__ vaddqs(Q2, Q0, Q1);
@@ -1758,7 +2078,7 @@
__ bx(LR);
} else {
- __ LoadImmediate(R0, 8);
+ __ LoadImmediate(R0, 36);
__ bx(LR);
}
}
@@ -1767,7 +2087,249 @@
ASSEMBLER_TEST_RUN(Vaddqs, test) {
EXPECT(test != NULL);
typedef int (*Tst)();
- EXPECT_EQ(8, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ EXPECT_EQ(36, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(Vsubqs, assembler) {
+ if (CPUFeatures::neon_supported()) {
+ __ LoadSImmediate(S0, 1.0);
+ __ LoadSImmediate(S1, 2.0);
+ __ LoadSImmediate(S2, 3.0);
+ __ LoadSImmediate(S3, 4.0);
+ __ LoadSImmediate(S4, 2.0);
+ __ LoadSImmediate(S5, 4.0);
+ __ LoadSImmediate(S6, 6.0);
+ __ LoadSImmediate(S7, 8.0);
+
+ __ vsubqs(Q2, Q1, Q0);
+
+ __ vadds(S8, S8, S9);
+ __ vadds(S8, S8, S10);
+ __ vadds(S8, S8, S11);
+
+ __ vcvtis(S0, S8);
+ __ vmovrs(R0, S0);
+
+ __ bx(LR);
+ } else {
+ __ LoadImmediate(R0, 10);
+ __ bx(LR);
+ }
+}
+
+
+ASSEMBLER_TEST_RUN(Vsubqs, test) {
+ EXPECT(test != NULL);
+ typedef int (*Tst)();
+ EXPECT_EQ(10, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(Vmulqs, assembler) {
+ if (CPUFeatures::neon_supported()) {
+ __ LoadSImmediate(S0, 1.0);
+ __ LoadSImmediate(S1, 2.0);
+ __ LoadSImmediate(S2, 3.0);
+ __ LoadSImmediate(S3, 4.0);
+ __ LoadSImmediate(S4, 5.0);
+ __ LoadSImmediate(S5, 6.0);
+ __ LoadSImmediate(S6, 7.0);
+ __ LoadSImmediate(S7, 8.0);
+
+ __ vmulqs(Q2, Q1, Q0);
+
+ __ vadds(S8, S8, S9);
+ __ vadds(S8, S8, S10);
+ __ vadds(S8, S8, S11);
+
+ __ vcvtis(S0, S8);
+ __ vmovrs(R0, S0);
+
+ __ bx(LR);
+ } else {
+ __ LoadImmediate(R0, 70);
+ __ bx(LR);
+ }
+}
+
+
+ASSEMBLER_TEST_RUN(Vmulqs, test) {
+ EXPECT(test != NULL);
+ typedef int (*Tst)();
+ EXPECT_EQ(70, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(VtblX, assembler) {
+ if (CPUFeatures::neon_supported()) {
+ // Index.
+ __ LoadImmediate(R0, 0x03020100);
+ __ vmovsr(S0, R0);
+ __ vmovsr(S1, R0);
+
+ // Table.
+ __ LoadSImmediate(S2, 1.0);
+ __ LoadSImmediate(S3, 2.0);
+ __ LoadSImmediate(S4, 3.0);
+ __ LoadSImmediate(S5, 4.0);
+
+ // Select.
+ __ vtbl(D3, D1, 2, D0);
+
+ // Check that S6, S7 are both 1.0
+ __ vcvtis(S0, S6);
+ __ vcvtis(S1, S7);
+ __ vmovrs(R2, S0);
+ __ vmovrs(R3, S1);
+
+ __ LoadImmediate(R0, 0);
+ __ CompareImmediate(R2, 1);
+ __ bx(LR, NE);
+ __ CompareImmediate(R3, 1);
+ __ bx(LR, NE);
+ __ LoadImmediate(R0, 42);
+ __ bx(LR);
+ } else {
+ __ LoadImmediate(R0, 42);
+ __ bx(LR);
+ }
+}
+
+
+ASSEMBLER_TEST_RUN(VtblX, test) {
+ EXPECT(test != NULL);
+ typedef int (*Tst)();
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(VtblY, assembler) {
+ if (CPUFeatures::neon_supported()) {
+ // Index.
+ __ LoadImmediate(R0, 0x07060504);
+ __ vmovsr(S0, R0);
+ __ vmovsr(S1, R0);
+
+ // Table.
+ __ LoadSImmediate(S2, 2.0);
+ __ LoadSImmediate(S3, 1.0);
+ __ LoadSImmediate(S4, 3.0);
+ __ LoadSImmediate(S5, 4.0);
+
+ // Select.
+ __ vtbl(D3, D1, 2, D0);
+
+ // Check that S6, S7 are both 1.0
+ __ vcvtis(S0, S6);
+ __ vcvtis(S1, S7);
+ __ vmovrs(R2, S0);
+ __ vmovrs(R3, S1);
+
+ __ LoadImmediate(R0, 0);
+ __ CompareImmediate(R2, 1);
+ __ bx(LR, NE);
+ __ CompareImmediate(R3, 1);
+ __ bx(LR, NE);
+ __ LoadImmediate(R0, 42);
+ __ bx(LR);
+ } else {
+ __ LoadImmediate(R0, 42);
+ __ bx(LR);
+ }
+}
+
+
+ASSEMBLER_TEST_RUN(VtblY, test) {
+ EXPECT(test != NULL);
+ typedef int (*Tst)();
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(VtblZ, assembler) {
+ if (CPUFeatures::neon_supported()) {
+ // Index.
+ __ LoadImmediate(R0, 0x0b0a0908);
+ __ vmovsr(S0, R0);
+ __ vmovsr(S1, R0);
+
+ // Table.
+ __ LoadSImmediate(S2, 2.0);
+ __ LoadSImmediate(S3, 3.0);
+ __ LoadSImmediate(S4, 1.0);
+ __ LoadSImmediate(S5, 4.0);
+
+ // Select.
+ __ vtbl(D3, D1, 2, D0);
+
+ // Check that S6, S7 are both 1.0
+ __ vcvtis(S0, S6);
+ __ vcvtis(S1, S7);
+ __ vmovrs(R2, S0);
+ __ vmovrs(R3, S1);
+
+ __ LoadImmediate(R0, 0);
+ __ CompareImmediate(R2, 1);
+ __ bx(LR, NE);
+ __ CompareImmediate(R3, 1);
+ __ bx(LR, NE);
+ __ LoadImmediate(R0, 42);
+ __ bx(LR);
+ } else {
+ __ LoadImmediate(R0, 42);
+ __ bx(LR);
+ }
+}
+
+
+ASSEMBLER_TEST_RUN(VtblZ, test) {
+ EXPECT(test != NULL);
+ typedef int (*Tst)();
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(VtblW, assembler) {
+ if (CPUFeatures::neon_supported()) {
+ // Index.
+ __ LoadImmediate(R0, 0x0f0e0d0c);
+ __ vmovsr(S0, R0);
+ __ vmovsr(S1, R0);
+
+ // Table.
+ __ LoadSImmediate(S2, 2.0);
+ __ LoadSImmediate(S3, 3.0);
+ __ LoadSImmediate(S4, 4.0);
+ __ LoadSImmediate(S5, 1.0);
+
+ // Select.
+ __ vtbl(D3, D1, 2, D0);
+
+ // Check that S6, S7 are both 1.0
+ __ vcvtis(S0, S6);
+ __ vcvtis(S1, S7);
+ __ vmovrs(R2, S0);
+ __ vmovrs(R3, S1);
+
+ __ LoadImmediate(R0, 0);
+ __ CompareImmediate(R2, 1);
+ __ bx(LR, NE);
+ __ CompareImmediate(R3, 1);
+ __ bx(LR, NE);
+ __ LoadImmediate(R0, 42);
+ __ bx(LR);
+ } else {
+ __ LoadImmediate(R0, 42);
+ __ bx(LR);
+ }
+}
+
+
+ASSEMBLER_TEST_RUN(VtblW, test) {
+ EXPECT(test != NULL);
+ typedef int (*Tst)();
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
}
diff --git a/runtime/vm/ast.cc b/runtime/vm/ast.cc
index 809b4db..f935546 100644
--- a/runtime/vm/ast.cc
+++ b/runtime/vm/ast.cc
@@ -495,7 +495,7 @@
const Function& getter =
Function::Handle(cls().LookupStaticFunction(getter_name));
ASSERT(!getter.IsNull() &&
- (getter.kind() == RawFunction::kConstImplicitGetter));
+ (getter.kind() == RawFunction::kImplicitStaticFinalGetter));
#endif
return new StoreStaticFieldNode(token_pos(), field, rhs);
}
diff --git a/runtime/vm/bootstrap_natives.h b/runtime/vm/bootstrap_natives.h
index df3fc8c0..99008cb 100644
--- a/runtime/vm/bootstrap_natives.h
+++ b/runtime/vm/bootstrap_natives.h
@@ -240,12 +240,18 @@
V(Mirrors_makeLocalClassMirror, 1) \
V(Mirrors_makeLocalMirrorSystem, 0) \
V(Mirrors_metadata, 1) \
- V(LocalObjectMirrorImpl_invoke, 4) \
- V(LocalObjectMirrorImpl_getField, 2) \
- V(LocalObjectMirrorImpl_setField, 4) \
- V(LocalClosureMirrorImpl_apply, 3) \
- V(LocalClassMirrorImpl_invokeConstructor, 4) \
+ V(InstanceMirror_invoke, 4) \
+ V(InstanceMirror_invokeGetter, 3) \
+ V(InstanceMirror_invokeSetter, 4) \
+ V(ClosureMirror_apply, 2) \
V(ClassMirror_name, 1) \
+ V(ClassMirror_invoke, 4) \
+ V(ClassMirror_invokeGetter, 3) \
+ V(ClassMirror_invokeSetter, 4) \
+ V(ClassMirror_invokeConstructor, 3) \
+ V(LibraryMirror_invoke, 4) \
+ V(LibraryMirror_invokeGetter, 3) \
+ V(LibraryMirror_invokeSetter, 4) \
V(MethodMirror_name, 1) \
V(GrowableObjectArray_allocate, 2) \
V(GrowableObjectArray_getIndexed, 2) \
diff --git a/runtime/vm/code_generator.cc b/runtime/vm/code_generator.cc
index afa0fcc..8efe89c 100644
--- a/runtime/vm/code_generator.cc
+++ b/runtime/vm/code_generator.cc
@@ -801,16 +801,13 @@
const ICData& ic_data) {
ArgumentsDescriptor
arguments_descriptor(Array::Handle(ic_data.arguments_descriptor()));
- intptr_t num_arguments = arguments_descriptor.Count();
- int num_named_arguments = arguments_descriptor.NamedCount();
String& function_name = String::Handle(ic_data.target_name());
ASSERT(function_name.IsSymbol());
Function& function = Function::Handle();
function = Resolver::ResolveDynamic(receiver,
function_name,
- num_arguments,
- num_named_arguments);
+ arguments_descriptor);
if (function.IsNull()) {
return Code::null();
} else {
@@ -1063,15 +1060,11 @@
cls.ToCString(), name.ToCString());
}
- intptr_t arg_count =
- Smi::Cast(Object::Handle(descriptor.At(0))).Value();
- intptr_t named_arg_count =
- arg_count - Smi::Cast(Object::Handle(descriptor.At(1))).Value();
+ ArgumentsDescriptor args_desc(descriptor);
const Function& target = Function::Handle(
Resolver::ResolveDynamicForReceiverClass(cls,
name,
- arg_count,
- named_arg_count));
+ args_desc));
Instructions& instructions = Instructions::Handle();
if (!target.IsNull()) {
@@ -1112,12 +1105,12 @@
args.Add(&receiver);
args.Add(&arg1);
const intptr_t kNumArguments = 2;
- const intptr_t kNumNamedArguments = 0;
- Function& target_function = Function::Handle();
- target_function = Resolver::ResolveDynamic(receiver,
- target_name,
- kNumArguments,
- kNumNamedArguments);
+ ArgumentsDescriptor args_desc(
+ Array::Handle(ArgumentsDescriptor::New(kNumArguments)));
+ const Function& target_function = Function::Handle(
+ Resolver::ResolveDynamic(receiver,
+ target_name,
+ args_desc));
ASSERT(!target_function.IsNull());
GrowableArray<intptr_t> class_ids(kNumArguments);
ASSERT(ic_data.num_args_tested() == kNumArguments);
@@ -1189,12 +1182,12 @@
// 1. Check if there is a getter with the same name.
const String& getter_name = String::Handle(Field::GetterName(target_name));
const int kNumArguments = 1;
- const int kNumNamedArguments = 0;
+ ArgumentsDescriptor args_desc(
+ Array::Handle(ArgumentsDescriptor::New(kNumArguments)));
const Function& getter = Function::Handle(
Resolver::ResolveDynamicForReceiverClass(receiver_class,
getter_name,
- kNumArguments,
- kNumNamedArguments));
+ args_desc));
if (getter.IsNull() || getter.IsMethodExtractor()) {
return false;
}
diff --git a/runtime/vm/compiler.cc b/runtime/vm/compiler.cc
index ee9a5a0..a0dc2814 100644
--- a/runtime/vm/compiler.cc
+++ b/runtime/vm/compiler.cc
@@ -843,7 +843,7 @@
const char* kEvalConst = "eval_const";
const Function& func = Function::ZoneHandle(Function::New(
String::Handle(Symbols::New(kEvalConst)),
- RawFunction::kConstImplicitGetter,
+ RawFunction::kImplicitStaticFinalGetter,
true, // static function.
false, // not const function.
false, // not abstract
diff --git a/runtime/vm/constants_arm.h b/runtime/vm/constants_arm.h
index 7006fe7..1a65c51 100644
--- a/runtime/vm/constants_arm.h
+++ b/runtime/vm/constants_arm.h
@@ -164,10 +164,19 @@
}
+static inline SRegister EvenSRegisterOf(DRegister d) {
+ return static_cast<SRegister>(d * 2);
+}
+
+static inline SRegister OddSRegisterOf(DRegister d) {
+ return static_cast<SRegister>((d * 2) + 1);
+}
+
+
// Register aliases for floating point scratch registers.
const QRegister QTMP = Q7; // Overlaps with DTMP, STMP.
-const DRegister DTMP = D14; // Overlaps with STMP.
-const SRegister STMP = S28;
+const DRegister DTMP = EvenDRegisterOf(QTMP); // Overlaps with STMP.
+const SRegister STMP = EvenSRegisterOf(DTMP);
// Architecture independent aliases.
typedef QRegister FpuRegister;
diff --git a/runtime/vm/dart.cc b/runtime/vm/dart.cc
index e401374..af17f5e 100644
--- a/runtime/vm/dart.cc
+++ b/runtime/vm/dart.cc
@@ -14,6 +14,7 @@
#include "vm/isolate.h"
#include "vm/object.h"
#include "vm/object_store.h"
+#include "vm/object_id_ring.h"
#include "vm/port.h"
#include "vm/simulator.h"
#include "vm/snapshot.h"
@@ -159,6 +160,7 @@
StackZone zone(isolate);
HandleScope handle_scope(isolate);
Heap::Init(isolate);
+ ObjectIdRing::Init(isolate);
ObjectStore::Init(isolate);
if (snapshot_buffer == NULL) {
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index ccda777..1162b05 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -1874,13 +1874,17 @@
return Api::NewError("Object does not implement the List interface");
}
const String& name = String::Handle(Field::GetterName(Symbols::Length()));
+ const int kNumArgs = 1;
+ ArgumentsDescriptor args_desc(
+ Array::Handle(ArgumentsDescriptor::New(kNumArgs)));
const Function& function =
- Function::Handle(isolate, Resolver::ResolveDynamic(instance, name, 1, 0));
+ Function::Handle(isolate, Resolver::ResolveDynamic(instance,
+ name,
+ args_desc));
if (function.IsNull()) {
return Api::NewError("List object does not have a 'length' field.");
}
- const int kNumArgs = 1;
const Array& args = Array::Handle(isolate, Array::New(kNumArgs));
args.SetAt(0, instance); // Set up the receiver as the first argument.
const Object& retval =
@@ -1940,11 +1944,13 @@
const Instance& instance =
Instance::Handle(isolate, GetListInstance(isolate, obj));
if (!instance.IsNull()) {
+ const int kNumArgs = 2;
+ ArgumentsDescriptor args_desc(
+ Array::Handle(ArgumentsDescriptor::New(kNumArgs)));
const Function& function = Function::Handle(
isolate,
- Resolver::ResolveDynamic(instance, Symbols::IndexToken(), 2, 0));
+ Resolver::ResolveDynamic(instance, Symbols::IndexToken(), args_desc));
if (!function.IsNull()) {
- const int kNumArgs = 2;
const Array& args = Array::Handle(isolate, Array::New(kNumArgs));
const Integer& indexobj = Integer::Handle(isolate, Integer::New(index));
args.SetAt(0, instance);
@@ -1992,12 +1998,14 @@
const Instance& instance =
Instance::Handle(isolate, GetListInstance(isolate, obj));
if (!instance.IsNull()) {
+ const intptr_t kNumArgs = 3;
+ ArgumentsDescriptor args_desc(
+ Array::Handle(ArgumentsDescriptor::New(kNumArgs)));
const Function& function = Function::Handle(
isolate,
Resolver::ResolveDynamic(instance,
Symbols::AssignIndexToken(),
- 3,
- 0));
+ args_desc));
if (!function.IsNull()) {
const Integer& index_obj =
Integer::Handle(isolate, Integer::New(index));
@@ -2006,7 +2014,6 @@
if (!value_obj.IsNull() && !value_obj.IsInstance()) {
RETURN_TYPE_ERROR(isolate, value, Instance);
}
- const intptr_t kNumArgs = 3;
const Array& args = Array::Handle(isolate, Array::New(kNumArgs));
args.SetAt(0, instance);
args.SetAt(1, index_obj);
@@ -2165,13 +2172,15 @@
const Instance& instance =
Instance::Handle(isolate, GetListInstance(isolate, obj));
if (!instance.IsNull()) {
+ const int kNumArgs = 2;
+ ArgumentsDescriptor args_desc(
+ Array::Handle(ArgumentsDescriptor::New(kNumArgs)));
const Function& function = Function::Handle(
isolate,
- Resolver::ResolveDynamic(instance, Symbols::IndexToken(), 2, 0));
+ Resolver::ResolveDynamic(instance, Symbols::IndexToken(), args_desc));
if (!function.IsNull()) {
Object& result = Object::Handle(isolate);
Integer& intobj = Integer::Handle(isolate);
- const int kNumArgs = 2;
const Array& args = Array::Handle(isolate, Array::New(kNumArgs));
args.SetAt(0, instance); // Set up the receiver as the first argument.
for (int i = 0; i < length; i++) {
@@ -2260,16 +2269,17 @@
const Instance& instance =
Instance::Handle(isolate, GetListInstance(isolate, obj));
if (!instance.IsNull()) {
+ const int kNumArgs = 3;
+ ArgumentsDescriptor args_desc(
+ Array::Handle(ArgumentsDescriptor::New(kNumArgs)));
const Function& function = Function::Handle(
isolate,
Resolver::ResolveDynamic(instance,
Symbols::AssignIndexToken(),
- 3,
- 0));
+ args_desc));
if (!function.IsNull()) {
Integer& indexobj = Integer::Handle(isolate);
Integer& valueobj = Integer::Handle(isolate);
- const int kNumArgs = 3;
const Array& args = Array::Handle(isolate, Array::New(kNumArgs));
args.SetAt(0, instance); // Set up the receiver as the first argument.
for (int i = 0; i < length; i++) {
@@ -2957,12 +2967,11 @@
} else if (obj.IsNull() || obj.IsInstance()) {
Instance& instance = Instance::Handle(isolate);
instance ^= obj.raw();
+ ArgumentsDescriptor args_desc(
+ Array::Handle(ArgumentsDescriptor::New(number_of_arguments + 1)));
const Function& function = Function::Handle(
isolate,
- Resolver::ResolveDynamic(instance,
- function_name,
- (number_of_arguments + 1),
- Resolver::kIsQualified));
+ Resolver::ResolveDynamic(instance, function_name, args_desc));
args.SetAt(0, instance);
if (function.IsNull()) {
const Array& args_descriptor =
diff --git a/runtime/vm/dart_entry.cc b/runtime/vm/dart_entry.cc
index 839407d..dd3f08f 100644
--- a/runtime/vm/dart_entry.cc
+++ b/runtime/vm/dart_entry.cc
@@ -138,12 +138,12 @@
// Now use the invocation mirror object and invoke NoSuchMethod.
const int kNumArguments = 2;
- const int kNumNamedArguments = 0;
+ ArgumentsDescriptor args_desc(
+ Array::Handle(ArgumentsDescriptor::New(kNumArguments)));
const Function& function = Function::Handle(
Resolver::ResolveDynamic(receiver,
Symbols::NoSuchMethod(),
- kNumArguments,
- kNumNamedArguments));
+ args_desc));
ASSERT(!function.IsNull());
const Array& args = Array::Handle(Array::New(kNumArguments));
args.SetAt(0, receiver);
@@ -152,6 +152,59 @@
}
+RawObject* DartEntry::InvokeConstructor(const Class& klass,
+ const Function& constructor,
+ const Array& arguments) {
+ Class& ultimate_klass = Class::Handle(klass.raw());
+ Function& ultimate_constructor = Function::Handle(constructor.raw());
+
+ Instance& new_object = Instance::Handle();
+ if (ultimate_constructor.IsRedirectingFactory()) {
+ Type& type = Type::Handle(ultimate_constructor.RedirectionType());
+ ultimate_klass = type.type_class();
+ ultimate_constructor = ultimate_constructor.RedirectionTarget();
+ }
+ if (ultimate_constructor.IsConstructor()) {
+ // "Constructors" are really instance initializers. They are passed a newly
+ // allocated object as an extra argument.
+ new_object = Instance::New(ultimate_klass);
+ }
+
+ // Create the argument list.
+ intptr_t number_of_arguments = arguments.Length();
+ intptr_t arg_index = 0;
+ int extra_args = (ultimate_constructor.IsConstructor() ? 2 : 1);
+ const Array& args =
+ Array::Handle(Array::New(number_of_arguments + extra_args));
+ if (ultimate_constructor.IsConstructor()) {
+ // Constructors get the uninitialized object and a constructor phase.
+ args.SetAt(arg_index++, new_object);
+ args.SetAt(arg_index++,
+ Smi::Handle(Smi::New(Function::kCtorPhaseAll)));
+ } else {
+ // Factories get type arguments.
+ args.SetAt(arg_index++, TypeArguments::Handle());
+ }
+ Object& argument = Object::Handle();
+ for (int i = 0; i < number_of_arguments; i++) {
+ argument = (arguments.At(i));
+ args.SetAt(arg_index++, argument);
+ }
+
+ // Invoke the constructor and return the new object.
+ const Object& result =
+ Object::Handle(DartEntry::InvokeFunction(ultimate_constructor, args));
+ if (result.IsError()) {
+ return result.raw();
+ }
+ if (ultimate_constructor.IsConstructor()) {
+ return new_object.raw();
+ } else {
+ return result.raw();
+ }
+}
+
+
ArgumentsDescriptor::ArgumentsDescriptor(const Array& array)
: array_(array) {
}
@@ -336,12 +389,12 @@
RawObject* DartLibraryCalls::ToString(const Instance& receiver) {
const int kNumArguments = 1; // Receiver.
- const int kNumNamedArguments = 0; // None.
+ ArgumentsDescriptor args_desc(
+ Array::Handle(ArgumentsDescriptor::New(kNumArguments)));
const Function& function = Function::Handle(
Resolver::ResolveDynamic(receiver,
Symbols::toString(),
- kNumArguments,
- kNumNamedArguments));
+ args_desc));
ASSERT(!function.IsNull());
const Array& args = Array::Handle(Array::New(kNumArguments));
args.SetAt(0, receiver);
@@ -355,12 +408,12 @@
RawObject* DartLibraryCalls::Equals(const Instance& left,
const Instance& right) {
const int kNumArguments = 2;
- const int kNumNamedArguments = 0;
+ ArgumentsDescriptor args_desc(
+ Array::Handle(ArgumentsDescriptor::New(kNumArguments)));
const Function& function = Function::Handle(
Resolver::ResolveDynamic(left,
Symbols::EqualOperator(),
- kNumArguments,
- kNumNamedArguments));
+ args_desc));
ASSERT(!function.IsNull());
const Array& args = Array::Handle(Array::New(kNumArguments));
@@ -467,11 +520,12 @@
const Instance& key,
const Instance& value) {
const int kNumArguments = 3;
+ ArgumentsDescriptor args_desc(
+ Array::Handle(ArgumentsDescriptor::New(kNumArguments)));
const Function& function = Function::Handle(
Resolver::ResolveDynamic(map,
Symbols::AssignIndexToken(),
- kNumArguments,
- 0));
+ args_desc));
ASSERT(!function.IsNull());
const Array& args = Array::Handle(Array::New(kNumArguments));
args.SetAt(0, map);
diff --git a/runtime/vm/dart_entry.h b/runtime/vm/dart_entry.h
index 92d05af..63ed513 100644
--- a/runtime/vm/dart_entry.h
+++ b/runtime/vm/dart_entry.h
@@ -142,6 +142,13 @@
const String& target_name,
const Array& arguments,
const Array& arguments_descriptor);
+
+ // Invokes a generative constructor, redirecting constructor, factory or
+ // redirecting factory. On success, returns a RawInstance. On failure,
+ // a RawError.
+ static RawObject* InvokeConstructor(const Class& klass,
+ const Function &constructor,
+ const Array& arguments);
};
diff --git a/runtime/vm/debugger.cc b/runtime/vm/debugger.cc
index d26ae75..f479a4e 100644
--- a/runtime/vm/debugger.cc
+++ b/runtime/vm/debugger.cc
@@ -1536,7 +1536,7 @@
RawFunction::Kind fkind = func.kind();
if ((fkind == RawFunction::kImplicitGetter) ||
(fkind == RawFunction::kImplicitSetter) ||
- (fkind == RawFunction::kConstImplicitGetter) ||
+ (fkind == RawFunction::kImplicitStaticFinalGetter) ||
(fkind == RawFunction::kMethodExtractor) ||
(fkind == RawFunction::kNoSuchMethodDispatcher) ||
(fkind == RawFunction::kInvokeFieldDispatcher)) {
diff --git a/runtime/vm/disassembler_arm.cc b/runtime/vm/disassembler_arm.cc
index 52e3a52..d3dd288 100644
--- a/runtime/vm/disassembler_arm.cc
+++ b/runtime/vm/disassembler_arm.cc
@@ -33,6 +33,7 @@
void PrintRegister(int reg);
void PrintSRegister(int reg);
void PrintDRegister(int reg);
+ void PrintDRegisterList(int start, int reg_count);
void PrintQRegister(int reg);
void PrintCondition(Instr* instr);
void PrintShiftRm(Instr* instr);
@@ -330,6 +331,18 @@
}
+void ARMDecoder::PrintDRegisterList(int start, int reg_count) {
+ Print("{");
+ for (int i = start; i < start + reg_count; i++) {
+ PrintDRegister(i);
+ if (i != start + reg_count - 1) {
+ Print(", ");
+ }
+ }
+ Print("}");
+}
+
+
int ARMDecoder::FormatDRegister(Instr* instr, const char* format) {
ASSERT(format[0] == 'd');
if (format[1] == 'n') { // 'dn: Dn register
@@ -348,15 +361,14 @@
ASSERT(STRING_STARTS_WITH(format, "dlist"));
int reg_count = instr->Bits(0, 8) >> 1;
int start = (instr->Bit(22) << 4) | instr->Bits(12, 4);
- Print("{");
- for (int i = start; i < start + reg_count; i++) {
- PrintDRegister(i);
- if (i != start + reg_count - 1) {
- Print(", ");
- }
- }
- Print("}");
+ PrintDRegisterList(start, reg_count);
return 5;
+ } else if (format[1] == 't') {
+ ASSERT(STRING_STARTS_WITH(format, "dtbllist"));
+ int reg_count = instr->Bits(8, 2) + 1;
+ int start = (instr->Bit(7) << 4) | instr->Bits(16, 4);
+ PrintDRegisterList(start, reg_count);
+ return 8;
}
UNREACHABLE();
return -1;
@@ -531,12 +543,20 @@
instr->SvcField());
return 3;
} else if (format[1] == 'z') {
- // 'sz: Size field of SIMD instruction.
- int sz = 8 << (instr->Bits(20, 2));
+ // 'sz: Size field of SIMD instructions.
+ int sz = instr->Bits(20, 2);
+ char const* sz_str;
+ switch (sz) {
+ case 0: sz_str = "b"; break;
+ case 1: sz_str = "h"; break;
+ case 2: sz_str = "w"; break;
+ case 3: sz_str = "l"; break;
+ default: sz_str = "?"; break;
+ }
buffer_pos_ += OS::SNPrint(current_position_in_buffer(),
remaining_size_in_buffer(),
- "I%d",
- sz);
+ "%s",
+ sz_str);
return 2;
} else if (format[1] == ' ') {
// 's: S field of data processing instructions.
@@ -1270,16 +1290,33 @@
ASSERT(instr->ConditionField() == kSpecialCondition);
if (instr->Bit(6) == 1) {
if ((instr->Bits(8, 4) == 8) && (instr->Bit(4) == 0) &&
- (instr->Bit(24) == 0)) {
- Format(instr, "vadd.'sz 'qd, 'qn, 'qm");
+ (instr->Bits(23, 2) == 0)) {
+ Format(instr, "vaddq'sz 'qd, 'qn, 'qm");
} else if ((instr->Bits(8, 4) == 13) && (instr->Bit(4) == 0) &&
- (instr->Bit(24) == 0)) {
- Format(instr, "vadd.F32 'qd, 'qn, 'qm");
+ (instr->Bits(23, 2) == 0) && (instr->Bit(21) == 0)) {
+ Format(instr, "vaddqs 'qd, 'qn, 'qm");
+ } else if ((instr->Bits(8, 4) == 8) && (instr->Bit(4) == 0) &&
+ (instr->Bits(23, 2) == 2)) {
+ Format(instr, "vsubq'sz 'qd, 'qn, 'qm");
+ } else if ((instr->Bits(8, 4) == 13) && (instr->Bit(4) == 0) &&
+ (instr->Bits(23, 2) == 0) && (instr->Bit(21) == 1)) {
+ Format(instr, "vsubqs 'qd, 'qn, 'qm");
+ } else if ((instr->Bits(8, 4) == 9) && (instr->Bit(4) == 1) &&
+ (instr->Bits(23, 2) == 0)) {
+ Format(instr, "vmulq'sz 'qd, 'qn, 'qm");
+ } else if ((instr->Bits(8, 4) == 13) && (instr->Bit(4) == 1) &&
+ (instr->Bits(23, 2) == 2) && (instr->Bit(21) == 0)) {
+ Format(instr, "vmulqs 'qd, 'qn, 'qm");
} else {
Unknown(instr);
}
} else {
- Unknown(instr);
+ if ((instr->Bits(23, 2) == 3) && (instr->Bits(20, 2) == 3) &&
+ (instr->Bits(10, 2) == 2) && (instr->Bit(4) == 0)) {
+ Format(instr, "vtbl 'dd, 'dtbllist, 'dm");
+ } else {
+ Unknown(instr);
+ }
}
}
diff --git a/runtime/vm/exceptions.cc b/runtime/vm/exceptions.cc
index f994178..35c9582 100644
--- a/runtime/vm/exceptions.cc
+++ b/runtime/vm/exceptions.cc
@@ -618,6 +618,14 @@
library = Library::CoreLibrary();
class_name = &Symbols::AbstractClassInstantiationError();
break;
+ case kMirroredUncaughtExceptionError:
+ library = Library::MirrorsLibrary();
+ class_name = &Symbols::MirroredUncaughtExceptionError();
+ break;
+ case kMirroredCompilationError:
+ library = Library::MirrorsLibrary();
+ class_name = &Symbols::MirroredCompilationError();
+ break;
}
return DartLibraryCalls::ExceptionCreate(library,
diff --git a/runtime/vm/exceptions.h b/runtime/vm/exceptions.h
index 9d4a18e..e3b3c12 100644
--- a/runtime/vm/exceptions.h
+++ b/runtime/vm/exceptions.h
@@ -62,6 +62,8 @@
kType,
kFallThrough,
kAbstractClassInstantiation,
+ kMirroredUncaughtExceptionError,
+ kMirroredCompilationError,
};
static void ThrowByType(ExceptionType type, const Array& arguments);
diff --git a/runtime/vm/flow_graph_builder.cc b/runtime/vm/flow_graph_builder.cc
index e0d2fff..6665626 100644
--- a/runtime/vm/flow_graph_builder.cc
+++ b/runtime/vm/flow_graph_builder.cc
@@ -802,7 +802,7 @@
const bool is_implicit_dynamic_getter =
(!function.is_static() &&
((function.kind() == RawFunction::kImplicitGetter) ||
- (function.kind() == RawFunction::kConstImplicitGetter)));
+ (function.kind() == RawFunction::kImplicitStaticFinalGetter)));
// Implicit getters do not need a type check at return, unless they compute
// the initial value of a static field.
// The body of a constructor cannot modify the type of the
diff --git a/runtime/vm/flow_graph_compiler_arm.cc b/runtime/vm/flow_graph_compiler_arm.cc
index 31acb69..82deb39 100644
--- a/runtime/vm/flow_graph_compiler_arm.cc
+++ b/runtime/vm/flow_graph_compiler_arm.cc
@@ -879,6 +879,11 @@
// Copy or initialize optional named arguments.
Label all_arguments_processed;
+#ifdef DEBUG
+ const bool check_correct_named_args = true;
+#else
+ const bool check_correct_named_args = function.IsClosureFunction();
+#endif
if (num_opt_named_params > 0) {
// Start by alphabetically sorting the names of the optional parameters.
LocalVariable** opt_param = new LocalVariable*[num_opt_named_params];
@@ -946,10 +951,13 @@
}
delete[] opt_param;
delete[] opt_param_position;
- // Check that R6 now points to the null terminator in the array descriptor.
- __ ldr(R5, Address(R6, 0));
- __ CompareImmediate(R5, reinterpret_cast<int32_t>(Object::null()));
- __ b(&all_arguments_processed, EQ);
+ if (check_correct_named_args) {
+ // Check that R6 now points to the null terminator in the arguments
+ // descriptor.
+ __ ldr(R5, Address(R6, 0));
+ __ CompareImmediate(R5, reinterpret_cast<int32_t>(Object::null()));
+ __ b(&all_arguments_processed, EQ);
+ }
} else {
ASSERT(num_opt_pos_params > 0);
__ ldr(R8,
@@ -976,27 +984,30 @@
__ str(R5, param_addr);
__ Bind(&next_parameter);
}
- __ ldr(R7, FieldAddress(R4, ArgumentsDescriptor::count_offset()));
- __ SmiUntag(R7);
- // Check that R8 equals R7, i.e. no named arguments passed.
- __ cmp(R8, ShifterOperand(R7));
- __ b(&all_arguments_processed, EQ);
+ if (check_correct_named_args) {
+ __ ldr(R7, FieldAddress(R4, ArgumentsDescriptor::count_offset()));
+ __ SmiUntag(R7);
+ // Check that R8 equals R7, i.e. no named arguments passed.
+ __ cmp(R8, ShifterOperand(R7));
+ __ b(&all_arguments_processed, EQ);
+ }
}
__ Bind(&wrong_num_arguments);
- // Invoke noSuchMethod function passing the original name of the function.
- // If the function is a closure function, use "call" as the original name.
- const String& name = String::Handle(
- function.IsClosureFunction() ? Symbols::Call().raw() : function.name());
- const int kNumArgsChecked = 1;
- const ICData& ic_data = ICData::ZoneHandle(
- ICData::New(function, name, Object::null_array(),
- Isolate::kNoDeoptId, kNumArgsChecked));
- __ LoadObject(R5, ic_data);
- __ LeaveDartFrame(); // The arguments are still on the stack.
- __ Branch(&StubCode::CallNoSuchMethodFunctionLabel());
- // The noSuchMethod call may return to the caller, but not here.
- __ bkpt(0);
+ if (function.IsClosureFunction()) {
+ // Invoke noSuchMethod function passing "call" as the original name.
+ const int kNumArgsChecked = 1;
+ const ICData& ic_data = ICData::ZoneHandle(
+ ICData::New(function, Symbols::Call(), Object::null_array(),
+ Isolate::kNoDeoptId, kNumArgsChecked));
+ __ LoadObject(R5, ic_data);
+ __ LeaveDartFrame(); // The arguments are still on the stack.
+ __ Branch(&StubCode::CallNoSuchMethodFunctionLabel());
+ // The noSuchMethod call may return to the caller, but not here.
+ __ bkpt(0);
+ } else if (check_correct_named_args) {
+ __ Stop("Wrong arguments");
+ }
__ Bind(&all_arguments_processed);
// Nullify originally passed arguments only after they have been copied and
@@ -1026,7 +1037,7 @@
// SP: receiver.
// Sequence node has one return node, its input is load field node.
__ ldr(R0, Address(SP, 0 * kWordSize));
- __ LoadFromOffset(kLoadWord, R0, R0, offset - kHeapObjectTag);
+ __ LoadFromOffset(kWord, R0, R0, offset - kHeapObjectTag);
__ Ret();
}
@@ -1323,7 +1334,7 @@
const MegamorphicCache& cache =
MegamorphicCache::ZoneHandle(table->Lookup(name, arguments_descriptor));
Label not_smi, load_cache;
- __ LoadFromOffset(kLoadWord, R0, SP, (argument_count - 1) * kWordSize);
+ __ LoadFromOffset(kWord, R0, SP, (argument_count - 1) * kWordSize);
__ tst(R0, ShifterOperand(kSmiTagMask));
__ b(¬_smi, NE);
__ mov(R0, ShifterOperand(Smi::RawValue(kSmiCid)));
@@ -1511,6 +1522,7 @@
if (locs->live_registers()->ContainsFpuRegister(fpu_reg)) {
DRegister d1 = EvenDRegisterOf(fpu_reg);
DRegister d2 = OddDRegisterOf(fpu_reg);
+ // TOOD(regis): merge stores using vstmd instruction.
__ vstrd(d1, Address(SP, offset));
__ vstrd(d2, Address(SP, offset + 2 * kWordSize));
offset += kFpuRegisterSize;
@@ -1547,6 +1559,7 @@
if (locs->live_registers()->ContainsFpuRegister(fpu_reg)) {
DRegister d1 = EvenDRegisterOf(fpu_reg);
DRegister d2 = OddDRegisterOf(fpu_reg);
+ // TOOD(regis): merge loads using vldmd instruction.
__ vldrd(d1, Address(SP, offset));
__ vldrd(d2, Address(SP, offset + 2 * kWordSize));
offset += kFpuRegisterSize;
diff --git a/runtime/vm/flow_graph_compiler_ia32.cc b/runtime/vm/flow_graph_compiler_ia32.cc
index 3ecdfc3..eab9bcf 100644
--- a/runtime/vm/flow_graph_compiler_ia32.cc
+++ b/runtime/vm/flow_graph_compiler_ia32.cc
@@ -899,6 +899,11 @@
const Immediate& raw_null =
Immediate(reinterpret_cast<intptr_t>(Object::null()));
Label all_arguments_processed;
+#ifdef DEBUG
+ const bool check_correct_named_args = true;
+#else
+ const bool check_correct_named_args = function.IsClosureFunction();
+#endif
if (num_opt_named_params > 0) {
// Start by alphabetically sorting the names of the optional parameters.
LocalVariable** opt_param = new LocalVariable*[num_opt_named_params];
@@ -966,9 +971,12 @@
}
delete[] opt_param;
delete[] opt_param_position;
- // Check that EDI now points to the null terminator in the array descriptor.
- __ cmpl(Address(EDI, 0), raw_null);
- __ j(EQUAL, &all_arguments_processed, Assembler::kNearJump);
+ if (check_correct_named_args) {
+ // Check that EDI now points to the null terminator in the arguments
+ // descriptor.
+ __ cmpl(Address(EDI, 0), raw_null);
+ __ j(EQUAL, &all_arguments_processed, Assembler::kNearJump);
+ }
} else {
ASSERT(num_opt_pos_params > 0);
__ movl(ECX,
@@ -995,27 +1003,30 @@
__ movl(param_addr, EAX);
__ Bind(&next_parameter);
}
- __ movl(EBX, FieldAddress(EDX, ArgumentsDescriptor::count_offset()));
- __ SmiUntag(EBX);
- // Check that ECX equals EBX, i.e. no named arguments passed.
- __ cmpl(ECX, EBX);
- __ j(EQUAL, &all_arguments_processed, Assembler::kNearJump);
+ if (check_correct_named_args) {
+ __ movl(EBX, FieldAddress(EDX, ArgumentsDescriptor::count_offset()));
+ __ SmiUntag(EBX);
+ // Check that ECX equals EBX, i.e. no named arguments passed.
+ __ cmpl(ECX, EBX);
+ __ j(EQUAL, &all_arguments_processed, Assembler::kNearJump);
+ }
}
__ Bind(&wrong_num_arguments);
- // Invoke noSuchMethod function passing the original name of the function.
- // If the function is a closure function, use "call" as the original name.
- const String& name = String::Handle(
- function.IsClosureFunction() ? Symbols::Call().raw() : function.name());
- const int kNumArgsChecked = 1;
- const ICData& ic_data = ICData::ZoneHandle(
- ICData::New(function, name, Object::null_array(),
- Isolate::kNoDeoptId, kNumArgsChecked));
- __ LoadObject(ECX, ic_data);
- __ LeaveFrame(); // The arguments are still on the stack.
- __ jmp(&StubCode::CallNoSuchMethodFunctionLabel());
- // The noSuchMethod call may return to the caller, but not here.
- __ int3();
+ if (function.IsClosureFunction()) {
+ // Invoke noSuchMethod function passing "call" as the original name.
+ const int kNumArgsChecked = 1;
+ const ICData& ic_data = ICData::ZoneHandle(
+ ICData::New(function, Symbols::Call(), Object::null_array(),
+ Isolate::kNoDeoptId, kNumArgsChecked));
+ __ LoadObject(ECX, ic_data);
+ __ LeaveFrame(); // The arguments are still on the stack.
+ __ jmp(&StubCode::CallNoSuchMethodFunctionLabel());
+ // The noSuchMethod call may return to the caller, but not here.
+ __ int3();
+ } else if (check_correct_named_args) {
+ __ Stop("Wrong arguments");
+ }
__ Bind(&all_arguments_processed);
// Nullify originally passed arguments only after they have been copied and
diff --git a/runtime/vm/flow_graph_compiler_mips.cc b/runtime/vm/flow_graph_compiler_mips.cc
index a98f0a5..114c060 100644
--- a/runtime/vm/flow_graph_compiler_mips.cc
+++ b/runtime/vm/flow_graph_compiler_mips.cc
@@ -905,6 +905,11 @@
// Copy or initialize optional named arguments.
Label all_arguments_processed;
+#ifdef DEBUG
+ const bool check_correct_named_args = true;
+#else
+ const bool check_correct_named_args = function.IsClosureFunction();
+#endif
if (num_opt_named_params > 0) {
__ Comment("There are named parameters");
// Start by alphabetically sorting the names of the optional parameters.
@@ -974,10 +979,13 @@
}
delete[] opt_param;
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);
+ if (check_correct_named_args) {
+ // Check that T0 now points to the null terminator in the arguments
+ // descriptor.
+ __ lw(T3, Address(T0));
+ __ BranchEqual(T3, reinterpret_cast<int32_t>(Object::null()),
+ &all_arguments_processed);
+ }
} else {
ASSERT(num_opt_pos_params > 0);
__ Comment("There are optional positional parameters");
@@ -1003,26 +1011,29 @@
__ sw(T3, Address(FP, computed_param_pos * kWordSize));
__ Bind(&next_parameter);
}
- __ lw(T1, FieldAddress(S4, ArgumentsDescriptor::count_offset()));
- __ SmiUntag(T1);
- // Check that T2 equals T1, i.e. no named arguments passed.
- __ beq(T2, T1, &all_arguments_processed);
+ if (check_correct_named_args) {
+ __ lw(T1, FieldAddress(S4, ArgumentsDescriptor::count_offset()));
+ __ SmiUntag(T1);
+ // Check that T2 equals T1, i.e. no named arguments passed.
+ __ beq(T2, T1, &all_arguments_processed);
+ }
}
__ Bind(&wrong_num_arguments);
- // Invoke noSuchMethod function passing the original name of the function.
- // If the function is a closure function, use "call" as the original name.
- const String& name = String::Handle(
- function.IsClosureFunction() ? Symbols::Call().raw() : function.name());
- const int kNumArgsChecked = 1;
- const ICData& ic_data = ICData::ZoneHandle(
- ICData::New(function, name, Object::null_array(),
- Isolate::kNoDeoptId, kNumArgsChecked));
- __ LoadObject(S5, ic_data);
- __ LeaveDartFrame(); // The arguments are still on the stack.
- __ Branch(&StubCode::CallNoSuchMethodFunctionLabel());
- // The noSuchMethod call may return to the caller, but not here.
- __ break_(0);
+ if (function.IsClosureFunction()) {
+ // Invoke noSuchMethod function passing "call" as the original name.
+ const int kNumArgsChecked = 1;
+ const ICData& ic_data = ICData::ZoneHandle(
+ ICData::New(function, Symbols::Call(), Object::null_array(),
+ Isolate::kNoDeoptId, kNumArgsChecked));
+ __ LoadObject(S5, ic_data);
+ __ LeaveDartFrame(); // The arguments are still on the stack.
+ __ Branch(&StubCode::CallNoSuchMethodFunctionLabel());
+ // The noSuchMethod call may return to the caller, but not here.
+ __ break_(0);
+ } else if (check_correct_named_args) {
+ __ Stop("Wrong arguments");
+ }
__ Bind(&all_arguments_processed);
// Nullify originally passed arguments only after they have been copied and
diff --git a/runtime/vm/flow_graph_compiler_x64.cc b/runtime/vm/flow_graph_compiler_x64.cc
index 4375d7f..b2f730c 100644
--- a/runtime/vm/flow_graph_compiler_x64.cc
+++ b/runtime/vm/flow_graph_compiler_x64.cc
@@ -893,6 +893,11 @@
const Immediate& raw_null =
Immediate(reinterpret_cast<intptr_t>(Object::null()));
Label all_arguments_processed;
+#ifdef DEBUG
+ const bool check_correct_named_args = true;
+#else
+ const bool check_correct_named_args = function.IsClosureFunction();
+#endif
if (num_opt_named_params > 0) {
// Start by alphabetically sorting the names of the optional parameters.
LocalVariable** opt_param = new LocalVariable*[num_opt_named_params];
@@ -960,9 +965,12 @@
}
delete[] opt_param;
delete[] opt_param_position;
- // Check that RDI now points to the null terminator in the array descriptor.
- __ cmpq(Address(RDI, 0), raw_null);
- __ j(EQUAL, &all_arguments_processed, Assembler::kNearJump);
+ if (check_correct_named_args) {
+ // Check that RDI now points to the null terminator in the arguments
+ // descriptor.
+ __ cmpq(Address(RDI, 0), raw_null);
+ __ j(EQUAL, &all_arguments_processed, Assembler::kNearJump);
+ }
} else {
ASSERT(num_opt_pos_params > 0);
__ movq(RCX,
@@ -989,27 +997,30 @@
__ movq(param_addr, RAX);
__ Bind(&next_parameter);
}
- __ movq(RBX, FieldAddress(R10, ArgumentsDescriptor::count_offset()));
- __ SmiUntag(RBX);
- // Check that RCX equals RBX, i.e. no named arguments passed.
- __ cmpq(RCX, RBX);
- __ j(EQUAL, &all_arguments_processed, Assembler::kNearJump);
+ if (check_correct_named_args) {
+ __ movq(RBX, FieldAddress(R10, ArgumentsDescriptor::count_offset()));
+ __ SmiUntag(RBX);
+ // Check that RCX equals RBX, i.e. no named arguments passed.
+ __ cmpq(RCX, RBX);
+ __ j(EQUAL, &all_arguments_processed, Assembler::kNearJump);
+ }
}
__ Bind(&wrong_num_arguments);
- // Invoke noSuchMethod function passing the original name of the function.
- // If the function is a closure function, use "call" as the original name.
- const String& name = String::Handle(
- function.IsClosureFunction() ? Symbols::Call().raw() : function.name());
- const int kNumArgsChecked = 1;
- const ICData& ic_data = ICData::ZoneHandle(
- ICData::New(function, name, Object::null_array(),
- Isolate::kNoDeoptId, kNumArgsChecked));
- __ LoadObject(RBX, ic_data);
- __ LeaveFrame(); // The arguments are still on the stack.
- __ jmp(&StubCode::CallNoSuchMethodFunctionLabel());
- // The noSuchMethod call may return to the caller, but not here.
- __ int3();
+ if (function.IsClosureFunction()) {
+ // Invoke noSuchMethod function passing "call" as the original name.
+ const int kNumArgsChecked = 1;
+ const ICData& ic_data = ICData::ZoneHandle(
+ ICData::New(function, Symbols::Call(), Object::null_array(),
+ Isolate::kNoDeoptId, kNumArgsChecked));
+ __ LoadObject(RBX, ic_data);
+ __ LeaveFrame(); // The arguments are still on the stack.
+ __ jmp(&StubCode::CallNoSuchMethodFunctionLabel());
+ // The noSuchMethod call may return to the caller, but not here.
+ __ int3();
+ } else if (check_correct_named_args) {
+ __ Stop("Wrong arguments");
+ }
__ Bind(&all_arguments_processed);
// Nullify originally passed arguments only after they have been copied and
diff --git a/runtime/vm/flow_graph_inliner.cc b/runtime/vm/flow_graph_inliner.cc
index 4c51acf..b22eda0 100644
--- a/runtime/vm/flow_graph_inliner.cc
+++ b/runtime/vm/flow_graph_inliner.cc
@@ -370,7 +370,8 @@
FlowGraph* caller_graph() const { return caller_graph_; }
// Inlining heuristics based on Cooper et al. 2008.
- bool ShouldWeInline(intptr_t instr_count,
+ bool ShouldWeInline(const Function& callee,
+ intptr_t instr_count,
intptr_t call_site_count,
intptr_t const_arg_count) {
if (inlined_size_ > FLAG_inlining_caller_size_threshold) {
@@ -387,6 +388,9 @@
(instr_count <= FLAG_inlining_constant_arguments_size_threshold)) {
return true;
}
+ if (MethodRecognizer::AlwaysInline(callee)) {
+ return true;
+ }
return false;
}
@@ -462,7 +466,8 @@
GrowableArray<Value*>* arguments = call_data->arguments;
const intptr_t constant_arguments = CountConstants(*arguments);
- if (!ShouldWeInline(function.optimized_instruction_count(),
+ if (!ShouldWeInline(function,
+ function.optimized_instruction_count(),
function.optimized_call_site_count(),
constant_arguments)) {
TRACE_INLINING(OS::Print(" Bailout: early heuristics with "
@@ -608,7 +613,7 @@
function.set_optimized_call_site_count(call_site_count);
// Use heuristics do decide if this call should be inlined.
- if (!ShouldWeInline(size, call_site_count, constants_count)) {
+ if (!ShouldWeInline(function, size, call_site_count, constants_count)) {
// If size is larger than all thresholds, don't consider it again.
if ((size > FLAG_inlining_size_threshold) &&
(call_site_count > FLAG_inlining_callee_call_sites_threshold) &&
@@ -750,8 +755,9 @@
continue;
}
}
- if ((call_info[call_idx].ratio * 100) < FLAG_inlining_hotness) {
- const Function& target = call->function();
+ const Function& target = call->function();
+ if (!MethodRecognizer::AlwaysInline(target) &&
+ (call_info[call_idx].ratio * 100) < FLAG_inlining_hotness) {
TRACE_INLINING(OS::Print(
" => %s (deopt count %d)\n Bailout: cold %f\n",
target.ToCString(),
@@ -812,7 +818,8 @@
const ICData& ic_data = call->ic_data();
const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(0));
- if ((call_info[call_idx].ratio * 100) < FLAG_inlining_hotness) {
+ if (!MethodRecognizer::AlwaysInline(target) &&
+ (call_info[call_idx].ratio * 100) < FLAG_inlining_hotness) {
TRACE_INLINING(OS::Print(
" => %s (deopt count %d)\n Bailout: cold %f\n",
target.ToCString(),
diff --git a/runtime/vm/flow_graph_optimizer.cc b/runtime/vm/flow_graph_optimizer.cc
index 1665cb9..a350e07 100644
--- a/runtime/vm/flow_graph_optimizer.cc
+++ b/runtime/vm/flow_graph_optimizer.cc
@@ -6,6 +6,7 @@
#include "vm/bit_vector.h"
#include "vm/cha.h"
+#include "vm/dart_entry.h"
#include "vm/flow_graph_builder.h"
#include "vm/flow_graph_compiler.h"
#include "vm/hash_map.h"
@@ -102,16 +103,16 @@
return false;
}
if (class_ids[0] != kDynamicCid) {
- const intptr_t num_named_arguments = call->argument_names().IsNull() ?
- 0 : call->argument_names().Length();
+ ArgumentsDescriptor args_desc(
+ Array::Handle(ArgumentsDescriptor::New(call->ArgumentCount(),
+ call->argument_names())));
const Class& receiver_class = Class::Handle(
Isolate::Current()->class_table()->At(class_ids[0]));
- Function& function = Function::Handle();
- function = Resolver::ResolveDynamicForReceiverClass(
- receiver_class,
- call->function_name(),
- call->ArgumentCount(),
- num_named_arguments);
+ const Function& function = Function::Handle(
+ Resolver::ResolveDynamicForReceiverClass(
+ receiver_class,
+ call->function_name(),
+ args_desc));
if (function.IsNull()) {
return false;
}
@@ -229,9 +230,9 @@
// Replace Mint op with Smi op.
BinarySmiOpInstr* smi_op = new BinarySmiOpInstr(
Token::kBIT_AND,
- bit_and_instr->AsBinaryMintOp()->instance_call(),
new Value(left_instr),
- new Value(right_instr));
+ new Value(right_instr),
+ bit_and_instr->deopt_id());
bit_and_instr->ReplaceWith(smi_op, current_iterator());
}
}
@@ -733,7 +734,7 @@
InsertBefore(call,
new CheckArrayBoundInstr(new Value(length),
new Value(*index),
- call),
+ call->deopt_id()),
call->env(),
Definition::kEffect);
@@ -1105,25 +1106,25 @@
InsertBefore(call,
new CheckEitherNonSmiInstr(new Value(left),
new Value(right),
- call),
+ call->deopt_id()),
call->env(),
Definition::kEffect);
BinaryDoubleOpInstr* double_bin_op =
new BinaryDoubleOpInstr(op_kind, new Value(left), new Value(right),
- call);
+ call->deopt_id());
ReplaceCall(call, double_bin_op);
} else if (operands_type == kMintCid) {
if (!FlowGraphCompiler::SupportsUnboxedMints()) return false;
if ((op_kind == Token::kSHR) || (op_kind == Token::kSHL)) {
ShiftMintOpInstr* shift_op =
new ShiftMintOpInstr(op_kind, new Value(left), new Value(right),
- call);
+ call->deopt_id());
ReplaceCall(call, shift_op);
} else {
BinaryMintOpInstr* bin_op =
new BinaryMintOpInstr(op_kind, new Value(left), new Value(right),
- call);
+ call->deopt_id());
ReplaceCall(call, bin_op);
}
} else if (operands_type == kFloat32x4Cid) {
@@ -1184,9 +1185,10 @@
ConstantInstr* constant =
flow_graph()->GetConstant(Smi::Handle(Smi::New(value - 1)));
BinarySmiOpInstr* bin_op =
- new BinarySmiOpInstr(Token::kBIT_AND, call,
+ new BinarySmiOpInstr(Token::kBIT_AND,
new Value(left),
- new Value(constant));
+ new Value(constant),
+ call->deopt_id());
ReplaceCall(call, bin_op);
} else {
ASSERT(operands_type == kSmiCid);
@@ -1202,7 +1204,8 @@
right = temp;
}
BinarySmiOpInstr* bin_op =
- new BinarySmiOpInstr(op_kind, call, new Value(left), new Value(right));
+ new BinarySmiOpInstr(op_kind, new Value(left), new Value(right),
+ call->deopt_id());
ReplaceCall(call, bin_op);
}
return true;
@@ -1219,11 +1222,12 @@
new CheckSmiInstr(new Value(input), call->deopt_id()),
call->env(),
Definition::kEffect);
- unary_op = new UnarySmiOpInstr(op_kind, call, new Value(input));
+ unary_op = new UnarySmiOpInstr(op_kind, new Value(input), call->deopt_id());
} else if ((op_kind == Token::kBIT_NOT) &&
HasOnlySmiOrMint(*call->ic_data()) &&
FlowGraphCompiler::SupportsUnboxedMints()) {
- unary_op = new UnaryMintOpInstr(op_kind, new Value(input), call);
+ unary_op = new UnaryMintOpInstr(
+ op_kind, new Value(input), call->deopt_id());
} else if (HasOnlyOneDouble(*call->ic_data()) &&
(op_kind == Token::kNEGATE)) {
AddReceiverCheck(call);
@@ -1232,7 +1236,7 @@
unary_op = new BinaryDoubleOpInstr(Token::kMUL,
new Value(input),
new Value(minus_one),
- call);
+ call->deopt_id());
}
if (unary_op == NULL) return false;
@@ -1614,7 +1618,7 @@
InsertBefore(call,
new CheckArrayBoundInstr(new Value(length),
new Value(index),
- call),
+ call->deopt_id()),
call->env(),
Definition::kEffect);
}
@@ -1769,7 +1773,7 @@
d2i_instr = new DoubleToIntegerInstr(new Value(input), call);
} else {
// Optimistically assume result fits into Smi.
- d2i_instr = new DoubleToSmiInstr(new Value(input), call);
+ d2i_instr = new DoubleToSmiInstr(new Value(input), call->deopt_id());
}
ReplaceCall(call, d2i_instr);
return true;
@@ -1788,8 +1792,7 @@
AddReceiverCheck(call);
DoubleToDoubleInstr* d2d_instr =
new DoubleToDoubleInstr(new Value(call->ArgumentAt(0)),
- call,
- recognized_kind);
+ recognized_kind, call->deopt_id());
ReplaceCall(call, d2d_instr);
}
return true;
@@ -2238,16 +2241,16 @@
flow_graph()->GetConstant(Smi::Handle(Smi::New(element_size)));
BinarySmiOpInstr* len_in_bytes =
new BinarySmiOpInstr(Token::kMUL,
- call,
new Value(length),
- new Value(bytes_per_element));
+ new Value(bytes_per_element),
+ call->deopt_id());
InsertBefore(call, len_in_bytes, call->env(), Definition::kValue);
// Check byte_index < len_in_bytes.
InsertBefore(call,
new CheckArrayBoundInstr(new Value(len_in_bytes),
new Value(byte_index),
- call),
+ call->deopt_id()),
call->env(),
Definition::kEffect);
@@ -2656,12 +2659,14 @@
Isolate::Current()->class_table()->At(receiver_cid));
// Resolve equality operator.
+ const intptr_t kNumArgs = 2;
+ ArgumentsDescriptor args_desc(
+ Array::Handle(ArgumentsDescriptor::New(kNumArgs)));
const Function& function = Function::Handle(
Resolver::ResolveDynamicForReceiverClass(
receiver_class,
Symbols::EqualOperator(),
- 2,
- 0));
+ args_desc));
if (function.IsNull()) {
return false;
diff --git a/runtime/vm/flow_graph_type_propagator.cc b/runtime/vm/flow_graph_type_propagator.cc
index 3006a6a..53bfab2 100644
--- a/runtime/vm/flow_graph_type_propagator.cc
+++ b/runtime/vm/flow_graph_type_propagator.cc
@@ -412,8 +412,8 @@
if (ToAbstractType()->IsMoreSpecificThan(*other->ToAbstractType(),
&malformed_error)) {
type_ = other->ToAbstractType();
- } else if (ToAbstractType()->IsMoreSpecificThan(*ToAbstractType(),
- &malformed_error)) {
+ } else if (other->ToAbstractType()->IsMoreSpecificThan(*ToAbstractType(),
+ &malformed_error)) {
// Nothing to do.
} else {
// Can't unify.
diff --git a/runtime/vm/gc_marker.cc b/runtime/vm/gc_marker.cc
index b7ae253..c5b5dc8 100644
--- a/runtime/vm/gc_marker.cc
+++ b/runtime/vm/gc_marker.cc
@@ -14,6 +14,7 @@
#include "vm/raw_object.h"
#include "vm/stack_frame.h"
#include "vm/visitor.h"
+#include "vm/object_id_ring.h"
namespace dart {
@@ -399,6 +400,33 @@
}
+class ObjectIdRingClearPointerVisitor : public ObjectPointerVisitor {
+ public:
+ explicit ObjectIdRingClearPointerVisitor(Isolate* isolate) :
+ ObjectPointerVisitor(isolate) {}
+
+
+ void VisitPointers(RawObject** first, RawObject** last) {
+ for (RawObject** current = first; current <= last; current++) {
+ RawObject* raw_obj = *current;
+ ASSERT(raw_obj->IsHeapObject());
+ if (raw_obj->IsOldObject() && !raw_obj->IsMarked()) {
+ // Object has become garbage. Replace it will null.
+ *current = Object::null();
+ }
+ }
+ }
+};
+
+
+void GCMarker::ProcessObjectIdTable(Isolate* isolate) {
+ ObjectIdRingClearPointerVisitor visitor(isolate);
+ ObjectIdRing* ring = isolate->object_id_ring();
+ ASSERT(ring != NULL);
+ ring->VisitPointers(&visitor);
+}
+
+
void GCMarker::MarkObjects(Isolate* isolate,
PageSpace* page_space,
bool invoke_api_callbacks) {
@@ -412,6 +440,9 @@
IterateWeakRoots(isolate, &mark_weak, invoke_api_callbacks);
mark.Finalize();
ProcessWeakTables(page_space);
+ ProcessObjectIdTable(isolate);
+
+
Epilogue(isolate, invoke_api_callbacks);
}
diff --git a/runtime/vm/gc_marker.h b/runtime/vm/gc_marker.h
index 36c899c..422d062 100644
--- a/runtime/vm/gc_marker.h
+++ b/runtime/vm/gc_marker.h
@@ -42,6 +42,8 @@
void DrainMarkingStack(Isolate* isolate, MarkingVisitor* visitor);
void ProcessWeakProperty(RawWeakProperty* raw_weak, MarkingVisitor* visitor);
void ProcessWeakTables(PageSpace* page_space);
+ void ProcessObjectIdTable(Isolate* isolate);
+
Heap* heap_;
diff --git a/runtime/vm/heap.cc b/runtime/vm/heap.cc
index 59691e8..851f6a6 100644
--- a/runtime/vm/heap.cc
+++ b/runtime/vm/heap.cc
@@ -36,7 +36,7 @@
"old gen heap size in MB,"
"e.g: --old_gen_heap_size=1024 allocates a 1024MB old gen heap");
- Heap::Heap() : read_only_(false), gc_in_progress_(false) {
+Heap::Heap() : read_only_(false), gc_in_progress_(false) {
for (int sel = 0;
sel < kNumWeakSelectors;
sel++) {
diff --git a/runtime/vm/intermediate_language.cc b/runtime/vm/intermediate_language.cc
index b04cc21..84e3fdc 100644
--- a/runtime/vm/intermediate_language.cc
+++ b/runtime/vm/intermediate_language.cc
@@ -336,7 +336,8 @@
// List of libraries where methods can be recognized.
return (library.raw() == Library::CoreLibrary())
|| (library.raw() == Library::MathLibrary())
- || (library.raw() == Library::TypedDataLibrary());
+ || (library.raw() == Library::TypedDataLibrary())
+ || (library.raw() == Library::CollectionDevLibrary());
}
@@ -363,6 +364,28 @@
}
+bool MethodRecognizer::AlwaysInline(const Function& function) {
+ const Class& function_class = Class::Handle(function.Owner());
+ const Library& lib = Library::Handle(function_class.library());
+ if (!IsRecognizedLibrary(lib)) {
+ return false;
+ }
+
+ const String& function_name = String::Handle(function.name());
+ const String& class_name = String::Handle(function_class.Name());
+
+#define RECOGNIZE_FUNCTION(test_class_name, test_function_name, enum_name, fp) \
+ if (CompareNames(lib, #test_function_name, function_name) && \
+ CompareNames(lib, #test_class_name, class_name)) { \
+ ASSERT(function.CheckSourceFingerprint(fp)); \
+ return true; \
+ }
+INLINE_WHITE_LIST(RECOGNIZE_FUNCTION)
+#undef RECOGNIZE_FUNCTION
+ return false;
+}
+
+
const char* MethodRecognizer::KindToCString(Kind kind) {
#define KIND_TO_STRING(class_name, function_name, enum_name, fp) \
if (kind == k##enum_name) return #enum_name;
diff --git a/runtime/vm/intermediate_language.h b/runtime/vm/intermediate_language.h
index df01ffb..49d2a54 100644
--- a/runtime/vm/intermediate_language.h
+++ b/runtime/vm/intermediate_language.h
@@ -121,6 +121,11 @@
V(_Uint32x4, _toFloat32x4, Uint32x4ToUint32x4, 912844231) \
+// A list of core function that should always be inlined.
+#define INLINE_WHITE_LIST(V) \
+ V(ListIterator, moveNext, ListIteratorMoveNext, 203118278) \
+ V(_GrowableObjectArray, get:iterator, GrowableArrayIterator, 810824939)
+
// Class that recognizes the name and owner of a function and returns the
// corresponding enum. See RECOGNIZED_LIST above for list of recognizable
// functions.
@@ -134,6 +139,7 @@
};
static Kind RecognizeKind(const Function& function);
+ static bool AlwaysInline(const Function& function);
static const char* KindToCString(Kind kind);
};
@@ -4324,10 +4330,11 @@
public:
CheckEitherNonSmiInstr(Value* left,
Value* right,
- InstanceCallInstr* instance_call) {
+ intptr_t deopt_id) {
SetInputAt(0, left);
SetInputAt(1, right);
- deopt_id_ = instance_call->deopt_id();
+ // Override generated deopt-id.
+ deopt_id_ = deopt_id;
}
Value* left() const { return inputs_[0]; }
@@ -4654,11 +4661,12 @@
BinaryDoubleOpInstr(Token::Kind op_kind,
Value* left,
Value* right,
- InstanceCallInstr* instance_call)
+ intptr_t deopt_id)
: op_kind_(op_kind) {
SetInputAt(0, left);
SetInputAt(1, right);
- deopt_id_ = instance_call->deopt_id();
+ // Overrided generated deopt_id.
+ deopt_id_ = deopt_id;
}
Value* left() const { return inputs_[0]; }
@@ -5672,12 +5680,12 @@
BinaryMintOpInstr(Token::Kind op_kind,
Value* left,
Value* right,
- InstanceCallInstr* instance_call)
- : op_kind_(op_kind),
- instance_call_(instance_call) {
+ intptr_t deopt_id)
+ : op_kind_(op_kind) {
SetInputAt(0, left);
SetInputAt(1, right);
- deopt_id_ = instance_call->deopt_id();
+ // Override generated deopt-id.
+ deopt_id_ = deopt_id;
}
Value* left() const { return inputs_[0]; }
@@ -5685,8 +5693,6 @@
Token::Kind op_kind() const { return op_kind_; }
- InstanceCallInstr* instance_call() const { return instance_call_; }
-
virtual void PrintOperandsTo(BufferFormatter* f) const;
virtual bool CanDeoptimize() const {
@@ -5725,7 +5731,6 @@
private:
const Token::Kind op_kind_;
- InstanceCallInstr* instance_call_;
DISALLOW_COPY_AND_ASSIGN(BinaryMintOpInstr);
};
@@ -5736,12 +5741,13 @@
ShiftMintOpInstr(Token::Kind op_kind,
Value* left,
Value* right,
- InstanceCallInstr* instance_call)
+ intptr_t deopt_id)
: op_kind_(op_kind) {
ASSERT(op_kind == Token::kSHR || op_kind == Token::kSHL);
SetInputAt(0, left);
SetInputAt(1, right);
- deopt_id_ = instance_call->deopt_id();
+ // Override generated deopt-id.
+ deopt_id_ = deopt_id;
}
Value* left() const { return inputs_[0]; }
@@ -5790,13 +5796,12 @@
class UnaryMintOpInstr : public TemplateDefinition<1> {
public:
- UnaryMintOpInstr(Token::Kind op_kind,
- Value* value,
- InstanceCallInstr* instance_call)
+ UnaryMintOpInstr(Token::Kind op_kind, Value* value, intptr_t deopt_id)
: op_kind_(op_kind) {
ASSERT(op_kind == Token::kBIT_NOT);
SetInputAt(0, value);
- deopt_id_ = instance_call->deopt_id();
+ // Override generated deopt-id.
+ deopt_id_ = deopt_id;
}
Value* value() const { return inputs_[0]; }
@@ -5844,16 +5849,16 @@
class BinarySmiOpInstr : public TemplateDefinition<2> {
public:
BinarySmiOpInstr(Token::Kind op_kind,
- InstanceCallInstr* instance_call,
Value* left,
- Value* right)
+ Value* right,
+ intptr_t deopt_id)
: op_kind_(op_kind),
- instance_call_(instance_call),
overflow_(true),
is_truncating_(false) {
SetInputAt(0, left);
SetInputAt(1, right);
- deopt_id_ = instance_call->deopt_id();
+ // Override generated deopt-id.
+ deopt_id_ = deopt_id;
}
Value* left() const { return inputs_[0]; }
@@ -5861,10 +5866,6 @@
Token::Kind op_kind() const { return op_kind_; }
- InstanceCallInstr* instance_call() const { return instance_call_; }
-
- const ICData* ic_data() const { return instance_call()->ic_data(); }
-
void set_overflow(bool overflow) { overflow_ = overflow; }
void set_is_truncating(bool value) { is_truncating_ = value; }
@@ -5896,7 +5897,6 @@
private:
const Token::Kind op_kind_;
- InstanceCallInstr* instance_call_;
bool overflow_;
bool is_truncating_;
@@ -5908,12 +5908,13 @@
class UnarySmiOpInstr : public TemplateDefinition<1> {
public:
UnarySmiOpInstr(Token::Kind op_kind,
- InstanceCallInstr* instance_call,
- Value* value)
+ Value* value,
+ intptr_t deopt_id)
: op_kind_(op_kind) {
ASSERT((op_kind == Token::kNEGATE) || (op_kind == Token::kBIT_NOT));
SetInputAt(0, value);
- deopt_id_ = instance_call->deopt_id();
+ // Override generated deopt-id.
+ deopt_id_ = deopt_id;
}
Value* value() const { return inputs_[0]; }
@@ -6035,9 +6036,10 @@
// and creates a Smi.
class DoubleToSmiInstr : public TemplateDefinition<1> {
public:
- DoubleToSmiInstr(Value* value, InstanceCallInstr* instance_call) {
+ DoubleToSmiInstr(Value* value, intptr_t deopt_id) {
SetInputAt(0, value);
- deopt_id_ = instance_call->deopt_id();
+ // Override generated deopt-id.
+ deopt_id_ = deopt_id;
}
Value* value() const { return inputs_[0]; }
@@ -6066,11 +6068,12 @@
class DoubleToDoubleInstr : public TemplateDefinition<1> {
public:
DoubleToDoubleInstr(Value* value,
- InstanceCallInstr* instance_call,
- MethodRecognizer::Kind recognized_kind)
+ MethodRecognizer::Kind recognized_kind,
+ intptr_t deopt_id)
: recognized_kind_(recognized_kind) {
SetInputAt(0, value);
- deopt_id_ = instance_call->deopt_id();
+ // Override generated deopt-id.
+ deopt_id_ = deopt_id;
}
Value* value() const { return inputs_[0]; }
@@ -6252,12 +6255,11 @@
class CheckArrayBoundInstr : public TemplateInstruction<2> {
public:
- CheckArrayBoundInstr(Value* length,
- Value* index,
- InstanceCallInstr* instance_call) {
+ CheckArrayBoundInstr(Value* length, Value* index, intptr_t deopt_id) {
SetInputAt(kLengthPos, length);
SetInputAt(kIndexPos, index);
- deopt_id_ = instance_call->deopt_id();
+ // Override generated deopt-id.
+ deopt_id_ = deopt_id;
}
Value* length() const { return inputs_[kLengthPos]; }
diff --git a/runtime/vm/intermediate_language_arm.cc b/runtime/vm/intermediate_language_arm.cc
index d6f1736..ae18cca 100644
--- a/runtime/vm/intermediate_language_arm.cc
+++ b/runtime/vm/intermediate_language_arm.cc
@@ -172,7 +172,7 @@
void LoadLocalInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
Register result = locs()->out().reg();
- __ LoadFromOffset(kLoadWord, result, FP, local().index() * kWordSize);
+ __ LoadFromOffset(kWord, result, FP, local().index() * kWordSize);
}
@@ -1044,7 +1044,7 @@
void LoadUntaggedInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
Register object = locs()->in(0).reg();
Register result = locs()->out().reg();
- __ LoadFromOffset(kLoadWord, result, object, offset() - kHeapObjectTag);
+ __ LoadFromOffset(kWord, result, object, offset() - kHeapObjectTag);
}
@@ -1701,7 +1701,7 @@
void LoadStaticFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
Register field = locs()->in(0).reg();
Register result = locs()->out().reg();
- __ LoadFromOffset(kLoadWord, result,
+ __ LoadFromOffset(kWord, result,
field, Field::value_offset() - kHeapObjectTag);
}
@@ -1809,7 +1809,7 @@
Register instance_reg = locs()->in(0).reg();
Register result_reg = locs()->out().reg();
- __ LoadFromOffset(kLoadWord, result_reg,
+ __ LoadFromOffset(kWord, result_reg,
instance_reg, offset_in_bytes() - kHeapObjectTag);
}
@@ -2044,9 +2044,9 @@
ASSERT(!exception_var().is_captured());
ASSERT(!stacktrace_var().is_captured());
- __ StoreToOffset(kStoreWord, kExceptionObjectReg,
+ __ StoreToOffset(kWord, kExceptionObjectReg,
FP, exception_var().index() * kWordSize);
- __ StoreToOffset(kStoreWord, kStackTraceObjectReg,
+ __ StoreToOffset(kWord, kStackTraceObjectReg,
FP, stacktrace_var().index() * kWordSize);
// Restore the pool pointer.
@@ -3200,7 +3200,7 @@
}
// Load receiver into R0.
- __ LoadFromOffset(kLoadWord, R0, SP,
+ __ LoadFromOffset(kWord, R0, SP,
(instance_call()->ArgumentCount() - 1) * kWordSize);
LoadValueCid(compiler, R2, R0,
diff --git a/runtime/vm/intrinsifier_arm.cc b/runtime/vm/intrinsifier_arm.cc
index 1da04b9..4faae9f 100644
--- a/runtime/vm/intrinsifier_arm.cc
+++ b/runtime/vm/intrinsifier_arm.cc
@@ -1396,13 +1396,13 @@
FlowGraphCompiler::DataOffsetFor(kTypedDataUint32ArrayCid);
__ LoadImmediate(R0, a_int32_value);
- __ LoadFromOffset(kLoadWord, R2, R1, disp_0 - kHeapObjectTag);
- __ LoadFromOffset(kLoadWord, R3, R1, disp_1 - kHeapObjectTag);
+ __ LoadFromOffset(kWord, R2, R1, disp_0 - kHeapObjectTag);
+ __ LoadFromOffset(kWord, R3, R1, disp_1 - kHeapObjectTag);
__ mov(R6, ShifterOperand(0)); // Zero extend unsigned _state[kSTATE_HI].
// Unsigned 32-bit multiply and 64-bit accumulate into R6:R3.
__ umlal(R3, R6, R0, R2); // R6:R3 <- R6:R3 + R0 * R2.
- __ StoreToOffset(kStoreWord, R3, R1, disp_0 - kHeapObjectTag);
- __ StoreToOffset(kStoreWord, R6, R1, disp_1 - kHeapObjectTag);
+ __ StoreToOffset(kWord, R3, R1, disp_0 - kHeapObjectTag);
+ __ StoreToOffset(kWord, R6, R1, disp_1 - kHeapObjectTag);
__ Ret();
return true;
}
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
index 76e6235..5c5f977 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -26,6 +26,7 @@
#include "vm/thread.h"
#include "vm/timer.h"
#include "vm/visitor.h"
+#include "vm/object_id_ring.h"
namespace dart {
@@ -415,6 +416,7 @@
stacktrace_(NULL),
stack_frame_index_(-1),
object_histogram_(NULL),
+ object_id_ring_(NULL),
REUSABLE_HANDLE_LIST(REUSABLE_HANDLE_INITIALIZERS)
reusable_handles_() {
if (FLAG_print_object_histogram && (Dart::vm_isolate() != NULL)) {
diff --git a/runtime/vm/isolate.h b/runtime/vm/isolate.h
index 27ad1ea..b8eb6c2 100644
--- a/runtime/vm/isolate.h
+++ b/runtime/vm/isolate.h
@@ -55,6 +55,7 @@
class TypeArguments;
class TypeParameter;
class ObjectHistogram;
+class ObjectIdRing;
// Used by the deoptimization infrastructure to defer allocation of unboxed
@@ -533,6 +534,13 @@
}
intptr_t deopt_frame_copy_size() const { return deopt_frame_copy_size_; }
+ void set_object_id_ring(ObjectIdRing* ring) {
+ object_id_ring_ = ring;
+ }
+ ObjectIdRing* object_id_ring() {
+ return object_id_ring_;
+ }
+
void PrepareForDeferredMaterialization(intptr_t count) {
if (count > 0) {
deferred_objects_ = new DeferredObject*[count];
@@ -686,6 +694,9 @@
intptr_t stack_frame_index_;
ObjectHistogram* object_histogram_;
+ // Ring buffer of objects assigned an id.
+ ObjectIdRing* object_id_ring_;
+
// Reusable handles support.
#define REUSABLE_HANDLE_FIELDS(object) \
object* object##_handle_; \
diff --git a/runtime/vm/mirrors_api_impl.cc b/runtime/vm/mirrors_api_impl.cc
index 917d54d..dcc9495 100644
--- a/runtime/vm/mirrors_api_impl.cc
+++ b/runtime/vm/mirrors_api_impl.cc
@@ -261,7 +261,7 @@
// Skip implicit getters and setters.
if (func.kind() == RawFunction::kImplicitGetter ||
func.kind() == RawFunction::kImplicitSetter ||
- func.kind() == RawFunction::kConstImplicitGetter ||
+ func.kind() == RawFunction::kImplicitStaticFinalGetter ||
func.kind() == RawFunction::kMethodExtractor ||
func.kind() == RawFunction::kNoSuchMethodDispatcher) {
continue;
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 6e89a43..a16190e 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -1444,15 +1444,14 @@
const Class& canonical_class = Class::Handle(function.signature_class());
return canonical_class.SignatureType();
}
- // Return the first canonical signature type if already computed.
+ // Return the first canonical signature type if already computed at class
+ // finalization time. The optimizer may canonicalize instantiated function
+ // types of the same signature class, but these will be added after the
+ // uninstantiated signature class at index 0.
const Array& signature_types = Array::Handle(canonical_types());
// The canonical_types array is initialized to the empty array.
ASSERT(!signature_types.IsNull());
if (signature_types.Length() > 0) {
- // At most one signature type per signature class.
- ASSERT((signature_types.Length() == 1) ||
- ((signature_types.Length() == 2) &&
- (signature_types.At(1) == Type::null())));
Type& signature_type = Type::Handle();
signature_type ^= signature_types.At(0);
ASSERT(!signature_type.IsNull());
@@ -2738,6 +2737,10 @@
ReusableHandleScope reused_handles(isolate);
Array& flds = reused_handles.ArrayHandle();
flds ^= fields();
+ if (flds.IsNull()) {
+ // This can occur, e.g., for Null classes.
+ return Field::null();
+ }
Field& field = reused_handles.FieldHandle();
String& field_name = reused_handles.StringHandle();
intptr_t len = flds.Length();
@@ -4093,8 +4096,8 @@
}
-bool Function::AreValidArgumentCounts(int num_arguments,
- int num_named_arguments,
+bool Function::AreValidArgumentCounts(intptr_t num_arguments,
+ intptr_t num_named_arguments,
String* error_message) const {
if (num_named_arguments > NumOptionalNamedParameters()) {
if (error_message != NULL) {
@@ -4102,7 +4105,7 @@
char message_buffer[kMessageBufferSize];
OS::SNPrint(message_buffer,
kMessageBufferSize,
- "%d named passed, at most %"Pd" expected",
+ "%"Pd" named passed, at most %"Pd" expected",
num_named_arguments,
NumOptionalNamedParameters());
*error_message = String::New(message_buffer);
@@ -4150,10 +4153,10 @@
}
-bool Function::AreValidArguments(int num_arguments,
+bool Function::AreValidArguments(intptr_t num_arguments,
const Array& argument_names,
String* error_message) const {
- const int num_named_arguments =
+ const intptr_t num_named_arguments =
argument_names.IsNull() ? 0 : argument_names.Length();
if (!AreValidArgumentCounts(num_arguments,
num_named_arguments,
@@ -4164,13 +4167,61 @@
Isolate* isolate = Isolate::Current();
String& argument_name = String::Handle(isolate);
String& parameter_name = String::Handle(isolate);
- for (int i = 0; i < num_named_arguments; i++) {
+ for (intptr_t i = 0; i < num_named_arguments; i++) {
argument_name ^= argument_names.At(i);
ASSERT(argument_name.IsSymbol());
bool found = false;
- const int num_positional_args = num_arguments - num_named_arguments;
+ const intptr_t num_positional_args = num_arguments - num_named_arguments;
+ const intptr_t num_parameters = NumParameters();
+ for (intptr_t j = num_positional_args;
+ !found && (j < num_parameters);
+ j++) {
+ parameter_name = ParameterNameAt(j);
+ ASSERT(argument_name.IsSymbol());
+ if (argument_name.Equals(parameter_name)) {
+ found = true;
+ }
+ }
+ if (!found) {
+ if (error_message != NULL) {
+ const intptr_t kMessageBufferSize = 64;
+ char message_buffer[kMessageBufferSize];
+ OS::SNPrint(message_buffer,
+ kMessageBufferSize,
+ "no optional formal parameter named '%s'",
+ argument_name.ToCString());
+ *error_message = String::New(message_buffer);
+ }
+ return false;
+ }
+ }
+ return true;
+}
+
+
+bool Function::AreValidArguments(const ArgumentsDescriptor& args_desc,
+ String* error_message) const {
+ const intptr_t num_arguments = args_desc.Count();
+ const intptr_t num_named_arguments = args_desc.NamedCount();
+
+ if (!AreValidArgumentCounts(num_arguments,
+ num_named_arguments,
+ error_message)) {
+ return false;
+ }
+ // Verify that all argument names are valid parameter names.
+ Isolate* isolate = Isolate::Current();
+ String& argument_name = String::Handle(isolate);
+ String& parameter_name = String::Handle(isolate);
+ for (intptr_t i = 0; i < num_named_arguments; i++) {
+ argument_name ^= args_desc.NameAt(i);
+ ASSERT(argument_name.IsSymbol());
+ bool found = false;
+ const intptr_t num_positional_args = num_arguments - num_named_arguments;
const int num_parameters = NumParameters();
- for (int j = num_positional_args; !found && (j < num_parameters); j++) {
+ for (intptr_t j = num_positional_args;
+ !found && (j < num_parameters);
+ j++) {
parameter_name = ParameterNameAt(j);
ASSERT(argument_name.IsSymbol());
if (argument_name.Equals(parameter_name)) {
@@ -4873,8 +4924,8 @@
case RawFunction::kImplicitSetter:
kind_str = " setter";
break;
- case RawFunction::kConstImplicitGetter:
- kind_str = " const-getter";
+ case RawFunction::kImplicitStaticFinalGetter:
+ kind_str = " static-final-getter";
break;
case RawFunction::kMethodExtractor:
kind_str = " method-extractor";
@@ -10504,11 +10555,7 @@
if (type.IsNull()) {
break;
}
- if (!type.IsFinalized()) {
- ASSERT((index == 0) && cls.IsSignatureClass());
- index++;
- continue;
- }
+ ASSERT(type.IsFinalized());
if (this->Equals(type)) {
return type.raw();
}
@@ -10529,6 +10576,30 @@
} else {
canonical_types.SetAt(index, *this);
}
+#ifdef DEBUG
+ if ((index == 0) && cls.IsCanonicalSignatureClass()) {
+ // Verify that the first canonical type is the signature type by checking
+ // that the type argument vector of the canonical type ends with the
+ // uninstantiated type parameters of the signature class.
+ // The signature type is finalized during class finalization, before the
+ // optimizer may canonicalize instantiated function types of the same
+ // signature class.
+ // Although the signature class extends class Instance, the type arguments
+ // of the super class of the owner class of its signature function will be
+ // prepended to the type argument vector during class finalization.
+ const TypeArguments& type_params =
+ TypeArguments::Handle(cls.type_parameters());
+ const intptr_t num_type_params = cls.NumTypeParameters();
+ const intptr_t num_type_args = cls.NumTypeArguments();
+ TypeParameter& type_arg = TypeParameter::Handle();
+ TypeParameter& type_param = TypeParameter::Handle();
+ for (intptr_t i = 0; i < num_type_params; i++) {
+ type_arg ^= type_args.TypeAt(num_type_args - num_type_params + i);
+ type_param ^= type_params.TypeAt(i);
+ ASSERT(type_arg.Equals(type_param));
+ }
+ }
+#endif
ASSERT(IsOld());
SetCanonical();
return this->raw();
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index e298739..fb7f36b 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -27,6 +27,7 @@
CLASS_LIST(DEFINE_FORWARD_DECLARATION)
#undef DEFINE_FORWARD_DECLARATION
class Api;
+class ArgumentsDescriptor;
class Assembler;
class Closure;
class Code;
@@ -688,6 +689,8 @@
// 'F<T, R>(T, [b: B, c: C]) => R', then its signature type is a parameterized
// type with this class as the type class and type parameters 'T' and 'R'
// as its type argument vector.
+ // SignatureType is used as the type of formal parameters representing a
+ // function.
RawType* SignatureType() const;
RawLibrary* library() const { return raw_ptr()->library_; }
@@ -1494,7 +1497,7 @@
return true;
case RawFunction::kClosureFunction:
case RawFunction::kConstructor:
- case RawFunction::kConstImplicitGetter:
+ case RawFunction::kImplicitStaticFinalGetter:
return false;
default:
UNREACHABLE();
@@ -1511,7 +1514,7 @@
case RawFunction::kSetterFunction:
case RawFunction::kImplicitGetter:
case RawFunction::kImplicitSetter:
- case RawFunction::kConstImplicitGetter:
+ case RawFunction::kImplicitStaticFinalGetter:
return true;
case RawFunction::kClosureFunction:
case RawFunction::kConstructor:
@@ -1636,16 +1639,18 @@
// Returns true if the argument counts are valid for calling this function.
// Otherwise, it returns false and the reason (if error_message is not NULL).
- bool AreValidArgumentCounts(int num_arguments,
- int num_named_arguments,
+ bool AreValidArgumentCounts(intptr_t num_arguments,
+ intptr_t num_named_arguments,
String* error_message) const;
// Returns true if the total argument count and the names of optional
// arguments are valid for calling this function.
// Otherwise, it returns false and the reason (if error_message is not NULL).
- bool AreValidArguments(int num_arguments,
+ bool AreValidArguments(intptr_t num_arguments,
const Array& argument_names,
String* error_message) const;
+ bool AreValidArguments(const ArgumentsDescriptor& args_desc,
+ String* error_message) const;
// Fully qualified name uniquely identifying the function under gdb and during
// ast printing. The special ':' character, if present, is replaced by '_'.
diff --git a/runtime/vm/object_id_ring.cc b/runtime/vm/object_id_ring.cc
new file mode 100644
index 0000000..f7199bd
--- /dev/null
+++ b/runtime/vm/object_id_ring.cc
@@ -0,0 +1,164 @@
+// 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 "platform/assert.h"
+#include "vm/dart_api_state.h"
+#include "vm/object_id_ring.h"
+
+namespace dart {
+
+void ObjectIdRing::Init(Isolate* isolate, int32_t capacity) {
+ ObjectIdRing* ring = new ObjectIdRing(isolate, capacity);
+ isolate->set_object_id_ring(ring);
+}
+
+
+ObjectIdRing::~ObjectIdRing() {
+ ASSERT(table_ != NULL);
+ free(table_);
+ table_ = NULL;
+ if (isolate_ != NULL) {
+ isolate_->set_object_id_ring(NULL);
+ isolate_ = NULL;
+ }
+}
+
+
+int32_t ObjectIdRing::GetIdForObject(RawObject* object) {
+ return AllocateNewId(object);
+}
+
+
+RawObject* ObjectIdRing::GetObjectForId(int32_t id) {
+ int32_t index = IndexOfId(id);
+ if (index == kInvalidId) {
+ return Object::null();
+ }
+ ASSERT(index >= 0);
+ ASSERT(index < capacity_);
+ return table_[index];
+}
+
+
+void ObjectIdRing::VisitPointers(ObjectPointerVisitor* visitor) {
+ ASSERT(table_ != NULL);
+ visitor->VisitPointers(table_, capacity_);
+}
+
+
+ObjectIdRing::ObjectIdRing(Isolate* isolate, int32_t capacity) {
+ ASSERT(capacity > 0);
+ isolate_ = isolate;
+ serial_num_ = 0;
+ wrapped_ = false;
+ table_ = NULL;
+ SetCapacityAndMaxSerial(capacity, kMaxId);
+}
+
+
+void ObjectIdRing::SetCapacityAndMaxSerial(int32_t capacity,
+ int32_t max_serial) {
+ ASSERT(max_serial <= kMaxId);
+ capacity_ = capacity;
+ if (table_ != NULL) {
+ free(table_);
+ }
+ table_ = reinterpret_cast<RawObject**>(calloc(capacity_, kWordSize));
+ for (int i = 0; i < capacity_; i++) {
+ table_[i] = Object::null();
+ }
+ // The maximum serial number is a multiple of the capacity, so that when
+ // the serial number wraps, the index into table_ wraps with it.
+ max_serial_ = max_serial - (max_serial % capacity_);
+}
+
+
+int32_t ObjectIdRing::NextSerial() {
+ int32_t r = serial_num_;
+ serial_num_++;
+ if (serial_num_ >= max_serial_) {
+ serial_num_ = 0;
+ wrapped_ = true;
+ }
+ return r;
+}
+
+
+int32_t ObjectIdRing::AllocateNewId(RawObject* raw_obj) {
+ ASSERT(raw_obj->IsHeapObject());
+ int32_t id = NextSerial();
+ ASSERT(id != kInvalidId);
+ int32_t cursor = IndexOfId(id);
+ ASSERT(cursor != kInvalidId);
+ if (table_[cursor] != Object::null()) {
+ // Free old handle.
+ table_[cursor] = Object::null();
+ }
+ ASSERT(table_[cursor] == Object::null());
+ table_[cursor] = raw_obj;
+ return id;
+}
+
+
+int32_t ObjectIdRing::IndexOfId(int32_t id) {
+ if (!IsValidId(id)) {
+ return kInvalidId;
+ }
+ ASSERT((id >= 0) && (id < max_serial_));
+ return id % capacity_;
+}
+
+
+bool ObjectIdRing::IsValidContiguous(int32_t id) {
+ ASSERT(id != kInvalidId);
+ ASSERT((id >= 0) && (id < max_serial_));
+ if (id >= serial_num_) {
+ // Too large.
+ return false;
+ }
+ int32_t bottom = 0;
+ if (serial_num_ >= capacity_) {
+ bottom = serial_num_ - capacity_;
+ }
+ return id >= bottom;
+}
+
+
+bool ObjectIdRing::IsValidId(int32_t id) {
+ if (id == kInvalidId) {
+ return false;
+ }
+ if (id >= max_serial_) {
+ return false;
+ }
+ ASSERT((id >= 0) && (id < max_serial_));
+ if (wrapped_) {
+ // Serial number has wrapped around to 0.
+ if (serial_num_ >= capacity_) {
+ // Serial number is larger than capacity, the serial
+ // numbers are contiguous again.
+ wrapped_ = false;
+ return IsValidContiguous(id);
+ } else {
+ // When the serial number first wraps, the valid serial number range
+ // spans two intervals:
+ // #1 [0, serial_num_)
+ // #2 [max_serial_ - (capacity_ - serial_num), max_serial_)
+ //
+ // Check for both.
+ if (id < serial_num_) {
+ // Interval #1
+ return true;
+ }
+ // Interval #2
+ const int32_t max_serial_num = max_serial_;
+ const int32_t bottom = max_serial_num - (capacity_ - serial_num_);
+ return id >= bottom && bottom < max_serial_num;
+ }
+ }
+ ASSERT(wrapped_ == false);
+ return IsValidContiguous(id);
+}
+
+} // namespace dart
diff --git a/runtime/vm/object_id_ring.h b/runtime/vm/object_id_ring.h
new file mode 100644
index 0000000..b0dfee7
--- /dev/null
+++ b/runtime/vm/object_id_ring.h
@@ -0,0 +1,66 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#ifndef VM_OBJECT_ID_RING_H_
+#define VM_OBJECT_ID_RING_H_
+
+namespace dart {
+
+// Forward declarations.
+class RawObject;
+class Isolate;
+class ObjectPointerVisitor;
+
+// A ring buffer of object pointers that have been given an id. An object
+// may be pointed to by multiple ids. Objects contained in the ring will
+// be preserved across scavenges but not old space collections.
+// When the ring buffer wraps around older objects will be replaced and their
+// ids will be invalidated.
+class ObjectIdRing {
+ public:
+ static const int32_t kMaxId = 0x3FFFFFFF;
+ static const int32_t kInvalidId = -1;
+ static const int32_t kDefaultCapacity = 1024;
+
+ static void Init(Isolate* isolate, int32_t capacity = kDefaultCapacity);
+
+ ~ObjectIdRing();
+
+ int32_t GetIdForObject(RawObject* raw_obj);
+ RawObject* GetObjectForId(int32_t id);
+
+ void VisitPointers(ObjectPointerVisitor* visitor);
+
+ private:
+ friend class ObjectIdRingTestHelper;
+
+ void SetCapacityAndMaxSerial(int32_t capacity, int32_t max_serial);
+
+ ObjectIdRing(Isolate* isolate, int32_t capacity);
+ Isolate* isolate_;
+ RawObject** table_;
+ int32_t max_serial_;
+ int32_t capacity_;
+ int32_t serial_num_;
+ bool wrapped_;
+
+ RawObject** table() {
+ return table_;
+ }
+ int32_t table_size() {
+ return capacity_;
+ }
+
+ int32_t NextSerial();
+ int32_t AllocateNewId(RawObject* object);
+ int32_t IndexOfId(int32_t id);
+ bool IsValidContiguous(int32_t id);
+ bool IsValidId(int32_t id);
+
+ DISALLOW_COPY_AND_ASSIGN(ObjectIdRing);
+};
+
+} // namespace dart
+
+#endif // VM_OBJECT_ID_RING_H_
diff --git a/runtime/vm/object_id_ring_test.cc b/runtime/vm/object_id_ring_test.cc
new file mode 100644
index 0000000..aeae8e2
--- /dev/null
+++ b/runtime/vm/object_id_ring_test.cc
@@ -0,0 +1,192 @@
+// 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 "platform/assert.h"
+#include "vm/globals.h"
+#include "vm/object_id_ring.h"
+#include "vm/unit_test.h"
+#include "vm/dart_api_impl.h"
+#include "vm/dart_api_state.h"
+
+namespace dart {
+
+
+class ObjectIdRingTestHelper {
+ public:
+ static void SetCapacityAndMaxSerial(ObjectIdRing* ring, int32_t capacity,
+ int32_t max_serial) {
+ ring->SetCapacityAndMaxSerial(capacity, max_serial);
+ }
+
+ static void ExpectIdIsValid(ObjectIdRing* ring, intptr_t id) {
+ EXPECT(ring->IsValidId(id));
+ }
+
+ static void ExpectIdIsInvalid(ObjectIdRing* ring, intptr_t id) {
+ EXPECT(!ring->IsValidId(id));
+ }
+
+ static RawObject* MakeString(const char* s) {
+ return String::New(s);
+ }
+
+ static void ExpectString(RawObject* obj, const char* s) {
+ String& str = String::Handle();
+ str ^= obj;
+ EXPECT(str.Equals(s));
+ }
+};
+
+
+// Test that serial number wrapping works.
+TEST_CASE(ObjectIdRingSerialWrapTest) {
+ Isolate* isolate = Isolate::Current();
+ ObjectIdRing* ring = isolate->object_id_ring();
+ ObjectIdRingTestHelper::SetCapacityAndMaxSerial(ring, 2, 4);
+ intptr_t id;
+ id = ring->GetIdForObject(ObjectIdRingTestHelper::MakeString("0"));
+ EXPECT_EQ(0, id);
+ id = ring->GetIdForObject(ObjectIdRingTestHelper::MakeString("1"));
+ EXPECT_EQ(1, id);
+ // Test that id 1 gives us the "1" string.
+ ObjectIdRingTestHelper::ExpectString(ring->GetObjectForId(id), "1");
+ ObjectIdRingTestHelper::ExpectIdIsValid(ring, 0);
+ ObjectIdRingTestHelper::ExpectIdIsValid(ring, 1);
+ ObjectIdRingTestHelper::ExpectIdIsInvalid(ring, 2);
+ ObjectIdRingTestHelper::ExpectIdIsInvalid(ring, 3);
+ id = ring->GetIdForObject(ObjectIdRingTestHelper::MakeString("2"));
+ EXPECT_EQ(2, id);
+ ObjectIdRingTestHelper::ExpectIdIsInvalid(ring, 0);
+ ObjectIdRingTestHelper::ExpectIdIsValid(ring, 1);
+ ObjectIdRingTestHelper::ExpectIdIsValid(ring, 2);
+ ObjectIdRingTestHelper::ExpectIdIsInvalid(ring, 3);
+ id = ring->GetIdForObject(ObjectIdRingTestHelper::MakeString("3"));
+ EXPECT_EQ(3, id);
+ ObjectIdRingTestHelper::ExpectIdIsInvalid(ring, 0);
+ ObjectIdRingTestHelper::ExpectIdIsInvalid(ring, 1);
+ ObjectIdRingTestHelper::ExpectIdIsValid(ring, 2);
+ ObjectIdRingTestHelper::ExpectIdIsValid(ring, 3);
+ id = ring->GetIdForObject(ObjectIdRingTestHelper::MakeString("4"));
+ EXPECT_EQ(0, id);
+ ObjectIdRingTestHelper::ExpectString(ring->GetObjectForId(id), "4");
+ ObjectIdRingTestHelper::ExpectIdIsValid(ring, 0);
+ ObjectIdRingTestHelper::ExpectIdIsInvalid(ring, 1);
+ ObjectIdRingTestHelper::ExpectIdIsInvalid(ring, 2);
+ ObjectIdRingTestHelper::ExpectIdIsValid(ring, 3);
+ id = ring->GetIdForObject(ObjectIdRingTestHelper::MakeString("5"));
+ EXPECT_EQ(1, id);
+ ObjectIdRingTestHelper::ExpectString(ring->GetObjectForId(id), "5");
+ ObjectIdRingTestHelper::ExpectIdIsValid(ring, 0);
+ ObjectIdRingTestHelper::ExpectIdIsValid(ring, 1);
+ ObjectIdRingTestHelper::ExpectIdIsInvalid(ring, 2);
+ ObjectIdRingTestHelper::ExpectIdIsInvalid(ring, 3);
+}
+
+
+// Test that the ring table is updated when the scavenger moves an object.
+TEST_CASE(ObjectIdRingScavengeMoveTest) {
+ const char* kScriptChars =
+ "main() {\n"
+ " return [1, 2, 3];\n"
+ "}\n";
+ Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
+ Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, NULL);
+ intptr_t list_length = 0;
+ EXPECT_VALID(result);
+ EXPECT(!Dart_IsNull(result));
+ EXPECT(Dart_IsList(result));
+ EXPECT_VALID(Dart_ListLength(result, &list_length));
+ EXPECT_EQ(3, list_length);
+ Isolate* isolate = Isolate::Current();
+ Heap* heap = isolate->heap();
+ ObjectIdRing* ring = isolate->object_id_ring();
+ RawObject* raw_obj = Api::UnwrapHandle(result);
+ // Located in new heap.
+ EXPECT(raw_obj->IsNewObject());
+ EXPECT_NE(Object::null(), raw_obj);
+ intptr_t raw_obj_id1 = ring->GetIdForObject(raw_obj);
+ EXPECT_EQ(0, raw_obj_id1);
+ intptr_t raw_obj_id2 = ring->GetIdForObject(raw_obj);
+ EXPECT_EQ(1, raw_obj_id2);
+ intptr_t raw_obj_id3 = ring->GetIdForObject(Object::null());
+ RawObject* raw_obj1 = ring->GetObjectForId(raw_obj_id1);
+ RawObject* raw_obj2 = ring->GetObjectForId(raw_obj_id2);
+ RawObject* raw_obj3 = ring->GetObjectForId(raw_obj_id3);
+ EXPECT_NE(Object::null(), raw_obj1);
+ EXPECT_NE(Object::null(), raw_obj2);
+ EXPECT_EQ(Object::null(), raw_obj3);
+ EXPECT_EQ(RawObject::ToAddr(raw_obj), RawObject::ToAddr(raw_obj1));
+ EXPECT_EQ(RawObject::ToAddr(raw_obj), RawObject::ToAddr(raw_obj2));
+ // Force a scavenge.
+ heap->CollectGarbage(Heap::kNew);
+ RawObject* raw_object_moved1 = ring->GetObjectForId(raw_obj_id1);
+ RawObject* raw_object_moved2 = ring->GetObjectForId(raw_obj_id2);
+ RawObject* raw_object_moved3 = ring->GetObjectForId(raw_obj_id3);
+ EXPECT_NE(Object::null(), raw_object_moved1);
+ EXPECT_NE(Object::null(), raw_object_moved2);
+ EXPECT_EQ(Object::null(), raw_object_moved3);
+ EXPECT_EQ(RawObject::ToAddr(raw_object_moved1),
+ RawObject::ToAddr(raw_object_moved2));
+ // Test that objects have moved.
+ EXPECT_NE(RawObject::ToAddr(raw_obj1), RawObject::ToAddr(raw_object_moved1));
+ EXPECT_NE(RawObject::ToAddr(raw_obj2), RawObject::ToAddr(raw_object_moved2));
+ // Test that we still point at the same list.
+ Dart_Handle moved_handle = Api::NewHandle(isolate, raw_object_moved1);
+ EXPECT_VALID(moved_handle);
+ EXPECT(!Dart_IsNull(moved_handle));
+ EXPECT(Dart_IsList(moved_handle));
+ EXPECT_VALID(Dart_ListLength(moved_handle, &list_length));
+ EXPECT_EQ(3, list_length);
+}
+
+
+// Test that the ring table is updated with nulls when the old GC collects.
+TEST_CASE(ObjectIdRingOldGCTest) {
+ Isolate* isolate = Isolate::Current();
+ Heap* heap = isolate->heap();
+ ObjectIdRing* ring = isolate->object_id_ring();
+
+ intptr_t raw_obj_id1 = -1;
+ intptr_t raw_obj_id2 = -1;
+ {
+ Dart_EnterScope();
+ Dart_Handle result;
+ // Create a string in the old heap.
+ result = Api::NewHandle(isolate, String::New("old", Heap::kOld));
+ EXPECT_VALID(result);
+ intptr_t string_length = 0;
+ // Inspect string.
+ EXPECT(!Dart_IsNull(result));
+ EXPECT(Dart_IsString(result));
+ EXPECT_VALID(Dart_StringLength(result, &string_length));
+ EXPECT_EQ(3, string_length);
+ RawObject* raw_obj = Api::UnwrapHandle(result);
+ // Verify that it is located in old heap.
+ EXPECT(raw_obj->IsOldObject());
+ EXPECT_NE(Object::null(), raw_obj);
+ raw_obj_id1 = ring->GetIdForObject(raw_obj);
+ EXPECT_EQ(0, raw_obj_id1);
+ raw_obj_id2 = ring->GetIdForObject(raw_obj);
+ EXPECT_EQ(1, raw_obj_id2);
+ RawObject* raw_obj1 = ring->GetObjectForId(raw_obj_id1);
+ RawObject* raw_obj2 = ring->GetObjectForId(raw_obj_id2);
+ EXPECT_NE(Object::null(), raw_obj1);
+ EXPECT_NE(Object::null(), raw_obj2);
+ EXPECT_EQ(RawObject::ToAddr(raw_obj), RawObject::ToAddr(raw_obj1));
+ EXPECT_EQ(RawObject::ToAddr(raw_obj), RawObject::ToAddr(raw_obj2));
+ // Exit scope. Freeing result handle.
+ Dart_ExitScope();
+ }
+ // Force a GC. No reference exist to the old string anymore. It should be
+ // collected and the object id ring will now return the null object for
+ // those ids.
+ heap->CollectGarbage(Heap::kOld);
+ RawObject* raw_object_moved1 = ring->GetObjectForId(raw_obj_id1);
+ RawObject* raw_object_moved2 = ring->GetObjectForId(raw_obj_id2);
+ // Objects should now be null.
+ EXPECT_EQ(Object::null(), raw_object_moved1);
+ EXPECT_EQ(Object::null(), raw_object_moved2);
+}
+
+} // namespace dart
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
index fb1bed9..60c57bc 100644
--- a/runtime/vm/parser.cc
+++ b/runtime/vm/parser.cc
@@ -766,8 +766,8 @@
ASSERT(!func.is_static());
node_sequence = parser.ParseInstanceSetter(func);
break;
- case RawFunction::kConstImplicitGetter:
- node_sequence = parser.ParseStaticConstGetter(func);
+ case RawFunction::kImplicitStaticFinalGetter:
+ node_sequence = parser.ParseStaticFinalGetter(func);
break;
case RawFunction::kMethodExtractor:
node_sequence = parser.ParseMethodExtractor(func);
@@ -878,11 +878,8 @@
}
-// TODO(regis): Since a const variable is implicitly final,
-// rename ParseStaticConstGetter to ParseStaticFinalGetter and
-// rename kConstImplicitGetter to kImplicitFinalGetter.
-SequenceNode* Parser::ParseStaticConstGetter(const Function& func) {
- TRACE_PARSER("ParseStaticConstGetter");
+SequenceNode* Parser::ParseStaticFinalGetter(const Function& func) {
+ TRACE_PARSER("ParseStaticFinalGetter");
ParamList params;
ASSERT(func.num_fixed_parameters() == 0); // static.
ASSERT(!func.HasOptionalParameters());
@@ -1582,7 +1579,7 @@
const String& getter_name = String::ZoneHandle(Field::GetterName(name));
super_func = Resolver::ResolveDynamicAnyArgs(super_class, getter_name);
ASSERT(super_func.IsNull() ||
- (super_func.kind() != RawFunction::kConstImplicitGetter));
+ (super_func.kind() != RawFunction::kImplicitStaticFinalGetter));
}
if (super_func.IsNull()) {
super_func =
@@ -3139,13 +3136,13 @@
ConsumeToken();
init_value = Object::sentinel().raw();
// For static const fields, the initialization expression
- // will be parsed through the kConstImplicitGetter method
+ // will be parsed through the kImplicitStaticFinalGetter method
// invocation/compilation.
// For instance fields, the expression is parsed when a constructor
// is compiled.
// For static const fields with very simple initializer expressions
// (e.g. a literal number or string) we optimize away the
- // kConstImplicitGetter and initialize the field here.
+ // kImplicitStaticFinalGetter and initialize the field here.
// We also do it for static final non-const fields, but only in production
// mode.
@@ -3180,14 +3177,14 @@
library_.AddFieldMetadata(class_field, field->metadata_pos);
}
- // For static const fields, set value to "uninitialized" and
- // create a kConstImplicitGetter getter method.
+ // For static final fields (this includes static const fields), set value to
+ // "uninitialized" and create a kFinalImplicitGetter getter method.
if (field->has_static && has_initializer) {
class_field.set_value(init_value);
if (!has_simple_literal) {
String& getter_name = String::Handle(Field::GetterSymbol(*field->name));
getter = Function::New(getter_name,
- RawFunction::kConstImplicitGetter,
+ RawFunction::kImplicitStaticFinalGetter,
field->has_static,
field->has_const,
/* is_abstract = */ false,
@@ -4305,7 +4302,7 @@
// Create a static const getter.
String& getter_name = String::ZoneHandle(Field::GetterSymbol(var_name));
getter = Function::New(getter_name,
- RawFunction::kConstImplicitGetter,
+ RawFunction::kImplicitStaticFinalGetter,
is_static,
is_const,
/* is_abstract = */ false,
@@ -7641,7 +7638,7 @@
Object::empty_array(),
Resolver::kIsQualified);
if (!func.IsNull()) {
- ASSERT(func.kind() != RawFunction::kConstImplicitGetter);
+ ASSERT(func.kind() != RawFunction::kImplicitStaticFinalGetter);
EnsureSavedCurrentContext();
closure = new StaticGetterNode(call_pos,
NULL,
@@ -7723,7 +7720,7 @@
if (getter.IsNull()) {
return new LoadStaticFieldNode(ident_pos, Field::ZoneHandle(field.raw()));
} else {
- ASSERT(getter.kind() == RawFunction::kConstImplicitGetter);
+ ASSERT(getter.kind() == RawFunction::kImplicitStaticFinalGetter);
return new StaticGetterNode(ident_pos,
NULL, // Receiver.
false, // is_super_getter.
@@ -7808,7 +7805,7 @@
}
access = CreateImplicitClosureNode(func, call_pos, NULL);
} else {
- ASSERT(func.kind() != RawFunction::kConstImplicitGetter);
+ ASSERT(func.kind() != RawFunction::kImplicitStaticFinalGetter);
access = new StaticGetterNode(call_pos,
NULL,
false,
@@ -8371,7 +8368,7 @@
Object::empty_array(),
Resolver::kIsQualified));
ASSERT(!func.IsNull());
- ASSERT(func.kind() == RawFunction::kConstImplicitGetter);
+ ASSERT(func.kind() == RawFunction::kImplicitStaticFinalGetter);
Object& const_value = Object::Handle(
DartEntry::InvokeFunction(func, Object::empty_array()));
if (const_value.IsError()) {
@@ -8405,7 +8402,8 @@
field_name);
}
}
- if (getter.IsNull() || (getter.kind() == RawFunction::kConstImplicitGetter)) {
+ if (getter.IsNull() ||
+ (getter.kind() == RawFunction::kImplicitStaticFinalGetter)) {
return NULL;
}
ASSERT(getter.kind() == RawFunction::kImplicitGetter);
diff --git a/runtime/vm/parser.h b/runtime/vm/parser.h
index baac074..cca62c0 100644
--- a/runtime/vm/parser.h
+++ b/runtime/vm/parser.h
@@ -435,7 +435,7 @@
SequenceNode* ParseInstanceGetter(const Function& func);
SequenceNode* ParseInstanceSetter(const Function& func);
- SequenceNode* ParseStaticConstGetter(const Function& func);
+ SequenceNode* ParseStaticFinalGetter(const Function& func);
SequenceNode* ParseMethodExtractor(const Function& func);
SequenceNode* ParseNoSuchMethodDispatcher(const Function& func,
Array& default_values);
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index 2c8c137..6ec46b3 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -597,7 +597,8 @@
kConstructor,
kImplicitGetter, // represents an implicit getter for fields.
kImplicitSetter, // represents an implicit setter for fields.
- kConstImplicitGetter, // represents an implicit const getter for fields.
+ kImplicitStaticFinalGetter, // represents an implicit getter for static
+ // final fields (incl. static const fields).
kMethodExtractor, // converts method into implicit closure on the receiver.
kNoSuchMethodDispatcher, // invokes noSuchMethod.
kInvokeFieldDispatcher, // invokes a field as a closure.
diff --git a/runtime/vm/resolver.cc b/runtime/vm/resolver.cc
index 9833fe7..dffbd73 100644
--- a/runtime/vm/resolver.cc
+++ b/runtime/vm/resolver.cc
@@ -4,6 +4,7 @@
#include "vm/resolver.h"
+#include "vm/dart_entry.h"
#include "vm/flags.h"
#include "vm/isolate.h"
#include "vm/object.h"
@@ -23,8 +24,7 @@
// arguments is passed in.
RawFunction* Resolver::ResolveDynamic(const Instance& receiver,
const String& function_name,
- int num_arguments,
- int num_named_arguments) {
+ const ArgumentsDescriptor& args_desc) {
// Figure out type of receiver first.
Class& cls = Class::Handle();
cls = receiver.clazz();
@@ -34,33 +34,27 @@
}
ASSERT(!cls.IsNull());
- return ResolveDynamicForReceiverClass(
- cls, function_name, num_arguments, num_named_arguments);
+ return ResolveDynamicForReceiverClass(cls, function_name, args_desc);
}
RawFunction* Resolver::ResolveDynamicForReceiverClass(
const Class& receiver_class,
const String& function_name,
- int num_arguments,
- int num_named_arguments) {
+ const ArgumentsDescriptor& args_desc) {
Function& function =
Function::Handle(ResolveDynamicAnyArgs(receiver_class, function_name));
if (function.IsNull() ||
- !function.AreValidArgumentCounts(num_arguments,
- num_named_arguments,
- NULL)) {
+ !function.AreValidArguments(args_desc, NULL)) {
// Return a null function to signal to the upper levels to dispatch to
// "noSuchMethod" function.
if (FLAG_trace_resolving) {
String& error_message = String::Handle(String::New("function not found"));
if (!function.IsNull()) {
// Obtain more detailed error message.
- function.AreValidArgumentCounts(num_arguments,
- num_named_arguments,
- &error_message);
+ function.AreValidArguments(args_desc, &error_message);
}
OS::Print("ResolveDynamic error '%s': %s.\n",
function_name.ToCString(),
@@ -154,7 +148,7 @@
RawFunction* Resolver::ResolveStatic(const Library& library,
const String& class_name,
const String& function_name,
- int num_arguments,
+ intptr_t num_arguments,
const Array& argument_names,
StaticResolveType resolve_type) {
ASSERT(!library.IsNull());
@@ -230,7 +224,7 @@
RawFunction* Resolver::ResolveStatic(const Class& cls,
const String& function_name,
- int num_arguments,
+ intptr_t num_arguments,
const Array& argument_names,
StaticResolveType resolve_type) {
const Function& function = Function::Handle(
diff --git a/runtime/vm/resolver.h b/runtime/vm/resolver.h
index 942ea56..a0f2b33 100644
--- a/runtime/vm/resolver.h
+++ b/runtime/vm/resolver.h
@@ -16,6 +16,7 @@
class Library;
class RawFunction;
class String;
+class ArgumentsDescriptor;
// Resolver abstracts functionality needed to resolve dart functions at
@@ -25,14 +26,12 @@
// Resolve specified dart instance function.
static RawFunction* ResolveDynamic(const Instance& receiver,
const String& function_name,
- int num_arguments,
- int num_named_arguments);
+ const ArgumentsDescriptor& args_desc);
static RawFunction* ResolveDynamicForReceiverClass(
const Class& receiver_class,
const String& function_name,
- int num_arguments,
- int num_named_arguments);
+ const ArgumentsDescriptor& args_desc);
static RawFunction* ResolveDynamicAnyArgs(
const Class& receiver_class,
@@ -52,7 +51,7 @@
static RawFunction* ResolveStatic(const Library& library,
const String& cls_name,
const String& function_name,
- int num_arguments,
+ intptr_t num_arguments,
const Array& argument_names,
StaticResolveType resolve_type);
@@ -64,7 +63,7 @@
// Resolve specified dart static function with specified arity.
static RawFunction* ResolveStatic(const Class& cls,
const String& function_name,
- int num_arguments,
+ intptr_t num_arguments,
const Array& argument_names,
StaticResolveType resolve_type);
};
diff --git a/runtime/vm/resolver_test.cc b/runtime/vm/resolver_test.cc
index 2f253ba..d64b6d3 100644
--- a/runtime/vm/resolver_test.cc
+++ b/runtime/vm/resolver_test.cc
@@ -170,15 +170,15 @@
// Now try to resolve and invoke the instance function in this class.
{
- const int kNumPositionalArguments = 3;
- const int kNumNamedArguments = 0;
+ const int kNumArguments = 3;
+ ArgumentsDescriptor args_desc(
+ Array::Handle(ArgumentsDescriptor::New(kNumArguments)));
const Function& function = Function::Handle(
Resolver::ResolveDynamic(receiver,
function_name,
- kNumPositionalArguments,
- kNumNamedArguments));
+ args_desc));
EXPECT(!function.IsNull());
- const Array& args = Array::Handle(Array::New(kNumPositionalArguments));
+ const Array& args = Array::Handle(Array::New(kNumArguments));
args.SetAt(0, receiver);
const String& arg0 = String::Handle(String::New("junk"));
args.SetAt(1, arg0);
@@ -191,27 +191,27 @@
// Now try to resolve an instance function with invalid argument count.
{
- const int kNumPositionalArguments = 1;
- const int kNumNamedArguments = 0;
+ const int kNumArguments = 1;
+ ArgumentsDescriptor args_desc(
+ Array::Handle(ArgumentsDescriptor::New(kNumArguments)));
const Function& bad_function = Function::Handle(
Resolver::ResolveDynamic(receiver,
function_name,
- kNumPositionalArguments,
- kNumNamedArguments));
+ args_desc));
EXPECT(bad_function.IsNull());
}
// Hierarchy walking.
{
- const int kNumPositionalArguments = 1;
- const int kNumNamedArguments = 0;
+ const int kNumArguments = 1;
+ ArgumentsDescriptor args_desc(
+ Array::Handle(ArgumentsDescriptor::New(kNumArguments)));
const String& super_function_name =
String::Handle(String::New("dynCall"));
const Function& super_function = Function::Handle(
Resolver::ResolveDynamic(receiver,
super_function_name,
- kNumPositionalArguments,
- kNumNamedArguments));
+ args_desc));
EXPECT(!super_function.IsNull());
}
}
diff --git a/runtime/vm/scavenger.cc b/runtime/vm/scavenger.cc
index 8d6e4bf..17b95f2 100644
--- a/runtime/vm/scavenger.cc
+++ b/runtime/vm/scavenger.cc
@@ -17,6 +17,7 @@
#include "vm/verifier.h"
#include "vm/visitor.h"
#include "vm/weak_table.h"
+#include "vm/object_id_ring.h"
namespace dart {
@@ -404,6 +405,14 @@
}
+void Scavenger::IterateObjectIdTable(Isolate* isolate,
+ ScavengerVisitor* visitor) {
+ ObjectIdRing* ring = isolate->object_id_ring();
+ ASSERT(ring != NULL);
+ ring->VisitPointers(visitor);
+}
+
+
void Scavenger::IterateRoots(Isolate* isolate,
ScavengerVisitor* visitor,
bool visit_prologue_weak_persistent_handles) {
@@ -413,6 +422,7 @@
StackFrameIterator::kDontValidateFrames);
int64_t middle = OS::GetCurrentTimeMicros();
IterateStoreBuffers(isolate, visitor);
+ IterateObjectIdTable(isolate, visitor);
int64_t end = OS::GetCurrentTimeMicros();
heap_->RecordTime(kVisitIsolateRoots, middle - start);
heap_->RecordTime(kIterateStoreBuffers, end - middle);
diff --git a/runtime/vm/scavenger.h b/runtime/vm/scavenger.h
index 2ff0033..8dd60ab 100644
--- a/runtime/vm/scavenger.h
+++ b/runtime/vm/scavenger.h
@@ -103,6 +103,7 @@
uword FirstObjectStart() const { return to_->start() | object_alignment_; }
void Prologue(Isolate* isolate, bool invoke_api_callbacks);
void IterateStoreBuffers(Isolate* isolate, ScavengerVisitor* visitor);
+ void IterateObjectIdTable(Isolate* isolate, ScavengerVisitor* visitor);
void IterateRoots(Isolate* isolate,
ScavengerVisitor* visitor,
bool visit_prologue_weak_persistent_handles);
diff --git a/runtime/vm/simulator_arm.cc b/runtime/vm/simulator_arm.cc
index 726a25c2..9fdb01e 100644
--- a/runtime/vm/simulator_arm.cc
+++ b/runtime/vm/simulator_arm.cc
@@ -447,7 +447,7 @@
"h/help -- print this help string\n"
"break <address> -- set break point at specified address\n"
"p/print <reg or value or *addr> -- print integer value\n"
- "pf/printfloat <sreg or *addr> -- print float value\n"
+ "ps/printsingle <sreg or *addr> -- print float value\n"
"pd/printdouble <dreg or *addr> -- print double value\n"
"po/printobject <*reg or *addr> -- print object\n"
"si/stepi -- single step an instruction\n"
@@ -476,7 +476,8 @@
} else {
OS::Print("print <reg or value or *addr>\n");
}
- } else if ((strcmp(cmd, "pf") == 0) || (strcmp(cmd, "printfloat") == 0)) {
+ } else if ((strcmp(cmd, "ps") == 0) ||
+ (strcmp(cmd, "printsingle") == 0)) {
if (args == 2) {
float fvalue;
if (GetFValue(arg1, &fvalue)) {
@@ -2921,7 +2922,7 @@
int64_t* s8m_64 = reinterpret_cast<int64_t*>(&s8m);
if ((instr->Bits(8, 4) == 8) && (instr->Bit(4) == 0) &&
- (instr->Bit(24) == 0)) {
+ (instr->Bits(23, 2) == 0)) {
// Uses q registers.
// Format(instr, "vadd.'sz 'qd, 'qn, 'qm");
const int size = instr->Bits(20, 2);
@@ -2945,11 +2946,67 @@
UNREACHABLE();
}
} else if ((instr->Bits(8, 4) == 13) && (instr->Bit(4) == 0) &&
- (instr->Bit(24) == 0)) {
+ (instr->Bits(23, 2) == 0) && (instr->Bit(21) == 0)) {
// Format(instr, "vadd.F32 'qd, 'qn, 'qm");
for (int i = 0; i < 4; i++) {
s8d.data_[i].f = s8n.data_[i].f + s8m.data_[i].f;
}
+ } else if ((instr->Bits(8, 4) == 8) && (instr->Bit(4) == 0) &&
+ (instr->Bits(23, 2) == 2)) {
+ // Format(instr, "vsub.'sz 'qd, 'qn, 'qm");
+ const int size = instr->Bits(20, 2);
+ if (size == 0) {
+ for (int i = 0; i < 16; i++) {
+ s8d_8[i] = s8n_8[i] - s8m_8[i];
+ }
+ } else if (size == 1) {
+ for (int i = 0; i < 8; i++) {
+ s8d_16[i] = s8n_16[i] - s8m_16[i];
+ }
+ } else if (size == 2) {
+ for (int i = 0; i < 4; i++) {
+ s8d.data_[i].u = s8n.data_[i].u - s8m.data_[i].u;
+ }
+ } else if (size == 3) {
+ for (int i = 0; i < 2; i++) {
+ s8d_64[i] = s8n_64[i] - s8m_64[i];
+ }
+ } else {
+ UNREACHABLE();
+ }
+ } else if ((instr->Bits(8, 4) == 13) && (instr->Bit(4) == 0) &&
+ (instr->Bits(23, 2) == 0) && (instr->Bit(21) == 1)) {
+ // Format(instr, "vsub.F32 'qd, 'qn, 'qm");
+ for (int i = 0; i < 4; i++) {
+ s8d.data_[i].f = s8n.data_[i].f - s8m.data_[i].f;
+ }
+ } else if ((instr->Bits(8, 4) == 9) && (instr->Bit(4) == 1) &&
+ (instr->Bits(23, 2) == 0)) {
+ // Format(instr, "vmul.'sz 'qd, 'qn, 'qm");
+ const int size = instr->Bits(20, 2);
+ if (size == 0) {
+ for (int i = 0; i < 16; i++) {
+ s8d_8[i] = s8n_8[i] * s8m_8[i];
+ }
+ } else if (size == 1) {
+ for (int i = 0; i < 8; i++) {
+ s8d_16[i] = s8n_16[i] * s8m_16[i];
+ }
+ } else if (size == 2) {
+ for (int i = 0; i < 4; i++) {
+ s8d.data_[i].u = s8n.data_[i].u * s8m.data_[i].u;
+ }
+ } else if (size == 3) {
+ UnimplementedInstruction(instr);
+ } else {
+ UNREACHABLE();
+ }
+ } else if ((instr->Bits(8, 4) == 13) && (instr->Bit(4) == 1) &&
+ (instr->Bits(23, 2) == 2) && (instr->Bit(21) == 0)) {
+ // Format(instr, "vmul.F32 'qd, 'qn, 'qm");
+ for (int i = 0; i < 4; i++) {
+ s8d.data_[i].f = s8n.data_[i].f * s8m.data_[i].f;
+ }
} else {
UnimplementedInstruction(instr);
}
@@ -2957,7 +3014,42 @@
set_qregister(qd, s8d);
} else {
// Q == 0, Uses 64-bit D registers.
- UnimplementedInstruction(instr);
+ if ((instr->Bits(23, 2) == 3) && (instr->Bits(20, 2) == 3) &&
+ (instr->Bits(10, 2) == 2) && (instr->Bit(4) == 0)) {
+ // Format(instr, "vtbl 'dd, 'dtbllist, 'dm");
+ DRegister dd = instr->DdField();
+ DRegister dm = instr->DmField();
+ int reg_count = instr->Bits(8, 2) + 1;
+ int start = (instr->Bit(7) << 4) | instr->Bits(16, 4);
+ int64_t table[4];
+
+ for (int i = 0; i < reg_count; i++) {
+ DRegister d = static_cast<DRegister>(start + i);
+ table[i] = get_dregister_bits(d);
+ }
+ for (int i = reg_count; i < 4; i++) {
+ table[i] = 0;
+ }
+
+
+ int64_t dm_value = get_dregister_bits(dm);
+ int64_t result;
+ int8_t* dm_bytes = reinterpret_cast<int8_t*>(&dm_value);
+ int8_t* result_bytes = reinterpret_cast<int8_t*>(&result);
+ int8_t* table_bytes = reinterpret_cast<int8_t*>(&table[0]);
+ for (int i = 0; i < 8; i++) {
+ int idx = dm_bytes[i];
+ if ((idx >= 0) && (idx < 256)) {
+ result_bytes[i] = table_bytes[idx];
+ } else {
+ result_bytes[i] = 0;
+ }
+ }
+
+ set_dregister_bits(dd, result);
+ } else {
+ UnimplementedInstruction(instr);
+ }
}
}
diff --git a/runtime/vm/stub_code_arm.cc b/runtime/vm/stub_code_arm.cc
index 040655e..ec602d6 100644
--- a/runtime/vm/stub_code_arm.cc
+++ b/runtime/vm/stub_code_arm.cc
@@ -47,10 +47,10 @@
// Save exit frame information to enable stack walking as we are about
// to transition to Dart VM C++ code.
- __ StoreToOffset(kStoreWord, SP, R0, Isolate::top_exit_frame_info_offset());
+ __ StoreToOffset(kWord, SP, R0, Isolate::top_exit_frame_info_offset());
// Save current Context pointer into Isolate structure.
- __ StoreToOffset(kStoreWord, CTX, R0, Isolate::top_context_offset());
+ __ StoreToOffset(kWord, CTX, R0, Isolate::top_context_offset());
// Cache Isolate pointer into CTX while executing runtime code.
__ mov(CTX, ShifterOperand(R0));
@@ -83,14 +83,14 @@
// Reset exit frame information in Isolate structure.
__ LoadImmediate(R2, 0);
- __ StoreToOffset(kStoreWord, R2, CTX, Isolate::top_exit_frame_info_offset());
+ __ StoreToOffset(kWord, R2, CTX, Isolate::top_exit_frame_info_offset());
// Load Context pointer from Isolate structure into R2.
- __ LoadFromOffset(kLoadWord, R2, CTX, Isolate::top_context_offset());
+ __ LoadFromOffset(kWord, R2, CTX, Isolate::top_context_offset());
// Reset Context pointer in Isolate structure.
__ LoadImmediate(R3, reinterpret_cast<intptr_t>(Object::null()));
- __ StoreToOffset(kStoreWord, R3, CTX, Isolate::top_context_offset());
+ __ StoreToOffset(kWord, R3, CTX, Isolate::top_context_offset());
// Cache Context pointer into CTX while executing Dart code.
__ mov(CTX, ShifterOperand(R2));
@@ -138,10 +138,10 @@
// Save exit frame information to enable stack walking as we are about
// to transition to native code.
- __ StoreToOffset(kStoreWord, SP, R0, Isolate::top_exit_frame_info_offset());
+ __ StoreToOffset(kWord, SP, R0, Isolate::top_exit_frame_info_offset());
// Save current Context pointer into Isolate structure.
- __ StoreToOffset(kStoreWord, CTX, R0, Isolate::top_context_offset());
+ __ StoreToOffset(kWord, CTX, R0, Isolate::top_context_offset());
// Cache Isolate pointer into CTX while executing native code.
__ mov(CTX, ShifterOperand(R0));
@@ -179,14 +179,14 @@
// Reset exit frame information in Isolate structure.
__ LoadImmediate(R2, 0);
- __ StoreToOffset(kStoreWord, R2, CTX, Isolate::top_exit_frame_info_offset());
+ __ StoreToOffset(kWord, R2, CTX, Isolate::top_exit_frame_info_offset());
// Load Context pointer from Isolate structure into R2.
- __ LoadFromOffset(kLoadWord, R2, CTX, Isolate::top_context_offset());
+ __ LoadFromOffset(kWord, R2, CTX, Isolate::top_context_offset());
// Reset Context pointer in Isolate structure.
__ LoadImmediate(R3, reinterpret_cast<intptr_t>(Object::null()));
- __ StoreToOffset(kStoreWord, R3, CTX, Isolate::top_context_offset());
+ __ StoreToOffset(kWord, R3, CTX, Isolate::top_context_offset());
// Cache Context pointer into CTX while executing Dart code.
__ mov(CTX, ShifterOperand(R2));
@@ -475,15 +475,15 @@
__ b(&slow_case, NE);
}
__ ldr(R8, FieldAddress(CTX, Context::isolate_offset()));
- __ LoadFromOffset(kLoadWord, R8, R8, Isolate::heap_offset());
- __ LoadFromOffset(kLoadWord, R8, R8, Heap::new_space_offset());
+ __ LoadFromOffset(kWord, R8, R8, Isolate::heap_offset());
+ __ LoadFromOffset(kWord, R8, R8, Heap::new_space_offset());
// Calculate and align allocation size.
// Load new object start and calculate next object start.
// R1: array element type.
// R2: array length as Smi.
// R8: points to new space object.
- __ LoadFromOffset(kLoadWord, R0, R8, Scavenger::top_offset());
+ __ LoadFromOffset(kWord, R0, R8, Scavenger::top_offset());
intptr_t fixed_size = sizeof(RawArray) + kObjectAlignment - 1;
__ LoadImmediate(R3, fixed_size);
__ add(R3, R3, ShifterOperand(R2, LSL, 1)); // R2 is Smi.
@@ -498,7 +498,7 @@
// R3: array size.
// R7: potential next object start.
// R8: points to new space object.
- __ LoadFromOffset(kLoadWord, IP, R8, Scavenger::end_offset());
+ __ LoadFromOffset(kWord, IP, R8, Scavenger::end_offset());
__ cmp(R7, ShifterOperand(IP));
__ b(&slow_case, CS); // Branch if unsigned higher or equal.
@@ -507,7 +507,7 @@
// R0: potential new object start.
// R7: potential next object start.
// R8: Points to new space object.
- __ StoreToOffset(kStoreWord, R7, R8, Scavenger::top_offset());
+ __ StoreToOffset(kWord, R7, R8, Scavenger::top_offset());
__ add(R0, R0, ShifterOperand(kHeapObjectTag));
// R0: new object start as a tagged pointer.
@@ -709,16 +709,16 @@
// Save the top exit frame info. Use R5 as a temporary register.
// StackFrameIterator reads the top exit frame info saved in this frame.
- __ LoadFromOffset(kLoadWord, R5, R8, Isolate::top_exit_frame_info_offset());
+ __ LoadFromOffset(kWord, R5, R8, Isolate::top_exit_frame_info_offset());
__ LoadImmediate(R6, 0);
- __ StoreToOffset(kStoreWord, R6, R8, Isolate::top_exit_frame_info_offset());
+ __ StoreToOffset(kWord, R6, R8, Isolate::top_exit_frame_info_offset());
// Save the old Context pointer. Use R4 as a temporary register.
// Note that VisitObjectPointers will find this saved Context pointer during
// GC marking, since it traverses any information between SP and
// FP - kExitLinkSlotFromEntryFp.
// EntryFrame::SavedContext reads the context saved in this frame.
- __ LoadFromOffset(kLoadWord, R4, R8, Isolate::top_context_offset());
+ __ LoadFromOffset(kWord, R4, R8, Isolate::top_context_offset());
// The constants kSavedContextSlotFromEntryFp and
// kExitLinkSlotFromEntryFp must be kept in sync with the code below.
@@ -773,8 +773,8 @@
// Restore the saved top exit frame info back into the Isolate structure.
// Uses R5 as a temporary register for this.
__ PopList((1 << R4) | (1 << R5));
- __ StoreToOffset(kStoreWord, R4, CTX, Isolate::top_context_offset());
- __ StoreToOffset(kStoreWord, R5, CTX, Isolate::top_exit_frame_info_offset());
+ __ StoreToOffset(kWord, R4, CTX, Isolate::top_context_offset());
+ __ StoreToOffset(kWord, R5, CTX, Isolate::top_exit_frame_info_offset());
// Restore C++ ABI callee-saved registers.
__ PopList((1 << R3) | kAbiPreservedCpuRegs); // Ignore restored R3.
@@ -1070,7 +1070,7 @@
for (intptr_t current_offset = sizeof(RawObject);
current_offset < instance_size;
current_offset += kWordSize) {
- __ StoreToOffset(kStoreWord, R0, R2, current_offset);
+ __ StoreToOffset(kWord, R0, R2, current_offset);
}
} else {
__ add(R4, R2, ShifterOperand(sizeof(RawObject)));
@@ -1093,7 +1093,7 @@
if (is_cls_parameterized) {
// R1: new object type arguments.
// Set the type arguments in the new object.
- __ StoreToOffset(kStoreWord, R1, R2, cls.type_arguments_field_offset());
+ __ StoreToOffset(kWord, R1, R2, cls.type_arguments_field_offset());
}
// Done allocating and initializing the instance.
// R2: new object still missing its heap tag.
@@ -1421,7 +1421,7 @@
__ ldr(R0, Address(SP, R0, LSL, 1));
__ bl(&get_class_id_as_smi);
// R0: next argument class ID (smi).
- __ LoadFromOffset(kLoadWord, R1, R6, i * kWordSize);
+ __ LoadFromOffset(kWord, R1, R6, i * kWordSize);
// R1: next class ID to check (smi).
}
__ cmp(R0, ShifterOperand(R1)); // Class id match?
@@ -1465,7 +1465,7 @@
__ PushList((1 << R0) | (1 << R4) | (1 << R5));
// Push call arguments.
for (intptr_t i = 0; i < num_args; i++) {
- __ LoadFromOffset(kLoadWord, IP, R7, -i * kWordSize);
+ __ LoadFromOffset(kWord, IP, R7, -i * kWordSize);
__ Push(IP);
}
// Pass IC data object and arguments descriptor array.
@@ -1501,13 +1501,13 @@
// R6: pointer to an IC data check group.
const intptr_t target_offset = ICData::TargetIndexFor(num_args) * kWordSize;
const intptr_t count_offset = ICData::CountIndexFor(num_args) * kWordSize;
- __ LoadFromOffset(kLoadWord, R0, R6, target_offset);
- __ LoadFromOffset(kLoadWord, R1, R6, count_offset);
+ __ LoadFromOffset(kWord, R0, R6, target_offset);
+ __ LoadFromOffset(kWord, R1, R6, count_offset);
__ adds(R1, R1, ShifterOperand(Smi::RawValue(1)));
- __ StoreToOffset(kStoreWord, R1, R6, count_offset);
+ __ StoreToOffset(kWord, R1, R6, count_offset);
__ b(&call_target_function, VC); // No overflow.
__ LoadImmediate(R1, Smi::RawValue(Smi::kMaxValue));
- __ StoreToOffset(kStoreWord, R1, R6, count_offset);
+ __ StoreToOffset(kWord, R1, R6, count_offset);
__ Bind(&call_target_function);
// R0: target function.
@@ -1628,17 +1628,17 @@
// Increment count for this call.
Label increment_done;
- __ LoadFromOffset(kLoadWord, R1, R6, count_offset);
+ __ LoadFromOffset(kWord, R1, R6, count_offset);
__ adds(R1, R1, ShifterOperand(Smi::RawValue(1)));
- __ StoreToOffset(kStoreWord, R1, R6, count_offset);
+ __ StoreToOffset(kWord, R1, R6, count_offset);
__ b(&increment_done, VC); // No overflow.
__ LoadImmediate(R1, Smi::RawValue(Smi::kMaxValue));
- __ StoreToOffset(kStoreWord, R1, R6, count_offset);
+ __ StoreToOffset(kWord, R1, R6, count_offset);
__ Bind(&increment_done);
Label target_is_compiled;
// Get function and call it, if possible.
- __ LoadFromOffset(kLoadWord, R1, R6, target_offset);
+ __ LoadFromOffset(kWord, R1, R6, target_offset);
__ ldr(R0, FieldAddress(R1, Function::code_offset()));
__ CompareImmediate(R0, reinterpret_cast<intptr_t>(Object::null()));
__ b(&target_is_compiled, NE);
diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h
index 6ac9824..8b0b2f0 100644
--- a/runtime/vm/symbols.h
+++ b/runtime/vm/symbols.h
@@ -228,6 +228,8 @@
V(IsolateSpawnException, "IsolateSpawnException") \
V(IsolateUnhandledException, "IsolateUnhandledException") \
V(FiftyThreeBitOverflowError, "_FiftyThreeBitOverflowError") \
+ V(MirroredCompilationError, "MirroredCompilationError") \
+ V(MirroredUncaughtExceptionError, "MirroredUncaughtExceptionError") \
V(_setupFullStackTrace, "_setupFullStackTrace") \
V(BooleanExpression, "boolean expression") \
V(Malformed, "malformed") \
diff --git a/runtime/vm/vm_sources.gypi b/runtime/vm/vm_sources.gypi
index 422b80b..46868ff 100644
--- a/runtime/vm/vm_sources.gypi
+++ b/runtime/vm/vm_sources.gypi
@@ -238,6 +238,9 @@
'object.h',
'object_arm_test.cc',
'object_ia32_test.cc',
+ 'object_id_ring.cc',
+ 'object_id_ring.h',
+ 'object_id_ring_test.cc',
'object_mips_test.cc',
'object_store.cc',
'object_store.h',
diff --git a/sdk/lib/_internal/compiler/implementation/deferred_load.dart b/sdk/lib/_internal/compiler/implementation/deferred_load.dart
index 38a6245..b39e475 100644
--- a/sdk/lib/_internal/compiler/implementation/deferred_load.dart
+++ b/sdk/lib/_internal/compiler/implementation/deferred_load.dart
@@ -56,6 +56,8 @@
/// DeferredLibrary from dart:async
ClassElement get deferredLibraryClass => compiler.deferredLibraryClass;
+ bool get areAnyElementsDeferred => !allDeferredElements.isEmpty;
+
bool isDeferred(Element element) {
element = element.implementation;
return allDeferredElements.contains(element);
diff --git a/sdk/lib/_internal/compiler/implementation/elements/elements.dart b/sdk/lib/_internal/compiler/implementation/elements/elements.dart
index 7411bc9..f367345 100644
--- a/sdk/lib/_internal/compiler/implementation/elements/elements.dart
+++ b/sdk/lib/_internal/compiler/implementation/elements/elements.dart
@@ -497,7 +497,9 @@
if (r != 0) return r;
Token positionA = a.position();
Token positionB = b.position();
- r = positionA.charOffset.compareTo(positionB.charOffset);
+ int offsetA = positionA == null ? -1 : positionA.charOffset;
+ int offsetB = positionB == null ? -1 : positionB.charOffset;
+ r = offsetA.compareTo(offsetB);
if (r != 0) return r;
r = a.name.slowToString().compareTo(b.name.slowToString());
if (r != 0) return r;
@@ -881,6 +883,9 @@
void forEachInstanceField(void f(ClassElement enclosingClass, Element field),
{includeSuperAndInjectedMembers: false});
+ /// Similar to [forEachInstanceField] but visits static fields.
+ void forEachStaticField(void f(ClassElement enclosingClass, Element field));
+
void forEachBackendMember(void f(Element member));
}
diff --git a/sdk/lib/_internal/compiler/implementation/elements/modelx.dart b/sdk/lib/_internal/compiler/implementation/elements/modelx.dart
index 58c2344..76b16e4 100644
--- a/sdk/lib/_internal/compiler/implementation/elements/modelx.dart
+++ b/sdk/lib/_internal/compiler/implementation/elements/modelx.dart
@@ -1892,6 +1892,18 @@
includeSuperAndInjectedMembers: includeSuperAndInjectedMembers);
}
+ /// Similar to [forEachInstanceField] but visits static fields.
+ void forEachStaticField(void f(ClassElement enclosingClass, Element field)) {
+ // Filters so that [f] is only invoked with static fields.
+ void fieldFilter(ClassElement enclosingClass, Element member) {
+ if (!member.isInstanceMember() && member.kind == ElementKind.FIELD) {
+ f(enclosingClass, member);
+ }
+ }
+
+ forEachMember(fieldFilter);
+ }
+
void forEachBackendMember(void f(Element member)) {
backendMembers.forEach(f);
}
diff --git a/sdk/lib/_internal/compiler/implementation/enqueue.dart b/sdk/lib/_internal/compiler/implementation/enqueue.dart
index ac465fc..77a146a 100644
--- a/sdk/lib/_internal/compiler/implementation/enqueue.dart
+++ b/sdk/lib/_internal/compiler/implementation/enqueue.dart
@@ -326,31 +326,24 @@
ClassElement cls = element.declaration.getEnclosingClass();
registerInstantiatedType(cls.rawType, elements);
registerStaticUse(element.declaration);
+ } else if (element.isMixinApplication) {
+ // Don't enqueue mixin applications.
+ } else if (element.isClass()) {
+ ClassElement cls = element.declaration;
+ registerInstantiatedType(cls.rawType, elements);
+ // Make sure that even abstract classes are considered instantiated.
+ universe.instantiatedClasses.add(cls);
} else if (element.impliesType()) {
- // Don't enqueue classes, typedefs, and type variables.
+ // Don't enqueue typedefs, and type variables.
} else if (Elements.isStaticOrTopLevel(element)) {
registerStaticUse(element.declaration);
} else if (element.isInstanceMember()) {
- if (element.isFunction()) {
- int arity =
- element.asFunctionElement().requiredParameterCount(compiler);
- Selector selector =
- new Selector.call(element.name, element.getLibrary(), arity);
- registerInvocation(selector);
- } else if (element.isSetter()) {
+ Selector selector = new Selector.fromElement(element, compiler);
+ registerSelectorUse(selector);
+ if (element.isField()) {
Selector selector =
new Selector.setter(element.name, element.getLibrary());
registerInvokedSetter(selector);
- } else if (element.isGetter()) {
- Selector selector =
- new Selector.getter(element.name, element.getLibrary());
- registerInvokedGetter(selector);
- } else if (element.isField()) {
- Selector selector =
- new Selector.setter(element.name, element.getLibrary());
- registerInvokedSetter(selector);
- selector = new Selector.getter(element.name, element.getLibrary());
- registerInvokedGetter(selector);
}
}
}
diff --git a/sdk/lib/_internal/compiler/implementation/js/nodes.dart b/sdk/lib/_internal/compiler/implementation/js/nodes.dart
index 1f1134c..04eafb9 100644
--- a/sdk/lib/_internal/compiler/implementation/js/nodes.dart
+++ b/sdk/lib/_internal/compiler/implementation/js/nodes.dart
@@ -28,6 +28,7 @@
T visitLabeledStatement(LabeledStatement node);
T visitLiteralStatement(LiteralStatement node);
+ T visitBlob(Blob node);
T visitLiteralExpression(LiteralExpression node);
T visitVariableDeclarationList(VariableDeclarationList node);
T visitSequence(Sequence node);
@@ -103,6 +104,7 @@
T visitDefault(Default node) => visitNode(node);
T visitExpression(Expression node) => visitNode(node);
+ T visitBlob(Blob node) => visitExpression(node);
T visitVariableReference(VariableReference node) => visitExpression(node);
T visitLiteralExpression(LiteralExpression node) => visitExpression(node);
@@ -516,6 +518,22 @@
Prefix get not => new Prefix('!', this);
}
+/// Wrap a CodeBuffer as an expression.
+class Blob extends Expression {
+ // TODO(ahe): This class is an aid to convert everything to ASTs, remove when
+ // not needed anymore.
+
+ final leg.CodeBuffer buffer;
+
+ Blob(this.buffer);
+
+ accept(NodeVisitor visitor) => visitor.visitBlob(this);
+
+ void visitChildren(NodeVisitor visitor) {}
+
+ int get precedenceLevel => PRIMARY;
+}
+
class LiteralExpression extends Expression {
final String template;
final List<Expression> inputs;
diff --git a/sdk/lib/_internal/compiler/implementation/js/printer.dart b/sdk/lib/_internal/compiler/implementation/js/printer.dart
index f7d65c1..a5870d8 100644
--- a/sdk/lib/_internal/compiler/implementation/js/printer.dart
+++ b/sdk/lib/_internal/compiler/implementation/js/printer.dart
@@ -140,6 +140,10 @@
visitAll(program.body);
}
+ visitBlob(Blob node) {
+ outBuffer.addBuffer(node.buffer);
+ }
+
bool blockBody(Node body, {bool needsSeparation, bool needsNewline}) {
if (body is Block) {
spaceOut();
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart b/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart
index 2f90272..f7c5b46 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart
@@ -122,6 +122,47 @@
}
}
+/*
+ * Invariants:
+ * canInline(function) implies canInline(function, insideLoop:true)
+ * !canInline(function, insideLoop: true) implies !canInline(function)
+ */
+class FunctionInlineCache {
+ final Map<FunctionElement, bool> canBeInlined =
+ new Map<FunctionElement, bool>();
+
+ final Map<FunctionElement, bool> canBeInlinedInsideLoop =
+ new Map<FunctionElement, bool>();
+
+ // Returns [:true:]/[:false:] if we have a cached decision.
+ // Returns [:null:] otherwise.
+ bool canInline(FunctionElement element, {bool insideLoop}) {
+ return insideLoop ? canBeInlinedInsideLoop[element] : canBeInlined[element];
+ }
+
+ void markAsInlinable(FunctionElement element, {bool insideLoop}) {
+ if (insideLoop) {
+ canBeInlinedInsideLoop[element] = true;
+ } else {
+ // If we can inline a function outside a loop then we should do it inside
+ // a loop as well.
+ canBeInlined[element] = true;
+ canBeInlinedInsideLoop[element] = true;
+ }
+ }
+
+ void markAsNonInlinable(FunctionElement element, {bool insideLoop}) {
+ if (insideLoop) {
+ // If we can't inline a function inside a loop, then we should not inline
+ // it outside a loop either.
+ canBeInlined[element] = false;
+ canBeInlinedInsideLoop[element] = false;
+ } else {
+ canBeInlined[element] = false;
+ }
+ }
+}
+
class JavaScriptBackend extends Backend {
SsaBuilderTask builder;
@@ -142,12 +183,7 @@
final Map<Element, jsAst.Expression> generatedBailoutCode =
new Map<Element, jsAst.Expression>();
- /**
- * Keep track of which function elements are simple enough to be
- * inlined in callers.
- */
- final Map<FunctionElement, bool> canBeInlined =
- new Map<FunctionElement, bool>();
+ FunctionInlineCache inlineCache = new FunctionInlineCache();
ClassElement jsInterceptorClass;
ClassElement jsStringClass;
@@ -436,9 +472,9 @@
compiler.findHelper(const SourceString('defineNativeMethodsFinish'));
// These methods are overwritten with generated versions.
- canBeInlined[getInterceptorMethod] = false;
- canBeInlined[getDispatchPropertyMethod] = false;
- canBeInlined[setDispatchPropertyMethod] = false;
+ inlineCache.markAsNonInlinable(getInterceptorMethod, insideLoop: true);
+ inlineCache.markAsNonInlinable(getDispatchPropertyMethod, insideLoop: true);
+ inlineCache.markAsNonInlinable(setDispatchPropertyMethod, insideLoop: true);
List<ClassElement> classes = [
jsInterceptorClass =
@@ -672,7 +708,7 @@
void registerUseInterceptor(Enqueuer enqueuer) {
assert(!enqueuer.isResolutionQueue);
- if (!enqueuer.nativeEnqueuer.hasNativeClasses()) return;
+ if (!enqueuer.nativeEnqueuer.hasInstantiatedNativeClasses()) return;
enqueuer.registerStaticUse(getNativeInterceptorMethod);
enqueuer.registerStaticUse(defineNativeMethodsFinishMethod);
enqueuer.registerStaticUse(initializeDispatchPropertyMethod);
@@ -1393,6 +1429,8 @@
bool retainName(SourceString name) => mustPreserveNames;
+ bool get rememberLazies => isTreeShakingDisabled;
+
bool retainMetadataOf(Element element) {
if (mustRetainMetadata) {
// TODO(ahe): This is a little hacky, but I'll have to rewrite this when
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart b/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart
index 7b04eb2..281a07a 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart
@@ -82,6 +82,7 @@
final List<ClassElement> nativeClasses = <ClassElement>[];
final List<Selector> trivialNsmHandlers = <Selector>[];
final Map<String, String> mangledFieldNames = <String, String>{};
+ final Map<String, String> mangledGlobalFieldNames = <String, String>{};
final Set<String> recordedMangledNames = new Set<String>();
final Set<String> interceptorInvocationNames = new Set<String>();
@@ -137,6 +138,16 @@
Set<FunctionType> checkedNonGenericFunctionTypes =
new Set<FunctionType>();
+ /**
+ * For classes and libraries, record code for static/top-level members.
+ * Later, this code is emitted when the class or library is emitted.
+ * See [bufferForElement].
+ */
+ // TODO(ahe): Generate statics with their class, and store only libraries in
+ // this map.
+ final Map<Element, List<CodeBuffer>> elementBuffers =
+ new Map<Element, List<CodeBuffer>>();
+
void registerDynamicFunctionTypeCheck(FunctionType functionType) {
ClassElement classElement = Types.getClassContext(functionType);
if (classElement != null) {
@@ -586,30 +597,39 @@
' $longNamesConstant'));
}
- String sliceOffset = '," + (j < $firstNormalSelector ? 1 : 0)';
- if (firstNormalSelector == 0) sliceOffset = '"';
- if (firstNormalSelector == shorts.length) sliceOffset = ', 1"';
+ String sliceOffset = ', (j < $firstNormalSelector) ? 1 : 0';
+ if (firstNormalSelector == 0) sliceOffset = '';
+ if (firstNormalSelector == shorts.length) sliceOffset = ', 1';
String whatToPatch = nativeEmitter.handleNoSuchMethod ?
"Object.prototype" :
"objectClassObject";
+ var params = ['name', 'short', 'type'];
+ var sliceOffsetParam = '';
+ var slice = 'Array.prototype.slice.call';
+ if (!sliceOffset.isEmpty) {
+ sliceOffsetParam = ', sliceOffset';
+ params.add('sliceOffset');
+ }
statements.addAll([
js.for_('var j = 0', 'j < shortNames.length', 'j++', [
js('var type = 0'),
js('var short = shortNames[j]'),
js.if_('short[0] == "${namer.getterPrefix[0]}"', js('type = 1')),
js.if_('short[0] == "${namer.setterPrefix[0]}"', js('type = 2')),
- js('$whatToPatch[short] = Function("'
- 'return this.$noSuchMethodName('
- 'this,'
- '${namer.CURRENT_ISOLATE}.$createInvocationMirror(\'"'
- ' + ${minify ? "shortNames" : "longNames"}[j]'
- ' + "\',\'" + short + "\',"'
- ' + type'
- ' + ",Array.prototype.slice.call(arguments'
- '$sliceOffset'
- ' + "),[]))")')
+ // Generate call to:
+ // createInvocationMirror(String name, internalName, type, arguments,
+ // argumentNames)
+ js('$whatToPatch[short] = #(${minify ? "shortNames" : "longNames"}[j], '
+ 'short, type$sliceOffset)',
+ js.fun(params, [js.return_(js.fun([],
+ [js.return_(js(
+ 'this.$noSuchMethodName('
+ 'this, '
+ '${namer.CURRENT_ISOLATE}.$createInvocationMirror('
+ 'name, short, type, '
+ '$slice(arguments$sliceOffsetParam), []))'))]))]))
])
]);
}
@@ -821,8 +841,8 @@
js('var isolatePrototype = oldIsolate.prototype'),
js('var str = "{\\n"'),
- js('str += '
- '"var properties = $isolate.${namer.isolatePropertiesName};\\n"'),
+ js('str += "var properties = '
+ 'arguments.callee.${namer.isolatePropertiesName};\\n"'),
js('var hasOwnProperty = Object.prototype.hasOwnProperty'),
// for (var staticName in isolateProperties) {
@@ -856,7 +876,7 @@
var parameters = <String>['prototype', 'staticName', 'fieldName',
'getterName', 'lazyValue'];
return js.fun(parameters, [
- js('var getter = new Function("{ return $isolate." + fieldName + ";}")'),
+ js('var getter = new Function("{ return this." + fieldName + ";}")'),
]..addAll(addLazyInitializerLogic())
);
}
@@ -864,8 +884,14 @@
List addLazyInitializerLogic() {
String isolate = namer.CURRENT_ISOLATE;
String cyclicThrow = namer.isolateAccess(backend.getCyclicThrowHelper());
+ var lazies = [];
+ if (backend.rememberLazies) {
+ lazies = [
+ js.if_('!init.lazies', js('init.lazies = {}')),
+ js('init.lazies[fieldName] = getterName')];
+ }
- return [
+ return lazies..addAll([
js('var sentinelUndefined = {}'),
js('var sentinelInProgress = {}'),
js('prototype[fieldName] = sentinelUndefined'),
@@ -908,7 +934,7 @@
js('$isolate[getterName] = getter')
])
]))
- ];
+ ]);
}
List buildDefineClassAndFinishClassFunctionsIfNecessary() {
@@ -1410,6 +1436,8 @@
// Add checks to the constructors of instantiated classes.
for (ClassElement cls in typeChecks) {
+ // TODO(9556). The properties added to 'holder' should be generated
+ // directly as properties of the class object, not added later.
String holder = namer.isolateAccess(backend.getImplementationClass(cls));
for (TypeCheck check in typeChecks[cls]) {
ClassElement cls = check.cls;
@@ -1435,11 +1463,31 @@
}
/**
+ * Returns the classes with constructors used as a 'holder' in
+ * [emitRuntimeTypeSupport].
+ * TODO(9556): Some cases will go away when the class objects are created as
+ * complete. Not all classes will go away while constructors are referenced
+ * from type substitutions.
+ */
+ Set<ClassElement> classesModifiedByEmitRuntimeTypeSupport() {
+ TypeChecks typeChecks = backend.rti.requiredChecks;
+ Set<ClassElement> result = new Set<ClassElement>();
+ for (ClassElement cls in typeChecks) {
+ for (TypeCheck check in typeChecks[cls]) {
+ result.add(backend.getImplementationClass(cls));
+ break;
+ }
+ }
+ return result;
+ }
+
+ /**
* Documentation wanted -- johnniwinther
*
* Invariant: [classElement] must be a declaration element.
*/
void visitClassFields(ClassElement classElement,
+ bool visitStatics,
void addField(Element member,
String name,
String accessorName,
@@ -1506,18 +1554,22 @@
}
}
- // TODO(kasperl): We should make sure to only emit one version of
- // overridden fields. Right now, we rely on the ordering so the
- // fields pulled in from mixins are replaced with the fields from
- // the class definition.
+ if (visitStatics) {
+ classElement.implementation.forEachStaticField(visitField);
+ } else {
+ // TODO(kasperl): We should make sure to only emit one version of
+ // overridden fields. Right now, we rely on the ordering so the
+ // fields pulled in from mixins are replaced with the fields from
+ // the class definition.
- // If a class is not instantiated then we add the field just so we can
- // generate the field getter/setter dynamically. Since this is only
- // allowed on fields that are in [classElement] we don't need to visit
- // superclasses for non-instantiated classes.
- classElement.implementation.forEachInstanceField(
- visitField,
- includeSuperAndInjectedMembers: isInstantiated);
+ // If a class is not instantiated then we add the field just so we can
+ // generate the field getter/setter dynamically. Since this is only
+ // allowed on fields that are in [classElement] we don't need to visit
+ // superclasses for non-instantiated classes.
+ classElement.implementation.forEachInstanceField(
+ visitField,
+ includeSuperAndInjectedMembers: isInstantiated);
+ }
}
void generateGetter(Element member, String fieldName, String accessorName,
@@ -1545,6 +1597,8 @@
}
bool canGenerateCheckedSetter(Element member) {
+ // We never generate accessors for top-level/static fields.
+ if (!member.isInstanceMember()) return false;
DartType type = member.computeType(compiler).unalias(compiler);
if (type.element.isTypeVariable() ||
(type is FunctionType && type.containsTypeVariables) ||
@@ -1603,9 +1657,16 @@
String accessorName,
String memberName) {
if (!backend.retainGetter(member)) return;
- String previousName = mangledFieldNames.putIfAbsent(
- '${namer.getterPrefix}$accessorName',
- () => memberName);
+ String previousName;
+ if (member.isInstanceMember()) {
+ previousName = mangledFieldNames.putIfAbsent(
+ '${namer.getterPrefix}$accessorName',
+ () => memberName);
+ } else {
+ previousName = mangledGlobalFieldNames.putIfAbsent(
+ accessorName,
+ () => memberName);
+ }
assert(invariant(member, previousName == memberName,
message: '$previousName != ${memberName}'));
}
@@ -1614,26 +1675,30 @@
bool emitClassFields(ClassElement classElement,
ClassBuilder builder,
String superName,
- { bool classIsNative: false }) {
+ { bool classIsNative: false,
+ bool emitStatics: false }) {
assert(superName != null);
String separator = '';
String nativeName = namer.getPrimitiveInterceptorRuntimeName(classElement);
StringBuffer buffer = new StringBuffer();
- if (nativeName != null) {
- buffer.write('$nativeName/');
+ if (!emitStatics) {
+ if (nativeName != null) {
+ buffer.write('$nativeName/');
+ }
+ buffer.write('$superName;');
}
- buffer.write('$superName;');
int bufferClassLength = buffer.length;
var fieldMetadata = [];
bool hasMetadata = false;
- visitClassFields(classElement, (Element member,
- String name,
- String accessorName,
- bool needsGetter,
- bool needsSetter,
- bool needsCheckedSetter) {
+ visitClassFields(classElement, emitStatics,
+ (Element member,
+ String name,
+ String accessorName,
+ bool needsGetter,
+ bool needsSetter,
+ bool needsCheckedSetter) {
// Ignore needsCheckedSetter - that is handled below.
bool needsAccessor = (needsGetter || needsSetter);
// We need to output the fields for non-native classes so we can auto-
@@ -1675,7 +1740,7 @@
// TODO(sra): 'isInterceptorClass' might not be the correct test for
// methods forced to use the interceptor convention because the
// method's class was elsewhere mixed-in to an interceptor.
- assert(getterCode != 0);
+ assert(!member.isInstanceMember() || getterCode != 0);
}
int setterCode = 0;
if (needsSetter) {
@@ -1684,7 +1749,7 @@
// 11: function(receiver, value) { this.field = value; }
setterCode += backend.fieldHasInterceptedSetter(member) ? 2 : 0;
setterCode += backend.isInterceptorClass(classElement) ? 0 : 1;
- assert(setterCode != 0);
+ assert(!member.isInstanceMember() || setterCode != 0);
}
int code = getterCode + (setterCode << 2);
if (code == 0) {
@@ -1711,12 +1776,13 @@
void emitClassGettersSetters(ClassElement classElement,
ClassBuilder builder) {
- visitClassFields(classElement, (Element member,
- String name,
- String accessorName,
- bool needsGetter,
- bool needsSetter,
- bool needsCheckedSetter) {
+ visitClassFields(classElement, false,
+ (Element member,
+ String name,
+ String accessorName,
+ bool needsGetter,
+ bool needsSetter,
+ bool needsCheckedSetter) {
compiler.withCurrentElement(member, () {
if (needsCheckedSetter) {
assert(!needsSetter);
@@ -1775,6 +1841,36 @@
}
emitIsTests(classElement, builder);
+ List<CodeBuffer> classBuffers = elementBuffers[classElement];
+ if (classBuffers == null) {
+ classBuffers = [];
+ } else {
+ elementBuffers.remove(classElement);
+ }
+ CodeBuffer statics = new CodeBuffer();
+ statics.write('{$n');
+ bool hasStatics = false;
+ ClassBuilder staticsBuilder = new ClassBuilder();
+ if (emitClassFields(
+ classElement, staticsBuilder, superName, emitStatics: true)) {
+ hasStatics = true;
+ statics.write('"":$_');
+ statics.write(
+ jsAst.prettyPrint(staticsBuilder.properties.single.value, compiler));
+ statics.write(',$n');
+ }
+ for (CodeBuffer classBuffer in classBuffers) {
+ // TODO(ahe): What about deferred?
+ if (classBuffer != null) {
+ hasStatics = true;
+ statics.addBuffer(classBuffer);
+ }
+ }
+ statics.write('}$n');
+ if (hasStatics) {
+ builder.addProperty('static', new jsAst.Blob(statics));
+ }
+
// TODO(ahe): This method (generateClass) should return a jsAst.Expression.
if (!buffer.isEmpty) {
buffer.write(',$n$n');
@@ -1993,6 +2089,8 @@
* that needs to be emitted.
*/
Function computeClassFilter() {
+ if (backend.isTreeShakingDisabled) return (ClassElement cls) => true;
+
Set<ClassElement> unneededClasses = new Set<ClassElement>();
// The [Bool] class is not marked as abstract, but has a factory
// constructor that always throws. We never need to emit it.
@@ -2008,14 +2106,7 @@
);
// Add interceptors referenced by constants.
- ConstantHandler handler = compiler.constantHandler;
- List<Constant> constants = handler.getConstantsForEmission();
- for (Constant constant in constants) {
- if (constant is InterceptorConstant) {
- InterceptorConstant inceptorConstant = constant;
- needed.add(inceptorConstant.dispatchedType.element);
- }
- }
+ needed.addAll(interceptorsReferencedFromConstants());
// Add unneeded interceptors to the [unneededClasses] set.
for (ClassElement interceptor in backend.interceptedClasses) {
@@ -2028,6 +2119,19 @@
return (ClassElement cls) => !unneededClasses.contains(cls);
}
+ Set<ClassElement> interceptorsReferencedFromConstants() {
+ Set<ClassElement> classes = new Set<ClassElement>();
+ ConstantHandler handler = compiler.constantHandler;
+ List<Constant> constants = handler.getConstantsForEmission();
+ for (Constant constant in constants) {
+ if (constant is InterceptorConstant) {
+ InterceptorConstant interceptorConstant = constant;
+ classes.add(interceptorConstant.dispatchedType.element);
+ }
+ }
+ return classes;
+ }
+
void emitFinishClassesInvocationIfNecessary(CodeBuffer buffer) {
if (needsDefineClass) {
buffer.write('$finishClassesName($classesCollector,'
@@ -2846,7 +2950,8 @@
if (classes == backend.interceptedClasses) {
// I.e. this is the general interceptor.
- hasNative = compiler.enqueuer.codegen.nativeEnqueuer.hasNativeClasses();
+ hasNative = compiler.enqueuer.codegen.nativeEnqueuer
+ .hasInstantiatedNativeClasses();
}
jsAst.Block block = new jsAst.Block.empty();
@@ -3366,12 +3471,19 @@
mainBuffer.add(buildGeneratedBy());
addComment(HOOKS_API_USAGE, mainBuffer);
+
+ if (!areAnyElementsDeferred) {
+ mainBuffer.add('(function(${namer.CURRENT_ISOLATE})$_{$n');
+ }
+
mainBuffer.add('function ${namer.isolateName}()$_{}\n');
mainBuffer.add('init()$N$n');
// Shorten the code by using [namer.CURRENT_ISOLATE] as temporary.
isolateProperties = namer.CURRENT_ISOLATE;
mainBuffer.add(
- 'var $isolateProperties$_=$_$isolatePropertiesName$N');
+ '$isolateProperties$_=$_$isolatePropertiesName$N');
+
+ emitStaticFunctions(mainBuffer);
if (!regularClasses.isEmpty ||
!deferredClasses.isEmpty ||
@@ -3427,9 +3539,7 @@
// the classesCollector variable.
classesCollector = 'classesCollector should not be used from now on';
- emitStaticFunctions(mainBuffer);
-
- if (!libraryBuffers.isEmpty) {
+ if (!elementBuffers.isEmpty) {
var oldClassesCollector = classesCollector;
classesCollector = r"$$";
if (compiler.enableMinification) {
@@ -3451,13 +3561,44 @@
mainBuffer.write(';');
}
}
+ if (!mangledGlobalFieldNames.isEmpty) {
+ var keys = mangledGlobalFieldNames.keys.toList();
+ keys.sort();
+ var properties = [];
+ for (String key in keys) {
+ var value = js.string('${mangledGlobalFieldNames[key]}');
+ properties.add(new jsAst.Property(js.string(key), value));
+ }
+ var map = new jsAst.ObjectInitializer(properties);
+ mainBuffer.write(
+ jsAst.prettyPrint(
+ js('init.mangledGlobalNames = #', map).toStatement(),
+ compiler));
+ if (compiler.enableMinification) {
+ mainBuffer.write(';');
+ }
+ }
mainBuffer
..write(getReflectionDataParser())
..write('([$n');
- var sortedLibraries = Elements.sortedByPosition(libraryBuffers.keys);
- for (LibraryElement library in sortedLibraries) {
- List<CodeBuffer> buffers = libraryBuffers[library];
+ List<Element> sortedElements =
+ Elements.sortedByPosition(elementBuffers.keys);
+ bool hasPendingStatics = false;
+ for (Element element in sortedElements) {
+ if (!element.isLibrary()) {
+ for (CodeBuffer b in elementBuffers[element]) {
+ if (b != null) {
+ hasPendingStatics = true;
+ compiler.reportInfo(
+ element, MessageKind.GENERIC, {'text': 'Pending statics.'});
+ print(b.getText());
+ }
+ }
+ continue;
+ }
+ LibraryElement library = element;
+ List<CodeBuffer> buffers = elementBuffers[library];
var buffer = buffers[0];
var uri = library.canonicalUri;
if (uri.scheme == 'file' && compiler.sourceMapUri != null) {
@@ -3489,7 +3630,10 @@
..addBuffer(buffer)
..write('}],$n');
}
- libraryBuffers[library] = const [];
+ elementBuffers[library] = const [];
+ }
+ if (hasPendingStatics) {
+ compiler.internalError('Pending statics (see above).');
}
mainBuffer.write('])$N');
@@ -3519,14 +3663,17 @@
isolateProperties = isolatePropertiesName;
// The following code should not use the short-hand for the
// initialStatics.
- mainBuffer.add('var ${namer.CURRENT_ISOLATE}$_=${_}null$N');
+ mainBuffer.add('${namer.CURRENT_ISOLATE}$_=${_}null$N');
emitFinishIsolateConstructorInvocation(mainBuffer);
- mainBuffer.add('var ${namer.CURRENT_ISOLATE}$_='
- '${_}new ${namer.isolateName}()$N');
+ mainBuffer.add(
+ '${namer.CURRENT_ISOLATE}$_=${_}new ${namer.isolateName}()$N');
emitMain(mainBuffer);
emitInitFunction(mainBuffer);
+ if (!areAnyElementsDeferred) {
+ mainBuffer.add('})()$n');
+ }
compiler.assembledCode = mainBuffer.getText();
outputSourceMap(mainBuffer, compiler.assembledCode, '');
@@ -3536,13 +3683,24 @@
return compiler.assembledCode;
}
- final Map<LibraryElement, List<CodeBuffer>> libraryBuffers =
- new Map<LibraryElement, List<CodeBuffer>>();
-
CodeBuffer bufferForElement(Element element, CodeBuffer eagerBuffer) {
- LibraryElement library = element.getLibrary();
- List<CodeBuffer> buffers = libraryBuffers.putIfAbsent(
- library, () => <CodeBuffer>[null, null]);
+ Element owner = element.getLibrary();
+ if (!element.isTopLevel() && !element.isNative()) {
+ // For static (not top level) elements, record their code in a buffer
+ // specific to the class. For now, not supported for native classes and
+ // native elements.
+ ClassElement cls =
+ element.getEnclosingClassOrCompilationUnit().declaration;
+ if (compiler.codegenWorld.instantiatedClasses.contains(cls)
+ && !cls.isNative()) {
+ owner = cls;
+ }
+ }
+ if (owner == null) {
+ compiler.internalErrorOnElement(element, 'Owner is null');
+ }
+ List<CodeBuffer> buffers = elementBuffers.putIfAbsent(
+ owner, () => <CodeBuffer>[null, null]);
bool deferred = isDeferred(element);
int index = deferred ? 1 : 0;
CodeBuffer buffer = buffers[index];
@@ -3650,6 +3808,10 @@
return compiler.deferredLoadTask.isDeferred(element);
}
+ bool get areAnyElementsDeferred {
+ return compiler.deferredLoadTask.areAnyElementsDeferred;
+ }
+
// TODO(ahe): Remove this when deferred loading is fully implemented.
void warnNotImplemented(Element element, String message) {
compiler.reportMessage(compiler.spanFromSpannable(element),
@@ -3659,11 +3821,13 @@
// TODO(ahe): This code should be integrated in finishClasses.
String getReflectionDataParser() {
+ String metadataField = '"${namer.metadataField}"';
return '''
(function (reflectionData) {
if (!init.libraries) init.libraries = [];
if (!init.mangledNames) init.mangledNames = {};
if (!init.mangledGlobalNames) init.mangledGlobalNames = {};
+ if (!init.statics) init.statics = {};
init.getterPrefix = "${namer.getterPrefix}";
init.setterPrefix = "${namer.setterPrefix}";
var libraries = init.libraries;
@@ -3679,39 +3843,44 @@
var descriptor = data[3];
var classes = [];
var functions = [];
- for (var property in descriptor) {
- if (!hasOwnProperty.call(descriptor, property)) continue;
- var element = descriptor[property];
- var firstChar = property.substring(0, 1);
- var previousProperty;
- if (firstChar == "+") {
- mangledGlobalNames[previousProperty] = property.substring(1);
- } else if (firstChar == "@") {
- property = property.substring(1);
- ${namer.CURRENT_ISOLATE}[property]["${namer.metadataField}"] = element;
- } else if (typeof element === "function") {
- ${namer.CURRENT_ISOLATE}[previousProperty = property] = element;
- functions.push(property);
- } else {
- previousProperty = property;
- var newDesc = {};
- var previousProp;
- for (var prop in element) {
- if (!hasOwnProperty.call(element, prop)) continue;
- firstChar = prop.substring(0, 1);
- if (firstChar == "+") {
- mangledNames[previousProp] = prop.substring(1);
- } else if (firstChar == "@" && prop != "@") {
- newDesc[prop.substring(1)]["${namer.metadataField}"] ='''
-'''element[prop];
- } else {
- newDesc[previousProp = prop] = element[prop];
+ function processStatics(descriptor) {
+ for (var property in descriptor) {
+ if (!hasOwnProperty.call(descriptor, property)) continue;
+ if (property === "") continue;
+ var element = descriptor[property];
+ var firstChar = property.substring(0, 1);
+ var previousProperty;
+ if (firstChar === "+") {
+ mangledGlobalNames[previousProperty] = property.substring(1);
+ } else if (firstChar === "@") {
+ property = property.substring(1);
+ ${namer.CURRENT_ISOLATE}[property][$metadataField] = element;
+ } else if (typeof element === "function") {
+ ${namer.CURRENT_ISOLATE}[previousProperty = property] = element;
+ functions.push(property);
+ } else {
+ previousProperty = property;
+ var newDesc = {};
+ var previousProp;
+ for (var prop in element) {
+ if (!hasOwnProperty.call(element, prop)) continue;
+ firstChar = prop.substring(0, 1);
+ if (prop === "static") {
+ processStatics(init.statics[property] = element[prop]);
+ } else if (firstChar === "+") {
+ mangledNames[previousProp] = prop.substring(1);
+ } else if (firstChar === "@" && prop !== "@") {
+ newDesc[prop.substring(1)][$metadataField] = element[prop];
+ } else {
+ newDesc[previousProp = prop] = element[prop];
+ }
}
+ $classesCollector[property] = newDesc;
+ classes.push(property);
}
- $classesCollector[property] = newDesc;
- classes.push(property);
}
}
+ processStatics(descriptor);
libraries.push([name, uri, classes, functions, metadata]);
}
})''';
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/emitter_no_eval.dart b/sdk/lib/_internal/compiler/implementation/js_backend/emitter_no_eval.dart
index ebdb9fd..a0f3d01 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/emitter_no_eval.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/emitter_no_eval.dart
@@ -37,7 +37,8 @@
bool emitClassFields(ClassElement classElement,
ClassBuilder builder,
String superName,
- { bool classIsNative: false }) {
+ { bool classIsNative: false,
+ bool emitStatics: false }) {
// Class fields are dynamically generated so they have to be
// emitted using getters and setters instead.
return false;
@@ -53,12 +54,13 @@
// get$d : function() { return this.d; }
// set$d : function(x) { this.d = x; }
List<String> fields = <String>[];
- visitClassFields(classElement, (Element member,
- String name,
- String accessorName,
- bool needsGetter,
- bool needsSetter,
- bool needsCheckedSetter) {
+ visitClassFields(classElement, false,
+ (Element member,
+ String name,
+ String accessorName,
+ bool needsGetter,
+ bool needsSetter,
+ bool needsCheckedSetter) {
fields.add(name);
});
String constructorName = namer.safeName(classElement.name.slowToString());
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/native_emitter.dart b/sdk/lib/_internal/compiler/implementation/js_backend/native_emitter.dart
index 3f29f71..6538cf2 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/native_emitter.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/native_emitter.dart
@@ -152,6 +152,11 @@
Set<ClassElement> nonleafClasses = new Set<ClassElement>();
neededClasses.add(compiler.objectClass);
+ Set<ClassElement> neededByConstant =
+ emitter.interceptorsReferencedFromConstants();
+ Set<ClassElement> modifiedClasses =
+ emitter.classesModifiedByEmitRuntimeTypeSupport();
+
for (ClassElement classElement in preOrder.reversed) {
// Post-order traversal ensures we visit the subclasses before their
// superclass. This makes it easy to tell if a class is needed because a
@@ -165,10 +170,11 @@
needed = true;
} else if (!builder.isTrivial) {
needed = true;
- } else {
- // TODO(9556): We can't remove any unneeded classes until the class
- // builders contain all the information. [emitRuntimeTypeSupport] must
- // no longer add information to a class definition.
+ } else if (neededByConstant.contains(classElement)) {
+ needed = true;
+ } else if (modifiedClasses.contains(classElement)) {
+ // TODO(9556): Remove this test when [emitRuntimeTypeSupport] no longer
+ // adds information to a class prototype or constructor.
needed = true;
}
@@ -207,21 +213,23 @@
}
}
- // Emit code to set up dispatch data that maps tags to the interceptors.
-
- void generateDefines(ClassElement classElement) {
- generateDefineNativeMethods(leafTags[classElement], classElement,
- defineNativeMethodsName);
- generateDefineNativeMethods(nonleafTags[classElement], classElement,
- defineNativeMethodsNonleafName);
- }
- generateDefines(backend.jsInterceptorClass);
- for (ClassElement classElement in classes) {
- generateDefines(classElement);
+ // Emit code to set up dispatch data that maps tags to the interceptors, but
+ // only if native classes are actually instantiated.
+ if (compiler.enqueuer.codegen.nativeEnqueuer
+ .hasInstantiatedNativeClasses()) {
+ void generateDefines(ClassElement classElement) {
+ generateDefineNativeMethods(leafTags[classElement], classElement,
+ defineNativeMethodsName);
+ generateDefineNativeMethods(nonleafTags[classElement], classElement,
+ defineNativeMethodsNonleafName);
+ }
+ generateDefines(backend.jsInterceptorClass);
+ for (ClassElement classElement in classes) {
+ generateDefines(classElement);
+ }
}
// Emit the native class interceptors that were actually used.
-
for (ClassElement classElement in classes) {
if (neededClasses.contains(classElement)) {
ClassBuilder builder = builders[classElement];
@@ -260,7 +268,9 @@
emitter.emitInstanceMembers(classElement, builder);
emitter.emitIsTests(classElement, builder);
- if (!hasFields && builder.properties.length == propertyCount) {
+ if (!hasFields &&
+ builder.properties.length == propertyCount &&
+ superclass is! MixinApplicationElement) {
builder.isTrivial = true;
}
diff --git a/sdk/lib/_internal/compiler/implementation/native_handler.dart b/sdk/lib/_internal/compiler/implementation/native_handler.dart
index 687003a..49975b8 100644
--- a/sdk/lib/_internal/compiler/implementation/native_handler.dart
+++ b/sdk/lib/_internal/compiler/implementation/native_handler.dart
@@ -53,7 +53,7 @@
NativeBehavior getNativeBehaviorOf(Send node) => NativeBehavior.NONE;
/// Returns whether native classes are being used.
- bool hasNativeClasses() => false;
+ bool hasInstantiatedNativeClasses() => false;
/**
* Handles JS-calls, which can be an instantiation point for types.
@@ -84,7 +84,7 @@
final Set<ClassElement> pendingClasses = new Set<ClassElement>();
final Set<ClassElement> unusedClasses = new Set<ClassElement>();
- bool hasNativeClasses() => !registeredClasses.isEmpty;
+ bool hasInstantiatedNativeClasses() => !registeredClasses.isEmpty;
/**
* Records matched constraints ([SpecialType] or [DartType]). Once a type
@@ -494,6 +494,7 @@
|| libraryName == 'dart:html'
|| libraryName == 'dart:html_common'
|| libraryName == 'dart:indexed_db'
+ || libraryName == 'dart:js'
|| libraryName == 'dart:svg'
|| libraryName == 'dart:typed_data'
|| libraryName == 'dart:web_audio'
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/builder.dart b/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
index 6ba92ac..b46ef2b 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
@@ -929,9 +929,6 @@
localsHandler = new LocalsHandler(this);
}
- static const MAX_INLINING_DEPTH = 3;
- static const MAX_INLINING_NODES = 46;
-
List<InliningState> inliningStack;
Element returnElement;
@@ -1225,7 +1222,12 @@
element = element.implementation;
FunctionElement function = element;
- bool cachedCanBeInlined = backend.canBeInlined[function];
+ bool insideLoop = loopNesting > 0 || graph.calledInLoop;
+
+ // Bail out early if the inlining decision is in the cache and we can't
+ // inline (no need to check the hard constraints).
+ bool cachedCanBeInlined =
+ backend.inlineCache.canInline(function, insideLoop: insideLoop);
if (cachedCanBeInlined == false) return false;
bool meetsHardConstraints() {
@@ -1239,8 +1241,9 @@
assert(selector != null
|| Elements.isStaticOrTopLevel(element)
|| element.isGenerativeConstructorBody());
- if (selector != null && !selector.applies(function, compiler))
+ if (selector != null && !selector.applies(function, compiler)) {
return false;
+ }
// Don't inline operator== methods if the parameter can be null.
if (element.name == const SourceString('==')) {
@@ -1262,20 +1265,31 @@
return true;
}
- bool heuristicsSayGoodToGo(FunctionExpression functionExpression,
- TreeElements newElements) {
- if (loopNesting == 0 && !graph.calledInLoop) return false;
-
- int maxDepth = (loopNesting > 0) ? MAX_INLINING_DEPTH : 1;
- if (inliningStack.length >= maxDepth) return false;
-
- if (cachedCanBeInlined == null) {
- var canBeInlined =
- InlineWeeder.canBeInlined(functionExpression, newElements);
- backend.canBeInlined[function] = canBeInlined;
- return canBeInlined;
+ bool heuristicSayGoodToGo(FunctionExpression functionExpression) {
+ // Don't inline recursivly
+ if (inliningStack.any((entry) => entry.function == function)) {
+ return false;
}
- return cachedCanBeInlined;
+
+ if (cachedCanBeInlined == true) return cachedCanBeInlined;
+
+ int numParameters = function.functionSignature.parameterCount;
+ int maxInliningNodes;
+ if (insideLoop) {
+ maxInliningNodes = InlineWeeder.INLINING_NODES_INSIDE_LOOP +
+ InlineWeeder.INLINING_NODES_INSIDE_LOOP_ARG_FACTOR * numParameters;
+ } else {
+ maxInliningNodes = InlineWeeder.INLINING_NODES_OUTSIDE_LOOP +
+ InlineWeeder.INLINING_NODES_OUTSIDE_LOOP_ARG_FACTOR * numParameters;
+ }
+ bool canBeInlined = InlineWeeder.canBeInlined(
+ functionExpression, maxInliningNodes);
+ if (canBeInlined) {
+ backend.inlineCache.markAsInlinable(element, insideLoop: insideLoop);
+ } else {
+ backend.inlineCache.markAsNonInlinable(element, insideLoop: insideLoop);
+ }
+ return canBeInlined;
}
void doInlining(FunctionExpression functionExpression) {
@@ -1307,13 +1321,8 @@
if (meetsHardConstraints()) {
FunctionExpression functionExpression = function.parseNode(compiler);
- TreeElements newElements =
- compiler.enqueuer.resolution.getCachedElements(function);
- if (newElements == null) {
- compiler.internalError("Element not resolved: $function");
- }
- if (heuristicsSayGoodToGo(functionExpression, newElements)) {
+ if (heuristicSayGoodToGo(functionExpression)) {
doInlining(functionExpression);
return true;
}
@@ -5125,25 +5134,29 @@
* finds whether it is too difficult to inline.
*/
class InlineWeeder extends Visitor {
- final TreeElements elements;
+ // Invariant: *INSIDE_LOOP* > *OUTSIDE_LOOP*
+ static const INLINING_NODES_OUTSIDE_LOOP = 18;
+ static const INLINING_NODES_OUTSIDE_LOOP_ARG_FACTOR = 3;
+ static const INLINING_NODES_INSIDE_LOOP = 42;
+ static const INLINING_NODES_INSIDE_LOOP_ARG_FACTOR = 4;
bool seenReturn = false;
bool tooDifficult = false;
int nodeCount = 0;
+ final int maxInliningNodes;
- InlineWeeder(this.elements);
+ InlineWeeder(this.maxInliningNodes);
static bool canBeInlined(FunctionExpression functionExpression,
- TreeElements elements) {
- InlineWeeder weeder = new InlineWeeder(elements);
+ int maxInliningNodes) {
+ InlineWeeder weeder = new InlineWeeder(maxInliningNodes);
weeder.visit(functionExpression.initializers);
weeder.visit(functionExpression.body);
- if (weeder.tooDifficult) return false;
- return true;
+ return !weeder.tooDifficult;
}
bool registerNode() {
- if (nodeCount++ > SsaBuilder.MAX_INLINING_NODES) {
+ if (nodeCount++ > maxInliningNodes) {
tooDifficult = true;
return false;
} else {
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart b/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart
index 23e9d32..be46135 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart
@@ -620,6 +620,7 @@
* information on [to], and that dominates the user.
*/
void rewriteWithBetterUser(HInstruction from, HInstruction to) {
+ // BUG(11841): Turn this method into a phase to be run after GVN phases.
Link<HCheck> better = const Link<HCheck>();
for (HInstruction user in to.usedBy) {
if (user == from || user is! HCheck) continue;
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/value_range_analyzer.dart b/sdk/lib/_internal/compiler/implementation/ssa/value_range_analyzer.dart
index 42560e0..7cddf8f 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/value_range_analyzer.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/value_range_analyzer.dart
@@ -615,6 +615,11 @@
Range visitPhi(HPhi phi) {
if (!phi.isInteger()) return info.newUnboundRange();
+ // Some phases may replace instructions that change the inputs of
+ // this phi. Only the [SsaTypesPropagation] phase will update the
+ // phi type. Play it safe by assuming the [SsaTypesPropagation]
+ // phase is not necessarily run before the [ValueRangeAnalyzer].
+ if (phi.inputs.any((i) => !i.isInteger())) return info.newUnboundRange();
if (phi.block.isLoopHeader()) {
Range range = tryInferLoopPhiRange(phi);
if (range == null) return info.newUnboundRange();
diff --git a/sdk/lib/_internal/compiler/implementation/types/container_tracer.dart b/sdk/lib/_internal/compiler/implementation/types/container_tracer.dart
index 4913c8b..92f69e7 100644
--- a/sdk/lib/_internal/compiler/implementation/types/container_tracer.dart
+++ b/sdk/lib/_internal/compiler/implementation/types/container_tracer.dart
@@ -161,7 +161,7 @@
analysisCount++;
}
- if (!continueAnalyzing) return inferrer.dynamicType;
+ if (!continueAnalyzing) return compiler.typesTask.dynamicType;
// [potentialType] can be null if we did not find any instruction
// that adds elements to the list.
@@ -187,7 +187,7 @@
potentialType = potentialType == null
? newType
: newType.union(potentialType, compiler);
- if (potentialType == inferrer.dynamicType) {
+ if (potentialType == compiler.typesTask.dynamicType) {
bailout('Moved to dynamic');
}
}
@@ -233,7 +233,7 @@
print('Bailout on $analyzedNode $startElement because of $reason');
}
continueAnalyzing = false;
- return inferrer.dynamicType;
+ return compiler.typesTask.dynamicType;
}
bool couldBeTheList(resolved) {
@@ -306,6 +306,8 @@
if (!indices.isEmpty) {
Iterable<Element> callees;
if (callee is Element) {
+ // No need to go further, we know the call will throw.
+ if (callee.isErroneous()) return false;
callees = [callee];
} else {
assert(callee is Selector);
@@ -354,11 +356,11 @@
visitingInitializers = false;
visit(node.body);
}
- return inferrer.functionType;
+ return compiler.typesTask.functionType;
}
TypeMask visitLiteralList(LiteralList node) {
- if (node.isConst()) return inferrer.constListType;
+ if (node.isConst()) return compiler.typesTask.constListType;
if (tracer.couldBeTheList(node)) {
escaping = true;
for (Node element in node.elements.nodes) {
@@ -367,7 +369,7 @@
} else {
node.visitChildren(this);
}
- return inferrer.growableListType;
+ return compiler.typesTask.growableListType;
}
// TODO(ngeoffray): Try to move the following two methods in
@@ -415,7 +417,7 @@
bool isIndexEscaping = false;
bool isValueEscaping = false;
if (isIncrementOrDecrement) {
- rhsType = inferrer.intType;
+ rhsType = compiler.typesTask.intType;
if (node.isIndex) {
isIndexEscaping = visitAndCatchEscaping(() {
indexType = visit(node.arguments.head);
@@ -464,7 +466,7 @@
} else if (isReceiver) {
if (setterSelector.name == const SourceString('length')) {
// Changing the length.
- tracer.unionPotentialTypeWith(inferrer.nullType);
+ tracer.unionPotentialTypeWith(compiler.typesTask.nullType);
}
} else if (isValueEscaping) {
if (element != null
@@ -518,7 +520,7 @@
} else if (element.isFunction()) {
return inferrer.getReturnTypeOfElement(element);
} else {
- return inferrer.dynamicType;
+ return compiler.typesTask.dynamicType;
}
}
@@ -530,14 +532,14 @@
if (tracer.couldBeTheList(node)) {
escaping = true;
}
- return inferrer.growableListType;
+ return compiler.typesTask.growableListType;
} else if (Elements.isFixedListConstructorCall(element, node, compiler)) {
- tracer.unionPotentialTypeWith(inferrer.nullType);
+ tracer.unionPotentialTypeWith(compiler.typesTask.nullType);
visitArguments(node.arguments, element);
if (tracer.couldBeTheList(node)) {
escaping = true;
}
- return inferrer.fixedListType;
+ return compiler.typesTask.fixedListType;
} else if (Elements.isFilledListConstructorCall(element, node, compiler)) {
if (tracer.couldBeTheList(node)) {
escaping = true;
@@ -547,7 +549,7 @@
} else {
visitArguments(node.arguments, element);
}
- return inferrer.fixedListType;
+ return compiler.typesTask.fixedListType;
}
bool isEscaping = visitArguments(node.arguments, element);
@@ -564,7 +566,7 @@
return inferrer.getReturnTypeOfElement(element);
} else {
// Closure call or unresolved.
- return inferrer.dynamicType;
+ return compiler.typesTask.dynamicType;
}
}
@@ -579,9 +581,9 @@
} else if (Elements.isInstanceSend(node, elements)) {
return visitDynamicSend(node);
} else if (Elements.isStaticOrTopLevelFunction(element)) {
- return inferrer.functionType;
+ return compiler.typesTask.functionType;
} else if (Elements.isErroneousElement(element)) {
- return inferrer.dynamicType;
+ return compiler.typesTask.dynamicType;
} else if (Elements.isLocal(element)) {
if (tracer.couldBeTheList(element)) {
escaping = true;
@@ -589,7 +591,7 @@
return locals.use(element);
} else {
node.visitChildren(this);
- return inferrer.dynamicType;
+ return compiler.typesTask.dynamicType;
}
}
@@ -600,7 +602,7 @@
visitArguments(node.arguments, elements.getSelector(node));
if (isEscaping) return tracer.bailout('Passed to a closure');
- return inferrer.dynamicType;
+ return compiler.typesTask.dynamicType;
}
TypeMask visitDynamicSend(Send node) {
@@ -645,7 +647,7 @@
TypeMask visitReturn(Return node) {
if (node.expression == null) {
- return inferrer.nullType;
+ return compiler.typesTask.nullType;
}
TypeMask type;
diff --git a/sdk/lib/_internal/compiler/implementation/types/inferrer_visitor.dart b/sdk/lib/_internal/compiler/implementation/types/inferrer_visitor.dart
index 9878bf2..eb82a47 100644
--- a/sdk/lib/_internal/compiler/implementation/types/inferrer_visitor.dart
+++ b/sdk/lib/_internal/compiler/implementation/types/inferrer_visitor.dart
@@ -15,7 +15,7 @@
TypeMask otherType;
if (annotation.kind == TypeKind.TYPEDEF
|| annotation.kind == TypeKind.FUNCTION) {
- otherType = compiler.typesTask.typesInferrer.functionType;
+ otherType = compiler.typesTask.functionType;
} else if (annotation.kind == TypeKind.TYPE_VARIABLE) {
return type;
} else {
@@ -248,7 +248,7 @@
TypeMask visitNode(Node node) {
node.visitChildren(this);
- return inferrer.dynamicType;
+ return compiler.typesTask.dynamicType;
}
TypeMask visitNewExpression(NewExpression node) {
@@ -256,39 +256,39 @@
}
TypeMask visit(Node node) {
- return node == null ? inferrer.dynamicType : node.accept(this);
+ return node == null ? compiler.typesTask.dynamicType : node.accept(this);
}
TypeMask visitFunctionExpression(FunctionExpression node) {
node.visitChildren(this);
- return inferrer.functionType;
+ return compiler.typesTask.functionType;
}
TypeMask visitFunctionDeclaration(FunctionDeclaration node) {
- locals.update(elements[node], inferrer.functionType);
+ locals.update(elements[node], compiler.typesTask.functionType);
return visit(node.function);
}
TypeMask visitLiteralString(LiteralString node) {
- return inferrer.stringType;
+ return compiler.typesTask.stringType;
}
TypeMask visitStringInterpolation(StringInterpolation node) {
node.visitChildren(this);
- return inferrer.stringType;
+ return compiler.typesTask.stringType;
}
TypeMask visitStringJuxtaposition(StringJuxtaposition node) {
node.visitChildren(this);
- return inferrer.stringType;
+ return compiler.typesTask.stringType;
}
TypeMask visitLiteralBool(LiteralBool node) {
- return inferrer.boolType;
+ return compiler.typesTask.boolType;
}
TypeMask visitLiteralDouble(LiteralDouble node) {
- return inferrer.doubleType;
+ return compiler.typesTask.doubleType;
}
TypeMask visitLiteralInt(LiteralInt node) {
@@ -297,30 +297,30 @@
// The JavaScript backend may turn this literal into a double at
// runtime.
return constantSystem.isDouble(constant)
- ? inferrer.doubleType
- : inferrer.intType;
+ ? compiler.typesTask.doubleType
+ : compiler.typesTask.intType;
}
TypeMask visitLiteralList(LiteralList node) {
node.visitChildren(this);
return node.isConst()
- ? inferrer.constListType
- : inferrer.growableListType;
+ ? compiler.typesTask.constListType
+ : compiler.typesTask.growableListType;
}
TypeMask visitLiteralMap(LiteralMap node) {
node.visitChildren(this);
return node.isConst()
- ? inferrer.constMapType
- : inferrer.mapType;
+ ? compiler.typesTask.constMapType
+ : compiler.typesTask.mapType;
}
TypeMask visitLiteralNull(LiteralNull node) {
- return inferrer.nullType;
+ return compiler.typesTask.nullType;
}
TypeMask visitTypeReferenceSend(Send node) {
- return inferrer.typeType;
+ return compiler.typesTask.typeType;
}
bool isThisOrSuper(Node node) => node.isThis() || node.isSuper();
@@ -356,7 +356,7 @@
} else if (node.isSuper()) {
return superType;
}
- return inferrer.dynamicType;
+ return compiler.typesTask.dynamicType;
}
void potentiallyAddIsCheck(Send node) {
@@ -398,7 +398,7 @@
updateIsChecks(isChecks, usePositive: true);
visit(node.arguments.head);
locals.merge(saved);
- return inferrer.boolType;
+ return compiler.typesTask.boolType;
} else if (const SourceString("||") == op.source) {
conditionIsSimple = false;
visit(node.receiver);
@@ -409,17 +409,17 @@
visit(node.arguments.head);
accumulateIsChecks = oldAccumulateIsChecks;
locals.merge(saved);
- return inferrer.boolType;
+ return compiler.typesTask.boolType;
} else if (const SourceString("!") == op.source) {
bool oldAccumulateIsChecks = accumulateIsChecks;
accumulateIsChecks = false;
node.visitChildren(this);
accumulateIsChecks = oldAccumulateIsChecks;
- return inferrer.boolType;
+ return compiler.typesTask.boolType;
} else if (const SourceString("is") == op.source) {
potentiallyAddIsCheck(node);
node.visitChildren(this);
- return inferrer.boolType;
+ return compiler.typesTask.boolType;
} else if (const SourceString("as") == op.source) {
TypeMask receiverType = visit(node.receiver);
DartType type = elements.getType(node.arguments.head);
@@ -430,7 +430,7 @@
} else if (const SourceString('===') == op.source
|| const SourceString('!==') == op.source) {
node.visitChildren(this);
- return inferrer.boolType;
+ return compiler.typesTask.boolType;
} else {
// Binary operator.
return visitDynamicSend(node);
@@ -464,13 +464,13 @@
link = link.tail) {
Node definition = link.head;
if (definition is Identifier) {
- locals.update(elements[definition], inferrer.nullType);
+ locals.update(elements[definition], compiler.typesTask.nullType);
} else {
assert(definition.asSendSet() != null);
visit(definition);
}
}
- return inferrer.dynamicType;
+ return compiler.typesTask.dynamicType;
}
bool handleCondition(Node node, List<Send> tests) {
@@ -499,7 +499,7 @@
if (simpleCondition) updateIsChecks(tests, usePositive: false);
visit(node.elsePart);
locals.merge(thenLocals);
- return inferrer.dynamicType;
+ return compiler.typesTask.dynamicType;
}
void setupBreaksAndContinues(TargetElement element) {
@@ -546,7 +546,7 @@
loopLevel--;
mergeBreaks(target);
clearBreaksAndContinues(target);
- return inferrer.dynamicType;
+ return compiler.typesTask.dynamicType;
}
TypeMask visitWhile(While node) {
@@ -591,13 +591,13 @@
locals = saved;
}
visit(node.finallyBlock);
- return inferrer.dynamicType;
+ return compiler.typesTask.dynamicType;
}
TypeMask visitThrow(Throw node) {
node.visitChildren(this);
locals.seenReturnOrThrow = true;
- return inferrer.dynamicType;
+ return compiler.typesTask.dynamicType;
}
TypeMask visitCatchBlock(CatchBlock node) {
@@ -605,16 +605,16 @@
if (exception != null) {
DartType type = elements.getType(node.type);
TypeMask mask = type == null
- ? inferrer.dynamicType
+ ? compiler.typesTask.dynamicType
: new TypeMask.nonNullSubtype(type.asRaw());
locals.update(elements[exception], mask);
}
Node trace = node.trace;
if (trace != null) {
- locals.update(elements[trace], inferrer.dynamicType);
+ locals.update(elements[trace], compiler.typesTask.dynamicType);
}
visit(node.block);
- return inferrer.dynamicType;
+ return compiler.typesTask.dynamicType;
}
TypeMask visitParenthesizedExpression(ParenthesizedExpression node) {
@@ -628,7 +628,7 @@
if (locals.aborts) break;
}
}
- return inferrer.dynamicType;
+ return compiler.typesTask.dynamicType;
}
TypeMask visitLabeledStatement(LabeledStatement node) {
@@ -638,7 +638,7 @@
|| Elements.isUnusedLabel(node, elements)) {
// Loops and switches handle their own labels.
visit(body);
- return inferrer.dynamicType;
+ return compiler.typesTask.dynamicType;
}
TargetElement targetElement = elements[body];
@@ -646,21 +646,21 @@
visit(body);
mergeBreaks(targetElement);
clearBreaksAndContinues(targetElement);
- return inferrer.dynamicType;
+ return compiler.typesTask.dynamicType;
}
TypeMask visitBreakStatement(BreakStatement node) {
TargetElement target = elements[node];
breaksFor[target].add(locals);
locals.seenBreakOrContinue = true;
- return inferrer.dynamicType;
+ return compiler.typesTask.dynamicType;
}
TypeMask visitContinueStatement(ContinueStatement node) {
TargetElement target = elements[node];
continuesFor[target].add(locals);
locals.seenBreakOrContinue = true;
- return inferrer.dynamicType;
+ return compiler.typesTask.dynamicType;
}
void internalError(String reason, {Node node}) {
@@ -735,6 +735,6 @@
// that the [visitBlock] method does not assume the code after the
// switch is dead code.
locals.seenBreakOrContinue = false;
- return inferrer.dynamicType;
+ return compiler.typesTask.dynamicType;
}
}
diff --git a/sdk/lib/_internal/compiler/implementation/types/simple_types_inferrer.dart b/sdk/lib/_internal/compiler/implementation/types/simple_types_inferrer.dart
index 5f25672..6b49b54 100644
--- a/sdk/lib/_internal/compiler/implementation/types/simple_types_inferrer.dart
+++ b/sdk/lib/_internal/compiler/implementation/types/simple_types_inferrer.dart
@@ -178,36 +178,20 @@
compiler = compiler,
internal = new InternalSimpleTypesInferrer(compiler, OPTIMISTIC);
- TypeMask get dynamicType => compiler.typesTask.dynamicType;
- TypeMask get nullType => compiler.typesTask.nullType;
- TypeMask get intType => compiler.typesTask.intType;
- TypeMask get doubleType => compiler.typesTask.doubleType;
- TypeMask get numType => compiler.typesTask.numType;
- TypeMask get boolType => compiler.typesTask.boolType;
- TypeMask get functionType => compiler.typesTask.functionType;
- TypeMask get listType => compiler.typesTask.listType;
- TypeMask get constListType => compiler.typesTask.constListType;
- TypeMask get fixedListType => compiler.typesTask.fixedListType;
- TypeMask get growableListType => compiler.typesTask.growableListType;
- TypeMask get mapType => compiler.typesTask.mapType;
- TypeMask get constMapType => compiler.typesTask.constMapType;
- TypeMask get stringType => compiler.typesTask.stringType;
- TypeMask get typeType => compiler.typesTask.typeType;
-
TypeMask getReturnTypeOfElement(Element element) {
- if (compiler.disableTypeInference) return dynamicType;
+ if (compiler.disableTypeInference) return compiler.typesTask.dynamicType;
return internal.getReturnTypeOfElement(element.implementation);
}
TypeMask getTypeOfElement(Element element) {
- if (compiler.disableTypeInference) return dynamicType;
+ if (compiler.disableTypeInference) return compiler.typesTask.dynamicType;
return internal.getTypeOfElement(element.implementation);
}
TypeMask getTypeOfNode(Element owner, Node node) {
- if (compiler.disableTypeInference) return dynamicType;
+ if (compiler.disableTypeInference) return compiler.typesTask.dynamicType;
return internal.getTypeOfNode(owner, node);
}
TypeMask getTypeOfSelector(Selector selector) {
- if (compiler.disableTypeInference) return dynamicType;
+ if (compiler.disableTypeInference) return compiler.typesTask.dynamicType;
return internal.getTypeOfSelector(selector);
}
Iterable<Element> getCallersOf(Element element) {
diff --git a/sdk/lib/_internal/compiler/implementation/universe/universe.dart b/sdk/lib/_internal/compiler/implementation/universe/universe.dart
index c366000..db18031 100644
--- a/sdk/lib/_internal/compiler/implementation/universe/universe.dart
+++ b/sdk/lib/_internal/compiler/implementation/universe/universe.dart
@@ -154,6 +154,15 @@
this.namedArguments,
this.orderedNamedArguments,
this.hashCode) {
+ assert(kind == SelectorKind.INDEX
+ || (name != INDEX_NAME && name != INDEX_SET_NAME));
+ assert(kind == SelectorKind.OPERATOR
+ || kind == SelectorKind.INDEX
+ || Elements.operatorNameToIdentifier(name) == name);
+ assert(kind == SelectorKind.CALL
+ || kind == SelectorKind.GETTER
+ || kind == SelectorKind.SETTER
+ || Elements.operatorNameToIdentifier(name) != name);
assert(!name.isPrivate() || library != null);
}
@@ -177,6 +186,28 @@
hashCode);
}
+ factory Selector.fromElement(Element element, Compiler compiler) {
+ SourceString name = element.name;
+ if (element.isFunction()) {
+ int arity = element.asFunctionElement().requiredParameterCount(compiler);
+ if (name == const SourceString('[]')) {
+ return new Selector.index();
+ } else if (name == const SourceString('[]=')) {
+ return new Selector.indexSet();
+ } else if (Elements.operatorNameToIdentifier(name) != name) {
+ return new Selector(SelectorKind.OPERATOR, name, null, arity);
+ } else {
+ return new Selector.call(name, element.getLibrary(), arity);
+ }
+ } else if (element.isSetter()) {
+ return new Selector.setter(name, element.getLibrary());
+ } else if (element.isGetter()) {
+ return new Selector.getter(name, element.getLibrary());
+ } else if (element.isField()) {
+ return new Selector.getter(name, element.getLibrary());
+ }
+ }
+
factory Selector.getter(SourceString name, LibraryElement library)
=> new Selector(SelectorKind.GETTER, name, library, 0);
diff --git a/sdk/lib/_internal/lib/js_mirrors.dart b/sdk/lib/_internal/lib/js_mirrors.dart
index 1d1c825..802ec36 100644
--- a/sdk/lib/_internal/lib/js_mirrors.dart
+++ b/sdk/lib/_internal/lib/js_mirrors.dart
@@ -307,7 +307,7 @@
var mirror = classMirrors[constructorOrInterceptor];
if (mirror == null) {
mirror = new JsClassMirror(
- symbol, constructorOrInterceptor, fields, fieldsMetadata);
+ symbol, mangledName, constructorOrInterceptor, fields, fieldsMetadata);
classMirrors[constructorOrInterceptor] = mirror;
}
return mirror;
@@ -343,7 +343,7 @@
List<Object> positionalArguments,
[Map<Symbol, dynamic> namedArguments]) {
if (namedArguments != null && !namedArguments.isEmpty) {
- throw new UnsupportedError('Named arguments are not implemented');
+ throw new UnsupportedError('Named arguments are not implemented.');
}
return
new Future<InstanceMirror>(
@@ -354,7 +354,7 @@
List positionalArguments,
[Map<Symbol,dynamic> namedArguments]) {
if (namedArguments != null && !namedArguments.isEmpty) {
- throw new UnsupportedError('Named arguments are not implemented');
+ throw new UnsupportedError('Named arguments are not implemented.');
}
// Copy the list to ensure that it can safely be passed to
// JavaScript.
@@ -402,19 +402,22 @@
class JsClassMirror extends JsTypeMirror with JsObjectMirror
implements ClassMirror {
+ final String _mangledName;
final _jsConstructorOrInterceptor;
- final String _fields;
+ final String _fieldsDescriptor;
final List _fieldsMetadata;
List _metadata;
JsClassMirror _superclass;
List<JsMethodMirror> _cachedMethods;
+ List<JsVariableMirror> _cachedFields;
// Set as side-effect of accessing JsLibraryMirror.classes.
JsLibraryMirror _owner;
JsClassMirror(Symbol simpleName,
+ this._mangledName,
this._jsConstructorOrInterceptor,
- this._fields,
+ this._fieldsDescriptor,
this._fieldsMetadata)
: super(simpleName);
@@ -429,15 +432,10 @@
}
Map<Symbol, MethodMirror> get constructors {
- Map<Symbol, MethodMirror> result = new Map<Symbol, MethodMirror>();
- JsLibraryMirror library = owner;
- String unmangledName = n(simpleName);
- for (JsMethodMirror mirror in library._functionMirrors) {
- Symbol name = mirror.simpleName;
- if (mirror.isConstructor
- && (name == simpleName || n(name).startsWith('$unmangledName.'))) {
- result[name] = mirror;
- mirror._owner = this;
+ var result = new Map<Symbol, MethodMirror>();
+ for (JsMethodMirror method in _methods) {
+ if (method.isConstructor) {
+ result[method.simpleName] = method;
}
}
return result;
@@ -448,7 +446,6 @@
var prototype = JS('', '#.prototype', _jsConstructor);
List<String> keys = extractKeys(prototype);
var result = <JsMethodMirror>[];
- int i = 0;
for (String key in keys) {
if (key == '') continue;
String simpleName = mangledNames[key];
@@ -464,13 +461,92 @@
result.add(mirror);
mirror._owner = this;
}
+
+ keys = extractKeys(JS('', 'init.statics[#]', _mangledName));
+ int length = keys.length;
+ for (int i = 0; i < length; i++) {
+ String mangledName = keys[i];
+ String unmangledName = mangledName;
+ // TODO(ahe): Create accessor for accessing $. It is also
+ // used in js_helper.
+ var jsFunction = JS('', '#[#]', JS_CURRENT_ISOLATE(), mangledName);
+
+ bool isConstructor = false;
+ if (i + 1 < length) {
+ String reflectionName = keys[i + 1];
+ if (reflectionName.startsWith('+')) {
+ i++;
+ reflectionName = reflectionName.substring(1);
+ isConstructor = reflectionName.startsWith('new ');
+ if (isConstructor) {
+ reflectionName = reflectionName.substring(4).replaceAll(r'$', '.');
+ }
+ }
+ unmangledName = reflectionName;
+ }
+ bool isStatic = !isConstructor; // Constructors are not static.
+ JsMethodMirror mirror =
+ new JsMethodMirror.fromUnmangledName(
+ unmangledName, jsFunction, isStatic, isConstructor);
+ result.add(mirror);
+ mirror._owner = this;
+ }
+
return _cachedMethods = result;
}
+ List<VariableMirror> get _fields {
+ if (_cachedFields != null) return _cachedFields;
+ var result = <VariableMirror>[];
+ var s = _fieldsDescriptor.split(';');
+ var fields = s[1] == '' ? [] : s[1].split(',');
+ int fieldNumber = 0;
+ for (String field in fields) {
+ var metadata;
+ if (_fieldsMetadata != null) {
+ metadata = _fieldsMetadata[fieldNumber++];
+ }
+ JsVariableMirror mirror =
+ new JsVariableMirror.from(field, metadata, this, false);
+ if (mirror != null) {
+ result.add(mirror);
+ }
+ }
+
+ var staticDescriptor = JS('', 'init.statics[#]', _mangledName);
+ if (staticDescriptor != null) {
+ var staticFieldsDescriptor = JS('', '#[""]', staticDescriptor);
+ var staticFieldsMetadata = null;
+ var staticFields;
+ if (staticFieldsDescriptor is List) {
+ staticFields = staticFieldsDescriptor[0].split(',');
+ staticFieldsMetadata = staticFieldsDescriptor.sublist(1);
+ } else if (staticFieldsDescriptor is String) {
+ staticFields = staticFieldsDescriptor.split(',');
+ } else {
+ staticFields = [];
+ }
+ fieldNumber = 0;
+ for (String staticField in staticFields) {
+ var metadata;
+ if (staticFieldsMetadata != null) {
+ metadata = staticFieldsMetadata[fieldNumber++];
+ }
+ JsVariableMirror mirror =
+ new JsVariableMirror.from(staticField, metadata, this, true);
+ if (mirror != null) {
+ result.add(mirror);
+ }
+ }
+ }
+ _cachedFields = result;
+ return _cachedFields;
+ }
+
Map<Symbol, MethodMirror> get methods {
var result = new Map<Symbol, MethodMirror>();
for (JsMethodMirror method in _methods) {
- if (!method.isGetter && !method.isSetter) {
+ if (!method.isConstructor && !method.isGetter && !method.isSetter) {
result[method.simpleName] = method;
}
}
@@ -478,10 +554,16 @@
}
Map<Symbol, MethodMirror> get getters {
- // TODO(ahe): Should this include getters for fields?
+ // TODO(ahe): This is a hack to remove getters corresponding to a field.
+ var fields = variables;
+
var result = new Map<Symbol, MethodMirror>();
for (JsMethodMirror method in _methods) {
if (method.isGetter) {
+
+ // TODO(ahe): This is a hack to remove getters corresponding to a field.
+ if (fields[method.simpleName] != null) continue;
+
result[method.simpleName] = method;
}
}
@@ -489,10 +571,18 @@
}
Map<Symbol, MethodMirror> get setters {
- // TODO(ahe): Should this include setters for fields?
+ // TODO(ahe): This is a hack to remove setters corresponding to a field.
+ var fields = variables;
+
var result = new Map<Symbol, MethodMirror>();
for (JsMethodMirror method in _methods) {
if (method.isSetter) {
+
+ // TODO(ahe): This is a hack to remove setters corresponding to a field.
+ String name = n(method.simpleName);
+ name = name.substring(0, name.length - 1); // Remove '='.
+ if (fields[s(name)] != null) continue;
+
result[method.simpleName] = method;
}
}
@@ -501,19 +591,8 @@
Map<Symbol, VariableMirror> get variables {
var result = new Map<Symbol, VariableMirror>();
- var s = _fields.split(';');
- var fields = s[1] == '' ? [] : s[1].split(',');
- int fieldNumber = 0;
- for (String field in fields) {
- var metadata;
- if (_fieldsMetadata != null) {
- metadata = _fieldsMetadata[fieldNumber++];
- }
- JsVariableMirror mirror = new JsVariableMirror.from(field, metadata);
- if (mirror != null) {
- result[mirror.simpleName] = mirror;
- mirror._owner = this;
- }
+ for (JsVariableMirror mirror in _fields) {
+ result[mirror.simpleName] = mirror;
}
return result;
}
@@ -534,44 +613,53 @@
}
InstanceMirror setField(Symbol fieldName, Object arg) {
- // TODO(ahe): This is extremely dangerous!!!
- JS('void', '#[#] = #', JS_CURRENT_ISOLATE(),
- '${n(simpleName)}_${n(fieldName)}', arg);
- return reflect(arg);
+ JsVariableMirror mirror = variables[fieldName];
+ if (mirror != null && mirror.isStatic && !mirror.isFinal) {
+ String jsName = mirror._jsName;
+ if (!JS('bool', '# in #', jsName, JS_CURRENT_ISOLATE())) {
+ throw new RuntimeError('Cannot find "$jsName" in current isolate.');
+ }
+ JS('void', '#[#] = #', JS_CURRENT_ISOLATE(), jsName, arg);
+ return reflect(arg);
+ }
+ // TODO(ahe): What receiver to use?
+ throw new NoSuchMethodError(this, '${n(fieldName)}=', [arg], null);
}
InstanceMirror getField(Symbol fieldName) {
- // TODO(ahe): This is extremely dangerous!!!
- return reflect(
- JS('', '#[#]', JS_CURRENT_ISOLATE(),
- '${n(simpleName)}_${n(fieldName)}'));
+ JsVariableMirror mirror = variables[fieldName];
+ if (mirror != null && mirror.isStatic) {
+ String jsName = mirror._jsName;
+ if (!JS('bool', '# in #', jsName, JS_CURRENT_ISOLATE())) {
+ throw new RuntimeError('Cannot find "$jsName" in current isolate.');
+ }
+ if (JS('bool', '# in init.lazies', jsName)) {
+ String getterName = JS('String', 'init.lazies[#]', jsName);
+ return reflect(JS('', '#[#]()', JS_CURRENT_ISOLATE(), getterName));
+ } else {
+ return reflect(JS('', '#[#]', JS_CURRENT_ISOLATE(), jsName));
+ }
+ }
+ // TODO(ahe): What receiver to use?
+ throw new NoSuchMethodError(this, n(fieldName), null, null);
}
InstanceMirror newInstance(Symbol constructorName,
List positionalArguments,
[Map<Symbol, dynamic> namedArguments]) {
if (namedArguments != null && !namedArguments.isEmpty) {
- throw new UnsupportedError('Named arguments are not implemented');
+ throw new UnsupportedError('Named arguments are not implemented.');
}
- String reflectiveName = 'new ${n(simpleName)}';
- String name = n(constructorName);
- if (!name.isEmpty) {
- reflectiveName = '$reflectiveName\$$name';
- }
- reflectiveName = '$reflectiveName:${positionalArguments.length}:0';
- String mangledName = reflectiveGlobalNames[reflectiveName];
- var factory = JS('', '#[#]', JS_CURRENT_ISOLATE(), mangledName);
- if (factory == null) {
- // TODO(ahe): Pass namedArguments when NoSuchMethodError has
- // been fixed to use Symbol.
- // TODO(ahe): What receiver to use?
- throw new NoSuchMethodError(
- this, reflectiveName, positionalArguments, null);
- }
- return reflect(JS('', r'#.apply(#, #)',
- factory,
- JS_CURRENT_ISOLATE(),
- new List.from(positionalArguments)));
+ JsMethodMirror mirror = constructors.values.firstWhere(
+ (m) => m.constructorName == constructorName,
+ orElse: () {
+ // TODO(ahe): Pass namedArguments when NoSuchMethodError has been
+ // fixed to use Symbol.
+ // TODO(ahe): What receiver to use?
+ throw new NoSuchMethodError(
+ owner, n(constructorName), positionalArguments, null);
+ });
+ return reflect(mirror._invoke(positionalArguments, namedArguments));
}
Future<InstanceMirror> newInstanceAsync(
@@ -579,7 +667,7 @@
List positionalArguments,
[Map<Symbol, dynamic> namedArguments]) {
if (namedArguments != null && !namedArguments.isEmpty) {
- throw new UnsupportedError('Named arguments are not implemented');
+ throw new UnsupportedError('Named arguments are not implemented.');
}
return new Future<InstanceMirror>(
() => newInstance(
@@ -616,7 +704,7 @@
ClassMirror get superclass {
if (_superclass == null) {
- var superclassName = _fields.split(';')[0];
+ var superclassName = _fieldsDescriptor.split(';')[0];
// Use _superclass == this to represent class with no superclass (Object).
_superclass = (superclassName == '')
? this : reflectClassByMangledName(superclassName);
@@ -624,12 +712,27 @@
return _superclass == this ? null : _superclass;
}
- // TODO(ahe): Implement these;
InstanceMirror invoke(Symbol memberName,
List positionalArguments,
[Map<Symbol,dynamic> namedArguments]) {
- throw new UnimplementedError();
+ // Mirror API gotcha: Calling [invoke] on a ClassMirror means invoke a
+ // static method.
+
+ if (namedArguments != null && !namedArguments.isEmpty) {
+ throw new UnsupportedError('Named arguments are not implemented.');
+ }
+ JsMethodMirror mirror = methods[memberName];
+ if (mirror == null || !mirror.isStatic) {
+ // TODO(ahe): Pass namedArguments when NoSuchMethodError has
+ // been fixed to use Symbol.
+ // TODO(ahe): What receiver to use?
+ throw new NoSuchMethodError(
+ this, n(memberName), positionalArguments, null);
+ }
+ return reflect(mirror._invoke(positionalArguments, namedArguments));
}
+
+ // TODO(ahe): Implement these.
List<ClassMirror> get superinterfaces => throw new UnimplementedError();
Map<Symbol, TypeVariableMirror> get typeVariables
=> throw new UnimplementedError();
@@ -646,17 +749,21 @@
final bool isFinal;
final bool isStatic;
final _metadataFunction;
- DeclarationMirror _owner;
+ final DeclarationMirror _owner;
List _metadata;
JsVariableMirror(Symbol simpleName,
this._jsName,
this.isFinal,
this.isStatic,
- this._metadataFunction)
+ this._metadataFunction,
+ this._owner)
: super(simpleName);
- factory JsVariableMirror.from(String descriptor, metadataFunction) {
+ factory JsVariableMirror.from(String descriptor,
+ metadataFunction,
+ JsClassMirror owner,
+ bool isStatic) {
int length = descriptor.length;
var code = fieldCode(descriptor.codeUnitAt(length - 1));
bool isFinal = false;
@@ -672,8 +779,26 @@
accessorName = accessorName.substring(0, divider);
jsName = accessorName.substring(divider + 1);
}
+ var unmangledName;
+ if (isStatic) {
+ unmangledName = mangledGlobalNames[accessorName];
+ } else {
+ String getterPrefix = JS('String', 'init.getterPrefix');
+ unmangledName = mangledNames['$getterPrefix$accessorName'];
+ }
+ if (unmangledName == null) unmangledName = accessorName;
+ if (!hasSetter) {
+ // TODO(ahe): This is a hack to handle checked setters in checked mode.
+ var setterName = s('$unmangledName=');
+ for (JsMethodMirror method in owner._methods) {
+ if (method.simpleName == setterName) {
+ isFinal = false;
+ break;
+ }
+ }
+ }
return new JsVariableMirror(
- s(accessorName), jsName, isFinal, false, metadataFunction);
+ s(unmangledName), jsName, isFinal, isStatic, metadataFunction, owner);
}
String get _prettyName => 'VariableMirror';
@@ -844,6 +969,24 @@
return s(name.substring(index + 1));
}
+ _invoke(List positionalArguments, [Map<Symbol, dynamic> namedArguments]) {
+ if (namedArguments != null && !namedArguments.isEmpty) {
+ throw new UnsupportedError('Named arguments are not implemented.');
+ }
+ if (!isStatic && !isConstructor) {
+ throw new RuntimeError('Cannot invoke instance method without receiver.');
+ }
+ if (_parameterCount != positionalArguments.length || _jsFunction == null) {
+ // TODO(ahe): Pass namedArguments when NoSuchMethodError has
+ // been fixed to use Symbol.
+ // TODO(ahe): What receiver to use?
+ throw new NoSuchMethodError(
+ owner, n(simpleName), positionalArguments, null);
+ }
+ return JS('', r'#.apply(#, #)', _jsFunction, JS_CURRENT_ISOLATE(),
+ new List.from(positionalArguments));
+ }
+
// TODO(ahe): Implement these.
bool get isAbstract => throw new UnimplementedError();
bool get isRegularMethod => throw new UnimplementedError();
diff --git a/sdk/lib/_internal/libraries.dart b/sdk/lib/_internal/libraries.dart
index 044fbf2..e2af8d5 100644
--- a/sdk/lib/_internal/libraries.dart
+++ b/sdk/lib/_internal/libraries.dart
@@ -70,6 +70,11 @@
"isolate/isolate.dart",
dart2jsPatchPath: "_internal/lib/isolate_patch.dart"),
+ "js": const LibraryInfo(
+ "js/dartium/js_dartium.dart",
+ category: "Client",
+ dart2jsPath: "js/dart2js/js_dart2js.dart"),
+
"json": const LibraryInfo(
"json/json.dart",
dart2jsPatchPath: "_internal/lib/json_patch.dart"),
diff --git a/sdk/lib/_internal/pub/lib/src/command/lish.dart b/sdk/lib/_internal/pub/lib/src/command/lish.dart
index c44eeeb..23f4c97 100644
--- a/sdk/lib/_internal/pub/lib/src/command/lish.dart
+++ b/sdk/lib/_internal/pub/lib/src/command/lish.dart
@@ -44,7 +44,7 @@
help: 'Validate but do not publish the package.');
commandParser.addFlag('force', abbr: 'f', negatable: false,
help: 'Publish without confirmation if there are no errors.');
- commandParser.addOption('server', defaultsTo: HostedSource.DEFAULT_URL,
+ commandParser.addOption('server', defaultsTo: HostedSource.defaultUrl,
help: 'The package server to which to upload this package.');
}
diff --git a/sdk/lib/_internal/pub/lib/src/command/uploader.dart b/sdk/lib/_internal/pub/lib/src/command/uploader.dart
index 8ecdd38..86daaa1 100644
--- a/sdk/lib/_internal/pub/lib/src/command/uploader.dart
+++ b/sdk/lib/_internal/pub/lib/src/command/uploader.dart
@@ -30,7 +30,7 @@
Uri get server => Uri.parse(commandOptions['server']);
UploaderCommand() {
- commandParser.addOption('server', defaultsTo: HostedSource.DEFAULT_URL,
+ commandParser.addOption('server', defaultsTo: HostedSource.defaultUrl,
help: 'The package server on which the package is hosted.');
commandParser.addOption('package',
help: 'The package whose uploaders will be modified.\n'
diff --git a/sdk/lib/_internal/pub/lib/src/source/hosted.dart b/sdk/lib/_internal/pub/lib/src/source/hosted.dart
index 097ec68..f65a56a 100644
--- a/sdk/lib/_internal/pub/lib/src/source/hosted.dart
+++ b/sdk/lib/_internal/pub/lib/src/source/hosted.dart
@@ -24,12 +24,17 @@
/// A package source that installs packages from a package hosting site that
/// uses the same API as pub.dartlang.org.
class HostedSource extends Source {
- /// The URL of the default package repository.
- static const DEFAULT_URL = "https://pub.dartlang.org";
final name = "hosted";
final shouldCache = true;
+ /// Gets the default URL for the package server for hosted dependencies.
+ static String get defaultUrl {
+ var url = io.Platform.environment["PUB_HOSTED_URL"];
+ if (url != null) return url;
+ return "https://pub.dartlang.org";
+ }
+
/// Downloads a list of all versions of a package that are available from the
/// site.
Future<List<Version>> getVersions(String name, description) {
@@ -125,7 +130,7 @@
}
List<Package> getCachedPackages([String url]) {
- if (url == null) url = DEFAULT_URL;
+ if (url == null) url = defaultUrl;
var cacheDir = path.join(systemCacheRoot,
_getSourceDirectory(url));
@@ -237,7 +242,7 @@
/// this throws a descriptive FormatException.
Pair<String, String> _parseDescription(description) {
if (description is String) {
- return new Pair<String, String>(description, HostedSource.DEFAULT_URL);
+ return new Pair<String, String>(description, HostedSource.defaultUrl);
}
if (description is! Map) {
@@ -256,7 +261,7 @@
}
var url = description["url"];
- if (url == null) url = HostedSource.DEFAULT_URL;
+ if (url == null) url = HostedSource.defaultUrl;
return new Pair<String, String>(name, url);
}
diff --git a/sdk/lib/codec/encoding.dart b/sdk/lib/codec/encoding.dart
index 50b724b..40e0f2b 100644
--- a/sdk/lib/codec/encoding.dart
+++ b/sdk/lib/codec/encoding.dart
@@ -20,11 +20,41 @@
* A [Utf8Codec] encodes strings to utf-8 code units (bytes) and decodes
* UTF-8 code units to strings.
*/
-// TODO(floitsch): Needs a way to specify if decoding should throw or use
-// the replacement character.
class Utf8Codec extends Encoding {
- const Utf8Codec();
+ final bool _allowMalformed;
+
+ /**
+ * Instantiates a new [Utf8Codec].
+ *
+ * The optional [allowMalformed] argument defines how [decoder] (and [decode])
+ * deal with invalid or unterminated character sequences.
+ *
+ * If it is `true` (and not overriden at the method invocation) [decode] and
+ * the [decoder] replace invalid (or unterminated) octet
+ * sequences with the Unicode Replacement character `U+FFFD` (�). Otherwise
+ * they throw a [FormatException].
+ */
+ const Utf8Codec({ bool allowMalformed: false })
+ : _allowMalformed = allowMalformed;
+
+ /**
+ * Decodes the UTF-8 [codeUnits] (a list of unsigned 8-bit integers) to the
+ * corresponding string.
+ *
+ * If [allowMalformed] is `true` the decoder replaces invalid (or
+ * unterminated) character sequences with the Unicode Replacement character
+ * `U+FFFD` (�). Otherwise it throws a [FormatException].
+ *
+ * If [allowMalformed] is not given, it defaults to the `allowMalformed` that
+ * was used to instantiate `this`.
+ */
+ String decode(List<int> codeUnits, { bool allowMalformed }) {
+ if (allowMalformed == null) allowMalformed = _allowMalformed;
+ return new Utf8Decoder(allowMalformed: allowMalformed).convert(codeUnits);
+ }
Converter<String, List<int>> get encoder => new Utf8Encoder();
- Converter<List<int>, String> get decoder => new Utf8Decoder();
+ Converter<List<int>, String> get decoder {
+ return new Utf8Decoder(allowMalformed: _allowMalformed);
+ }
}
diff --git a/sdk/lib/convert/utf.dart b/sdk/lib/convert/utf.dart
index 09692f0..b7fc365 100644
--- a/sdk/lib/convert/utf.dart
+++ b/sdk/lib/convert/utf.dart
@@ -21,11 +21,187 @@
* to a string.
*/
class Utf8Decoder extends Converter<List<int>, String> {
+ final bool _allowMalformed;
+
+ /**
+ * Instantiates a new [Utf8Decoder].
+ *
+ * The optional [allowMalformed] argument defines how [convert] deals
+ * with invalid or unterminated character sequences.
+ *
+ * If it is `true` [convert] replaces invalid (or unterminated) character
+ * sequences with the Unicode Replacement character `U+FFFD` (�). Otherwise
+ * it throws a [FormatException].
+ */
+ Utf8Decoder({ bool allowMalformed: false })
+ : this._allowMalformed = allowMalformed;
+
/**
* Converts the UTF-8 [codeUnits] (a list of unsigned 8-bit integers) to the
* corresponding string.
*/
- // TODO(floitsch): allow to configure the decoder (for example the replacement
- // character).
- String convert(List<int> codeUnits) => OLD_UTF_LIB.decodeUtf8(codeUnits);
+ String convert(List<int> codeUnits) {
+ StringBuffer buffer = new StringBuffer();
+ _Utf8Decoder decoder = new _Utf8Decoder(_allowMalformed);
+ decoder.convert(codeUnits, 0, codeUnits.length, buffer);
+ decoder.close(buffer);
+ return buffer.toString();
+ }
+}
+
+// UTF-8 constants.
+const int _ONE_BYTE_LIMIT = 0x7f; // 7 bytes
+const int _TWO_BYTE_LIMIT = 0x7ff; // 11 bytes
+const int _THREE_BYTE_LIMIT = 0xffff; // 16 bytes
+const int _FOUR_BYTE_LIMIT = 0x10ffff; // 21 bytes, truncated to Unicode max.
+
+// UTF-16 constants.
+const int _SURROGATE_MASK = 0xF800;
+const int _SURROGATE_TAG_MASK = 0xFC00;
+const int _SURROGATE_VALUE_MASK = 0x3FF;
+const int _LEAD_SURROGATE_MIN = 0xD800;
+const int _TAIL_SURROGATE_MIN = 0xDC00;
+
+const int _REPLACEMENT_CHARACTER = 0xFFFD;
+const int _BOM_CHARACTER = 0xFEFF;
+
+bool _isSurrogate(int codeUnit) =>
+ (codeUnit & _SURROGATE_MASK) == _LEAD_SURROGATE_MIN;
+bool _isLeadSurrogate(int codeUnit) =>
+ (codeUnit & _SURROGATE_TAG_MASK) == _LEAD_SURROGATE_MIN;
+bool _isTailSurrogate(int codeUnit) =>
+ (codeUnit & _SURROGATE_TAG_MASK) == _TAIL_SURROGATE_MIN;
+int _combineSurrogatePair(int lead, int tail) =>
+ 0x10000 | ((lead & _SURROGATE_VALUE_MASK) << 10)
+ | (tail & _SURROGATE_VALUE_MASK);
+
+
+/**
+ * Decodes UTF-8.
+ *
+ * The decoder handles chunked input.
+ */
+// TODO(floitsch): make this class public.
+class _Utf8Decoder {
+ final bool _allowMalformed;
+ bool _isFirstCharacter = true;
+ int _value = 0;
+ int _expectedUnits = 0;
+ int _extraUnits = 0;
+
+ _Utf8Decoder(this._allowMalformed);
+
+ bool get hasPartialInput => _expectedUnits > 0;
+
+ // Limits of one through four byte encodings.
+ static const List<int> _LIMITS = const <int>[
+ _ONE_BYTE_LIMIT,
+ _TWO_BYTE_LIMIT,
+ _THREE_BYTE_LIMIT,
+ _FOUR_BYTE_LIMIT ];
+
+ void close(StringSink sink) {
+ if (hasPartialInput) {
+ if (!_allowMalformed) {
+ throw new FormatException("Unfinished UTF-8 octet sequence");
+ }
+ sink.writeCharCode(_REPLACEMENT_CHARACTER);
+ }
+ }
+
+ void convert(List<int> codeUnits, int startIndex, int endIndex,
+ StringSink sink) {
+ int value = _value;
+ int expectedUnits = _expectedUnits;
+ int extraUnits = _extraUnits;
+ _value = 0;
+ _expectedUnits = 0;
+ _extraUnits = 0;
+
+ int i = startIndex;
+ loop: while (true) {
+ multibyte: if (expectedUnits > 0) {
+ do {
+ if (i == endIndex) {
+ break loop;
+ }
+ int unit = codeUnits[i];
+ if ((unit & 0xC0) != 0x80) {
+ expectedUnits = 0;
+ if (!_allowMalformed) {
+ throw new FormatException(
+ "Bad UTF-8 encoding 0x${unit.toRadixString(16)}");
+ }
+ _isFirstCharacter = false;
+ sink.writeCharCode(_REPLACEMENT_CHARACTER);
+ break multibyte;
+ } else {
+ value = (value << 6) | (unit & 0x3f);
+ expectedUnits--;
+ i++;
+ }
+ } while (expectedUnits > 0);
+ if (value <= _LIMITS[extraUnits - 1]) {
+ // Overly long encoding. The value could be encoded with a shorter
+ // encoding.
+ if (!_allowMalformed) {
+ throw new FormatException(
+ "Overlong encoding of 0x${value.toRadixString(16)}");
+ }
+ expectedUnits = extraUnits = 0;
+ value = _REPLACEMENT_CHARACTER;
+ }
+ if (value > _FOUR_BYTE_LIMIT) {
+ if (!_allowMalformed) {
+ throw new FormatException("Character outside valid Unicode range: "
+ "0x${value.toRadixString(16)}");
+ }
+ value = _REPLACEMENT_CHARACTER;
+ }
+ if (!_isFirstCharacter || value != _BOM_CHARACTER) {
+ sink.writeCharCode(value);
+ }
+ _isFirstCharacter = false;
+ }
+
+ while (i < endIndex) {
+ int unit = codeUnits[i++];
+ if (unit <= _ONE_BYTE_LIMIT) {
+ _isFirstCharacter = false;
+ sink.writeCharCode(unit);
+ } else {
+ if ((unit & 0xE0) == 0xC0) {
+ value = unit & 0x1F;
+ expectedUnits = extraUnits = 1;
+ continue loop;
+ }
+ if ((unit & 0xF0) == 0xE0) {
+ value = unit & 0x0F;
+ expectedUnits = extraUnits = 2;
+ continue loop;
+ }
+ // 0xF5, 0xF6 ... 0xFF never appear in valid UTF-8 sequences.
+ if ((unit & 0xF8) == 0xF0 && unit < 0xF5) {
+ value = unit & 0x07;
+ expectedUnits = extraUnits = 3;
+ continue loop;
+ }
+ if (!_allowMalformed) {
+ throw new FormatException(
+ "Bad UTF-8 encoding 0x${unit.toRadixString(16)}");
+ }
+ value = _REPLACEMENT_CHARACTER;
+ expectedUnits = extraUnits = 0;
+ _isFirstCharacter = false;
+ sink.writeCharCode(value);
+ }
+ }
+ break loop;
+ }
+ if (expectedUnits > 0) {
+ _value = value;
+ _expectedUnits = expectedUnits;
+ _extraUnits = extraUnits;
+ }
+ }
}
diff --git a/sdk/lib/html/dart2js/html_dart2js.dart b/sdk/lib/html/dart2js/html_dart2js.dart
index 47f469b..1733d9e 100644
--- a/sdk/lib/html/dart2js/html_dart2js.dart
+++ b/sdk/lib/html/dart2js/html_dart2js.dart
@@ -8983,10 +8983,9 @@
@DocsEditable()
final HtmlCollection $dom_children;
- @JSName('className')
@DomName('Element.className')
@DocsEditable()
- String $dom_className;
+ String className;
@DomName('Element.clientHeight')
@DocsEditable()
@@ -16916,6 +16915,10 @@
@DocsEditable()
final Node nextNode;
+ @DomName('Node.nodeName')
+ @DocsEditable()
+ final String nodeName;
+
@DomName('Node.nodeType')
@DocsEditable()
final int nodeType;
@@ -26638,7 +26641,7 @@
void writeClasses(Set<String> s) {
var classes = new List.from(s).join(' ');
for (Element e in _elementIterable) {
- e.$dom_className = classes;
+ e.className = classes;
}
}
@@ -26683,7 +26686,7 @@
Set<String> readClasses() {
var s = new LinkedHashSet<String>();
- var classname = _element.$dom_className;
+ var classname = _element.className;
for (String name in classname.split(' ')) {
String trimmed = name.trim();
@@ -26696,7 +26699,7 @@
void writeClasses(Set<String> s) {
List list = new List.from(s);
- _element.$dom_className = s.join(' ');
+ _element.className = s.join(' ');
}
}
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
diff --git a/sdk/lib/html/dartium/html_dartium.dart b/sdk/lib/html/dartium/html_dartium.dart
index d308ceb..4a510d0 100644
--- a/sdk/lib/html/dartium/html_dartium.dart
+++ b/sdk/lib/html/dartium/html_dartium.dart
@@ -9268,11 +9268,11 @@
@DomName('Element.className')
@DocsEditable()
- String get $dom_className native "Element_className_Getter";
+ String get className native "Element_className_Getter";
@DomName('Element.className')
@DocsEditable()
- void set $dom_className(String value) native "Element_className_Setter";
+ void set className(String value) native "Element_className_Setter";
@DomName('Element.clientHeight')
@DocsEditable()
@@ -17887,6 +17887,10 @@
@DocsEditable()
Node get nextNode native "Node_nextSibling_Getter";
+ @DomName('Node.nodeName')
+ @DocsEditable()
+ String get nodeName native "Node_nodeName_Getter";
+
@DomName('Node.nodeType')
@DocsEditable()
int get nodeType native "Node_nodeType_Getter";
@@ -28248,7 +28252,7 @@
void writeClasses(Set<String> s) {
var classes = new List.from(s).join(' ');
for (Element e in _elementIterable) {
- e.$dom_className = classes;
+ e.className = classes;
}
}
@@ -28293,7 +28297,7 @@
Set<String> readClasses() {
var s = new LinkedHashSet<String>();
- var classname = _element.$dom_className;
+ var classname = _element.className;
for (String name in classname.split(' ')) {
String trimmed = name.trim();
@@ -28306,7 +28310,7 @@
void writeClasses(Set<String> s) {
List list = new List.from(s);
- _element.$dom_className = s.join(' ');
+ _element.className = s.join(' ');
}
}
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
@@ -30965,6 +30969,127 @@
static void spawnDomFunction(Function f, int replyTo) native "Utils_spawnDomFunction";
static void spawnDomUri(String uri, int replyTo) native "Utils_spawnDomUri";
static int _getNewIsolateId() native "Utils_getNewIsolateId";
+
+ // The following methods were added for debugger integration to make working
+ // with the Dart C mirrors API simpler.
+ // TODO(jacobr): consider moving them to a separate library.
+ // If Dart supported dynamic code injection, we would only inject this code
+ // when the debugger is invoked.
+
+ /**
+ * Strips the private secret prefix from member names of the form
+ * someName@hash.
+ */
+ static String stripMemberName(String name) {
+ int endIndex = name.indexOf('@');
+ return endIndex > 0 ? name.substring(0, endIndex) : name;
+ }
+
+ /**
+ * Takes a list containing variable names and corresponding values and
+ * returns a map from normalized names to values. Variable names are assumed
+ * to have list offsets 2*n values at offset 2*n+1. This method is required
+ * because Dart_GetLocalVariables returns a list instead of an object that
+ * can be queried to lookup names and values.
+ */
+ static Map<String, dynamic> createLocalVariablesMap(List localVariables) {
+ var map = {};
+ for (int i = 0; i < localVariables.length; i+=2) {
+ map[stripMemberName(localVariables[i])] = localVariables[i+1];
+ }
+ return map;
+ }
+
+ /**
+ * Convenience helper to get the keys of a [Map] as a [List].
+ */
+ static List getMapKeyList(Map map) => map.keys.toList();
+
+ /**
+ * Returns the keys of an arbitrary Dart Map encoded as unique Strings.
+ * Keys that are strings are left unchanged except that the prefix ":" is
+ * added to disambiguate keys from other Dart members.
+ * Keys that are not strings have # followed by the index of the key in the map
+ * prepended to disambuguate. This scheme is simplistic but easy to encode and
+ * decode. The use case for this method is displaying all map keys in a human
+ * readable way in debugging tools.
+ */
+ static List<String> getEncodedMapKeyList(dynamic obj) {
+ if (obj is! Map) return null;
+
+ var ret = new List<String>();
+ int i = 0;
+ return obj.keys.map((key) {
+ var encodedKey;
+ if (key is String) {
+ encodedKey = ':$key';
+ } else {
+ // If the key isn't a string, return a guaranteed unique for this map
+ // string representation of the key that is still somewhat human
+ // readable.
+ encodedKey = '#${i}:$key';
+ }
+ i++;
+ return encodedKey;
+ }).toList(growable: false);
+ }
+
+ static final RegExp _NON_STRING_KEY_REGEXP = new RegExp("^#(\\d+):(.+)\$");
+
+ static _decodeKey(Map map, String key) {
+ // The key is a regular old String.
+ if (key.startsWith(':')) return key.substring(1);
+
+ var match = _NON_STRING_KEY_REGEXP.firstMatch(key);
+ if (match != null) {
+ int index = int.parse(match.group(1));
+ var iter = map.keys.skip(index);
+ if (iter.isNotEmpty) {
+ var ret = iter.first;
+ // Validate that the toString representation of the key matches what we
+ // expect. FIXME: throw an error if it does not.
+ assert(match.group(2) == '$ret');
+ return ret;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Converts keys encoded with [getEncodedMapKeyList] to their actual keys.
+ */
+ static lookupValueForEncodedMapKey(Map obj, String key) => obj[_decodeKey(obj, key)];
+
+ /**
+ * Builds a constructor name with the form expected by the C Dart mirrors API.
+ */
+ static String buildConstructorName(String className, String constructorName) => '$className.$constructorName';
+
+ /**
+ * Strips the class name from an expression of the form "className.someName".
+ */
+ static String stripClassName(String str, String className) {
+ if (str.length > className.length + 1 &&
+ str.startsWith(className) && str[className.length] == '.') {
+ return str.substring(className.length + 1);
+ } else {
+ return str;
+ }
+ }
+
+ /**
+ * Removes the trailing dot from an expression ending in a dot.
+ * This method is used as Library prefixes include a trailing dot when using
+ * the C Dart debugger API.
+ */
+ static String stripTrailingDot(String str) =>
+ (str != null && str[str.length - 1] == '.') ? str.substring(0, str.length - 1) : str;
+
+ static String addTrailingDot(String str) => '${str}.';
+
+ // TODO(jacobr): we need a failsafe way to determine that a Node is really a
+ // DOM node rather than just a class that extends Node.
+ static bool isNode(obj) => obj is Node;
}
class _NPObject extends NativeFieldWrapperClass1 {
diff --git a/sdk/lib/js/dart2js/js_dart2js.dart b/sdk/lib/js/dart2js/js_dart2js.dart
new file mode 100644
index 0000000..7f806b7
--- /dev/null
+++ b/sdk/lib/js/dart2js/js_dart2js.dart
@@ -0,0 +1,201 @@
+// 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 dart.js;
+
+import 'dart:_foreign_helper' show JS;
+import 'dart:_js_helper' show convertDartClosureToJS;
+
+JsObject get context {
+ return new JsObject._fromJs(JS('=Object', 'window'));
+}
+
+JsObject jsify(dynamic data) => data == null ? null : new JsObject._json(data);
+
+class Callback implements Serializable<JsFunction> {
+ final Function _f; // here to allow capture in closure
+ final bool _withThis; // here to allow capture in closure
+ dynamic _jsFunction;
+
+ Callback._(this._f, this._withThis) {
+ _jsFunction = JS('=Object', r'''
+(function(){
+ var f = #;
+ return function(){
+ return f(this, Array.prototype.slice.apply(arguments));
+ };
+}).apply(this)''', convertDartClosureToJS(_call, 2));
+ }
+
+ factory Callback(Function f) => new Callback._(f, false);
+ factory Callback.withThis(Function f) => new Callback._(f, true);
+
+ _call(thisArg, List args) {
+ final arguments = new List.from(args);
+ if (_withThis) arguments.insert(0, thisArg);
+ final dartArgs = arguments.map(_convertToDart).toList();
+ return _convertToJS(Function.apply(_f, dartArgs));
+ }
+
+ JsFunction toJs() => new JsFunction._fromJs(_jsFunction);
+}
+
+class JsObject implements Serializable<JsObject> {
+ final dynamic _jsObject;
+
+ JsObject._fromJs(this._jsObject);
+
+ // TODO(vsm): Type constructor as Serializable<JsFunction> when
+ // dartbug.com/11854 is fixed.
+ factory JsObject(var constructor, [List arguments]) {
+ final constr = _convertToJS(constructor);
+ if (arguments == null) {
+ return new JsObject._fromJs(JS('=Object', 'new #()', constr));
+ }
+ final args = arguments.map(_convertToJS).toList();
+ switch (args.length) {
+ case 0:
+ return new JsObject._fromJs(JS('=Object', 'new #()', constr));
+ case 1:
+ return new JsObject._fromJs(JS('=Object', 'new #(#)', constr, args[0]));
+ case 2:
+ return new JsObject._fromJs(JS('=Object', 'new #(#,#)', constr, args[0],
+ args[1]));
+ case 3:
+ return new JsObject._fromJs(JS('=Object', 'new #(#,#,#)', constr,
+ args[0], args[1], args[2]));
+ case 4:
+ return new JsObject._fromJs(JS('=Object', 'new #(#,#,#,#)', constr,
+ args[0], args[1], args[2], args[3]));
+ case 5:
+ return new JsObject._fromJs(JS('=Object', 'new #(#,#,#,#,#)', constr,
+ args[0], args[1], args[2], args[3], args[4]));
+ case 6:
+ return new JsObject._fromJs(JS('=Object', 'new #(#,#,#,#,#,#)', constr,
+ args[0], args[1], args[2], args[3], args[4], args[5]));
+ case 7:
+ return new JsObject._fromJs(JS('=Object', 'new #(#,#,#,#,#,#,#)',
+ constr, args[0], args[1], args[2], args[3], args[4], args[5],
+ args[6]));
+ case 8:
+ return new JsObject._fromJs(JS('=Object', 'new #(#,#,#,#,#,#,#,#)',
+ constr, args[0], args[1], args[2], args[3], args[4], args[5],
+ args[6], args[7]));
+ case 9:
+ return new JsObject._fromJs(JS('=Object', 'new #(#,#,#,#,#,#,#,#,#)',
+ constr, args[0], args[1], args[2], args[3], args[4], args[5],
+ args[6], args[7], args[8]));
+ case 10:
+ return new JsObject._fromJs(JS('=Object', 'new #(#,#,#,#,#,#,#,#,#,#)',
+ constr, args[0], args[1], args[2], args[3], args[4], args[5],
+ args[6], args[7], args[8], args[9]));
+ }
+ return new JsObject._fromJs(JS('=Object', r'''(function(){
+var Type = function(){};
+Type.prototype = #.prototype;
+var instance = new Type();
+ret = #.apply(instance, #);
+ret = Object(ret) === ret ? ret : instance;
+return ret;
+})()''', constr, constr, args));
+ }
+
+ factory JsObject._json(data) => new JsObject._fromJs(_convertDataTree(data));
+
+ static _convertDataTree(data) {
+ if (data is Map) {
+ final convertedData = JS('=Object', '{}');
+ for (var key in data.keys) {
+ JS('=Object', '#[#]=#', convertedData, key,
+ _convertDataTree(data[key]));
+ }
+ return convertedData;
+ } else if (data is Iterable) {
+ return data.map(_convertDataTree).toList();
+ } else {
+ return _convertToJS(data);
+ }
+ }
+
+ JsObject toJs() => this;
+
+ operator[](key) =>
+ _convertToDart(JS('=Object', '#[#]', _convertToJS(this), key));
+ operator[]=(key, value) => JS('void', '#[#]=#', _convertToJS(this), key,
+ _convertToJS(value));
+
+ int get hashCode => 0;
+
+ operator==(other) => other is JsObject &&
+ JS('bool', '# === #', _convertToJS(this), _convertToJS(other));
+
+ bool hasProperty(String property) => JS('bool', '# in #', property,
+ _convertToJS(this));
+
+ void deleteProperty(String name) {
+ JS('void', 'delete #[#]', _convertToJS(this), name);
+ }
+
+ // TODO(vsm): Type type as Serializable<JsFunction> when
+ // dartbug.com/11854 is fixed.
+ bool instanceof(var type) =>
+ JS('bool', '# instanceof #', _convertToJS(this), _convertToJS(type));
+
+ String toString() {
+ try {
+ return JS('String', '#.toString()', _convertToJS(this));
+ } catch(e) {
+ return super.toString();
+ }
+ }
+
+ callMethod(String name, [List args]) =>
+ _convertToDart(JS('=Object', '#[#].apply(#, #)', _convertToJS(this), name,
+ _convertToJS(this),
+ args == null ? null : args.map(_convertToJS).toList()));
+}
+
+class JsFunction extends JsObject implements Serializable<JsFunction> {
+ JsFunction._fromJs(jsObject) : super._fromJs(jsObject);
+ apply(thisArg, [List args]) =>
+ _convertToDart(JS('=Object', '#.apply(#, #)', _convertToJS(this),
+ _convertToJS(thisArg),
+ args == null ? null : args.map(_convertToJS).toList()));
+}
+
+abstract class Serializable<T> {
+ T toJs();
+}
+
+dynamic _convertToJS(dynamic o) {
+ if (o == null) {
+ return null;
+ } else if (o is String || o is num || o is bool) {
+ return o;
+ } else if (o is JsObject) {
+ return o._jsObject;
+ } else if (o is Serializable) {
+ return _convertToJS(o.toJs());
+ } else if (o is Function) {
+ return _convertToJS(new Callback(o));
+ } else {
+ return JS('=Object', 'new DartProxy(#)', o);
+ }
+}
+
+dynamic _convertToDart(dynamic o) {
+ if (JS('bool', '# == null', o)) {
+ return null;
+ } else if (JS('bool', 'typeof # == "string" || # instanceof String', o, o) ||
+ JS('bool', 'typeof # == "number" || # instanceof Number', o, o) ||
+ JS('bool', 'typeof # == "boolean" || # instanceof Boolean', o, o)) {
+ return o;
+ } else if (JS('bool', '# instanceof Function', o)) {
+ return new JsFunction._fromJs(JS('=Object', '#', o));
+ } else if (JS('bool', '# instanceof DartProxy', o)) {
+ return JS('var', '#.o', o);
+ } else {
+ return new JsObject._fromJs(JS('=Object', '#', o));
+ }
+}
\ No newline at end of file
diff --git a/sdk/lib/js/dartium/js_dartium.dart b/sdk/lib/js/dartium/js_dartium.dart
new file mode 100644
index 0000000..393320f
--- /dev/null
+++ b/sdk/lib/js/dartium/js_dartium.dart
@@ -0,0 +1,371 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * The js.dart library provides simple JavaScript invocation from Dart that
+ * works on both Dartium and on other modern browsers via Dart2JS.
+ *
+ * It provides a model based on scoped [JsObject] objects. Proxies give Dart
+ * code access to JavaScript objects, fields, and functions as well as the
+ * ability to pass Dart objects and functions to JavaScript functions. Scopes
+ * enable developers to use proxies without memory leaks - a common challenge
+ * with cross-runtime interoperation.
+ *
+ * The top-level [context] getter provides a [JsObject] to the global JavaScript
+ * context for the page your Dart code is running on. In the following example:
+ *
+ * import 'dart:js';
+ *
+ * void main() {
+ * context.callMethod('alert', ['Hello from Dart via JavaScript']);
+ * }
+ *
+ * context['alert'] creates a proxy to the top-level alert function in
+ * JavaScript. It is invoked from Dart as a regular function that forwards to
+ * the underlying JavaScript one. By default, proxies are released when
+ * the currently executing event completes, e.g., when main is completes
+ * in this example.
+ *
+ * The library also enables JavaScript proxies to Dart objects and functions.
+ * For example, the following Dart code:
+ *
+ * context['dartCallback'] = new Callback.once((x) => print(x*2));
+ *
+ * defines a top-level JavaScript function 'dartCallback' that is a proxy to
+ * the corresponding Dart function. The [Callback.once] constructor allows the
+ * proxy to the Dart function to be retained across multiple events;
+ * instead it is released after the first invocation. (This is a common
+ * pattern for asychronous callbacks.)
+ *
+ * Note, parameters and return values are intuitively passed by value for
+ * primitives and by reference for non-primitives. In the latter case, the
+ * references are automatically wrapped and unwrapped as proxies by the library.
+ *
+ * This library also allows construction of JavaScripts objects given a
+ * [JsObject] to a corresponding JavaScript constructor. For example, if the
+ * following JavaScript is loaded on the page:
+ *
+ * function Foo(x) {
+ * this.x = x;
+ * }
+ *
+ * Foo.prototype.add = function(other) {
+ * return new Foo(this.x + other.x);
+ * }
+ *
+ * then, the following Dart:
+ *
+ * var foo = new JsObject(context['Foo'], [42]);
+ * var foo2 = foo.callMethod('add', [foo]);
+ * print(foo2['x']);
+ *
+ * will construct a JavaScript Foo object with the parameter 42, invoke its
+ * add method, and return a [JsObject] to a new Foo object whose x field is 84.
+ */
+
+library dart.js;
+
+import 'dart:html';
+import 'dart:isolate';
+
+// Global ports to manage communication from Dart to JS.
+SendPortSync _jsPortSync = window.lookupPort('dart-js-context');
+SendPortSync _jsPortCreate = window.lookupPort('dart-js-create');
+SendPortSync _jsPortInstanceof = window.lookupPort('dart-js-instanceof');
+SendPortSync _jsPortDeleteProperty = window.lookupPort('dart-js-delete-property');
+SendPortSync _jsPortConvert = window.lookupPort('dart-js-convert');
+
+/**
+ * Returns a proxy to the global JavaScript context for this page.
+ */
+JsObject get context => _deserialize(_jsPortSync.callSync([]));
+
+/**
+ * Converts a json-like [data] to a JavaScript map or array and return a
+ * [JsObject] to it.
+ */
+JsObject jsify(dynamic data) => data == null ? null : new JsObject._json(data);
+
+/**
+ * Converts a local Dart function to a callback that can be passed to
+ * JavaScript.
+ */
+class Callback implements Serializable<JsFunction> {
+ JsFunction _f;
+
+ Callback._(Function f, bool withThis) {
+ final id = _proxiedObjectTable.add((List args) {
+ final arguments = new List.from(args);
+ if (!withThis) arguments.removeAt(0);
+ return Function.apply(f, arguments);
+ });
+ _f = new JsFunction._internal(_proxiedObjectTable.sendPort, id);
+ }
+
+ factory Callback(Function f) => new Callback._(f, false);
+ factory Callback.withThis(Function f) => new Callback._(f, true);
+
+ JsFunction toJs() => _f;
+}
+
+/**
+ * Proxies to JavaScript objects.
+ */
+class JsObject implements Serializable<JsObject> {
+ final SendPortSync _port;
+ final String _id;
+
+ /**
+ * Constructs a [JsObject] to a new JavaScript object by invoking a (proxy to
+ * a) JavaScript [constructor]. The [arguments] list should contain either
+ * primitive values, DOM elements, or Proxies.
+ */
+ factory JsObject(Serializable<JsFunction> constructor, [List arguments]) {
+ final params = [constructor];
+ if (arguments != null) params.addAll(arguments);
+ final serialized = params.map(_serialize).toList();
+ final result = _jsPortCreate.callSync(serialized);
+ return _deserialize(result);
+ }
+
+ /**
+ * Constructs a [JsObject] to a new JavaScript map or list created defined via
+ * Dart map or list.
+ */
+ factory JsObject._json(data) => _convert(data);
+
+ static _convert(data) =>
+ _deserialize(_jsPortConvert.callSync(_serializeDataTree(data)));
+
+ static _serializeDataTree(data) {
+ if (data is Map) {
+ final entries = new List();
+ for (var key in data.keys) {
+ entries.add([key, _serializeDataTree(data[key])]);
+ }
+ return ['map', entries];
+ } else if (data is Iterable) {
+ return ['list', data.map(_serializeDataTree).toList()];
+ } else {
+ return ['simple', _serialize(data)];
+ }
+ }
+
+ JsObject._internal(this._port, this._id);
+
+ JsObject toJs() => this;
+
+ // Resolve whether this is needed.
+ operator[](arg) => _forward(this, '[]', 'method', [ arg ]);
+
+ // Resolve whether this is needed.
+ operator[]=(key, value) => _forward(this, '[]=', 'method', [ key, value ]);
+
+ int get hashCode => _id.hashCode;
+
+ // Test if this is equivalent to another Proxy. This essentially
+ // maps to JavaScript's === operator.
+ operator==(other) => other is JsObject && this._id == other._id;
+
+ /**
+ * Check if this [JsObject] has a [name] property.
+ */
+ bool hasProperty(String name) => _forward(this, name, 'hasProperty', []);
+
+ /**
+ * Delete the [name] property.
+ */
+ void deleteProperty(String name) {
+ _jsPortDeleteProperty.callSync([this, name].map(_serialize).toList());
+ }
+
+ /**
+ * Check if this [JsObject] is instance of [type].
+ */
+ bool instanceof(Serializable<JsFunction> type) =>
+ _jsPortInstanceof.callSync([this, type].map(_serialize).toList());
+
+ String toString() {
+ try {
+ return _forward(this, 'toString', 'method', []);
+ } catch(e) {
+ return super.toString();
+ }
+ }
+
+ callMethod(String name, [List args]) {
+ return _forward(this, name, 'method', args != null ? args : []);
+ }
+
+ // Forward member accesses to the backing JavaScript object.
+ static _forward(JsObject receiver, String member, String kind, List args) {
+ var result = receiver._port.callSync([receiver._id, member, kind,
+ args.map(_serialize).toList()]);
+ switch (result[0]) {
+ case 'return': return _deserialize(result[1]);
+ case 'throws': throw _deserialize(result[1]);
+ case 'none': throw new NoSuchMethodError(receiver, member, args, {});
+ default: throw 'Invalid return value';
+ }
+ }
+}
+
+/// A [JsObject] subtype to JavaScript functions.
+class JsFunction extends JsObject implements Serializable<JsFunction> {
+ JsFunction._internal(SendPortSync port, String id)
+ : super._internal(port, id);
+
+ apply(thisArg, [List args]) {
+ return JsObject._forward(this, '', 'apply',
+ [thisArg]..addAll(args == null ? [] : args));
+ }
+}
+
+/// Marker class used to indicate it is serializable to js. If a class is a
+/// [Serializable] the "toJs" method will be called and the result will be used
+/// as value.
+abstract class Serializable<T> {
+ T toJs();
+}
+
+// A table to managed local Dart objects that are proxied in JavaScript.
+class _ProxiedObjectTable {
+ // Debugging name.
+ final String _name;
+
+ // Generator for unique IDs.
+ int _nextId;
+
+ // Table of IDs to Dart objects.
+ final Map<String, Object> _registry;
+
+ // Port to handle and forward requests to the underlying Dart objects.
+ // A remote proxy is uniquely identified by an ID and SendPortSync.
+ final ReceivePortSync _port;
+
+ _ProxiedObjectTable() :
+ _name = 'dart-ref',
+ _nextId = 0,
+ _registry = {},
+ _port = new ReceivePortSync() {
+ _port.receive((msg) {
+ try {
+ final receiver = _registry[msg[0]];
+ final method = msg[1];
+ final args = msg[2].map(_deserialize).toList();
+ if (method == '#call') {
+ final func = receiver as Function;
+ var result = _serialize(func(args));
+ return ['return', result];
+ } else {
+ // TODO(vsm): Support a mechanism to register a handler here.
+ throw 'Invocation unsupported on non-function Dart proxies';
+ }
+ } catch (e) {
+ // TODO(vsm): callSync should just handle exceptions itself.
+ return ['throws', '$e'];
+ }
+ });
+ }
+
+ // Adds a new object to the table and return a new ID for it.
+ String add(x) {
+ // TODO(vsm): Cache x and reuse id.
+ final id = '$_name-${_nextId++}';
+ _registry[id] = x;
+ return id;
+ }
+
+ // Gets an object by ID.
+ Object get(String id) {
+ return _registry[id];
+ }
+
+ // Gets the current number of objects kept alive by this table.
+ get count => _registry.length;
+
+ // Gets a send port for this table.
+ get sendPort => _port.toSendPort();
+}
+
+// The singleton to manage proxied Dart objects.
+_ProxiedObjectTable _proxiedObjectTable = new _ProxiedObjectTable();
+
+/// End of proxy implementation.
+
+// Dart serialization support.
+
+_serialize(var message) {
+ if (message == null) {
+ return null; // Convert undefined to null.
+ } else if (message is String ||
+ message is num ||
+ message is bool) {
+ // Primitives are passed directly through.
+ return message;
+ } else if (message is SendPortSync) {
+ // Non-proxied objects are serialized.
+ return message;
+ } else if (message is JsFunction) {
+ // Remote function proxy.
+ return [ 'funcref', message._id, message._port ];
+ } else if (message is JsObject) {
+ // Remote object proxy.
+ return [ 'objref', message._id, message._port ];
+ } else if (message is Serializable) {
+ // use of result of toJs()
+ return _serialize(message.toJs());
+ } else if (message is Function) {
+ return _serialize(new Callback(message));
+ } else {
+ // Local object proxy.
+ return [ 'objref',
+ _proxiedObjectTable.add(message),
+ _proxiedObjectTable.sendPort ];
+ }
+}
+
+_deserialize(var message) {
+ deserializeFunction(message) {
+ var id = message[1];
+ var port = message[2];
+ if (port == _proxiedObjectTable.sendPort) {
+ // Local function.
+ return _proxiedObjectTable.get(id);
+ } else {
+ // Remote function. Forward to its port.
+ return new JsFunction._internal(port, id);
+ }
+ }
+
+ deserializeObject(message) {
+ var id = message[1];
+ var port = message[2];
+ if (port == _proxiedObjectTable.sendPort) {
+ // Local object.
+ return _proxiedObjectTable.get(id);
+ } else {
+ // Remote object.
+ return new JsObject._internal(port, id);
+ }
+ }
+
+ if (message == null) {
+ return null; // Convert undefined to null.
+ } else if (message is String ||
+ message is num ||
+ message is bool) {
+ // Primitives are passed directly through.
+ return message;
+ } else if (message is SendPortSync) {
+ // Serialized type.
+ return message;
+ }
+ var tag = message[0];
+ switch (tag) {
+ case 'funcref': return deserializeFunction(message);
+ case 'objref': return deserializeObject(message);
+ }
+ throw 'Unsupported serialized data: $message';
+}
diff --git a/sdk/lib/math/math.dart b/sdk/lib/math/math.dart
index b6ac482..6cea069 100644
--- a/sdk/lib/math/math.dart
+++ b/sdk/lib/math/math.dart
@@ -58,32 +58,24 @@
* is returned.
*/
num min(num a, num b) {
- if (a is num) {
- // TODO(floitsch): merge this if into the previous one, once dart2js
- // correctly propagates types for logical ands.
- if (b is num) {
- if (a > b) return b;
- if (a < b) return a;
- if (b is double) {
- // Special case for NaN and -0.0. If one argument is NaN return NaN.
- // [min] must also distinguish between -0.0 and 0.0.
- if (a is double) {
- if (a == 0.0) {
- // a is either 0.0 or -0.0. b is either 0.0, -0.0 or NaN.
- // The following returns -0.0 if either a or b is -0.0, and it
- // returns NaN if b is NaN.
- return (a + b) * a * b;
- }
- }
- // Check for NaN and b == -0.0.
- if (a == 0 && b.isNegative || b.isNaN) return b;
- return a;
+ if (a > b) return b;
+ if (a < b) return a;
+ if (b is double) {
+ // Special case for NaN and -0.0. If one argument is NaN return NaN.
+ // [min] must also distinguish between -0.0 and 0.0.
+ if (a is double) {
+ if (a == 0.0) {
+ // a is either 0.0 or -0.0. b is either 0.0, -0.0 or NaN.
+ // The following returns -0.0 if either a or b is -0.0, and it
+ // returns NaN if b is NaN.
+ return (a + b) * a * b;
}
- return a;
}
- throw new ArgumentError(b);
+ // Check for NaN and b == -0.0.
+ if (a == 0 && b.isNegative || b.isNaN) return b;
+ return a;
}
- throw new ArgumentError(a);
+ return a;
}
/**
@@ -95,34 +87,26 @@
* then it is unspecified which of the two arguments is returned.
*/
num max(num a, num b) {
- if (a is num) {
- // TODO(floitsch): merge this if into the previous one, once dart2js
- // correctly propagates types for logical ands.
- if (b is num) {
- if (a > b) return a;
- if (a < b) return b;
- if (b is double) {
- // Special case for NaN and -0.0. If one argument is NaN return NaN.
- // [max] must also distinguish between -0.0 and 0.0.
- if (a is double) {
- if (a == 0.0) {
- // a is either 0.0 or -0.0. b is either 0.0, -0.0, or NaN.
- // The following returns 0.0 if either a or b is 0.0, and it
- // returns NaN if b is NaN.
- return a + b;
- }
- }
- // Check for NaN.
- if (b.isNaN) return b;
- return a;
+ if (a > b) return a;
+ if (a < b) return b;
+ if (b is double) {
+ // Special case for NaN and -0.0. If one argument is NaN return NaN.
+ // [max] must also distinguish between -0.0 and 0.0.
+ if (a is double) {
+ if (a == 0.0) {
+ // a is either 0.0 or -0.0. b is either 0.0, -0.0, or NaN.
+ // The following returns 0.0 if either a or b is 0.0, and it
+ // returns NaN if b is NaN.
+ return a + b;
}
- // max(-0.0, 0) must return 0.
- if (b == 0 && a.isNegative) return b;
- return a;
}
- throw new ArgumentError(b);
+ // Check for NaN.
+ if (b.isNaN) return b;
+ return a;
}
- throw new ArgumentError(a);
+ // max(-0.0, 0) must return 0.
+ if (b == 0 && a.isNegative) return b;
+ return a;
}
/**
diff --git a/tests/co19/co19-analyzer.status b/tests/co19/co19-analyzer.status
index 906a6f5..2820b5f 100644
--- a/tests/co19/co19-analyzer.status
+++ b/tests/co19/co19-analyzer.status
@@ -20,7 +20,14 @@
# analyzer problem: forward reference of typedef with type parameters
Language/13_Libraries_and_Scripts/3_Parts_A02_t03: skip
+# not clear: typedef int func2(int);
+Language/14_Types/6_Type_dynamic_A04_t01: fail
+# TBF: _f is private, so does not collide
+Language/07_Classes/1_Instance_Methods_A05_t08: fail
+
+# TBF: return without value is not a warning
+Language/12_Statements/11_Return_A07_t01: fail
# co19 issue #380, Strings class has been removed
@@ -219,6 +226,208 @@
# co19 issue #464, not initialized final instance variable is warning, not error
Language/07_Classes/6_Constructors/1_Generative_Constructors_A09_t01: fail
+# co19 issue #442, undefined name "Expect"
+Language/07_Classes/6_Constructors/1_Generative_Constructors_A17_t04: fail, OK
+Language/07_Classes/6_Constructors/2_Factories_A06_t03: fail, OK
+Language/09_Generics/09_Generics_A05_t02: fail, OK
+Language/09_Generics/09_Generics_A05_t01: fail, OK
+Language/11_Expressions/04_Booleans/1_Boolean_Conversion_A01_t01: fail, OK
+Language/11_Expressions/04_Booleans/1_Boolean_Conversion_A02_t01: fail, OK
+Language/11_Expressions/06_Lists_A09_t01: fail, OK
+Language/11_Expressions/14_Function_Invocation/2_Binding_Actuals_to_Formals_A02_t01: fail, OK
+Language/11_Expressions/14_Function_Invocation/2_Binding_Actuals_to_Formals_A03_t01: fail, OK
+Language/11_Expressions/18_Assignment_A02_t01: fail, OK
+Language/11_Expressions/18_Assignment_A04_t06: fail, OK
+Language/11_Expressions/18_Assignment_A06_t01: fail, OK
+Language/11_Expressions/19_Conditional_A02_t03: fail, OK
+Language/11_Expressions/19_Conditional_A02_t04: fail, OK
+Language/11_Expressions/19_Conditional_A04_t03: fail, OK
+Language/11_Expressions/27_Unary_Expressions_A02_t03: fail, OK
+Language/12_Statements/03_Variable_Declaration_A01_t01: fail, OK
+Language/12_Statements/03_Variable_Declaration_A01_t02: fail, OK
+Language/12_Statements/05_If_A02_t01: fail, OK
+Language/12_Statements/05_If_A02_t02: fail, OK
+Language/12_Statements/10_Try_A01_t01: fail, OK
+Language/12_Statements/11_Return_A03_t02: fail, OK
+Language/12_Statements/11_Return_A04_t01: fail, OK
+Language/12_Statements/15_Assert_A03_t03: fail, OK
+Language/12_Statements/15_Assert_A03_t09: fail, OK
+Language/12_Statements/15_Assert_A03_t08: fail, OK
+Language/12_Statements/15_Assert_A04_t02: fail, OK
+Language/14_Types/2_Dynamic_Type_System_A01_t01: fail, OK
+Language/14_Types/4_Interface_Types_A08_t03: fail, OK
+Language/14_Types/7_Type_Void_A04_t02: fail, OK
+Language/15_Reference/1_Lexical_Rules/2_Comments_A04_t03: fail, OK
+LibTest/core/AssertionError/toString_A01_t01: fail, OK
+LibTest/core/Date/add_A01_t01: fail, OK
+LibTest/core/Date/add_A03_t01: fail, OK
+LibTest/core/Date/add_A02_t01: fail, OK
+LibTest/core/Date/add_A05_t01: fail, OK
+LibTest/core/Date/compareTo_A01_t01: fail, OK
+LibTest/core/Date/compareTo_A02_t01: fail, OK
+LibTest/core/Date/compareTo_A03_t01: fail, OK
+LibTest/core/Date/compareTo_A01_t02: fail, OK
+LibTest/core/Date/Date.fromMillisecondsSinceEpoch_A01_t01: fail, OK
+LibTest/core/Date/Date.fromMillisecondsSinceEpoch_A01_t02: fail, OK
+LibTest/core/Date/Date.fromMillisecondsSinceEpoch_A02_t01: fail, OK
+LibTest/core/Date/Date.fromString_A01_t01: fail, OK
+LibTest/core/Date/Date.fromString_A01_t02: fail, OK
+LibTest/core/Date/Date.fromString_A02_t01: fail, OK
+LibTest/core/Date/Date.fromString_A03_t01: fail, OK
+LibTest/core/Date/Date.now_A01_t01: fail, OK
+LibTest/core/Date/Date.now_A01_t02: fail, OK
+LibTest/core/Date/Date.now_A01_t03: fail, OK
+LibTest/core/Date/Date.utc_A01_t01: fail, OK
+LibTest/core/Date/Date_A01_t01: fail, OK
+LibTest/core/Date/Date_A01_t03: fail, OK
+LibTest/core/Date/Date_A01_t02: fail, OK
+LibTest/core/Date/Date_A01_t04: fail, OK
+LibTest/core/Date/day_A01_t01: fail, OK
+LibTest/core/Date/difference_A01_t01: fail, OK
+LibTest/core/Date/difference_A01_t02: fail, OK
+LibTest/core/Date/difference_A02_t01: fail, OK
+LibTest/core/Date/hour_A01_t01: fail, OK
+LibTest/core/Date/isUtc_A01_t01: fail, OK
+LibTest/core/Date/millisecond_A01_t01: fail, OK
+LibTest/core/Date/millisecondsSinceEpoch_A01_t01: fail, OK
+LibTest/core/Date/minute_A01_t01: fail, OK
+LibTest/core/Date/month_A01_t01: fail, OK
+LibTest/core/Date/operator_equality_A01_t01: fail, OK
+LibTest/core/Date/operator_GE_A01_t01: fail, OK
+LibTest/core/Date/operator_GT_A01_t01: fail, OK
+LibTest/core/Date/operator_LE_A01_t01: fail, OK
+LibTest/core/Date/operator_LT_A01_t01: fail, OK
+LibTest/core/Date/second_A01_t01: fail, OK
+LibTest/core/Date/subtract_A01_t01: fail, OK
+LibTest/core/Date/subtract_A03_t01: fail, OK
+LibTest/core/Date/subtract_A02_t01: fail, OK
+LibTest/core/Date/subtract_A05_t01: fail, OK
+LibTest/core/Date/timeZoneName_A01_t01: fail, OK
+LibTest/core/Date/timeZoneOffset_A01_t01: fail, OK
+LibTest/core/Date/toLocal_A01_t01: fail, OK
+LibTest/core/Date/toString_A01_t01: fail, OK
+LibTest/core/Date/toString_A02_t01: fail, OK
+LibTest/core/Date/toUtc_A01_t01: fail, OK
+LibTest/core/Date/year_A01_t01: fail, OK
+LibTest/core/Date/weekday_A01_t01: fail, OK
+LibTest/core/List/getRange_A06_t01: fail, OK
+LibTest/core/List/indexOf_A06_t01: fail, OK
+LibTest/core/List/operator_subscript_A03_t01: fail, OK
+LibTest/core/List/operator_subscripted_assignment_A03_t01: fail, OK
+LibTest/core/Map/putIfAbsent_A01_t04: fail, OK
+LibTest/core/Strings/concatAll_A04_t01: fail, OK
+LibTest/core/Strings/join_A04_t01: fail, OK
+
+# co19 issue #443, Undefined class 'InvocationMirror'
+Language/11_Expressions/14_Function_Invocation/4_Function_Expression_Invocation_A01_t02: fail, OK
+Language/11_Expressions/15_Method_Invocation/1_Ordinary_Invocation_A05_t02: fail, OK
+Language/11_Expressions/15_Method_Invocation/1_Ordinary_Invocation_A05_t03: fail, OK
+Language/11_Expressions/15_Method_Invocation/1_Ordinary_Invocation_A05_t06: fail, OK
+Language/11_Expressions/17_Getter_Invocation_A02_t01: fail, OK
+Language/11_Expressions/17_Getter_Invocation_A02_t02: fail, OK
+
+# co19 issue #444, AsyncError has been removed
+LibTest/async/Completer/complete_A02_t02: fail, OK
+LibTest/async/Completer/completeError_A01_t01: fail, OK
+LibTest/async/Completer/completeError_A03_t02: fail, OK
+LibTest/async/Future/catchError_A01_t01: fail, OK
+LibTest/async/Future/catchError_A01_t02: fail, OK
+LibTest/async/Future/catchError_A02_t01: fail, OK
+LibTest/async/Future/catchError_A03_t01: fail, OK
+LibTest/async/Future/catchError_A03_t02: fail, OK
+LibTest/async/Future/catchError_A03_t03: fail, OK
+LibTest/async/Future/forEach_A03_t01: fail, OK
+LibTest/async/Future/Future.delayed_A02_t01: fail, OK
+LibTest/async/Future/then_A02_t01: fail, OK
+LibTest/async/Future/then_A02_t02: fail, OK
+LibTest/async/Future/then_A03_t01: fail, OK
+LibTest/async/Future/then_A04_t01: fail, OK
+LibTest/async/Future/whenComplete_A03_t01: fail, OK
+LibTest/async/Future/whenComplete_A04_t02: fail, OK
+
+# co19 issue #445, Future.immediate was repalce with Future.value
+LibTest/async/Future/asStream_A01_t01: fail, OK
+LibTest/async/Future/asStream_A01_t02: fail, OK
+LibTest/async/Future/asStream_A02_t01: fail, OK
+LibTest/async/Future/Future.immediate_A01_t01: fail, OK
+LibTest/async/Future/Future.immediateError_A01_t01: fail, OK
+LibTest/async/Future/then_A01_t03: fail, OK
+
+# co19 issue #446, Date was replaced with DateTime
+Language/14_Types/6_Type_dynamic_A03_t01: fail, OK
+
+# co19 issue 447, In Future delayed int replaced with Duration
+LibTest/async/Future/asStream_A01_t02: fail, OK
+LibTest/async/Future/asStream_A02_t01: fail, OK
+LibTest/async/Future/forEach_A01_t01: fail, OK
+LibTest/async/Future/forEach_A02_t01: fail, OK
+LibTest/async/Future/then_A01_t03: fail, OK
+LibTest/async/Future/wait_A01_t01: fail, OK
+LibTest/async/Future/wait_A01_t04: fail, OK
+LibTest/async/Future/wait_A01_t05: fail, OK
+LibTest/async/Future/wait_A01_t06: fail, OK
+LibTest/async/Future/whenComplete_A01_t01: fail, OK
+LibTest/async/Future/whenComplete_A02_t01: fail, OK
+LibTest/async/Future/whenComplete_A04_t01: fail, OK
+
+# co19 issue #448, Collection was removed
+LibTest/collection/Queue/Queue.from_A01_t01: fail, OK
+LibTest/collection/Queue/Queue.from_A01_t02: fail, OK
+LibTest/core/List/List.from_A01_t01: fail, OK
+LibTest/core/Match/pattern_A01_t01: fail, OK
+LibTest/core/Match/str_A01_t01: fail, OK
+LibTest/core/RegExp/allMatches_A01_t01: fail, OK
+LibTest/core/Set/intersection_A01_t02: fail, OK
+
+# co19 issue #449, Strings was removed
+LibTest/core/Strings/concatAll_A01_t01: fail, OK
+LibTest/core/Strings/concatAll_A02_t01: fail, OK
+LibTest/core/Strings/concatAll_A03_t01: fail, OK
+LibTest/core/Strings/join_A01_t01: fail, OK
+LibTest/core/Strings/join_A02_t01: fail, OK
+LibTest/core/Strings/join_A03_t01: fail, OK
+
+# co19 issue #450, The class 'List' does not have a constructor 'fixedLength'
+LibTest/core/List/add_A02_t01: fail, OK
+LibTest/core/List/addAll_A02_t01: fail, OK
+LibTest/core/List/clear_A02_t01: fail, OK
+LibTest/core/List/length_A04_t01: fail, OK
+LibTest/core/List/removeLast_A02_t01: fail, OK
+LibTest/core/List/removeRange_A02_t01: fail, OK
+
+# co19 issue 451, Set.intersection() requires Set argument
+LibTest/core/Set/intersection_A01_t01: fail, OK
+LibTest/core/Set/intersection_A01_t03: fail, OK
+LibTest/core/Set/intersection_A03_t01: fail, OK
+
+# co19 issue 452, more method in Iterable
+LibTest/core/Set/Set.from_A01_t02: fail, OK
+
+# co19 issue #453, abstract member in concrete class
+Language/07_Classes/07_Classes_A07_t10: fail, OK
+
+# co19 issue #454, should be static warning
+Language/11_Expressions/11_Instance_Creation/1_New_A01_t04: fail, OK
+
+# co19 issue #455, undeclared identifier is static warning
+Language/11_Expressions/14_Function_Invocation/3_Unqualified_Invocation_A01_t10: fail, OK
+Language/12_Statements/04_Local_Function_Declaration_A02_t02: fail, OK
+Language/13_Libraries_and_Scripts/1_Imports_A02_t12: fail, OK
+Language/13_Libraries_and_Scripts/1_Imports_A02_t14: fail, OK
+Language/13_Libraries_and_Scripts/1_Imports_A02_t15: fail, OK
+
+# co19 issue #456
+Language/11_Expressions/15_Method_Invocation/3_Static_Invocation_A03_t04: fail, OK
+Language/11_Expressions/15_Method_Invocation/3_Static_Invocation_A03_t05: fail, OK
+Language/11_Expressions/15_Method_Invocation/3_Static_Invocation_A04_t08: fail, OK
+
+# co19 issue 457, malformed type is static warning
+Language/11_Expressions/31_Type_Test_A05_t01: fail, OK
+Language/11_Expressions/31_Type_Test_A05_t02: fail, OK
+Language/11_Expressions/31_Type_Test_A05_t03: fail, OK
+Language/11_Expressions/32_Type_Cast_A04_t01: fail, OK
+Language/11_Expressions/32_Type_Cast_A04_t02: fail, OK
+
# co19 issue #465, any use of a malbounded type gives rise to a static warning.
Language/11_Expressions/11_Instance_Creation/1_New_A05_t01: fail, OK
Language/11_Expressions/11_Instance_Creation/1_New_A05_t02: fail, OK
@@ -226,4 +435,3 @@
Language/11_Expressions/11_Instance_Creation_A03_t01: fail, OK
Language/11_Expressions/11_Instance_Creation_A04_t01: fail, OK
Language/11_Expressions/11_Instance_Creation_A04_t02: fail, OK
-
diff --git a/tests/co19/co19-analyzer2.status b/tests/co19/co19-analyzer2.status
index 71b2817..81a6b85 100644
--- a/tests/co19/co19-analyzer2.status
+++ b/tests/co19/co19-analyzer2.status
@@ -20,7 +20,14 @@
# analyzer problem: forward reference of typedef with type parameters
Language/13_Libraries_and_Scripts/3_Parts_A02_t03: skip
+# not clear: typedef int func2(int);
+Language/14_Types/6_Type_dynamic_A04_t01: fail
+# TBF: _f is private, so does not collide
+Language/07_Classes/1_Instance_Methods_A05_t08: fail
+
+# TBF: return without value is not a warning
+Language/12_Statements/11_Return_A07_t01: fail
# co19 issue #380, Strings class has been removed
@@ -219,6 +226,208 @@
# co19 issue #464, not initialized final instance variable is warning, not error
Language/07_Classes/6_Constructors/1_Generative_Constructors_A09_t01: fail
+# co19 issue #442, undefined name "Expect"
+Language/07_Classes/6_Constructors/1_Generative_Constructors_A17_t04: fail, OK
+Language/07_Classes/6_Constructors/2_Factories_A06_t03: fail, OK
+Language/09_Generics/09_Generics_A05_t02: fail, OK
+Language/09_Generics/09_Generics_A05_t01: fail, OK
+Language/11_Expressions/04_Booleans/1_Boolean_Conversion_A01_t01: fail, OK
+Language/11_Expressions/04_Booleans/1_Boolean_Conversion_A02_t01: fail, OK
+Language/11_Expressions/06_Lists_A09_t01: fail, OK
+Language/11_Expressions/14_Function_Invocation/2_Binding_Actuals_to_Formals_A02_t01: fail, OK
+Language/11_Expressions/14_Function_Invocation/2_Binding_Actuals_to_Formals_A03_t01: fail, OK
+Language/11_Expressions/18_Assignment_A02_t01: fail, OK
+Language/11_Expressions/18_Assignment_A04_t06: fail, OK
+Language/11_Expressions/18_Assignment_A06_t01: fail, OK
+Language/11_Expressions/19_Conditional_A02_t03: fail, OK
+Language/11_Expressions/19_Conditional_A02_t04: fail, OK
+Language/11_Expressions/19_Conditional_A04_t03: fail, OK
+Language/11_Expressions/27_Unary_Expressions_A02_t03: fail, OK
+Language/12_Statements/03_Variable_Declaration_A01_t01: fail, OK
+Language/12_Statements/03_Variable_Declaration_A01_t02: fail, OK
+Language/12_Statements/05_If_A02_t01: fail, OK
+Language/12_Statements/05_If_A02_t02: fail, OK
+Language/12_Statements/10_Try_A01_t01: fail, OK
+Language/12_Statements/11_Return_A03_t02: fail, OK
+Language/12_Statements/11_Return_A04_t01: fail, OK
+Language/12_Statements/15_Assert_A03_t03: fail, OK
+Language/12_Statements/15_Assert_A03_t09: fail, OK
+Language/12_Statements/15_Assert_A03_t08: fail, OK
+Language/12_Statements/15_Assert_A04_t02: fail, OK
+Language/14_Types/2_Dynamic_Type_System_A01_t01: fail, OK
+Language/14_Types/4_Interface_Types_A08_t03: fail, OK
+Language/14_Types/7_Type_Void_A04_t02: fail, OK
+Language/15_Reference/1_Lexical_Rules/2_Comments_A04_t03: fail, OK
+LibTest/core/AssertionError/toString_A01_t01: fail, OK
+LibTest/core/Date/add_A01_t01: fail, OK
+LibTest/core/Date/add_A03_t01: fail, OK
+LibTest/core/Date/add_A02_t01: fail, OK
+LibTest/core/Date/add_A05_t01: fail, OK
+LibTest/core/Date/compareTo_A01_t01: fail, OK
+LibTest/core/Date/compareTo_A02_t01: fail, OK
+LibTest/core/Date/compareTo_A03_t01: fail, OK
+LibTest/core/Date/compareTo_A01_t02: fail, OK
+LibTest/core/Date/Date.fromMillisecondsSinceEpoch_A01_t01: fail, OK
+LibTest/core/Date/Date.fromMillisecondsSinceEpoch_A01_t02: fail, OK
+LibTest/core/Date/Date.fromMillisecondsSinceEpoch_A02_t01: fail, OK
+LibTest/core/Date/Date.fromString_A01_t01: fail, OK
+LibTest/core/Date/Date.fromString_A01_t02: fail, OK
+LibTest/core/Date/Date.fromString_A02_t01: fail, OK
+LibTest/core/Date/Date.fromString_A03_t01: fail, OK
+LibTest/core/Date/Date.now_A01_t01: fail, OK
+LibTest/core/Date/Date.now_A01_t02: fail, OK
+LibTest/core/Date/Date.now_A01_t03: fail, OK
+LibTest/core/Date/Date.utc_A01_t01: fail, OK
+LibTest/core/Date/Date_A01_t01: fail, OK
+LibTest/core/Date/Date_A01_t03: fail, OK
+LibTest/core/Date/Date_A01_t02: fail, OK
+LibTest/core/Date/Date_A01_t04: fail, OK
+LibTest/core/Date/day_A01_t01: fail, OK
+LibTest/core/Date/difference_A01_t01: fail, OK
+LibTest/core/Date/difference_A01_t02: fail, OK
+LibTest/core/Date/difference_A02_t01: fail, OK
+LibTest/core/Date/hour_A01_t01: fail, OK
+LibTest/core/Date/isUtc_A01_t01: fail, OK
+LibTest/core/Date/millisecond_A01_t01: fail, OK
+LibTest/core/Date/millisecondsSinceEpoch_A01_t01: fail, OK
+LibTest/core/Date/minute_A01_t01: fail, OK
+LibTest/core/Date/month_A01_t01: fail, OK
+LibTest/core/Date/operator_equality_A01_t01: fail, OK
+LibTest/core/Date/operator_GE_A01_t01: fail, OK
+LibTest/core/Date/operator_GT_A01_t01: fail, OK
+LibTest/core/Date/operator_LE_A01_t01: fail, OK
+LibTest/core/Date/operator_LT_A01_t01: fail, OK
+LibTest/core/Date/second_A01_t01: fail, OK
+LibTest/core/Date/subtract_A01_t01: fail, OK
+LibTest/core/Date/subtract_A03_t01: fail, OK
+LibTest/core/Date/subtract_A02_t01: fail, OK
+LibTest/core/Date/subtract_A05_t01: fail, OK
+LibTest/core/Date/timeZoneName_A01_t01: fail, OK
+LibTest/core/Date/timeZoneOffset_A01_t01: fail, OK
+LibTest/core/Date/toLocal_A01_t01: fail, OK
+LibTest/core/Date/toString_A01_t01: fail, OK
+LibTest/core/Date/toString_A02_t01: fail, OK
+LibTest/core/Date/toUtc_A01_t01: fail, OK
+LibTest/core/Date/year_A01_t01: fail, OK
+LibTest/core/Date/weekday_A01_t01: fail, OK
+LibTest/core/List/getRange_A06_t01: fail, OK
+LibTest/core/List/indexOf_A06_t01: fail, OK
+LibTest/core/List/operator_subscript_A03_t01: fail, OK
+LibTest/core/List/operator_subscripted_assignment_A03_t01: fail, OK
+LibTest/core/Map/putIfAbsent_A01_t04: fail, OK
+LibTest/core/Strings/concatAll_A04_t01: fail, OK
+LibTest/core/Strings/join_A04_t01: fail, OK
+
+# co19 issue #443, Undefined class 'InvocationMirror'
+Language/11_Expressions/14_Function_Invocation/4_Function_Expression_Invocation_A01_t02: fail, OK
+Language/11_Expressions/15_Method_Invocation/1_Ordinary_Invocation_A05_t02: fail, OK
+Language/11_Expressions/15_Method_Invocation/1_Ordinary_Invocation_A05_t03: fail, OK
+Language/11_Expressions/15_Method_Invocation/1_Ordinary_Invocation_A05_t06: fail, OK
+Language/11_Expressions/17_Getter_Invocation_A02_t01: fail, OK
+Language/11_Expressions/17_Getter_Invocation_A02_t02: fail, OK
+
+# co19 issue #444, AsyncError has been removed
+LibTest/async/Completer/complete_A02_t02: fail, OK
+LibTest/async/Completer/completeError_A01_t01: fail, OK
+LibTest/async/Completer/completeError_A03_t02: fail, OK
+LibTest/async/Future/catchError_A01_t01: fail, OK
+LibTest/async/Future/catchError_A01_t02: fail, OK
+LibTest/async/Future/catchError_A02_t01: fail, OK
+LibTest/async/Future/catchError_A03_t01: fail, OK
+LibTest/async/Future/catchError_A03_t02: fail, OK
+LibTest/async/Future/catchError_A03_t03: fail, OK
+LibTest/async/Future/forEach_A03_t01: fail, OK
+LibTest/async/Future/Future.delayed_A02_t01: fail, OK
+LibTest/async/Future/then_A02_t01: fail, OK
+LibTest/async/Future/then_A02_t02: fail, OK
+LibTest/async/Future/then_A03_t01: fail, OK
+LibTest/async/Future/then_A04_t01: fail, OK
+LibTest/async/Future/whenComplete_A03_t01: fail, OK
+LibTest/async/Future/whenComplete_A04_t02: fail, OK
+
+# co19 issue #445, Future.immediate was repalce with Future.value
+LibTest/async/Future/asStream_A01_t01: fail, OK
+LibTest/async/Future/asStream_A01_t02: fail, OK
+LibTest/async/Future/asStream_A02_t01: fail, OK
+LibTest/async/Future/Future.immediate_A01_t01: fail, OK
+LibTest/async/Future/Future.immediateError_A01_t01: fail, OK
+LibTest/async/Future/then_A01_t03: fail, OK
+
+# co19 issue #446, Date was replaced with DateTime
+Language/14_Types/6_Type_dynamic_A03_t01: fail, OK
+
+# co19 issue 447, In Future delayed int replaced with Duration
+LibTest/async/Future/asStream_A01_t02: fail, OK
+LibTest/async/Future/asStream_A02_t01: fail, OK
+LibTest/async/Future/forEach_A01_t01: fail, OK
+LibTest/async/Future/forEach_A02_t01: fail, OK
+LibTest/async/Future/then_A01_t03: fail, OK
+LibTest/async/Future/wait_A01_t01: fail, OK
+LibTest/async/Future/wait_A01_t04: fail, OK
+LibTest/async/Future/wait_A01_t05: fail, OK
+LibTest/async/Future/wait_A01_t06: fail, OK
+LibTest/async/Future/whenComplete_A01_t01: fail, OK
+LibTest/async/Future/whenComplete_A02_t01: fail, OK
+LibTest/async/Future/whenComplete_A04_t01: fail, OK
+
+# co19 issue #448, Collection was removed
+LibTest/collection/Queue/Queue.from_A01_t01: fail, OK
+LibTest/collection/Queue/Queue.from_A01_t02: fail, OK
+LibTest/core/List/List.from_A01_t01: fail, OK
+LibTest/core/Match/pattern_A01_t01: fail, OK
+LibTest/core/Match/str_A01_t01: fail, OK
+LibTest/core/RegExp/allMatches_A01_t01: fail, OK
+LibTest/core/Set/intersection_A01_t02: fail, OK
+
+# co19 issue #449, Strings was removed
+LibTest/core/Strings/concatAll_A01_t01: fail, OK
+LibTest/core/Strings/concatAll_A02_t01: fail, OK
+LibTest/core/Strings/concatAll_A03_t01: fail, OK
+LibTest/core/Strings/join_A01_t01: fail, OK
+LibTest/core/Strings/join_A02_t01: fail, OK
+LibTest/core/Strings/join_A03_t01: fail, OK
+
+# co19 issue #450, The class 'List' does not have a constructor 'fixedLength'
+LibTest/core/List/add_A02_t01: fail, OK
+LibTest/core/List/addAll_A02_t01: fail, OK
+LibTest/core/List/clear_A02_t01: fail, OK
+LibTest/core/List/length_A04_t01: fail, OK
+LibTest/core/List/removeLast_A02_t01: fail, OK
+LibTest/core/List/removeRange_A02_t01: fail, OK
+
+# co19 issue 451, Set.intersection() requires Set argument
+LibTest/core/Set/intersection_A01_t01: fail, OK
+LibTest/core/Set/intersection_A01_t03: fail, OK
+LibTest/core/Set/intersection_A03_t01: fail, OK
+
+# co19 issue 452, more method in Iterable
+LibTest/core/Set/Set.from_A01_t02: fail, OK
+
+# co19 issue #453, abstract member in concrete class
+Language/07_Classes/07_Classes_A07_t10: fail, OK
+
+# co19 issue #454, should be static warning
+Language/11_Expressions/11_Instance_Creation/1_New_A01_t04: fail, OK
+
+# co19 issue #455, undeclared identifier is static warning
+Language/11_Expressions/14_Function_Invocation/3_Unqualified_Invocation_A01_t10: fail, OK
+Language/12_Statements/04_Local_Function_Declaration_A02_t02: fail, OK
+Language/13_Libraries_and_Scripts/1_Imports_A02_t12: fail, OK
+Language/13_Libraries_and_Scripts/1_Imports_A02_t14: fail, OK
+Language/13_Libraries_and_Scripts/1_Imports_A02_t15: fail, OK
+
+# co19 issue #456
+Language/11_Expressions/15_Method_Invocation/3_Static_Invocation_A03_t04: fail, OK
+Language/11_Expressions/15_Method_Invocation/3_Static_Invocation_A03_t05: fail, OK
+Language/11_Expressions/15_Method_Invocation/3_Static_Invocation_A04_t08: fail, OK
+
+# co19 issue 457, malformed type is static warning
+Language/11_Expressions/31_Type_Test_A05_t01: fail, OK
+Language/11_Expressions/31_Type_Test_A05_t02: fail, OK
+Language/11_Expressions/31_Type_Test_A05_t03: fail, OK
+Language/11_Expressions/32_Type_Cast_A04_t01: fail, OK
+Language/11_Expressions/32_Type_Cast_A04_t02: fail, OK
+
# co19 issue #465, any use of a malbounded type gives rise to a static warning.
Language/11_Expressions/11_Instance_Creation/1_New_A05_t01: fail, OK
Language/11_Expressions/11_Instance_Creation/1_New_A05_t02: fail, OK
@@ -226,4 +435,3 @@
Language/11_Expressions/11_Instance_Creation_A03_t01: fail, OK
Language/11_Expressions/11_Instance_Creation_A04_t01: fail, OK
Language/11_Expressions/11_Instance_Creation_A04_t02: fail, OK
-
diff --git a/tests/co19/co19-dart2dart.status b/tests/co19/co19-dart2dart.status
index 5692eb8..16e1222 100644
--- a/tests/co19/co19-dart2dart.status
+++ b/tests/co19/co19-dart2dart.status
@@ -4,6 +4,9 @@
[ $compiler == dart2dart ]
+LibTest/math/max_A01_t03: Fail # co19 issue 467
+LibTest/math/min_A01_t03: Fail # co19 issue 467
+
# The following tests fail because they contain number literals with a + prefix (co19 issue 428)
LibTest/core/double/floor_A01_t05: Fail # issue 428
LibTest/core/double/ceil_A01_t05: Fail # issue 428
diff --git a/tests/co19/co19-dart2js.status b/tests/co19/co19-dart2js.status
index dd3854d..33ec9d5 100644
--- a/tests/co19/co19-dart2js.status
+++ b/tests/co19/co19-dart2js.status
@@ -12,6 +12,9 @@
# Crashes first, please. Then untriaged bugs. There is a section below
# for co19 bugs.
[ $compiler == dart2js ]
+LibTest/math/max_A01_t03: Fail # co19 issue 467
+LibTest/math/min_A01_t03: Fail # co19 issue 467
+
Language/03_Overview/1_Scoping_A02_t05: Fail # TODO(ahe): Please triage this failure.
Language/03_Overview/1_Scoping_A02_t06: Fail # TODO(ahe): Please triage this failure.
Language/05_Variables/05_Variables_A05_t04: Fail # TODO(ahe): Please triage this failure.
@@ -72,6 +75,7 @@
Language/12_Statements/04_Local_Function_Declaration_A02_t02: Fail # TODO(ahe): Please triage this failure.
Language/12_Statements/09_Switch_A02_t02: Fail # TODO(ahe): Please triage this failure.
Language/12_Statements/09_Switch_A06_t02: Fail # co19 issue 413
+Language/12_Statements/10_Try_A06_t01: Fail # Issue 11850: dart2js inlining results in stack traces not as accurate
Language/12_Statements/10_Try_A07_t03: Fail # TODO(ahe): Please triage this failure.
Language/12_Statements/11_Return_A05_t01: Fail # TODO(ahe): Please triage this failure.
Language/12_Statements/11_Return_A05_t02: Fail # TODO(ahe): Please triage this failure.
@@ -132,6 +136,7 @@
LibTest/math/pow_A01_t01: Fail # TODO(ahe): Please triage this failure.
LibTest/math/pow_A11_t01: Fail # TODO(ahe): Please triage this failure.
LibTest/math/pow_A13_t01: Fail # TODO(ahe): Please triage this failure.
+LibTest/core/List/sort_A01_t04: Pass, Slow # http://dartbug.com/11846
[ $compiler == dart2js && $runtime == jsshell ]
diff --git a/tests/co19/co19-runtime.status b/tests/co19/co19-runtime.status
index 75e703b..13f3b11 100644
--- a/tests/co19/co19-runtime.status
+++ b/tests/co19/co19-runtime.status
@@ -9,6 +9,9 @@
Language/11_Expressions/33_Argument_Definition_Test_A03_t01: Fail, OK # co19 issue 436
Language/11_Expressions/33_Argument_Definition_Test_A03_t02: Fail, OK # co19 issue 436
+LibTest/math/max_A01_t03: Fail # co19 issue 467
+LibTest/math/min_A01_t03: Fail # co19 issue 467
+
[ $runtime == vm && $system == windows ]
LibTest/core/Stopwatch/elapsed_A01_t01: Pass, Fail # Issue 11382.
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 fa543ff..9c7e0cd 100644
--- a/tests/compiler/dart2js/call_site_simple_type_inferer_test.dart
+++ b/tests/compiler/dart2js/call_site_simple_type_inferer_test.dart
@@ -20,7 +20,7 @@
compiler.runCompiler(uri);
var cls = findElement(compiler, className);
var member = cls.lookupLocalMember(buildSourceString(memberName));
- return check(compiler.typesTask.typesInferrer, member);
+ return check(compiler, member);
}
const String TEST_1 = r"""
@@ -216,13 +216,14 @@
'A',
'x',
enableInlining,
- (inferrer, element) {
- var expectedTypes = f(inferrer);
- var signature = element.computeSignature(inferrer.compiler);
+ (compiler, element) {
+ var expectedTypes = f(compiler);
+ var signature = element.computeSignature(compiler);
int index = 0;
+ var inferrer = compiler.typesTask.typesInferrer;
signature.forEachParameter((Element element) {
Expect.equals(expectedTypes[index++],
- inferrer.getTypeOfElement(element).simplify(inferrer.compiler));
+ inferrer.getTypeOfElement(element).simplify(compiler));
});
Expect.equals(index, expectedTypes.length);
});
@@ -233,47 +234,52 @@
doTest(test, true, f);
}
-subclassOfInterceptor(inferrer) {
- return findTypeMask(inferrer.compiler, 'Interceptor', 'nonNullSubclass');
+subclassOfInterceptor(compiler) {
+ return findTypeMask(compiler, 'Interceptor', 'nonNullSubclass');
}
void test() {
- runTest(TEST_1, (inferrer) => [inferrer.stringType]);
- runTest(TEST_2, (inferrer) => [inferrer.intType]);
- runTest(TEST_3, (inferrer) => [inferrer.numType]);
- runTest(TEST_4, (inferrer) => [inferrer.numType]);
- runTest(TEST_5, (inferrer) => [inferrer.numType]);
- runTest(TEST_6, (inferrer) => [inferrer.numType]);
- runTest(TEST_7a, (inferrer) => [subclassOfInterceptor(inferrer)]);
- runTest(TEST_7b, (inferrer) => [inferrer.dynamicType.nonNullable()]);
+ runTest(TEST_1, (compiler) => [compiler.typesTask.stringType]);
+ runTest(TEST_2, (compiler) => [compiler.typesTask.intType]);
+ runTest(TEST_3, (compiler) => [compiler.typesTask.numType]);
+ runTest(TEST_4, (compiler) => [compiler.typesTask.numType]);
+ runTest(TEST_5, (compiler) => [compiler.typesTask.numType]);
+ runTest(TEST_6, (compiler) => [compiler.typesTask.numType]);
+ runTest(TEST_7a, (compiler) => [subclassOfInterceptor(compiler)]);
+ runTest(TEST_7b,
+ (compiler) => [compiler.typesTask.dynamicType.nonNullable()]);
- runTest(TEST_8, (inferrer) => [inferrer.intType,
- subclassOfInterceptor(inferrer),
- inferrer.dynamicType.nonNullable()]);
- runTest(TEST_9, (inferrer) => [inferrer.intType, inferrer.intType]);
- // runTest(TEST_10, (inferrer) => [subclassOfInterceptor(inferrer),
- // subclassOfInterceptor(inferrer)]);
- runTest(TEST_11, (inferrer) => [subclassOfInterceptor(inferrer),
- subclassOfInterceptor(inferrer)]);
+ runTest(TEST_8, (compiler) => [compiler.typesTask.intType,
+ subclassOfInterceptor(compiler),
+ compiler.typesTask.dynamicType.nonNullable()]);
+ runTest(TEST_9, (compiler) => [compiler.typesTask.intType,
+ compiler.typesTask.intType]);
+ runTest(TEST_10, (compiler) => [subclassOfInterceptor(compiler),
+ subclassOfInterceptor(compiler)]);
+ runTest(TEST_11, (compiler) => [subclassOfInterceptor(compiler),
+ subclassOfInterceptor(compiler)]);
- runTest(TEST_12, (inferrer) => [inferrer.stringType, inferrer.intType]);
+ runTest(TEST_12, (compiler) => [compiler.typesTask.stringType,
+ compiler.typesTask.intType]);
- runTest(TEST_13, (inferrer) => [inferrer.numType]);
+ runTest(TEST_13, (compiler) => [compiler.typesTask.numType]);
- runTest(TEST_14, (inferrer) => [inferrer.intType, inferrer.stringType]);
+ runTest(TEST_14, (compiler) => [compiler.typesTask.intType,
+ compiler.typesTask.stringType]);
- runTest(TEST_15, (inferrer) => [inferrer.stringType, inferrer.boolType]);
+ runTest(TEST_15, (compiler) => [compiler.typesTask.stringType,
+ compiler.typesTask.boolType]);
- runTest(TEST_16, (inferrer) => [inferrer.intType,
- inferrer.intType,
- inferrer.stringType]);
+ runTest(TEST_16, (compiler) => [compiler.typesTask.intType,
+ compiler.typesTask.intType,
+ compiler.typesTask.stringType]);
- runTest(TEST_17, (inferrer) => [inferrer.intType,
- inferrer.boolType,
- inferrer.doubleType]);
+ runTest(TEST_17, (compiler) => [compiler.typesTask.intType,
+ compiler.typesTask.boolType,
+ compiler.typesTask.doubleType]);
- runTest(TEST_18, (inferrer) => [subclassOfInterceptor(inferrer),
- subclassOfInterceptor(inferrer)]);
+ runTest(TEST_18, (compiler) => [subclassOfInterceptor(compiler),
+ subclassOfInterceptor(compiler)]);
}
void main() {
diff --git a/tests/compiler/dart2js/class_codegen_test.dart b/tests/compiler/dart2js/class_codegen_test.dart
index 24d8c63..b4e72c1 100644
--- a/tests/compiler/dart2js/class_codegen_test.dart
+++ b/tests/compiler/dart2js/class_codegen_test.dart
@@ -81,7 +81,7 @@
fieldTest() {
String generated = compileAll(TEST_FOUR);
- Expect.isTrue(generated.contains(r"""B: {"": "A;y,z,x"}"""));
+ Expect.isTrue(generated.contains(r"""B: {"": "A;y,z,x", static:"""));
}
constructor1() {
diff --git a/tests/compiler/dart2js/concrete_type_inference_test.dart b/tests/compiler/dart2js/concrete_type_inference_test.dart
index 71d8488..fe95c49 100644
--- a/tests/compiler/dart2js/concrete_type_inference_test.dart
+++ b/tests/compiler/dart2js/concrete_type_inference_test.dart
@@ -34,7 +34,8 @@
printElement.computeSignature(compiler).requiredParameters.head;
var type = compiler.typesTask.getGuaranteedTypeOfElement(parameter);
var inferrer = compiler.typesTask.typesInferrer;
- Expect.identical(inferrer.dynamicType, type.simplify(compiler));
+ Expect.identical(compiler.typesTask.dynamicType,
+ type.simplify(compiler));
});
compileAndFind(
@@ -51,28 +52,28 @@
void testBasicTypes() {
checkPrintType('true', (compiler, type) {
var inferrer = compiler.typesTask.typesInferrer;
- Expect.identical(inferrer.boolType, type);
+ Expect.identical(compiler.typesTask.boolType, type);
});
checkPrintType('1.0', (compiler, type) {
var inferrer = compiler.typesTask.typesInferrer;
- Expect.identical(inferrer.doubleType, type);
+ Expect.identical(compiler.typesTask.doubleType, type);
});
checkPrintType('1', (compiler, type) {
var inferrer = compiler.typesTask.typesInferrer;
- Expect.identical(inferrer.intType, type);
+ Expect.identical(compiler.typesTask.intType, type);
});
checkPrintType('[]', (compiler, type) {
var inferrer = compiler.typesTask.typesInferrer;
if (type.isForwarding) type = type.forwardTo;
- Expect.identical(inferrer.growableListType, type);
+ Expect.identical(compiler.typesTask.growableListType, type);
});
checkPrintType('null', (compiler, type) {
var inferrer = compiler.typesTask.typesInferrer;
- Expect.identical(inferrer.nullType, type);
+ Expect.identical(compiler.typesTask.nullType, type);
});
checkPrintType('"foo"', (compiler, type) {
var inferrer = compiler.typesTask.typesInferrer;
- Expect.identical(inferrer.stringType, type);
+ Expect.identical(compiler.typesTask.stringType, type);
});
}
@@ -90,13 +91,13 @@
var typesTask = compiler.typesTask;
var inferrer = typesTask.typesInferrer;
Expect.identical(
- inferrer.intType,
+ typesTask.intType,
typesTask.getGuaranteedTypeOfElement(firstParameter));
Expect.identical(
- inferrer.nullType,
+ typesTask.nullType,
typesTask.getGuaranteedTypeOfElement(secondParameter));
Expect.identical(
- inferrer.nullType,
+ typesTask.nullType,
typesTask.getGuaranteedTypeOfElement(thirdParameter));
});
}
diff --git a/tests/compiler/dart2js/cpa_inference_test.dart b/tests/compiler/dart2js/cpa_inference_test.dart
index 8e81e93..1171906 100644
--- a/tests/compiler/dart2js/cpa_inference_test.dart
+++ b/tests/compiler/dart2js/cpa_inference_test.dart
@@ -1108,36 +1108,6 @@
result.checkNodeHasType('x', []);
}
-// Assuming the mock compiler's interceptor library faithfully reflects the
-// real interceptor library, this test boils down to checking that
-// JSExtendableArray and JSFixedArray don't override JSArray's square bracket
-// operators.
-testListHierarchy() {
- final String source1 = r"""
- import 'dart:interceptors';
-
- main() {
- var l = new JSExtendableArray();
- l[0] = 'foo';
- var x = l[0];
- x;
- }""";
- AnalysisResult result1 = analyze(source1);
- result1.checkNodeHasType('x', [result1.string]);
-
- final String source2 = r"""
- import 'dart:interceptors';
-
- main() {
- var l = new JSFixedArray();
- l[0] = 'foo';
- var x = l[0];
- x;
- }""";
- AnalysisResult result2 = analyze(source1);
- result2.checkNodeHasType('x', [result2.string]);
-}
-
testSendWithWrongArity() {
final String source = r"""
f(x) { }
@@ -1596,7 +1566,6 @@
testLists();
testListWithCapacity();
testEmptyList();
- testListHierarchy();
testJsCall();
testJsCallAugmentsSeenClasses();
testIsCheck();
diff --git a/tests/compiler/dart2js/field_type_simple_inferer_test.dart b/tests/compiler/dart2js/field_type_simple_inferer_test.dart
index db2d968..9f43fd5 100644
--- a/tests/compiler/dart2js/field_type_simple_inferer_test.dart
+++ b/tests/compiler/dart2js/field_type_simple_inferer_test.dart
@@ -20,7 +20,7 @@
compiler.disableInlining = disableInlining;
var cls = findElement(compiler, className);
var member = cls.lookupMember(buildSourceString(memberName));
- return check(compiler.typesTask.typesInferrer, member);
+ return check(compiler, member);
}
const String TEST_1 = r"""
@@ -450,8 +450,9 @@
'A',
name,
disableInlining,
- (inferrer, field) {
- TypeMask type = f(inferrer);
+ (compiler, field) {
+ TypeMask type = f(compiler);
+ var inferrer = compiler.typesTask.typesInferrer;
TypeMask inferredType =
inferrer.getTypeOfElement(field).simplify(inferrer.compiler);
Expect.equals(type, inferredType, name);
@@ -465,17 +466,16 @@
}
void test() {
- subclassOfInterceptor(inferrer) =>
- findTypeMask(inferrer.compiler, 'Interceptor', 'nonNullSubclass');
- dynamicType(inferrer) => inferrer.dynamicType;
+ subclassOfInterceptor(compiler) =>
+ findTypeMask(compiler, 'Interceptor', 'nonNullSubclass');
- runTest(TEST_1, {'f': (inferrer) => inferrer.nullType});
- runTest(TEST_2, {'f1': (inferrer) => inferrer.nullType,
- 'f2': (inferrer) => inferrer.intType});
- runTest(TEST_3, {'f1': (inferrer) => inferrer.intType,
- 'f2': (inferrer) => inferrer.intType.nullable()});
+ runTest(TEST_1, {'f': (compiler) => compiler.typesTask.nullType});
+ runTest(TEST_2, {'f1': (compiler) => compiler.typesTask.nullType,
+ 'f2': (compiler) => compiler.typesTask.intType});
+ runTest(TEST_3, {'f1': (compiler) => compiler.typesTask.intType,
+ 'f2': (compiler) => compiler.typesTask.intType.nullable()});
runTest(TEST_4, {'f1': subclassOfInterceptor,
- 'f2': (inferrer) => inferrer.stringType.nullable()});
+ 'f2': (compiler) => compiler.typesTask.stringType.nullable()});
// TODO(ngeoffray): We should try to infer that the initialization
// code at the declaration site of the fields does not matter.
@@ -486,50 +486,50 @@
runTest(TEST_7, {'f1': subclassOfInterceptor,
'f2': subclassOfInterceptor});
- runTest(TEST_8, {'f': (inferrer) => inferrer.stringType.nullable()});
- runTest(TEST_9, {'f': (inferrer) => inferrer.stringType.nullable()});
- runTest(TEST_10, {'f': (inferrer) => inferrer.intType});
- runTest(TEST_11, {'fs': (inferrer) => inferrer.intType});
+ runTest(TEST_8, {'f': (compiler) => compiler.typesTask.stringType.nullable()});
+ runTest(TEST_9, {'f': (compiler) => compiler.typesTask.stringType.nullable()});
+ runTest(TEST_10, {'f': (compiler) => compiler.typesTask.intType});
+ runTest(TEST_11, {'fs': (compiler) => compiler.typesTask.intType});
// TODO(ngeoffray): We should try to infer that the initialization
// code at the declaration site of the fields does not matter.
runTest(TEST_12, {'fs': subclassOfInterceptor});
- runTest(TEST_13, {'fs': (inferrer) => inferrer.intType});
- runTest(TEST_14, {'f': (inferrer) => inferrer.intType});
- runTest(TEST_15, {'f': (inferrer) {
+ runTest(TEST_13, {'fs': (compiler) => compiler.typesTask.intType});
+ runTest(TEST_14, {'f': (compiler) => compiler.typesTask.intType});
+ runTest(TEST_15, {'f': (compiler) {
ClassElement cls =
- inferrer.compiler.backend.jsIndexableClass;
+ compiler.typesTask.compiler.backend.jsIndexableClass;
return new TypeMask.nonNullSubtype(cls.rawType);
}});
runTest(TEST_16, {'f': subclassOfInterceptor});
- runTest(TEST_17, {'f': (inferrer) => inferrer.intType.nullable()});
- runTest(TEST_18, {'f1': (inferrer) => inferrer.intType,
- 'f2': (inferrer) => inferrer.stringType,
- 'f3': (inferrer) => inferrer.dynamicType});
- runTest(TEST_19, {'f1': (inferrer) => inferrer.intType,
- 'f2': (inferrer) => inferrer.stringType,
- 'f3': (inferrer) => inferrer.dynamicType});
- runTest(TEST_20, {'f': (inferrer) => inferrer.intType.nullable()});
- runTest(TEST_21, {'f': (inferrer) => inferrer.intType.nullable()});
+ runTest(TEST_17, {'f': (compiler) => compiler.typesTask.intType.nullable()});
+ runTest(TEST_18, {'f1': (compiler) => compiler.typesTask.intType,
+ 'f2': (compiler) => compiler.typesTask.stringType,
+ 'f3': (compiler) => compiler.typesTask.dynamicType});
+ runTest(TEST_19, {'f1': (compiler) => compiler.typesTask.intType,
+ 'f2': (compiler) => compiler.typesTask.stringType,
+ 'f3': (compiler) => compiler.typesTask.dynamicType});
+ runTest(TEST_20, {'f': (compiler) => compiler.typesTask.intType.nullable()});
+ runTest(TEST_21, {'f': (compiler) => compiler.typesTask.intType.nullable()});
- runTest(TEST_22, {'f1': (inferrer) => inferrer.intType,
- 'f2': (inferrer) => inferrer.intType,
- 'f3': (inferrer) => inferrer.stringType.nullable()});
+ runTest(TEST_22, {'f1': (compiler) => compiler.typesTask.intType,
+ 'f2': (compiler) => compiler.typesTask.intType,
+ 'f3': (compiler) => compiler.typesTask.stringType.nullable()});
- runTest(TEST_23, {'f1': (inferrer) => inferrer.intType.nullable(),
- 'f2': (inferrer) => inferrer.intType.nullable(),
- 'f3': (inferrer) => inferrer.intType.nullable(),
- 'f4': (inferrer) => inferrer.intType.nullable()});
+ runTest(TEST_23, {'f1': (compiler) => compiler.typesTask.intType.nullable(),
+ 'f2': (compiler) => compiler.typesTask.intType.nullable(),
+ 'f3': (compiler) => compiler.typesTask.intType.nullable(),
+ 'f4': (compiler) => compiler.typesTask.intType.nullable()});
- runTest(TEST_24, {'f1': (inferrer) => inferrer.intType,
- 'f2': (inferrer) => inferrer.intType,
- 'f3': (inferrer) => inferrer.intType,
- 'f4': (inferrer) => inferrer.intType,
- 'f5': (inferrer) => inferrer.numType.nullable(),
- 'f6': (inferrer) => inferrer.stringType.nullable()});
+ runTest(TEST_24, {'f1': (compiler) => compiler.typesTask.intType,
+ 'f2': (compiler) => compiler.typesTask.intType,
+ 'f3': (compiler) => compiler.typesTask.intType,
+ 'f4': (compiler) => compiler.typesTask.intType,
+ 'f5': (compiler) => compiler.typesTask.numType.nullable(),
+ 'f6': (compiler) => compiler.typesTask.stringType.nullable()});
- runTest(TEST_25, {'f1': (inferrer) => inferrer.intType });
+ runTest(TEST_25, {'f1': (compiler) => compiler.typesTask.intType });
}
void main() {
diff --git a/tests/compiler/dart2js/list_tracer_test.dart b/tests/compiler/dart2js/list_tracer_test.dart
index d782239..691c95b 100644
--- a/tests/compiler/dart2js/list_tracer_test.dart
+++ b/tests/compiler/dart2js/list_tracer_test.dart
@@ -190,7 +190,8 @@
Uri uri = new Uri(scheme: 'source');
var compiler = compilerFor(generateTest(allocation), uri);
compiler.runCompiler(uri);
- var typesInferrer = compiler.typesTask.typesInferrer;
+ var typesTask = compiler.typesTask;
+ var typesInferrer = typesTask.typesInferrer;
checkType(String name, type) {
var element = findElement(compiler, name);
@@ -199,29 +200,29 @@
Expect.equals(type, mask.elementType.simplify(compiler), name);
}
- checkType('listInField', typesInferrer.numType);
- checkType('listPassedToMethod', typesInferrer.numType);
- checkType('listReturnedFromMethod', typesInferrer.numType);
- checkType('listUsedWithCascade', typesInferrer.numType);
- checkType('listUsedInClosure', typesInferrer.numType);
- checkType('listPassedToSelector', typesInferrer.numType);
- checkType('listReturnedFromSelector', typesInferrer.numType);
- checkType('listUsedWithAddAndInsert', typesInferrer.numType);
- checkType('listUsedWithConstraint', typesInferrer.numType);
- checkType('listEscapingFromSetter', typesInferrer.numType);
- checkType('listUsedInLocal', typesInferrer.numType);
- checkType('listEscapingInSetterValue', typesInferrer.numType);
- checkType('listEscapingInIndex', typesInferrer.numType);
- checkType('listEscapingInIndexSet', typesInferrer.intType);
- checkType('listEscapingTwiceInIndexSet', typesInferrer.numType);
- checkType('listSetInNonFinalField', typesInferrer.numType);
- checkType('listWithChangedLength', typesInferrer.intType.nullable());
+ checkType('listInField', typesTask.numType);
+ checkType('listPassedToMethod', typesTask.numType);
+ checkType('listReturnedFromMethod', typesTask.numType);
+ checkType('listUsedWithCascade', typesTask.numType);
+ checkType('listUsedInClosure', typesTask.numType);
+ checkType('listPassedToSelector', typesTask.numType);
+ checkType('listReturnedFromSelector', typesTask.numType);
+ checkType('listUsedWithAddAndInsert', typesTask.numType);
+ checkType('listUsedWithConstraint', typesTask.numType);
+ checkType('listEscapingFromSetter', typesTask.numType);
+ checkType('listUsedInLocal', typesTask.numType);
+ checkType('listEscapingInSetterValue', typesTask.numType);
+ checkType('listEscapingInIndex', typesTask.numType);
+ checkType('listEscapingInIndexSet', typesTask.intType);
+ checkType('listEscapingTwiceInIndexSet', typesTask.numType);
+ checkType('listSetInNonFinalField', typesTask.numType);
+ checkType('listWithChangedLength', typesTask.intType.nullable());
- checkType('listPassedToClosure', typesInferrer.dynamicType);
- checkType('listReturnedFromClosure', typesInferrer.dynamicType);
- checkType('listUsedWithNonOkSelector', typesInferrer.dynamicType);
- checkType('listPassedAsOptionalParameter', typesInferrer.dynamicType);
- checkType('listPassedAsNamedParameter', typesInferrer.dynamicType);
+ checkType('listPassedToClosure', typesTask.dynamicType);
+ checkType('listReturnedFromClosure', typesTask.dynamicType);
+ checkType('listUsedWithNonOkSelector', typesTask.dynamicType);
+ checkType('listPassedAsOptionalParameter', typesTask.dynamicType);
+ checkType('listPassedAsNamedParameter', typesTask.dynamicType);
if (!allocation.contains('filled')) {
checkType('listUnset', new TypeMask.nonNullEmpty());
diff --git a/tests/compiler/dart2js/no_constructor_body_test.dart b/tests/compiler/dart2js/no_constructor_body_test.dart
index 666afeb..0a11b01 100644
--- a/tests/compiler/dart2js/no_constructor_body_test.dart
+++ b/tests/compiler/dart2js/no_constructor_body_test.dart
@@ -19,5 +19,5 @@
main() {
String generated = compileAll(TEST);
Expect.isTrue(
- generated.contains('A: {"": "Object;"}'));
+ generated.contains('A: {"": "Object;", static:'));
}
diff --git a/tests/compiler/dart2js/simple_inferrer_and_or_test.dart b/tests/compiler/dart2js/simple_inferrer_and_or_test.dart
index 267f5fe..22ec51a 100644
--- a/tests/compiler/dart2js/simple_inferrer_and_or_test.dart
+++ b/tests/compiler/dart2js/simple_inferrer_and_or_test.dart
@@ -72,7 +72,7 @@
checkReturn('returnDyn1', subclassOfInterceptor);
checkReturn('returnDyn2', subclassOfInterceptor);
checkReturn('returnDyn3', subclassOfInterceptor);
- checkReturn('returnDyn4', typesInferrer.dynamicType.nonNullable());
- checkReturn('returnDyn5', typesInferrer.dynamicType.nonNullable());
- checkReturn('returnDyn6', typesInferrer.dynamicType.nonNullable());
+ checkReturn('returnDyn4', compiler.typesTask.dynamicType.nonNullable());
+ checkReturn('returnDyn5', compiler.typesTask.dynamicType.nonNullable());
+ checkReturn('returnDyn6', compiler.typesTask.dynamicType.nonNullable());
}
diff --git a/tests/compiler/dart2js/simple_inferrer_closure_test.dart b/tests/compiler/dart2js/simple_inferrer_closure_test.dart
index 0f10a24..822fee3 100644
--- a/tests/compiler/dart2js/simple_inferrer_closure_test.dart
+++ b/tests/compiler/dart2js/simple_inferrer_closure_test.dart
@@ -90,15 +90,15 @@
Expect.equals(type, typesInferrer.getReturnTypeOfElement(element));
}
- checkReturn('returnInt1', typesInferrer.intType);
+ checkReturn('returnInt1', compiler.typesTask.intType);
// TODO(ngeoffray): We don't use types of mutated captured
// variables anymore, because they could lead to optimistic results
// needing to be re-analyzed.
- checkReturn('returnInt2', typesInferrer.dynamicType);
- checkReturn('returnInt3', typesInferrer.intType);
- checkReturn('returnInt4', typesInferrer.intType);
+ checkReturn('returnInt2', compiler.typesTask.dynamicType);
+ checkReturn('returnInt3', compiler.typesTask.intType);
+ checkReturn('returnInt4', compiler.typesTask.intType);
- checkReturn('returnDyn1', typesInferrer.dynamicType);
- checkReturn('returnDyn2', typesInferrer.dynamicType);
- checkReturn('returnDyn3', typesInferrer.dynamicType);
+ checkReturn('returnDyn1', compiler.typesTask.dynamicType);
+ checkReturn('returnDyn2', compiler.typesTask.dynamicType);
+ checkReturn('returnDyn3', compiler.typesTask.dynamicType);
}
diff --git a/tests/compiler/dart2js/simple_inferrer_final_field2_test.dart b/tests/compiler/dart2js/simple_inferrer_final_field2_test.dart
index 5904dee..75bf803 100644
--- a/tests/compiler/dart2js/simple_inferrer_final_field2_test.dart
+++ b/tests/compiler/dart2js/simple_inferrer_final_field2_test.dart
@@ -35,6 +35,6 @@
Expect.equals(type, typesInferrer.getTypeOfElement(element));
}
- checkFieldTypeInClass('A', 'intField', typesInferrer.intType);
- checkFieldTypeInClass('A', 'stringField', typesInferrer.stringType);
+ checkFieldTypeInClass('A', 'intField', compiler.typesTask.intType);
+ checkFieldTypeInClass('A', 'stringField', compiler.typesTask.stringType);
}
diff --git a/tests/compiler/dart2js/simple_inferrer_final_field_test.dart b/tests/compiler/dart2js/simple_inferrer_final_field_test.dart
index 8cea159..f4d5d04 100644
--- a/tests/compiler/dart2js/simple_inferrer_final_field_test.dart
+++ b/tests/compiler/dart2js/simple_inferrer_final_field_test.dart
@@ -38,10 +38,10 @@
typesInferrer.getTypeOfElement(element).simplify(compiler));
}
- checkFieldTypeInClass('A', 'intField', typesInferrer.intType);
+ checkFieldTypeInClass('A', 'intField', compiler.typesTask.intType);
checkFieldTypeInClass('A', 'giveUpField1',
findTypeMask(compiler, 'Interceptor', 'nonNullSubclass'));
checkFieldTypeInClass('A', 'giveUpField2',
- typesInferrer.dynamicType.nonNullable());
- checkFieldTypeInClass('A', 'fieldParameter', typesInferrer.intType);
+ compiler.typesTask.dynamicType.nonNullable());
+ checkFieldTypeInClass('A', 'fieldParameter', compiler.typesTask.intType);
}
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 f4589cd..45669dd 100644
--- a/tests/compiler/dart2js/simple_inferrer_no_such_method_test.dart
+++ b/tests/compiler/dart2js/simple_inferrer_no_such_method_test.dart
@@ -107,27 +107,27 @@
name);
}
- checkReturn('test1', typesInferrer.intType);
- checkReturn('test2', typesInferrer.dynamicType.nonNullable());
- checkReturn('test3', typesInferrer.intType);
- checkReturn('test4', typesInferrer.mapType);
- checkReturn('test5', typesInferrer.dynamicType.nonNullable());
- checkReturn('test6', typesInferrer.dynamicType.nonNullable());
+ checkReturn('test1', compiler.typesTask.intType);
+ checkReturn('test2', compiler.typesTask.dynamicType.nonNullable());
+ checkReturn('test3', compiler.typesTask.intType);
+ checkReturn('test4', compiler.typesTask.mapType);
+ checkReturn('test5', compiler.typesTask.dynamicType.nonNullable());
+ checkReturn('test6', compiler.typesTask.dynamicType.nonNullable());
compiler = compilerFor(TEST2, uri);
compiler.runCompiler(uri);
typesInferrer = compiler.typesTask.typesInferrer;
- checkReturn('test1', typesInferrer.dynamicType.nonNullable());
- checkReturn('test2', typesInferrer.mapType);
- checkReturn('test3', typesInferrer.mapType);
- checkReturn('test4', typesInferrer.mapType);
- checkReturn('test5', typesInferrer.mapType);
+ checkReturn('test1', compiler.typesTask.dynamicType.nonNullable());
+ checkReturn('test2', compiler.typesTask.mapType);
+ checkReturn('test3', compiler.typesTask.mapType);
+ checkReturn('test4', compiler.typesTask.mapType);
+ checkReturn('test5', compiler.typesTask.mapType);
- checkReturn('test6', typesInferrer.numType);
- checkReturn('test7', typesInferrer.intType);
- checkReturn('test8', typesInferrer.intType);
- checkReturn('test9', typesInferrer.intType);
- checkReturn('test10', typesInferrer.numType);
- checkReturn('test11', typesInferrer.doubleType);
+ checkReturn('test6', compiler.typesTask.numType);
+ checkReturn('test7', compiler.typesTask.intType);
+ checkReturn('test8', compiler.typesTask.intType);
+ checkReturn('test9', compiler.typesTask.intType);
+ checkReturn('test10', compiler.typesTask.numType);
+ checkReturn('test11', compiler.typesTask.doubleType);
}
diff --git a/tests/compiler/dart2js/simple_inferrer_postfix_prefix_test.dart b/tests/compiler/dart2js/simple_inferrer_postfix_prefix_test.dart
index c5fbce1..e346b11 100644
--- a/tests/compiler/dart2js/simple_inferrer_postfix_prefix_test.dart
+++ b/tests/compiler/dart2js/simple_inferrer_postfix_prefix_test.dart
@@ -64,7 +64,8 @@
Uri uri = new Uri(scheme: 'source');
var compiler = compilerFor(TEST, uri);
compiler.runCompiler(uri);
- var typesInferrer = compiler.typesTask.typesInferrer;
+ var typesTask = compiler.typesTask;
+ var typesInferrer = typesTask.typesInferrer;
checkReturnInClass(String className, String methodName, type) {
var cls = findElement(compiler, className);
@@ -76,20 +77,20 @@
var subclassOfInterceptor =
findTypeMask(compiler, 'Interceptor', 'nonNullSubclass');
- checkReturnInClass('A', 'returnNum1', typesInferrer.numType);
- checkReturnInClass('A', 'returnNum2', typesInferrer.numType);
- checkReturnInClass('A', 'returnNum3', typesInferrer.numType);
- checkReturnInClass('A', 'returnNum4', typesInferrer.numType);
- checkReturnInClass('A', 'returnNum5', typesInferrer.numType);
- checkReturnInClass('A', 'returnNum6', typesInferrer.numType);
+ checkReturnInClass('A', 'returnNum1', typesTask.numType);
+ checkReturnInClass('A', 'returnNum2', typesTask.numType);
+ checkReturnInClass('A', 'returnNum3', typesTask.numType);
+ checkReturnInClass('A', 'returnNum4', typesTask.numType);
+ checkReturnInClass('A', 'returnNum5', typesTask.numType);
+ checkReturnInClass('A', 'returnNum6', typesTask.numType);
checkReturnInClass('A', 'returnDynamic1', subclassOfInterceptor);
checkReturnInClass('A', 'returnDynamic2', subclassOfInterceptor);
- checkReturnInClass('A', 'returnDynamic3', typesInferrer.dynamicType);
+ checkReturnInClass('A', 'returnDynamic3', typesTask.dynamicType);
- checkReturnInClass('B', 'returnString1', typesInferrer.stringType);
- checkReturnInClass('B', 'returnString2', typesInferrer.stringType);
- checkReturnInClass('B', 'returnDynamic1', typesInferrer.dynamicType);
- checkReturnInClass('B', 'returnDynamic2', typesInferrer.dynamicType);
- checkReturnInClass('B', 'returnDynamic3', typesInferrer.dynamicType);
- checkReturnInClass('B', 'returnDynamic4', typesInferrer.dynamicType);
+ checkReturnInClass('B', 'returnString1', typesTask.stringType);
+ checkReturnInClass('B', 'returnString2', typesTask.stringType);
+ checkReturnInClass('B', 'returnDynamic1', typesTask.dynamicType);
+ checkReturnInClass('B', 'returnDynamic2', typesTask.dynamicType);
+ checkReturnInClass('B', 'returnDynamic3', typesTask.dynamicType);
+ checkReturnInClass('B', 'returnDynamic4', typesTask.dynamicType);
}
diff --git a/tests/compiler/dart2js/simple_inferrer_test.dart b/tests/compiler/dart2js/simple_inferrer_test.dart
index 186504d..fc6fe0a 100644
--- a/tests/compiler/dart2js/simple_inferrer_test.dart
+++ b/tests/compiler/dart2js/simple_inferrer_test.dart
@@ -485,7 +485,8 @@
Uri uri = new Uri(scheme: 'source');
var compiler = compilerFor(TEST, uri);
compiler.runCompiler(uri);
- var typesInferrer = compiler.typesTask.typesInferrer;
+ var typesTask = compiler.typesTask;
+ var typesInferrer = typesTask.typesInferrer;
checkReturn(String name, type) {
var element = findElement(compiler, name);
@@ -497,63 +498,63 @@
var interceptorType =
findTypeMask(compiler, 'Interceptor', 'nonNullSubclass');
- checkReturn('returnNum1', typesInferrer.numType);
- checkReturn('returnNum2', typesInferrer.numType);
- checkReturn('returnInt1', typesInferrer.intType);
- checkReturn('returnInt2', typesInferrer.intType);
- checkReturn('returnDouble', typesInferrer.doubleType);
+ checkReturn('returnNum1', typesTask.numType);
+ checkReturn('returnNum2', typesTask.numType);
+ checkReturn('returnInt1', typesTask.intType);
+ checkReturn('returnInt2', typesTask.intType);
+ checkReturn('returnDouble', typesTask.doubleType);
checkReturn('returnGiveUp', interceptorType);
- checkReturn('returnInt5', typesInferrer.intType);
- checkReturn('returnInt6', typesInferrer.intType);
- checkReturn('returnIntOrNull', typesInferrer.intType.nullable());
- checkReturn('returnInt3', typesInferrer.intType);
- checkReturn('returnDynamic', typesInferrer.dynamicType);
- checkReturn('returnInt4', typesInferrer.intType);
- checkReturn('returnInt7', typesInferrer.intType);
- checkReturn('returnInt8', typesInferrer.intType);
- checkReturn('returnDynamic1', typesInferrer.dynamicType);
- checkReturn('returnDynamic2', typesInferrer.dynamicType);
+ checkReturn('returnInt5', typesTask.intType);
+ checkReturn('returnInt6', typesTask.intType);
+ checkReturn('returnIntOrNull', typesTask.intType.nullable());
+ checkReturn('returnInt3', typesTask.intType);
+ checkReturn('returnDynamic', typesTask.dynamicType);
+ checkReturn('returnInt4', typesTask.intType);
+ checkReturn('returnInt7', typesTask.intType);
+ checkReturn('returnInt8', typesTask.intType);
+ checkReturn('returnDynamic1', typesTask.dynamicType);
+ checkReturn('returnDynamic2', typesTask.dynamicType);
TypeMask intType = new TypeMask.nonNullSubtype(compiler.intClass.rawType);
checkReturn('testIsCheck1', intType);
checkReturn('testIsCheck2', intType);
checkReturn('testIsCheck3', intType.nullable());
checkReturn('testIsCheck4', intType);
checkReturn('testIsCheck5', intType);
- checkReturn('testIsCheck6', typesInferrer.dynamicType);
+ checkReturn('testIsCheck6', typesTask.dynamicType);
checkReturn('testIsCheck7', intType);
- checkReturn('testIsCheck8', typesInferrer.dynamicType);
+ checkReturn('testIsCheck8', typesTask.dynamicType);
checkReturn('testIsCheck9', intType);
- checkReturn('testIsCheck10', typesInferrer.dynamicType);
+ checkReturn('testIsCheck10', typesTask.dynamicType);
checkReturn('testIsCheck11', intType);
- checkReturn('testIsCheck12', typesInferrer.dynamicType);
+ checkReturn('testIsCheck12', typesTask.dynamicType);
checkReturn('testIsCheck13', intType);
- checkReturn('testIsCheck14', typesInferrer.dynamicType);
+ checkReturn('testIsCheck14', typesTask.dynamicType);
checkReturn('testIsCheck15', intType);
- checkReturn('testIsCheck16', typesInferrer.dynamicType);
+ checkReturn('testIsCheck16', typesTask.dynamicType);
checkReturn('testIsCheck17', intType);
- checkReturn('testIsCheck18', typesInferrer.dynamicType);
- checkReturn('testIsCheck19', typesInferrer.dynamicType);
- checkReturn('testIsCheck20', typesInferrer.dynamicType.nonNullable());
+ checkReturn('testIsCheck18', typesTask.dynamicType);
+ checkReturn('testIsCheck19', typesTask.dynamicType);
+ checkReturn('testIsCheck20', typesTask.dynamicType.nonNullable());
checkReturn('returnAsString',
new TypeMask.subtype(compiler.stringClass.computeType(compiler)));
- checkReturn('returnIntAsNum', typesInferrer.intType);
- checkReturn('returnAsTypedef', typesInferrer.functionType.nullable());
- checkReturn('returnTopLevelGetter', typesInferrer.intType);
- checkReturn('testDeadCode', typesInferrer.intType);
- checkReturn('testLabeledIf', typesInferrer.intType.nullable());
- checkReturn('testSwitch1', typesInferrer.intType
- .union(typesInferrer.doubleType, compiler).nullable().simplify(compiler));
- checkReturn('testSwitch2', typesInferrer.intType);
+ checkReturn('returnIntAsNum', typesTask.intType);
+ checkReturn('returnAsTypedef', typesTask.functionType.nullable());
+ checkReturn('returnTopLevelGetter', typesTask.intType);
+ checkReturn('testDeadCode', typesTask.intType);
+ checkReturn('testLabeledIf', typesTask.intType.nullable());
+ checkReturn('testSwitch1', typesTask.intType
+ .union(typesTask.doubleType, compiler).nullable().simplify(compiler));
+ checkReturn('testSwitch2', typesTask.intType);
checkReturn('testSwitch3', interceptorType.nullable());
- checkReturn('testSwitch4', typesInferrer.intType);
+ checkReturn('testSwitch4', typesTask.intType);
checkReturn('testContinue1', interceptorType.nullable());
checkReturn('testBreak1', interceptorType.nullable());
checkReturn('testContinue2', interceptorType.nullable());
- checkReturn('testBreak2', typesInferrer.intType.nullable());
- checkReturn('testReturnElementOfConstList1', typesInferrer.intType);
- checkReturn('testReturnElementOfConstList2', typesInferrer.intType);
- checkReturn('testReturnItselfOrInt', typesInferrer.intType);
- checkReturn('testReturnInvokeDynamicGetter', typesInferrer.dynamicType);
+ checkReturn('testBreak2', typesTask.intType.nullable());
+ checkReturn('testReturnElementOfConstList1', typesTask.intType);
+ checkReturn('testReturnElementOfConstList2', typesTask.intType);
+ checkReturn('testReturnItselfOrInt', typesTask.intType);
+ checkReturn('testReturnInvokeDynamicGetter', typesTask.dynamicType);
checkReturnInClass(String className, String methodName, type) {
var cls = findElement(compiler, className);
@@ -562,23 +563,23 @@
typesInferrer.getReturnTypeOfElement(element).simplify(compiler));
}
- checkReturnInClass('A', 'returnInt1', typesInferrer.intType);
- checkReturnInClass('A', 'returnInt2', typesInferrer.intType);
- checkReturnInClass('A', 'returnInt3', typesInferrer.intType);
- checkReturnInClass('A', 'returnInt4', typesInferrer.intType);
- checkReturnInClass('A', 'returnInt5', typesInferrer.intType);
- checkReturnInClass('A', 'returnInt6', typesInferrer.intType);
+ checkReturnInClass('A', 'returnInt1', typesTask.intType);
+ checkReturnInClass('A', 'returnInt2', typesTask.intType);
+ checkReturnInClass('A', 'returnInt3', typesTask.intType);
+ checkReturnInClass('A', 'returnInt4', typesTask.intType);
+ checkReturnInClass('A', 'returnInt5', typesTask.intType);
+ checkReturnInClass('A', 'returnInt6', typesTask.intType);
checkReturnInClass('A', '==', interceptorType);
- checkReturnInClass('B', 'returnInt1', typesInferrer.intType);
- checkReturnInClass('B', 'returnInt2', typesInferrer.intType);
- checkReturnInClass('B', 'returnInt3', typesInferrer.intType);
- checkReturnInClass('B', 'returnInt4', typesInferrer.intType);
- checkReturnInClass('B', 'returnInt5', typesInferrer.intType);
- checkReturnInClass('B', 'returnInt6', typesInferrer.intType);
- checkReturnInClass('B', 'returnInt7', typesInferrer.intType);
- checkReturnInClass('B', 'returnInt8', typesInferrer.intType);
- checkReturnInClass('B', 'returnInt9', typesInferrer.intType);
+ checkReturnInClass('B', 'returnInt1', typesTask.intType);
+ checkReturnInClass('B', 'returnInt2', typesTask.intType);
+ checkReturnInClass('B', 'returnInt3', typesTask.intType);
+ checkReturnInClass('B', 'returnInt4', typesTask.intType);
+ checkReturnInClass('B', 'returnInt5', typesTask.intType);
+ checkReturnInClass('B', 'returnInt6', typesTask.intType);
+ checkReturnInClass('B', 'returnInt7', typesTask.intType);
+ checkReturnInClass('B', 'returnInt8', typesTask.intType);
+ checkReturnInClass('B', 'returnInt9', typesTask.intType);
checkFactoryConstructor(String className, String factoryName) {
var cls = findElement(compiler, className);
diff --git a/tests/compiler/dart2js/simple_inferrer_try_catch_test.dart b/tests/compiler/dart2js/simple_inferrer_try_catch_test.dart
index 18eddc7..f4ecaef 100644
--- a/tests/compiler/dart2js/simple_inferrer_try_catch_test.dart
+++ b/tests/compiler/dart2js/simple_inferrer_try_catch_test.dart
@@ -157,7 +157,8 @@
Uri uri = new Uri(scheme: 'source');
var compiler = compilerFor(TEST, uri);
compiler.runCompiler(uri);
- var typesInferrer = compiler.typesTask.typesInferrer;
+ var typesTask = compiler.typesTask;
+ var typesInferrer = typesTask.typesInferrer;
checkReturn(String name, type) {
var element = findElement(compiler, name);
@@ -165,11 +166,11 @@
typesInferrer.getReturnTypeOfElement(element).simplify(compiler));
}
- checkReturn('returnInt1', typesInferrer.intType);
- checkReturn('returnInt2', typesInferrer.intType);
- checkReturn('returnInt3', typesInferrer.intType);
- checkReturn('returnInt4', typesInferrer.intType);
- checkReturn('returnInt5', typesInferrer.intType);
+ checkReturn('returnInt1', typesTask.intType);
+ checkReturn('returnInt2', typesTask.intType);
+ checkReturn('returnInt3', typesTask.intType);
+ checkReturn('returnInt4', typesTask.intType);
+ checkReturn('returnInt5', typesTask.intType);
checkReturn('returnInt6',
new TypeMask.nonNullSubtype(compiler.intClass.rawType));
@@ -181,5 +182,5 @@
checkReturn('returnDyn3', subclassOfInterceptor);
checkReturn('returnDyn4', subclassOfInterceptor);
checkReturn('returnDyn5', subclassOfInterceptor);
- checkReturn('returnDyn6', typesInferrer.dynamicType);
+ checkReturn('returnDyn6', typesTask.dynamicType);
}
diff --git a/tests/compiler/dart2js/simple_inferrer_unregister_call_test.dart b/tests/compiler/dart2js/simple_inferrer_unregister_call_test.dart
index 020f4c6..81bbe0f 100644
--- a/tests/compiler/dart2js/simple_inferrer_unregister_call_test.dart
+++ b/tests/compiler/dart2js/simple_inferrer_unregister_call_test.dart
@@ -41,5 +41,5 @@
Expect.equals(type, typesInferrer.getReturnTypeOfElement(element));
}
- checkReturnInClass('A', '+', typesInferrer.intType);
+ checkReturnInClass('A', '+', compiler.typesTask.intType);
}
diff --git a/tests/compiler/dart2js_extra/minified_mirrors_test.dart b/tests/compiler/dart2js_extra/minified_mirrors_test.dart
index 71533b4..e79b743 100644
--- a/tests/compiler/dart2js_extra/minified_mirrors_test.dart
+++ b/tests/compiler/dart2js_extra/minified_mirrors_test.dart
@@ -5,8 +5,10 @@
// This test should be removed when dart2js can pass all mirror tests.
// TODO(ahe): Remove this test.
-import '../../lib/mirrors/mirrors_test.dart';
+import '../../lib/mirrors/mirrors_test.dart' as test;
main() {
- mainWithArgument(isDart2js: true, isMinified: true);
+ test.isDart2js = true;
+ test.isMinified = true;
+ test.main();
}
diff --git a/tests/compiler/dart2js_extra/mirrors_test.dart b/tests/compiler/dart2js_extra/mirrors_test.dart
index d9df6c5..cc56f5e 100644
--- a/tests/compiler/dart2js_extra/mirrors_test.dart
+++ b/tests/compiler/dart2js_extra/mirrors_test.dart
@@ -5,8 +5,10 @@
// This test should be removed when dart2js can pass all mirror tests.
// TODO(ahe): Remove this test.
-import '../../lib/mirrors/mirrors_test.dart';
+
+import '../../lib/mirrors/mirrors_test.dart' as test;
main() {
- mainWithArgument(isDart2js: true);
+ test.isDart2js = true;
+ test.main();
}
diff --git a/tests/compiler/dart2js_foreign/dart2js_foreign.status b/tests/compiler/dart2js_foreign/dart2js_foreign.status
index d5919cc..953a89f 100644
--- a/tests/compiler/dart2js_foreign/dart2js_foreign.status
+++ b/tests/compiler/dart2js_foreign/dart2js_foreign.status
@@ -58,8 +58,6 @@
native_checked_fields_test: Fail # TODO(ahe): Convert to metadata syntax.
native_class_inheritance4_test: Fail # TODO(ahe): Convert to metadata syntax.
native_class_with_dart_methods_test: Fail # TODO(ahe): Convert to metadata syntax.
-native_missing_method1_test: Fail # TODO(ahe): Convert to metadata syntax.
-native_missing_method2_test: Fail # TODO(ahe): Convert to metadata syntax.
native_to_string_test: Fail # TODO(ahe): Convert to metadata syntax.
[ $compiler == dartc || $browser ]
diff --git a/tests/compiler/dart2js_native/uninstantiated_type_parameter_test.dart b/tests/compiler/dart2js_native/uninstantiated_type_parameter_test.dart
new file mode 100644
index 0000000..61f3b604
--- /dev/null
+++ b/tests/compiler/dart2js_native/uninstantiated_type_parameter_test.dart
@@ -0,0 +1,24 @@
+// 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.
+
+import "package:expect/expect.dart";
+
+// Test for uninstantiated native classes as type parameters.
+
+class UA {
+}
+
+class UB native "B" {
+}
+
+class C<T> {
+}
+
+main() {
+ var a = new C<UA>();
+ var b = new C<UB>();
+
+ Expect.isTrue(a is! C<int>);
+ Expect.isTrue(a is! C<C>);
+}
diff --git a/tests/corelib/corelib.status b/tests/corelib/corelib.status
index fe615af..d71a582 100644
--- a/tests/corelib/corelib.status
+++ b/tests/corelib/corelib.status
@@ -118,6 +118,7 @@
[ $arch == simmips && $checked ]
hash_map2_test: Pass, Crash # Too far PC relative branch (?)
+list_test: Pass, Crash # Invalid relative branch offset. Issue 11851.
collection_length_test: Pass, Timeout
[ $arch == simmips && $mode == debug ]
diff --git a/tests/html/html.status b/tests/html/html.status
index 71d10c1..5a76fb9 100644
--- a/tests/html/html.status
+++ b/tests/html/html.status
@@ -28,6 +28,7 @@
indexeddb_3_test: Pass, Timeout, Slow # Issue: http://dartbug.com/9437
indexeddb_4_test: Pass, Timeout, Slow # Issue: http://dartbug.com/9437
async_test: Pass, Fail # timers test fails on ie10.
+js_test: Fail # http://dartbug.com/11855
[ $compiler == dart2js && ( $runtime == ie9 || $runtime == ie10 ) ]
worker_api_test: Fail # IE does not support URL.createObjectURL in web workers.
@@ -44,6 +45,9 @@
*layout_test: Skip
[ $runtime == chrome ]
+canvasrenderingcontext2d_test/drawImage_video_element: Pass,Fail # Issue 11836
+canvasrenderingcontext2d_test/drawImage_video_element_dataUrl: Pass,Fail # Issue 11836
+
touchevent_test/supported: Fail
[ $runtime == chrome || $runtime == chromeOnAndroid || $runtime == drt || $runtime == safari ]
@@ -365,10 +369,12 @@
isolates_test: Skip # Timeout because leg does not support web workers.
[ $compiler == dart2js && $csp && ($runtime == drt || $runtime == safari || $runtime == ff || $runtime == chrome || $runtime == chromeOnAndroid) ]
+# Note: these tests are all injecting scripts by design. This is not allowed under CSP.
event_customevent_test: Fail # Test cannot run under CSP restrictions.
js_interop_1_test: Skip # Test cannot run under CSP restrictions (times out).
js_interop_2_test: Fail, OK # Test cannot run under CSP restrictions.
js_interop_3_test: Skip # Test cannot run under CSP restrictions (times out).
+js_test: Skip # Test cannot run under CSP restrictions (times out).
postmessage_structured_test: Skip # Test cannot run under CSP restrictions (times out).
safe_dom_test: Skip # Test cannot run under CSP restrictions (times out).
shadow_dom_layout_test: Fail, OK # Test cannot run under CSP restrictions.
diff --git a/tests/html/js_test.dart b/tests/html/js_test.dart
new file mode 100644
index 0000000..ff6753d
--- /dev/null
+++ b/tests/html/js_test.dart
@@ -0,0 +1,469 @@
+// 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 jsTest;
+
+import 'dart:async';
+import 'dart:html';
+import 'dart:js';
+
+import '../../pkg/unittest/lib/unittest.dart';
+import '../../pkg/unittest/lib/html_config.dart';
+
+_injectJs() {
+ final script = new ScriptElement();
+ script.type = 'text/javascript';
+ script.innerHtml = r"""
+var x = 42;
+
+var _x = 123;
+
+var myArray = ["value1"];
+
+var foreignDoc = (function(){
+ var doc = document.implementation.createDocument("", "root", null);
+ var element = doc.createElement('element');
+ element.setAttribute('id', 'abc');
+ doc.documentElement.appendChild(element);
+ return doc;
+})();
+
+function razzle() {
+ return x;
+}
+
+function getTypeOf(o) {
+ return typeof(o);
+}
+
+function varArgs() {
+ var args = arguments;
+ var sum = 0;
+ for (var i = 0; i < args.length; ++i) {
+ sum += args[i];
+ }
+ return sum;
+}
+
+function Foo(a) {
+ this.a = a;
+}
+
+Foo.b = 38;
+
+Foo.prototype.bar = function() {
+ return this.a;
+}
+Foo.prototype.toString = function() {
+ return "I'm a Foo a=" + this.a;
+}
+
+var container = new Object();
+container.Foo = Foo;
+
+function isArray(a) {
+ return a instanceof Array;
+}
+
+function checkMap(m, key, value) {
+ if (m.hasOwnProperty(key))
+ return m[key] == value;
+ else
+ return false;
+}
+
+function invokeCallback() {
+ return callback();
+}
+
+function invokeCallbackWith11params() {
+ return callbackWith11params(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11);
+}
+
+function returnElement(element) {
+ return element;
+}
+
+function getElementAttribute(element, attr) {
+ return element.getAttribute(attr);
+}
+
+function addClassAttributes(list) {
+ var result = "";
+ for (var i=0; i < list.length; i++) {
+ result += list[i].getAttribute("class");
+ }
+ return result;
+}
+
+function getNewDivElement() {
+ return document.createElement("div");
+}
+
+function testJsMap(callback) {
+ var result = callback();
+ return result['value'];
+}
+
+function Bar() {
+ return "ret_value";
+}
+Bar.foo = "property_value";
+
+function Baz(p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11) {
+ this.f1 = p1;
+ this.f2 = p2;
+ this.f3 = p3;
+ this.f4 = p4;
+ this.f5 = p5;
+ this.f6 = p6;
+ this.f7 = p7;
+ this.f8 = p8;
+ this.f9 = p9;
+ this.f10 = p10;
+ this.f11 = p11;
+}
+""";
+ document.body.append(script);
+}
+
+class Foo implements Serializable<JsObject> {
+ final JsObject _proxy;
+
+ Foo(num a) : this._proxy = new JsObject(context['Foo'], [a]);
+
+ JsObject toJs() => _proxy;
+
+ num get a => _proxy['a'];
+ num bar() => _proxy.callMethod('bar');
+}
+
+class Color implements Serializable<String> {
+ static final RED = new Color._("red");
+ static final BLUE = new Color._("blue");
+ String _value;
+ Color._(this._value);
+ String toJs() => this._value;
+}
+
+main() {
+ _injectJs();
+ useHtmlConfiguration();
+
+ test('read global field', () {
+ expect(context['x'], equals(42));
+ expect(context['y'], isNull);
+ });
+
+ test('read global field with underscore', () {
+ expect(context['_x'], equals(123));
+ expect(context['y'], isNull);
+ });
+
+ test('hashCode and operator==(other)', () {
+ final o1 = context['Object'];
+ final o2 = context['Object'];
+ expect(o1 == o2, isTrue);
+ expect(o1.hashCode == o2.hashCode, isTrue);
+ final d = context['document'];
+ expect(o1 == d, isFalse);
+ });
+
+ test('js instantiation : new Foo()', () {
+ final Foo2 = context['container']['Foo'];
+ final foo = new JsObject(Foo2, [42]);
+ expect(foo['a'], 42);
+ expect(Foo2['b'], 38);
+ });
+
+ test('js instantiation : new Array()', () {
+ final a = new JsObject(context['Array']);
+ expect(a, isNotNull);
+ expect(a['length'], equals(0));
+
+ a.callMethod('push', ["value 1"]);
+ expect(a['length'], equals(1));
+ expect(a[0], equals("value 1"));
+
+ a.callMethod('pop');
+ expect(a['length'], equals(0));
+ });
+
+ test('js instantiation : new Date()', () {
+ final a = new JsObject(context['Date']);
+ expect(a.callMethod('getTime'), isNotNull);
+ });
+
+ test('js instantiation : new Date(12345678)', () {
+ final a = new JsObject(context['Date'], [12345678]);
+ expect(a.callMethod('getTime'), equals(12345678));
+ });
+
+ test('js instantiation : new Date("December 17, 1995 03:24:00 GMT")',
+ () {
+ final a = new JsObject(context['Date'],
+ ["December 17, 1995 03:24:00 GMT"]);
+ expect(a.callMethod('getTime'), equals(819170640000));
+ });
+
+ test('js instantiation : new Date(1995,11,17)', () {
+ // Note: JS Date counts months from 0 while Dart counts from 1.
+ final a = new JsObject(context['Date'], [1995, 11, 17]);
+ final b = new DateTime(1995, 12, 17);
+ expect(a.callMethod('getTime'), equals(b.millisecondsSinceEpoch));
+ });
+
+ test('js instantiation : new Date(1995,11,17,3,24,0)', () {
+ // Note: JS Date counts months from 0 while Dart counts from 1.
+ final a = new JsObject(context['Date'],
+ [1995, 11, 17, 3, 24, 0]);
+ final b = new DateTime(1995, 12, 17, 3, 24, 0);
+ expect(a.callMethod('getTime'), equals(b.millisecondsSinceEpoch));
+ });
+
+ test('js instantiation : new Object()', () {
+ final a = new JsObject(context['Object']);
+ expect(a, isNotNull);
+
+ a['attr'] = "value";
+ expect(a['attr'], equals("value"));
+ });
+
+ test(r'js instantiation : new RegExp("^\w+$")', () {
+ final a = new JsObject(context['RegExp'], [r'^\w+$']);
+ expect(a, isNotNull);
+ expect(a.callMethod('test', ['true']), isTrue);
+ expect(a.callMethod('test', [' false']), isFalse);
+ });
+
+ test('js instantiation via map notation : new Array()', () {
+ final a = new JsObject(context['Array']);
+ expect(a, isNotNull);
+ expect(a['length'], equals(0));
+
+ a['push'].apply(a, ["value 1"]);
+ expect(a['length'], equals(1));
+ expect(a[0], equals("value 1"));
+
+ a['pop'].apply(a);
+ expect(a['length'], equals(0));
+ });
+
+ test('js instantiation via map notation : new Date()', () {
+ final a = new JsObject(context['Date']);
+ expect(a['getTime'].apply(a), isNotNull);
+ });
+
+ test('js instantiation : typed array', () {
+ if (Platform.supportsTypedData) {
+ final codeUnits = "test".codeUnits;
+ final buf = new JsObject(context['ArrayBuffer'], [codeUnits.length]);
+ final bufView = new JsObject(context['Uint8Array'], [buf]);
+ for (var i = 0; i < codeUnits.length; i++) {
+ bufView[i] = codeUnits[i];
+ }
+ }
+ });
+
+ test('js instantiation : >10 parameters', () {
+ final o = new JsObject(context['Baz'], [1,2,3,4,5,6,7,8,9,10,11]);
+ for (var i = 1; i <= 11; i++) {
+ o["f$i"] = i;
+ }
+ });
+
+ test('write global field', () {
+ context['y'] = 42;
+ expect(context['y'], equals(42));
+ });
+
+ test('get JS JsFunction', () {
+ var razzle = context['razzle'];
+ expect(razzle.apply(context), equals(42));
+ });
+
+ test('call JS function', () {
+ expect(context.callMethod('razzle'), equals(42));
+ expect(() => context.callMethod('dazzle'), throwsA(isNoSuchMethodError));
+ });
+
+ test('call JS function via map notation', () {
+ expect(context['razzle'].apply(context), equals(42));
+ expect(() => context['dazzle'].apply(context),
+ throwsA(isNoSuchMethodError));
+ });
+
+ test('call JS function with varargs', () {
+ expect(context.callMethod('varArgs', [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]),
+ equals(55));
+ });
+
+ test('allocate JS object', () {
+ var foo = new JsObject(context['Foo'], [42]);
+ expect(foo['a'], equals(42));
+ expect(foo.callMethod('bar'), equals(42));
+ expect(() => foo.callMethod('baz'), throwsA(isNoSuchMethodError));
+ });
+
+ test('call toString()', () {
+ var foo = new JsObject(context['Foo'], [42]);
+ expect(foo.toString(), equals("I'm a Foo a=42"));
+ var container = context['container'];
+ expect(container.toString(), equals("[object Object]"));
+ });
+
+ test('allocate simple JS array', () {
+ final list = [1, 2, 3, 4, 5, 6, 7, 8];
+ var array = jsify(list);
+ expect(context.callMethod('isArray', [array]), isTrue);
+ expect(array['length'], equals(list.length));
+ for (var i = 0; i < list.length ; i++) {
+ expect(array[i], equals(list[i]));
+ }
+ });
+
+ test('allocate JS array with iterable', () {
+ final set = new Set.from([1, 2, 3, 4, 5, 6, 7, 8]);
+ var array = jsify(set);
+ expect(context.callMethod('isArray', [array]), isTrue);
+ expect(array['length'], equals(set.length));
+ for (var i = 0; i < array['length'] ; i++) {
+ expect(set.contains(array[i]), isTrue);
+ }
+ });
+
+ test('allocate simple JS map', () {
+ var map = {'a': 1, 'b': 2, 'c': 3};
+ var jsMap = jsify(map);
+ expect(!context.callMethod('isArray', [jsMap]), isTrue);
+ for (final key in map.keys) {
+ expect(context.callMethod('checkMap', [jsMap, key, map[key]]), isTrue);
+ }
+ });
+
+ test('allocate complex JS object', () {
+ final object =
+ {
+ 'a': [1, [2, 3]],
+ 'b': {
+ 'c': 3,
+ 'd': new JsObject(context['Foo'], [42])
+ },
+ 'e': null
+ };
+ var jsObject = jsify(object);
+ expect(jsObject['a'][0], equals(object['a'][0]));
+ expect(jsObject['a'][1][0], equals(object['a'][1][0]));
+ expect(jsObject['a'][1][1], equals(object['a'][1][1]));
+ expect(jsObject['b']['c'], equals(object['b']['c']));
+ expect(jsObject['b']['d'], equals(object['b']['d']));
+ expect(jsObject['b']['d'].callMethod('bar'), equals(42));
+ expect(jsObject['e'], isNull);
+ });
+
+ test('invoke Dart callback from JS', () {
+ expect(() => context.callMethod('invokeCallback'), throws);
+
+ context['callback'] = new Callback(() => 42);
+ expect(context.callMethod('invokeCallback'), equals(42));
+
+ context.deleteProperty('callback');
+ expect(() => context.callMethod('invokeCallback'), throws);
+
+ context['callback'] = () => 42;
+ expect(context.callMethod('invokeCallback'), equals(42));
+
+ context.deleteProperty('callback');
+ });
+
+ test('callback as parameter', () {
+ expect(context.callMethod('getTypeOf', [context['razzle']]),
+ equals("function"));
+ });
+
+ test('invoke Dart callback from JS with this', () {
+ final constructor = new Callback.withThis(($this, arg1) {
+ $this['a'] = 42;
+ $this['b'] = jsify(["a", arg1]);
+ });
+ var o = new JsObject(constructor, ["b"]);
+ expect(o['a'], equals(42));
+ expect(o['b'][0], equals("a"));
+ expect(o['b'][1], equals("b"));
+ });
+
+ test('invoke Dart callback from JS with 11 parameters', () {
+ context['callbackWith11params'] = new Callback((p1, p2, p3, p4, p5, p6, p7,
+ p8, p9, p10, p11) => '$p1$p2$p3$p4$p5$p6$p7$p8$p9$p10$p11');
+ expect(context.callMethod('invokeCallbackWith11params'),
+ equals('1234567891011'));
+ });
+
+ test('return a JS proxy to JavaScript', () {
+ var result = context.callMethod('testJsMap', [() => jsify({'value': 42})]);
+ expect(result, 42);
+ });
+
+ test('test proxy equality', () {
+ var foo1 = new JsObject(context['Foo'], [1]);
+ var foo2 = new JsObject(context['Foo'], [2]);
+ context['foo'] = foo1;
+ context['foo'] = foo2;
+ expect(foo1, isNot(equals(context['foo'])));
+ expect(foo2, equals(context['foo']));
+ });
+
+ test('test instanceof', () {
+ var foo = new JsObject(context['Foo'], [1]);
+ expect(foo.instanceof(context['Foo']), isTrue);
+ expect(foo.instanceof(context['Object']), isTrue);
+ expect(foo.instanceof(context['String']), isFalse);
+ });
+
+ test('test deleteProperty', () {
+ var object = jsify({});
+ object['a'] = 1;
+ expect(context['Object'].callMethod('keys', [object])['length'], 1);
+ expect(context['Object'].callMethod('keys', [object])[0], "a");
+ object.deleteProperty("a");
+ expect(context['Object'].callMethod('keys', [object])['length'], 0);
+ });
+
+ test('test hasProperty', () {
+ var object = jsify({});
+ object['a'] = 1;
+ expect(object.hasProperty('a'), isTrue);
+ expect(object.hasProperty('b'), isFalse);
+ });
+
+ test('test index get and set', () {
+ final myArray = context['myArray'];
+ expect(myArray['length'], equals(1));
+ expect(myArray[0], equals("value1"));
+ myArray[0] = "value2";
+ expect(myArray['length'], equals(1));
+ expect(myArray[0], equals("value2"));
+
+ final foo = new JsObject(context['Foo'], [1]);
+ foo["getAge"] = () => 10;
+ expect(foo.callMethod('getAge'), equals(10));
+ });
+
+ test('access a property of a function', () {
+ expect(context.callMethod('Bar'), "ret_value");
+ expect(context['Bar']['foo'], "property_value");
+ });
+
+ test('retrieve same dart Object', () {
+ final date = new DateTime.now();
+ context['dartDate'] = date;
+ expect(context['dartDate'], equals(date));
+ });
+
+ test('usage of Serializable', () {
+ final red = Color.RED;
+ context['color'] = red;
+ expect(context['color'], equals(red._value));
+ });
+}
diff --git a/tests/html/xhr_test.dart b/tests/html/xhr_test.dart
index 8ddae00..7c2f863 100644
--- a/tests/html/xhr_test.dart
+++ b/tests/html/xhr_test.dart
@@ -18,7 +18,11 @@
main() {
useHtmlIndividualConfiguration();
- var url = "/root_dart/tests/html/xhr_cross_origin_data.txt";
+ // Cache blocker is a workaround for:
+ // https://code.google.com/p/dart/issues/detail?id=11834
+ var cacheBlocker = new DateTime.now().millisecondsSinceEpoch;
+ var url = '/root_dart/tests/html/xhr_cross_origin_data.txt?'
+ 'cacheBlock=$cacheBlocker';
void validate200Response(xhr) {
expect(xhr.status, equals(200));
diff --git a/tests/language/issue11724_test.dart b/tests/language/issue11724_test.dart
new file mode 100644
index 0000000..146a6fe
--- /dev/null
+++ b/tests/language/issue11724_test.dart
@@ -0,0 +1,9 @@
+// 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 main() {
+ Expect.throws(() => method(<int>[]), (e) => e is NoSuchMethodError);
+}
diff --git a/tests/language/issue11793_test.dart b/tests/language/issue11793_test.dart
new file mode 100644
index 0000000..0cd00b4
--- /dev/null
+++ b/tests/language/issue11793_test.dart
@@ -0,0 +1,47 @@
+// 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, whose value range analysis phase
+// assumed loop phis that were integer necessarily had integer inputs.
+
+var array = const [0, 0.5];
+var globalB = array[0];
+var otherArray = [5];
+
+main() {
+ var b = globalB;
+ var a = b + 1;
+ if (otherArray[0] == 0) {
+ // Use a non-existing selector to prevent adding a bailout check.
+ a.noSuch();
+ a = otherArray[0];
+ }
+
+ // Use [a] to make sure it does not become dead code.
+ var f = array[a];
+
+ // Add an integer check on [b].
+ var d = array[b];
+
+ // This instruction will be GVN to the same value as [a].
+ // By being GVN'ed, [e] will have its type changed from integer
+ // to number: because of the int type check on [b], we know
+ // [: b + 1 :] returns an integer.
+ // However we update this instruction with the previous [: b + 1 :]
+ // that did not have that information and therefore only knows that
+ // the instruction returns a number.
+ var e = b + 1;
+
+ // Introduce a loop phi that has [e] as header input, and [e++] as
+ // update input. By having [e] as input, dart2js will compute an
+ // integer type for the phi. However, after GVN, [e] becomes a
+ // number.
+
+ while (otherArray[0] == 0) {
+ // Use [e] as an index for an array so that the value range
+ // analysis tries to compute a range for [e].
+ otherArray[e] = d + f;
+ e++;
+ }
+}
diff --git a/tests/language/language.status b/tests/language/language.status
index 1f8c433..0c2d5300 100644
--- a/tests/language/language.status
+++ b/tests/language/language.status
@@ -16,11 +16,13 @@
# 3) Update the language/src directory with the updated test.
[ $compiler == dart2dart ]
+mixin_type_parameters_simple_test: Fail, Crash # issue 11803
mixin_super_constructor_named_test: Fail
mixin_super_constructor_positionals_test: Fail
const_constructor_super_test/01: fail
[ $compiler == none ]
+mixin_type_parameters_simple_test: Fail, Crash # issue 11803
mixin_super_constructor_named_test: Fail
mixin_super_constructor_positionals_test: Fail
built_in_identifier_prefix_test: Fail # http://dartbug.com/6970
diff --git a/tests/language/language_analyzer.status b/tests/language/language_analyzer.status
index bf69624..acbbb4c 100644
--- a/tests/language/language_analyzer.status
+++ b/tests/language/language_analyzer.status
@@ -4,56 +4,37 @@
[ $compiler == dartanalyzer ]
#argument_definition_test/01: fail # issue 11565 (passing for the wrong reason)
-abstract_factory_constructor_test/00: fail
-assign_instance_method_negative_test: fail
-assign_static_type_test/06: fail
-bad_named_parameters2_test: fail
-bad_named_parameters_test: fail
-bad_override_test/01: fail
-bad_override_test/02: fail
-black_listed_test/11: fail
-built_in_identifier_prefix_test: fail
-call_constructor_on_unresolvable_class_test/01: fail
-call_constructor_on_unresolvable_class_test/02: fail
-call_constructor_on_unresolvable_class_test/03: fail
-call_constructor_on_unresolvable_class_test/07: fail
-call_nonexistent_static_test/04: fail
-call_nonexistent_static_test/06: fail
-call_nonexistent_static_test/07: fail
-call_nonexistent_static_test/09: fail
-call_nonexistent_static_test/10: fail
+
+# test issue 11581, it is not warning to call dynamic
call_through_getter_test: fail
-cast_test/04: fail
-cast_test/05: fail
-closure_call_wrong_argument_count_negative_test: fail
-const_constructor_super_test/01: fail
+
+# test issue 11582, non-final field with 'const' constructor
compile_time_constant10_test/none: fail
+
+# test issue 11583, int is valid key for constant map literal
compile_time_constant_c_test/01: fail
-compile_time_constant_checked2_test/03: fail
-compile_time_constant_checked2_test/04: fail
-compile_time_constant_checked3_test/03: fail
-compile_time_constant_checked3_test/04: fail
-compile_time_constant_e_test: fail
-constructor2_negative_test: fail
-constructor3_negative_test: fail
-constructor_call_wrong_argument_count_negative_test: fail
-constructor_initializer_test: fail # uses argument definition test
-constructor_negative_test: fail
-cyclic_type_variable_test/01: fail
-cyclic_type_variable_test/02: fail
-cyclic_type_variable_test/03: fail
-cyclic_type_variable_test/04: fail
-default_factory2_test/01: fail
-default_implementation2_test: fail
-dynamic_field_test: fail
+
+# test issue 11589, export D from 2 export directives
export_cyclic_test: fail
-f_bounded_quantification_test/01: fail
-f_bounded_quantification_test/02: fail
-factory2_test: fail
-factory5_test/00: fail
-factory_implementation_test/none: fail
+
+# test issue 11580, Function is not a malformed type
+black_listed_test/11: fail
+
+# test issue 11584, positional arguments cannot be used for named parameters
+compile_time_constant_e_test: fail
+
+# test issue 11585, static warning, not negative test
+constructor3_negative_test: fail # issue 11585
+constructor_call_wrong_argument_count_negative_test: fail
+instance_call_wrong_argument_count_negative_test: fail
+
+# test issue 11586, Class(args) is compile-time warning, not error
+constructor_negative_test: fail
+
+# test issue 11590, runtime only negative test
field_method4_negative_test: fail
-field_override_test/01: fail
+
+# test issue 11591, assigning to the final variable is warning, not error
final_for_in_variable_test/01: fail
final_param_negative_test: fail
final_var_negative_test: fail
@@ -61,38 +42,82 @@
final_variable_assignment_test/02: fail
final_variable_assignment_test/03: fail
final_variable_assignment_test/04: fail
-first_class_types_constants_test: fail
-getter_no_setter2_test/00: fail
-getter_no_setter2_test/03: fail
-getter_no_setter_test/00: fail
getter_no_setter_test/01: fail
-getters_setters2_test/01: fail
-getters_setters_type_test/01: fail
-implicit_this_test/01: fail
-implicit_this_test/04: fail
+
+# test issue 11592, Function type alias (typedef) is not a constant
+first_class_types_constants_test: fail
+
+# test issue 11594, Reference to a not resolve identifier is static warning
import_combinators_negative_test: fail
-instance_call_wrong_argument_count_negative_test: fail
-instantiate_type_variable_negative_test: fail
interface_static_non_final_fields_negative_test: fail
-interface_test/00: fail
+
+# test issue 11595, It is static warning to create instance (new) of the malformed type
+instantiate_type_variable_negative_test: fail
+
+# test issue 11596. e is Unknown is not a compile time error
is_not_class2_negative_test: fail
+
+# test issue 11597, It is a compile-time error if part has no "part of" directive
library_juxtaposition_test: fail
-map_literal3_test: fail
-mixin_illegal_constructor_test/13: fail
-mixin_illegal_constructor_test/14: fail
-mixin_illegal_constructor_test/15: fail
-mixin_illegal_constructor_test/16: fail
-mixin_illegal_syntax_test/13: fail
+
+# test issue 11598, Any use of a malbounded type gives rise to a static warning
mixin_type_parameters_errors_test/01: fail
mixin_type_parameters_errors_test/02: fail
-mixin_type_parameters_errors_test/04: fail
mixin_type_parameters_errors_test/05: fail
-named_parameters2_test: fail
+
+
+
+
+# TBF: a.imethod = () { return 1; };
+assign_instance_method_negative_test: fail
+
+# TBF: m([int p = 'String'])
+assign_static_type_test/06: fail
+
+# TBD: using built-in identifers
+built_in_identifier_prefix_test: fail
+
+# TBF: (o as C) is not rolled back
+cast_test/04: fail
+cast_test/05: fail
+
+# TBF: It is a compile-time error if the superclass of a class C appears in the implements clause of C.
+closure_call_wrong_argument_count_negative_test: fail
+const_constructor_super_test/01: fail
+compile_time_constant10_test/none: fail
+compile_time_constant_c_test/01: fail
+
+# Runtime negative test. No static errors or warnings.
+closure_call_wrong_argument_count_negative_test: skip
+
+# TBF: m([int p = 'String']) and call 'const' instance creation
+compile_time_constant_checked2_test/03: fail
+compile_time_constant_checked3_test/03: fail
+
+# TBF: not initialized final instance variable
+constructor2_negative_test: fail
+constructor3_negative_test: fail
+constructor_call_wrong_argument_count_negative_test: fail
+constructor_initializer_test: fail # uses argument definition test
+constructor_negative_test: fail
+
+# TBF: It is a static type warning if a type parameter is a supertype of its upper bound.
+cyclic_type_variable_test/01: fail
+cyclic_type_variable_test/02: fail
+cyclic_type_variable_test/03: fail
+cyclic_type_variable_test/04: fail
+
+# TBF: It is a static type warning if any of the type arguments to k' are not subtypes of the bounds of the corresponding formal type parameters of type.
+default_factory2_test/01: fail
+
+# TBF: It is a static warning if the function type of k' is not a subtype of the type of k.
+default_implementation2_test: fail
+
+# TBD: F-bounded quantification
+f_bounded_quantification_test/01: fail
+f_bounded_quantification_test/02: fail
+
named_parameters_aggregated_test/03: fail
-named_parameters_aggregated_test/05: fail
-new_expression_type_args_test/00: fail
-new_expression_type_args_test/01: fail
-new_expression_type_args_test/02: fail
no_such_method_negative_test: fail
non_const_super_negative_test: fail
number_identifier_negative_test: fail
@@ -103,8 +128,6 @@
prefix11_negative_test: fail
prefix12_negative_test: fail
prefix1_negative_test: fail
-prefix22_test: fail
-prefix23_test: fail
prefix2_negative_test: fail
prefix4_negative_test: fail
prefix5_negative_test: fail
@@ -116,14 +139,8 @@
private_member3_negative_test: fail
pseudo_kw_illegal_test/14: fail
pseudo_kw_test: fail
-redirecting_factory_infinite_steps_test/01: fail
scope_negative_test: fail
-setter3_test/01: fail
-setter3_test/02: fail
static_call_wrong_argument_count_negative_test: fail
-static_field3_test/01: fail
-static_field3_test/02: fail
-static_field3_test/04: fail
static_field_test/01: fail
static_field_test/02: fail
static_field_test/03: fail
@@ -137,21 +154,13 @@
syntax_test/33: fail
throw7_negative_test: fail
type_error_test: fail
-type_parameter_test/01: fail
-type_parameter_test/02: fail
-type_parameter_test/03: fail
-type_parameter_test/04: fail
-type_parameter_test/05: fail
-type_parameter_test/06: fail
+type_parameter_test/none: fail
type_variable_bounds2_test/00: fail
type_variable_bounds2_test/01: fail
type_variable_bounds2_test/02: fail
type_variable_bounds2_test/03: fail
type_variable_bounds2_test/04: fail
type_variable_bounds2_test/06: fail
-type_variable_bounds_test/00: fail
-type_variable_bounds_test/03: fail
-type_variable_bounds_test/04: fail
type_variable_static_context_negative_test: fail
unresolved_in_factory_negative_test: fail
unresolved_top_level_method_negative_test: fail
@@ -223,6 +232,7 @@
# Test issue 11564, named parameter starts with '_'
named_parameters_with_object_property_names_test: fail
+# TBF
method_override2_test/00: fail # issue 11497
method_override2_test/01: fail # issue 11497
method_override2_test/02: fail # issue 11497
@@ -236,10 +246,33 @@
# testing framework problem: we do report warning, framework does not understand it
# may be https://codereview.chromium.org/18174010/ will fix this
-mixin_type_parameters_errors_test/03: fail
type_variable_bounds_test/08: fail
wrong_number_type_arguments_test/01: fail
+# test issue 11575, classes with abstrac members are not marked as abstract
+abstract_factory_constructor_test/none: fail
+abstract_syntax_test/none: fail
+get_set_syntax_test/none: fail
+implicit_this_test/none: fail
+interface_test/none: fail
+syntax_test/none: fail
+
+# test issue 11576
+bad_constructor_test/none: fail
+
+# test issue 11577, has return type for []=
+cascade_test/none: fail
+
+# test issue 11578, redirecting factory with not subtype
+factory5_test/none: fail
+factory_redirection_test/none: fail
+type_variable_bounds_test/none: fail
+type_variable_scope_test/none: fail
+factory_implementation_test/none: fail
+
+# test issue 11579, assignment, no setter
+getter_no_setter_test/none: fail
+
[ $compiler == dartanalyzer && $checked ]
factory1_test/00: fail
factory1_test/01: fail
diff --git a/tests/language/language_analyzer2.status b/tests/language/language_analyzer2.status
index a5cfdc9..096888f 100644
--- a/tests/language/language_analyzer2.status
+++ b/tests/language/language_analyzer2.status
@@ -4,56 +4,37 @@
[ $compiler == dart2analyzer ]
#argument_definition_test/01: fail # issue 11565 (passing for the wrong reason)
-abstract_factory_constructor_test/00: fail
-assign_instance_method_negative_test: fail
-assign_static_type_test/06: fail
-bad_named_parameters2_test: fail
-bad_named_parameters_test: fail
-bad_override_test/01: fail
-bad_override_test/02: fail
-black_listed_test/11: fail
-built_in_identifier_prefix_test: fail
-call_constructor_on_unresolvable_class_test/01: fail
-call_constructor_on_unresolvable_class_test/02: fail
-call_constructor_on_unresolvable_class_test/03: fail
-call_constructor_on_unresolvable_class_test/07: fail
-call_nonexistent_static_test/04: fail
-call_nonexistent_static_test/06: fail
-call_nonexistent_static_test/07: fail
-call_nonexistent_static_test/09: fail
-call_nonexistent_static_test/10: fail
+
+# test issue 11581, it is not warning to call dynamic
call_through_getter_test: fail
-cast_test/04: fail
-cast_test/05: fail
-closure_call_wrong_argument_count_negative_test: fail
-const_constructor_super_test/01: fail
+
+# test issue 11582, non-final field with 'const' constructor
compile_time_constant10_test/none: fail
+
+# test issue 11583, int is valid key for constant map literal
compile_time_constant_c_test/01: fail
-compile_time_constant_checked2_test/03: fail
-compile_time_constant_checked2_test/04: fail
-compile_time_constant_checked3_test/03: fail
-compile_time_constant_checked3_test/04: fail
-compile_time_constant_e_test: fail
-constructor2_negative_test: fail
-constructor3_negative_test: fail
-constructor_call_wrong_argument_count_negative_test: fail
-constructor_initializer_test: fail # uses argument definition test
-constructor_negative_test: fail
-cyclic_type_variable_test/01: fail
-cyclic_type_variable_test/02: fail
-cyclic_type_variable_test/03: fail
-cyclic_type_variable_test/04: fail
-default_factory2_test/01: fail
-default_implementation2_test: fail
-dynamic_field_test: fail
+
+# test issue 11589, export D from 2 export directives
export_cyclic_test: fail
-f_bounded_quantification_test/01: fail
-f_bounded_quantification_test/02: fail
-factory2_test: fail
-factory5_test/00: fail
-factory_implementation_test/none: fail
+
+# test issue 11580, Function is not a malformed type
+black_listed_test/11: fail
+
+# test issue 11584, positional arguments cannot be used for named parameters
+compile_time_constant_e_test: fail
+
+# test issue 11585, static warning, not negative test
+constructor3_negative_test: fail # issue 11585
+constructor_call_wrong_argument_count_negative_test: fail
+instance_call_wrong_argument_count_negative_test: fail
+
+# test issue 11586, Class(args) is compile-time warning, not error
+constructor_negative_test: fail
+
+# test issue 11590, runtime only negative test
field_method4_negative_test: fail
-field_override_test/01: fail
+
+# test issue 11591, assigning to the final variable is warning, not error
final_for_in_variable_test/01: fail
final_param_negative_test: fail
final_var_negative_test: fail
@@ -61,38 +42,82 @@
final_variable_assignment_test/02: fail
final_variable_assignment_test/03: fail
final_variable_assignment_test/04: fail
-first_class_types_constants_test: fail
-getter_no_setter2_test/00: fail
-getter_no_setter2_test/03: fail
-getter_no_setter_test/00: fail
getter_no_setter_test/01: fail
-getters_setters2_test/01: fail
-getters_setters_type_test/01: fail
-implicit_this_test/01: fail
-implicit_this_test/04: fail
+
+# test issue 11592, Function type alias (typedef) is not a constant
+first_class_types_constants_test: fail
+
+# test issue 11594, Reference to a not resolve identifier is static warning
import_combinators_negative_test: fail
-instance_call_wrong_argument_count_negative_test: fail
-instantiate_type_variable_negative_test: fail
interface_static_non_final_fields_negative_test: fail
-interface_test/00: fail
+
+# test issue 11595, It is static warning to create instance (new) of the malformed type
+instantiate_type_variable_negative_test: fail
+
+# test issue 11596. e is Unknown is not a compile time error
is_not_class2_negative_test: fail
+
+# test issue 11597, It is a compile-time error if part has no "part of" directive
library_juxtaposition_test: fail
-map_literal3_test: fail
-mixin_illegal_constructor_test/13: fail
-mixin_illegal_constructor_test/14: fail
-mixin_illegal_constructor_test/15: fail
-mixin_illegal_constructor_test/16: fail
-mixin_illegal_syntax_test/13: fail
+
+# test issue 11598, Any use of a malbounded type gives rise to a static warning
mixin_type_parameters_errors_test/01: fail
mixin_type_parameters_errors_test/02: fail
-mixin_type_parameters_errors_test/04: fail
mixin_type_parameters_errors_test/05: fail
-named_parameters2_test: fail
+
+
+
+
+# TBF: a.imethod = () { return 1; };
+assign_instance_method_negative_test: fail
+
+# TBF: m([int p = 'String'])
+assign_static_type_test/06: fail
+
+# TBD: using built-in identifers
+built_in_identifier_prefix_test: fail
+
+# TBF: (o as C) is not rolled back
+cast_test/04: fail
+cast_test/05: fail
+
+# TBF: It is a compile-time error if the superclass of a class C appears in the implements clause of C.
+closure_call_wrong_argument_count_negative_test: fail
+const_constructor_super_test/01: fail
+compile_time_constant10_test/none: fail
+compile_time_constant_c_test/01: fail
+
+# Runtime negative test. No static errors or warnings.
+closure_call_wrong_argument_count_negative_test: skip
+
+# TBF: m([int p = 'String']) and call 'const' instance creation
+compile_time_constant_checked2_test/03: fail
+compile_time_constant_checked3_test/03: fail
+
+# TBF: not initialized final instance variable
+constructor2_negative_test: fail
+constructor3_negative_test: fail
+constructor_call_wrong_argument_count_negative_test: fail
+constructor_initializer_test: fail # uses argument definition test
+constructor_negative_test: fail
+
+# TBF: It is a static type warning if a type parameter is a supertype of its upper bound.
+cyclic_type_variable_test/01: fail
+cyclic_type_variable_test/02: fail
+cyclic_type_variable_test/03: fail
+cyclic_type_variable_test/04: fail
+
+# TBF: It is a static type warning if any of the type arguments to k' are not subtypes of the bounds of the corresponding formal type parameters of type.
+default_factory2_test/01: fail
+
+# TBF: It is a static warning if the function type of k' is not a subtype of the type of k.
+default_implementation2_test: fail
+
+# TBD: F-bounded quantification
+f_bounded_quantification_test/01: fail
+f_bounded_quantification_test/02: fail
+
named_parameters_aggregated_test/03: fail
-named_parameters_aggregated_test/05: fail
-new_expression_type_args_test/00: fail
-new_expression_type_args_test/01: fail
-new_expression_type_args_test/02: fail
no_such_method_negative_test: fail
non_const_super_negative_test: fail
number_identifier_negative_test: fail
@@ -103,8 +128,6 @@
prefix11_negative_test: fail
prefix12_negative_test: fail
prefix1_negative_test: fail
-prefix22_test: fail
-prefix23_test: fail
prefix2_negative_test: fail
prefix4_negative_test: fail
prefix5_negative_test: fail
@@ -116,14 +139,8 @@
private_member3_negative_test: fail
pseudo_kw_illegal_test/14: fail
pseudo_kw_test: fail
-redirecting_factory_infinite_steps_test/01: fail
scope_negative_test: fail
-setter3_test/01: fail
-setter3_test/02: fail
static_call_wrong_argument_count_negative_test: fail
-static_field3_test/01: fail
-static_field3_test/02: fail
-static_field3_test/04: fail
static_field_test/01: fail
static_field_test/02: fail
static_field_test/03: fail
@@ -137,19 +154,13 @@
syntax_test/33: fail
throw7_negative_test: fail
type_error_test: fail
-type_parameter_test/01: fail
-type_parameter_test/02: fail
-type_parameter_test/03: fail
-type_parameter_test/04: fail
+type_parameter_test/none: fail
type_variable_bounds2_test/00: fail
type_variable_bounds2_test/01: fail
type_variable_bounds2_test/02: fail
type_variable_bounds2_test/03: fail
type_variable_bounds2_test/04: fail
type_variable_bounds2_test/06: fail
-type_variable_bounds_test/00: fail
-type_variable_bounds_test/03: fail
-type_variable_bounds_test/04: fail
type_variable_static_context_negative_test: fail
unresolved_in_factory_negative_test: fail
unresolved_top_level_method_negative_test: fail
@@ -221,6 +232,7 @@
# Test issue 11564, named parameter starts with '_'
named_parameters_with_object_property_names_test: fail
+# TBF
method_override2_test/00: fail # issue 11497
method_override2_test/01: fail # issue 11497
method_override2_test/02: fail # issue 11497
@@ -234,10 +246,33 @@
# testing framework problem: we do report warning, framework does not understand it
# may be https://codereview.chromium.org/18174010/ will fix this
-mixin_type_parameters_errors_test/03: fail
type_variable_bounds_test/08: fail
wrong_number_type_arguments_test/01: fail
+# test issue 11575, classes with abstrac members are not marked as abstract
+abstract_factory_constructor_test/none: fail
+abstract_syntax_test/none: fail
+get_set_syntax_test/none: fail
+implicit_this_test/none: fail
+interface_test/none: fail
+syntax_test/none: fail
+
+# test issue 11576
+bad_constructor_test/none: fail
+
+# test issue 11577, has return type for []=
+cascade_test/none: fail
+
+# test issue 11578, redirecting factory with not subtype
+factory5_test/none: fail
+factory_redirection_test/none: fail
+type_variable_bounds_test/none: fail
+type_variable_scope_test/none: fail
+factory_implementation_test/none: fail
+
+# test issue 11579, assignment, no setter
+getter_no_setter_test/none: fail
+
[ $compiler == dart2analyzer && $checked ]
factory1_test/00: fail
factory1_test/01: fail
diff --git a/tests/language/language_dart2js.status b/tests/language/language_dart2js.status
index d4d1733..26d084f 100644
--- a/tests/language/language_dart2js.status
+++ b/tests/language/language_dart2js.status
@@ -152,7 +152,7 @@
get_set_syntax_test/16: Fail # Fixed by https://chromiumcodereview.appspot.com/10915111
method_binding_test: Fail # internal error: super property read not implemented.
method_override_test: Fail # cannot resolve type GetKeysFunctionType
-method_override5_test: Fail # Issue 11496
+method_override5_test: Pass, Fail # Issue 11496 (passes if it's inlined)
abstract_getter_test/01: Fail # instantiation of abstract class
abstract_factory_constructor_test/01: Fail # instantiation of abstract class
parameter_initializer6_negative_test: Fail # Issue 3502
@@ -289,7 +289,7 @@
expect_test: Fail
stack_overflow_test: Fail
stack_overflow_stacktrace_test: Fail
-inlined_throw_test: Fail # BUG(11480): Triage.
+licm2_test: Timeout # Issue: 11848
[ $compiler == dart2js && $runtime == safari ]
diff --git a/tests/language/mixin_type_parameters_simple_test.dart b/tests/language/mixin_type_parameters_simple_test.dart
new file mode 100644
index 0000000..0df7996
--- /dev/null
+++ b/tests/language/mixin_type_parameters_simple_test.dart
@@ -0,0 +1,26 @@
+// 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";
+
+class S {}
+
+class M1<X> {
+ m1() => X;
+}
+
+class M2<Y> {
+ m2() => Y;
+}
+
+class A<T> extends S with M1<T> , M2<T> { }
+
+main() {
+ var a = new A<int>();
+ Expect.equals("int", a.m1().toString());
+ Expect.equals("int", a.m2().toString());
+ a = new A<String>();
+ Expect.equals("String", a.m1().toString());
+ Expect.equals("String", a.m2().toString());
+}
diff --git a/tests/language/recursive_calls_test.dart b/tests/language/recursive_calls_test.dart
new file mode 100644
index 0000000..9a44ea6
--- /dev/null
+++ b/tests/language/recursive_calls_test.dart
@@ -0,0 +1,13 @@
+// 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";
+
+int bar(x) => foo(x+1);
+int foo(x) => x > 9 ? x : bar(x);
+
+main() {
+ Expect.equals(foo(int.parse("1")), 10);
+}
+
diff --git a/tests/lib/analyzer/analyze_library.status b/tests/lib/analyzer/analyze_library.status
index 7298d80..227e5c6 100644
--- a/tests/lib/analyzer/analyze_library.status
+++ b/tests/lib/analyzer/analyze_library.status
@@ -2,3 +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.
+[ $compiler == dart2analyzer ]
+lib/async/async: fail
+lib/core/core: fail
+lib/typed_data/typed_data: fail
+lib/io/io: fail
diff --git a/tests/lib/analyzer/analyze_tests.status b/tests/lib/analyzer/analyze_tests.status
index 28e1660..6348c8b 100644
--- a/tests/lib/analyzer/analyze_tests.status
+++ b/tests/lib/analyzer/analyze_tests.status
@@ -3,10 +3,58 @@
# BSD-style license that can be found in the LICENSE file.
[ $compiler == dartanalyzer ]
-standalone/io/process_exit_negative_test: fail
53bit_overflow_literal_test/01: fail, ok
+# https://code.google.com/p/dart/issues/detail?id=11665
+standalone/assert_test: fail
+standalone/io/directory_invalid_arguments_test: fail
+standalone/io/file_constructor_test: fail
+standalone/io/file_fuzz_test: fail
+standalone/io/http_cookie_date_test: fail
+standalone/io/http_headers_test: fail
+standalone/io/http_parser_test: fail
+standalone/io/process_invalid_arguments_test: fail
+standalone/io/raw_secure_server_socket_argument_test: fail
+standalone/io/secure_socket_argument_test: fail
+standalone/io/stdout_bad_argument_test: fail
+standalone/io/skipping_dart2js_compilations_test: fail
+standalone/io/url_encoding_test: fail
+standalone/io/web_socket_protocol_processor_test: fail
+standalone/io/test_runner_test: fail
+standalone/package/invalid_uri_test: fail
+standalone/package/package1_test: fail
+standalone/package/package_test: fail
+standalone/typed_data_view_test: fail
+standalone/typed_data_test: fail
+
+# pkg issue https://code.google.com/p/dart/issues/detail?id=11856
+standalone/io/secure_socket_renegotiate_test: fail
+
[ $compiler == dart2analyzer ]
-standalone/io/process_exit_negative_test: fail
53bit_overflow_literal_test/01: fail, ok
+
+# https://code.google.com/p/dart/issues/detail?id=11665
+standalone/assert_test: fail
+standalone/io/directory_invalid_arguments_test: fail
+standalone/io/file_constructor_test: fail
+standalone/io/file_fuzz_test: fail
+standalone/io/http_cookie_date_test: fail
+standalone/io/http_headers_test: fail
+standalone/io/http_parser_test: fail
+standalone/io/process_invalid_arguments_test: fail
+standalone/io/raw_secure_server_socket_argument_test: fail
+standalone/io/secure_socket_argument_test: fail
+standalone/io/stdout_bad_argument_test: fail
+standalone/io/skipping_dart2js_compilations_test: fail
+standalone/io/url_encoding_test: fail
+standalone/io/web_socket_protocol_processor_test: fail
+standalone/io/test_runner_test: fail
+standalone/package/invalid_uri_test: fail
+standalone/package/package1_test: fail
+standalone/package/package_test: fail
+standalone/typed_data_view_test: fail
+standalone/typed_data_test: fail
+
+# pkg issue https://code.google.com/p/dart/issues/detail?id=11856
+standalone/io/secure_socket_renegotiate_test: fail
diff --git a/tests/lib/convert/utf82_test.dart b/tests/lib/convert/utf82_test.dart
new file mode 100644
index 0000000..f972803
--- /dev/null
+++ b/tests/lib/convert/utf82_test.dart
@@ -0,0 +1,135 @@
+// 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 utf8_test;
+import "package:expect/expect.dart";
+import 'dart:convert';
+import 'dart:codec';
+
+String decode(List<int> bytes) => new Utf8Decoder().convert(bytes);
+String decodeAllowMalformed(List<int> bytes) {
+ return new Utf8Decoder(allowMalformed: true).convert(bytes);
+}
+
+String decode2(List<int> bytes) => UTF8.decode(bytes);
+String decodeAllowMalformed2(List<int> bytes) {
+ return UTF8.decode(bytes, allowMalformed: true);
+}
+
+String decode3(List<int> bytes) => new Utf8Codec().decode(bytes);
+String decodeAllowMalformed3(List<int> bytes) {
+ return new Utf8Codec(allowMalformed: true).decode(bytes);
+}
+
+String decode4(List<int> bytes) => new Utf8Codec().decoder.convert(bytes);
+String decodeAllowMalformed4(List<int> bytes) {
+ return new Utf8Codec(allowMalformed: true).decoder.convert(bytes);
+}
+
+final TESTS = [
+ // Unfinished UTF-8 sequences.
+ [ 0xc3 ],
+ [ 0xE2, 0x82 ],
+ [ 0xF0, 0xA4, 0xAD ],
+ // Overlong encoding of euro-sign.
+ [ 0xF0, 0x82, 0x82, 0xAC ],
+ // Other overlong/unfinished sequences.
+ [ 0xC0 ],
+ [ 0xC1 ],
+ [ 0xF5 ],
+ [ 0xF6 ],
+ [ 0xF7 ],
+ [ 0xF8 ],
+ [ 0xF9 ],
+ [ 0xFA ],
+ [ 0xFB ],
+ [ 0xFC ],
+ [ 0xFD ],
+ [ 0xFE ],
+ [ 0xFF ],
+ [ 0xC0, 0x80 ],
+ [ 0xC1, 0x80 ],
+ // Outside valid range.
+ [ 0xF4, 0xBF, 0xBF, 0xBF ]];
+
+final TESTS2 = [
+ // Test that 0xC0|1, 0x80 does not eat the next character.
+ [[ 0xC0, 0x80, 0x61 ], "Xa" ],
+ [[ 0xC1, 0x80, 0x61 ], "Xa" ],
+ // 0xF5 .. 0xFF never appear in valid UTF-8 sequences.
+ [[ 0xF5, 0x80 ], "XX" ],
+ [[ 0xF6, 0x80 ], "XX" ],
+ [[ 0xF7, 0x80 ], "XX" ],
+ [[ 0xF8, 0x80 ], "XX" ],
+ [[ 0xF9, 0x80 ], "XX" ],
+ [[ 0xFA, 0x80 ], "XX" ],
+ [[ 0xFB, 0x80 ], "XX" ],
+ [[ 0xFC, 0x80 ], "XX" ],
+ [[ 0xFD, 0x80 ], "XX" ],
+ [[ 0xFE, 0x80 ], "XX" ],
+ [[ 0xFF, 0x80 ], "XX" ],
+ [[ 0xF5, 0x80, 0x61 ], "XXa" ],
+ [[ 0xF6, 0x80, 0x61 ], "XXa" ],
+ [[ 0xF7, 0x80, 0x61 ], "XXa" ],
+ [[ 0xF8, 0x80, 0x61 ], "XXa" ],
+ [[ 0xF9, 0x80, 0x61 ], "XXa" ],
+ [[ 0xFA, 0x80, 0x61 ], "XXa" ],
+ [[ 0xFB, 0x80, 0x61 ], "XXa" ],
+ [[ 0xFC, 0x80, 0x61 ], "XXa" ],
+ [[ 0xFD, 0x80, 0x61 ], "XXa" ],
+ [[ 0xFE, 0x80, 0x61 ], "XXa" ],
+ [[ 0xFF, 0x80, 0x61 ], "XXa" ],
+ // Characters outside the valid range.
+ [[ 0xF5, 0x80, 0x80, 0x61 ], "XXXa" ],
+ [[ 0xF6, 0x80, 0x80, 0x61 ], "XXXa" ],
+ [[ 0xF7, 0x80, 0x80, 0x61 ], "XXXa" ],
+ [[ 0xF8, 0x80, 0x80, 0x61 ], "XXXa" ],
+ [[ 0xF9, 0x80, 0x80, 0x61 ], "XXXa" ],
+ [[ 0xFA, 0x80, 0x80, 0x61 ], "XXXa" ],
+ [[ 0xFB, 0x80, 0x80, 0x61 ], "XXXa" ],
+ [[ 0xFC, 0x80, 0x80, 0x61 ], "XXXa" ],
+ [[ 0xFD, 0x80, 0x80, 0x61 ], "XXXa" ],
+ [[ 0xFE, 0x80, 0x80, 0x61 ], "XXXa" ],
+ [[ 0xFF, 0x80, 0x80, 0x61 ], "XXXa" ]];
+
+main() {
+ var allTests = TESTS.expand((test) {
+ // Pairs of test and expected string output when malformed strings are
+ // allowed. Replacement character: U+FFFD
+ return [[ test, "\u{FFFD}" ],
+ [ new List.from([0x61])..addAll(test), "a\u{FFFD}" ],
+ [ new List.from([0x61])..addAll(test)..add(0x61), "a\u{FFFD}a" ],
+ [ new List.from(test)..add(0x61), "\u{FFFD}a" ],
+ [ new List.from(test)..addAll(test), "\u{FFFD}\u{FFFD}" ],
+ [ new List.from(test)..add(0x61)..addAll(test),
+ "\u{FFFD}a\u{FFFD}" ],
+ [ new List.from([0xc3, 0xa5])..addAll(test), "å\u{FFFD}" ],
+ [ new List.from([0xc3, 0xa5])..addAll(test)..addAll([0xc3, 0xa5]),
+ "å\u{FFFD}å" ],
+ [ new List.from(test)..addAll([0xc3, 0xa5]), "\u{FFFD}å" ],
+ [ new List.from(test)..addAll([0xc3, 0xa5])..addAll(test),
+ "\u{FFFD}å\u{FFFD}" ]];
+ });
+
+ var allTests2 = TESTS2.map((test) {
+ // Pairs of test and expected string output when malformed strings are
+ // allowed. Replacement character: U+FFFD
+ String expected = test[1].replaceAll("X", "\u{FFFD}");
+ return [test[0], expected];
+ });
+
+ for (var test in []..addAll(allTests)..addAll(allTests2)) {
+ List<int> bytes = test[0];
+ Expect.throws(() => decode(bytes), (e) => e is FormatException);
+ Expect.throws(() => decode2(bytes), (e) => e is FormatException);
+ Expect.throws(() => decode3(bytes), (e) => e is FormatException);
+ Expect.throws(() => decode4(bytes), (e) => e is FormatException);
+
+ String expected = test[1];
+ Expect.equals(expected, decodeAllowMalformed(bytes));
+ Expect.equals(expected, decodeAllowMalformed2(bytes));
+ Expect.equals(expected, decodeAllowMalformed3(bytes));
+ Expect.equals(expected, decodeAllowMalformed4(bytes));
+ }
+}
diff --git a/tests/lib/convert/utf83_test.dart b/tests/lib/convert/utf83_test.dart
new file mode 100644
index 0000000..3e155dd
--- /dev/null
+++ b/tests/lib/convert/utf83_test.dart
@@ -0,0 +1,46 @@
+// 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 utf8_test;
+import "package:expect/expect.dart";
+import 'dart:codec';
+import 'dart:convert';
+
+main() {
+ // Test that UTF8-decoder removes leading BOM.
+ Expect.equals("a", UTF8.decode([0xEF, 0xBB, 0xBF, 0x61]));
+ Expect.equals("a", UTF8.decoder.convert([0xEF, 0xBB, 0xBF, 0x61]));
+ Expect.equals("a", new Utf8Decoder().convert([0xEF, 0xBB, 0xBF, 0x61]));
+ Expect.equals("a",
+ UTF8.decode([0xEF, 0xBB, 0xBF, 0x61], allowMalformed: true));
+ Expect.equals("a", new Utf8Codec(allowMalformed: true)
+ .decode([0xEF, 0xBB, 0xBF, 0x61]));
+ Expect.equals("a", new Utf8Codec(allowMalformed: true)
+ .decoder.convert([0xEF, 0xBB, 0xBF, 0x61]));
+ Expect.equals("a", new Utf8Decoder(allowMalformed: true)
+ .convert([0xEF, 0xBB, 0xBF, 0x61]));
+ Expect.equals("", UTF8.decode([0xEF, 0xBB, 0xBF]));
+ Expect.equals("", UTF8.decoder.convert([0xEF, 0xBB, 0xBF]));
+ Expect.equals("", new Utf8Decoder().convert([0xEF, 0xBB, 0xBF]));
+ Expect.equals("",
+ UTF8.decode([0xEF, 0xBB, 0xBF], allowMalformed: true));
+ Expect.equals("", new Utf8Codec(allowMalformed: true)
+ .decode([0xEF, 0xBB, 0xBF]));
+ Expect.equals("", new Utf8Codec(allowMalformed: true)
+ .decoder.convert([0xEF, 0xBB, 0xBF]));
+ Expect.equals("", new Utf8Decoder(allowMalformed: true)
+ .convert([0xEF, 0xBB, 0xBF]));
+ Expect.equals("a\u{FEFF}", UTF8.decode([0x61, 0xEF, 0xBB, 0xBF]));
+ Expect.equals("a\u{FEFF}", UTF8.decoder.convert([0x61, 0xEF, 0xBB, 0xBF]));
+ Expect.equals("a\u{FEFF}",
+ new Utf8Decoder().convert([0x61, 0xEF, 0xBB, 0xBF]));
+ Expect.equals("a\u{FEFF}",
+ UTF8.decode([0x61, 0xEF, 0xBB, 0xBF], allowMalformed: true));
+ Expect.equals("a\u{FEFF}", new Utf8Codec(allowMalformed: true)
+ .decode([0x61, 0xEF, 0xBB, 0xBF]));
+ Expect.equals("a\u{FEFF}", new Utf8Codec(allowMalformed: true)
+ .decoder.convert([0x61, 0xEF, 0xBB, 0xBF]));
+ Expect.equals("a\u{FEFF}", new Utf8Decoder(allowMalformed: true)
+ .convert([0x61, 0xEF, 0xBB, 0xBF]));
+}
diff --git a/tests/lib/convert/utf8_test.dart b/tests/lib/convert/utf8_test.dart
new file mode 100644
index 0000000..4fa0297
--- /dev/null
+++ b/tests/lib/convert/utf8_test.dart
@@ -0,0 +1,47 @@
+// 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 utf8_test;
+import "package:expect/expect.dart";
+import 'dart:convert';
+
+String decode(List<int> bytes) => new Utf8Decoder().convert(bytes);
+
+main() {
+ // Google favorite: "Îñţérñåţîöñåļîžåţîờñ".
+ String string = decode([0xc3, 0x8e, 0xc3, 0xb1, 0xc5, 0xa3, 0xc3, 0xa9, 0x72,
+ 0xc3, 0xb1, 0xc3, 0xa5, 0xc5, 0xa3, 0xc3, 0xae, 0xc3,
+ 0xb6, 0xc3, 0xb1, 0xc3, 0xa5, 0xc4, 0xbc, 0xc3, 0xae,
+ 0xc5, 0xbe, 0xc3, 0xa5, 0xc5, 0xa3, 0xc3, 0xae, 0xe1,
+ 0xbb, 0x9d, 0xc3, 0xb1]);
+ Expect.stringEquals("Îñţérñåţîöñåļîžåţîờñ", string);
+
+ // Blueberry porridge in Danish: "blåbærgrød".
+ string = decode([0x62, 0x6c, 0xc3, 0xa5, 0x62, 0xc3, 0xa6, 0x72, 0x67, 0x72,
+ 0xc3, 0xb8, 0x64]);
+ Expect.stringEquals("blåbærgrød", string);
+
+ // "சிவா அணாமாைல", that is "Siva Annamalai" in Tamil.
+ string = decode([0xe0, 0xae, 0x9a, 0xe0, 0xae, 0xbf, 0xe0, 0xae, 0xb5, 0xe0,
+ 0xae, 0xbe, 0x20, 0xe0, 0xae, 0x85, 0xe0, 0xae, 0xa3, 0xe0,
+ 0xae, 0xbe, 0xe0, 0xae, 0xae, 0xe0, 0xae, 0xbe, 0xe0, 0xaf,
+ 0x88, 0xe0, 0xae, 0xb2]);
+ Expect.stringEquals("சிவா அணாமாைல", string);
+
+ // "िसवा अणामालै", that is "Siva Annamalai" in Devanagari.
+ string = decode([0xe0, 0xa4, 0xbf, 0xe0, 0xa4, 0xb8, 0xe0, 0xa4, 0xb5, 0xe0,
+ 0xa4, 0xbe, 0x20, 0xe0, 0xa4, 0x85, 0xe0, 0xa4, 0xa3, 0xe0,
+ 0xa4, 0xbe, 0xe0, 0xa4, 0xae, 0xe0, 0xa4, 0xbe, 0xe0, 0xa4,
+ 0xb2, 0xe0, 0xa5, 0x88]);
+ Expect.stringEquals("िसवा अणामालै", string);
+
+ // DESERET CAPITAL LETTER BEE, unicode 0x10412(0xD801+0xDC12)
+ // UTF-8: F0 90 90 92
+ string = decode([0xf0, 0x90, 0x90, 0x92]);
+ Expect.equals(string.length, 2);
+ Expect.equals("𐐒".length, 2);
+ Expect.stringEquals("𐐒", string);
+
+ // TODO(ahe): Add tests of bad input.
+}
diff --git a/tests/lib/lib.status b/tests/lib/lib.status
index 11cee52..b443409 100644
--- a/tests/lib/lib.status
+++ b/tests/lib/lib.status
@@ -4,7 +4,8 @@
[ $compiler == dart2js ]
math/*: Skip
-mirrors/method_mirror_test: Fail # Issue 6335
+mirrors/method_mirror_name_test: Fail # Issue 6335
+mirrors/method_mirror_properties_test: Fail # Issue 11861
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.
async/run_async3_test: Fail # _enqueueImmediate runs after Timer. http://dartbug.com/9002
@@ -20,19 +21,8 @@
[ $compiler == dart2js && ($runtime == d8 || $runtime == ie9) ]
typed_data/byte_data_test: Fail, OK # d8/ie9 doesn't support DataView
-[ $compiler == dart2js && $minified ]
-mirrors/reflect_model_test: Fail # Issue 6490
-mirrors/to_string_test: Fail # Issue 6490
-
[ $csp ]
-mirrors/intercepted_class_test: Fail # Issue 6490
-mirrors/intercepted_object_test: Fail # Issue 6490
-mirrors/metadata_test: Fail # Issue 6490
-mirrors/reflect_model_test: Fail # Issue 6490
-mirrors/reflect_runtime_type_test: Fail # Issue 6490
-mirrors/reflect_uninstantiated_class_test: Fail # Issue 6490
-mirrors/superclass_test: Fail # Issue 6490
-mirrors/to_string_test: Fail # Issue 6490
+mirrors/*: Skip # Issue 6490
[ $compiler == dart2js && $jscl ]
async/future_test: Fail # Timer interface not supported; dartbug.com/7728.
diff --git a/tests/lib/mirrors/abstract_test.dart b/tests/lib/mirrors/abstract_test.dart
new file mode 100644
index 0000000..3992363
--- /dev/null
+++ b/tests/lib/mirrors/abstract_test.dart
@@ -0,0 +1,19 @@
+// 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 abstract classes are retained.
+
+library test.abstract_test;
+
+import 'dart:mirrors';
+
+import 'stringify.dart';
+
+abstract class Foo {
+}
+
+void main() {
+ expect('Class(s(Foo) in s(test.abstract_test), top-level)',
+ reflectClass(Foo));
+}
diff --git a/tests/lib/mirrors/inherit_field_test.dart b/tests/lib/mirrors/inherit_field_test.dart
new file mode 100644
index 0000000..d61e3bb
--- /dev/null
+++ b/tests/lib/mirrors/inherit_field_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 inherited fields.
+
+library test.inherit_field_test;
+
+import 'dart:mirrors';
+
+import 'stringify.dart';
+
+class Foo {
+ var field;
+}
+
+class Bar extends Foo {
+}
+
+void main() {
+ expect('Variable(s(field) in s(Foo))',
+ reflectClass(Foo).members[new Symbol('field')]);
+ expect('<null>',
+ reflectClass(Bar).members[new Symbol('field')]);
+}
diff --git a/tests/lib/mirrors/lazy_static_test.dart b/tests/lib/mirrors/lazy_static_test.dart
new file mode 100644
index 0000000..d82316b
--- /dev/null
+++ b/tests/lib/mirrors/lazy_static_test.dart
@@ -0,0 +1,33 @@
+// 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 static members.
+
+import 'dart:mirrors';
+
+import 'package:expect/expect.dart';
+
+import 'stringify.dart';
+
+class Foo {
+ static var hello = {
+ 'a': 'b',
+ 'c': 'd',
+ };
+}
+
+void main() {
+ expect('Variable(s(hello) in s(Foo), static)',
+ reflectClass(Foo).members[new Symbol('hello')]);
+ var reflectee = reflectClass(Foo).getField(new Symbol('hello')).reflectee;
+ Expect.stringEquals('a, c', reflectee.keys.join(', '));
+ // Call the lazy getter twice as different things probably happen in the
+ // underlying implementation.
+ reflectee = reflectClass(Foo).getField(new Symbol('hello')).reflectee;
+ Expect.stringEquals('a, c', reflectee.keys.join(', '));
+ var value = 'fisk';
+ Foo.hello = value;
+ reflectee = reflectClass(Foo).getField(new Symbol('hello')).reflectee;
+ Expect.identical(value, reflectee);
+}
diff --git a/tests/lib/mirrors/method_mirror_name_test.dart b/tests/lib/mirrors/method_mirror_name_test.dart
new file mode 100644
index 0000000..a921d33
--- /dev/null
+++ b/tests/lib/mirrors/method_mirror_name_test.dart
@@ -0,0 +1,17 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "dart:mirrors";
+
+import "package:expect/expect.dart";
+import "stringify.dart";
+
+doNothing42() {}
+
+main() {
+ // Regression test for http://www.dartbug.com/6335
+ var closureMirror = reflect(doNothing42);
+ Expect.equals(stringifySymbol(closureMirror.function.simpleName),
+ "s(doNothing42)");
+}
diff --git a/tests/lib/mirrors/method_mirror_properties_test.dart b/tests/lib/mirrors/method_mirror_properties_test.dart
new file mode 100644
index 0000000..c29c6f8
--- /dev/null
+++ b/tests/lib/mirrors/method_mirror_properties_test.dart
@@ -0,0 +1,78 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "dart:mirrors";
+
+import "package:expect/expect.dart";
+
+doNothing42() {}
+
+int _x = 5;
+int get topGetter => _x;
+void set topSetter(x) { _x = x; }
+
+class AbstractC {
+
+ AbstractC();
+
+ void bar();
+ get priv;
+ set priv(value);
+}
+
+class C extends AbstractC {
+
+ static foo() {}
+
+ C();
+ C.other();
+ C.other2() : this.other();
+
+ var _priv;
+ get priv => _priv;
+ set priv(value) => _priv = value;
+}
+
+checkKinds(method, kinds) {
+ Expect.equals(method.isStatic, kinds[0]);
+ Expect.equals(method.isAbstract, kinds[1]);
+ Expect.equals(method.isGetter, kinds[2]);
+ Expect.equals(method.isSetter, kinds[3]);
+ Expect.equals(method.isConstructor, kinds[4]);
+}
+
+main() {
+ // Top level functions should be static.
+ var closureMirror = reflect(doNothing42);
+ checkKinds(closureMirror.function,
+ [true, false, false, false, false]);
+ var libraryMirror = reflectClass(C).owner;
+ checkKinds(libraryMirror.getters[const Symbol("topGetter")],
+ [true, false, true, false, false]);
+ checkKinds(libraryMirror.setters[const Symbol("topSetter=")],
+ [true, false, false, true, false]);
+ var classMirror;
+ classMirror = reflectClass(C);
+ checkKinds(classMirror.members[const Symbol("foo")],
+ [true, false, false, false, false]);
+ checkKinds(classMirror.members[const Symbol("priv")],
+ [false, false, true, false, false]);
+ checkKinds(classMirror.members[const Symbol("priv=")],
+ [false, false, false, true, false]);
+ checkKinds(classMirror.constructors[const Symbol("C")],
+ [false, false, false, false, true]);
+ checkKinds(classMirror.constructors[const Symbol("C.other")],
+ [false, false, false, false, true]);
+ checkKinds(classMirror.constructors[const Symbol("C.other2")],
+ [false, false, false, false, true]);
+ classMirror = reflectClass(AbstractC);
+ checkKinds(classMirror.constructors[const Symbol("AbstractC")],
+ [false, false, false, false, true]);
+ checkKinds(classMirror.members[const Symbol("bar")],
+ [false, true, false, false, false]);
+ checkKinds(classMirror.members[const Symbol("priv")],
+ [false, true, true, false, false]);
+ checkKinds(classMirror.members[const Symbol("priv=")],
+ [false, true, false, true, false]);
+}
diff --git a/tests/lib/mirrors/method_mirror_test.dart b/tests/lib/mirrors/method_mirror_test.dart
deleted file mode 100644
index 16851c9..0000000
--- a/tests/lib/mirrors/method_mirror_test.dart
+++ /dev/null
@@ -1,21 +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.
-
-import "dart:mirrors";
-
-import "../../../pkg/unittest/lib/unittest.dart";
-
-String _symbolToString(Symbol sym) {
- return MirrorSystem.getName(sym);
-}
-
-doNothing42() {}
-
-main() {
- // Regression test for http://www.dartbug.com/6335
- test("NamedMethodName", () {
- var closureMirror = reflect(doNothing42);
- expect(_symbolToString(closureMirror.function.simpleName), "doNothing42");
- });
-}
diff --git a/tests/lib/mirrors/mirrors_test.dart b/tests/lib/mirrors/mirrors_test.dart
index 13f8587..1b9a999 100644
--- a/tests/lib/mirrors/mirrors_test.dart
+++ b/tests/lib/mirrors/mirrors_test.dart
@@ -2,21 +2,34 @@
// 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(rmacnak): Move the existing mirror tests here (a place for
-// cross-implementation tests).
-
library MirrorsTest;
import "dart:mirrors";
import "../../../pkg/unittest/lib/unittest.dart";
+bool isDart2js = false; // TODO(ahe): Remove this field.
+bool isMinified = false; // TODO(ahe): Remove this field.
+
var topLevelField;
+u(a, b, c) => {"a": a, "b": b, "c": c};
+_v(a, b) => a + b;
class Class<T> {
Class() { this.field = "default value"; }
Class.withInitialValue(this.field);
var field;
- static var staticField;
+
+ Class.generative(this.field);
+ Class.redirecting(y) : this.generative(y*2);
+ factory Class.faktory(y) => new Class.withInitialValue(y*3);
+ factory Class.redirectingFactory(y) = Class.faktory;
+
m(a, b, c) => {"a": a, "b": b, "c": c};
+ _n(a, b) => a + b;
+ noSuchMethod(invocation) => "DNU";
+
+ static var staticField;
+ static s(a, b, c) => {"a": a, "b": b, "c": c};
+ static _t(a, b) => a + b;
}
typedef Typedef();
@@ -27,6 +40,37 @@
expect(instMirror.invoke(const Symbol("m"),['A', 'B', instance]).reflectee,
equals({"a": 'A', "b":'B', "c": instance}));
+ expect(instMirror.invoke(const Symbol("notDefined"), []).reflectee,
+ equals("DNU"));
+ expect(instMirror.invoke(const Symbol("m"), []).reflectee,
+ equals("DNU")); // Wrong arity.
+ // TODO(rmacnak): Implement access to private members.
+ // expect(instMirror.invoke(const Symbol("_n"), [3, 4]).reflectee,
+ // equals(7));
+
+ var classMirror = instMirror.type;
+ expect(classMirror.invoke(const Symbol("s"),['A', 'B', instance]).reflectee,
+ equals({"a": 'A', "b":'B', "c": instance}));
+ expect(() => classMirror.invoke(const Symbol("notDefined"), []).reflectee,
+ throws);
+ expect(() => classMirror.invoke(const Symbol("s"), []).reflectee,
+ throws); // Wrong arity.
+ // TODO(rmacnak): Implement access to private members.
+ // expect(classMirror.invoke(const Symbol("_t"), [3, 4]).reflectee,
+ // equals(7));
+
+ if (isDart2js) return;
+
+ var libMirror = classMirror.owner;
+ expect(libMirror.invoke(const Symbol("u"),['A', 'B', instance]).reflectee,
+ equals({"a": 'A', "b":'B', "c": instance}));
+ expect(() => libMirror.invoke(const Symbol("notDefined"), []).reflectee,
+ throws);
+ expect(() => libMirror.invoke(const Symbol("u"), []).reflectee,
+ throws); // Wrong arity.
+ // NB: This works on the VM but fails at compile-time on dart2js.
+ // expect(libMirror.invoke(const Symbol("_v"), [3, 4]).reflectee,
+ // equals(7));
}
testInstanceFieldAccess(mirrors) {
@@ -72,21 +116,24 @@
var classMirror = libMirror.classes[const Symbol("Class")];
var instMirror = reflect(instance);
var fieldMirror = classMirror.members[const Symbol('field')];
+ var future;
expect(fieldMirror is VariableMirror, isTrue);
expect(fieldMirror.type, equals(mirrors.dynamicType));
- libMirror.setField(const Symbol('topLevelField'), [91]);
- expect(libMirror.getField(const Symbol('topLevelField')).reflectee,
- equals([91]));
- expect(topLevelField, equals([91]));
+ if (!isMinified) {
+ libMirror.setField(const Symbol('topLevelField'), [91]);
+ expect(libMirror.getField(const Symbol('topLevelField')).reflectee,
+ equals([91]));
+ expect(topLevelField, equals([91]));
- libMirror.setFieldAsync(const Symbol('topLevelField'), 42);
- var future = libMirror.getFieldAsync(const Symbol('topLevelField'));
- future.then(expectAsync1((resultMirror) {
- expect(resultMirror.reflectee, equals(42));
- expect(topLevelField, equals(42));
- }));
+ libMirror.setFieldAsync(const Symbol('topLevelField'), 42);
+ future = libMirror.getFieldAsync(const Symbol('topLevelField'));
+ future.then(expectAsync1((resultMirror) {
+ expect(resultMirror.reflectee, equals(42));
+ expect(topLevelField, equals(42));
+ }));
+ }
classMirror.setFieldAsync(const Symbol('staticField'), 43);
future = classMirror.getFieldAsync(const Symbol('staticField'));
@@ -134,6 +181,30 @@
expect(instanceMirror.reflectee is Class, equals(true));
expect(instanceMirror.reflectee.field, equals(45));
+
+ instanceMirror = classMirror.newInstance(const Symbol('generative'),
+ [7]);
+ expect(instanceMirror.reflectee is Class, equals(true));
+ expect(instanceMirror.reflectee.field, equals(7));
+
+ instanceMirror = classMirror.newInstance(const Symbol('redirecting'),
+ [8]);
+ expect(instanceMirror.reflectee is Class, equals(true));
+ expect(instanceMirror.reflectee.field, equals(16));
+
+ instanceMirror = classMirror.newInstance(const Symbol('faktory'),
+ [9]);
+ expect(instanceMirror.reflectee is Class, equals(true));
+ expect(instanceMirror.reflectee.field, equals(27));
+
+ instanceMirror = classMirror.newInstance(const Symbol('redirectingFactory'),
+ [10]);
+ if (!isDart2js) {
+ expect(instanceMirror.reflectee is Class, equals(true));
+ expect(instanceMirror.reflectee.field, equals(30));
+ }
+
+
var future = classMirror.newInstanceAsync(const Symbol(''), []);
future.then(expectAsync1((resultMirror) {
var instance = resultMirror.reflectee;
@@ -155,12 +226,13 @@
var symbolClassMirror = reflectClass(Symbol);
var symbolMirror = symbolClassMirror.newInstance(const Symbol(''),
['withInitialValue']);
+ if (isDart2js) return;
var objectMirror = classMirror.newInstance(symbolMirror.reflectee,[1234]);
expect(objectMirror.reflectee is Class, equals(true));
expect(objectMirror.reflectee.field, equals(1234));
}
-testNames(mirrors, isDart2js) {
+testNames(mirrors) {
var libMirror = mirrors.findLibrary(const Symbol("MirrorsTest")).single;
var classMirror = libMirror.classes[const Symbol('Class')];
var typedefMirror = libMirror.members[const Symbol('Typedef')];
@@ -200,12 +272,11 @@
expect(check(valueLibrary.uri), isTrue);
}
-mainWithArgument({bool isDart2js: false, bool isMinified: false}) {
+main() {
var mirrors = currentMirrorSystem();
test("Test reflective method invocation", () { testInvoke(mirrors); });
test("Test instance field access", () { testInstanceFieldAccess(mirrors); });
test('Test intercepted objects', () { testIntercepted(mirrors); });
- if (!isMinified) // TODO(ahe): Remove this line.
test("Test field access", () { testFieldAccess(mirrors); });
test("Test closure mirrors", () { testClosureMirrors(mirrors); });
test("Test invoke constructor", () { testInvokeConstructor(mirrors); });
@@ -216,12 +287,6 @@
test("Test dart library uri", () {
testLibraryUri("test", (Uri uri) => uri == Uri.parse('dart:core'));
});
- if (!isMinified) // TODO(ahe): Remove this line.
- test("Test simple and qualifiedName", () { testNames(mirrors, isDart2js); });
- if (isDart2js) return; // TODO(ahe): Remove this line.
+ test("Test simple and qualifiedName", () { testNames(mirrors); });
test("Test reflect type", () { testReflectClass(mirrors); });
}
-
-main() {
- mainWithArgument();
-}
diff --git a/tests/lib/mirrors/parameter_test.dart b/tests/lib/mirrors/parameter_test.dart
index 3f97939..aa5cdee 100644
--- a/tests/lib/mirrors/parameter_test.dart
+++ b/tests/lib/mirrors/parameter_test.dart
@@ -27,23 +27,23 @@
var unnamedConstructor = constructors[new Symbol('B')];
expect('[]', unnamedConstructor.parameters);
- expect('Type(s(B) in s(test.parameter_test), top-level)',
+ expect('Class(s(B) in s(test.parameter_test), top-level)',
unnamedConstructor.returnType);
var fooConstructor = constructors[new Symbol('B.foo')];
expect('[Parameter(s(x) in s(B.foo),'
- ' type = Type(s(int) in s(dart.core), top-level))]',
+ ' type = Class(s(int) in s(dart.core), top-level))]',
fooConstructor.parameters);
- expect('Type(s(B) in s(test.parameter_test), top-level)',
+ expect('Class(s(B) in s(test.parameter_test), top-level)',
fooConstructor.returnType);
var barConstructor = constructors[new Symbol('B.bar')];
expect('[Parameter(s(z) in s(B.bar),'
- ' type = Type(s(int) in s(dart.core), top-level)), '
+ ' type = Class(s(int) in s(dart.core), top-level)), '
'Parameter(s(x) in s(B.bar),'
' type = Type(s(dynamic), top-level))]',
barConstructor.parameters);
- expect('Type(s(B) in s(test.parameter_test), top-level)',
+ expect('Class(s(B) in s(test.parameter_test), top-level)',
barConstructor.returnType);
print(constructors);
diff --git a/tests/lib/mirrors/reflect_model_test.dart b/tests/lib/mirrors/reflect_model_test.dart
index e5eabdf..69239e1 100644
--- a/tests/lib/mirrors/reflect_model_test.dart
+++ b/tests/lib/mirrors/reflect_model_test.dart
@@ -47,8 +47,6 @@
Expect.equals(89, fieldC);
expect('{accessor: Method(s(accessor) in s(A), getter)'
- // TODO(ahe): Include instance field getters?
- ', field: Method(s(field) in s(A), getter)'
'}',
aClass.getters);
expect('{accessor: Method(s(accessor) in s(B), getter)'
@@ -58,8 +56,6 @@
cClass.getters);
expect('{accessor=: Method(s(accessor=) in s(A), setter)'
- // TODO(ahe): Include instance field setters?
- ', field=: Method(s(field=) in s(A), setter)'
'}',
aClass.setters);
expect('{accessor=: Method(s(accessor=) in s(B), setter)}',
diff --git a/tests/lib/mirrors/return_type_test.dart b/tests/lib/mirrors/return_type_test.dart
index db4ad76..ebc208a 100644
--- a/tests/lib/mirrors/return_type_test.dart
+++ b/tests/lib/mirrors/return_type_test.dart
@@ -34,9 +34,9 @@
var i = methods[const Symbol('i')];
expect('Type(s(dynamic), top-level)', f.returnType);
- expect('Type(s(int) in s(dart.core), top-level)', g.returnType);
- expect('Type(s(List) in s(dart.core), top-level)', h.returnType);
- expect('Type(s(B) in s(test.return_type_test), top-level)', i.returnType);
+ expect('Class(s(int) in s(dart.core), top-level)', g.returnType);
+ expect('Class(s(List) in s(dart.core), top-level)', h.returnType);
+ expect('Class(s(B) in s(test.return_type_test), top-level)', i.returnType);
print(methods);
}
diff --git a/tests/lib/mirrors/static_test.dart b/tests/lib/mirrors/static_test.dart
new file mode 100644
index 0000000..b238e24
--- /dev/null
+++ b/tests/lib/mirrors/static_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.
+
+// Test static members.
+
+import 'dart:mirrors';
+
+import 'stringify.dart';
+
+class Foo {
+ static String bar = '...';
+ String aux = '';
+ static foo() {}
+ baz() {}
+}
+
+void main() {
+ expect('Variable(s(aux) in s(Foo))',
+ reflectClass(Foo).members[new Symbol('aux')]);
+ expect('Method(s(baz) in s(Foo))',
+ reflectClass(Foo).members[new Symbol('baz')]);
+ expect('<null>',
+ reflectClass(Foo).setters[new Symbol('aux=')]);
+ expect('Method(s(foo) in s(Foo), static)',
+ reflectClass(Foo).members[new Symbol('foo')]);
+ expect('Variable(s(bar) in s(Foo), static)',
+ reflectClass(Foo).members[new Symbol('bar')]);
+}
diff --git a/tests/lib/mirrors/stringify.dart b/tests/lib/mirrors/stringify.dart
index e8c31a8..0e3b2c0 100644
--- a/tests/lib/mirrors/stringify.dart
+++ b/tests/lib/mirrors/stringify.dart
@@ -70,7 +70,7 @@
buffer.write(', value = ${stringify(parameter.defaultValue)}');
}
// TODO(ahe): Move to writeVariableOn.
- buffer.write(', type = ${stringifyType(parameter.type)}');
+ buffer.write(', type = ${stringify(parameter.type)}');
return 'Parameter($buffer)';
}
@@ -80,6 +80,12 @@
return 'Type($buffer)';
}
+stringifyClass(ClassMirror cls) {
+ var buffer = new StringBuffer();
+ writeDeclarationOn(cls, buffer);
+ return 'Class($buffer)';
+}
+
stringifyMethod(MethodMirror method) {
var buffer = new StringBuffer();
writeDeclarationOn(method, buffer);
@@ -97,6 +103,7 @@
if (value is VariableMirror) return stringifyVariable(value);
if (value is MethodMirror) return stringifyMethod(value);
if (value is Symbol) return stringifySymbol(value);
+ if (value is ClassMirror) return stringifyClass(value);
if (value is TypeMirror) return stringifyType(value);
if (value == null) return '<null>';
throw 'Unexpected value: $value';
diff --git a/tests/standalone/io/skipping_dart2js_compilations_test.dart b/tests/standalone/io/skipping_dart2js_compilations_test.dart
index dfb71a5..98e65f1 100644
--- a/tests/standalone/io/skipping_dart2js_compilations_test.dart
+++ b/tests/standalone/io/skipping_dart2js_compilations_test.dart
@@ -154,6 +154,7 @@
var bootstrapDeps = [
Uri.parse("file://${fileUtils.testSnapshotFilePath}")];
var commands = [new runner.CompilationCommand(
+ 'dart2js',
fileUtils.testJsFilePath.toNativePath(),
false,
bootstrapDeps,
diff --git a/tests/standalone/io/test_runner_test.dart b/tests/standalone/io/test_runner_test.dart
index 79a8522..d07558a 100644
--- a/tests/standalone/io/test_runner_test.dart
+++ b/tests/standalone/io/test_runner_test.dart
@@ -71,13 +71,15 @@
}
TestCase _makeNormalTestCase(name, expectations) {
- var command = new Command(Platform.executable,
+ var command = new Command('custom',
+ Platform.executable,
[Platform.script, name]);
return _makeTestCase(name, DEFAULT_TIMEOUT, command, expectations);
}
_makeCrashTestCase(name, expectations) {
- var crashCommand = new Command(getProcessTestFileName(),
+ var crashCommand = new Command('custom_crash',
+ getProcessTestFileName(),
["0", "0", "1", "1"]);
// The crash test sometimes times out. Run it with a large timeout
// to help diagnose the delay.
diff --git a/tools/VERSION b/tools/VERSION
index 54ef79b..9d22974 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -1,4 +1,4 @@
MAJOR 0
MINOR 6
-BUILD 5
+BUILD 6
PATCH 0
diff --git a/tools/bots/editor.py b/tools/bots/editor.py
index f9db5ef..ffe7311 100755
--- a/tools/bots/editor.py
+++ b/tools/bots/editor.py
@@ -5,9 +5,7 @@
import os
import re
-import shutil
import sys
-import tempfile
import bot
@@ -20,14 +18,6 @@
GCS_DARTIUM_BUCKET = "gs://dartium-archive/continuous"
GCS_EDITOR_BUCKET = "gs://continuous-editor-archive"
-class TempDir(object):
- def __enter__(self):
- self._temp_dir = tempfile.mkdtemp('eclipse-workspace')
- return self._temp_dir
-
- def __exit__(self, *_):
- shutil.rmtree(self._temp_dir, ignore_errors = True)
-
def GetBuildDirectory(mode, arch):
configuration_dir = mode + arch.upper()
build_directory_dict = {
@@ -96,7 +86,7 @@
mac_build_dmg_py = os.path.join('tools', 'mac_build_editor_dmg.sh')
editor_dir = GetEditorDirectory('Release', arch)
dart_sdk = GetDartSdkDirectory('Release', arch)
- with TempDir() as temp_dir:
+ with utils.TempDir('eclipse') as temp_dir:
# Get dartium
dartium_directory = DownloadDartium(temp_dir, 'dartium-mac.zip')
dartium_bundle_dir = os.path.join(dartium_directory,
@@ -135,9 +125,8 @@
for arch in test_architectures:
editor_executable = GetEditorExecutable('Release', arch)
with bot.BuildStep('Test Editor %s' % arch):
- with TempDir() as temp_dir:
- args = [editor_executable, '-noSplash', '--test', '--auto-exit',
- '-data', temp_dir]
+ with utils.TempDir('eclipse') as temp_dir:
+ args = [editor_executable, '--test', '--auto-exit', '-data', temp_dir]
RunProcess(args)
# TODO: Permissions need to be clarified
diff --git a/tools/create_sdk.py b/tools/create_sdk.py
index 6791159..89b6aca 100755
--- a/tools/create_sdk.py
+++ b/tools/create_sdk.py
@@ -36,6 +36,7 @@
# ......html/
# ......io/
# ......isolate/
+# ......js/
# ......json/
# ......math/
# ......mirrors/
@@ -203,7 +204,7 @@
join('html', 'dart2js'), join('html', 'dartium'),
join('html', 'html_common'),
join('indexed_db', 'dart2js'), join('indexed_db', 'dartium'),
- 'json', 'math', 'mirrors', 'typed_data',
+ 'js', 'json', 'math', 'mirrors', 'typed_data',
join('svg', 'dart2js'), join('svg', 'dartium'),
'utf',
join('web_audio', 'dart2js'), join('web_audio', 'dartium'),
diff --git a/tools/dom/scripts/htmlrenamer.py b/tools/dom/scripts/htmlrenamer.py
index aff410d..339ba08 100644
--- a/tools/dom/scripts/htmlrenamer.py
+++ b/tools/dom/scripts/htmlrenamer.py
@@ -195,7 +195,6 @@
'DocumentFragment.querySelectorAll',
'Element.childElementCount',
'Element.children',
- 'Element.className',
'Element.firstElementChild',
'Element.getAttribute',
'Element.getAttributeNS',
@@ -680,7 +679,6 @@
'Node.get:DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC',
'Node.get:DOCUMENT_POSITION_PRECEDING',
'Node.get:baseURI',
- 'Node.get:nodeName',
'Node.get:prefix',
'Node.hasAttributes',
'Node.isDefaultNamespace',
diff --git a/tools/dom/src/CssClassSet.dart b/tools/dom/src/CssClassSet.dart
index 5355446..58c1d6a 100644
--- a/tools/dom/src/CssClassSet.dart
+++ b/tools/dom/src/CssClassSet.dart
@@ -98,7 +98,7 @@
void writeClasses(Set<String> s) {
var classes = new List.from(s).join(' ');
for (Element e in _elementIterable) {
- e.$dom_className = classes;
+ e.className = classes;
}
}
@@ -143,7 +143,7 @@
Set<String> readClasses() {
var s = new LinkedHashSet<String>();
- var classname = _element.$dom_className;
+ var classname = _element.className;
for (String name in classname.split(' ')) {
String trimmed = name.trim();
@@ -156,6 +156,6 @@
void writeClasses(Set<String> s) {
List list = new List.from(s);
- _element.$dom_className = s.join(' ');
+ _element.className = s.join(' ');
}
}
diff --git a/tools/dom/src/native_DOMImplementation.dart b/tools/dom/src/native_DOMImplementation.dart
index 61740d3..1616d41 100644
--- a/tools/dom/src/native_DOMImplementation.dart
+++ b/tools/dom/src/native_DOMImplementation.dart
@@ -71,6 +71,127 @@
static void spawnDomFunction(Function f, int replyTo) native "Utils_spawnDomFunction";
static void spawnDomUri(String uri, int replyTo) native "Utils_spawnDomUri";
static int _getNewIsolateId() native "Utils_getNewIsolateId";
+
+ // The following methods were added for debugger integration to make working
+ // with the Dart C mirrors API simpler.
+ // TODO(jacobr): consider moving them to a separate library.
+ // If Dart supported dynamic code injection, we would only inject this code
+ // when the debugger is invoked.
+
+ /**
+ * Strips the private secret prefix from member names of the form
+ * someName@hash.
+ */
+ static String stripMemberName(String name) {
+ int endIndex = name.indexOf('@');
+ return endIndex > 0 ? name.substring(0, endIndex) : name;
+ }
+
+ /**
+ * Takes a list containing variable names and corresponding values and
+ * returns a map from normalized names to values. Variable names are assumed
+ * to have list offsets 2*n values at offset 2*n+1. This method is required
+ * because Dart_GetLocalVariables returns a list instead of an object that
+ * can be queried to lookup names and values.
+ */
+ static Map<String, dynamic> createLocalVariablesMap(List localVariables) {
+ var map = {};
+ for (int i = 0; i < localVariables.length; i+=2) {
+ map[stripMemberName(localVariables[i])] = localVariables[i+1];
+ }
+ return map;
+ }
+
+ /**
+ * Convenience helper to get the keys of a [Map] as a [List].
+ */
+ static List getMapKeyList(Map map) => map.keys.toList();
+
+ /**
+ * Returns the keys of an arbitrary Dart Map encoded as unique Strings.
+ * Keys that are strings are left unchanged except that the prefix ":" is
+ * added to disambiguate keys from other Dart members.
+ * Keys that are not strings have # followed by the index of the key in the map
+ * prepended to disambuguate. This scheme is simplistic but easy to encode and
+ * decode. The use case for this method is displaying all map keys in a human
+ * readable way in debugging tools.
+ */
+ static List<String> getEncodedMapKeyList(dynamic obj) {
+ if (obj is! Map) return null;
+
+ var ret = new List<String>();
+ int i = 0;
+ return obj.keys.map((key) {
+ var encodedKey;
+ if (key is String) {
+ encodedKey = ':$key';
+ } else {
+ // If the key isn't a string, return a guaranteed unique for this map
+ // string representation of the key that is still somewhat human
+ // readable.
+ encodedKey = '#${i}:$key';
+ }
+ i++;
+ return encodedKey;
+ }).toList(growable: false);
+ }
+
+ static final RegExp _NON_STRING_KEY_REGEXP = new RegExp("^#(\\d+):(.+)\$");
+
+ static _decodeKey(Map map, String key) {
+ // The key is a regular old String.
+ if (key.startsWith(':')) return key.substring(1);
+
+ var match = _NON_STRING_KEY_REGEXP.firstMatch(key);
+ if (match != null) {
+ int index = int.parse(match.group(1));
+ var iter = map.keys.skip(index);
+ if (iter.isNotEmpty) {
+ var ret = iter.first;
+ // Validate that the toString representation of the key matches what we
+ // expect. FIXME: throw an error if it does not.
+ assert(match.group(2) == '$ret');
+ return ret;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Converts keys encoded with [getEncodedMapKeyList] to their actual keys.
+ */
+ static lookupValueForEncodedMapKey(Map obj, String key) => obj[_decodeKey(obj, key)];
+
+ /**
+ * Builds a constructor name with the form expected by the C Dart mirrors API.
+ */
+ static String buildConstructorName(String className, String constructorName) => '$className.$constructorName';
+
+ /**
+ * Strips the class name from an expression of the form "className.someName".
+ */
+ static String stripClassName(String str, String className) {
+ if (str.length > className.length + 1 &&
+ str.startsWith(className) && str[className.length] == '.') {
+ return str.substring(className.length + 1);
+ } else {
+ return str;
+ }
+ }
+
+ /**
+ * Removes the trailing dot from an expression ending in a dot.
+ * This method is used as Library prefixes include a trailing dot when using
+ * the C Dart debugger API.
+ */
+ static String stripTrailingDot(String str) =>
+ (str != null && str[str.length - 1] == '.') ? str.substring(0, str.length - 1) : str;
+
+ static String addTrailingDot(String str) => '${str}.';
+
+ // TODO(jacobr): we need a failsafe way to determine that a Node is really a
+ // DOM node rather than just a class that extends Node.
+ static bool isNode(obj) => obj is Node;
}
class _NPObject extends NativeFieldWrapperClass1 {
diff --git a/tools/testing/dart/test_progress.dart b/tools/testing/dart/test_progress.dart
index b288db5..20da10f 100644
--- a/tools/testing/dart/test_progress.dart
+++ b/tools/testing/dart/test_progress.dart
@@ -94,7 +94,7 @@
var command = test.commands[i];
var commandOutput = test.commandOutputs[command];
if (commandOutput != null) {
- output.add("CommandOutput[$i]:");
+ output.add("CommandOutput[${command.displayName}]:");
if (!commandOutput.diagnostics.isEmpty) {
String prefix = 'diagnostics:';
for (var s in commandOutput.diagnostics) {
@@ -203,29 +203,31 @@
}
class TimingPrinter extends EventListener {
- List<TestCase> _tests = <TestCase>[];
+ List<CommandOutput> _commandOutputs = <CommandOutput>[];
DateTime _startTime;
TimingPrinter(this._startTime);
void done(TestCase testCase) {
- _tests.add(testCase);
+ for (var commandOutput in testCase.commandOutputs.values) {
+ _commandOutputs.add(commandOutput);
+ }
}
void allDone() {
- // TODO: We should take all the commands into account
Duration d = (new DateTime.now()).difference(_startTime);
print('\n--- Total time: ${_timeString(d)} ---');
- _tests.sort((a, b) {
- Duration aDuration = a.lastCommandOutput.time;
- Duration bDuration = b.lastCommandOutput.time;
- return bDuration.inMilliseconds - aDuration.inMilliseconds;
+ _commandOutputs.sort((a, b) {
+ return b.time.inMilliseconds - a.time.inMilliseconds;
});
- for (int i = 0; i < 20 && i < _tests.length; i++) {
- var name = _tests[i].displayName;
- var duration = _tests[i].lastCommandOutput.time;
- var configuration = _tests[i].configurationString;
- print('${duration} - $configuration $name');
+ for (int i = 0; i < 20 && i < _commandOutputs.length; i++) {
+ var commandOutput = _commandOutputs[i];
+ var command = commandOutput.command;
+ var testCase = commandOutput.testCase;
+ var duration = commandOutput.time;
+ var configuration = testCase.configurationString;
+ print('${commandOutput.time} - $configuration'
+ ' - ${testCase.displayName} (${command.displayName})');
}
}
}
diff --git a/tools/testing/dart/test_runner.dart b/tools/testing/dart/test_runner.dart
index 991f8de..e4a51d9 100644
--- a/tools/testing/dart/test_runner.dart
+++ b/tools/testing/dart/test_runner.dart
@@ -107,7 +107,11 @@
/** The actual command line that will be executed. */
String commandLine;
- Command(this.executable, this.arguments, [this.environment = null]) {
+ /** A descriptive name for this command. */
+ String displayName;
+
+ Command(this.displayName, this.executable,
+ this.arguments, [this.environment = null]) {
if (io.Platform.operatingSystem == 'windows') {
// Windows can't handle the first command if it is a .bat file or the like
// with the slashes going the other direction.
@@ -132,12 +136,13 @@
bool _neverSkipCompilation;
List<Uri> _bootstrapDependencies;
- CompilationCommand(this._outputFile,
+ CompilationCommand(String displayName,
+ this._outputFile,
this._neverSkipCompilation,
this._bootstrapDependencies,
String executable,
List<String> arguments)
- : super(executable, arguments);
+ : super(displayName, executable, arguments);
Future<bool> get outputIsUpToDate {
if (_neverSkipCompilation) return new Future.value(false);
@@ -195,7 +200,8 @@
List<String> options,
List<String> dartFlags,
io.Path this.expectedOutputPath)
- : super(executable,
+ : super("content_shell",
+ executable,
_getArguments(options, htmlFile),
_getEnvironment(dartFlags));
@@ -457,6 +463,8 @@
Command get command;
+ TestCase testCase;
+
bool get incomplete;
String get result;
@@ -621,7 +629,6 @@
}
return testCase.isNegative ? !didFail : didFail;
}
-
}
class BrowserCommandOutputImpl extends CommandOutputImpl {
@@ -848,11 +855,7 @@
if (fields[ERROR_LEVEL] == 'ERROR') {
errors.add(fields[FORMATTED_ERROR]);
} else if (fields[ERROR_LEVEL] == 'WARNING') {
- // We only care about testing Static type warnings
- // ignore all others
- if (fields[ERROR_TYPE] == 'STATIC_TYPE' || fields[ERROR_TYPE] == 'STATIC_TYPE_WARNING') {
- staticWarnings.add(fields[FORMATTED_ERROR]);
- }
+ staticWarnings.add(fields[FORMATTED_ERROR]);
}
// OK to Skip error output that doesn't match the machine format
}
@@ -919,9 +922,9 @@
return true;
}
- if (isStaticClean && staticWarnings.length > 0) {
+ if (isStaticClean && (errors.isNotEmpty || staticWarnings.isNotEmpty)) {
diagnostics.add(
- "@static-clean annotation found but analyzer returned warnings.");
+ "@static-clean annotation found but analyzer returned problems.");
return true;
}
diff --git a/tools/testing/dart/test_suite.dart b/tools/testing/dart/test_suite.dart
index 6abfa34..6796368 100644
--- a/tools/testing/dart/test_suite.dart
+++ b/tools/testing/dart/test_suite.dart
@@ -360,11 +360,12 @@
var args = TestUtils.standardOptions(configuration);
args.add(testName);
- doTest(new TestCase(constructedName,
- [new Command(targetRunnerPath, args)],
- configuration,
- completeHandler,
- expectations));
+ doTest(
+ new TestCase(constructedName,
+ [new Command('run_vm_unittest', targetRunnerPath, args)],
+ configuration,
+ completeHandler,
+ expectations));
}
}
@@ -746,14 +747,16 @@
}
List<Command> makeCommands(TestInformation info, var vmOptions, var args) {
- switch (configuration['compiler']) {
+ var compiler = configuration['compiler'];
+ switch (compiler) {
case 'dart2js':
args = new List.from(args);
String tempDir = createOutputDirectory(info.filePath, '');
args.add('--out=$tempDir/out.js');
List<Command> commands =
- <Command>[new CompilationCommand("$tempDir/out.js",
+ <Command>[new CompilationCommand(compiler,
+ "$tempDir/out.js",
!useSdk,
dart2JsBootstrapDependencies,
compilerPath,
@@ -762,9 +765,10 @@
// Do not attempt to run the compiled result. A compilation
// error should be reported by the compilation command.
} else if (configuration['runtime'] == 'd8') {
- commands.add(new Command(d8FileName, ['$tempDir/out.js']));
+ commands.add(new Command("d8", d8FileName, ['$tempDir/out.js']));
} else if (configuration['runtime'] == 'jsshell') {
- commands.add(new Command(jsShellFileName, ['$tempDir/out.js']));
+ commands.add(
+ new Command("jsshell", jsShellFileName, ['$tempDir/out.js']));
}
return commands;
@@ -775,7 +779,8 @@
args.add('--out=$tempDir/out.dart');
List<Command> commands =
- <Command>[new CompilationCommand("$tempDir/out.dart",
+ <Command>[new CompilationCommand(compiler,
+ "$tempDir/out.dart",
!useSdk,
dart2JsBootstrapDependencies,
compilerPath,
@@ -788,7 +793,7 @@
var vmArguments = new List.from(vmOptions);
vmArguments.addAll([
'--ignore-unrecognized-flags', '$tempDir/out.dart']);
- commands.add(new Command(vmFileName, vmArguments));
+ commands.add(new Command("vm", vmFileName, vmArguments));
} else {
throw 'Unsupported runtime ${configuration["runtime"]} for dart2dart';
}
@@ -798,9 +803,12 @@
case 'dartc':
case 'dartanalyzer':
case 'dart2analyzer':
+ var displayName = (configuration['compiler'] == 'none'
+ ? 'vm' : configuration['compiler']);
var arguments = new List.from(vmOptions);
arguments.addAll(args);
- return <Command>[new Command(dartShellFileName, arguments)];
+ return <Command>[
+ new Command(displayName, dartShellFileName, arguments)];
default:
throw 'Unknown compiler ${configuration["compiler"]}';
@@ -1024,7 +1032,8 @@
args = ['tools/testing/dart/launch_browser.dart',
runtime,
fullHtmlPath];
- commandSet.add(new Command(TestUtils.dartTestExecutable.toString(),
+ commandSet.add(new Command(runtime,
+ TestUtils.dartTestExecutable.toString(),
args));
} else if (TestUtils.usesWebDriver(runtime)) {
args = [
@@ -1039,7 +1048,7 @@
if (subtestIndex != 0) {
args.add('--force-refresh');
}
- commandSet.add(new Command('python', args));
+ commandSet.add(new Command(runtime, 'python', args));
} else {
if (runtime != "drt") {
print("Unknown runtime $runtime");
@@ -1106,36 +1115,27 @@
/** Helper to create a compilation command for a single input file. */
Command _compileCommand(String inputFile, String outputFile,
String compiler, String dir, vmOptions, optionsFromFile) {
+ assert (['dart2js', 'dart2dart'].contains(compiler));
String executable = compilerPath;
List<String> args = TestUtils.standardOptions(configuration);
- switch (compiler) {
- case 'dart2js':
- case 'dart2dart':
- String packageRoot =
- packageRootArgument(optionsFromFile['packageRoot']);
- if (packageRoot != null) {
- args.add(packageRoot);
- }
- args.add('--out=$outputFile');
- args.add(inputFile);
- break;
- default:
- print('unimplemented compiler $compiler');
- exit(1);
+ String packageRoot =
+ packageRootArgument(optionsFromFile['packageRoot']);
+ if (packageRoot != null) {
+ args.add(packageRoot);
}
+ args.add('--out=$outputFile');
+ args.add(inputFile);
if (executable.endsWith('.dart')) {
// Run the compiler script via the Dart VM.
args.insert(0, executable);
executable = dartShellFileName;
}
- if (['dart2js', 'dart2dart'].contains(configuration['compiler'])) {
- return new CompilationCommand(outputFile,
- !useSdk,
- dart2JsBootstrapDependencies,
- compilerPath,
- args);
- }
- return new Command(executable, args);
+ return new CompilationCommand(compiler,
+ outputFile,
+ !useSdk,
+ dart2JsBootstrapDependencies,
+ compilerPath,
+ args);
}
/**
@@ -1518,7 +1518,7 @@
"packageRoot": null,
"hasCompileError": hasCompileError,
"hasRuntimeError": hasRuntimeError,
- "isStaticClean" : !hasStaticWarning,
+ "isStaticClean" : !hasCompileError && !hasStaticWarning,
"otherScripts": <String>[],
"isMultitest": isMultitest,
"isMultiHtmlTest": false,
@@ -1668,7 +1668,7 @@
});
updatedConfiguration['timeout'] *= 3;
doTest(new TestCase(suiteName,
- [new Command('java', args)],
+ [new Command('junit_test', 'java', args)],
updatedConfiguration,
completeHandler,
new Set<String>.from([PASS])));
diff --git a/tools/utils.py b/tools/utils.py
index 8346d09..0abb0ed 100644
--- a/tools/utils.py
+++ b/tools/utils.py
@@ -9,8 +9,10 @@
import os
import platform
import re
+import shutil
import subprocess
import sys
+import tempfile
# Try to guess the host operating system.
@@ -406,6 +408,18 @@
dart_binary_prefix = os.path.join(tools_dir, '..', 'sdk' , 'bin')
return os.path.join(dart_binary_prefix, 'dart')
+class TempDir(object):
+ def __init__(self, prefix=''):
+ self._temp_dir = None
+ self._prefix = prefix
+
+ def __enter__(self):
+ self._temp_dir = tempfile.mkdtemp(self._prefix)
+ return self._temp_dir
+
+ def __exit__(self, *_):
+ shutil.rmtree(self._temp_dir, ignore_errors=True)
+
if __name__ == "__main__":
import sys