Version 0.6.2.0 .
svn merge -r 24475:24603 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
git-svn-id: http://dart.googlecode.com/svn/trunk@24607 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/pkg/docgen/bin/docgen.dart b/pkg/docgen/bin/docgen.dart
index 6222b0f..f181a83 100644
--- a/pkg/docgen/bin/docgen.dart
+++ b/pkg/docgen/bin/docgen.dart
@@ -17,7 +17,7 @@
logger.onRecord.listen((record) => print(record.message));
var results = initArgParser().parse(new Options().arguments);
if (results['help']) return;
- new Docgen(results);
+ docgen(results);
}
/**
@@ -31,7 +31,7 @@
callback: (help) {
if (help) {
logger.info(parser.getUsage());
- logger.info(usage);
+ logger.info(USAGE);
}
});
parser.addFlag('verbose', abbr: 'v',
@@ -52,6 +52,9 @@
help: 'Flag to include private declarations.', negatable: false);
parser.addFlag('include-sdk',
help: 'Flag to parse SDK Library files.', negatable: false);
+ parser.addFlag('parse-sdk',
+ help: 'Parses the SDK libraries only.',
+ defaultsTo: false, negatable: false);
return parser;
}
diff --git a/pkg/docgen/lib/dart2yaml.dart b/pkg/docgen/lib/dart2yaml.dart
index a03c7f1..a481aca 100644
--- a/pkg/docgen/lib/dart2yaml.dart
+++ b/pkg/docgen/lib/dart2yaml.dart
@@ -52,7 +52,8 @@
* Returns an escaped String form of the inputted element.
*/
String _processElement(var element) {
- return "\"${element.toString().replaceAll("\"", "\\\"")}\"\n";
+ return "\"${element.toString().replaceAll('\\', '\\\\')
+ .replaceAll("\"", "\\\"")}\"\n";
}
/**
diff --git a/pkg/docgen/lib/docgen.dart b/pkg/docgen/lib/docgen.dart
index 52d10d2..a542195 100644
--- a/pkg/docgen/lib/docgen.dart
+++ b/pkg/docgen/lib/docgen.dart
@@ -33,275 +33,311 @@
import '../../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors.dart';
import '../../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors_util.dart';
import '../../../sdk/lib/_internal/compiler/implementation/source_file_provider.dart';
+import '../../../sdk/lib/_internal/libraries.dart';
var logger = new Logger('Docgen');
-const String usage = 'Usage: dart docgen.dart [OPTIONS] [fooDir/barFile]';
+const String USAGE = 'Usage: dart docgen.dart [OPTIONS] [fooDir/barFile]';
+
+/// Current library being documented to be used for comment links.
+LibraryMirror _currentLibrary;
+
+/// Current class being documented to be used for comment links.
+ClassMirror _currentClass;
+
+/// Current member being documented to be used for comment links.
+MemberMirror _currentMember;
+
+/// Resolves reference links in doc comments.
+markdown.Resolver linkResolver;
+
+/// Package directory of directory being analyzed.
+String packageDir;
+
+bool outputToYaml;
+bool outputToJson;
+bool includePrivate;
+/// State for whether imported SDK libraries should also be outputted.
+bool includeSdk;
+/// State for whether all SDK libraries should be outputted.
+bool parseSdk;
/**
- * This class documents a list of libraries.
+ * Docgen constructor initializes the link resolver for markdown parsing.
+ * Also initializes the command line arguments.
*/
-class Docgen {
-
- /// Libraries to be documented.
- List<LibraryMirror> _libraries;
-
- /// Current library being documented to be used for comment links.
- LibraryMirror _currentLibrary;
+void docgen(ArgResults argResults) {
+ _setCommandLineArguments(argResults);
- /// Current class being documented to be used for comment links.
- ClassMirror _currentClass;
+ linkResolver = (name) =>
+ fixReference(name, _currentLibrary, _currentClass, _currentMember);
- /// Current member being documented to be used for comment links.
- MemberMirror _currentMember;
-
- /// Resolves reference links in doc comments.
- markdown.Resolver linkResolver;
-
- /// Package directory of directory being analyzed.
- String packageDir;
-
- bool outputToYaml;
- bool outputToJson;
- bool includePrivate;
- /// State for whether or not the SDK libraries should also be outputted.
- bool includeSdk;
-
- /**
- * Docgen constructor initializes the link resolver for markdown parsing.
- * Also initializes the command line arguments.
- */
- Docgen(ArgResults argResults) {
- if (argResults['output-format'] == null) {
- outputToYaml =
- (argResults['yaml'] == false && argResults['json'] == false) ?
- true : argResults['yaml'];
- } else {
- if ((argResults['output-format'] == 'yaml' &&
- argResults['json'] == true) ||
- (argResults['output-format'] == 'json' &&
- argResults['yaml'] == true)) {
- throw new UnsupportedError('Cannot have contradictory output flags.');
- }
- outputToYaml = argResults['output-format'] == 'yaml' ? true : false;
+ getMirrorSystem(argResults.rest).then((MirrorSystem mirrorSystem) {
+ if (mirrorSystem.libraries.values.isEmpty) {
+ throw new StateError('No Library Mirrors.');
}
- outputToJson = !outputToYaml;
- includePrivate = argResults['include-private'];
- includeSdk = argResults['include-sdk'];
-
- this.linkResolver = (name) =>
- fixReference(name, _currentLibrary, _currentClass, _currentMember);
-
- analyze(argResults.rest);
- }
-
- List<String> listLibraries(List<String> args) {
- // TODO(janicejl): At the moment, only have support to have either one file,
- // or one directory. This is because there can only be one package directory
- // since only one docgen is created per run.
- if (args.length != 1) throw new UnsupportedError(usage);
- var libraries = new List<String>();
- var type = FileSystemEntity.typeSync(args[0]);
-
- if (type == FileSystemEntityType.FILE) {
- libraries.add(path.absolute(args[0]));
- logger.info('Added to libraries: ${libraries.last}');
- } else {
- libraries.addAll(listDartFromDir(args[0]));
- }
- logger.info('Package Directory: $packageDir');
- return libraries;
- }
+ _documentLibraries(mirrorSystem.libraries.values);
+ });
+}
- List<String> listDartFromDir(String args) {
- var files = listDir(args, recursive: true);
- packageDir = files.firstWhere((f) =>
- f.endsWith('/pubspec.yaml'), orElse: () => '');
- if (packageDir != '') packageDir = path.dirname(packageDir) + '/packages';
- return files.where((f) =>
- f.endsWith('.dart') && !f.contains('/packages')).toList()
- ..forEach((lib) => logger.info('Added to libraries: $lib'));
+void _setCommandLineArguments(ArgResults argResults) {
+ outputToYaml = argResults['yaml'] || argResults['output-format'] == 'yaml';
+ outputToJson = argResults['json'] || argResults['output-format'] == 'json';
+ if (outputToYaml && outputToJson) {
+ throw new ArgumentError('Cannot have contradictory output flags.');
}
+ outputToYaml = outputToYaml || !outputToJson;
+ includePrivate = argResults['include-private'];
+ parseSdk = argResults['parse-sdk'];
+ includeSdk = parseSdk || argResults['include-sdk'];
+}
- /**
- * Analyzes set of libraries by getting a mirror system and triggers the
- * documentation of the libraries.
- */
- void analyze(List<String> args) {
- var libraries = listLibraries(args);
- if (libraries.isEmpty) throw new StateError('No Libraries.');
- // DART_SDK should be set to the root of the SDK library.
- var sdkRoot = Platform.environment['DART_SDK'];
- if (sdkRoot != null) {
- logger.info('Using DART_SDK to find SDK at $sdkRoot');
- } else {
- // If DART_SDK is not defined in the environment,
- // assuming the dart executable is from the Dart SDK folder inside bin.
- sdkRoot = path.dirname(path.dirname(new Options().executable));
- logger.info('SDK Root: ${sdkRoot}');
- }
-
- getMirrorSystem(libraries, sdkRoot, packageRoot: packageDir)
- .then((MirrorSystem mirrorSystem) {
- if (mirrorSystem.libraries.values.isEmpty) {
- throw new UnsupportedError('No Library Mirrors.');
- }
- this.libraries = mirrorSystem.libraries.values;
- documentLibraries();
- });
- }
+List<String> _listLibraries(List<String> args) {
+ // TODO(janicejl): At the moment, only have support to have either one file,
+ // or one directory. This is because there can only be one package directory
+ // since only one docgen is created per run.
+ if (args.length != 1) throw new UnsupportedError(USAGE);
+ var libraries = new List<String>();
+ var type = FileSystemEntity.typeSync(args[0]);
- /**
- * Analyzes set of libraries and provides a mirror system which can be used
- * for static inspection of the source code.
- */
- Future<MirrorSystem> getMirrorSystem(List<String> libraries,
- String libraryRoot, {String packageRoot}) {
- SourceFileProvider provider = new SourceFileProvider();
- api.DiagnosticHandler diagnosticHandler =
- new FormattingDiagnosticHandler(provider).diagnosticHandler;
- Uri libraryUri = currentDirectory.resolve(appendSlash('$libraryRoot'));
- Uri packageUri = null;
- if (packageRoot != null) {
- packageUri = currentDirectory.resolve(appendSlash('$packageRoot'));
- }
- List<Uri> librariesUri = <Uri>[];
- libraries.forEach((library) {
- librariesUri.add(currentDirectory.resolve(library));
- });
- return dart2js.analyze(librariesUri, libraryUri, packageUri,
- provider.readStringFromUri, diagnosticHandler,
- ['--preserve-comments', '--categories=Client,Server']);
- }
-
- /**
- * Creates documentation for filtered libraries.
- */
- void documentLibraries() {
- _libraries.forEach((library) {
- // Files belonging to the SDK have a uri that begins with 'dart:'.
- if (includeSdk || !library.uri.toString().startsWith('dart:')) {
- _currentLibrary = library;
- var result = new Library(library.qualifiedName, _getComment(library),
- _getVariables(library.variables), _getMethods(library.functions),
- _getClasses(library.classes));
- if (outputToJson) {
- _writeToFile(stringify(result.toMap()), '${result.name}.json');
- }
- if (outputToYaml) {
- _writeToFile(getYamlString(result.toMap()), '${result.name}.yaml');
- }
- }
- });
- }
-
- /// Saves list of libraries for Docgen object.
- void set libraries(value){
- _libraries = value;
- }
-
- /**
- * Returns any documentation comments associated with a mirror with
- * simple markdown converted to html.
- */
- String _getComment(DeclarationMirror mirror) {
- String commentText;
- mirror.metadata.forEach((metadata) {
- if (metadata is CommentInstanceMirror) {
- CommentInstanceMirror comment = metadata;
- if (comment.isDocComment) {
- if (commentText == null) {
- commentText = comment.trimmedText;
- } else {
- commentText = '$commentText ${comment.trimmedText}';
- }
- }
- }
- });
- commentText = commentText == null ? '' :
- markdown.markdownToHtml(commentText.trim(), linkResolver: linkResolver)
- .replaceAll('\n', '');
- return commentText;
- }
-
- /**
- * Converts all [_] references in comments to <code>_</code>.
- */
- // TODO(tmandel): Create proper links for [_] style markdown based
- // on scope once layout of viewer is finished.
- markdown.Node fixReference(String name, LibraryMirror currentLibrary,
- ClassMirror currentClass, MemberMirror currentMember) {
- return new markdown.Element.text('code', name);
- }
-
- /**
- * Returns a map of [Variable] objects constructed from inputted mirrors.
- */
- Map<String, Variable> _getVariables(Map<String, VariableMirror> mirrorMap) {
- var data = {};
- mirrorMap.forEach((String mirrorName, VariableMirror mirror) {
- if (includePrivate || !mirror.isPrivate) {
- _currentMember = mirror;
- data[mirrorName] = new Variable(mirrorName, mirror.qualifiedName,
- mirror.isFinal, mirror.isStatic, mirror.type.qualifiedName,
- _getComment(mirror));
- }
- });
- return data;
- }
-
- /**
- * Returns a map of [Method] objects constructed from inputted mirrors.
- */
- Map<String, Method> _getMethods(Map<String, MethodMirror> mirrorMap) {
- var data = {};
- mirrorMap.forEach((String mirrorName, MethodMirror mirror) {
- if (includePrivate || !mirror.isPrivate) {
- _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));
- }
- });
- return data;
+ if (type == FileSystemEntityType.FILE) {
+ libraries.add(path.absolute(args[0]));
+ logger.info('Added to libraries: ${libraries.last}');
+ } else {
+ libraries.addAll(_listDartFromDir(args[0]));
}
-
- /**
- * Returns a map of [Class] objects constructed from inputted mirrors.
- */
- Map<String, Class> _getClasses(Map<String, ClassMirror> mirrorMap) {
- var data = {};
- mirrorMap.forEach((String mirrorName, ClassMirror mirror) {
- if (includePrivate || !mirror.isPrivate) {
- _currentClass = mirror;
- var superclass = (mirror.superclass != null) ?
- 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(),
- _getVariables(mirror.variables), _getMethods(mirror.methods));
- }
- });
- return data;
+ logger.info('Package Directory: $packageDir');
+ return libraries;
+}
+
+List<String> _listDartFromDir(String args) {
+ var files = listDir(args, recursive: true);
+ packageDir = files.firstWhere((f) =>
+ f.endsWith('/pubspec.yaml'), orElse: () => '');
+ if (packageDir != '') packageDir = path.dirname(packageDir) + '/packages';
+ return files.where((f) =>
+ f.endsWith('.dart') && !f.contains('/packages')).toList()
+ ..forEach((lib) => logger.info('Added to libraries: $lib'));
+}
+
+List<String> _listSdk() {
+ var sdk = new List<String>();
+ LIBRARIES.forEach((String name, LibraryInfo info) {
+ if (info.documented) {
+ sdk.add('dart:$name');
+ logger.info('Add to SDK: ${sdk.last}');
+ }
+ });
+ return sdk;
+}
+
+/**
+ * Analyzes set of libraries by getting a mirror system and triggers the
+ * documentation of the libraries.
+ */
+Future<MirrorSystem> getMirrorSystem(List<String> args) {
+ var libraries = !parseSdk ? _listLibraries(args) : _listSdk();
+ if (libraries.isEmpty) throw new StateError('No Libraries.');
+ // DART_SDK should be set to the root of the SDK library.
+ var sdkRoot = Platform.environment['DART_SDK'];
+ if (sdkRoot != null) {
+ logger.info('Using DART_SDK to find SDK at $sdkRoot');
+ } else {
+ // If DART_SDK is not defined in the environment,
+ // assuming the dart executable is from the Dart SDK folder inside bin.
+ sdkRoot = path.dirname(path.dirname(new Options().executable));
+ logger.info('SDK Root: ${sdkRoot}');
}
- /**
- * Returns a map of [Parameter] objects constructed from inputted mirrors.
- */
- Map<String, Parameter> _getParameters(List<ParameterMirror> mirrorList) {
- var data = {};
- mirrorList.forEach((ParameterMirror mirror) {
+ return _getMirrorSystemHelper(libraries, sdkRoot, packageRoot: packageDir);
+}
+
+/**
+ * Analyzes set of libraries and provides a mirror system which can be used
+ * for static inspection of the source code.
+ */
+Future<MirrorSystem> _getMirrorSystemHelper(List<String> libraries,
+ String libraryRoot, {String packageRoot}) {
+ SourceFileProvider provider = new SourceFileProvider();
+ api.DiagnosticHandler diagnosticHandler =
+ new FormattingDiagnosticHandler(provider).diagnosticHandler;
+ Uri libraryUri = currentDirectory.resolve(appendSlash('$libraryRoot'));
+ Uri packageUri = null;
+ if (packageRoot != null) {
+ packageUri = currentDirectory.resolve(appendSlash('$packageRoot'));
+ }
+ List<Uri> librariesUri = <Uri>[];
+ libraries.forEach((library) {
+ librariesUri.add(currentDirectory.resolve(library));
+ });
+ return dart2js.analyze(librariesUri, libraryUri, packageUri,
+ provider.readStringFromUri, diagnosticHandler,
+ ['--preserve-comments', '--categories=Client,Server']);
+}
+
+/**
+ * Creates documentation for filtered libraries.
+ */
+void _documentLibraries(List<LibraryMirror> libraries) {
+ libraries.forEach((lib) {
+ // Files belonging to the SDK have a uri that begins with 'dart:'.
+ if (includeSdk || !lib.uri.toString().startsWith('dart:')) {
+ var library = generateLibrary(lib);
+ _outputLibrary(library);
+ }
+ });
+ // Outputs a text file with a list of files available after creating all
+ // the libraries. This will help the viewer know what files are available
+ // to read in.
+ _writeToFile(listDir("docs").join('\n'), 'library_list.txt');
+}
+
+Library generateLibrary(dart2js.Dart2JsLibraryMirror library) {
+ _currentLibrary = library;
+ var result = new Library(library.qualifiedName, _getComment(library),
+ _getVariables(library.variables), _getMethods(library.functions),
+ _getClasses(library.classes));
+ logger.fine('Generated library for ${result.name}');
+ return result;
+}
+
+void _outputLibrary(Library result) {
+ if (outputToJson) {
+ _writeToFile(stringify(result.toMap()), '${result.name}.json');
+ }
+ if (outputToYaml) {
+ _writeToFile(getYamlString(result.toMap()), '${result.name}.yaml');
+ }
+}
+
+/**
+ * Returns a list of meta annotations assocated with a mirror.
+ */
+List<String> _getAnnotations(DeclarationMirror mirror) {
+ var annotations = mirror.metadata.where((e) =>
+ e is dart2js.Dart2JsConstructedConstantMirror);
+ return annotations.map((e) => e.type.qualifiedName).toList();
+}
+
+/**
+ * Returns any documentation comments associated with a mirror with
+ * simple markdown converted to html.
+ */
+String _getComment(DeclarationMirror mirror) {
+ String commentText;
+ mirror.metadata.forEach((metadata) {
+ if (metadata is CommentInstanceMirror) {
+ CommentInstanceMirror comment = metadata;
+ if (comment.isDocComment) {
+ if (commentText == null) {
+ commentText = comment.trimmedText;
+ } else {
+ commentText = '$commentText ${comment.trimmedText}';
+ }
+ }
+ }
+ });
+ commentText = commentText == null ? '' :
+ markdown.markdownToHtml(commentText.trim(), linkResolver: linkResolver)
+ .replaceAll('\n', ' ');
+ return commentText;
+}
+
+/**
+ * Converts all [_] references in comments to <code>_</code>.
+ */
+// TODO(tmandel): Create proper links for [_] style markdown based
+// on scope once layout of viewer is finished.
+markdown.Node fixReference(String name, LibraryMirror currentLibrary,
+ ClassMirror currentClass, MemberMirror currentMember) {
+ return new markdown.Element.text('code', name);
+}
+
+/**
+ * Returns a map of [Variable] objects constructed from inputted mirrors.
+ */
+Map<String, Variable> _getVariables(Map<String, VariableMirror> mirrorMap) {
+ var data = {};
+ mirrorMap.forEach((String mirrorName, VariableMirror mirror) {
+ if (includePrivate || !mirror.isPrivate) {
_currentMember = mirror;
- data[mirror.simpleName] = new Parameter(mirror.simpleName,
- mirror.qualifiedName, mirror.isOptional, mirror.isNamed,
- mirror.hasDefaultValue, mirror.type.qualifiedName,
- mirror.defaultValue);
- });
- return data;
+ data[mirrorName] = new Variable(mirrorName, mirror.qualifiedName,
+ mirror.isFinal, mirror.isStatic, mirror.type.qualifiedName,
+ _getComment(mirror), _getAnnotations(mirror));
+ }
+ });
+ return data;
+}
+
+/**
+ * Returns a map of [Method] objects constructed from inputted mirrors.
+ */
+Map<String, Method> _getMethods(Map<String, MethodMirror> mirrorMap) {
+ var data = {};
+ mirrorMap.forEach((String mirrorName, MethodMirror mirror) {
+ if (includePrivate || !mirror.isPrivate) {
+ _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));
+ }
+ });
+ return data;
+}
+
+/**
+ * Returns a map of [Class] objects constructed from inputted mirrors.
+ */
+Map<String, Class> _getClasses(Map<String, ClassMirror> mirrorMap) {
+ var data = {};
+ mirrorMap.forEach((String mirrorName, ClassMirror mirror) {
+ if (includePrivate || !mirror.isPrivate) {
+ _currentClass = mirror;
+ var superclass = (mirror.superclass != null) ?
+ 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(),
+ _getVariables(mirror.variables), _getMethods(mirror.methods),
+ _getAnnotations(mirror));
+ }
+ });
+ return data;
+}
+
+/**
+ * Returns a map of [Parameter] objects constructed from inputted mirrors.
+ */
+Map<String, Parameter> _getParameters(List<ParameterMirror> mirrorList) {
+ var data = {};
+ mirrorList.forEach((ParameterMirror mirror) {
+ _currentMember = mirror;
+ data[mirror.simpleName] = new Parameter(mirror.simpleName,
+ mirror.qualifiedName, mirror.isOptional, mirror.isNamed,
+ mirror.hasDefaultValue, mirror.type.qualifiedName,
+ mirror.defaultValue, _getAnnotations(mirror));
+ });
+ return data;
+}
+
+/**
+ * Writes text to a file in the 'docs' directory.
+ */
+void _writeToFile(String text, String filename) {
+ Directory dir = new Directory('docs');
+ if (!dir.existsSync()) {
+ dir.createSync();
}
+ File file = new File('docs/$filename');
+ if (!file.existsSync()) {
+ file.createSync();
+ }
+ file.openSync();
+ file.writeAsString(text);
}
/**
@@ -372,9 +408,13 @@
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);
+ Class(this.name, this.qualifiedName, 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() {
@@ -388,6 +428,7 @@
classMap['implements'] = new List.from(interfaces);
classMap['variables'] = recurseMap(variables);
classMap['methods'] = recurseMap(methods);
+ classMap['annotations'] = new List.from(annotations);
return classMap;
}
}
@@ -405,9 +446,12 @@
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.type, this.comment, this.annotations);
/// Generates a map describing the [Variable] object.
Map toMap() {
@@ -418,6 +462,7 @@
variableMap['final'] = isFinal.toString();
variableMap['static'] = isStatic.toString();
variableMap['type'] = type;
+ variableMap['annotations'] = new List.from(annotations);
return variableMap;
}
}
@@ -442,9 +487,12 @@
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.comment, this.parameters, this.annotations);
/// Generates a map describing the [Method] object.
Map toMap() {
@@ -457,6 +505,7 @@
methodMap['static'] = isStatic.toString();
methodMap['return'] = returnType;
methodMap['parameters'] = recurseMap(parameters);
+ methodMap['annotations'] = new List.from(annotations);
return methodMap;
}
}
@@ -474,8 +523,11 @@
String type;
String defaultValue;
- Parameter(this.name, this.qualifiedName, this.isOptional, this.isNamed, this.hasDefaultValue,
- this.type, this.defaultValue);
+ /// 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);
/// Generates a map describing the [Parameter] object.
Map toMap() {
@@ -487,22 +539,7 @@
parameterMap['default'] = hasDefaultValue.toString();
parameterMap['type'] = type;
parameterMap['value'] = defaultValue;
+ parameterMap['annotations'] = new List.from(annotations);
return parameterMap;
}
}
-
-/**
- * Writes text to a file in the 'docs' directory.
- */
-void _writeToFile(String text, String filename) {
- Directory dir = new Directory('docs');
- if (!dir.existsSync()) {
- dir.createSync();
- }
- File file = new File('docs/$filename');
- if (!file.existsSync()) {
- file.createSync();
- }
- file.openSync();
- file.writeAsString(text);
-}
\ No newline at end of file
diff --git a/pkg/http_server/lib/src/virtual_directory.dart b/pkg/http_server/lib/src/virtual_directory.dart
index 6ce667b..bb3b7ac 100644
--- a/pkg/http_server/lib/src/virtual_directory.dart
+++ b/pkg/http_server/lib/src/virtual_directory.dart
@@ -46,6 +46,13 @@
void serveRequest(HttpRequest request);
/**
+ * Set the [callback] to override the default directory listing. The
+ * [callback] will be called with the [Directory] to be listed and the
+ * [HttpRequest].
+ */
+ void setDirectoryHandler(void callback(Directory dir, HttpRequest request));
+
+ /**
* Set the [callback] to override the error page handler. When [callback] is
* invoked, the `statusCode` property of the response is set.
*/
@@ -59,6 +66,7 @@
bool followLinks = true;
Function _errorCallback;
+ Function _dirCallback;
_VirtualDirectory(this.root);
@@ -81,12 +89,18 @@
}
if (entity is File) {
_serveFile(entity, request);
+ } else if (entity is Directory) {
+ _serveDirectory(entity, request);
} else {
_serveErrorPage(HttpStatus.NOT_FOUND, request);
}
});
}
+ void setDirectoryHandler(void callback(Directory dir, HttpRequest request)) {
+ _dirCallback = callback;
+ }
+
void setErrorPageHandler(void callback(HttpRequest request)) {
_errorCallback = callback;
}
@@ -118,10 +132,13 @@
.then((target) {
var targetPath = new Path(target).canonicalize();
if (targetPath.isAbsolute) return null;
- targetPath = path.directoryPath.join(targetPath)
- .canonicalize();
+ targetPath =
+ path.directoryPath.join(targetPath).canonicalize();
if (targetPath.segments().isEmpty ||
targetPath.segments().first == '..') return null;
+ if (segments.isEmpty) {
+ return _locateResource(targetPath, []);
+ }
return _locateResource(targetPath.append(segments.first),
segments.skip(1));
});
@@ -197,6 +214,86 @@
});
}
+ void _serveDirectory(Directory dir, HttpRequest request) {
+ if (_dirCallback != null) {
+ _dirCallback(dir, request);
+ return;
+ }
+ var response = request.response;
+ dir.stat().then((stats) {
+ if (request.headers.ifModifiedSince != null &&
+ !stats.modified.isAfter(request.headers.ifModifiedSince)) {
+ response.statusCode = HttpStatus.NOT_MODIFIED;
+ response.close();
+ return;
+ }
+
+ response.headers.set(HttpHeaders.LAST_MODIFIED, stats.modified);
+ var path = request.uri.path;
+ var header =
+'''<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<title>Index of $path</title>
+</head>
+<body>
+<h1>Index of $path</h1>
+<table>
+ <tr>
+ <td>Name</td>
+ <td>Last modified</td>
+ <td>Size</td>
+ </tr>
+''';
+ var server = response.headers.value(HttpHeaders.SERVER);
+ if (server == null) server = "";
+ var footer =
+'''</table>
+$server
+</body>
+</html>
+''';
+
+ response.write(header);
+
+ void add(String name, String modified, var size) {
+ if (size == null) size = "-";
+ if (modified == null) modified = "";
+ var p = new Path(path).append(name).canonicalize().toString();
+ var entry =
+''' <tr>
+ <td><a href="$p">$name</a></td>
+ <td>$modified</td>
+ <td style="text-align: right">$size</td>
+ </tr>''';
+ response.write(entry);
+ }
+
+ if (path != '/') {
+ add('../', null, null);
+ }
+
+ dir.list(followLinks: true).listen((entity) {
+ // TODO(ajohnsen): Consider async dir listing.
+ if (entity is File) {
+ var stat = entity.statSync();
+ add(new Path(entity.path).filename,
+ stat.modified.toString(),
+ stat.size);
+ } else if (entity is Directory) {
+ add(new Path(entity.path).filename + '/',
+ entity.statSync().modified.toString(),
+ null);
+ }
+ }, onError: (e) {
+ }, onDone: () {
+ response.write(footer);
+ response.close();
+ });
+ }, onError: (e) => response.close());
+ }
+
void _serveErrorPage(int error, HttpRequest request) {
var response = request.response;
response.statusCode = error;
@@ -207,22 +304,22 @@
// Default error page.
var path = request.uri.path;
var reason = response.reasonPhrase;
- response.write(
- '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"\n');
- response.writeln(
- '"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">');
- response.writeln('<html xmlns="http://www.w3.org/1999/xhtml">');
- response.writeln('<head>');
- response.writeln('<title>$reason: $path</title>');
- response.writeln('</head>');
- response.writeln('<body>');
- response.writeln('<h1>Error $error at \'$path\': $reason</h1>');
+
var server = response.headers.value(HttpHeaders.SERVER);
- if (server != null) {
- response.writeln(server);
- }
- response.writeln('</body>');
- response.writeln('</html>');
+ if (server == null) server = "";
+ var page =
+'''<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<title>$reason: $path</title>
+</head>
+<body>
+<h1>Error $error at \'$path\': $reason</h1>
+$server
+</body>
+</html>''';
+ response.write(page);
response.close();
}
}
diff --git a/pkg/http_server/test/virtual_directory_test.dart b/pkg/http_server/test/virtual_directory_test.dart
index 1c579da..ca70948 100644
--- a/pkg/http_server/test/virtual_directory_test.dart
+++ b/pkg/http_server/test/virtual_directory_test.dart
@@ -115,6 +115,119 @@
});
});
+ group('serve-dir', () {
+ group('top-level', () {
+ test('simple', () {
+ expect(HttpServer.bind('localhost', 0).then((server) {
+ var dir = new Directory('').createTempSync();
+ var virDir = new VirtualDirectory(dir.path);
+ virDir.allowDirectoryListing = true;
+
+ virDir.serve(server);
+
+ return getAsString(server.port, '/')
+ .whenComplete(() {
+ server.close();
+ dir.deleteSync();
+ });
+ }), completion(contains('Index of /')));
+ });
+
+ test('files', () {
+ expect(HttpServer.bind('localhost', 0).then((server) {
+ var dir = new Directory('').createTempSync();
+ var virDir = new VirtualDirectory(dir.path);
+ for (int i = 0; i < 10; i++) {
+ new File('${dir.path}/$i').createSync();
+ }
+ virDir.allowDirectoryListing = true;
+
+ virDir.serve(server);
+
+ return getAsString(server.port, '/')
+ .whenComplete(() {
+ server.close();
+ dir.deleteSync(recursive: true);
+ });
+ }), completion(contains('Index of /')));
+ });
+
+ test('dirs', () {
+ expect(HttpServer.bind('localhost', 0).then((server) {
+ var dir = new Directory('').createTempSync();
+ var virDir = new VirtualDirectory(dir.path);
+ for (int i = 0; i < 10; i++) {
+ new Directory('${dir.path}/$i').createSync();
+ }
+ virDir.allowDirectoryListing = true;
+
+ virDir.serve(server);
+
+ return getAsString(server.port, '/')
+ .whenComplete(() {
+ server.close();
+ dir.deleteSync(recursive: true);
+ });
+ }), completion(contains('Index of /')));
+ });
+
+ if (!Platform.isWindows) {
+ test('recursive-link', () {
+ expect(HttpServer.bind('localhost', 0).then((server) {
+ var dir = new Directory('').createTempSync();
+ var link = new Link('${dir.path}/recursive')..createSync('.');
+ var virDir = new VirtualDirectory(dir.path);
+ virDir.allowDirectoryListing = true;
+
+ virDir.serve(server);
+
+ return Future.wait([
+ getAsString(server.port, '/').then(
+ (s) => s.contains('recursive/')),
+ getAsString(server.port, '/').then(
+ (s) => !s.contains('../')),
+ getAsString(server.port, '/').then(
+ (s) => s.contains('Index of /')),
+ getAsString(server.port, '/recursive').then(
+ (s) => s.contains('recursive/')),
+ getAsString(server.port, '/recursive').then(
+ (s) => s.contains('../')),
+ getAsString(server.port, '/recursive').then(
+ (s) => s.contains('Index of /recursive'))])
+ .whenComplete(() {
+ server.close();
+ dir.deleteSync(recursive: true);
+ });
+ }), completion(equals([true, true, true, true, true, true])));
+ });
+ }
+ });
+
+ group('custom', () {
+ test('simple', () {
+ expect(HttpServer.bind('localhost', 0).then((server) {
+ var dir = new Directory('').createTempSync();
+ var virDir = new VirtualDirectory(dir.path);
+ virDir.allowDirectoryListing = true;
+ virDir.setDirectoryHandler((dir2, request) {
+ expect(dir2, isNotNull);
+ expect(FileSystemEntity.identicalSync(dir.path, dir2.path), isTrue);
+ request.response.write('My handler ${request.uri.path}');
+ request.response.close();
+ });
+
+ virDir.serve(server);
+
+ return getAsString(server.port, '/')
+ .whenComplete(() {
+ server.close();
+ dir.deleteSync();
+ });
+ }), completion(contains('My handler /')));
+ });
+ });
+ });
+
group('links', () {
if (!Platform.isWindows) {
group('follow-links', () {
diff --git a/pkg/mdv/lib/mdv.dart b/pkg/mdv/lib/mdv.dart
new file mode 100644
index 0000000..29a4a0b
--- /dev/null
+++ b/pkg/mdv/lib/mdv.dart
@@ -0,0 +1,103 @@
+// 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.
+
+// TODO(jmesserly): more commentary here.
+/**
+ * This library provides access to Model-Driven-Views APIs on HTML elements.
+ * More information can be found at: <https://github.com/toolkitchen/mdv>.
+ */
+library mdv;
+
+import 'dart:async';
+import 'dart:collection';
+import 'dart:html';
+import 'dart:math' as math;
+import 'package:observe/observe.dart';
+
+// TODO(jmesserly): get this from somewhere else. See http://dartbug.com/4161.
+import 'package:serialization/src/serialization_helpers.dart' show IdentityMap;
+
+part 'src/bindings.dart';
+part 'src/element.dart';
+part 'src/input_element.dart';
+part 'src/node.dart';
+part 'src/template.dart';
+part 'src/text.dart';
+
+/** Initialize the Model-Driven Views polyfill. */
+void initialize() {
+ TemplateElement.mdvPackage = _mdv;
+}
+
+StreamController<DocumentFragment> _instanceCreated;
+
+/**
+ * *Warning*: This is an implementation helper for Model-Driven Views and
+ * should not be used in your code.
+ *
+ * This event is fired whenever a template is instantiated via
+ * [Element.createInstance].
+ */
+// TODO(rafaelw): This is a hack, and is neccesary for the polyfill
+// because custom elements are not upgraded during clone()
+Stream<DocumentFragment> get instanceCreated {
+ if (_instanceCreated == null) {
+ _instanceCreated =
+ new StreamController<DocumentFragment>(sync: true);
+ }
+ return _instanceCreated.stream;
+}
+
+/**
+ * Binds all mustaches recursively starting from the [root] node.
+ *
+ * Note: this is not an official Model-Driven-Views API; it is intended to
+ * support binding the [ShadowRoot]'s content to a model.
+ */
+// TODO(jmesserly): this is needed to avoid two <template> nodes when using
+// bindings in a custom element's template. See also:
+// https://github.com/polymer-project/polymer/blob/master/src/bindMDV.js#L68
+// Called from:
+// https://github.com/polymer-project/polymer/blob/master/src/register.js#L99
+void bindModel(Node root, model, [CustomBindingSyntax syntax]) {
+ _Bindings._addBindings(root, model, syntax);
+}
+
+
+// TODO(jmesserly): investigate if expandos give us enough performance.
+
+// The expando for storing our MDV wrappers.
+//
+// In general, we need state associated with the nodes. Rather than having a
+// bunch of individual expandos, we keep one per node.
+//
+// Aside from the potentially helping performance, it also keeps things simpler
+// if we decide to integrate MDV into the DOM later, and means less code needs
+// to worry about expandos.
+final Expando _mdvExpando = new Expando('mdv');
+
+_mdv(node) {
+ var wrapper = _mdvExpando[node];
+ if (wrapper != null) return wrapper;
+
+ if (node is InputElement) {
+ wrapper = new _InputElementExtension(node);
+ } else if (node is Element) {
+ if (node.isTemplate) {
+ wrapper = new _TemplateExtension(node);
+ } else {
+ wrapper = new _ElementExtension(node);
+ }
+ } else if (node is Text) {
+ wrapper = new _TextExtension(node);
+ } else if (node is Node) {
+ wrapper = new _NodeExtension(node);
+ } else {
+ // TODO(jmesserly): this happens for things like CompoundBinding.
+ wrapper = node;
+ }
+
+ _mdvExpando[node] = wrapper;
+ return wrapper;
+}
diff --git a/pkg/mdv/lib/src/bindings.dart b/pkg/mdv/lib/src/bindings.dart
new file mode 100644
index 0000000..2b40671
--- /dev/null
+++ b/pkg/mdv/lib/src/bindings.dart
@@ -0,0 +1,513 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of mdv;
+
+// This code is a port of Model-Driven-Views:
+// https://github.com/polymer-project/mdv
+// The code mostly comes from src/template_element.js
+
+typedef void _ChangeHandler(value);
+
+abstract class _InputBinding {
+ final InputElement element;
+ PathObserver binding;
+ StreamSubscription _pathSub;
+ StreamSubscription _eventSub;
+
+ _InputBinding(this.element, model, String path) {
+ binding = new PathObserver(model, path);
+ _pathSub = binding.bindSync(valueChanged);
+ _eventSub = _getStreamForInputType(element).listen(updateBinding);
+ }
+
+ void valueChanged(newValue);
+
+ void updateBinding(e);
+
+ void unbind() {
+ binding = null;
+ _pathSub.cancel();
+ _eventSub.cancel();
+ }
+
+ static EventStreamProvider<Event> _checkboxEventType = () {
+ // Attempt to feature-detect which event (change or click) is fired first
+ // for checkboxes.
+ var div = new DivElement();
+ var checkbox = div.append(new InputElement());
+ checkbox.type = 'checkbox';
+ var fired = [];
+ checkbox.onClick.listen((e) {
+ fired.add(Element.clickEvent);
+ });
+ checkbox.onChange.listen((e) {
+ fired.add(Element.changeEvent);
+ });
+ checkbox.dispatchEvent(new MouseEvent('click', view: window));
+ // WebKit/Blink don't fire the change event if the element is outside the
+ // document, so assume 'change' for that case.
+ return fired.length == 1 ? Element.changeEvent : fired.first;
+ }();
+
+ static Stream<Event> _getStreamForInputType(InputElement element) {
+ switch (element.type) {
+ case 'checkbox':
+ return _checkboxEventType.forTarget(element);
+ case 'radio':
+ case 'select-multiple':
+ case 'select-one':
+ return element.onChange;
+ default:
+ return element.onInput;
+ }
+ }
+}
+
+class _ValueBinding extends _InputBinding {
+ _ValueBinding(element, model, path) : super(element, model, path);
+
+ void valueChanged(value) {
+ element.value = value == null ? '' : '$value';
+ }
+
+ void updateBinding(e) {
+ binding.value = element.value;
+ }
+}
+
+class _CheckedBinding extends _InputBinding {
+ _CheckedBinding(element, model, path) : super(element, model, path);
+
+ void valueChanged(value) {
+ element.checked = _Bindings._toBoolean(value);
+ }
+
+ void updateBinding(e) {
+ binding.value = element.checked;
+
+ // Only the radio button that is getting checked gets an event. We
+ // therefore find all the associated radio buttons and update their
+ // CheckedBinding manually.
+ if (element is InputElement && element.type == 'radio') {
+ for (var r in _getAssociatedRadioButtons(element)) {
+ var checkedBinding = _mdv(r)._checkedBinding;
+ if (checkedBinding != null) {
+ // Set the value directly to avoid an infinite call stack.
+ checkedBinding.binding.value = false;
+ }
+ }
+ }
+ }
+
+ // |element| is assumed to be an HTMLInputElement with |type| == 'radio'.
+ // Returns an array containing all radio buttons other than |element| that
+ // have the same |name|, either in the form that |element| belongs to or,
+ // if no form, in the document tree to which |element| belongs.
+ //
+ // This implementation is based upon the HTML spec definition of a
+ // "radio button group":
+ // http://www.whatwg.org/specs/web-apps/current-work/multipage/number-state.html#radio-button-group
+ //
+ static Iterable _getAssociatedRadioButtons(element) {
+ if (!_isNodeInDocument(element)) return [];
+ if (element.form != null) {
+ return element.form.nodes.where((el) {
+ return el != element &&
+ el is InputElement &&
+ el.type == 'radio' &&
+ el.name == element.name;
+ });
+ } else {
+ var radios = element.document.queryAll(
+ 'input[type="radio"][name="${element.name}"]');
+ return radios.where((el) => el != element && el.form == null);
+ }
+ }
+
+ // TODO(jmesserly): polyfill document.contains API instead of doing it here
+ static bool _isNodeInDocument(Node node) {
+ // On non-IE this works:
+ // return node.document.contains(node);
+ var document = node.document;
+ if (node == document || node.parentNode == document) return true;
+ return document.documentElement.contains(node);
+ }
+}
+
+class _Bindings {
+ // TODO(jmesserly): not sure what kind of boolean conversion rules to
+ // apply for template data-binding. HTML attributes are true if they're
+ // present. However Dart only treats "true" as true. Since this is HTML we'll
+ // use something closer to the HTML rules: null (missing) and false are false,
+ // everything else is true. See: https://github.com/polymer-project/mdv/issues/59
+ static bool _toBoolean(value) => null != value && false != value;
+
+ static Node _createDeepCloneAndDecorateTemplates(Node node, String syntax) {
+ var clone = node.clone(false); // Shallow clone.
+ if (clone is Element && clone.isTemplate) {
+ TemplateElement.decorate(clone, node);
+ if (syntax != null) {
+ clone.attributes.putIfAbsent('syntax', () => syntax);
+ }
+ }
+
+ for (var c = node.firstChild; c != null; c = c.nextNode) {
+ clone.append(_createDeepCloneAndDecorateTemplates(c, syntax));
+ }
+ return clone;
+ }
+
+ static void _addBindings(Node node, model, [CustomBindingSyntax syntax]) {
+ if (node is Element) {
+ _addAttributeBindings(node, model, syntax);
+ } else if (node is Text) {
+ _parseAndBind(node, 'text', node.text, model, syntax);
+ }
+
+ for (var c = node.firstChild; c != null; c = c.nextNode) {
+ _addBindings(c, model, syntax);
+ }
+ }
+
+ static void _addAttributeBindings(Element element, model, syntax) {
+ element.attributes.forEach((name, value) {
+ if (value == '' && (name == 'bind' || name == 'repeat')) {
+ value = '{{}}';
+ }
+ _parseAndBind(element, name, value, model, syntax);
+ });
+ }
+
+ static void _parseAndBind(Node node, String name, String text, model,
+ CustomBindingSyntax syntax) {
+
+ var tokens = _parseMustacheTokens(text);
+ if (tokens.length == 0 || (tokens.length == 1 && tokens[0].isText)) {
+ return;
+ }
+
+ // If this is a custom element, give the .xtag a change to bind.
+ node = _nodeOrCustom(node);
+
+ if (tokens.length == 1 && tokens[0].isBinding) {
+ _bindOrDelegate(node, name, model, tokens[0].value, syntax);
+ return;
+ }
+
+ var replacementBinding = new CompoundBinding();
+ for (var i = 0; i < tokens.length; i++) {
+ var token = tokens[i];
+ if (token.isBinding) {
+ _bindOrDelegate(replacementBinding, i, model, token.value, syntax);
+ }
+ }
+
+ replacementBinding.combinator = (values) {
+ var newValue = new StringBuffer();
+
+ for (var i = 0; i < tokens.length; i++) {
+ var token = tokens[i];
+ if (token.isText) {
+ newValue.write(token.value);
+ } else {
+ var value = values[i];
+ if (value != null) {
+ newValue.write(value);
+ }
+ }
+ }
+
+ return newValue.toString();
+ };
+
+ node.bind(name, replacementBinding, 'value');
+ }
+
+ static void _bindOrDelegate(node, name, model, String path,
+ CustomBindingSyntax syntax) {
+
+ if (syntax != null) {
+ var delegateBinding = syntax.getBinding(model, path, name, node);
+ if (delegateBinding != null) {
+ model = delegateBinding;
+ path = 'value';
+ }
+ }
+
+ node.bind(name, model, path);
+ }
+
+ /**
+ * Gets the [node]'s custom [Element.xtag] if present, otherwise returns
+ * the node. This is used so nodes can override [Node.bind], [Node.unbind],
+ * and [Node.unbindAll] like InputElement does.
+ */
+ // TODO(jmesserly): remove this when we can extend Element for real.
+ static _nodeOrCustom(node) => node is Element ? node.xtag : node;
+
+ static List<_BindingToken> _parseMustacheTokens(String s) {
+ var result = [];
+ var length = s.length;
+ var index = 0, lastIndex = 0;
+ while (lastIndex < length) {
+ index = s.indexOf('{{', lastIndex);
+ if (index < 0) {
+ result.add(new _BindingToken(s.substring(lastIndex)));
+ break;
+ } else {
+ // There is a non-empty text run before the next path token.
+ if (index > 0 && lastIndex < index) {
+ result.add(new _BindingToken(s.substring(lastIndex, index)));
+ }
+ lastIndex = index + 2;
+ index = s.indexOf('}}', lastIndex);
+ if (index < 0) {
+ var text = s.substring(lastIndex - 2);
+ if (result.length > 0 && result.last.isText) {
+ result.last.value += text;
+ } else {
+ result.add(new _BindingToken(text));
+ }
+ break;
+ }
+
+ var value = s.substring(lastIndex, index).trim();
+ result.add(new _BindingToken(value, isBinding: true));
+ lastIndex = index + 2;
+ }
+ }
+ return result;
+ }
+
+ static void _addTemplateInstanceRecord(fragment, model) {
+ if (fragment.firstChild == null) {
+ return;
+ }
+
+ var instanceRecord = new TemplateInstance(
+ fragment.firstChild, fragment.lastChild, model);
+
+ var node = instanceRecord.firstNode;
+ while (node != null) {
+ _mdv(node)._templateInstance = instanceRecord;
+ node = node.nextNode;
+ }
+ }
+}
+
+class _BindingToken {
+ final String value;
+ final bool isBinding;
+
+ _BindingToken(this.value, {this.isBinding: false});
+
+ bool get isText => !isBinding;
+}
+
+class _TemplateIterator {
+ final Element _templateElement;
+ final List<Node> terminators = [];
+ final CompoundBinding inputs;
+ List iteratedValue;
+ Object _lastValue;
+
+ StreamSubscription _sub;
+ StreamSubscription _valueBinding;
+
+ _TemplateIterator(this._templateElement)
+ : inputs = new CompoundBinding(resolveInputs) {
+
+ _valueBinding = new PathObserver(inputs, 'value').bindSync(valueChanged);
+ }
+
+ static Object resolveInputs(Map values) {
+ if (values.containsKey('if') && !_Bindings._toBoolean(values['if'])) {
+ return null;
+ }
+
+ if (values.containsKey('repeat')) {
+ return values['repeat'];
+ }
+
+ if (values.containsKey('bind')) {
+ return [values['bind']];
+ }
+
+ return null;
+ }
+
+ void valueChanged(value) {
+ // TODO(jmesserly): should PathObserver do this for us?
+ var oldValue = _lastValue;
+ _lastValue = value;
+
+ if (value is! List) {
+ value = [];
+ }
+
+ unobserve();
+ iteratedValue = value;
+
+ if (value is Observable) {
+ _sub = value.changes.listen(_handleChanges);
+ }
+
+ int addedCount = iteratedValue.length;
+ var removedCount = oldValue is List ? (oldValue as List).length : 0;
+ if (addedCount == 0 && removedCount == 0) return; // nothing to do.
+
+ _handleChanges([new ListChangeRecord(0, addedCount: addedCount,
+ removedCount: removedCount)]);
+ }
+
+ Node getTerminatorAt(int index) {
+ if (index == -1) return _templateElement;
+ var terminator = terminators[index];
+ if (terminator is Element && (terminator as Element).isTemplate) {
+ var subIterator = _mdv(terminator)._templateIterator;
+ if (subIterator != null) {
+ return subIterator.getTerminatorAt(subIterator.terminators.length - 1);
+ }
+ }
+
+ return terminator;
+ }
+
+ void insertInstanceAt(int index, List<Node> instanceNodes) {
+ var previousTerminator = getTerminatorAt(index - 1);
+ var terminator = instanceNodes.length > 0 ? instanceNodes.last
+ : previousTerminator;
+
+ terminators.insert(index, terminator);
+
+ var parent = _templateElement.parentNode;
+ var insertBeforeNode = previousTerminator.nextNode;
+ for (var node in instanceNodes) {
+ parent.insertBefore(node, insertBeforeNode);
+ }
+ }
+
+ List<Node> extractInstanceAt(int index) {
+ var instanceNodes = <Node>[];
+ var previousTerminator = getTerminatorAt(index - 1);
+ var terminator = getTerminatorAt(index);
+ terminators.removeAt(index);
+
+ var parent = _templateElement.parentNode;
+ while (terminator != previousTerminator) {
+ var node = terminator;
+ terminator = node.previousNode;
+ node.remove();
+ instanceNodes.add(node);
+ }
+ return instanceNodes;
+ }
+
+ getInstanceModel(model, syntax) {
+ if (syntax != null) {
+ return syntax.getInstanceModel(_templateElement, model);
+ }
+ return model;
+ }
+
+ Node getInstanceFragment(syntax) {
+ if (syntax != null) {
+ return syntax.getInstanceFragment(_templateElement);
+ }
+ return _templateElement.createInstance();
+ }
+
+ List<Node> getInstanceNodes(model, syntax) {
+ // TODO(jmesserly): this line of code is jumping ahead of what MDV supports.
+ // It doesn't let the custom syntax override createInstance().
+ var fragment = getInstanceFragment(syntax);
+
+ _Bindings._addBindings(fragment, model, syntax);
+ _Bindings._addTemplateInstanceRecord(fragment, model);
+
+ var instanceNodes = fragment.nodes.toList();
+ fragment.nodes.clear();
+ return instanceNodes;
+ }
+
+ void _handleChanges(Iterable<ChangeRecord> splices) {
+ splices = splices.where((s) => s is ListChangeRecord);
+
+ var template = _templateElement;
+ var syntax = TemplateElement.syntax[template.attributes['syntax']];
+
+ if (template.parentNode == null || template.document.window == null) {
+ abandon();
+ // TODO(jmesserly): MDV calls templateIteratorTable.delete(this) here,
+ // but I think that's a no-op because only nodes are used as keys.
+ // See https://github.com/Polymer/mdv/pull/114.
+ return;
+ }
+
+ // TODO(jmesserly): IdentityMap matches JS semantics, but it's O(N) right
+ // now. See http://dartbug.com/4161.
+ var instanceCache = new IdentityMap();
+ var removeDelta = 0;
+ for (var splice in splices) {
+ for (int i = 0; i < splice.removedCount; i++) {
+ var instanceNodes = extractInstanceAt(splice.index + removeDelta);
+ var model = _mdv(instanceNodes.first)._templateInstance.model;
+ instanceCache[model] = instanceNodes;
+ }
+
+ removeDelta -= splice.addedCount;
+ }
+
+ for (var splice in splices) {
+ for (var addIndex = splice.index;
+ addIndex < splice.index + splice.addedCount;
+ addIndex++) {
+
+ var model = getInstanceModel(iteratedValue[addIndex], syntax);
+
+ var instanceNodes = instanceCache.remove(model);
+ if (instanceNodes == null) {
+ instanceNodes = getInstanceNodes(model, syntax);
+ }
+ insertInstanceAt(addIndex, instanceNodes);
+ }
+ }
+
+ for (var instanceNodes in instanceCache.values) {
+ instanceNodes.forEach(_unbindAllRecursively);
+ }
+ }
+
+ void unobserve() {
+ if (_sub == null) return;
+ _sub.cancel();
+ _sub = null;
+ }
+
+ void abandon() {
+ unobserve();
+ _valueBinding.cancel();
+ terminators.clear();
+ inputs.dispose();
+ }
+
+ static void _unbindAllRecursively(Node node) {
+ var nodeExt = _mdv(node);
+ nodeExt._templateInstance = null;
+ if (node is Element && (node as Element).isTemplate) {
+ // Make sure we stop observing when we remove an element.
+ var templateIterator = nodeExt._templateIterator;
+ if (templateIterator != null) {
+ templateIterator.abandon();
+ nodeExt._templateIterator = null;
+ }
+ }
+
+ _Bindings._nodeOrCustom(node).unbindAll();
+ for (var c = node.firstChild; c != null; c = c.nextNode) {
+ _unbindAllRecursively(c);
+ }
+ }
+}
diff --git a/pkg/mdv/lib/src/element.dart b/pkg/mdv/lib/src/element.dart
new file mode 100644
index 0000000..6c0f405
--- /dev/null
+++ b/pkg/mdv/lib/src/element.dart
@@ -0,0 +1,65 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of mdv;
+
+/** Extensions to the [Element] API. */
+class _ElementExtension extends _NodeExtension {
+ _ElementExtension(Element node) : super(node);
+
+ Element get node => super.node;
+
+ Map<String, StreamSubscription> _attributeBindings;
+
+ // TODO(jmesserly): should path be optional, and default to empty path?
+ // It is used that way in at least one path in JS TemplateElement tests
+ // (see "BindImperative" test in original JS code).
+ void bind(String name, model, String path) {
+ if (_attributeBindings == null) {
+ _attributeBindings = new Map<String, StreamSubscription>();
+ }
+
+ node.xtag.attributes.remove(name);
+
+ var changed;
+ if (name.endsWith('?')) {
+ name = name.substring(0, name.length - 1);
+
+ changed = (value) {
+ if (_Bindings._toBoolean(value)) {
+ node.xtag.attributes[name] = '';
+ } else {
+ node.xtag.attributes.remove(name);
+ }
+ };
+ } else {
+ changed = (value) {
+ // TODO(jmesserly): escape value if needed to protect against XSS.
+ // See https://github.com/polymer-project/mdv/issues/58
+ node.xtag.attributes[name] = value == null ? '' : '$value';
+ };
+ }
+
+ unbind(name);
+
+ _attributeBindings[name] =
+ new PathObserver(model, path).bindSync(changed);
+ }
+
+ void unbind(String name) {
+ if (_attributeBindings != null) {
+ var binding = _attributeBindings.remove(name);
+ if (binding != null) binding.cancel();
+ }
+ }
+
+ void unbindAll() {
+ if (_attributeBindings != null) {
+ for (var binding in _attributeBindings.values) {
+ binding.cancel();
+ }
+ _attributeBindings = null;
+ }
+ }
+}
diff --git a/pkg/mdv/lib/src/input_element.dart b/pkg/mdv/lib/src/input_element.dart
new file mode 100644
index 0000000..32b9834
--- /dev/null
+++ b/pkg/mdv/lib/src/input_element.dart
@@ -0,0 +1,60 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of mdv;
+
+/** Extensions to the [InputElement] API. */
+class _InputElementExtension extends _ElementExtension {
+ _InputElementExtension(InputElement node) : super(node);
+
+ InputElement get node => super.node;
+
+ _ValueBinding _valueBinding;
+
+ _CheckedBinding _checkedBinding;
+
+ void bind(String name, model, String path) {
+ switch (name) {
+ case 'value':
+ unbind('value');
+ node.attributes.remove('value');
+ _valueBinding = new _ValueBinding(node, model, path);
+ break;
+ case 'checked':
+ unbind('checked');
+ node.attributes.remove('checked');
+ _checkedBinding = new _CheckedBinding(node, model, path);
+ break;
+ default:
+ super.bind(name, model, path);
+ break;
+ }
+ }
+
+ void unbind(String name) {
+ switch (name) {
+ case 'value':
+ if (_valueBinding != null) {
+ _valueBinding.unbind();
+ _valueBinding = null;
+ }
+ break;
+ case 'checked':
+ if (_checkedBinding != null) {
+ _checkedBinding.unbind();
+ _checkedBinding = null;
+ }
+ break;
+ default:
+ super.unbind(name);
+ break;
+ }
+ }
+
+ void unbindAll() {
+ unbind('value');
+ unbind('checked');
+ super.unbindAll();
+ }
+}
diff --git a/pkg/mdv/lib/src/node.dart b/pkg/mdv/lib/src/node.dart
new file mode 100644
index 0000000..0379838
--- /dev/null
+++ b/pkg/mdv/lib/src/node.dart
@@ -0,0 +1,34 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of mdv;
+
+/** Extensions to the [Node] API. */
+class _NodeExtension {
+ final Node node;
+
+ _NodeExtension(this.node);
+
+ /**
+ * Binds the attribute [name] to the [path] of the [model].
+ * Path is a String of accessors such as `foo.bar.baz`.
+ */
+ void bind(String name, model, String path) {
+ window.console.error('Unhandled binding to Node: '
+ '$this $name $model $path');
+ }
+
+ /** Unbinds the attribute [name]. */
+ void unbind(String name) {}
+
+ /** Unbinds all bound attributes. */
+ void unbindAll() {}
+
+ TemplateInstance _templateInstance;
+
+ /** Gets the template instance that instantiated this node, if any. */
+ TemplateInstance get templateInstance =>
+ _templateInstance != null ? _templateInstance :
+ (node.parent != null ? node.parent.templateInstance : null);
+}
diff --git a/pkg/mdv/lib/src/template.dart b/pkg/mdv/lib/src/template.dart
new file mode 100644
index 0000000..9b379ea
--- /dev/null
+++ b/pkg/mdv/lib/src/template.dart
@@ -0,0 +1,76 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of mdv;
+
+/** Extensions to [Element]s that behave as templates. */
+class _TemplateExtension extends _ElementExtension {
+ var _model;
+ _TemplateIterator _templateIterator;
+
+ _TemplateExtension(Element node) : super(node);
+
+ void bind(String name, model, String path) {
+ switch (name) {
+ case 'bind':
+ case 'repeat':
+ case 'if':
+ if (_templateIterator == null) {
+ _templateIterator = new _TemplateIterator(node);
+ }
+ _templateIterator.inputs.bind(name, model, path);
+ return;
+ default:
+ super.bind(name, model, path);
+ }
+ }
+
+ void unbind(String name) {
+ switch (name) {
+ case 'bind':
+ case 'repeat':
+ case 'if':
+ if (_templateIterator != null) {
+ _templateIterator.inputs.unbind(name);
+ }
+ return;
+ default:
+ super.unbind(name);
+ }
+ }
+
+ void unbindAll() {
+ unbind('bind');
+ unbind('repeat');
+ unbind('if');
+ super.unbindAll();
+ }
+
+ /**
+ * Creates an instance of the template.
+ */
+ DocumentFragment createInstance() {
+ var template = node.ref;
+ if (template == null) template = node;
+
+ var instance = _Bindings._createDeepCloneAndDecorateTemplates(
+ template.content, node.attributes['syntax']);
+
+ if (_instanceCreated != null) {
+ _instanceCreated.add(instance);
+ }
+ return instance;
+ }
+
+ /**
+ * The data model which is inherited through the tree.
+ */
+ get model => _model;
+
+ void set model(value) {
+ var syntax = TemplateElement.syntax[node.attributes['syntax']];
+ _model = value;
+ _Bindings._addBindings(node, model, syntax);
+ }
+}
diff --git a/pkg/mdv/lib/src/text.dart b/pkg/mdv/lib/src/text.dart
new file mode 100644
index 0000000..6d2b380
--- /dev/null
+++ b/pkg/mdv/lib/src/text.dart
@@ -0,0 +1,44 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of mdv;
+
+/** Extensions to the [Text] API. */
+class _TextExtension extends _NodeExtension {
+ _TextExtension(Text node) : super(node);
+
+ Text get node => super.node;
+
+ StreamSubscription _textBinding;
+
+ void bind(String name, model, String path) {
+ if (name != 'text') {
+ super.bind(name, model, path);
+ return;
+ }
+
+ unbind('text');
+
+ _textBinding = new PathObserver(model, path).bindSync((value) {
+ node.text = value == null ? '' : '$value';
+ });
+ }
+
+ void unbind(String name) {
+ if (name != 'text') {
+ super.unbind(name);
+ return;
+ }
+
+ if (_textBinding == null) return;
+
+ _textBinding.cancel();
+ _textBinding = null;
+ }
+
+ void unbindAll() {
+ unbind('text');
+ super.unbindAll();
+ }
+}
diff --git a/pkg/mdv/pubspec.yaml b/pkg/mdv/pubspec.yaml
new file mode 100644
index 0000000..f1149f6
--- /dev/null
+++ b/pkg/mdv/pubspec.yaml
@@ -0,0 +1,15 @@
+name: mdv
+author: "Web UI Team <web-ui-dev@dartlang.org>"
+homepage: https://github.com/dart-lang/web-ui
+description: >
+ Model-Driven-Views (MDV) extends HTML and the DOM APIs to support a sensible
+ separation between the UI (DOM) of a document or application and its
+ underlying data (model).
+ Updates to the model are reflected in the DOM and user input into the DOM is
+ immediately assigned to the model.
+dependencies:
+ observe: any
+ # This is only for IdentityMap. See http://dartbug.com/4161.
+ serialization: any
+dev_dependencies:
+ unittest: any
diff --git a/tests/html/binding_syntax_test.dart b/pkg/mdv/test/binding_syntax_test.dart
similarity index 97%
rename from tests/html/binding_syntax_test.dart
rename to pkg/mdv/test/binding_syntax_test.dart
index 4e89a0a..55bb1f4 100644
--- a/tests/html/binding_syntax_test.dart
+++ b/pkg/mdv/test/binding_syntax_test.dart
@@ -7,15 +7,17 @@
import 'dart:async';
import 'dart:collection';
import 'dart:html';
-import 'package:mdv_observe/mdv_observe.dart';
+import 'package:mdv/mdv.dart' as mdv;
+import 'package:observe/observe.dart';
import 'package:unittest/html_config.dart';
import 'package:unittest/unittest.dart';
-import 'mdv_observe_utils.dart';
+import 'observe_utils.dart';
// Note: this file ported from
// https://github.com/toolkitchen/mdv/blob/master/tests/syntax.js
main() {
+ mdv.initialize();
useHtmlConfiguration();
group('Syntax', syntaxTests);
}
diff --git a/tests/html/custom_element_bindings_test.dart b/pkg/mdv/test/custom_element_bindings_test.dart
similarity index 96%
rename from tests/html/custom_element_bindings_test.dart
rename to pkg/mdv/test/custom_element_bindings_test.dart
index 6548a7f..af9919e 100644
--- a/tests/html/custom_element_bindings_test.dart
+++ b/pkg/mdv/test/custom_element_bindings_test.dart
@@ -6,12 +6,14 @@
import 'dart:async';
import 'dart:html';
-import 'package:mdv_observe/mdv_observe.dart';
+import 'package:mdv/mdv.dart' as mdv;
+import 'package:observe/observe.dart';
import 'package:unittest/html_config.dart';
import 'package:unittest/unittest.dart';
-import 'mdv_observe_utils.dart';
+import 'observe_utils.dart';
main() {
+ mdv.initialize();
useHtmlConfiguration();
group('Custom Element Bindings', customElementBindingsTest);
}
@@ -120,7 +122,7 @@
'</my-custom-element>'
'</template>');
- TemplateElement.instanceCreated.listen((fragment) {
+ mdv.instanceCreated.listen((fragment) {
for (var e in fragment.queryAll('my-custom-element')) {
new MyCustomElement.attach(e);
}
@@ -208,14 +210,12 @@
switch (name) {
case 'my-point':
if (_sub1 != null) {
- print('!!! unbind $name');
_sub1.cancel();
_sub1 = null;
}
return;
case 'scary-monster':
if (_sub2 != null) {
- print('!!! unbind $name');
_sub2.cancel();
_sub2 = null;
}
diff --git a/tests/html/element_bindings_test.dart b/pkg/mdv/test/element_bindings_test.dart
similarity index 87%
rename from tests/html/element_bindings_test.dart
rename to pkg/mdv/test/element_bindings_test.dart
index b960c99..e0f7973 100644
--- a/tests/html/element_bindings_test.dart
+++ b/pkg/mdv/test/element_bindings_test.dart
@@ -6,15 +6,17 @@
import 'dart:async';
import 'dart:html';
-import 'package:mdv_observe/mdv_observe.dart';
+import 'package:mdv/mdv.dart' as mdv;
+import 'package:observe/observe.dart';
import 'package:unittest/html_config.dart';
import 'package:unittest/unittest.dart';
-import 'mdv_observe_utils.dart';
+import 'observe_utils.dart';
// Note: this file ported from
// https://github.com/toolkitchen/mdv/blob/master/tests/element_bindings.js
main() {
+ mdv.initialize();
useHtmlConfiguration();
group('Element Bindings', elementBindingTests);
}
@@ -187,8 +189,51 @@
el.click();
expect(model[sym('val')], false);
+
+ el.onClick.listen((_) {
+ expect(model[sym('val')], true);
+ });
+ el.onChange.listen((_) {
+ expect(model[sym('val')], true);
+ });
+
+ el.dispatchEvent(new MouseEvent('click', view: window));
});
+ test('InputElementCheckbox - binding updated on click', () {
+ var model = toSymbolMap({'val': true});
+
+ var el = new InputElement();
+ testDiv.append(el);
+ el.type = 'checkbox';
+ el.bind('checked', model, 'val');
+ deliverChangeRecords();
+ expect(el.checked, true);
+
+ el.onClick.listen((_) {
+ expect(model[sym('val')], false);
+ });
+
+ el.dispatchEvent(new MouseEvent('click', view: window));
+ });
+
+ test('InputElementCheckbox - binding updated on change', () {
+ var model = toSymbolMap({'val': true});
+
+ var el = new InputElement();
+ testDiv.append(el);
+ el.type = 'checkbox';
+ el.bind('checked', model, 'val');
+ deliverChangeRecords();
+ expect(el.checked, true);
+
+ el.onChange.listen((_) {
+ expect(model[sym('val')], false);
+ });
+
+ el.dispatchEvent(new MouseEvent('click', view: window));
+ });
+
test('InputElementRadio', () {
var model = toSymbolMap({'val1': true, 'val2': false, 'val3': false,
'val4': true});
diff --git a/tests/html/node_bindings_test.dart b/pkg/mdv/test/node_bindings_test.dart
similarity index 96%
rename from tests/html/node_bindings_test.dart
rename to pkg/mdv/test/node_bindings_test.dart
index fd08fd4..e97f3dce 100644
--- a/tests/html/node_bindings_test.dart
+++ b/pkg/mdv/test/node_bindings_test.dart
@@ -6,15 +6,17 @@
import 'dart:async';
import 'dart:html';
-import 'package:mdv_observe/mdv_observe.dart';
+import 'package:mdv/mdv.dart' as mdv;
+import 'package:observe/observe.dart';
import 'package:unittest/html_config.dart';
import 'package:unittest/unittest.dart';
-import 'mdv_observe_utils.dart';
+import 'observe_utils.dart';
// Note: this file ported from
// https://github.com/toolkitchen/mdv/blob/master/tests/node_bindings.js
main() {
+ mdv.initialize();
useHtmlConfiguration();
group('Node Bindings', nodeBindingTests);
}
diff --git a/tests/html/mdv_observe_utils.dart b/pkg/mdv/test/observe_utils.dart
similarity index 84%
rename from tests/html/mdv_observe_utils.dart
rename to pkg/mdv/test/observe_utils.dart
index 56c3ceb..d3f33e1 100644
--- a/tests/html/mdv_observe_utils.dart
+++ b/pkg/mdv/test/observe_utils.dart
@@ -2,9 +2,9 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-library mdv_observe_utils;
+library observe_utils;
-import 'package:mdv_observe/mdv_observe.dart';
+import 'package:observe/observe.dart';
toSymbolMap(Map map) {
var result = new ObservableMap.linked();
diff --git a/tests/html/template_element_test.dart b/pkg/mdv/test/template_element_test.dart
similarity index 89%
rename from tests/html/template_element_test.dart
rename to pkg/mdv/test/template_element_test.dart
index d71f854..10b39e1 100644
--- a/tests/html/template_element_test.dart
+++ b/pkg/mdv/test/template_element_test.dart
@@ -8,10 +8,11 @@
import 'dart:collection';
import 'dart:html';
import 'dart:math' as math;
-import 'package:mdv_observe/mdv_observe.dart';
+import 'package:mdv/mdv.dart' as mdv;
+import 'package:observe/observe.dart';
import 'package:unittest/html_config.dart';
import 'package:unittest/unittest.dart';
-import 'mdv_observe_utils.dart';
+import 'observe_utils.dart';
// Note: this file ported from
// https://github.com/toolkitchen/mdv/blob/master/tests/template_element.js
@@ -20,6 +21,7 @@
// look for "assertNodesAre".
main() {
+ mdv.initialize();
useHtmlConfiguration();
group('Template Element', templateElementTests);
}
@@ -71,6 +73,22 @@
target.dispatchEvent(new Event(type, cancelable: false));
}
+ var expando = new Expando('test');
+ void addExpandos(node) {
+ while (node != null) {
+ expando[node] = node.text;
+ node = node.nextNode;
+ }
+ }
+
+ void checkExpandos(node) {
+ expect(node, isNotNull);
+ while (node != null) {
+ expect(expando[node], node.text);
+ node = node.nextNode;
+ }
+ }
+
test('Template', () {
var div = createTestHtml('<template bind={{}}>text</template>');
recursivelySetTemplateModel(div, null);
@@ -79,6 +97,31 @@
expect(div.nodes.last.text, 'text');
});
+ test('Template bind, no parent', () {
+ var div = createTestHtml('<template bind>text</template>');
+ var template = div.nodes[0];
+ template.remove();
+
+ recursivelySetTemplateModel(template, toSymbolMap({}));
+ deliverChangeRecords();
+ expect(template.nodes.length, 0);
+ expect(template.nextNode, null);
+ // TODO(jmesserly): the JS tests assert that observer callbacks had no
+ // exceptions. How do we replicate this?
+ });
+
+ test('Template bind, no defaultView', () {
+ var div = createTestHtml('<template bind>text</template>');
+ var template = div.nodes[0];
+ var doc = document.implementation.createHtmlDocument('');
+ doc.adoptNode(div);
+ recursivelySetTemplateModel(template, toSymbolMap({}));
+ deliverChangeRecords();
+ expect(div.nodes.length, 1);
+ // TODO(jmesserly): the JS tests assert that observer callbacks had no
+ // exceptions. How do we replicate this?
+ });
+
test('Template-Empty Bind', () {
var div = createTestHtml('<template bind>text</template>');
recursivelySetTemplateModel(div, null);
@@ -240,6 +283,67 @@
expect(div.nodes.length, 3);
});
+ test('Repeat - Reuse Instances', () {
+ var div = createTestHtml('<template repeat>{{ val }}</template>');
+
+ var model = toSymbols([
+ {'val': 10},
+ {'val': 5},
+ {'val': 2},
+ {'val': 8},
+ {'val': 1}
+ ]);
+ recursivelySetTemplateModel(div, model);
+
+ deliverChanges(model);
+ expect(div.nodes.length, 6);
+ var template = div.firstChild;
+
+ addExpandos(template.nextNode);
+ checkExpandos(template.nextNode);
+
+ final VAL = const Symbol('val');
+ model.sort((a, b) => a[VAL] - b[VAL]);
+ deliverChanges(model);
+ checkExpandos(template.nextNode);
+
+ model = toObservable(model.reversed);
+ recursivelySetTemplateModel(div, model);
+ deliverChanges(model);
+ checkExpandos(template.nextNode);
+
+ for (var item in model) {
+ item[VAL] += 1;
+ }
+
+ deliverChanges(model);
+ expect(div.nodes[1].text, "11");
+ expect(div.nodes[2].text, "9");
+ expect(div.nodes[3].text, "6");
+ expect(div.nodes[4].text, "3");
+ expect(div.nodes[5].text, "2");
+ });
+
+ test('Bind - Reuse Instance', () {
+ var div = createTestHtml(
+ '<template bind="{{ foo }}">{{ bar }}</template>');
+
+ var model = toObservable({ 'foo': { 'bar': 5 }});
+ recursivelySetTemplateModel(div, model);
+
+ deliverChanges(model);
+ expect(div.nodes.length, 2);
+ var template = div.firstChild;
+
+ addExpandos(template.nextNode);
+ checkExpandos(template.nextNode);
+
+ model = toObservable({'foo': model['foo']});
+ recursivelySetTemplateModel(div, model);
+ deliverChanges(model);
+ checkExpandos(template.nextNode);
+ });
+
test('Repeat-Empty', () {
var div = createTestHtml(
'<template repeat>text</template>');
@@ -943,6 +1047,39 @@
expect(div.nodes[i++].text, 'Item 2');
});
+ test('Attribute Template Option/Optgroup', () {
+ var div = createTestHtml(
+ '<template bind>'
+ '<select>'
+ '<optgroup template repeat="{{ groups }}" label="{{ name }}">'
+ '<option template repeat="{{ items }}">{{ val }}</option>'
+ '</optgroup>'
+ '</select>'
+ '</template>');
+
+ var m = toSymbols({
+ 'selected': 1,
+ 'groups': [{
+ 'name': 'one', 'items': [{ 'val': 0 }, { 'val': 1 }]
+ }],
+ });
+
+ recursivelySetTemplateModel(div, m);
+ deliverChanges(m);
+
+ var select = div.nodes[0].nextNode;
+ expect(select.nodes.length, 2);
+ expect(select.nodes[0].tagName, 'TEMPLATE');
+ expect(select.nodes[0].ref.content.nodes[0].tagName, 'OPTGROUP');
+
+ var optgroup = select.nodes[1];
+ expect(optgroup.nodes[0].tagName, 'TEMPLATE');
+ expect(optgroup.nodes[1].tagName, 'OPTION');
+ expect(optgroup.nodes[1].text, '0');
+ expect(optgroup.nodes[2].tagName, 'OPTION');
+ expect(optgroup.nodes[2].text, '1');
+ });
+
test('NestedIterateTableMixedSemanticNative', () {
if (!TemplateElement.supported) return;
@@ -1212,14 +1349,15 @@
'</template>');
var template = div.nodes.first;
+ // Note: this test data is a little different from the JS version, because
+ // we allow binding to the "length" field of the Map in preference to
+ // binding keys.
var m = toSymbols({
'a': [
- {'length': 0},
- {
- 'length': 1,
- 'b': {'length': 4}
- },
- {'length': 2}
+ [],
+ { 'b': [1,2,3,4] },
+ // Note: this will use the Map "length" property, not the "length" key.
+ {'length': 42, 'c': 123}
]
});
recursivelySetTemplateModel(div, m);
@@ -1324,7 +1462,7 @@
if (ShadowRoot.supported) {
var root = createShadowTestHtml('Hi {{ name }}');
var model = toSymbolMap({'name': 'Leela'});
- TemplateElement.bindModel(root, model);
+ mdv.bindModel(root, model);
deliverChangeRecords();
expect(root.text, 'Hi Leela');
}
@@ -1333,11 +1471,21 @@
test('bindModel to polyfilled shadow root', () {
var root = createTestHtml('Hi {{ name }}');
var model = toSymbolMap({'name': 'Leela'});
- TemplateElement.bindModel(root, model);
+ mdv.bindModel(root, model);
deliverChangeRecords();
expect(root.text, 'Hi Leela');
});
+ test('BindShadowDOM Template Ref', () {
+ if (ShadowRoot.supported) {
+ var root = createShadowTestHtml(
+ '<template id=foo>Hi</template><template bind ref=foo></template>');
+ recursivelySetTemplateModel(root, toSymbolMap({}));
+ deliverChangeRecords();
+ expect(root.nodes.length, 3);
+ }
+ });
+
// https://github.com/toolkitchen/mdv/issues/8
test('UnbindingInNestedBind', () {
var div = createTestHtml(
@@ -1445,7 +1593,7 @@
test('instanceCreated hack', () {
var called = false;
- var sub = TemplateElement.instanceCreated.listen((node) {
+ var sub = mdv.instanceCreated.listen((node) {
called = true;
expect(node.nodeType, Node.DOCUMENT_FRAGMENT_NODE);
});
diff --git a/pkg/mdv_observe/lib/mdv_observe.dart b/pkg/mdv_observe/lib/mdv_observe.dart
deleted file mode 100644
index 8864b36..0000000
--- a/pkg/mdv_observe/lib/mdv_observe.dart
+++ /dev/null
@@ -1,104 +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.
-
-/**
- * *Warning*: this library is experimental, and APIs are subject to change.
- *
- * This library is used to observe changes to [Observable] types. It also
- * has helpers to implement [Observable] objects.
- *
- * For example:
- *
- * class Monster extends Object with ObservableMixin {
- * static const _HEALTH = const Symbol('health');
- *
- * int _health = 100;
- * get health => _health;
- * set health(value) {
- * _health = notifyChange(_HEALTH, _health, value);
- * }
- *
- * void damage(int amount) {
- * print('$this takes $amount damage!');
- * health -= amount;
- * }
- *
- * toString() => 'Monster with $health hit points';
- *
- * // These methods are temporary until dart2js supports mirrors.
- * getValueWorkaround(key) {
- * if (key == _HEALTH) return health;
- * return null;
- * }
- * setValueWorkaround(key, val) {
- * if (key == _HEALTH) health = val;
- * }
- * }
- *
- * main() {
- * var obj = new Monster();
- * obj.changes.listen((records) {
- * print('Changes to $obj were: $records');
- * });
- * // Schedules asynchronous delivery of these changes
- * obj.damage(10);
- * obj.damage(20);
- * print('done!');
- * }
- */
-library mdv_observe;
-
-import 'dart:collection';
-
-// Import and reexport the observe implementation library. It contains the types
-// that are required to implement Model-Driven-Views in dart:html.
-// NOTE: always use package:mdv_observe (this package) in your code!
-// DO NOT import mdv_observe_impl; it may break unpredictably.
-import 'dart:mdv_observe_impl';
-export 'dart:mdv_observe_impl';
-
-part 'src/observable_box.dart';
-part 'src/observable_list.dart';
-part 'src/observable_map.dart';
-
-
-/**
- * Converts the [Iterable] or [Map] to an [ObservableList] or [ObservableMap],
- * respectively. This is a convenience function to make it easier to convert
- * literals into the corresponding observable collection type.
- *
- * If [value] is not one of those collection types, or is already [Observable],
- * it will be returned unmodified.
- *
- * If [value] is a [Map], the resulting value will use the appropriate kind of
- * backing map: either [HashMap], [LinkedHashMap], or [SplayTreeMap].
- *
- * By default this performs a deep conversion, but you can set [deep] to false
- * for a shallow conversion. This does not handle circular data structures.
- */
-// TODO(jmesserly): ObservableSet?
-toObservable(value, {bool deep: true}) =>
- deep ? _toObservableDeep(value) : _toObservableShallow(value);
-
-_toObservableShallow(value) {
- if (value is Observable) return value;
- if (value is Map) return new ObservableMap.from(value);
- if (value is Iterable) return new ObservableList.from(value);
- return value;
-}
-
-_toObservableDeep(value) {
- if (value is Observable) return value;
- if (value is Map) {
- var result = new ObservableMap._createFromType(value);
- value.forEach((k, v) {
- result[_toObservableDeep(k)] = _toObservableDeep(v);
- });
- return result;
- }
- if (value is Iterable) {
- return new ObservableList.from(value.map(_toObservableDeep));
- }
- return value;
-}
diff --git a/sdk/lib/mdv_observe_impl/mdv_observe_impl.dart b/pkg/observe/lib/observe.dart
similarity index 69%
rename from sdk/lib/mdv_observe_impl/mdv_observe_impl.dart
rename to pkg/observe/lib/observe.dart
index 9429da1..2f6a59d 100644
--- a/sdk/lib/mdv_observe_impl/mdv_observe_impl.dart
+++ b/pkg/observe/lib/observe.dart
@@ -2,17 +2,51 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-// This library itself is undocumented and not supported for end use.
-// Because dart:html must use some of this functionality, it has to be available
-// via a dart:* library. The public APIs are reexported via package:mdv_observe.
-// Generally we try to keep this library minimal, with utility types and
-// functions in the package.
-library dart.mdv_observe_impl;
+/**
+ * *Warning*: this library is experimental, and APIs are subject to change.
+ *
+ * This library is used to observe changes to [Observable] types. It also
+ * has helpers to implement [Observable] objects.
+ *
+ * For example:
+ *
+ * class Monster extends Unit with ObservableMixin {
+ * int _health = 100;
+ * get health => _health;
+ * set health(value) {
+ * _health = notifyChange(const Symbol('health'), _health, value);
+ * }
+ *
+ * void damage(int amount) {
+ * print('$this takes $amount damage!');
+ * health -= amount;
+ * }
+ *
+ * toString() => 'Monster with $health hit points';
+ * }
+ *
+ * main() {
+ * var obj = new Monster();
+ * obj.changes.listen((records) {
+ * print('Changes to $obj were: $records');
+ * });
+ * // Schedules asynchronous delivery of these changes
+ * obj.damage(10);
+ * obj.damage(20);
+ * print('done!');
+ * }
+ */
+library observe;
import 'dart:async';
import 'dart:collection';
+import 'dart:mirrors';
-part 'path_observer.dart';
+part 'src/compound_binding.dart';
+part 'src/observable_box.dart';
+part 'src/observable_list.dart';
+part 'src/observable_map.dart';
+part 'src/path_observer.dart';
/**
* Interface representing an observable object. This is used by data in
@@ -33,21 +67,6 @@
* [deliverChangeRecords] can be called to force delivery.
*/
Stream<List<ChangeRecord>> get changes;
-
- // TODO(jmesserly): remove these ASAP.
- /**
- * *Warning*: this method is temporary until dart2js supports mirrors.
- * Gets the value of a field or index. This should return null if it was
- * not found.
- */
- getValueWorkaround(key);
-
- /**
- * *Warning*: this method is temporary until dart2js supports mirrors.
- * Sets the value of a field or index. This should have no effect if the field
- * was not found.
- */
- void setValueWorkaround(key, Object value);
}
/**
@@ -226,3 +245,46 @@
}
Queue _deliverCallbacks;
+
+
+/**
+ * Converts the [Iterable] or [Map] to an [ObservableList] or [ObservableMap],
+ * respectively. This is a convenience function to make it easier to convert
+ * literals into the corresponding observable collection type.
+ *
+ * If [value] is not one of those collection types, or is already [Observable],
+ * it will be returned unmodified.
+ *
+ * If [value] is a [Map], the resulting value will use the appropriate kind of
+ * backing map: either [HashMap], [LinkedHashMap], or [SplayTreeMap].
+ *
+ * By default this performs a deep conversion, but you can set [deep] to false
+ * for a shallow conversion. This does not handle circular data structures.
+ * If a conversion is peformed, mutations are only observed to the result of
+ * this function. Changing the original collection will not affect it.
+ */
+// TODO(jmesserly): ObservableSet?
+toObservable(value, {bool deep: true}) =>
+ deep ? _toObservableDeep(value) : _toObservableShallow(value);
+
+_toObservableShallow(value) {
+ if (value is Observable) return value;
+ if (value is Map) return new ObservableMap.from(value);
+ if (value is Iterable) return new ObservableList.from(value);
+ return value;
+}
+
+_toObservableDeep(value) {
+ if (value is Observable) return value;
+ if (value is Map) {
+ var result = new ObservableMap._createFromType(value);
+ value.forEach((k, v) {
+ result[_toObservableDeep(k)] = _toObservableDeep(v);
+ });
+ return result;
+ }
+ if (value is Iterable) {
+ return new ObservableList.from(value.map(_toObservableDeep));
+ }
+ return value;
+}
diff --git a/pkg/observe/lib/src/compound_binding.dart b/pkg/observe/lib/src/compound_binding.dart
new file mode 100644
index 0000000..c239abe
--- /dev/null
+++ b/pkg/observe/lib/src/compound_binding.dart
@@ -0,0 +1,114 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of observe;
+
+/** The callback used in the [CompoundBinding.combinator] field. */
+typedef Object CompoundBindingCombinator(Map objects);
+
+/**
+ * Model-Driven Views contains a helper object which is useful for the
+ * implementation of a Custom Syntax.
+ *
+ * var binding = new CompoundBinding((values) {
+ * var combinedValue;
+ * // compute combinedValue based on the current values which are provided
+ * return combinedValue;
+ * });
+ * binding.bind('name1', obj1, path1);
+ * binding.bind('name2', obj2, path2);
+ * //...
+ * binding.bind('nameN', objN, pathN);
+ *
+ * CompoundBinding is an object which knows how to listen to multiple path
+ * values (registered via [bind]) and invoke its [combinator] when one or more
+ * of the values have changed and set its [value] property to the return value
+ * of the function. When any value has changed, all current values are provided
+ * to the [combinator] in the single `values` argument.
+ */
+// TODO(jmesserly): rename to something that indicates it's a computed value?
+class CompoundBinding extends ObservableBase {
+ CompoundBindingCombinator _combinator;
+
+ // TODO(jmesserly): ideally these would be String keys, but sometimes we
+ // use integers.
+ Map<dynamic, StreamSubscription> _bindings = new Map();
+ Map _values = new Map();
+ bool _scheduled = false;
+ bool _disposed = false;
+ Object _value;
+
+ CompoundBinding([CompoundBindingCombinator combinator]) {
+ // TODO(jmesserly): this is a tweak to the original code, it seemed to me
+ // that passing the combinator to the constructor should be equivalent to
+ // setting it via the property.
+ // I also added a null check to the combinator setter.
+ this.combinator = combinator;
+ }
+
+ CompoundBindingCombinator get combinator => _combinator;
+
+ set combinator(CompoundBindingCombinator combinator) {
+ _combinator = combinator;
+ if (combinator != null) _scheduleResolve();
+ }
+
+ static const _VALUE = const Symbol('value');
+
+ get value => _value;
+
+ void set value(newValue) {
+ _value = notifyPropertyChange(_VALUE, _value, newValue);
+ }
+
+ void bind(name, model, String path) {
+ unbind(name);
+
+ _bindings[name] = new PathObserver(model, path).bindSync((value) {
+ _values[name] = value;
+ _scheduleResolve();
+ });
+ }
+
+ void unbind(name, {bool suppressResolve: false}) {
+ var binding = _bindings.remove(name);
+ if (binding == null) return;
+
+ binding.cancel();
+ _values.remove(name);
+ if (!suppressResolve) _scheduleResolve();
+ }
+
+ // TODO(rafaelw): Is this the right processing model?
+ // TODO(rafaelw): Consider having a seperate ChangeSummary for
+ // CompoundBindings so to excess dirtyChecks.
+ void _scheduleResolve() {
+ if (_scheduled) return;
+ _scheduled = true;
+ queueChangeRecords(resolve);
+ }
+
+ void resolve() {
+ if (_disposed) return;
+ _scheduled = false;
+
+ if (_combinator == null) {
+ throw new StateError(
+ 'CompoundBinding attempted to resolve without a combinator');
+ }
+
+ value = _combinator(_values);
+ }
+
+ void dispose() {
+ for (var binding in _bindings.values) {
+ binding.cancel();
+ }
+ _bindings.clear();
+ _values.clear();
+
+ _disposed = true;
+ value = null;
+ }
+}
diff --git a/pkg/mdv_observe/lib/src/observable_box.dart b/pkg/observe/lib/src/observable_box.dart
similarity index 73%
rename from pkg/mdv_observe/lib/src/observable_box.dart
rename to pkg/observe/lib/src/observable_box.dart
index 484a900..7cc8fac 100644
--- a/pkg/mdv_observe/lib/src/observable_box.dart
+++ b/pkg/observe/lib/src/observable_box.dart
@@ -2,7 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-part of mdv_observe;
+part of observe;
// TODO(jmesserly): should the property name be configurable?
// That would be more convenient.
@@ -13,8 +13,6 @@
* [ObservableMixin]. The property name for changes is "value".
*/
class ObservableBox<T> extends ObservableBase {
- static const _VALUE = const Symbol('value');
-
T _value;
ObservableBox([T initialValue]) : _value = initialValue;
@@ -22,16 +20,8 @@
T get value => _value;
void set value(T newValue) {
- _value = notifyPropertyChange(_VALUE, _value, newValue);
+ _value = notifyPropertyChange(const Symbol('value'), _value, newValue);
}
String toString() => '#<$runtimeType value: $value>';
-
- getValueWorkaround(key) {
- if (key == _VALUE) return value;
- return null;
- }
- void setValueWorkaround(key, newValue) {
- if (key == _VALUE) value = newValue;
- }
}
diff --git a/pkg/mdv_observe/lib/src/observable_list.dart b/pkg/observe/lib/src/observable_list.dart
similarity index 96%
rename from pkg/mdv_observe/lib/src/observable_list.dart
rename to pkg/observe/lib/src/observable_list.dart
index 66ca771..bc66ea02 100644
--- a/pkg/mdv_observe/lib/src/observable_list.dart
+++ b/pkg/observe/lib/src/observable_list.dart
@@ -2,7 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-part of mdv_observe;
+part of observe;
/**
* Represents an observable list of model values. If any items are added,
@@ -14,8 +14,6 @@
implements List<E> {
List<ListChangeRecord> _records;
- static const _LENGTH = const Symbol('length');
-
/** The inner [List<E>] with the actual storage. */
final List<E> _list;
@@ -38,13 +36,6 @@
factory ObservableList.from(Iterable<E> other) =>
new ObservableList<E>()..addAll(other);
- // TODO(jmesserly): remove once we have mirrors
- getValueWorkaround(key) => key == _LENGTH ? length : null;
-
- setValueWorkaround(key, value) {
- if (key == _LENGTH) length = value;
- }
-
int get length => _list.length;
set length(int value) {
@@ -230,7 +221,7 @@
}
if (length != oldLength) {
- notifyPropertyChange(_LENGTH, oldLength, length);
+ notifyPropertyChange(const Symbol('length'), oldLength, length);
}
if (_records.length == 1) {
diff --git a/pkg/mdv_observe/lib/src/observable_map.dart b/pkg/observe/lib/src/observable_map.dart
similarity index 97%
rename from pkg/mdv_observe/lib/src/observable_map.dart
rename to pkg/observe/lib/src/observable_map.dart
index 3ce2d82..0c345fb 100644
--- a/pkg/mdv_observe/lib/src/observable_map.dart
+++ b/pkg/observe/lib/src/observable_map.dart
@@ -2,7 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-part of mdv_observe;
+part of observe;
// TODO(jmesserly): this needs to be faster. We currently require multiple
// lookups per key to get the old value.
@@ -68,7 +68,7 @@
*/
factory ObservableMap.from(Map<K, V> other) {
var result = new ObservableMap<K, V>._createFromType(other);
- other.forEach((K key, V value) { result[key] = value; });
+ other.forEach((key, value) { result[key] = value; });
return result;
}
diff --git a/sdk/lib/mdv_observe_impl/path_observer.dart b/pkg/observe/lib/src/path_observer.dart
similarity index 93%
rename from sdk/lib/mdv_observe_impl/path_observer.dart
rename to pkg/observe/lib/src/path_observer.dart
index 5d3fae4..7f26c39 100644
--- a/sdk/lib/mdv_observe_impl/path_observer.dart
+++ b/pkg/observe/lib/src/path_observer.dart
@@ -2,7 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-part of dart.mdv_observe_impl;
+part of observe;
// This code is inspired by ChangeSummary:
// https://github.com/rafaelw/ChangeSummary/blob/master/change_summary.js
@@ -171,7 +171,6 @@
}
}
-// TODO(jmesserly): these should go away in favor of mirrors!
_getObjectProperty(object, property) {
if (object is List && property is int) {
if (property >= 0 && property < object.length) {
@@ -181,27 +180,45 @@
}
}
- // TODO(jmesserly): what about length?
- if (object is Map) return object[property];
+ if (property is Symbol) {
+ var mirror = reflect(object);
+ try {
+ return mirror.getField(property).reflectee;
+ } catch (e) {}
+ }
- if (object is Observable) return object.getValueWorkaround(property);
+ if (object is Map) {
+ return object[property];
+ }
return null;
}
bool _setObjectProperty(object, property, value) {
if (object is List && property is int) {
- object[property] = value;
- } else if (object is Map) {
- object[property] = value;
- } else if (object is Observable) {
- (object as Observable).setValueWorkaround(property, value);
- } else {
- return false;
+ if (property >= 0 && property < object.length) {
+ object[property] = value;
+ return true;
+ } else {
+ return false;
+ }
}
- return true;
-}
+ if (property is Symbol) {
+ var mirror = reflect(object);
+ try {
+ mirror.setField(property, value);
+ return true;
+ } catch (e) {}
+ }
+
+ if (object is Map) {
+ object[property] = value;
+ return true;
+ }
+
+ return false;
+}
class _PropertyObserver {
final PathObserver _path;
diff --git a/pkg/mdv_observe/pubspec.yaml b/pkg/observe/pubspec.yaml
similarity index 96%
rename from pkg/mdv_observe/pubspec.yaml
rename to pkg/observe/pubspec.yaml
index 59da442..6479be6 100644
--- a/pkg/mdv_observe/pubspec.yaml
+++ b/pkg/observe/pubspec.yaml
@@ -1,4 +1,4 @@
-name: mdv_observe
+name: observe
author: "Web UI Team <web-ui-dev@dartlang.org>"
homepage: https://github.com/dart-lang/web-ui
description: >
diff --git a/pkg/mdv_observe/test/list_change_test.dart b/pkg/observe/test/list_change_test.dart
similarity index 99%
rename from pkg/mdv_observe/test/list_change_test.dart
rename to pkg/observe/test/list_change_test.dart
index e7e1249..46b04ed 100644
--- a/pkg/mdv_observe/test/list_change_test.dart
+++ b/pkg/observe/test/list_change_test.dart
@@ -2,7 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-import 'package:mdv_observe/mdv_observe.dart';
+import 'package:observe/observe.dart';
import 'package:unittest/unittest.dart';
import 'utils.dart';
diff --git a/pkg/mdv_observe/test/observable_list_test.dart b/pkg/observe/test/observable_list_test.dart
similarity index 98%
rename from pkg/mdv_observe/test/observable_list_test.dart
rename to pkg/observe/test/observable_list_test.dart
index 3a4c945..e211243 100644
--- a/pkg/mdv_observe/test/observable_list_test.dart
+++ b/pkg/observe/test/observable_list_test.dart
@@ -2,7 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-import 'package:mdv_observe/mdv_observe.dart';
+import 'package:observe/observe.dart';
import 'package:unittest/unittest.dart';
import 'utils.dart';
diff --git a/pkg/mdv_observe/test/observable_map_test.dart b/pkg/observe/test/observable_map_test.dart
similarity index 98%
rename from pkg/mdv_observe/test/observable_map_test.dart
rename to pkg/observe/test/observable_map_test.dart
index 155bfe1..35f7613 100644
--- a/pkg/mdv_observe/test/observable_map_test.dart
+++ b/pkg/observe/test/observable_map_test.dart
@@ -2,7 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-import 'package:mdv_observe/mdv_observe.dart';
+import 'package:observe/observe.dart';
import 'package:unittest/unittest.dart';
import 'utils.dart';
diff --git a/pkg/mdv_observe/test/observe_test.dart b/pkg/observe/test/observe_test.dart
similarity index 98%
rename from pkg/mdv_observe/test/observe_test.dart
rename to pkg/observe/test/observe_test.dart
index 8d6e6d3b..e60f740 100644
--- a/pkg/mdv_observe/test/observe_test.dart
+++ b/pkg/observe/test/observe_test.dart
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import 'dart:async';
-import 'package:mdv_observe/mdv_observe.dart';
+import 'package:observe/observe.dart';
import 'package:unittest/unittest.dart';
import 'utils.dart';
diff --git a/pkg/mdv_observe/test/path_observer_test.dart b/pkg/observe/test/path_observer_test.dart
similarity index 84%
rename from pkg/mdv_observe/test/path_observer_test.dart
rename to pkg/observe/test/path_observer_test.dart
index 4222f73..471ca27 100644
--- a/pkg/mdv_observe/test/path_observer_test.dart
+++ b/pkg/observe/test/path_observer_test.dart
@@ -2,7 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-import 'package:mdv_observe/mdv_observe.dart';
+import 'package:observe/observe.dart';
import 'package:unittest/unittest.dart';
// This file contains code ported from:
@@ -163,45 +163,43 @@
});
test('Path Observation', () {
- var model = new TestModel(const Symbol('a'),
- new TestModel(const Symbol('b'),
- new TestModel(const Symbol('c'), 'hello, world')));
+ var model = new TestModel()..a =
+ (new TestModel()..b = (new TestModel()..c = 'hello, world'));
var path = observePath(model, 'a.b.c');
var lastValue = null;
var sub = path.values.listen((v) { lastValue = v; });
- model.value.value.value = 'hello, mom';
+ model.a.b.c = 'hello, mom';
expect(lastValue, null);
deliverChangeRecords();
expect(lastValue, 'hello, mom');
- model.value.value = new TestModel(const Symbol('c'), 'hello, dad');
+ model.a.b = new TestModel()..c = 'hello, dad';
deliverChangeRecords();
expect(lastValue, 'hello, dad');
- model.value = new TestModel(const Symbol('b'),
- new TestModel(const Symbol('c'), 'hello, you'));
+ model.a = new TestModel()..b =
+ (new TestModel()..c = 'hello, you');
deliverChangeRecords();
expect(lastValue, 'hello, you');
- model.value.value = 1;
+ model.a.b = 1;
deliverChangeRecords();
expect(lastValue, null);
// Stop observing
sub.cancel();
- model.value.value = new TestModel(const Symbol('c'),
- 'hello, back again -- but not observing');
+ model.a.b = new TestModel()..c = 'hello, back again -- but not observing';
deliverChangeRecords();
expect(lastValue, null);
// Resume observing
sub = path.values.listen((v) { lastValue = v; });
- model.value.value.value = 'hello. Back for reals';
+ model.a.b.c = 'hello. Back for reals';
deliverChangeRecords();
expect(lastValue, 'hello. Back for reals');
});
@@ -226,24 +224,25 @@
}
class TestModel extends ObservableBase {
- final Symbol fieldName;
- var _value;
+ var _a, _b, _c;
- TestModel(this.fieldName, [initialValue]) : _value = initialValue;
+ TestModel();
- get value => _value;
+ get a => _a;
- void set value(newValue) {
- _value = notifyPropertyChange(fieldName, _value, newValue);
+ void set a(newValue) {
+ _a = notifyPropertyChange(const Symbol('a'), _a, newValue);
}
- getValueWorkaround(key) {
- if (key == fieldName) return value;
- return null;
- }
- void setValueWorkaround(key, newValue) {
- if (key == fieldName) value = newValue;
+ get b => _b;
+
+ void set b(newValue) {
+ _b = notifyPropertyChange(const Symbol('b'), _b, newValue);
}
- toString() => '#<$runtimeType $fieldName: $_value>';
+ get c => _c;
+
+ void set c(newValue) {
+ _c = notifyPropertyChange(const Symbol('c'), _c, newValue);
+ }
}
diff --git a/pkg/mdv_observe/test/utils.dart b/pkg/observe/test/utils.dart
similarity index 71%
rename from pkg/mdv_observe/test/utils.dart
rename to pkg/observe/test/utils.dart
index 5dd5e38..dafedc1 100644
--- a/pkg/mdv_observe/test/utils.dart
+++ b/pkg/observe/test/utils.dart
@@ -2,11 +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 mdv_observe.test.utils;
+library observe.test.utils;
import 'package:unittest/unittest.dart';
-// TODO(jmesserly): use matchers when this is supported. For now just
-// compare to toStrings.
+// TODO(jmesserly): use matchers when we have a way to compare ChangeRecords.
+// For now just use the toString.
expectChanges(actual, expected, {reason}) =>
expect('$actual', '$expected', reason: reason);
diff --git a/pkg/pkg.status b/pkg/pkg.status
index da54056..31818ec 100644
--- a/pkg/pkg.status
+++ b/pkg/pkg.status
@@ -32,6 +32,7 @@
[ $runtime == d8 || $runtime == jsshell ]
unittest/test/unittest_test: Pass, Fail # http://dartbug.com/10109
+stack_trace/test/vm_test: Fail, OK # VM-specific traces
[$compiler == dart2dart]
*: Skip
@@ -106,6 +107,7 @@
[ $compiler == dart2js && $browser ]
pathos/test/pathos_dartium_test: Fail # Issue 6490
+stack_trace/test/vm_test: Fail, OK # VM-specific traces
crypto/test/sha256_test: Slow, Pass
crypto/test/sha1_test: Slow, Pass
@@ -157,9 +159,6 @@
scheduled_test/test/scheduled_test/wrap_async_test: Fail # http://dartbug.com/8440
scheduled_test/test/scheduled_test/wrap_future_test: Fail # http://dartbug.com/8440
-stack_trace/test/frame_test: Fail # http://dartbug.com/6943
-stack_trace/test/trace_test: Fail # http://dartbug.com/6943
-
[ $runtime == safari]
# Bug in JSC: the test only passes when being debugged.
@@ -194,6 +193,6 @@
[ ($runtime == dartium || $runtime == drt) && $compiler == none ]
pathos/test/pathos_dart2js_test: Fail, OK # Issue 6490
-# Skip mdv_observe tests on command line VM, they only run in the browser.
+# Skip mdv tests on command line VM, they only run in the browser.
[ $runtime == vm ]
-mdv_observe: Skip
+mdv: Skip
diff --git a/pkg/serialization/lib/serialization.dart b/pkg/serialization/lib/serialization.dart
index 522a7d1..5ec329d 100644
--- a/pkg/serialization/lib/serialization.dart
+++ b/pkg/serialization/lib/serialization.dart
@@ -361,7 +361,7 @@
* The [format] parameter determines the form of the result. The default
* format returns a String in [json] format.
*/
- write(Object object, [Format format]) {
+ write(Object object, {Format format}) {
return newWriter(format).write(object);
}
@@ -370,13 +370,14 @@
* want to do something more complex with the writer than just returning
* the final result.
*/
- Writer newWriter([Format format]) =>
- new Writer(this, format);
+ Writer newWriter([Format format]) => new Writer(this, format);
/**
* Read the serialized data from [input] and return the root object
* from the result. The [input] can be of any type that the [Format]
* reads/writes, but normally will be a [List], [Map], or a simple type.
+ * The [format] parameter determines the form of the result. The default
+ * format returns a String in [json] format.
* If there are objects that need to be resolved
* in the current context, they should be provided in [externals] as a
* Map from names to values. In particular, in the current implementation
@@ -384,8 +385,8 @@
* class name as a key. In addition to the [externals] map provided here,
* values will be looked up in the [namedObjects] map.
*/
- read(input, [Map externals = const {}]) {
- return newReader().read(input, externals);
+ read(input, {Format format, Map externals: const {}}) {
+ return newReader(format).read(input, externals);
}
/**
@@ -500,6 +501,6 @@
*/
class SerializationException implements Exception {
final String message;
- const SerializationException([this.message]);
- toString() => "SerializationException($message)";
+ const SerializationException(this.message);
+ String toString() => "SerializationException($message)";
}
diff --git a/pkg/serialization/lib/src/format.dart b/pkg/serialization/lib/src/format.dart
index 2c71e42..791cc83 100644
--- a/pkg/serialization/lib/src/format.dart
+++ b/pkg/serialization/lib/src/format.dart
@@ -115,7 +115,7 @@
* of [Reference] objects instead of the [Reference] so that the structure
* can be serialized between isolates and json easily.
*/
- forAllStates(ReaderOrWriter w, bool predicate(value),
+ void forAllStates(ReaderOrWriter w, bool predicate(value),
void transform(value)) {
for (var eachRule in w.rules) {
var ruleData = w.states[eachRule.number];
@@ -214,7 +214,7 @@
* of Reference objects and to add rule numbers if [storeRoundTripInfo]
* is true.
*/
- jsonify(Writer w) {
+ void jsonify(Writer w) {
for (var eachRule in w.rules) {
var ruleData = w.states[eachRule.number];
jsonifyForRule(ruleData, w, eachRule);
@@ -224,7 +224,7 @@
/**
* For a particular [rule] modify the [ruleData] to conform to this format.
*/
- jsonifyForRule(List ruleData, Writer w, SerializationRule rule) {
+ void jsonifyForRule(List ruleData, Writer w, SerializationRule rule) {
for (var i = 0; i < ruleData.length; i++) {
var each = ruleData[i];
if (each is List) {
@@ -241,7 +241,7 @@
* For one particular entry, which is either a Map or a List, update it
* to turn References into a nested List/Map.
*/
- jsonifyEntry(map, Writer w) {
+ void jsonifyEntry(map, Writer w) {
// Note, if this is a Map, and the key might be a reference, we need to
// bend over backwards to avoid concurrent modifications. Non-string keys
// won't actually work if we try to write this to json, but might happen
@@ -496,7 +496,7 @@
* Read data for [rule] from [input] with [length] number of entries,
* creating lists from the results.
*/
- readLists(Iterator input, SerializationRule rule, int length, Reader r) {
+ List readLists(Iterator input, SerializationRule rule, int length, Reader r) {
var ruleData = [];
for (var i = 0; i < length; i++) {
var subLength =
@@ -514,7 +514,7 @@
* Read data for [rule] from [input] with [length] number of entries,
* creating maps from the results.
*/
- readMaps(Iterator input, SerializationRule rule, int length, Reader r) {
+ List readMaps(Iterator input, SerializationRule rule, int length, Reader r) {
var ruleData = [];
for (var i = 0; i < length; i++) {
var subLength =
@@ -534,7 +534,7 @@
* Read data for [rule] from [input] with [length] number of entries,
* treating the data as primitives that can be returned directly.
*/
- readPrimitives(Iterator input, SerializationRule rule, int length) {
+ List readPrimitives(Iterator input, SerializationRule rule, int length) {
var ruleData = [];
for (var i = 0; i < length; i++) {
ruleData.add(_next(input));
diff --git a/pkg/serialization/test/serialization_test.dart b/pkg/serialization/test/serialization_test.dart
index 1e2d3aa..3c20605 100644
--- a/pkg/serialization/test/serialization_test.dart
+++ b/pkg/serialization/test/serialization_test.dart
@@ -297,10 +297,10 @@
var metaWithMaps = metaSerializationUsingMaps();
for (var eachFormat in formats) {
for (var eachMeta in [meta, metaWithMaps]) {
- var serialized = eachMeta.write(s, eachFormat);
- var reader = new Reader(eachMeta, eachFormat);
- var newSerialization = reader.read(serialized,
- {"serialization_test.Node" : reflect(new Node('')).type});
+ var serialized = eachMeta.write(s, format: eachFormat);
+ var newSerialization = eachMeta.read(serialized, format: eachFormat,
+ externals: {"serialization_test.Node" : reflect(new Node('')).type}
+ );
runRoundTripTest((x) => newSerialization);
}
}
@@ -339,9 +339,7 @@
var s = new Serialization()
..selfDescribing = false
..addRuleFor(n1, constructorFields: ["name"]);
- var w = new Writer(s);
- var r = new Reader(s);
- var m1 = r.read(w.write(n1));
+ var m1 = writeAndReadBack(s, null, n1);
var m2 = m1.children.first;
var m3 = m1.children.last;
expect(m1, m2);
@@ -437,8 +435,7 @@
for (var eachFormat in formats) {
var w = s.newWriter(eachFormat);
var output = w.write({"stuff" : p1});
- var r = s.newReader(w.format);
- var result = r.read(output);
+ var result = s.read(output, format: w.format);
var p2 = result["stuff"];
expect(p2.name, "Alice");
var a2 = p2.address;
@@ -482,10 +479,9 @@
..addRuleFor(a1)
..addRuleFor(p1).configureForMaps()
..namedObjects["foo"] = a1;
- var writer = s.newWriter(const SimpleJsonFormat(storeRoundTripInfo: true));
- var out = writer.write(p1);
- var reader = s.newReader(const SimpleJsonFormat(storeRoundTripInfo: true));
- var p2 = reader.read(out, {"foo" : 12});
+ var format = const SimpleJsonFormat(storeRoundTripInfo: true);
+ var out = s.write(p1, format: format);
+ var p2 = s.read(out, format: format, externals: {"foo" : 12});
expect(p2.name, "Alice");
var a2 = p2.address;
expect(a2, 12);
@@ -499,9 +495,8 @@
data[p1] = a1;
data[a1] = p1;
for (var eachFormat in formats) {
- var output = s.write(data, eachFormat);
- var reader = s.newReader(eachFormat);
- var input = reader.read(output);
+ var output = s.write(data, format: eachFormat);
+ var input = s.read(output, format: eachFormat);
expect(input["simple data"], data["simple data"]);
var p2 = input.keys.firstWhere((x) => x is Person);
var a2 = input.keys.firstWhere((x) => x is Address);
@@ -528,7 +523,7 @@
var s = new Serialization()..addRuleFor(new Person());
var data = {"abc" : 1, "def" : "ghi"};
data["person"] = new Person()..name = "Foo";
- var output = s.write(data, const InternalMapFormat());
+ var output = s.write(data, format: const InternalMapFormat());
var mapRule = s.rules.firstWhere((x) => x is MapRule);
var map = output["data"][mapRule.number][0];
expect(map is Map, isTrue);
@@ -563,8 +558,7 @@
*/
void verify(input) {
var s2 = nodeSerializerReflective(new Node("a"));
- var reader = new Reader(s2);
- var m2 = reader.read(input);
+ var m2 = s2.read(input);
var m1 = m2.parent;
expect(m1 is Node, isTrue);
var children = m1.children;
@@ -583,10 +577,8 @@
******************************************************************************/
writeAndReadBack(Serialization s, Format format, object) {
- var w = s.newWriter(format);
- var output = w.write(object);
- var r = s.newReader(w.format);
- return r.read(output);
+ var output = s.write(object, format: format);
+ return s.read(output, format: format);
}
/** Create a Serialization for serializing Serializations. */
@@ -726,8 +718,7 @@
var s = serializerSetUp(n1);
var output = s.write(n2);
var s2 = serializerSetUp(n1);
- var reader = new Reader(s2);
- var m2 = reader.read(output);
+ var m2 = s2.read(output);
var m1 = m2.parent;
expect(m1 is Node, isTrue);
var children = m1.children;
@@ -750,11 +741,10 @@
n2.parent = n1;
n3.parent = n1;
var s = serializerSetUp(n1);
- var output = s.write(n2, const SimpleFlatFormat());
+ var output = s.write(n2, format: const SimpleFlatFormat());
expect(output is List, isTrue);
var s2 = serializerSetUp(n1);
- var reader = new Reader(s2, const SimpleFlatFormat());
- var m2 = reader.read(output);
+ var m2 = s2.read(output, format: const SimpleFlatFormat());
var m1 = m2.parent;
expect(m1 is Node, isTrue);
var children = m1.children;
diff --git a/pkg/stack_trace/lib/src/frame.dart b/pkg/stack_trace/lib/src/frame.dart
index d750b91..6daca46 100644
--- a/pkg/stack_trace/lib/src/frame.dart
+++ b/pkg/stack_trace/lib/src/frame.dart
@@ -9,9 +9,23 @@
import 'trace.dart';
-final _nativeFrameRegExp = new RegExp(
+// #1 Foo._bar (file:///home/nweiz/code/stuff.dart:42:21)
+final _vmFrame = new RegExp(
r'^#\d+\s+([^\s].*) \((.+):(\d+):(\d+)\)$');
+// at VW.call$0 (http://pub.dartlang.org/stuff.dart.js:560:28)
+// at http://pub.dartlang.org/stuff.dart.js:560:28
+final _v8Frame = new RegExp(
+ r'^\s*at (?:([^\s].*) \((.+):(\d+):(\d+)\)|(.+):(\d+):(\d+))$');
+
+// .VW.call$0@http://pub.dartlang.org/stuff.dart.js:560
+// .VW.call$0("arg")@http://pub.dartlang.org/stuff.dart.js:560
+// .VW.call$0/name<@http://pub.dartlang.org/stuff.dart.js:560
+final _firefoxFrame = new RegExp(
+ r'^([^@(/]*)(?:\(.*\))?(/[^<]*<?)?(?:\(.*\))?@(.*):(\d+)$');
+
+final _initialDot = new RegExp(r"^\.");
+
/// A single stack frame. Each frame points to a precise location in Dart code.
class Frame {
/// The URI of the file in which the code is located.
@@ -76,13 +90,11 @@
return new Trace.current(level + 1).frames.first;
}
- /// Parses a string representation of a stack frame.
- ///
- /// [frame] should be formatted in the same way as a native stack trace frame.
- factory Frame.parse(String frame) {
- var match = _nativeFrameRegExp.firstMatch(frame);
+ /// Parses a string representation of a Dart VM stack frame.
+ factory Frame.parseVM(String frame) {
+ var match = _vmFrame.firstMatch(frame);
if (match == null) {
- throw new FormatException("Couldn't parse stack trace line '$frame'.");
+ throw new FormatException("Couldn't parse VM stack trace line '$frame'.");
}
var uri = Uri.parse(match[2]);
@@ -90,6 +102,48 @@
return new Frame(uri, int.parse(match[3]), int.parse(match[4]), member);
}
+ /// Parses a string representation of a Chrome/V8 stack frame.
+ factory Frame.parseV8(String frame) {
+ var match = _v8Frame.firstMatch(frame);
+ if (match == null) {
+ throw new FormatException("Couldn't parse V8 stack trace line '$frame'.");
+ }
+
+ // V8 stack frames can be in two forms.
+ if (match[2] != null) {
+ // The first form looks like " at FUNCTION (URI:LINE:COL)"
+ var uri = Uri.parse(match[2]);
+ var member = match[1].replaceAll("<anonymous>", "<fn>");
+ return new Frame(uri, int.parse(match[3]), int.parse(match[4]), member);
+ } else {
+ // The second form looks like " at URI:LINE:COL", and is used for
+ // anonymous functions.
+ var uri = Uri.parse(match[5]);
+ return new Frame(uri, int.parse(match[6]), int.parse(match[7]), "<fn>");
+ }
+ }
+
+ /// Parses a string representation of a Firefox stack frame.
+ factory Frame.parseFirefox(String frame) {
+ var match = _firefoxFrame.firstMatch(frame);
+ if (match == null) {
+ throw new FormatException(
+ "Couldn't parse Firefox stack trace line '$frame'.");
+ }
+
+ var uri = Uri.parse(match[3]);
+ var member = match[1];
+ if (member == "") {
+ member = "<fn>";
+ } else if (match[2] != null) {
+ member = "$member.<fn>";
+ }
+ // Some Firefox members have initial dots. We remove them for consistency
+ // with other platforms.
+ member = member.replaceFirst(_initialDot, '');
+ return new Frame(uri, int.parse(match[4]), null, member);
+ }
+
Frame(this.uri, this.line, this.column, this.member);
String toString() => '$location in $member';
diff --git a/pkg/stack_trace/lib/src/trace.dart b/pkg/stack_trace/lib/src/trace.dart
index db0e70b..db7a404 100644
--- a/pkg/stack_trace/lib/src/trace.dart
+++ b/pkg/stack_trace/lib/src/trace.dart
@@ -12,6 +12,13 @@
final _terseRegExp = new RegExp(r"(-patch)?(/.*)?$");
+/// A RegExp to match Firefox's stack traces.
+///
+/// Firefox's trace frames start with the name of the function in which the
+/// error occurred, possibly including its parameters inside `()`. For example,
+/// `.VW.call$0("arg")@http://pub.dartlang.org/stuff.dart.js:560`.
+final _firefoxTrace = new RegExp(r"^([.0-9A-Za-z_$/<]*|\(.*\))*@");
+
/// A stack trace, comprised of a list of stack frames.
class Trace implements StackTrace {
/// The stack frames that comprise this stack trace.
@@ -57,9 +64,30 @@
/// Parses a string representation of a stack trace.
///
- /// [trace] should be formatted in the same way as native stack traces.
- Trace.parse(String trace)
- : this(trace.trim().split("\n").map((line) => new Frame.parse(line)));
+ /// [trace] should be formatted in the same way as a Dart VM or browser stack
+ /// trace.
+ factory Trace.parse(String trace) {
+ if (trace.isEmpty) return new Trace(<Frame>[]);
+ if (trace.startsWith("Error\n")) return new Trace.parseV8(trace);
+ if (trace.contains(_firefoxTrace)) return new Trace.parseFirefox(trace);
+
+ // Default to parsing the stack trace as a VM trace. This is also hit on IE
+ // and Safari, where the stack trace is just an empty string (issue 11257).
+ return new Trace.parseVM(trace);
+ }
+
+ /// Parses a string representation of a Dart VM stack trace.
+ Trace.parseVM(String trace)
+ : this(trace.trim().split("\n").map((line) => new Frame.parseVM(line)));
+
+ /// Parses a string representation of a Chrome/V8 stack trace.
+ Trace.parseV8(String trace)
+ : this(trace.split("\n").skip(1).map((line) => new Frame.parseV8(line)));
+
+ /// Parses a string representation of a Firefox stack trace.
+ Trace.parseFirefox(String trace)
+ : this(trace.trim().split("\n")
+ .map((line) => new Frame.parseFirefox(line)));
/// Returns a new [Trace] comprised of [frames].
Trace(Iterable<Frame> frames)
@@ -115,10 +143,9 @@
/// Returns a human-readable string representation of [this].
String toString() {
- if (frames.length == '') return '';
-
// Figure out the longest path so we know how much to pad.
- var longest = frames.map((frame) => frame.location.length).reduce(math.max);
+ var longest = frames.map((frame) => frame.location.length)
+ .fold(0, math.max);
// Print out the stack trace nicely formatted.
return frames.map((frame) {
diff --git a/pkg/stack_trace/test/frame_test.dart b/pkg/stack_trace/test/frame_test.dart
index a140670..2ab310c 100644
--- a/pkg/stack_trace/test/frame_test.dart
+++ b/pkg/stack_trace/test/frame_test.dart
@@ -4,73 +4,190 @@
library frame_test;
-import 'dart:io';
-
import 'package:pathos/path.dart' as path;
import 'package:stack_trace/stack_trace.dart';
import 'package:unittest/unittest.dart';
-String getStackFrame() {
- try {
- throw '';
- } catch (_, stackTrace) {
- return stackTrace.toString().split("\n").first;
- }
-}
-
-Frame getCaller([int level]) {
- if (level == null) return new Frame.caller();
- return new Frame.caller(level);
-}
-
-Frame nestedGetCaller(int level) => getCaller(level);
-
void main() {
- test('parses a stack frame correctly', () {
- var frame = new Frame.parse("#1 Foo._bar "
- "(file:///home/nweiz/code/stuff.dart:42:21)");
- expect(frame.uri, equals(Uri.parse("file:///home/nweiz/code/stuff.dart")));
- expect(frame.line, equals(42));
- expect(frame.column, equals(21));
- expect(frame.member, equals('Foo._bar'));
+ group('.parseVM', () {
+ test('parses a stack frame correctly', () {
+ var frame = new Frame.parseVM("#1 Foo._bar "
+ "(file:///home/nweiz/code/stuff.dart:42:21)");
+ expect(frame.uri,
+ equals(Uri.parse("file:///home/nweiz/code/stuff.dart")));
+ expect(frame.line, equals(42));
+ expect(frame.column, equals(21));
+ expect(frame.member, equals('Foo._bar'));
+ });
+
+ test('converts "<anonymous closure>" to "<fn>"', () {
+ String parsedMember(String member) =>
+ new Frame.parseVM('#0 $member (foo:0:0)').member;
+
+ expect(parsedMember('Foo.<anonymous closure>'), equals('Foo.<fn>'));
+ expect(parsedMember('<anonymous closure>.<anonymous closure>.bar'),
+ equals('<fn>.<fn>.bar'));
+ });
+
+ test('throws a FormatException for malformed frames', () {
+ expect(() => new Frame.parseVM(''), throwsFormatException);
+ expect(() => new Frame.parseVM('#1'), throwsFormatException);
+ expect(() => new Frame.parseVM('#1 Foo'), throwsFormatException);
+ expect(() => new Frame.parseVM('#1 Foo (dart:async/future.dart)'),
+ throwsFormatException);
+ expect(() => new Frame.parseVM('#1 Foo (dart:async/future.dart:10)'),
+ throwsFormatException);
+ expect(() => new Frame.parseVM('#1 (dart:async/future.dart:10:15)'),
+ throwsFormatException);
+ expect(() => new Frame.parseVM('Foo (dart:async/future.dart:10:15)'),
+ throwsFormatException);
+ });
});
- test('parses a real stack frame correctly', () {
- var frame = new Frame.parse(getStackFrame());
- // TODO(nweiz): use URL-style paths when such a thing exists.
- var builder = new path.Builder(style: path.Style.posix);
- expect(builder.basename(frame.uri.path), equals('frame_test.dart'));
- expect(frame.line, equals(15));
- expect(frame.column, equals(5));
- expect(frame.member, equals('getStackFrame'));
+ group('.parseV8', () {
+ test('parses a stack frame correctly', () {
+ var frame = new Frame.parseV8(" at VW.call\$0 "
+ "(http://pub.dartlang.org/stuff.dart.js:560:28)");
+ expect(frame.uri,
+ equals(Uri.parse("http://pub.dartlang.org/stuff.dart.js")));
+ expect(frame.line, equals(560));
+ expect(frame.column, equals(28));
+ expect(frame.member, equals('VW.call\$0'));
+ });
+
+ test('parses an anonymous stack frame correctly', () {
+ var frame = new Frame.parseV8(
+ " at http://pub.dartlang.org/stuff.dart.js:560:28");
+ expect(frame.uri,
+ equals(Uri.parse("http://pub.dartlang.org/stuff.dart.js")));
+ expect(frame.line, equals(560));
+ expect(frame.column, equals(28));
+ expect(frame.member, equals('<fn>'));
+ });
+
+ test('converts "<anonymous>" to "<fn>"', () {
+ String parsedMember(String member) =>
+ new Frame.parseV8(' at $member (foo:0:0)').member;
+
+ expect(parsedMember('Foo.<anonymous>'), equals('Foo.<fn>'));
+ expect(parsedMember('<anonymous>.<anonymous>.bar'),
+ equals('<fn>.<fn>.bar'));
+ });
+
+ test('throws a FormatException for malformed frames', () {
+ expect(() => new Frame.parseV8(''), throwsFormatException);
+ expect(() => new Frame.parseV8(' at'), throwsFormatException);
+ expect(() => new Frame.parseV8(' at Foo'), throwsFormatException);
+ expect(() => new Frame.parseV8(' at Foo (dart:async/future.dart)'),
+ throwsFormatException);
+ expect(() => new Frame.parseV8(' at Foo (dart:async/future.dart:10)'),
+ throwsFormatException);
+ expect(() => new Frame.parseV8(' at (dart:async/future.dart:10:15)'),
+ throwsFormatException);
+ expect(() => new Frame.parseV8('Foo (dart:async/future.dart:10:15)'),
+ throwsFormatException);
+ expect(() => new Frame.parseV8(' at dart:async/future.dart'),
+ throwsFormatException);
+ expect(() => new Frame.parseV8(' at dart:async/future.dart:10'),
+ throwsFormatException);
+ expect(() => new Frame.parseV8('dart:async/future.dart:10:15'),
+ throwsFormatException);
+ });
});
- test('converts "<anonymous closure>" to "<fn>"', () {
- String parsedMember(String member) =>
- new Frame.parse('#0 $member (foo:0:0)').member;
+ group('.parseFirefox', () {
+ test('parses a simple stack frame correctly', () {
+ var frame = new Frame.parseFirefox(
+ ".VW.call\$0@http://pub.dartlang.org/stuff.dart.js:560");
+ expect(frame.uri,
+ equals(Uri.parse("http://pub.dartlang.org/stuff.dart.js")));
+ expect(frame.line, equals(560));
+ expect(frame.column, isNull);
+ expect(frame.member, equals('VW.call\$0'));
+ });
- expect(parsedMember('Foo.<anonymous closure>'), equals('Foo.<fn>'));
- expect(parsedMember('<anonymous closure>.<anonymous closure>.bar'),
- equals('<fn>.<fn>.bar'));
- });
+ test('parses a simple anonymous stack frame correctly', () {
+ var frame = new Frame.parseFirefox(
+ "@http://pub.dartlang.org/stuff.dart.js:560");
+ expect(frame.uri,
+ equals(Uri.parse("http://pub.dartlang.org/stuff.dart.js")));
+ expect(frame.line, equals(560));
+ expect(frame.column, isNull);
+ expect(frame.member, equals("<fn>"));
+ });
- test('throws a FormatException for malformed frames', () {
- expect(() => new Frame.parse(''), throwsFormatException);
- expect(() => new Frame.parse('#1'), throwsFormatException);
- expect(() => new Frame.parse('#1 Foo'), throwsFormatException);
- expect(() => new Frame.parse('#1 Foo (dart:async/future.dart)'),
- throwsFormatException);
- expect(() => new Frame.parse('#1 Foo (dart:async/future.dart:10)'),
- throwsFormatException);
- expect(() => new Frame.parse('#1 (dart:async/future.dart:10:15)'),
- throwsFormatException);
- expect(() => new Frame.parse('Foo (dart:async/future.dart:10:15)'),
- throwsFormatException);
+ test('parses a nested anonymous stack frame correctly', () {
+ var frame = new Frame.parseFirefox(
+ ".foo/<@http://pub.dartlang.org/stuff.dart.js:560");
+ expect(frame.uri,
+ equals(Uri.parse("http://pub.dartlang.org/stuff.dart.js")));
+ expect(frame.line, equals(560));
+ expect(frame.column, isNull);
+ expect(frame.member, equals("foo.<fn>"));
+
+ frame = new Frame.parseFirefox(
+ ".foo/@http://pub.dartlang.org/stuff.dart.js:560");
+ expect(frame.uri,
+ equals(Uri.parse("http://pub.dartlang.org/stuff.dart.js")));
+ expect(frame.line, equals(560));
+ expect(frame.column, isNull);
+ expect(frame.member, equals("foo.<fn>"));
+ });
+
+ test('parses a named nested anonymous stack frame correctly', () {
+ var frame = new Frame.parseFirefox(
+ ".foo/.name<@http://pub.dartlang.org/stuff.dart.js:560");
+ expect(frame.uri,
+ equals(Uri.parse("http://pub.dartlang.org/stuff.dart.js")));
+ expect(frame.line, equals(560));
+ expect(frame.column, isNull);
+ expect(frame.member, equals("foo.<fn>"));
+
+ frame = new Frame.parseFirefox(
+ ".foo/.name@http://pub.dartlang.org/stuff.dart.js:560");
+ expect(frame.uri,
+ equals(Uri.parse("http://pub.dartlang.org/stuff.dart.js")));
+ expect(frame.line, equals(560));
+ expect(frame.column, isNull);
+ expect(frame.member, equals("foo.<fn>"));
+ });
+
+ test('parses a stack frame with parameters correctly', () {
+ var frame = new Frame.parseFirefox(
+ '.foo(12, "@)()/<")@http://pub.dartlang.org/stuff.dart.js:560');
+ expect(frame.uri,
+ equals(Uri.parse("http://pub.dartlang.org/stuff.dart.js")));
+ expect(frame.line, equals(560));
+ expect(frame.column, isNull);
+ expect(frame.member, equals("foo"));
+ });
+
+ test('parses a nested anonymous stack frame with parameters correctly', () {
+ var frame = new Frame.parseFirefox(
+ '.foo(12, "@)()/<")/.fn<@'
+ 'http://pub.dartlang.org/stuff.dart.js:560');
+ expect(frame.uri,
+ equals(Uri.parse("http://pub.dartlang.org/stuff.dart.js")));
+ expect(frame.line, equals(560));
+ expect(frame.column, isNull);
+ expect(frame.member, equals("foo.<fn>"));
+ });
+
+ test('throws a FormatException for malformed frames', () {
+ expect(() => new Frame.parseFirefox(''), throwsFormatException);
+ expect(() => new Frame.parseFirefox('.foo'), throwsFormatException);
+ expect(() => new Frame.parseFirefox('.foo@dart:async/future.dart'),
+ throwsFormatException);
+ expect(() => new Frame.parseFirefox('.foo(@dart:async/future.dart:10'),
+ throwsFormatException);
+ expect(() => new Frame.parseFirefox('@dart:async/future.dart'),
+ throwsFormatException);
+ });
});
test('only considers dart URIs to be core', () {
bool isCore(String library) =>
- new Frame.parse('#0 Foo ($library:0:0)').isCore;
+ new Frame.parseVM('#0 Foo ($library:0:0)').isCore;
expect(isCore('dart:core'), isTrue);
expect(isCore('dart:async'), isTrue);
@@ -82,39 +199,17 @@
expect(isCore('bart:core/uri.dart'), isFalse);
});
- group('.caller()', () {
- test('with no argument returns the parent frame', () {
- expect(getCaller().member, equals('main.<fn>.<fn>'));
- });
-
- test('at level 0 returns the current frame', () {
- expect(getCaller(0).member, equals('getCaller'));
- });
-
- test('at level 1 returns the current frame', () {
- expect(getCaller(1).member, equals('main.<fn>.<fn>'));
- });
-
- test('at level 2 returns the grandparent frame', () {
- expect(nestedGetCaller(2).member, equals('main.<fn>.<fn>'));
- });
-
- test('throws an ArgumentError for negative levels', () {
- expect(() => new Frame.caller(-1), throwsArgumentError);
- });
- });
-
group('.library', () {
test('returns the URI string for non-file URIs', () {
- expect(new Frame.parse('#0 Foo (dart:async/future.dart:0:0)').library,
+ expect(new Frame.parseVM('#0 Foo (dart:async/future.dart:0:0)').library,
equals('dart:async/future.dart'));
- expect(new Frame.parse('#0 Foo '
+ expect(new Frame.parseVM('#0 Foo '
'(http://dartlang.org/stuff/thing.dart:0:0)').library,
equals('http://dartlang.org/stuff/thing.dart'));
});
test('returns the relative path for file URIs', () {
- expect(new Frame.parse('#0 Foo (foo/bar.dart:0:0)').library,
+ expect(new Frame.parseVM('#0 Foo (foo/bar.dart:0:0)').library,
equals('foo/bar.dart'));
});
});
@@ -122,27 +217,27 @@
group('.location', () {
test('returns the library and line/column numbers for non-core '
'libraries', () {
- expect(new Frame.parse('#0 Foo '
+ expect(new Frame.parseVM('#0 Foo '
'(http://dartlang.org/thing.dart:5:10)').location,
equals('http://dartlang.org/thing.dart 5:10'));
- expect(new Frame.parse('#0 Foo (foo/bar.dart:1:2)').location,
+ expect(new Frame.parseVM('#0 Foo (foo/bar.dart:1:2)').location,
equals('foo/bar.dart 1:2'));
});
});
group('.package', () {
test('returns null for non-package URIs', () {
- expect(new Frame.parse('#0 Foo (dart:async/future.dart:0:0)').package,
+ expect(new Frame.parseVM('#0 Foo (dart:async/future.dart:0:0)').package,
isNull);
- expect(new Frame.parse('#0 Foo '
+ expect(new Frame.parseVM('#0 Foo '
'(http://dartlang.org/stuff/thing.dart:0:0)').package,
isNull);
});
test('returns the package name for package: URIs', () {
- expect(new Frame.parse('#0 Foo (package:foo/foo.dart:0:0)').package,
+ expect(new Frame.parseVM('#0 Foo (package:foo/foo.dart:0:0)').package,
equals('foo'));
- expect(new Frame.parse('#0 Foo (package:foo/zap/bar.dart:0:0)').package,
+ expect(new Frame.parseVM('#0 Foo (package:foo/zap/bar.dart:0:0)').package,
equals('foo'));
});
});
@@ -150,13 +245,13 @@
group('.toString()', () {
test('returns the library and line/column numbers for non-core '
'libraries', () {
- expect(new Frame.parse('#0 Foo (http://dartlang.org/thing.dart:5:10)')
+ expect(new Frame.parseVM('#0 Foo (http://dartlang.org/thing.dart:5:10)')
.toString(),
equals('http://dartlang.org/thing.dart 5:10 in Foo'));
});
test('converts "<anonymous closure>" to "<fn>"', () {
- expect(new Frame.parse('#0 Foo.<anonymous closure> '
+ expect(new Frame.parseVM('#0 Foo.<anonymous closure> '
'(dart:core/uri.dart:5:10)').toString(),
equals('dart:core/uri.dart 5:10 in Foo.<fn>'));
});
diff --git a/pkg/stack_trace/test/trace_test.dart b/pkg/stack_trace/test/trace_test.dart
index fcf4fe5..95753a0 100644
--- a/pkg/stack_trace/test/trace_test.dart
+++ b/pkg/stack_trace/test/trace_test.dart
@@ -4,8 +4,6 @@
library trace_test;
-import 'dart:io';
-
import 'package:pathos/path.dart' as path;
import 'package:stack_trace/stack_trace.dart';
import 'package:unittest/unittest.dart';
@@ -31,61 +29,82 @@
Trace nestedGetCurrentTrace(int level) => getCurrentTrace(level);
void main() {
- test('parses a stack trace correctly', () {
- var trace = new Trace.parse('''
-#0 Foo._bar (file:///home/nweiz/code/stuff.dart:42:21)
-#1 zip.<anonymous closure>.zap (dart:async/future.dart:0:2)
-#2 zip.<anonymous closure>.zap (http://pub.dartlang.org/thing.dart:1:100)
-''');
+ // This just shouldn't crash.
+ test('a native stack trace is parseable', () => new Trace.current());
- expect(trace.frames[0].uri,
- equals(Uri.parse("file:///home/nweiz/code/stuff.dart")));
- expect(trace.frames[1].uri, equals(Uri.parse("dart:async/future.dart")));
- expect(trace.frames[2].uri,
- equals(Uri.parse("http://pub.dartlang.org/thing.dart")));
- });
+ group('.parse', () {
+ test('.parse parses a VM stack trace correctly', () {
+ var trace = new Trace.parse(
+ '#0 Foo._bar (file:///home/nweiz/code/stuff.dart:42:21)\n'
+ '#1 zip.<anonymous closure>.zap (dart:async/future.dart:0:2)\n'
+ '#2 zip.<anonymous closure>.zap (http://pub.dartlang.org/thing.'
+ 'dart:1:100)');
- test('parses a real stack trace correctly', () {
- var trace = new Trace.parse(getStackTraceString());
- // TODO(nweiz): use URL-style paths when such a thing exists.
- var builder = new path.Builder(style: path.Style.posix);
- expect(builder.basename(trace.frames.first.uri.path),
- equals('trace_test.dart'));
- expect(trace.frames.first.member, equals('getStackTraceString'));
- });
-
- test('converts from a native stack trace correctly', () {
- var trace = new Trace.from(getStackTraceObject());
- // TODO(nweiz): use URL-style paths when such a thing exists.
- var builder = new path.Builder(style: path.Style.posix);
- expect(builder.basename(trace.frames.first.uri.path),
- equals('trace_test.dart'));
- expect(trace.frames.first.member, equals('getStackTraceObject'));
- });
-
- group('.current()', () {
- test('with no argument returns a trace starting at the current frame', () {
- var trace = new Trace.current();
- expect(trace.frames.first.member, equals('main.<fn>.<fn>'));
+ expect(trace.frames[0].uri,
+ equals(Uri.parse("file:///home/nweiz/code/stuff.dart")));
+ expect(trace.frames[1].uri, equals(Uri.parse("dart:async/future.dart")));
+ expect(trace.frames[2].uri,
+ equals(Uri.parse("http://pub.dartlang.org/thing.dart")));
});
- test('at level 0 returns a trace starting at the current frame', () {
- var trace = new Trace.current(0);
- expect(trace.frames.first.member, equals('main.<fn>.<fn>'));
+ test('parses a V8 stack trace correctly', () {
+ var trace = new Trace.parse(
+ 'Error\n'
+ ' at Foo._bar (http://pub.dartlang.org/stuff.js:42:21)\n'
+ ' at http://pub.dartlang.org/stuff.js:0:2\n'
+ ' at zip.<anonymous>.zap '
+ '(http://pub.dartlang.org/thing.js:1:100)');
+
+ expect(trace.frames[0].uri,
+ equals(Uri.parse("http://pub.dartlang.org/stuff.js")));
+ expect(trace.frames[1].uri,
+ equals(Uri.parse("http://pub.dartlang.org/stuff.js")));
+ expect(trace.frames[2].uri,
+ equals(Uri.parse("http://pub.dartlang.org/thing.js")));
});
- test('at level 1 returns a trace starting at the parent frame', () {
- var trace = getCurrentTrace(1);
- expect(trace.frames.first.member, equals('main.<fn>.<fn>'));
+ test('parses a Firefox stack trace correctly', () {
+ var trace = new Trace.parse(
+ 'Foo._bar@http://pub.dartlang.org/stuff.js:42\n'
+ 'zip/<@http://pub.dartlang.org/stuff.js:0\n'
+ 'zip.zap(12, "@)()/<")@http://pub.dartlang.org/thing.js:1');
+
+ expect(trace.frames[0].uri,
+ equals(Uri.parse("http://pub.dartlang.org/stuff.js")));
+ expect(trace.frames[1].uri,
+ equals(Uri.parse("http://pub.dartlang.org/stuff.js")));
+ expect(trace.frames[2].uri,
+ equals(Uri.parse("http://pub.dartlang.org/thing.js")));
+
+ trace = new Trace.parse(
+ 'zip/<@http://pub.dartlang.org/stuff.js:0\n'
+ 'Foo._bar@http://pub.dartlang.org/stuff.js:42\n'
+ 'zip.zap(12, "@)()/<")@http://pub.dartlang.org/thing.js:1');
+
+ expect(trace.frames[0].uri,
+ equals(Uri.parse("http://pub.dartlang.org/stuff.js")));
+ expect(trace.frames[1].uri,
+ equals(Uri.parse("http://pub.dartlang.org/stuff.js")));
+ expect(trace.frames[2].uri,
+ equals(Uri.parse("http://pub.dartlang.org/thing.js")));
+
+ trace = new Trace.parse(
+ 'zip.zap(12, "@)()/<")@http://pub.dartlang.org/thing.js:1\n'
+ 'zip/<@http://pub.dartlang.org/stuff.js:0\n'
+ 'Foo._bar@http://pub.dartlang.org/stuff.js:42');
+
+ expect(trace.frames[0].uri,
+ equals(Uri.parse("http://pub.dartlang.org/thing.js")));
+ expect(trace.frames[1].uri,
+ equals(Uri.parse("http://pub.dartlang.org/stuff.js")));
+ expect(trace.frames[2].uri,
+ equals(Uri.parse("http://pub.dartlang.org/stuff.js")));
});
- test('at level 2 returns a trace starting at the grandparent frame', () {
- var trace = nestedGetCurrentTrace(2);
- expect(trace.frames.first.member, equals('main.<fn>.<fn>'));
- });
-
- test('throws an ArgumentError for negative levels', () {
- expect(() => new Trace.current(-1), throwsArgumentError);
+ test('parses an empty string correctly', () {
+ var trace = new Trace.parse('');
+ expect(trace.frames, isEmpty);
+ expect(trace.toString(), equals(''));
});
});
diff --git a/pkg/stack_trace/test/vm_test.dart b/pkg/stack_trace/test/vm_test.dart
new file mode 100644
index 0000000..38b2b80
--- /dev/null
+++ b/pkg/stack_trace/test/vm_test.dart
@@ -0,0 +1,109 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// This file tests stack_trace's ability to parse live stack traces. It's a
+/// dual of dartium_test.dart, since method names can differ somewhat from
+/// platform to platform. No similar file exists for dart2js since the specific
+/// method names there are implementation details.
+
+import 'package:pathos/path.dart' as path;
+import 'package:stack_trace/stack_trace.dart';
+import 'package:unittest/unittest.dart';
+
+String getStackTraceString() {
+ try {
+ throw '';
+ } catch (_, stackTrace) {
+ return stackTrace.toString();
+ }
+}
+
+StackTrace getStackTraceObject() {
+ try {
+ throw '';
+ } catch (_, stackTrace) {
+ return stackTrace;
+ }
+}
+
+Frame getCaller([int level]) {
+ if (level == null) return new Frame.caller();
+ return new Frame.caller(level);
+}
+
+Frame nestedGetCaller(int level) => getCaller(level);
+
+Trace getCurrentTrace([int level]) => new Trace.current(level);
+
+Trace nestedGetCurrentTrace(int level) => getCurrentTrace(level);
+
+void main() {
+ group('Trace', () {
+ test('.parse parses a real stack trace correctly', () {
+ var string = getStackTraceString();
+ var trace = new Trace.parse(string);
+ var builder = new path.Builder(style: path.Style.url);
+ expect(builder.basename(trace.frames.first.uri.path),
+ equals('vm_test.dart'));
+ expect(trace.frames.first.member, equals('getStackTraceString'));
+ });
+
+ test('converts from a native stack trace correctly', () {
+ var trace = new Trace.from(getStackTraceObject());
+ var builder = new path.Builder(style: path.Style.url);
+ expect(builder.basename(trace.frames.first.uri.path),
+ equals('vm_test.dart'));
+ expect(trace.frames.first.member, equals('getStackTraceObject'));
+ });
+
+ group('.current()', () {
+ test('with no argument returns a trace starting at the current frame',
+ () {
+ var trace = new Trace.current();
+ expect(trace.frames.first.member, equals('main.<fn>.<fn>.<fn>'));
+ });
+
+ test('at level 0 returns a trace starting at the current frame', () {
+ var trace = new Trace.current(0);
+ expect(trace.frames.first.member, equals('main.<fn>.<fn>.<fn>'));
+ });
+
+ test('at level 1 returns a trace starting at the parent frame', () {
+ var trace = getCurrentTrace(1);
+ expect(trace.frames.first.member, equals('main.<fn>.<fn>.<fn>'));
+ });
+
+ test('at level 2 returns a trace starting at the grandparent frame', () {
+ var trace = nestedGetCurrentTrace(2);
+ expect(trace.frames.first.member, equals('main.<fn>.<fn>.<fn>'));
+ });
+
+ test('throws an ArgumentError for negative levels', () {
+ expect(() => new Trace.current(-1), throwsArgumentError);
+ });
+ });
+ });
+
+ group('Frame.caller()', () {
+ test('with no argument returns the parent frame', () {
+ expect(getCaller().member, equals('main.<fn>.<fn>'));
+ });
+
+ test('at level 0 returns the current frame', () {
+ expect(getCaller(0).member, equals('getCaller'));
+ });
+
+ test('at level 1 returns the current frame', () {
+ expect(getCaller(1).member, equals('main.<fn>.<fn>'));
+ });
+
+ test('at level 2 returns the grandparent frame', () {
+ expect(nestedGetCaller(2).member, equals('main.<fn>.<fn>'));
+ });
+
+ test('throws an ArgumentError for negative levels', () {
+ expect(() => new Frame.caller(-1), throwsArgumentError);
+ });
+ });
+}
diff --git a/pkg/unittest/test/instance_test.dart b/pkg/unittest/test/instance_test.dart
index cac6ca0..d9e9875 100644
--- a/pkg/unittest/test/instance_test.dart
+++ b/pkg/unittest/test/instance_test.dart
@@ -21,7 +21,7 @@
shouldPass(doesThrow, throwsA(equals('X')));
shouldFail(doesThrow, throwsA(equals('Y')),
"Expected: throws 'Y' "
- "Actual: <Closure: (dynamic) => dynamic "
+ "Actual: <Closure: () => dynamic "
"from Function 'doesThrow': static.> "
"Which: threw 'X'");
});
diff --git a/pkg/unittest/test/matchers_minified_test.dart b/pkg/unittest/test/matchers_minified_test.dart
index d9ee642..787c9e1 100644
--- a/pkg/unittest/test/matchers_minified_test.dart
+++ b/pkg/unittest/test/matchers_minified_test.dart
@@ -25,7 +25,7 @@
throwsFormatException,
matches(
r"Expected: throws FormatException +"
- r"Actual: <Closure(: \(dynamic\) => dynamic)?> +"
+ r"Actual: <Closure(: \(\) => dynamic)?> +"
r"Which: threw " + _minifiedName + r":<Exception>"));
});
@@ -36,7 +36,7 @@
throwsArgumentError,
matches(
r"Expected: throws ArgumentError +"
- r"Actual: <Closure(: \(dynamic\) => dynamic)?> +"
+ r"Actual: <Closure(: \(\) => dynamic)?> +"
r"Which: threw " + _minifiedName + r":<Exception>"));
});
@@ -47,7 +47,7 @@
throwsRangeError,
matches(
r"Expected: throws RangeError +"
- r"Actual: <Closure(: \(dynamic\) => dynamic)?> +"
+ r"Actual: <Closure(: \(\) => dynamic)?> +"
r"Which: threw " + _minifiedName + r":<Exception>"));
});
@@ -58,7 +58,7 @@
throwsNoSuchMethodError,
matches(
r"Expected: throws NoSuchMethodError +"
- r"Actual: <Closure(: \(dynamic\) => dynamic)?> +"
+ r"Actual: <Closure(: \(\) => dynamic)?> +"
r"Which: threw " + _minifiedName + r":<Exception>"));
});
@@ -69,7 +69,7 @@
throwsUnimplementedError,
matches(
r"Expected: throws UnimplementedError +"
- r"Actual: <Closure(: \(dynamic\) => dynamic)?> +"
+ r"Actual: <Closure(: \(\) => dynamic)?> +"
r"Which: threw " + _minifiedName + r":<Exception>"));
});
@@ -80,7 +80,7 @@
throwsUnsupportedError,
matches(
r"Expected: throws UnsupportedError +"
- r"Actual: <Closure(: \(dynamic\) => dynamic)?> +"
+ r"Actual: <Closure(: \(\) => dynamic)?> +"
r"Which: threw " + _minifiedName + r":<Exception>"));
});
@@ -91,7 +91,7 @@
throwsStateError,
matches(
r"Expected: throws StateError +"
- r"Actual: <Closure(: \(dynamic\) => dynamic)?> +"
+ r"Actual: <Closure(: \(\) => dynamic)?> +"
r"Which: threw " + _minifiedName + r":<Exception>"));
});
});
diff --git a/pkg/unittest/test/matchers_test.dart b/pkg/unittest/test/matchers_test.dart
index ebe87e9..51020b7 100644
--- a/pkg/unittest/test/matchers_test.dart
+++ b/pkg/unittest/test/matchers_test.dart
@@ -65,7 +65,7 @@
shouldFail(doesNotThrow, throws,
matches(
r"Expected: throws"
- r" Actual: <Closure(: \(dynamic\) => dynamic "
+ r" Actual: <Closure(: \(\) => dynamic "
r"from Function 'doesNotThrow': static\.)?>"
r" Which: did not throw"));
shouldPass(doesThrow, throws);
@@ -80,7 +80,7 @@
shouldFail(doesThrow, throwsA(equals('Y')),
matches(
r"Expected: throws 'Y'"
- r" Actual: <Closure(: \(dynamic\) => dynamic "
+ r" Actual: <Closure(: \(\) => dynamic "
r"from Function 'doesThrow': static\.)?>"
r" Which: threw 'X'"));
});
@@ -90,7 +90,7 @@
shouldFail(doesThrow, returnsNormally,
matches(
r"Expected: return normally"
- r" Actual: <Closure(: \(dynamic\) => dynamic "
+ r" Actual: <Closure(: \(\) => dynamic "
r"from Function 'doesThrow': static\.)?>"
r" Which: threw 'X'"));
});
diff --git a/pkg/unittest/test/matchers_unminified_test.dart b/pkg/unittest/test/matchers_unminified_test.dart
index 11fb2e9..8a1b005 100644
--- a/pkg/unittest/test/matchers_unminified_test.dart
+++ b/pkg/unittest/test/matchers_unminified_test.dart
@@ -23,7 +23,7 @@
throwsFormatException,
matches(
r"Expected: throws FormatException +"
- r"Actual: <Closure(: \(dynamic\) => dynamic)?> +"
+ r"Actual: <Closure(: \(\) => dynamic)?> +"
r"Which: threw \?:<Exception>"));
});
@@ -35,7 +35,7 @@
throwsArgumentError,
matches(
r"Expected: throws ArgumentError +"
- r"Actual: <Closure(: \(dynamic\) => dynamic)?> +"
+ r"Actual: <Closure(: \(\) => dynamic)?> +"
r"Which: threw \?:<Exception>"));
});
@@ -46,7 +46,7 @@
throwsRangeError,
matches(
r"Expected: throws RangeError +"
- r"Actual: <Closure(: \(dynamic\) => dynamic)?> +"
+ r"Actual: <Closure(: \(\) => dynamic)?> +"
r"Which: threw \?:<Exception>"));
});
@@ -57,7 +57,7 @@
throwsNoSuchMethodError,
matches(
r"Expected: throws NoSuchMethodError +"
- r"Actual: <Closure(: \(dynamic\) => dynamic)?> +"
+ r"Actual: <Closure(: \(\) => dynamic)?> +"
r"Which: threw \?:<Exception>"));
});
@@ -68,7 +68,7 @@
throwsUnimplementedError,
matches(
r"Expected: throws UnimplementedError +"
- r"Actual: <Closure(: \(dynamic\) => dynamic)?> +"
+ r"Actual: <Closure(: \(\) => dynamic)?> +"
r"Which: threw \?:<Exception>"));
});
@@ -79,7 +79,7 @@
throwsUnsupportedError,
matches(
r"Expected: throws UnsupportedError +"
- r"Actual: <Closure(: \(dynamic\) => dynamic)?> +"
+ r"Actual: <Closure(: \(\) => dynamic)?> +"
r"Which: threw \?:<Exception>"));
});
@@ -90,7 +90,7 @@
throwsStateError,
matches(
r"Expected: throws StateError +"
- r"Actual: <Closure(: \(dynamic\) => dynamic)?> +"
+ r"Actual: <Closure(: \(\) => dynamic)?> +"
r"Which: threw \?:<Exception>"));
});
});
diff --git a/pkg/unittest/test/pretty_print_test.dart b/pkg/unittest/test/pretty_print_test.dart
index e5cd2e2..a0608ac 100644
--- a/pkg/unittest/test/pretty_print_test.dart
+++ b/pkg/unittest/test/pretty_print_test.dart
@@ -12,7 +12,7 @@
expect(prettyPrint(true), equals('<true>'));
expect(prettyPrint(null), equals('<null>'));
expect(prettyPrint(() => 12),
- matches(r'<Closure(: \(dynamic\) => dynamic)?>'));
+ matches(r'<Closure(: \(\) => dynamic)?>'));
});
group('with a string', () {
diff --git a/runtime/bin/eventhandler_android.cc b/runtime/bin/eventhandler_android.cc
index bbc8acb..74fb5da 100644
--- a/runtime/bin/eventhandler_android.cc
+++ b/runtime/bin/eventhandler_android.cc
@@ -14,6 +14,7 @@
#include <sys/epoll.h> // NOLINT
#include <sys/stat.h> // NOLINT
#include <unistd.h> // NOLINT
+#include <fcntl.h> // NOLINT
#include "bin/dartutils.h"
#include "bin/fdutils.h"
@@ -215,7 +216,15 @@
// next message.
RemoveFromEpollInstance(epoll_fd_, sd);
intptr_t fd = sd->fd();
- sd->Close();
+ if (fd == STDOUT_FILENO) {
+ // If stdout, redirect fd to /dev/null.
+ int null_fd = TEMP_FAILURE_RETRY(open("/dev/null", O_WRONLY));
+ ASSERT(null_fd >= 0);
+ VOID_TEMP_FAILURE_RETRY(dup2(null_fd, STDOUT_FILENO));
+ VOID_TEMP_FAILURE_RETRY(close(null_fd));
+ } else {
+ sd->Close();
+ }
socket_map_.Remove(GetHashmapKeyFromFd(fd), GetHashmapHashFromFd(fd));
delete sd;
} else {
diff --git a/runtime/bin/eventhandler_linux.cc b/runtime/bin/eventhandler_linux.cc
index aa852d1..9ed591a 100644
--- a/runtime/bin/eventhandler_linux.cc
+++ b/runtime/bin/eventhandler_linux.cc
@@ -14,6 +14,7 @@
#include <sys/epoll.h> // NOLINT
#include <sys/stat.h> // NOLINT
#include <unistd.h> // NOLINT
+#include <fcntl.h> // NOLINT
#include "bin/dartutils.h"
#include "bin/fdutils.h"
@@ -223,7 +224,15 @@
// next message.
RemoveFromEpollInstance(epoll_fd_, sd);
intptr_t fd = sd->fd();
- sd->Close();
+ if (fd == STDOUT_FILENO) {
+ // If stdout, redirect fd to /dev/null.
+ int null_fd = TEMP_FAILURE_RETRY(open("/dev/null", O_WRONLY));
+ ASSERT(null_fd >= 0);
+ VOID_TEMP_FAILURE_RETRY(dup2(null_fd, STDOUT_FILENO));
+ VOID_TEMP_FAILURE_RETRY(close(null_fd));
+ } else {
+ sd->Close();
+ }
socket_map_.Remove(GetHashmapKeyFromFd(fd), GetHashmapHashFromFd(fd));
delete sd;
} else {
diff --git a/runtime/bin/eventhandler_macos.cc b/runtime/bin/eventhandler_macos.cc
index a6554c9..826e600 100644
--- a/runtime/bin/eventhandler_macos.cc
+++ b/runtime/bin/eventhandler_macos.cc
@@ -13,6 +13,7 @@
#include <string.h> // NOLINT
#include <sys/event.h> // NOLINT
#include <unistd.h> // NOLINT
+#include <fcntl.h> // NOLINT
#include "bin/dartutils.h"
#include "bin/fdutils.h"
@@ -235,7 +236,15 @@
// Close the socket and free system resources.
RemoveFromKqueue(kqueue_fd_, sd);
intptr_t fd = sd->fd();
- sd->Close();
+ if (fd == STDOUT_FILENO) {
+ // If stdout, redirect fd to /dev/null.
+ int null_fd = TEMP_FAILURE_RETRY(open("/dev/null", O_WRONLY));
+ ASSERT(null_fd >= 0);
+ VOID_TEMP_FAILURE_RETRY(dup2(null_fd, STDOUT_FILENO));
+ VOID_TEMP_FAILURE_RETRY(close(null_fd));
+ } else {
+ sd->Close();
+ }
socket_map_.Remove(GetHashmapKeyFromFd(fd), GetHashmapHashFromFd(fd));
delete sd;
} else {
diff --git a/runtime/bin/eventhandler_win.cc b/runtime/bin/eventhandler_win.cc
index 7c96ce8..f1257c3 100644
--- a/runtime/bin/eventhandler_win.cc
+++ b/runtime/bin/eventhandler_win.cc
@@ -11,6 +11,8 @@
#include <winsock2.h> // NOLINT
#include <ws2tcpip.h> // NOLINT
#include <mswsock.h> // NOLINT
+#include <io.h> // NOLINT
+#include <fcntl.h> // NOLINT
#include "bin/builtin.h"
#include "bin/dartutils.h"
@@ -326,6 +328,18 @@
}
+void FileHandle::DoClose() {
+ if (GetStdHandle(STD_OUTPUT_HANDLE) == handle_) {
+ int fd = _open("NUL", _O_WRONLY);
+ ASSERT(fd >= 0);
+ _dup2(fd, _fileno(stdout));
+ close(fd);
+ } else {
+ Handle::DoClose();
+ }
+}
+
+
void SocketHandle::HandleIssueError() {
int error = WSAGetLastError();
if (error == WSAECONNRESET) {
diff --git a/runtime/bin/eventhandler_win.h b/runtime/bin/eventhandler_win.h
index 9bb0610..73e8917 100644
--- a/runtime/bin/eventhandler_win.h
+++ b/runtime/bin/eventhandler_win.h
@@ -251,6 +251,7 @@
virtual void EnsureInitialized(EventHandlerImplementation* event_handler);
virtual bool IsClosed();
+ virtual void DoClose();
};
diff --git a/runtime/bin/process.cc b/runtime/bin/process.cc
index df53cd5..a6a5e2c 100644
--- a/runtime/bin/process.cc
+++ b/runtime/bin/process.cc
@@ -16,7 +16,7 @@
static const int kProcessIdNativeField = 0;
int Process::global_exit_code_ = 0;
-dart::Mutex Process::global_exit_code_mutex_;
+dart::Mutex* Process::global_exit_code_mutex_ = new dart::Mutex();
// Extract an array of C strings from a list of Dart strings.
static char** ExtractCStringList(Dart_Handle strings,
diff --git a/runtime/bin/process.h b/runtime/bin/process.h
index c0d8b8b..8e82f39 100644
--- a/runtime/bin/process.h
+++ b/runtime/bin/process.h
@@ -38,12 +38,12 @@
static void TerminateExitCodeHandler();
static int GlobalExitCode() {
- MutexLocker ml(&global_exit_code_mutex_);
+ MutexLocker ml(global_exit_code_mutex_);
return global_exit_code_;
}
static void SetGlobalExitCode(int exit_code) {
- MutexLocker ml(&global_exit_code_mutex_);
+ MutexLocker ml(global_exit_code_mutex_);
global_exit_code_ = exit_code;
}
@@ -56,7 +56,7 @@
private:
static int global_exit_code_;
- static dart::Mutex global_exit_code_mutex_;
+ static dart::Mutex* global_exit_code_mutex_;
DISALLOW_ALLOCATION();
DISALLOW_IMPLICIT_CONSTRUCTORS(Process);
diff --git a/runtime/bin/process_android.cc b/runtime/bin/process_android.cc
index 8fbc446..49df0c5 100644
--- a/runtime/bin/process_android.cc
+++ b/runtime/bin/process_android.cc
@@ -55,7 +55,7 @@
class ProcessInfoList {
public:
static void AddProcess(pid_t pid, intptr_t fd) {
- MutexLocker locker(&mutex_);
+ MutexLocker locker(mutex_);
ProcessInfo* info = new ProcessInfo(pid, fd);
info->set_next(active_processes_);
active_processes_ = info;
@@ -63,7 +63,7 @@
static intptr_t LookupProcessExitFd(pid_t pid) {
- MutexLocker locker(&mutex_);
+ MutexLocker locker(mutex_);
ProcessInfo* current = active_processes_;
while (current != NULL) {
if (current->pid() == pid) {
@@ -76,7 +76,7 @@
static void RemoveProcess(pid_t pid) {
- MutexLocker locker(&mutex_);
+ MutexLocker locker(mutex_);
ProcessInfo* prev = NULL;
ProcessInfo* current = active_processes_;
while (current != NULL) {
@@ -100,12 +100,12 @@
static ProcessInfo* active_processes_;
// Mutex protecting all accesses to the linked list of active
// processes.
- static dart::Mutex mutex_;
+ static dart::Mutex* mutex_;
};
ProcessInfo* ProcessInfoList::active_processes_ = NULL;
-dart::Mutex ProcessInfoList::mutex_;
+dart::Mutex* ProcessInfoList::mutex_ = new dart::Mutex();
// The exit code handler sets up a separate thread which is signalled
@@ -119,7 +119,7 @@
// Multiple isolates could be starting processes at the same
// time. Make sure that only one of them initializes the
// ExitCodeHandler.
- MutexLocker locker(&mutex_);
+ MutexLocker locker(mutex_);
if (initialized_) {
return true;
}
@@ -155,7 +155,7 @@
}
static void TerminateExitCodeThread() {
- MutexLocker locker(&mutex_);
+ MutexLocker locker(mutex_);
if (!initialized_) {
return;
}
@@ -168,7 +168,7 @@
}
{
- MonitorLocker terminate_locker(&thread_terminate_monitor_);
+ MonitorLocker terminate_locker(thread_terminate_monitor_);
while (!thread_terminated_) {
terminate_locker.Wait();
}
@@ -176,7 +176,7 @@
}
static void ExitCodeThreadTerminated() {
- MonitorLocker locker(&thread_terminate_monitor_);
+ MonitorLocker locker(thread_terminate_monitor_);
thread_terminated_ = true;
locker.Notify();
}
@@ -251,19 +251,19 @@
}
}
- static dart::Mutex mutex_;
+ static dart::Mutex* mutex_;
static bool initialized_;
static int sig_chld_fds_[2];
static bool thread_terminated_;
- static dart::Monitor thread_terminate_monitor_;
+ static dart::Monitor* thread_terminate_monitor_;
};
-dart::Mutex ExitCodeHandler::mutex_;
+dart::Mutex* ExitCodeHandler::mutex_ = new dart::Mutex();
bool ExitCodeHandler::initialized_ = false;
int ExitCodeHandler::sig_chld_fds_[2] = { 0, 0 };
bool ExitCodeHandler::thread_terminated_ = false;
-dart::Monitor ExitCodeHandler::thread_terminate_monitor_;
+dart::Monitor* ExitCodeHandler::thread_terminate_monitor_ = new dart::Monitor();
static void SetChildOsErrorMessage(char** os_error_message) {
diff --git a/runtime/bin/process_linux.cc b/runtime/bin/process_linux.cc
index e55cb5d..7d97425 100644
--- a/runtime/bin/process_linux.cc
+++ b/runtime/bin/process_linux.cc
@@ -57,7 +57,7 @@
class ProcessInfoList {
public:
static void AddProcess(pid_t pid, intptr_t fd) {
- MutexLocker locker(&mutex_);
+ MutexLocker locker(mutex_);
ProcessInfo* info = new ProcessInfo(pid, fd);
info->set_next(active_processes_);
active_processes_ = info;
@@ -65,7 +65,7 @@
static intptr_t LookupProcessExitFd(pid_t pid) {
- MutexLocker locker(&mutex_);
+ MutexLocker locker(mutex_);
ProcessInfo* current = active_processes_;
while (current != NULL) {
if (current->pid() == pid) {
@@ -78,7 +78,7 @@
static void RemoveProcess(pid_t pid) {
- MutexLocker locker(&mutex_);
+ MutexLocker locker(mutex_);
ProcessInfo* prev = NULL;
ProcessInfo* current = active_processes_;
while (current != NULL) {
@@ -102,12 +102,12 @@
static ProcessInfo* active_processes_;
// Mutex protecting all accesses to the linked list of active
// processes.
- static dart::Mutex mutex_;
+ static dart::Mutex* mutex_;
};
ProcessInfo* ProcessInfoList::active_processes_ = NULL;
-dart::Mutex ProcessInfoList::mutex_;
+dart::Mutex* ProcessInfoList::mutex_ = new dart::Mutex();
// The exit code handler sets up a separate thread which is signalled
@@ -121,7 +121,7 @@
// Multiple isolates could be starting processes at the same
// time. Make sure that only one of them initializes the
// ExitCodeHandler.
- MutexLocker locker(&mutex_);
+ MutexLocker locker(mutex_);
if (initialized_) {
return true;
}
@@ -157,7 +157,7 @@
}
static void TerminateExitCodeThread() {
- MutexLocker locker(&mutex_);
+ MutexLocker locker(mutex_);
if (!initialized_) {
return;
}
@@ -170,7 +170,7 @@
}
{
- MonitorLocker terminate_locker(&thread_terminate_monitor_);
+ MonitorLocker terminate_locker(thread_terminate_monitor_);
while (!thread_terminated_) {
terminate_locker.Wait();
}
@@ -178,7 +178,7 @@
}
static void ExitCodeThreadTerminated() {
- MonitorLocker locker(&thread_terminate_monitor_);
+ MonitorLocker locker(thread_terminate_monitor_);
thread_terminated_ = true;
locker.Notify();
}
@@ -253,19 +253,19 @@
}
}
- static dart::Mutex mutex_;
+ static dart::Mutex* mutex_;
static bool initialized_;
static int sig_chld_fds_[2];
static bool thread_terminated_;
- static dart::Monitor thread_terminate_monitor_;
+ static dart::Monitor* thread_terminate_monitor_;
};
-dart::Mutex ExitCodeHandler::mutex_;
+dart::Mutex* ExitCodeHandler::mutex_ = new dart::Mutex();
bool ExitCodeHandler::initialized_ = false;
int ExitCodeHandler::sig_chld_fds_[2] = { 0, 0 };
bool ExitCodeHandler::thread_terminated_ = false;
-dart::Monitor ExitCodeHandler::thread_terminate_monitor_;
+dart::Monitor* ExitCodeHandler::thread_terminate_monitor_ = new dart::Monitor();
static void SetChildOsErrorMessage(char** os_error_message) {
diff --git a/runtime/bin/process_macos.cc b/runtime/bin/process_macos.cc
index 43dcc28..3335181 100644
--- a/runtime/bin/process_macos.cc
+++ b/runtime/bin/process_macos.cc
@@ -56,7 +56,7 @@
class ProcessInfoList {
public:
static void AddProcess(pid_t pid, intptr_t fd) {
- MutexLocker locker(&mutex_);
+ MutexLocker locker(mutex_);
ProcessInfo* info = new ProcessInfo(pid, fd);
info->set_next(active_processes_);
active_processes_ = info;
@@ -64,7 +64,7 @@
static intptr_t LookupProcessExitFd(pid_t pid) {
- MutexLocker locker(&mutex_);
+ MutexLocker locker(mutex_);
ProcessInfo* current = active_processes_;
while (current != NULL) {
if (current->pid() == pid) {
@@ -77,7 +77,7 @@
static void RemoveProcess(pid_t pid) {
- MutexLocker locker(&mutex_);
+ MutexLocker locker(mutex_);
ProcessInfo* prev = NULL;
ProcessInfo* current = active_processes_;
while (current != NULL) {
@@ -101,12 +101,12 @@
static ProcessInfo* active_processes_;
// Mutex protecting all accesses to the linked list of active
// processes.
- static dart::Mutex mutex_;
+ static dart::Mutex* mutex_;
};
ProcessInfo* ProcessInfoList::active_processes_ = NULL;
-dart::Mutex ProcessInfoList::mutex_;
+dart::Mutex* ProcessInfoList::mutex_ = new dart::Mutex();
// The exit code handler sets up a separate thread which is signalled
@@ -120,7 +120,7 @@
// Multiple isolates could be starting processes at the same
// time. Make sure that only one of them initializes the
// ExitCodeHandler.
- MutexLocker locker(&mutex_);
+ MutexLocker locker(mutex_);
if (initialized_) {
return true;
}
@@ -156,7 +156,7 @@
}
static void TerminateExitCodeThread() {
- MutexLocker locker(&mutex_);
+ MutexLocker locker(mutex_);
if (!initialized_) {
return;
}
@@ -169,7 +169,7 @@
}
{
- MonitorLocker terminate_locker(&thread_terminate_monitor_);
+ MonitorLocker terminate_locker(thread_terminate_monitor_);
while (!thread_terminated_) {
terminate_locker.Wait();
}
@@ -177,7 +177,7 @@
}
static void ExitCodeThreadTerminated() {
- MonitorLocker locker(&thread_terminate_monitor_);
+ MonitorLocker locker(thread_terminate_monitor_);
thread_terminated_ = true;
locker.Notify();
}
@@ -252,19 +252,19 @@
}
}
- static dart::Mutex mutex_;
+ static dart::Mutex* mutex_;
static bool initialized_;
static int sig_chld_fds_[2];
static bool thread_terminated_;
- static dart::Monitor thread_terminate_monitor_;
+ static dart::Monitor* thread_terminate_monitor_;
};
-dart::Mutex ExitCodeHandler::mutex_;
+dart::Mutex* ExitCodeHandler::mutex_ = new dart::Mutex();
bool ExitCodeHandler::initialized_ = false;
int ExitCodeHandler::sig_chld_fds_[2] = { 0, 0 };
bool ExitCodeHandler::thread_terminated_ = false;
-dart::Monitor ExitCodeHandler::thread_terminate_monitor_;
+dart::Monitor* ExitCodeHandler::thread_terminate_monitor_ = new dart::Monitor();
static void SetChildOsErrorMessage(char** os_error_message) {
diff --git a/runtime/bin/process_win.cc b/runtime/bin/process_win.cc
index 1237f13..f6c809a 100644
--- a/runtime/bin/process_win.cc
+++ b/runtime/bin/process_win.cc
@@ -80,7 +80,7 @@
// is signaled. The callback runs in a independent thread from the OS pool.
// Because the callback depends on the process list containing
// the process, lock the mutex until the process is added to the list.
- MutexLocker locker(&mutex_);
+ MutexLocker locker(mutex_);
HANDLE wait_handle = INVALID_HANDLE_VALUE;
BOOL success = RegisterWaitForSingleObject(
&wait_handle,
@@ -102,7 +102,7 @@
HANDLE* handle,
HANDLE* wait_handle,
HANDLE* pipe) {
- MutexLocker locker(&mutex_);
+ MutexLocker locker(mutex_);
ProcessInfo* current = active_processes_;
while (current != NULL) {
if (current->pid() == pid) {
@@ -117,7 +117,7 @@
}
static void RemoveProcess(DWORD pid) {
- MutexLocker locker(&mutex_);
+ MutexLocker locker(mutex_);
ProcessInfo* prev = NULL;
ProcessInfo* current = active_processes_;
while (current != NULL) {
@@ -186,12 +186,12 @@
static ProcessInfo* active_processes_;
// Mutex protecting all accesses to the linked list of active
// processes.
- static dart::Mutex mutex_;
+ static dart::Mutex* mutex_;
};
ProcessInfo* ProcessInfoList::active_processes_ = NULL;
-dart::Mutex ProcessInfoList::mutex_;
+dart::Mutex* ProcessInfoList::mutex_ = new dart::Mutex();
// Types of pipes to create.
@@ -343,10 +343,10 @@
static bool EnsureInitialized() {
static bool load_attempted = false;
- static dart::Mutex mutex;
+ static dart::Mutex* mutex = new dart::Mutex();
HMODULE kernel32_module = GetModuleHandleW(L"kernel32.dll");
if (!load_attempted) {
- MutexLocker locker(&mutex);
+ MutexLocker locker(mutex);
if (load_attempted) return delete_proc_thread_attr_list != NULL;
init_proc_thread_attr_list = reinterpret_cast<InitProcThreadAttrListFn>(
GetProcAddress(kernel32_module, "InitializeProcThreadAttributeList"));
diff --git a/runtime/bin/secure_socket.cc b/runtime/bin/secure_socket.cc
index e6aacd7..1cfc508 100644
--- a/runtime/bin/secure_socket.cc
+++ b/runtime/bin/secure_socket.cc
@@ -36,7 +36,8 @@
namespace bin {
bool SSLFilter::library_initialized_ = false;
-dart::Mutex SSLFilter::mutex_; // To protect library initialization.
+// To protect library initialization.
+dart::Mutex* SSLFilter::mutex_ = new dart::Mutex();
// The password is needed when creating secure server sockets. It can
// be null if only secure client sockets are used.
const char* SSLFilter::password_ = NULL;
@@ -527,7 +528,7 @@
const char* password,
bool use_builtin_root_certificates,
bool report_duplicate_initialization) {
- MutexLocker locker(&mutex_);
+ MutexLocker locker(mutex_);
SECStatus status;
if (!library_initialized_) {
password_ = strdup(password); // This one copy persists until Dart exits.
@@ -536,7 +537,7 @@
if (certificate_database == NULL || certificate_database[0] == '\0') {
status = NSS_NoDB_Init(NULL);
if (status != SECSuccess) {
- mutex_.Unlock(); // MutexLocker destructor not called when throwing.
+ mutex_->Unlock(); // MutexLocker destructor not called when throwing.
ThrowPRException("TlsException",
"Failed NSS_NoDB_Init call.");
}
@@ -544,7 +545,7 @@
SECMODModule* module = SECMOD_LoadUserModule(
const_cast<char*>(builtin_roots_module), NULL, PR_FALSE);
if (!module) {
- mutex_.Unlock(); // MutexLocker destructor not called when throwing.
+ mutex_->Unlock(); // MutexLocker destructor not called when throwing.
ThrowPRException("TlsException",
"Failed to load builtin root certificates.");
}
@@ -560,7 +561,7 @@
SECMOD_DB,
init_flags);
if (status != SECSuccess) {
- mutex_.Unlock(); // MutexLocker destructor not called when throwing.
+ mutex_->Unlock(); // MutexLocker destructor not called when throwing.
ThrowPRException("TlsException",
"Failed NSS_Init call.");
}
@@ -569,26 +570,26 @@
status = NSS_SetDomesticPolicy();
if (status != SECSuccess) {
- mutex_.Unlock(); // MutexLocker destructor not called when throwing.
+ mutex_->Unlock(); // MutexLocker destructor not called when throwing.
ThrowPRException("TlsException",
"Failed NSS_SetDomesticPolicy call.");
}
// Enable TLS, as well as SSL3 and SSL2.
status = SSL_OptionSetDefault(SSL_ENABLE_TLS, PR_TRUE);
if (status != SECSuccess) {
- mutex_.Unlock(); // MutexLocker destructor not called when throwing.
+ mutex_->Unlock(); // MutexLocker destructor not called when throwing.
ThrowPRException("TlsException",
"Failed SSL_OptionSetDefault enable TLS call.");
}
status = SSL_ConfigServerSessionIDCache(0, 0, 0, NULL);
if (status != SECSuccess) {
- mutex_.Unlock(); // MutexLocker destructor not called when throwing.
+ mutex_->Unlock(); // MutexLocker destructor not called when throwing.
ThrowPRException("TlsException",
"Failed SSL_ConfigServerSessionIDCache call.");
}
} else if (report_duplicate_initialization) {
- mutex_.Unlock(); // MutexLocker destructor not called when throwing.
+ mutex_->Unlock(); // MutexLocker destructor not called when throwing.
// Like ThrowPRException, without adding an OSError.
Dart_ThrowException(DartUtils::NewDartIOException("TlsException",
"Called SecureSocket.initialize more than once",
diff --git a/runtime/bin/secure_socket.h b/runtime/bin/secure_socket.h
index 2f8225e..acdcda8 100644
--- a/runtime/bin/secure_socket.h
+++ b/runtime/bin/secure_socket.h
@@ -90,7 +90,7 @@
static const int kMemioBufferSize = 20 * KB;
static bool library_initialized_;
static const char* password_;
- static dart::Mutex mutex_; // To protect library initialization.
+ static dart::Mutex* mutex_; // To protect library initialization.
static NativeService filter_service_;
uint8_t* buffers_[kNumBuffers];
diff --git a/runtime/bin/secure_socket_unsupported.cc b/runtime/bin/secure_socket_unsupported.cc
index a571c85..99e5e3b 100644
--- a/runtime/bin/secure_socket_unsupported.cc
+++ b/runtime/bin/secure_socket_unsupported.cc
@@ -86,5 +86,20 @@
Dart_ExitScope();
}
+
+void FUNCTION_NAME(SecureSocket_FilterPointer)(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(
+ "Secure Sockets unsupported on this platform"));
+ Dart_ExitScope();
+}
} // namespace bin
} // namespace dart
diff --git a/runtime/bin/socket.cc b/runtime/bin/socket.cc
index 41bcc9e..b97661d 100644
--- a/runtime/bin/socket.cc
+++ b/runtime/bin/socket.cc
@@ -20,7 +20,7 @@
static const int kSocketIdNativeField = 0;
-dart::Mutex Socket::mutex_;
+dart::Mutex* Socket::mutex_ = new dart::Mutex();
int Socket::service_ports_size_ = 0;
Dart_Port* Socket::service_ports_ = NULL;
int Socket::service_ports_index_ = 0;
@@ -550,7 +550,7 @@
Dart_Port Socket::GetServicePort() {
- MutexLocker lock(&mutex_);
+ MutexLocker lock(mutex_);
if (service_ports_size_ == 0) {
ASSERT(service_ports_ == NULL);
service_ports_size_ = 16;
diff --git a/runtime/bin/socket.h b/runtime/bin/socket.h
index ffca207..8c6464b 100644
--- a/runtime/bin/socket.h
+++ b/runtime/bin/socket.h
@@ -191,7 +191,7 @@
static Dart_Handle GetSocketIdNativeField(Dart_Handle socket, intptr_t* id);
private:
- static dart::Mutex mutex_;
+ static dart::Mutex* mutex_;
static int service_ports_size_;
static Dart_Port* service_ports_;
static int service_ports_index_;
diff --git a/runtime/bin/socket_android.cc b/runtime/bin/socket_android.cc
index 748f33e..dd0e256 100644
--- a/runtime/bin/socket_android.cc
+++ b/runtime/bin/socket_android.cc
@@ -12,7 +12,6 @@
#include <sys/stat.h> // NOLINT
#include <unistd.h> // NOLINT
#include <netinet/tcp.h> // NOLINT
-#include <ifaddrs.h> // NOLINT
#include "bin/fdutils.h"
#include "bin/file.h"
@@ -246,50 +245,12 @@
}
-static bool ShouldIncludeIfaAddrs(struct ifaddrs* ifa, int lookup_family) {
- int family = ifa->ifa_addr->sa_family;
- if (lookup_family == family) return true;
- if (lookup_family == AF_UNSPEC &&
- (family == AF_INET || family == AF_INET6)) {
- return true;
- }
- return false;
-}
-
-
AddressList<InterfaceSocketAddress>* Socket::ListInterfaces(
int type,
OSError** os_error) {
- struct ifaddrs* ifaddr;
-
- int status = getifaddrs(&ifaddr);
- if (status != 0) {
- ASSERT(*os_error == NULL);
- *os_error = new OSError(status,
- gai_strerror(status),
- OSError::kGetAddressInfo);
- return NULL;
- }
-
- int lookup_family = SocketAddress::FromType(type);
-
- intptr_t count = 0;
- for (struct ifaddrs* ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
- if (ShouldIncludeIfaAddrs(ifa, lookup_family)) count++;
- }
-
- AddressList<InterfaceSocketAddress>* addresses =
- new AddressList<InterfaceSocketAddress>(count);
- int i = 0;
- for (struct ifaddrs* ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
- if (ShouldIncludeIfaAddrs(ifa, lookup_family)) {
- addresses->SetAt(i, new InterfaceSocketAddress(
- ifa->ifa_addr, strdup(ifa->ifa_name)));
- i++;
- }
- }
- freeifaddrs(ifaddr);
- return addresses;
+ // The ifaddrs.h header is not provided on Android. An Android
+ // implementation would have to use IOCTL or netlink.
+ return NULL;
}
@@ -325,11 +286,11 @@
// Test for invalid socket port 65535 (some browsers disallow it).
if (port == 0 && Socket::GetPort(fd) == 65535) {
- // Don't close fd until we have created new. By doing that we ensure another
- // port.
+ // Don't close the socket until we have created a new socket, ensuring
+ // that we do not get the bad port number again.
intptr_t new_fd = CreateBindListen(addr, 0, backlog, v6_only);
int err = errno;
- TEMP_FAILURE_RETRY(close(fd));
+ VOID_TEMP_FAILURE_RETRY(close(fd));
errno = err;
return new_fd;
}
diff --git a/runtime/bin/socket_linux.cc b/runtime/bin/socket_linux.cc
index 1aaba00..e2fdf5c 100644
--- a/runtime/bin/socket_linux.cc
+++ b/runtime/bin/socket_linux.cc
@@ -324,11 +324,11 @@
// Test for invalid socket port 65535 (some browsers disallow it).
if (port == 0 && Socket::GetPort(fd) == 65535) {
- // Don't close fd until we have created new. By doing that we ensure another
- // port.
+ // Don't close the socket until we have created a new socket, ensuring
+ // that we do not get the bad port number again.
intptr_t new_fd = CreateBindListen(addr, 0, backlog, v6_only);
int err = errno;
- TEMP_FAILURE_RETRY(close(fd));
+ VOID_TEMP_FAILURE_RETRY(close(fd));
errno = err;
return new_fd;
}
diff --git a/runtime/bin/socket_macos.cc b/runtime/bin/socket_macos.cc
index b9c6298..66737cd 100644
--- a/runtime/bin/socket_macos.cc
+++ b/runtime/bin/socket_macos.cc
@@ -324,11 +324,11 @@
// Test for invalid socket port 65535 (some browsers disallow it).
if (port == 0 && Socket::GetPort(fd) == 65535) {
- // Don't close fd until we have created new. By doing that we ensure another
- // port.
+ // Don't close the socket until we have created a new socket, ensuring
+ // that we do not get the bad port number again.
intptr_t new_fd = CreateBindListen(addr, 0, backlog, v6_only);
int err = errno;
- TEMP_FAILURE_RETRY(close(fd));
+ VOID_TEMP_FAILURE_RETRY(close(fd));
errno = err;
return new_fd;
}
diff --git a/runtime/embedders/openglui/common/extension.cc b/runtime/embedders/openglui/common/extension.cc
index 3e1885e..6304c3b 100644
--- a/runtime/embedders/openglui/common/extension.cc
+++ b/runtime/embedders/openglui/common/extension.cc
@@ -14,6 +14,7 @@
#include "embedders/openglui/common/log.h"
#include "embedders/openglui/common/opengl.h"
#include "include/dart_api.h"
+#include "include/dart_native_api.h"
Dart_Handle HandleError(Dart_Handle handle) {
if (Dart_IsError(handle)) Dart_PropagateError(handle);
@@ -861,13 +862,13 @@
void WrappedRandomArray(Dart_Port dest_port_id,
Dart_Port reply_port_id,
Dart_CObject* message) {
- if (message->type == Dart_CObject::kArray &&
+ if (message->type == Dart_CObject_kArray &&
2 == message->value.as_array.length) {
// Use .as_array and .as_int32 to access the data in the Dart_CObject.
Dart_CObject* param0 = message->value.as_array.values[0];
Dart_CObject* param1 = message->value.as_array.values[1];
- if (param0->type == Dart_CObject::kInt32 &&
- param1->type == Dart_CObject::kInt32) {
+ if (param0->type == Dart_CObject_kInt32 &&
+ param1->type == Dart_CObject_kInt32) {
int length = param0->value.as_int32;
int seed = param1->value.as_int32;
@@ -875,8 +876,8 @@
if (values != NULL) {
Dart_CObject result;
- result.type = Dart_CObject::kTypedData;
- result.value.as_typed_data.type = Dart_CObject::kUint8Array;
+ result.type = Dart_CObject_kTypedData;
+ result.value.as_typed_data.type = Dart_TypedData_kUint8;
result.value.as_typed_data.values = values;
result.value.as_typed_data.length = length;
Dart_PostCObject(reply_port_id, &result);
@@ -888,7 +889,7 @@
}
}
Dart_CObject result;
- result.type = Dart_CObject::kNull;
+ result.type = Dart_CObject_kNull;
Dart_PostCObject(reply_port_id, &result);
}
diff --git a/runtime/embedders/openglui/openglui_embedder.gypi b/runtime/embedders/openglui/openglui_embedder.gypi
index c67cf90..4b058cc 100644
--- a/runtime/embedders/openglui/openglui_embedder.gypi
+++ b/runtime/embedders/openglui/openglui_embedder.gypi
@@ -24,7 +24,7 @@
'libdart_vm',
'libjscre',
'libdouble_conversion',
- 'generate_version_cc_file',
+ 'generate_version_cc_file#host',
],
'include_dirs': [
'../..',
diff --git a/runtime/lib/mirrors.cc b/runtime/lib/mirrors.cc
index 7825319..efb2d16 100644
--- a/runtime/lib/mirrors.cc
+++ b/runtime/lib/mirrors.cc
@@ -47,11 +47,11 @@
static Dart_Handle MapNew() {
// TODO(turnidge): Switch to an order-preserving map type.
- Dart_Handle cls = Dart_GetClass(CoreLib(), NewString("Map"));
- if (Dart_IsError(cls)) {
- return cls;
+ Dart_Handle type = Dart_GetType(CoreLib(), NewString("Map"), 0, NULL);
+ if (Dart_IsError(type)) {
+ return type;
}
- return Dart_New(cls, Dart_Null(), 0, NULL);
+ return Dart_New(type, Dart_Null(), 0, NULL);
}
@@ -69,11 +69,11 @@
static Dart_Handle IsMirror(Dart_Handle object, bool* is_mirror) {
Dart_Handle cls_name = NewString("Mirror");
- Dart_Handle cls = Dart_GetClass(MirrorLib(), cls_name);
- if (Dart_IsError(cls)) {
- return cls;
+ Dart_Handle type = Dart_GetType(MirrorLib(), cls_name, 0, NULL);
+ if (Dart_IsError(type)) {
+ return type;
}
- Dart_Handle result = Dart_ObjectIsType(object, cls, is_mirror);
+ Dart_Handle result = Dart_ObjectIsType(object, type, is_mirror);
if (Dart_IsError(result)) {
return result;
}
@@ -82,11 +82,11 @@
static Dart_Handle IsMethodMirror(Dart_Handle object, bool* is_mirror) {
Dart_Handle cls_name = NewString("MethodMirror");
- Dart_Handle cls = Dart_GetClass(MirrorLib(), cls_name);
- if (Dart_IsError(cls)) {
- return cls;
+ Dart_Handle type = Dart_GetType(MirrorLib(), cls_name, 0, NULL);
+ if (Dart_IsError(type)) {
+ return type;
}
- Dart_Handle result = Dart_ObjectIsType(object, cls, is_mirror);
+ Dart_Handle result = Dart_ObjectIsType(object, type, is_mirror);
if (Dart_IsError(result)) {
return result;
}
@@ -95,11 +95,11 @@
static Dart_Handle IsVariableMirror(Dart_Handle object, bool* is_mirror) {
Dart_Handle cls_name = NewString("VariableMirror");
- Dart_Handle cls = Dart_GetClass(MirrorLib(), cls_name);
- if (Dart_IsError(cls)) {
- return cls;
+ Dart_Handle type = Dart_GetType(MirrorLib(), cls_name, 0, NULL);
+ if (Dart_IsError(type)) {
+ return type;
}
- Dart_Handle result = Dart_ObjectIsType(object, cls, is_mirror);
+ Dart_Handle result = Dart_ObjectIsType(object, type, is_mirror);
if (Dart_IsError(result)) {
return result;
}
@@ -126,11 +126,11 @@
static Dart_Handle CreateVMReference(Dart_Handle handle) {
// Create the VMReference object.
Dart_Handle cls_name = NewString("VMReference");
- Dart_Handle cls = Dart_GetClass(MirrorLib(), cls_name);
- if (Dart_IsError(cls)) {
- return cls;
+ Dart_Handle type = Dart_GetType(MirrorLib(), cls_name, 0, NULL);
+ if (Dart_IsError(type)) {
+ return type;
}
- Dart_Handle vm_ref = Dart_New(cls, Dart_Null(), 0, NULL);
+ Dart_Handle vm_ref = Dart_New(type, Dart_Null(), 0, NULL);
if (Dart_IsError(vm_ref)) {
return vm_ref;
}
@@ -340,22 +340,22 @@
}
Dart_Handle param_cls_name = NewString("_LocalParameterMirrorImpl");
- Dart_Handle param_cls = Dart_GetClass(MirrorLib(), param_cls_name);
- if (Dart_IsError(param_cls)) {
- return param_cls;
+ Dart_Handle param_type = Dart_GetType(MirrorLib(), param_cls_name, 0, NULL);
+ if (Dart_IsError(param_type)) {
+ return param_type;
}
for (int64_t i = 0; i < param_count; i++) {
- Dart_Handle param_type = Dart_FunctionParameterType(func, i);
- if (Dart_IsError(param_type)) {
- return param_type;
+ Dart_Handle arg_type = Dart_FunctionParameterType(func, i);
+ if (Dart_IsError(arg_type)) {
+ return arg_type;
}
Dart_Handle args[] = {
- CreateLazyMirror(param_type),
+ CreateLazyMirror(arg_type),
Dart_NewBoolean(i >= fixed_param_count), // optional param?
};
Dart_Handle param =
- Dart_New(param_cls, Dart_Null(), ARRAY_SIZE(args), args);
+ Dart_New(param_type, Dart_Null(), ARRAY_SIZE(args), args);
if (Dart_IsError(param)) {
return param;
}
@@ -375,15 +375,15 @@
if (Dart_IsLibrary(target)) {
Dart_Handle cls_name = NewString("_LazyLibraryMirror");
- Dart_Handle cls = Dart_GetClass(MirrorLib(), cls_name);
+ Dart_Handle type = Dart_GetType(MirrorLib(), cls_name, 0, NULL);
Dart_Handle args[] = { Dart_LibraryUrl(target) };
- return Dart_New(cls, Dart_Null(), ARRAY_SIZE(args), args);
+ return Dart_New(type, Dart_Null(), ARRAY_SIZE(args), args);
}
if (Dart_IsClass(target)) {
if (Dart_ClassIsFunctionType(target)) {
Dart_Handle cls_name = NewString("_LazyFunctionTypeMirror");
- Dart_Handle cls = Dart_GetClass(MirrorLib(), cls_name);
+ Dart_Handle type = Dart_GetType(MirrorLib(), cls_name, 0, NULL);
Dart_Handle sig = Dart_ClassGetFunctionTypeSignature(target);
Dart_Handle return_type = Dart_FunctionReturnType(sig);
@@ -395,10 +395,10 @@
CreateLazyMirror(return_type),
CreateParameterMirrorList(sig),
};
- return Dart_New(cls, Dart_Null(), ARRAY_SIZE(args), args);
+ return Dart_New(type, Dart_Null(), ARRAY_SIZE(args), args);
} else {
Dart_Handle cls_name = NewString("_LazyTypeMirror");
- Dart_Handle cls = Dart_GetClass(MirrorLib(), cls_name);
+ Dart_Handle type = Dart_GetType(MirrorLib(), cls_name, 0, NULL);
Dart_Handle lib = Dart_ClassGetLibrary(target);
Dart_Handle lib_url;
if (Dart_IsNull(lib)) {
@@ -407,7 +407,7 @@
lib_url = Dart_LibraryUrl(lib);
}
Dart_Handle args[] = { lib_url, Dart_ClassName(target) };
- return Dart_New(cls, Dart_Null(), ARRAY_SIZE(args), args);
+ return Dart_New(type, Dart_Null(), ARRAY_SIZE(args), args);
}
}
@@ -417,10 +417,10 @@
Dart_Handle owner_mirror = CreateLazyMirror(owner);
Dart_Handle cls_name = NewString("_LazyTypeVariableMirror");
- Dart_Handle cls = Dart_GetClass(MirrorLib(), cls_name);
+ Dart_Handle type = Dart_GetType(MirrorLib(), cls_name, 0, NULL);
Dart_Handle args[] = { var_name, owner_mirror };
- return Dart_New(cls, Dart_Null(), ARRAY_SIZE(args), args);
+ return Dart_New(type, Dart_Null(), ARRAY_SIZE(args), args);
}
UNREACHABLE();
@@ -463,9 +463,9 @@
Dart_Handle owner_mirror) {
ASSERT(Dart_IsTypeVariable(type_var));
Dart_Handle cls_name = NewString("_LocalTypeVariableMirrorImpl");
- Dart_Handle cls = Dart_GetClass(MirrorLib(), cls_name);
- if (Dart_IsError(cls)) {
- return cls;
+ Dart_Handle type = Dart_GetType(MirrorLib(), cls_name, 0, NULL);
+ if (Dart_IsError(type)) {
+ return type;
}
Dart_Handle upper_bound = Dart_TypeVariableUpperBound(type_var);
@@ -478,7 +478,7 @@
owner_mirror,
CreateLazyMirror(upper_bound),
};
- Dart_Handle mirror = Dart_New(cls, Dart_Null(), ARRAY_SIZE(args), args);
+ Dart_Handle mirror = Dart_New(type, Dart_Null(), ARRAY_SIZE(args), args);
return mirror;
}
@@ -527,9 +527,9 @@
Dart_Handle owner,
Dart_Handle owner_mirror) {
Dart_Handle mirror_cls_name = NewString("_LocalTypedefMirrorImpl");
- Dart_Handle mirror_cls = Dart_GetClass(MirrorLib(), mirror_cls_name);
- if (Dart_IsError(mirror_cls)) {
- return mirror_cls;
+ Dart_Handle mirror_type = Dart_GetType(MirrorLib(), mirror_cls_name, 0, NULL);
+ if (Dart_IsError(mirror_type)) {
+ return mirror_type;
}
Dart_Handle referent = Dart_ClassGetTypedefReferent(cls);
@@ -543,7 +543,7 @@
CreateLazyMirror(referent),
};
Dart_Handle mirror =
- Dart_New(mirror_cls, Dart_Null(), ARRAY_SIZE(args), args);
+ Dart_New(mirror_type, Dart_Null(), ARRAY_SIZE(args), args);
return mirror;
}
@@ -565,9 +565,9 @@
}
Dart_Handle cls_name = NewString("_LocalClassMirrorImpl");
- Dart_Handle cls = Dart_GetClass(MirrorLib(), cls_name);
- if (Dart_IsError(cls)) {
- return cls;
+ Dart_Handle type = Dart_GetType(MirrorLib(), cls_name, 0, NULL);
+ if (Dart_IsError(type)) {
+ return type;
}
// TODO(turnidge): Why am I getting Null when I expect Object?
@@ -608,7 +608,7 @@
constructor_map,
type_var_map,
};
- Dart_Handle mirror = Dart_New(cls, Dart_Null(), ARRAY_SIZE(args), args);
+ Dart_Handle mirror = Dart_New(type, Dart_Null(), ARRAY_SIZE(args), args);
return mirror;
}
@@ -618,9 +618,9 @@
Dart_Handle owner_mirror) {
ASSERT(Dart_IsFunction(func));
Dart_Handle mirror_cls_name = NewString("_LocalMethodMirrorImpl");
- Dart_Handle mirror_cls = Dart_GetClass(MirrorLib(), mirror_cls_name);
- if (Dart_IsError(mirror_cls)) {
- return mirror_cls;
+ Dart_Handle mirror_type = Dart_GetType(MirrorLib(), mirror_cls_name, 0, NULL);
+ if (Dart_IsError(mirror_type)) {
+ return mirror_type;
}
bool is_static = false;
@@ -681,7 +681,7 @@
Dart_False(),
};
Dart_Handle mirror =
- Dart_New(mirror_cls, Dart_Null(), ARRAY_SIZE(args), args);
+ Dart_New(mirror_type, Dart_Null(), ARRAY_SIZE(args), args);
return mirror;
}
@@ -691,9 +691,9 @@
Dart_Handle lib_mirror) {
ASSERT(Dart_IsVariable(var));
Dart_Handle cls_name = NewString("_LocalVariableMirrorImpl");
- Dart_Handle cls = Dart_GetClass(MirrorLib(), cls_name);
- if (Dart_IsError(cls)) {
- return cls;
+ Dart_Handle type = Dart_GetType(MirrorLib(), cls_name, 0, NULL);
+ if (Dart_IsError(type)) {
+ return type;
}
bool is_static = false;
@@ -708,19 +708,19 @@
return result;
}
- Dart_Handle type = Dart_VariableType(var);
- if (Dart_IsError(type)) {
- return type;
+ Dart_Handle var_type = Dart_VariableType(var);
+ if (Dart_IsError(var_type)) {
+ return var_type;
}
Dart_Handle args[] = {
var_name,
lib_mirror,
- CreateLazyMirror(type),
+ CreateLazyMirror(var_type),
Dart_NewBoolean(is_static),
Dart_NewBoolean(is_final),
};
- Dart_Handle mirror = Dart_New(cls, Dart_Null(), ARRAY_SIZE(args), args);
+ Dart_Handle mirror = Dart_New(type, Dart_Null(), ARRAY_SIZE(args), args);
return mirror;
}
@@ -924,9 +924,9 @@
static Dart_Handle CreateLibraryMirror(Dart_Handle lib) {
Dart_Handle cls_name = NewString("_LocalLibraryMirrorImpl");
- Dart_Handle cls = Dart_GetClass(MirrorLib(), cls_name);
- if (Dart_IsError(cls)) {
- return cls;
+ Dart_Handle type = Dart_GetType(MirrorLib(), cls_name, 0, NULL);
+ if (Dart_IsError(type)) {
+ return type;
}
Dart_Handle lazy_lib_mirror = CreateLazyMirror(lib);
if (Dart_IsError(lazy_lib_mirror)) {
@@ -942,7 +942,7 @@
Dart_LibraryUrl(lib),
member_map,
};
- Dart_Handle lib_mirror = Dart_New(cls, Dart_Null(), ARRAY_SIZE(args), args);
+ Dart_Handle lib_mirror = Dart_New(type, Dart_Null(), ARRAY_SIZE(args), args);
if (Dart_IsError(lib_mirror)) {
return lib_mirror;
}
@@ -988,23 +988,23 @@
static Dart_Handle CreateIsolateMirror() {
Dart_Handle cls_name = NewString("_LocalIsolateMirrorImpl");
- Dart_Handle cls = Dart_GetClass(MirrorLib(), cls_name);
- if (Dart_IsError(cls)) {
- return cls;
+ Dart_Handle type = Dart_GetType(MirrorLib(), cls_name, 0, NULL);
+ if (Dart_IsError(type)) {
+ return type;
}
Dart_Handle args[] = {
Dart_DebugName(),
CreateLazyMirror(Dart_RootLibrary()),
};
- return Dart_New(cls, Dart_Null(), ARRAY_SIZE(args), args);
+ return Dart_New(type, Dart_Null(), ARRAY_SIZE(args), args);
}
static Dart_Handle CreateMirrorSystem() {
Dart_Handle cls_name = NewString("_LocalMirrorSystemImpl");
- Dart_Handle cls = Dart_GetClass(MirrorLib(), cls_name);
- if (Dart_IsError(cls)) {
- return cls;
+ Dart_Handle type = Dart_GetType(MirrorLib(), cls_name, 0, NULL);
+ if (Dart_IsError(type)) {
+ return type;
}
Dart_Handle libraries = CreateLibrariesMap();
@@ -1016,7 +1016,7 @@
libraries,
CreateIsolateMirror(),
};
- Dart_Handle mirror = Dart_New(cls, Dart_Null(), ARRAY_SIZE(args), args);
+ Dart_Handle mirror = Dart_New(type, Dart_Null(), ARRAY_SIZE(args), args);
if (Dart_IsError(mirror)) {
return mirror;
}
@@ -1027,9 +1027,9 @@
static Dart_Handle CreateNullMirror() {
Dart_Handle cls_name = NewString("_LocalInstanceMirrorImpl");
- Dart_Handle cls = Dart_GetClass(MirrorLib(), cls_name);
- if (Dart_IsError(cls)) {
- return cls;
+ Dart_Handle type = Dart_GetType(MirrorLib(), cls_name, 0, NULL);
+ if (Dart_IsError(type)) {
+ return type;
}
// TODO(turnidge): This is wrong. The Null class is distinct from object.
@@ -1040,7 +1040,7 @@
CreateLazyMirror(object_class),
Dart_Null(),
};
- Dart_Handle mirror = Dart_New(cls, Dart_Null(), ARRAY_SIZE(args), args);
+ Dart_Handle mirror = Dart_New(type, Dart_Null(), ARRAY_SIZE(args), args);
return mirror;
}
@@ -1058,9 +1058,9 @@
if (Dart_IsClosure(instance)) {
Dart_Handle cls_name = NewString("_LocalClosureMirrorImpl");
- Dart_Handle cls = Dart_GetClass(MirrorLib(), cls_name);
- if (Dart_IsError(cls)) {
- return cls;
+ Dart_Handle type = Dart_GetType(MirrorLib(), cls_name, 0, NULL);
+ if (Dart_IsError(type)) {
+ return type;
}
// We set the function field of ClosureMirrors outside of the constructor
// to break the mutual recursion.
@@ -1089,20 +1089,20 @@
instance,
func_mirror,
};
- return Dart_New(cls, Dart_Null(), ARRAY_SIZE(args), args);
+ return Dart_New(type, Dart_Null(), ARRAY_SIZE(args), args);
} else {
Dart_Handle cls_name = NewString("_LocalInstanceMirrorImpl");
- Dart_Handle cls = Dart_GetClass(MirrorLib(), cls_name);
- if (Dart_IsError(cls)) {
- return cls;
+ Dart_Handle type = Dart_GetType(MirrorLib(), cls_name, 0, NULL);
+ if (Dart_IsError(type)) {
+ return type;
}
Dart_Handle args[] = {
CreateVMReference(instance),
CreateLazyMirror(instance_cls),
instance,
};
- return Dart_New(cls, Dart_Null(), ARRAY_SIZE(args), args);
+ return Dart_New(type, Dart_Null(), ARRAY_SIZE(args), args);
}
}
@@ -1128,22 +1128,22 @@
return stack;
}
Dart_Handle cls_name = NewString("MirroredUncaughtExceptionError");
- Dart_Handle cls = Dart_GetClass(MirrorLib(), cls_name);
+ Dart_Handle type = Dart_GetType(MirrorLib(), cls_name, 0, NULL);
Dart_Handle args[] = {
CreateInstanceMirror(exc),
exc_string,
stack,
};
Dart_Handle mirrored_exc =
- Dart_New(cls, Dart_Null(), ARRAY_SIZE(args), args);
+ 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 cls = Dart_GetClass(MirrorLib(), cls_name);
+ Dart_Handle type = Dart_GetType(MirrorLib(), cls_name, 0, NULL);
Dart_Handle args[] = { NewString(Dart_GetError(error)) };
Dart_Handle mirrored_exc =
- Dart_New(cls, Dart_Null(), ARRAY_SIZE(args), args);
+ Dart_New(type, Dart_Null(), ARRAY_SIZE(args), args);
return Dart_NewUnhandledExceptionError(mirrored_exc);
} else {
ASSERT(Dart_IsFatalError(error));
diff --git a/runtime/tools/benchmark.py b/runtime/tools/benchmark.py
index b3a587f..694b87c 100755
--- a/runtime/tools/benchmark.py
+++ b/runtime/tools/benchmark.py
@@ -54,7 +54,7 @@
default=False, action="store_true")
result.add_option("--arch",
help='Target architectures (comma-separated).',
- metavar='[all,ia32,x64,simarm,arm,dartc]',
+ metavar='[all,ia32,x64,simarm,simmips,arm,mips,dartc]',
default=utils.GuessArchitecture())
result.add_option("--executable",
help='Virtual machine to execute.',
@@ -68,7 +68,7 @@
def ProcessOptions(options):
if options.arch == 'all':
- options.arch = 'ia32,x64,simarm,dartc'
+ options.arch = 'ia32,x64,simarm,simmips,dartc'
if options.mode == 'all':
options.mode = 'debug,release'
options.mode = options.mode.split(',')
@@ -78,7 +78,7 @@
print "Unknown mode %s" % mode
return False
for arch in options.arch:
- if not arch in ['ia32', 'x64', 'simarm', 'arm', 'dartc']:
+ if not arch in ['ia32', 'x64', 'simarm', 'simmips', 'arm', 'mips', 'dartc']:
print "Unknown arch %s" % arch
return False
return True
diff --git a/runtime/vm/assembler_arm.cc b/runtime/vm/assembler_arm.cc
index c1803e2..87b1dbf 100644
--- a/runtime/vm/assembler_arm.cc
+++ b/runtime/vm/assembler_arm.cc
@@ -530,6 +530,13 @@
}
+void Assembler::umlal(Register rd_lo, Register rd_hi,
+ Register rn, Register rm, Condition cond) {
+ // Assembler registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs.
+ EmitMulOp(cond, B23 | B21, rd_lo, rd_hi, rn, rm);
+}
+
+
void Assembler::EmitDivOp(Condition cond, int32_t opcode,
Register rd, Register rn, Register rm) {
ASSERT(CPUFeatures::integer_division_supported());
@@ -1375,12 +1382,16 @@
StoreIntoObjectFilterNoSmi(object, value, &done);
}
// A store buffer update is required.
- if (value != R0) Push(R0); // Preserve R0.
+ RegList regs = (1 << LR);
+ if (value != R0) {
+ regs |= (1 << R0); // Preserve R0.
+ }
+ PushList(regs);
if (object != R0) {
mov(R0, ShifterOperand(object));
}
BranchLink(&StubCode::UpdateStoreBufferLabel());
- if (value != R0) Pop(R0); // Restore R0.
+ PopList(regs);
Bind(&done);
}
diff --git a/runtime/vm/assembler_arm.h b/runtime/vm/assembler_arm.h
index 7230266..16438d8 100644
--- a/runtime/vm/assembler_arm.h
+++ b/runtime/vm/assembler_arm.h
@@ -402,6 +402,8 @@
Condition cond = AL);
void smlal(Register rd_lo, Register rd_hi, Register rn, Register rm,
Condition cond = AL);
+ void umlal(Register rd_lo, Register rd_hi, Register rn, Register rm,
+ Condition cond = AL);
// Division instructions.
void sdiv(Register rd, Register rn, Register rm, Condition cond = AL);
diff --git a/runtime/vm/assembler_mips.cc b/runtime/vm/assembler_mips.cc
index f4f3de1..40db73b 100644
--- a/runtime/vm/assembler_mips.cc
+++ b/runtime/vm/assembler_mips.cc
@@ -264,12 +264,26 @@
StoreIntoObjectFilterNoSmi(object, value, &done);
}
// A store buffer update is required.
- if (value != T0) Push(T0); // Preserve T0.
+ if (value != T0) {
+ // Preserve T0.
+ addiu(SP, SP, Immediate(-2 * kWordSize));
+ sw(T0, Address(SP, 1 * kWordSize));
+ } else {
+ addiu(SP, SP, Immediate(-1 * kWordSize));
+ }
+ sw(RA, Address(SP, 0 * kWordSize));
if (object != T0) {
mov(T0, object);
}
BranchLink(&StubCode::UpdateStoreBufferLabel());
- if (value != T0) Pop(T0); // Restore T0.
+ lw(RA, Address(SP, 0 * kWordSize));
+ if (value != T0) {
+ // Restore T0.
+ lw(T0, Address(SP, 1 * kWordSize));
+ addiu(SP, SP, Immediate(2 * kWordSize));
+ } else {
+ addiu(SP, SP, Immediate(1 * kWordSize));
+ }
Bind(&done);
}
@@ -486,6 +500,18 @@
}
+void Assembler::LeaveDartFrame() {
+ addiu(SP, FP, Immediate(-kWordSize));
+
+ lw(RA, Address(SP, 2 * kWordSize));
+ lw(FP, Address(SP, 1 * kWordSize));
+ lw(PP, Address(SP, 0 * kWordSize));
+
+ // Adjust SP for PC, RA, FP, PP pushed in EnterDartFrame.
+ addiu(SP, SP, Immediate(4 * kWordSize));
+}
+
+
void Assembler::LeaveDartFrameAndReturn() {
addiu(SP, FP, Immediate(-kWordSize));
@@ -493,7 +519,7 @@
lw(FP, Address(SP, 1 * kWordSize));
lw(PP, Address(SP, 0 * kWordSize));
- // Adjust SP for PC pushed in EnterDartFrame, and return.
+ // Adjust SP for PC, RA, FP, PP pushed in EnterDartFrame, and return.
Ret();
delay_slot()->addiu(SP, SP, Immediate(4 * kWordSize));
}
diff --git a/runtime/vm/assembler_mips.h b/runtime/vm/assembler_mips.h
index b94675a..7b4a462 100644
--- a/runtime/vm/assembler_mips.h
+++ b/runtime/vm/assembler_mips.h
@@ -995,6 +995,26 @@
sra(reg, reg, kSmiTagSize);
}
+ void LoadFromOffset(Register reg, Register base, int32_t offset) {
+ if (Utils::IsInt(kImmBits, offset)) {
+ lw(reg, Address(base, offset));
+ } else {
+ LoadImmediate(TMP, offset);
+ addu(TMP, base, TMP);
+ lw(reg, Address(TMP, 0));
+ }
+ }
+
+ void StoreToOffset(Register reg, Register base, int32_t offset) {
+ if (Utils::IsInt(kImmBits, offset)) {
+ sw(reg, Address(base, offset));
+ } else {
+ LoadImmediate(TMP, offset);
+ addu(TMP, base, TMP);
+ sw(reg, Address(TMP, 0));
+ }
+ }
+
void StoreDToOffset(DRegister reg, Register base, int32_t offset) {
FRegister lo = static_cast<FRegister>(reg * 2);
FRegister hi = static_cast<FRegister>(reg * 2 + 1);
@@ -1049,6 +1069,7 @@
// enable easy access to the RawInstruction object of code corresponding
// to this frame.
void EnterDartFrame(intptr_t frame_size);
+ void LeaveDartFrame();
void LeaveDartFrameAndReturn();
private:
diff --git a/runtime/vm/ast.h b/runtime/vm/ast.h
index 0f2b66e..ffce35a 100644
--- a/runtime/vm/ast.h
+++ b/runtime/vm/ast.h
@@ -32,7 +32,6 @@
V(ForNode, "for") \
V(JumpNode, "jump") \
V(ArgumentListNode, "args") \
- V(ArgumentDefinitionTestNode, "defined") \
V(ArrayNode, "array") \
V(ClosureNode, "closure") \
V(InstanceCallNode, "instance call") \
@@ -229,41 +228,6 @@
};
-class ArgumentDefinitionTestNode : public AstNode {
- public:
- ArgumentDefinitionTestNode(intptr_t token_pos,
- intptr_t formal_parameter_index,
- const String& formal_parameter_name,
- LocalVariable* saved_arguments_descriptor)
- : AstNode(token_pos),
- formal_parameter_index_(formal_parameter_index),
- formal_parameter_name_(formal_parameter_name),
- saved_arguments_descriptor_(*saved_arguments_descriptor) {
- ASSERT(formal_parameter_index_ >= 0);
- ASSERT(formal_parameter_name_.IsZoneHandle());
- ASSERT(formal_parameter_name_.IsSymbol());
- ASSERT(saved_arguments_descriptor != NULL);
- }
-
- virtual void VisitChildren(AstNodeVisitor* visitor) const { }
-
- intptr_t formal_parameter_index() const { return formal_parameter_index_; }
- const String& formal_parameter_name() const { return formal_parameter_name_; }
- const LocalVariable& saved_arguments_descriptor() const {
- return saved_arguments_descriptor_;
- }
-
- DECLARE_COMMON_NODE_FUNCTIONS(ArgumentDefinitionTestNode);
-
- private:
- const intptr_t formal_parameter_index_;
- const String& formal_parameter_name_;
- const LocalVariable& saved_arguments_descriptor_;
-
- DISALLOW_COPY_AND_ASSIGN(ArgumentDefinitionTestNode);
-};
-
-
class LetNode : public AstNode {
public:
explicit LetNode(intptr_t token_pos);
diff --git a/runtime/vm/ast_printer.cc b/runtime/vm/ast_printer.cc
index 58fce94..db100d7 100644
--- a/runtime/vm/ast_printer.cc
+++ b/runtime/vm/ast_printer.cc
@@ -48,15 +48,6 @@
}
-void AstPrinter::VisitArgumentDefinitionTestNode(
- ArgumentDefinitionTestNode* node) {
- OS::Print("(%s ?%s @%"Pd")",
- node->Name(),
- node->formal_parameter_name().ToCString(),
- node->formal_parameter_index());
-}
-
-
void AstPrinter::VisitReturnNode(ReturnNode* node) {
VisitGenericAstNode(node);
}
diff --git a/runtime/vm/bigint_operations_test.cc b/runtime/vm/bigint_operations_test.cc
index 54dd297..46867fe 100644
--- a/runtime/vm/bigint_operations_test.cc
+++ b/runtime/vm/bigint_operations_test.cc
@@ -1340,9 +1340,6 @@
}
-#if defined(TARGET_ARCH_IA32) || \
- defined(TARGET_ARCH_X64) || \
- defined(TARGET_ARCH_ARM)
static void TestBigintMultiplyDivide(const char* a,
const char* b,
const char* product) {
@@ -2134,7 +2131,6 @@
"000000000000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000001");
}
-#endif
static void TestBigintDivideRemainder(const char* a,
diff --git a/runtime/vm/code_generator.cc b/runtime/vm/code_generator.cc
index 680fb33..ac1b3d5 100644
--- a/runtime/vm/code_generator.cc
+++ b/runtime/vm/code_generator.cc
@@ -30,29 +30,32 @@
DEFINE_FLAG(bool, deoptimize_alot, false,
"Deoptimizes all live frames when we are about to return to Dart code from"
" native entries.");
+DEFINE_FLAG(int, max_subtype_cache_entries, 100,
+ "Maximum number of subtype cache entries (number of checks cached).");
+DEFINE_FLAG(int, optimization_counter_threshold, 15000,
+ "Function's usage-counter value before it is optimized, -1 means never");
+DEFINE_FLAG(charp, optimization_filter, NULL, "Optimize only named function");
+DEFINE_FLAG(int, reoptimization_counter_threshold, 2000,
+ "Counter threshold before a function gets reoptimized.");
+DEFINE_FLAG(bool, stop_on_excessive_deoptimization, false,
+ "Debugging: stops program if deoptimizing same function too often");
DEFINE_FLAG(bool, trace_deoptimization, false, "Trace deoptimization");
DEFINE_FLAG(bool, trace_deoptimization_verbose, false,
"Trace deoptimization verbose");
+DEFINE_FLAG(bool, trace_failed_optimization_attempts, false,
+ "Traces all failed optimization attempts");
DEFINE_FLAG(bool, trace_ic, false, "Trace IC handling");
DEFINE_FLAG(bool, trace_ic_miss_in_optimized, false,
"Trace IC miss in optimized code");
-DEFINE_FLAG(bool, trace_patching, false, "Trace patching of code.");
-DEFINE_FLAG(bool, trace_runtime_calls, false, "Trace runtime calls");
-DEFINE_FLAG(int, optimization_counter_threshold, 15000,
- "Function's usage-counter value before it is optimized, -1 means never");
-DECLARE_FLAG(bool, enable_type_checks);
-DECLARE_FLAG(bool, trace_type_checks);
-DECLARE_FLAG(bool, report_usage_count);
-DECLARE_FLAG(int, deoptimization_counter_threshold);
-DEFINE_FLAG(charp, optimization_filter, NULL, "Optimize only named function");
-DEFINE_FLAG(bool, trace_failed_optimization_attempts, false,
- "Traces all failed optimization attempts");
DEFINE_FLAG(bool, trace_optimized_ic_calls, false,
"Trace IC calls in optimized code.");
-DEFINE_FLAG(int, reoptimization_counter_threshold, 2000,
- "Counter threshold before a function gets reoptimized.");
-DEFINE_FLAG(int, max_subtype_cache_entries, 100,
- "Maximum number of subtype cache entries (number of checks cached).");
+DEFINE_FLAG(bool, trace_patching, false, "Trace patching of code.");
+DEFINE_FLAG(bool, trace_runtime_calls, false, "Trace runtime calls");
+
+DECLARE_FLAG(int, deoptimization_counter_threshold);
+DECLARE_FLAG(bool, enable_type_checks);
+DECLARE_FLAG(bool, report_usage_count);
+DECLARE_FLAG(bool, trace_type_checks);
#if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64)
DEFINE_FLAG(bool, use_osr, true, "Use on-stack replacement.");
@@ -1297,9 +1300,13 @@
}
if (function.deoptimization_counter() >=
FLAG_deoptimization_counter_threshold) {
- if (FLAG_trace_failed_optimization_attempts) {
+ if (FLAG_trace_failed_optimization_attempts ||
+ FLAG_stop_on_excessive_deoptimization) {
OS::PrintErr("Too Many Deoptimizations: %s\n",
function.ToFullyQualifiedCString());
+ if (FLAG_stop_on_excessive_deoptimization) {
+ FATAL("Stop on excessive deoptimization");
+ }
}
// TODO(srdjan): Investigate excessive deoptimization.
function.set_usage_counter(kLowInvocationCount);
diff --git a/runtime/vm/compiler.cc b/runtime/vm/compiler.cc
index 2faa434..ee9a5a0 100644
--- a/runtime/vm/compiler.cc
+++ b/runtime/vm/compiler.cc
@@ -48,6 +48,8 @@
"attempt to sink temporary allocations to side exits");
DEFINE_FLAG(int, deoptimization_counter_threshold, 16,
"How many times we allow deoptimization before we disallow optimization.");
+DEFINE_FLAG(int, deoptimization_counter_licm_threshold, 8,
+ "How many times we allow deoptimization before we disable LICM.");
DEFINE_FLAG(bool, use_inlining, true, "Enable call-site inlining");
DEFINE_FLAG(bool, range_analysis, true, "Enable range analysis");
DEFINE_FLAG(bool, verify_compiler, false,
@@ -400,7 +402,7 @@
}
if (FLAG_loop_invariant_code_motion &&
(function.deoptimization_counter() <
- (FLAG_deoptimization_counter_threshold - 1))) {
+ FLAG_deoptimization_counter_licm_threshold)) {
LICM licm(flow_graph);
licm.Optimize();
DEBUG_ASSERT(flow_graph->VerifyUseLists());
diff --git a/runtime/vm/compiler_test.cc b/runtime/vm/compiler_test.cc
index 2287be2..43b7d58 100644
--- a/runtime/vm/compiler_test.cc
+++ b/runtime/vm/compiler_test.cc
@@ -11,11 +11,6 @@
namespace dart {
-// Compiler only implemented on IA32, X64, and ARM.
-#if defined(TARGET_ARCH_IA32) || \
- defined(TARGET_ARCH_X64) || \
- defined(TARGET_ARCH_ARM)
-
TEST_CASE(CompileScript) {
const char* kScriptChars =
"class A {\n"
@@ -67,6 +62,4 @@
EXPECT(function_moo.HasCode());
}
-#endif // TARGET_ARCH_IA32 || TARGET_ARCH_X64 || TARGET_ARCH_ARM
-
} // namespace dart
diff --git a/runtime/vm/dart_api_impl_test.cc b/runtime/vm/dart_api_impl_test.cc
index 2c78b52..c030ea6 100644
--- a/runtime/vm/dart_api_impl_test.cc
+++ b/runtime/vm/dart_api_impl_test.cc
@@ -2815,8 +2815,8 @@
// Error cases.
EXPECT_ERROR(Dart_ClassGetInterfaceCount(Dart_True(), &len),
- "Dart_ClassGetInterfaceCount expects argument 'clazz' to be of "
- "type Class.");
+ "Dart_ClassGetInterfaceCount expects argument 'object' to be of "
+ "type Class/Type.");
EXPECT_ERROR(Dart_ClassGetInterfaceCount(Dart_NewApiError("MyError"), &len),
"MyError");
}
diff --git a/runtime/vm/disassembler_arm.cc b/runtime/vm/disassembler_arm.cc
index ea92980..339f51d 100644
--- a/runtime/vm/disassembler_arm.cc
+++ b/runtime/vm/disassembler_arm.cc
@@ -638,6 +638,11 @@
Format(instr, "umull'cond's 'rd, 'rn, 'rm, 'rs");
break;
}
+ case 5: {
+ // Registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs.
+ Format(instr, "umlal'cond's 'rd, 'rn, 'rm, 'rs");
+ break;
+ }
case 6: {
// Registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs.
Format(instr, "smull'cond's 'rd, 'rn, 'rm, 'rs");
diff --git a/runtime/vm/flow_graph_builder.cc b/runtime/vm/flow_graph_builder.cc
index 2f96f61..e3700f6 100644
--- a/runtime/vm/flow_graph_builder.cc
+++ b/runtime/vm/flow_graph_builder.cc
@@ -1813,17 +1813,6 @@
}
-void EffectGraphVisitor::VisitArgumentDefinitionTestNode(
- ArgumentDefinitionTestNode* node) {
- InlineBailout("EffectGraphVisitor::VisitArgumentDefinitionTestNode");
- Definition* load = BuildLoadLocal(node->saved_arguments_descriptor());
- Value* arguments_descriptor = Bind(load);
- ArgumentDefinitionTestInstr* arg_def_test =
- new ArgumentDefinitionTestInstr(node, arguments_descriptor);
- ReturnDefinition(arg_def_test);
-}
-
-
intptr_t EffectGraphVisitor::GetCurrentTempLocalIndex() const {
return kFirstLocalSlotFromFp
- owner()->num_stack_locals()
@@ -3117,15 +3106,9 @@
if (node == owner()->parsed_function()->node_sequence()) {
ASSERT(scope->context_level() == 1);
const Function& function = owner()->parsed_function()->function();
- int num_params = function.NumParameters();
+ const int num_params = function.NumParameters();
int param_frame_index = (num_params == function.num_fixed_parameters()) ?
(kParamEndSlotFromFp + num_params) : kFirstLocalSlotFromFp;
- // Handle the saved arguments descriptor as an additional parameter.
- if (owner()->parsed_function()->GetSavedArgumentsDescriptorVar() !=
- NULL) {
- ASSERT(param_frame_index == kFirstLocalSlotFromFp);
- num_params++;
- }
for (int pos = 0; pos < num_params; param_frame_index--, pos++) {
const LocalVariable& parameter = *scope->VariableAt(pos);
ASSERT(parameter.owner() == scope);
@@ -3244,45 +3227,52 @@
void EffectGraphVisitor::VisitTryCatchNode(TryCatchNode* node) {
InlineBailout("EffectGraphVisitor::VisitTryCatchNode (exception)");
- intptr_t old_try_index = owner()->try_index();
- intptr_t try_index = owner()->AllocateTryIndex();
- owner()->set_try_index(try_index);
+ intptr_t original_handler_index = owner()->try_index();
+ intptr_t try_handler_index = owner()->AllocateTryIndex();
+ owner()->set_try_index(try_handler_index);
// Preserve CTX into local variable '%saved_context'.
BuildStoreContext(node->context_var());
- EffectGraphVisitor for_try_block(owner(), temp_index());
- node->try_block()->Visit(&for_try_block);
+ EffectGraphVisitor for_try(owner(), temp_index());
+ node->try_block()->Visit(&for_try);
- if (for_try_block.is_open()) {
+ if (for_try.is_open()) {
JoinEntryInstr* after_try =
- new JoinEntryInstr(owner()->AllocateBlockId(), old_try_index);
- for_try_block.Goto(after_try);
- for_try_block.exit_ = after_try;
+ new JoinEntryInstr(owner()->AllocateBlockId(), original_handler_index);
+ for_try.Goto(after_try);
+ for_try.exit_ = after_try;
}
JoinEntryInstr* try_entry =
- new JoinEntryInstr(owner()->AllocateBlockId(), try_index);
+ new JoinEntryInstr(owner()->AllocateBlockId(), try_handler_index);
Goto(try_entry);
- AppendFragment(try_entry, for_try_block);
- exit_ = for_try_block.exit_;
+ AppendFragment(try_entry, for_try);
+ exit_ = for_try.exit_;
// We are done generating code for the try block.
- owner()->set_try_index(old_try_index);
+ owner()->set_try_index(original_handler_index);
CatchClauseNode* catch_block = node->catch_block();
+ SequenceNode* finally_block = node->finally_block();
if (catch_block != NULL) {
- EffectGraphVisitor for_catch_block(owner(), temp_index());
- catch_block->Visit(&for_catch_block);
+ // If there is a finally block, it is the handler for code in the catch
+ // block.
+ intptr_t catch_handler_index = (finally_block == NULL)
+ ? original_handler_index
+ : owner()->AllocateTryIndex();
+ owner()->set_try_index(catch_handler_index);
+ EffectGraphVisitor for_catch(owner(), temp_index());
+ catch_block->Visit(&for_catch);
CatchBlockEntryInstr* catch_entry =
new CatchBlockEntryInstr(owner()->AllocateBlockId(),
- old_try_index,
+ catch_handler_index,
catch_block->handler_types(),
- try_index);
+ try_handler_index);
owner()->AddCatchEntry(catch_entry);
- ASSERT(!for_catch_block.is_open());
- AppendFragment(catch_entry, for_catch_block);
+ ASSERT(!for_catch.is_open());
+ AppendFragment(catch_entry, for_catch);
if (node->end_catch_label() != NULL) {
JoinEntryInstr* join = node->end_catch_label()->join_for_continue();
if (join != NULL) {
@@ -3290,12 +3280,47 @@
exit_ = join;
}
}
+
+ if (finally_block != NULL) {
+ // Create a handler for the code in the catch block, containing the
+ // code in the finally block.
+ owner()->set_try_index(original_handler_index);
+ EffectGraphVisitor for_finally(owner(), temp_index());
+ for_finally.AddInstruction(
+ new CatchEntryInstr(catch_block->exception_var(),
+ catch_block->stacktrace_var()));
+ for_finally.BuildLoadContext(catch_block->context_var());
+
+ finally_block->Visit(&for_finally);
+ if (for_finally.is_open()) {
+ // Rethrow the exception. Manually build the graph for rethrow.
+ Value* exception = for_finally.Bind(
+ for_finally.BuildLoadLocal(catch_block->exception_var()));
+ for_finally.PushArgument(exception);
+ Value* stacktrace = for_finally.Bind(
+ for_finally.BuildLoadLocal(catch_block->stacktrace_var()));
+ for_finally.PushArgument(stacktrace);
+ for_finally.AddInstruction(new ReThrowInstr(catch_block->token_pos()));
+ for_finally.CloseFragment();
+ }
+ ASSERT(!for_finally.is_open());
+
+ const Array& types = Array::ZoneHandle(Array::New(1, Heap::kOld));
+ types.SetAt(0, Type::Handle(Type::DynamicType()));
+ CatchBlockEntryInstr* finally_entry =
+ new CatchBlockEntryInstr(owner()->AllocateBlockId(),
+ original_handler_index,
+ types,
+ catch_handler_index);
+ owner()->AddCatchEntry(finally_entry);
+ AppendFragment(finally_entry, for_finally);
+ }
}
// Generate code for the finally block if one exists.
- if ((node->finally_block() != NULL) && is_open()) {
+ if ((finally_block != NULL) && is_open()) {
EffectGraphVisitor for_finally_block(owner(), temp_index());
- node->finally_block()->Visit(&for_finally_block);
+ finally_block->Visit(&for_finally_block);
Append(for_finally_block);
}
}
diff --git a/runtime/vm/flow_graph_compiler_arm.cc b/runtime/vm/flow_graph_compiler_arm.cc
index 6e61549..9aa4474 100644
--- a/runtime/vm/flow_graph_compiler_arm.cc
+++ b/runtime/vm/flow_graph_compiler_arm.cc
@@ -1035,8 +1035,6 @@
// the presence of optional parameters.
// No such checking code is generated if only fixed parameters are declared,
// unless we are in debug mode or unless we are compiling a closure.
- LocalVariable* saved_args_desc_var =
- parsed_function().GetSavedArgumentsDescriptorVar();
if (num_copied_params == 0) {
#ifdef DEBUG
ASSERT(!parsed_function().function().HasOptionalParameters());
@@ -1078,26 +1076,12 @@
}
__ Bind(&correct_num_arguments);
}
- // The arguments descriptor is never saved in the absence of optional
- // parameters, since any argument definition test would always yield true.
- ASSERT(saved_args_desc_var == NULL);
} else {
- if (saved_args_desc_var != NULL) {
- __ Comment("Save arguments descriptor");
- const Register kArgumentsDescriptorReg = R4;
- // The saved_args_desc_var is allocated one slot before the first local.
- const intptr_t slot = parsed_function().first_stack_local_index() + 1;
- // If the saved_args_desc_var is captured, it is first moved to the stack
- // and later to the context, once the context is allocated.
- ASSERT(saved_args_desc_var->is_captured() ||
- (saved_args_desc_var->index() == slot));
- __ str(kArgumentsDescriptorReg, Address(FP, slot * kWordSize));
- }
CopyParameters();
}
// In unoptimized code, initialize (non-argument) stack allocated slots to
- // null. This does not cover the saved_args_desc_var slot.
+ // null.
if (!is_optimizing() && (num_locals > 0)) {
__ Comment("Initialize spill slots");
const intptr_t slot_base = parsed_function().first_stack_local_index();
@@ -1354,7 +1338,11 @@
(obj.IsMint() || obj.IsDouble() || obj.IsBigint())) {
__ Push(reg);
__ PushObject(obj);
- __ BranchLink(&StubCode::IdenticalWithNumberCheckLabel());
+ if (is_optimizing()) {
+ __ BranchLink(&StubCode::OptimizedIdenticalWithNumberCheckLabel());
+ } else {
+ __ BranchLink(&StubCode::UnoptimizedIdenticalWithNumberCheckLabel());
+ }
AddCurrentDescriptor(PcDescriptors::kRuntimeCall,
Isolate::kNoDeoptId,
token_pos);
@@ -1374,7 +1362,11 @@
if (needs_number_check) {
__ Push(left);
__ Push(right);
- __ BranchLink(&StubCode::IdenticalWithNumberCheckLabel());
+ if (is_optimizing()) {
+ __ BranchLink(&StubCode::OptimizedIdenticalWithNumberCheckLabel());
+ } else {
+ __ BranchLink(&StubCode::UnoptimizedIdenticalWithNumberCheckLabel());
+ }
AddCurrentDescriptor(PcDescriptors::kRuntimeCall,
Isolate::kNoDeoptId,
token_pos);
@@ -1566,7 +1558,7 @@
intptr_t index_scale,
Register array,
intptr_t index) {
- UNIMPLEMENTED();
+ UNREACHABLE();
return FieldAddress(array, index);
}
@@ -1575,7 +1567,7 @@
intptr_t index_scale,
Register array,
Register index) {
- UNIMPLEMENTED();
+ UNREACHABLE();
return FieldAddress(array, index);
}
diff --git a/runtime/vm/flow_graph_compiler_ia32.cc b/runtime/vm/flow_graph_compiler_ia32.cc
index 6504aa6..ca0a90e 100644
--- a/runtime/vm/flow_graph_compiler_ia32.cc
+++ b/runtime/vm/flow_graph_compiler_ia32.cc
@@ -992,16 +992,6 @@
}
__ Bind(&wrong_num_arguments);
- if (StackSize() != 0) {
- // We need to unwind the space we reserved for locals and copied parameters.
- // The NoSuchMethodFunction stub does not expect to see that area on the
- // stack.
- __ addl(ESP, Immediate(StackSize() * kWordSize));
- }
- // The call below has an empty stackmap because we have just
- // dropped the spill slots.
- BitmapBuilder* empty_stack_bitmap = new BitmapBuilder();
-
// 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(
@@ -1011,24 +1001,10 @@
ICData::New(function, name, Object::null_array(),
Isolate::kNoDeoptId, kNumArgsChecked));
__ LoadObject(ECX, ic_data);
- // EBP - 4 : PC marker, allows easy identification of RawInstruction obj.
- // EBP : points to previous frame pointer.
- // EBP + 4 : points to return address.
- // EBP + 8 : address of last argument (arg n-1).
- // ESP + 8 + 4*(n-1) : address of first argument (arg 0).
- // ECX : ic-data.
- // EDX : arguments descriptor array.
- __ call(&StubCode::CallNoSuchMethodFunctionLabel());
- // Emit descriptors in order to provide correct postion in stacktrace.
- AddCurrentDescriptor(PcDescriptors::kOther, -1, function.token_pos());
- if (is_optimizing()) {
- stackmap_table_builder_->AddEntry(assembler()->CodeSize(),
- empty_stack_bitmap,
- 0); // No registers.
- }
- // The noSuchMethod call may return.
- __ LeaveFrame();
- __ ret();
+ __ LeaveFrame(); // The arguments are still on the stack.
+ __ jmp(&StubCode::CallNoSuchMethodFunctionLabel());
+ // The noSuchMethod call may return to the caller, but not here.
+ __ int3();
__ Bind(&all_arguments_processed);
// Nullify originally passed arguments only after they have been copied and
@@ -1142,8 +1118,6 @@
// the presence of optional parameters.
// No such checking code is generated if only fixed parameters are declared,
// unless we are in debug mode or unless we are compiling a closure.
- LocalVariable* saved_args_desc_var =
- parsed_function().GetSavedArgumentsDescriptorVar();
if (num_copied_params == 0) {
#ifdef DEBUG
ASSERT(!parsed_function().function().HasOptionalParameters());
@@ -1167,16 +1141,6 @@
__ Bind(&wrong_num_arguments);
if (function.IsClosureFunction() || function.IsNoSuchMethodDispatcher()) {
- if (StackSize() != 0) {
- // We need to unwind the space we reserved for locals and copied
- // parameters. The NoSuchMethodFunction stub does not expect to see
- // that area on the stack.
- __ addl(ESP, Immediate(StackSize() * kWordSize));
- }
- // The call below has an empty stackmap because we have just
- // dropped the spill slots.
- BitmapBuilder* empty_stack_bitmap = new BitmapBuilder();
-
// Invoke noSuchMethod function passing the original function name.
// For closure functions, use "call" as the original name.
const String& name =
@@ -1188,49 +1152,21 @@
ICData::New(function, name, Object::null_array(),
Isolate::kNoDeoptId, kNumArgsChecked));
__ LoadObject(ECX, ic_data);
- // EBP - 4 : PC marker, for easy identification of RawInstruction obj.
- // EBP : points to previous frame pointer.
- // EBP + 4 : points to return address.
- // EBP + 8 : address of last argument (arg n-1).
- // ESP + 8 + 4*(n-1) : address of first argument (arg 0).
- // ECX : ic-data.
- // EDX : arguments descriptor array.
- __ call(&StubCode::CallNoSuchMethodFunctionLabel());
- // Emit descriptors in order to provide correct postion in stacktrace.
- AddCurrentDescriptor(PcDescriptors::kOther, -1, function.token_pos());
- if (is_optimizing()) {
- stackmap_table_builder_->AddEntry(assembler()->CodeSize(),
- empty_stack_bitmap,
- 0); // No registers.
- }
- // The noSuchMethod call may return.
- __ LeaveFrame();
- __ ret();
+ __ LeaveFrame(); // The arguments are still on the stack.
+ __ jmp(&StubCode::CallNoSuchMethodFunctionLabel());
+ // The noSuchMethod call may return to the caller, but not here.
+ __ int3();
} else {
__ Stop("Wrong number of arguments");
}
__ Bind(&correct_num_arguments);
}
- // The arguments descriptor is never saved in the absence of optional
- // parameters, since any argument definition test would always yield true.
- ASSERT(saved_args_desc_var == NULL);
} else if (!flow_graph().IsCompiledForOsr()) {
- if (saved_args_desc_var != NULL) {
- __ Comment("Save arguments descriptor");
- const Register kArgumentsDescriptorReg = EDX;
- // The saved_args_desc_var is allocated one slot before the first local.
- const intptr_t slot = parsed_function().first_stack_local_index() + 1;
- // If the saved_args_desc_var is captured, it is first moved to the stack
- // and later to the context, once the context is allocated.
- ASSERT(saved_args_desc_var->is_captured() ||
- (saved_args_desc_var->index() == slot));
- __ movl(Address(EBP, slot * kWordSize), kArgumentsDescriptorReg);
- }
CopyParameters();
}
// In unoptimized code, initialize (non-argument) stack allocated slots to
- // null. This does not cover the saved_args_desc_var slot.
+ // null.
if (!is_optimizing() && (num_locals > 0)) {
__ Comment("Initialize spill slots");
const intptr_t slot_base = parsed_function().first_stack_local_index();
@@ -1496,7 +1432,11 @@
if (needs_number_check) {
__ pushl(reg);
__ PushObject(obj);
- __ call(&StubCode::IdenticalWithNumberCheckLabel());
+ if (is_optimizing()) {
+ __ call(&StubCode::OptimizedIdenticalWithNumberCheckLabel());
+ } else {
+ __ call(&StubCode::UnoptimizedIdenticalWithNumberCheckLabel());
+ }
AddCurrentDescriptor(PcDescriptors::kRuntimeCall,
Isolate::kNoDeoptId,
token_pos);
@@ -1516,7 +1456,11 @@
if (needs_number_check) {
__ pushl(left);
__ pushl(right);
- __ call(&StubCode::IdenticalWithNumberCheckLabel());
+ if (is_optimizing()) {
+ __ call(&StubCode::OptimizedIdenticalWithNumberCheckLabel());
+ } else {
+ __ call(&StubCode::UnoptimizedIdenticalWithNumberCheckLabel());
+ }
AddCurrentDescriptor(PcDescriptors::kRuntimeCall,
Isolate::kNoDeoptId,
token_pos);
diff --git a/runtime/vm/flow_graph_compiler_mips.cc b/runtime/vm/flow_graph_compiler_mips.cc
index 2177423..b618668 100644
--- a/runtime/vm/flow_graph_compiler_mips.cc
+++ b/runtime/vm/flow_graph_compiler_mips.cc
@@ -920,16 +920,6 @@
}
__ Bind(&wrong_num_arguments);
- if (StackSize() != 0) {
- // We need to unwind the space we reserved for locals and copied parameters.
- // The NoSuchMethodFunction stub does not expect to see that area on the
- // stack.
- __ AddImmediate(SP, StackSize() * kWordSize);
- }
- // The call below has an empty stackmap because we have just
- // dropped the spill slots.
- BitmapBuilder* empty_stack_bitmap = new BitmapBuilder();
-
// 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(
@@ -939,25 +929,10 @@
ICData::New(function, name, Object::null_array(),
Isolate::kNoDeoptId, kNumArgsChecked));
__ LoadObject(S5, ic_data);
- // FP - 4 : saved PP, object pool pointer of caller.
- // FP + 0 : previous frame pointer.
- // FP + 4 : return address.
- // FP + 8 : PC marker, for easy identification of RawInstruction obj.
- // FP + 12: last argument (arg n-1).
- // SP + 0 : saved PP.
- // SP + 16 + 4*(n-1) : first argument (arg 0).
- // S5 : ic-data.
- // S4 : arguments descriptor array.
- __ BranchLink(&StubCode::CallNoSuchMethodFunctionLabel());
- // Emit descriptors in order to provide correct postion in stacktrace.
- AddCurrentDescriptor(PcDescriptors::kOther, -1, function.token_pos());
- if (is_optimizing()) {
- stackmap_table_builder_->AddEntry(assembler()->CodeSize(),
- empty_stack_bitmap,
- 0); // No registers.
- }
- // The noSuchMethod call may return.
- __ LeaveDartFrameAndReturn();
+ __ LeaveDartFrame(); // The arguments are still on the stack.
+ __ Branch(&StubCode::CallNoSuchMethodFunctionLabel());
+ // The noSuchMethod call may return to the caller, but not here.
+ __ break_(0);
__ Bind(&all_arguments_processed);
// Nullify originally passed arguments only after they have been copied and
@@ -1110,8 +1085,6 @@
// the presence of optional parameters.
// No such checking code is generated if only fixed parameters are declared,
// unless we are in debug mode or unless we are compiling a closure.
- LocalVariable* saved_args_desc_var =
- parsed_function().GetSavedArgumentsDescriptorVar();
if (num_copied_params == 0) {
#ifdef DEBUG
ASSERT(!parsed_function().function().HasOptionalParameters());
@@ -1134,16 +1107,6 @@
__ beq(T0, T1, &correct_num_arguments);
__ Bind(&wrong_num_arguments);
if (function.IsClosureFunction() || function.IsNoSuchMethodDispatcher()) {
- if (StackSize() != 0) {
- // We need to unwind the space we reserved for locals and copied
- // parameters. The NoSuchMethodFunction stub does not expect to see
- // that area on the stack.
- __ AddImmediate(SP, StackSize() * kWordSize);
- }
- // The call below has an empty stackmap because we have just
- // dropped the spill slots.
- BitmapBuilder* empty_stack_bitmap = new BitmapBuilder();
-
// Invoke noSuchMethod function passing the original function name.
// For closure functions, use "call" as the original name.
const String& name =
@@ -1155,50 +1118,21 @@
ICData::New(function, name, Object::null_array(),
Isolate::kNoDeoptId, kNumArgsChecked));
__ LoadObject(S5, ic_data);
- // FP - 4 : saved PP, object pool pointer of caller.
- // FP + 0 : previous frame pointer.
- // FP + 4 : return address.
- // FP + 8 : PC marker, for easy identification of RawInstruction obj.
- // FP + 12: last argument (arg n-1).
- // SP + 0 : saved PP.
- // SP + 16 + 4*(n-1) : first argument (arg 0).
- // S5 : ic-data.
- // S4 : arguments descriptor array.
- __ BranchLink(&StubCode::CallNoSuchMethodFunctionLabel());
- // Emit descriptors in order to provide correct postion in stacktrace.
- AddCurrentDescriptor(PcDescriptors::kOther, -1, function.token_pos());
- if (is_optimizing()) {
- stackmap_table_builder_->AddEntry(assembler()->CodeSize(),
- empty_stack_bitmap,
- 0); // No registers.
- }
- // The noSuchMethod call may return.
- __ LeaveDartFrameAndReturn();
+ __ 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 {
__ Stop("Wrong number of arguments");
}
__ Bind(&correct_num_arguments);
}
- // The arguments descriptor is never saved in the absence of optional
- // parameters, since any argument definition test would always yield true.
- ASSERT(saved_args_desc_var == NULL);
} else {
- if (saved_args_desc_var != NULL) {
- __ Comment("Save arguments descriptor");
- const Register kArgumentsDescriptorReg = S4;
- // The saved_args_desc_var is allocated one slot before the first local.
- const intptr_t slot = parsed_function().first_stack_local_index() + 1;
- // If the saved_args_desc_var is captured, it is first moved to the stack
- // and later to the context, once the context is allocated.
- ASSERT(saved_args_desc_var->is_captured() ||
- (saved_args_desc_var->index() == slot));
- __ sw(kArgumentsDescriptorReg, Address(FP, slot * kWordSize));
- }
CopyParameters();
}
// In unoptimized code, initialize (non-argument) stack allocated slots to
- // null. This does not cover the saved_args_desc_var slot.
+ // null.
if (!is_optimizing() && (num_locals > 0)) {
__ TraceSimMsg("Initialize spill slots");
__ Comment("Initialize spill slots");
@@ -1465,7 +1399,11 @@
__ sw(reg, Address(SP, 1 * kWordSize));
__ LoadObject(TMP1, obj);
__ sw(TMP1, Address(SP, 0 * kWordSize));
- __ BranchLink(&StubCode::IdenticalWithNumberCheckLabel());
+ if (is_optimizing()) {
+ __ BranchLink(&StubCode::OptimizedIdenticalWithNumberCheckLabel());
+ } else {
+ __ BranchLink(&StubCode::UnoptimizedIdenticalWithNumberCheckLabel());
+ }
AddCurrentDescriptor(PcDescriptors::kRuntimeCall,
Isolate::kNoDeoptId,
token_pos);
@@ -1488,7 +1426,11 @@
__ addiu(SP, SP, Immediate(-2 * kWordSize));
__ sw(left, Address(SP, 1 * kWordSize));
__ sw(right, Address(SP, 0 * kWordSize));
- __ BranchLink(&StubCode::IdenticalWithNumberCheckLabel());
+ if (is_optimizing()) {
+ __ BranchLink(&StubCode::OptimizedIdenticalWithNumberCheckLabel());
+ } else {
+ __ BranchLink(&StubCode::UnoptimizedIdenticalWithNumberCheckLabel());
+ }
AddCurrentDescriptor(PcDescriptors::kRuntimeCall,
Isolate::kNoDeoptId,
token_pos);
@@ -1663,6 +1605,7 @@
switch (true_condition) {
case EQ: assembler()->ceqd(left, right); break;
+ case NE: assembler()->ceqd(left, right); break;
case LT: assembler()->coltd(left, right); break;
case LE: assembler()->coled(left, right); break;
case GT: assembler()->coltd(right, left); break;
@@ -1675,8 +1618,13 @@
}
assembler()->LoadImmediate(TMP, 1);
- assembler()->movf(CMPRES, TMP);
- assembler()->movt(CMPRES, ZR);
+ if (true_condition == NE) {
+ assembler()->movf(CMPRES, ZR);
+ assembler()->movt(CMPRES, TMP);
+ } else {
+ assembler()->movf(CMPRES, TMP);
+ assembler()->movt(CMPRES, ZR);
+ }
assembler()->mov(TMP, ZR);
// EmitBranchOnCondition expects ordering to be described by CMPRES, TMP1.
@@ -1696,6 +1644,7 @@
switch (true_condition) {
case EQ: assembler()->ceqd(left, right); break;
+ case NE: assembler()->ceqd(left, right); break;
case LT: assembler()->coltd(left, right); break;
case LE: assembler()->coled(left, right); break;
case GT: assembler()->coltd(right, left); break;
@@ -1707,7 +1656,11 @@
}
}
- assembler()->bc1f(&done); // False is already in result.
+ if (true_condition == NE) {
+ assembler()->bc1t(&done); // False is already in result.
+ } else {
+ assembler()->bc1f(&done);
+ }
assembler()->LoadObject(result, Bool::True());
assembler()->Bind(&done);
}
@@ -1726,7 +1679,7 @@
intptr_t index_scale,
Register array,
Register index) {
- UNIMPLEMENTED();
+ UNREACHABLE();
return FieldAddress(array, index);
}
@@ -1735,7 +1688,7 @@
intptr_t index_scale,
Register array,
intptr_t index) {
- UNIMPLEMENTED();
+ UNREACHABLE();
return FieldAddress(array, index);
}
@@ -1744,7 +1697,7 @@
intptr_t index_scale,
Register array,
Register index) {
- UNIMPLEMENTED();
+ UNREACHABLE();
return FieldAddress(array, index);
}
diff --git a/runtime/vm/flow_graph_compiler_x64.cc b/runtime/vm/flow_graph_compiler_x64.cc
index 6190bb1..aabc161 100644
--- a/runtime/vm/flow_graph_compiler_x64.cc
+++ b/runtime/vm/flow_graph_compiler_x64.cc
@@ -986,16 +986,6 @@
}
__ Bind(&wrong_num_arguments);
- if (StackSize() != 0) {
- // We need to unwind the space we reserved for locals and copied parameters.
- // The NoSuchMethodFunction stub does not expect to see that area on the
- // stack.
- __ addq(RSP, Immediate(StackSize() * kWordSize));
- }
- // The call below has an empty stackmap because we have just
- // dropped the spill slots.
- BitmapBuilder* empty_stack_bitmap = new BitmapBuilder();
-
// 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(
@@ -1005,24 +995,10 @@
ICData::New(function, name, Object::null_array(),
Isolate::kNoDeoptId, kNumArgsChecked));
__ LoadObject(RBX, ic_data);
- // RBP - 8 : PC marker, allows easy identification of RawInstruction obj.
- // RBP : points to previous frame pointer.
- // RBP + 8 : points to return address.
- // RBP + 16 : address of last argument (arg n-1).
- // RSP + 16 + 8*(n-1) : address of first argument (arg 0).
- // RBX : ic-data.
- // R10 : arguments descriptor array.
- __ call(&StubCode::CallNoSuchMethodFunctionLabel());
- // Emit descriptors in order to provide correct postion in stacktrace.
- AddCurrentDescriptor(PcDescriptors::kOther, -1, function.token_pos());
- if (is_optimizing()) {
- stackmap_table_builder_->AddEntry(assembler()->CodeSize(),
- empty_stack_bitmap,
- 0); // No registers.
- }
- // The noSuchMethod call may return.
- __ LeaveFrame();
- __ ret();
+ __ LeaveFrame(); // The arguments are still on the stack.
+ __ jmp(&StubCode::CallNoSuchMethodFunctionLabel());
+ // The noSuchMethod call may return to the caller, but not here.
+ __ int3();
__ Bind(&all_arguments_processed);
// Nullify originally passed arguments only after they have been copied and
@@ -1137,8 +1113,6 @@
// the presence of optional parameters.
// No such checking code is generated if only fixed parameters are declared,
// unless we are in debug mode or unless we are compiling a closure.
- LocalVariable* saved_args_desc_var =
- parsed_function().GetSavedArgumentsDescriptorVar();
if (num_copied_params == 0) {
#ifdef DEBUG
ASSERT(!parsed_function().function().HasOptionalParameters());
@@ -1162,16 +1136,6 @@
__ Bind(&wrong_num_arguments);
if (function.IsClosureFunction() || function.IsNoSuchMethodDispatcher()) {
- if (StackSize() != 0) {
- // We need to unwind the space we reserved for locals and copied
- // parameters. The NoSuchMethodFunction stub does not expect to see
- // that area on the stack.
- __ addq(RSP, Immediate(StackSize() * kWordSize));
- }
- // The call below has an empty stackmap because we have just
- // dropped the spill slots.
- BitmapBuilder* empty_stack_bitmap = new BitmapBuilder();
-
// Invoke noSuchMethod function passing the original function name.
// For closure functions, use "call" as the original name.
const String& name =
@@ -1183,49 +1147,21 @@
ICData::New(function, name, Object::null_array(),
Isolate::kNoDeoptId, kNumArgsChecked));
__ LoadObject(RBX, ic_data);
- // RBP - 8 : PC marker, for easy identification of RawInstruction obj.
- // RBP : points to previous frame pointer.
- // RBP + 8 : points to return address.
- // RBP + 16 : address of last argument (arg n-1).
- // RSP + 16 + 8*(n-1) : address of first argument (arg 0).
- // RBX : ic-data.
- // R10 : arguments descriptor array.
- __ call(&StubCode::CallNoSuchMethodFunctionLabel());
- // Emit descriptors in order to provide correct postion in stacktrace.
- AddCurrentDescriptor(PcDescriptors::kOther, -1, function.token_pos());
- if (is_optimizing()) {
- stackmap_table_builder_->AddEntry(assembler()->CodeSize(),
- empty_stack_bitmap,
- 0); // No registers.
- }
- // The noSuchMethod call may return.
- __ LeaveFrame();
- __ ret();
+ __ LeaveFrame(); // The arguments are still on the stack.
+ __ jmp(&StubCode::CallNoSuchMethodFunctionLabel());
+ // The noSuchMethod call may return to the caller, but not here.
+ __ int3();
} else {
__ Stop("Wrong number of arguments");
}
__ Bind(&correct_num_arguments);
}
- // The arguments descriptor is never saved in the absence of optional
- // parameters, since any argument definition test would always yield true.
- ASSERT(saved_args_desc_var == NULL);
} else if (!flow_graph().IsCompiledForOsr()) {
- if (saved_args_desc_var != NULL) {
- __ Comment("Save arguments descriptor");
- const Register kArgumentsDescriptorReg = R10;
- // The saved_args_desc_var is allocated one slot before the first local.
- const intptr_t slot = parsed_function().first_stack_local_index() + 1;
- // If the saved_args_desc_var is captured, it is first moved to the stack
- // and later to the context, once the context is allocated.
- ASSERT(saved_args_desc_var->is_captured() ||
- (saved_args_desc_var->index() == slot));
- __ movq(Address(RBP, slot * kWordSize), kArgumentsDescriptorReg);
- }
CopyParameters();
}
// In unoptimized code, initialize (non-argument) stack allocated slots to
- // null. This does not cover the saved_args_desc_var slot.
+ // null.
if (!is_optimizing() && (num_locals > 0)) {
__ Comment("Initialize spill slots");
const intptr_t slot_base = parsed_function().first_stack_local_index();
@@ -1491,7 +1427,11 @@
if (needs_number_check) {
__ pushq(reg);
__ PushObject(obj);
- __ call(&StubCode::IdenticalWithNumberCheckLabel());
+ if (is_optimizing()) {
+ __ call(&StubCode::OptimizedIdenticalWithNumberCheckLabel());
+ } else {
+ __ call(&StubCode::UnoptimizedIdenticalWithNumberCheckLabel());
+ }
AddCurrentDescriptor(PcDescriptors::kRuntimeCall,
Isolate::kNoDeoptId,
token_pos);
@@ -1511,7 +1451,11 @@
if (needs_number_check) {
__ pushq(left);
__ pushq(right);
- __ call(&StubCode::IdenticalWithNumberCheckLabel());
+ if (is_optimizing()) {
+ __ call(&StubCode::OptimizedIdenticalWithNumberCheckLabel());
+ } else {
+ __ call(&StubCode::UnoptimizedIdenticalWithNumberCheckLabel());
+ }
AddCurrentDescriptor(PcDescriptors::kRuntimeCall,
Isolate::kNoDeoptId,
token_pos);
diff --git a/runtime/vm/flow_graph_inliner.cc b/runtime/vm/flow_graph_inliner.cc
index fe8573a..b388cdc 100644
--- a/runtime/vm/flow_graph_inliner.cc
+++ b/runtime/vm/flow_graph_inliner.cc
@@ -19,6 +19,8 @@
namespace dart {
+DEFINE_FLAG(int, deoptimization_counter_inlining_threshold, 12,
+ "How many times we allow deoptimization before we stop inlining.");
DEFINE_FLAG(bool, trace_inlining, false, "Trace inlining");
DEFINE_FLAG(charp, inlining_filter, NULL, "Inline only in named function");
@@ -387,6 +389,10 @@
void InlineCalls() {
// If inlining depth is less then one abort.
if (FLAG_inlining_depth_threshold < 1) return;
+ if (caller_graph_->parsed_function().function().deoptimization_counter() >=
+ FLAG_deoptimization_counter_inlining_threshold) {
+ return;
+ }
// Create two call site collections to swap between.
CallSites sites1(caller_graph_);
CallSites sites2(caller_graph_);
@@ -543,16 +549,6 @@
arguments,
param_stubs,
callee_graph);
- // Add a bogus parameter at the end for the (unused) arguments
- // descriptor slot. The parser allocates an extra slot between
- // locals and parameters to hold the arguments descriptor in case it
- // escapes. We currently bailout if there are argument test
- // expressions or escaping variables so this parameter and the stack
- // slot are not used.
- if (parsed_function->GetSavedArgumentsDescriptorVar() != NULL) {
- param_stubs->Add(new ParameterInstr(
- function.NumParameters(), callee_graph->graph_entry()));
- }
}
// After treating optional parameters the actual/formal count must match.
diff --git a/runtime/vm/flow_graph_optimizer.cc b/runtime/vm/flow_graph_optimizer.cc
index 8a66d91..279bf96 100644
--- a/runtime/vm/flow_graph_optimizer.cc
+++ b/runtime/vm/flow_graph_optimizer.cc
@@ -4047,6 +4047,34 @@
const PhiPlaceMoves* phi_moves() const { return phi_moves_; }
+ // Returns true if the result of AllocateObject can be aliased by some
+ // other SSA variable and false otherwise. Currently simply checks if
+ // this value is stored in a field, escapes to another function or
+ // participates in a phi.
+ static bool CanBeAliased(AllocateObjectInstr* alloc) {
+ if (alloc->identity() == AllocateObjectInstr::kUnknown) {
+ bool escapes = false;
+ for (Value* use = alloc->input_use_list();
+ use != NULL;
+ use = use->next_use()) {
+ Instruction* instr = use->instruction();
+ if (instr->IsPushArgument() ||
+ (instr->IsStoreVMField() && (use->use_index() != 1)) ||
+ (instr->IsStoreInstanceField() && (use->use_index() != 0)) ||
+ (instr->IsStoreStaticField()) ||
+ (instr->IsPhi())) {
+ escapes = true;
+ break;
+ }
+ }
+
+ alloc->set_identity(escapes ? AllocateObjectInstr::kAliased
+ : AllocateObjectInstr::kNotAliased);
+ }
+
+ return alloc->identity() != AllocateObjectInstr::kNotAliased;
+ }
+
private:
// Get id assigned to the given field. Assign a new id if the field is seen
// for the first time.
@@ -4094,34 +4122,6 @@
return GetFieldId(kAnyInstance, field);
}
- // Returns true if the result of AllocateObject can be aliased by some
- // other SSA variable and false otherwise. Currently simply checks if
- // this value is stored in a field, escapes to another function or
- // participates in a phi.
- bool CanBeAliased(AllocateObjectInstr* alloc) {
- if (alloc->identity() == AllocateObjectInstr::kUnknown) {
- bool escapes = false;
- for (Value* use = alloc->input_use_list();
- use != NULL;
- use = use->next_use()) {
- Instruction* instr = use->instruction();
- if (instr->IsPushArgument() ||
- (instr->IsStoreVMField() && (use->use_index() != 0)) ||
- (instr->IsStoreInstanceField() && (use->use_index() != 0)) ||
- (instr->IsStoreStaticField()) ||
- (instr->IsPhi())) {
- escapes = true;
- break;
- }
- }
-
- alloc->set_identity(escapes ? AllocateObjectInstr::kAliased
- : AllocateObjectInstr::kNotAliased);
- }
-
- return alloc->identity() != AllocateObjectInstr::kNotAliased;
- }
-
// Returns true if the given load is unaffected by external side-effects.
// This essentially means that no stores to the same location can
// occur in other functions.
@@ -4507,9 +4507,8 @@
}
// For object allocation forward initial values of the fields to
- // subsequent loads.
- // For simplicity we ignore escaping objects and objects that have
- // type arguments.
+ // subsequent loads. For simplicity we ignore escaping objects.
+ //
// The reason to ignore escaping objects is that final fields are
// initialized in constructor that potentially can be not inlined into
// the function that we are currently optimizing. However at the same
@@ -4521,7 +4520,7 @@
// escaping object.
AllocateObjectInstr* alloc = instr->AsAllocateObject();
if ((alloc != NULL) &&
- (alloc->identity() == AllocateObjectInstr::kNotAliased) &&
+ !AliasedSet::CanBeAliased(alloc) &&
HasSimpleTypeArguments(alloc)) {
for (Value* use = alloc->input_use_list();
use != NULL;
@@ -5559,12 +5558,6 @@
}
-void ConstantPropagator::VisitArgumentDefinitionTest(
- ArgumentDefinitionTestInstr* instr) {
- SetValue(instr, non_constant_);
-}
-
-
void ConstantPropagator::VisitCurrentContext(CurrentContextInstr* instr) {
SetValue(instr, non_constant_);
}
@@ -5705,7 +5698,7 @@
if (instr->left()->definition() == instr->right()->definition()) {
// Fold x == x, and x != x to true/false for numbers and checked strict
// comparisons.
- if (instr->is_checked_strict_equal() ||
+ if (instr->IsCheckedStrictEqual() ||
RawObject::IsIntegerClassId(instr->receiver_class_id())) {
return SetValue(instr,
(instr->kind() == Token::kEQ)
@@ -6964,11 +6957,8 @@
alloc->ssa_temp_index());
}
- if (alloc->identity() == AllocateObjectInstr::kAliased) {
- // Allocation might have been classified as aliased earlier due to
- // some operations that are now eliminated.
- alloc->set_identity(AllocateObjectInstr::kNotAliased);
- }
+ // All sinking candidate are known to be not aliased.
+ alloc->set_identity(AllocateObjectInstr::kNotAliased);
candidates.Add(alloc);
}
diff --git a/runtime/vm/flow_graph_type_propagator.cc b/runtime/vm/flow_graph_type_propagator.cc
index 7366821..3006a6a 100644
--- a/runtime/vm/flow_graph_type_propagator.cc
+++ b/runtime/vm/flow_graph_type_propagator.cc
@@ -786,11 +786,6 @@
}
-CompileType ArgumentDefinitionTestInstr::ComputeType() const {
- return CompileType::Bool();
-}
-
-
CompileType BooleanNegateInstr::ComputeType() const {
return CompileType::Bool();
}
diff --git a/runtime/vm/il_printer.cc b/runtime/vm/il_printer.cc
index cdddcd7..d0cd907 100644
--- a/runtime/vm/il_printer.cc
+++ b/runtime/vm/il_printer.cc
@@ -329,14 +329,6 @@
}
-void ArgumentDefinitionTestInstr::PrintOperandsTo(BufferFormatter* f) const {
- saved_arguments_descriptor()->PrintTo(f);
- f->Print(", ?%s @%"Pd"",
- formal_parameter_name().ToCString(),
- formal_parameter_index());
-}
-
-
void ClosureCallInstr::PrintOperandsTo(BufferFormatter* f) const {
for (intptr_t i = 0; i < ArgumentCount(); ++i) {
if (i > 0) f->Print(", ");
diff --git a/runtime/vm/intermediate_language.cc b/runtime/vm/intermediate_language.cc
index 9ade377..b04cc21 100644
--- a/runtime/vm/intermediate_language.cc
+++ b/runtime/vm/intermediate_language.cc
@@ -21,6 +21,9 @@
namespace dart {
+DEFINE_FLAG(int, max_equality_polymorphic_checks, 32,
+ "Maximum number of polymorphic checks in equality operator,"
+ " otherwise use megamorphic dispatch.");
DEFINE_FLAG(bool, new_identity_spec, true,
"Use new identity check rules for numbers.");
DEFINE_FLAG(bool, propagate_ic_data, true,
@@ -1034,6 +1037,14 @@
}
+bool EqualityCompareInstr::IsCheckedStrictEqual() const {
+ if (!HasICData()) return false;
+ return ic_data()->AllTargetsHaveSameOwner(kInstanceCid) &&
+ (unary_ic_data_->NumberOfChecks() <=
+ FLAG_max_equality_polymorphic_checks);
+}
+
+
bool BinarySmiOpInstr::CanDeoptimize() const {
if (FLAG_throw_on_javascript_int_overflow) return true;
switch (op_kind()) {
diff --git a/runtime/vm/intermediate_language.h b/runtime/vm/intermediate_language.h
index f4dc796..0e0df87 100644
--- a/runtime/vm/intermediate_language.h
+++ b/runtime/vm/intermediate_language.h
@@ -523,7 +523,6 @@
M(Branch) \
M(AssertAssignable) \
M(AssertBoolean) \
- M(ArgumentDefinitionTest) \
M(CurrentContext) \
M(StoreContext) \
M(ClosureCall) \
@@ -2514,42 +2513,6 @@
};
-class ArgumentDefinitionTestInstr : public TemplateDefinition<1> {
- public:
- ArgumentDefinitionTestInstr(ArgumentDefinitionTestNode* node,
- Value* saved_arguments_descriptor)
- : ast_node_(*node) {
- SetInputAt(0, saved_arguments_descriptor);
- }
-
- DECLARE_INSTRUCTION(ArgumentDefinitionTest)
- virtual CompileType ComputeType() const;
-
- intptr_t token_pos() const { return ast_node_.token_pos(); }
- intptr_t formal_parameter_index() const {
- return ast_node_.formal_parameter_index();
- }
- const String& formal_parameter_name() const {
- return ast_node_.formal_parameter_name();
- }
-
- Value* saved_arguments_descriptor() const { return inputs_[0]; }
-
- virtual void PrintOperandsTo(BufferFormatter* f) const;
-
- virtual bool CanDeoptimize() const { return true; }
-
- virtual EffectSet Effects() const { return EffectSet::None(); }
-
- virtual bool MayThrow() const { return true; }
-
- private:
- const ArgumentDefinitionTestNode& ast_node_;
-
- DISALLOW_COPY_AND_ASSIGN(ArgumentDefinitionTestInstr);
-};
-
-
// Denotes the current context, normally held in a register. This is
// a computation, not a value, because it's mutable.
class CurrentContextInstr : public TemplateDefinition<0> {
@@ -2867,8 +2830,12 @@
const Array& ic_data_array)
: ComparisonInstr(token_pos, kind, left, right),
ic_data_(GetICData(ic_data_array)),
+ unary_ic_data_(NULL),
receiver_class_id_(kIllegalCid) {
ASSERT((kind == Token::kEQ) || (kind == Token::kNE));
+ if (HasICData()) {
+ unary_ic_data_ = &ICData::ZoneHandle(ic_data_->AsUnaryClassChecks());
+ }
}
DECLARE_INSTRUCTION(EqualityCompare)
@@ -2879,7 +2846,12 @@
bool HasICData() const {
return (ic_data() != NULL) && !ic_data()->IsNull();
}
- void set_ic_data(const ICData* value) { ic_data_ = value; }
+ void set_ic_data(const ICData* value) {
+ ic_data_ = value;
+ if (HasICData()) {
+ unary_ic_data_ = &ICData::ZoneHandle(ic_data_->AsUnaryClassChecks());
+ }
+ }
// Receiver class id is computed from collected ICData.
void set_receiver_class_id(intptr_t value) { receiver_class_id_ = value; }
@@ -2891,9 +2863,7 @@
|| (receiver_class_id() == kSmiCid);
}
- bool is_checked_strict_equal() const {
- return HasICData() && ic_data()->AllTargetsHaveSameOwner(kInstanceCid);
- }
+ bool IsCheckedStrictEqual() const;
virtual void PrintOperandsTo(BufferFormatter* f) const;
@@ -2922,11 +2892,12 @@
}
virtual bool MayThrow() const {
- return !IsInlinedNumericComparison() && !is_checked_strict_equal();
+ return !IsInlinedNumericComparison() && !IsCheckedStrictEqual();
}
private:
const ICData* ic_data_;
+ ICData* unary_ic_data_;
intptr_t receiver_class_id_; // Set by optimizer.
DISALLOW_COPY_AND_ASSIGN(EqualityCompareInstr);
diff --git a/runtime/vm/intermediate_language_arm.cc b/runtime/vm/intermediate_language_arm.cc
index d313806..218b64c 100644
--- a/runtime/vm/intermediate_language_arm.cc
+++ b/runtime/vm/intermediate_language_arm.cc
@@ -264,36 +264,6 @@
}
-LocationSummary* ArgumentDefinitionTestInstr::MakeLocationSummary() const {
- const intptr_t kNumInputs = 1;
- const intptr_t kNumTemps = 0;
- LocationSummary* locs =
- new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
- locs->set_in(0, Location::RegisterLocation(R0));
- locs->set_out(Location::RegisterLocation(R0));
- return locs;
-}
-
-
-void ArgumentDefinitionTestInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- Register saved_args_desc = locs()->in(0).reg();
- Register result = locs()->out().reg();
-
- // Push the result place holder initialized to NULL.
- __ PushObject(Object::ZoneHandle());
- __ LoadImmediate(IP, Smi::RawValue(formal_parameter_index()));
- __ Push(IP);
- __ PushObject(formal_parameter_name());
- __ Push(saved_args_desc);
- compiler->GenerateCallRuntime(token_pos(),
- deopt_id(),
- kArgumentDefinitionTestRuntimeEntry,
- locs());
- __ Drop(3);
- __ Pop(result); // Pop bool result.
-}
-
-
static Condition TokenKindToSmiCondition(Token::Kind kind) {
switch (kind) {
case Token::kEQ: return EQ;
@@ -343,7 +313,7 @@
locs->set_out(Location::RequiresRegister());
return locs;
}
- if (is_checked_strict_equal()) {
+ if (IsCheckedStrictEqual()) {
const intptr_t kNumTemps = 1;
LocationSummary* locs =
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
@@ -786,7 +756,7 @@
EmitDoubleComparisonOp(compiler, *locs(), kind(), kNoBranch);
return;
}
- if (is_checked_strict_equal()) {
+ if (IsCheckedStrictEqual()) {
EmitCheckedStrictEqual(compiler, *ic_data(), *locs(), kind(), kNoBranch,
deopt_id());
return;
@@ -827,7 +797,7 @@
EmitDoubleComparisonOp(compiler, *locs(), kind(), branch);
return;
}
- if (is_checked_strict_equal()) {
+ if (IsCheckedStrictEqual()) {
EmitCheckedStrictEqual(compiler, *ic_data(), *locs(), kind(), branch,
deopt_id());
return;
@@ -1193,42 +1163,41 @@
Location index = locs()->in(1);
Address element_address(kNoRegister, 0);
- if (IsExternal()) {
- UNIMPLEMENTED();
- } else {
- ASSERT(this->array()->definition()->representation() == kTagged);
- ASSERT(index.IsRegister()); // TODO(regis): Revisit.
- // Note that index is expected smi-tagged, (i.e, times 2) for all arrays
- // with index scale factor > 1. E.g., for Uint8Array and OneByteString the
- // index is expected to be untagged before accessing.
- ASSERT(kSmiTagShift == 1);
- switch (index_scale()) {
- case 1: {
- __ SmiUntag(index.reg());
- break;
- }
- case 2: {
- break;
- }
- case 4: {
- __ mov(index.reg(), ShifterOperand(index.reg(), LSL, 1));
- break;
- }
- case 8: {
- __ mov(index.reg(), ShifterOperand(index.reg(), LSL, 2));
- break;
- }
- case 16: {
- __ mov(index.reg(), ShifterOperand(index.reg(), LSL, 3));
- break;
- }
- default:
- UNREACHABLE();
+ ASSERT(index.IsRegister()); // TODO(regis): Revisit.
+ // Note that index is expected smi-tagged, (i.e, times 2) for all arrays
+ // with index scale factor > 1. E.g., for Uint8Array and OneByteString the
+ // index is expected to be untagged before accessing.
+ ASSERT(kSmiTagShift == 1);
+ switch (index_scale()) {
+ case 1: {
+ __ SmiUntag(index.reg());
+ break;
}
+ case 2: {
+ break;
+ }
+ case 4: {
+ __ mov(index.reg(), ShifterOperand(index.reg(), LSL, 1));
+ break;
+ }
+ case 8: {
+ __ mov(index.reg(), ShifterOperand(index.reg(), LSL, 2));
+ break;
+ }
+ case 16: {
+ __ mov(index.reg(), ShifterOperand(index.reg(), LSL, 3));
+ break;
+ }
+ default:
+ UNREACHABLE();
+ }
+
+ if (!IsExternal()) {
+ ASSERT(this->array()->definition()->representation() == kTagged);
__ AddImmediate(index.reg(),
FlowGraphCompiler::DataOffsetFor(class_id()) - kHeapObjectTag);
- element_address = Address(array, index.reg(), LSL, 0);
}
+ element_address = Address(array, index.reg(), LSL, 0);
if ((representation() == kUnboxedDouble) ||
(representation() == kUnboxedMint) ||
@@ -1391,42 +1360,40 @@
Location index = locs()->in(1);
Address element_address(kNoRegister, 0);
- if (IsExternal()) {
- UNIMPLEMENTED();
- } else {
- ASSERT(this->array()->definition()->representation() == kTagged);
- ASSERT(index.IsRegister()); // TODO(regis): Revisit.
- // Note that index is expected smi-tagged, (i.e, times 2) for all arrays
- // with index scale factor > 1. E.g., for Uint8Array and OneByteString the
- // index is expected to be untagged before accessing.
- ASSERT(kSmiTagShift == 1);
- switch (index_scale()) {
- case 1: {
- __ SmiUntag(index.reg());
- break;
- }
- case 2: {
- break;
- }
- case 4: {
- __ mov(index.reg(), ShifterOperand(index.reg(), LSL, 1));
- break;
- }
- case 8: {
- __ mov(index.reg(), ShifterOperand(index.reg(), LSL, 2));
- break;
- }
- case 16: {
- __ mov(index.reg(), ShifterOperand(index.reg(), LSL, 3));
- break;
- }
- default:
- UNREACHABLE();
+ ASSERT(index.IsRegister()); // TODO(regis): Revisit.
+ // Note that index is expected smi-tagged, (i.e, times 2) for all arrays
+ // with index scale factor > 1. E.g., for Uint8Array and OneByteString the
+ // index is expected to be untagged before accessing.
+ ASSERT(kSmiTagShift == 1);
+ switch (index_scale()) {
+ case 1: {
+ __ SmiUntag(index.reg());
+ break;
}
+ case 2: {
+ break;
+ }
+ case 4: {
+ __ mov(index.reg(), ShifterOperand(index.reg(), LSL, 1));
+ break;
+ }
+ case 8: {
+ __ mov(index.reg(), ShifterOperand(index.reg(), LSL, 2));
+ break;
+ }
+ case 16: {
+ __ mov(index.reg(), ShifterOperand(index.reg(), LSL, 3));
+ break;
+ }
+ default:
+ UNREACHABLE();
+ }
+ if (!IsExternal()) {
+ ASSERT(this->array()->definition()->representation() == kTagged);
__ AddImmediate(index.reg(),
FlowGraphCompiler::DataOffsetFor(class_id()) - kHeapObjectTag);
- element_address = Address(array, index.reg(), LSL, 0);
}
+ element_address = Address(array, index.reg(), LSL, 0);
switch (class_id()) {
case kArrayCid:
diff --git a/runtime/vm/intermediate_language_ia32.cc b/runtime/vm/intermediate_language_ia32.cc
index 2780369..b8c4942 100644
--- a/runtime/vm/intermediate_language_ia32.cc
+++ b/runtime/vm/intermediate_language_ia32.cc
@@ -213,35 +213,6 @@
}
-LocationSummary* ArgumentDefinitionTestInstr::MakeLocationSummary() const {
- const intptr_t kNumInputs = 1;
- const intptr_t kNumTemps = 0;
- LocationSummary* locs =
- new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
- locs->set_in(0, Location::RegisterLocation(EAX));
- locs->set_out(Location::RegisterLocation(EAX));
- return locs;
-}
-
-
-void ArgumentDefinitionTestInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- Register saved_args_desc = locs()->in(0).reg();
- Register result = locs()->out().reg();
-
- // Push the result place holder initialized to NULL.
- __ PushObject(Object::ZoneHandle());
- __ pushl(Immediate(Smi::RawValue(formal_parameter_index())));
- __ PushObject(formal_parameter_name());
- __ pushl(saved_args_desc);
- compiler->GenerateCallRuntime(token_pos(),
- deopt_id(),
- kArgumentDefinitionTestRuntimeEntry,
- locs());
- __ Drop(3);
- __ popl(result); // Pop bool result.
-}
-
-
static Condition TokenKindToSmiCondition(Token::Kind kind) {
switch (kind) {
case Token::kEQ: return EQUAL;
@@ -292,7 +263,7 @@
locs->set_out(Location::RequiresRegister());
return locs;
}
- if (is_checked_strict_equal()) {
+ if (IsCheckedStrictEqual()) {
const intptr_t kNumTemps = 1;
LocationSummary* locs =
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
@@ -835,7 +806,7 @@
EmitDoubleComparisonOp(compiler, *locs(), kind(), kNoBranch);
return;
}
- if (is_checked_strict_equal()) {
+ if (IsCheckedStrictEqual()) {
EmitCheckedStrictEqual(compiler, *ic_data(), *locs(), kind(), kNoBranch,
deopt_id());
return;
@@ -875,7 +846,7 @@
EmitDoubleComparisonOp(compiler, *locs(), kind(), branch);
return;
}
- if (is_checked_strict_equal()) {
+ if (IsCheckedStrictEqual()) {
EmitCheckedStrictEqual(compiler, *ic_data(), *locs(), kind(), branch,
deopt_id());
return;
diff --git a/runtime/vm/intermediate_language_mips.cc b/runtime/vm/intermediate_language_mips.cc
index bbb4f5e..c954766 100644
--- a/runtime/vm/intermediate_language_mips.cc
+++ b/runtime/vm/intermediate_language_mips.cc
@@ -268,41 +268,6 @@
}
-LocationSummary* ArgumentDefinitionTestInstr::MakeLocationSummary() const {
- const intptr_t kNumInputs = 1;
- const intptr_t kNumTemps = 0;
- LocationSummary* locs =
- new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
- locs->set_in(0, Location::RegisterLocation(T0));
- locs->set_out(Location::RegisterLocation(T0));
- return locs;
-}
-
-
-void ArgumentDefinitionTestInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- Register saved_args_desc = locs()->in(0).reg();
- Register result = locs()->out().reg();
-
- __ TraceSimMsg("ArgumentDefinitionTestInstr");
-
- __ addiu(SP, SP, Immediate(-4 * kWordSize));
- // Push the result place holder initialized to NULL.
- __ LoadObject(TMP1, Object::ZoneHandle());
- __ sw(TMP1, Address(SP, 3 * kWordSize));
- __ LoadImmediate(TMP1, Smi::RawValue(formal_parameter_index()));
- __ sw(TMP1, Address(SP, 2 * kWordSize));
- __ LoadObject(TMP1, formal_parameter_name());
- __ sw(TMP1, Address(SP, 1 * kWordSize));
- __ sw(saved_args_desc, Address(SP, 0 * kWordSize));
- compiler->GenerateCallRuntime(token_pos(),
- deopt_id(),
- kArgumentDefinitionTestRuntimeEntry,
- locs());
- __ lw(result, Address(SP, 3 * kWordSize)); // Pop bool result.
- __ addiu(SP, SP, Immediate(4 * kWordSize));
-}
-
-
LocationSummary* EqualityCompareInstr::MakeLocationSummary() const {
const intptr_t kNumInputs = 2;
if (receiver_class_id() == kMintCid) {
@@ -337,7 +302,7 @@
locs->set_out(Location::RequiresRegister());
return locs;
}
- if (is_checked_strict_equal()) {
+ if (IsCheckedStrictEqual()) {
const intptr_t kNumTemps = 1;
LocationSummary* locs =
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
@@ -839,7 +804,7 @@
EmitDoubleComparisonOp(compiler, *locs(), kind(), kNoBranch);
return;
}
- if (is_checked_strict_equal()) {
+ if (IsCheckedStrictEqual()) {
EmitCheckedStrictEqual(compiler, *ic_data(), *locs(), kind(), kNoBranch,
deopt_id());
return;
@@ -884,7 +849,7 @@
EmitDoubleComparisonOp(compiler, *locs(), kind(), branch);
return;
}
- if (is_checked_strict_equal()) {
+ if (IsCheckedStrictEqual()) {
EmitCheckedStrictEqual(compiler, *ic_data(), *locs(), kind(), branch,
deopt_id());
return;
@@ -1129,13 +1094,17 @@
LocationSummary* LoadUntaggedInstr::MakeLocationSummary() const {
- UNIMPLEMENTED();
- return NULL;
+ const intptr_t kNumInputs = 1;
+ return LocationSummary::Make(kNumInputs,
+ Location::RequiresRegister(),
+ LocationSummary::kNoCall);
}
void LoadUntaggedInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- UNIMPLEMENTED();
+ Register object = locs()->in(0).reg();
+ Register result = locs()->out().reg();
+ __ LoadFromOffset(result, object, offset() - kHeapObjectTag);
}
@@ -1256,39 +1225,44 @@
Location index = locs()->in(1);
Address element_address(kNoRegister, 0);
+
+ ASSERT(index.IsRegister()); // TODO(regis): Revisit.
+ // Note that index is expected smi-tagged, (i.e, times 2) for all arrays
+ // with index scale factor > 1. E.g., for Uint8Array and OneByteString the
+ // index is expected to be untagged before accessing.
+ ASSERT(kSmiTagShift == 1);
+ switch (index_scale()) {
+ case 1: {
+ __ SmiUntag(index.reg());
+ break;
+ }
+ case 2: {
+ break;
+ }
+ case 4: {
+ __ sll(index.reg(), index.reg(), 1);
+ break;
+ }
+ case 8: {
+ __ sll(index.reg(), index.reg(), 2);
+ break;
+ }
+ case 16: {
+ __ sll(index.reg(), index.reg(), 3);
+ break;
+ }
+ default:
+ UNREACHABLE();
+ }
+ __ addu(index.reg(), array, index.reg());
+
if (IsExternal()) {
- UNIMPLEMENTED();
+ element_address = Address(index.reg(), 0);
} else {
ASSERT(this->array()->definition()->representation() == kTagged);
- ASSERT(index.IsRegister()); // TODO(regis): Revisit.
- // Note that index is expected smi-tagged, (i.e, times 2) for all arrays
- // with index scale factor > 1. E.g., for Uint8Array and OneByteString the
- // index is expected to be untagged before accessing.
- ASSERT(kSmiTagShift == 1);
- switch (index_scale()) {
- case 1: {
- __ SmiUntag(index.reg());
- break;
- }
- case 2: {
- break;
- }
- case 4: {
- __ sll(index.reg(), index.reg(), 1);
- break;
- }
- case 8: {
- __ sll(index.reg(), index.reg(), 2);
- break;
- }
- case 16: {
- __ sll(index.reg(), index.reg(), 3);
- break;
- }
- default:
- UNREACHABLE();
- }
- __ addu(index.reg(), array, index.reg());
+ // If the data offset doesn't fit into the 18 bits we get for the addressing
+ // mode, then we must load the offset into a register and add it to the
+ // index.
element_address = Address(index.reg(),
FlowGraphCompiler::DataOffsetFor(class_id()) - kHeapObjectTag);
}
@@ -1454,39 +1428,40 @@
Location index = locs()->in(1);
Address element_address(kNoRegister, 0);
+ ASSERT(index.IsRegister()); // TODO(regis): Revisit.
+ // Note that index is expected smi-tagged, (i.e, times 2) for all arrays
+ // with index scale factor > 1. E.g., for Uint8Array and OneByteString the
+ // index is expected to be untagged before accessing.
+ ASSERT(kSmiTagShift == 1);
+ switch (index_scale()) {
+ case 1: {
+ __ SmiUntag(index.reg());
+ break;
+ }
+ case 2: {
+ break;
+ }
+ case 4: {
+ __ sll(index.reg(), index.reg(), 1);
+ break;
+ }
+ case 8: {
+ __ sll(index.reg(), index.reg(), 2);
+ break;
+ }
+ case 16: {
+ __ sll(index.reg(), index.reg(), 3);
+ break;
+ }
+ default:
+ UNREACHABLE();
+ }
+ __ addu(index.reg(), array, index.reg());
+
if (IsExternal()) {
- UNIMPLEMENTED();
+ element_address = Address(index.reg(), 0);
} else {
ASSERT(this->array()->definition()->representation() == kTagged);
- ASSERT(index.IsRegister()); // TODO(regis): Revisit.
- // Note that index is expected smi-tagged, (i.e, times 2) for all arrays
- // with index scale factor > 1. E.g., for Uint8Array and OneByteString the
- // index is expected to be untagged before accessing.
- ASSERT(kSmiTagShift == 1);
- switch (index_scale()) {
- case 1: {
- __ SmiUntag(index.reg());
- break;
- }
- case 2: {
- break;
- }
- case 4: {
- __ sll(index.reg(), index.reg(), 1);
- break;
- }
- case 8: {
- __ sll(index.reg(), index.reg(), 2);
- break;
- }
- case 16: {
- __ sll(index.reg(), index.reg(), 3);
- break;
- }
- default:
- UNREACHABLE();
- }
- __ addu(index.reg(), array, index.reg());
element_address = Address(index.reg(),
FlowGraphCompiler::DataOffsetFor(class_id()) - kHeapObjectTag);
}
@@ -2285,8 +2260,7 @@
__ sltiu(CMPRES,
right, Immediate(reinterpret_cast<int32_t>(Smi::New(Smi::kBits))));
__ movz(result, ZR, CMPRES); // result = right >= kBits ? 0 : result.
- __ mov(TMP1, right);
- __ SmiUntag(TMP1);
+ __ sra(TMP1, right, kSmiTagSize);
__ sllv(TMP1, left, TMP1);
// result = right < kBits ? left << right : result.
__ movn(result, TMP1, CMPRES);
@@ -2309,7 +2283,7 @@
__ srav(temp, temp, TMP);
__ bne(temp, left, deopt); // Overflow.
// Shift for result now we know there is no overflow.
- __ sll(result, left, TMP);
+ __ sllv(result, left, TMP);
}
}
@@ -3107,13 +3081,48 @@
LocationSummary* DoubleToIntegerInstr::MakeLocationSummary() const {
- UNIMPLEMENTED();
- return NULL;
+ const intptr_t kNumInputs = 1;
+ const intptr_t kNumTemps = 0;
+ LocationSummary* result =
+ new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
+ result->set_in(0, Location::RegisterLocation(T1));
+ result->set_out(Location::RegisterLocation(V0));
+ return result;
}
void DoubleToIntegerInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- UNIMPLEMENTED();
+ Register result = locs()->out().reg();
+ Register value_obj = locs()->in(0).reg();
+ ASSERT(result == V0);
+ ASSERT(result != value_obj);
+ __ LoadDFromOffset(DTMP, value_obj, Double::value_offset() - kHeapObjectTag);
+ __ cvtwd(STMP1, DTMP);
+ __ mfc1(result, STMP1);
+
+ // Overflow is signaled with minint.
+ Label do_call, done;
+ // Check for overflow and that it fits into Smi.
+ __ LoadImmediate(TMP, 0xC0000000);
+ __ subu(CMPRES, result, TMP);
+ __ bltz(CMPRES, &do_call);
+ __ SmiTag(result);
+ __ b(&done);
+ __ Bind(&do_call);
+ __ Push(value_obj);
+ ASSERT(instance_call()->HasICData());
+ const ICData& ic_data = *instance_call()->ic_data();
+ ASSERT((ic_data.NumberOfChecks() == 1));
+ const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(0));
+
+ const intptr_t kNumberOfArguments = 1;
+ compiler->GenerateStaticCall(deopt_id(),
+ instance_call()->token_pos(),
+ target,
+ kNumberOfArguments,
+ Object::null_array(), // No argument names.,
+ locs());
+ __ Bind(&done);
}
diff --git a/runtime/vm/intermediate_language_x64.cc b/runtime/vm/intermediate_language_x64.cc
index 16cb424..3d91a75 100644
--- a/runtime/vm/intermediate_language_x64.cc
+++ b/runtime/vm/intermediate_language_x64.cc
@@ -379,35 +379,6 @@
}
-LocationSummary* ArgumentDefinitionTestInstr::MakeLocationSummary() const {
- const intptr_t kNumInputs = 1;
- const intptr_t kNumTemps = 0;
- LocationSummary* locs =
- new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
- locs->set_in(0, Location::RegisterLocation(RAX));
- locs->set_out(Location::RegisterLocation(RAX));
- return locs;
-}
-
-
-void ArgumentDefinitionTestInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- Register saved_args_desc = locs()->in(0).reg();
- Register result = locs()->out().reg();
-
- // Push the result place holder initialized to NULL.
- __ PushObject(Object::ZoneHandle());
- __ pushq(Immediate(Smi::RawValue(formal_parameter_index())));
- __ PushObject(formal_parameter_name());
- __ pushq(saved_args_desc);
- compiler->GenerateCallRuntime(token_pos(),
- deopt_id(),
- kArgumentDefinitionTestRuntimeEntry,
- locs());
- __ Drop(3);
- __ popq(result); // Pop bool result.
-}
-
-
static Condition TokenKindToSmiCondition(Token::Kind kind) {
switch (kind) {
case Token::kEQ: return EQUAL;
@@ -448,7 +419,7 @@
locs->set_out(Location::RequiresRegister());
return locs;
}
- if (is_checked_strict_equal()) {
+ if (IsCheckedStrictEqual()) {
const intptr_t kNumTemps = 1;
LocationSummary* locs =
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
@@ -880,7 +851,7 @@
EmitDoubleComparisonOp(compiler, *locs(), kind(), kNoBranch);
return;
}
- if (is_checked_strict_equal()) {
+ if (IsCheckedStrictEqual()) {
EmitCheckedStrictEqual(compiler, *ic_data(), *locs(), kind(), kNoBranch,
deopt_id());
return;
@@ -917,7 +888,7 @@
EmitDoubleComparisonOp(compiler, *locs(), kind(), branch);
return;
}
- if (is_checked_strict_equal()) {
+ if (IsCheckedStrictEqual()) {
EmitCheckedStrictEqual(compiler, *ic_data(), *locs(), kind(), branch,
deopt_id());
return;
diff --git a/runtime/vm/intrinsifier_arm.cc b/runtime/vm/intrinsifier_arm.cc
index 74ab05b..5b59253 100644
--- a/runtime/vm/intrinsifier_arm.cc
+++ b/runtime/vm/intrinsifier_arm.cc
@@ -237,7 +237,6 @@
// Note that R1 is Smi, i.e, times 2.
ASSERT(kSmiTagShift == 1);
- // Destroy R2 as we will not continue in the function.
__ ldr(R2, Address(SP, 0 * kWordSize)); // Value.
__ add(R1, R0, ShifterOperand(R1, LSL, 1)); // R1 is Smi.
__ StoreIntoObject(R0,
@@ -788,11 +787,14 @@
bool Intrinsifier::Integer_negate(Assembler* assembler) {
+ Label fall_through;
__ ldr(R0, Address(SP, + 0 * kWordSize)); // Grab first argument.
__ tst(R0, ShifterOperand(kSmiTagMask)); // Test for Smi.
- __ rsb(R0, R0, ShifterOperand(0), EQ); // R0 is a Smi. R0 <- 0 - R0.
- __ bx(LR, EQ); // Return.
+ __ b(&fall_through, NE);
+ __ rsbs(R0, R0, ShifterOperand(0)); // R0 is a Smi. R0 <- 0 - R0.
+ __ bx(LR, VC); // Return if there wasn't overflow, fall through otherwise.
// R0 is not a Smi. Fall through.
+ __ Bind(&fall_through);
return false;
}
@@ -1400,9 +1402,9 @@
__ LoadImmediate(R0, a_int32_value);
__ LoadFromOffset(kLoadWord, R2, R1, disp_0 - kHeapObjectTag);
__ LoadFromOffset(kLoadWord, R3, R1, disp_1 - kHeapObjectTag);
- __ mov(R6, ShifterOperand(R3, ASR, 31)); // Sign extend into R6.
- // 64-bit multiply and accumulate into R6:R3.
- __ smlal(R3, R6, R0, R2); // R6:R3 <- R6:R3 + R0 * R2.
+ __ 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);
__ Ret();
@@ -1422,7 +1424,6 @@
bool Intrinsifier::String_getHashCode(Assembler* assembler) {
- __ Untested("Intrinsifier::String_getHashCode");
__ ldr(R0, Address(SP, 0 * kWordSize));
__ ldr(R0, FieldAddress(R0, String::hash_offset()));
__ cmp(R0, ShifterOperand(0));
@@ -1439,9 +1440,8 @@
}
-// TODO(srdjan): Implement for two and four byte strings as well.
bool Intrinsifier::String_codeUnitAt(Assembler* assembler) {
- Label fall_through;
+ Label fall_through, try_two_byte_string;
__ ldr(R1, Address(SP, 0 * kWordSize)); // Index.
__ ldr(R0, Address(SP, 1 * kWordSize)); // String.
@@ -1452,12 +1452,22 @@
__ cmp(R1, ShifterOperand(R2));
__ b(&fall_through, CS); // Runtime throws exception.
__ CompareClassId(R0, kOneByteStringCid, R3);
- __ b(&fall_through, NE);
+ __ b(&try_two_byte_string, NE);
__ SmiUntag(R1);
__ AddImmediate(R0, OneByteString::data_offset() - kHeapObjectTag);
__ ldrb(R0, Address(R0, R1));
__ SmiTag(R0);
__ Ret();
+
+ __ Bind(&try_two_byte_string);
+ __ CompareClassId(R0, kTwoByteStringCid, R3);
+ __ b(&fall_through, NE);
+ ASSERT(kSmiTagShift == 1);
+ __ AddImmediate(R0, OneByteString::data_offset() - kHeapObjectTag);
+ __ ldrh(R0, Address(R0, R1));
+ __ SmiTag(R0);
+ __ Ret();
+
__ Bind(&fall_through);
return false;
}
diff --git a/runtime/vm/intrinsifier_ia32.cc b/runtime/vm/intrinsifier_ia32.cc
index 5b704ce..62ec306 100644
--- a/runtime/vm/intrinsifier_ia32.cc
+++ b/runtime/vm/intrinsifier_ia32.cc
@@ -235,7 +235,7 @@
__ j(ABOVE_EQUAL, &fall_through);
// Note that EBX is Smi, i.e, times 2.
ASSERT(kSmiTagShift == 1);
- // Destroy ECX as we will not continue in the function.
+ // Destroy ECX (ic data) as we will not continue in the function.
__ movl(ECX, Address(ESP, + 1 * kWordSize)); // Value.
__ StoreIntoObject(EAX,
FieldAddress(EAX, EBX, TIMES_2, Array::data_offset()),
@@ -1510,9 +1510,8 @@
}
-// TODO(srdjan): Implement for two and four byte strings as well.
bool Intrinsifier::String_codeUnitAt(Assembler* assembler) {
- Label fall_through;
+ Label fall_through, try_two_byte_string;
__ movl(EBX, Address(ESP, + 1 * kWordSize)); // Index.
__ movl(EAX, Address(ESP, + 2 * kWordSize)); // String.
__ testl(EBX, Immediate(kSmiTagMask));
@@ -1522,11 +1521,20 @@
// Runtime throws exception.
__ j(ABOVE_EQUAL, &fall_through, Assembler::kNearJump);
__ CompareClassId(EAX, kOneByteStringCid, EDI);
- __ j(NOT_EQUAL, &fall_through);
+ __ j(NOT_EQUAL, &try_two_byte_string, Assembler::kNearJump);
__ SmiUntag(EBX);
__ movzxb(EAX, FieldAddress(EAX, EBX, TIMES_1, OneByteString::data_offset()));
__ SmiTag(EAX);
__ ret();
+
+ __ Bind(&try_two_byte_string);
+ __ CompareClassId(EAX, kTwoByteStringCid, EDI);
+ __ j(NOT_EQUAL, &fall_through, Assembler::kNearJump);
+ ASSERT(kSmiTagShift == 1);
+ __ movzxw(EAX, FieldAddress(EAX, EBX, TIMES_1, OneByteString::data_offset()));
+ __ SmiTag(EAX);
+ __ ret();
+
__ Bind(&fall_through);
return false;
}
diff --git a/runtime/vm/intrinsifier_mips.cc b/runtime/vm/intrinsifier_mips.cc
index 2627738..9f4f783d 100644
--- a/runtime/vm/intrinsifier_mips.cc
+++ b/runtime/vm/intrinsifier_mips.cc
@@ -241,7 +241,6 @@
// Note that T1 is Smi, i.e, times 2.
ASSERT(kSmiTagShift == 1);
- // Destroy T2 as we will not continue in the function.
__ lw(T2, Address(SP, 0 * kWordSize)); // Value.
__ sll(T1, T1, 1); // T1 is Smi.
__ addu(T1, T0, T1);
@@ -795,11 +794,12 @@
bool Intrinsifier::Integer_negate(Assembler* assembler) {
Label fall_through;
- __ lw(V0, Address(SP, + 0 * kWordSize)); // Grabs first argument.
- __ andi(CMPRES, V0, Immediate(kSmiTagMask)); // Test for Smi.
+ __ lw(T0, Address(SP, + 0 * kWordSize)); // Grabs first argument.
+ __ andi(CMPRES, T0, Immediate(kSmiTagMask)); // Test for Smi.
__ bne(CMPRES, ZR, &fall_through); // Fall through if not a Smi.
+ __ SubuDetectOverflow(V0, ZR, T0, CMPRES);
+ __ bltz(CMPRES, &fall_through); // There was overflow.
__ Ret();
- __ delay_slot()->subu(V0, ZR, V0);
__ Bind(&fall_through);
return false;
}
@@ -1459,11 +1459,10 @@
__ LoadImmediate(T0, a_int32_value);
__ lw(T2, addr_0);
__ lw(T3, addr_1);
- __ sra(T6, T3, 31); // Sign extend T3 into T6.
__ mtlo(T3);
- __ mthi(T6); // HI:LO <- T6:T3
+ __ mthi(ZR); // HI:LO <- ZR:T3 Zero extend T3 into HI.
// 64-bit multiply and accumulate into T6:T3.
- __ madd(T0, T2); // HI:LO <- HI:LO + T0 * T2.
+ __ maddu(T0, T2); // HI:LO <- HI:LO + T0 * T2.
__ mflo(T3);
__ mfhi(T6);
__ sw(T3, addr_0);
@@ -1490,7 +1489,6 @@
bool Intrinsifier::String_getHashCode(Assembler* assembler) {
Label fall_through;
- __ Untested("Intrinsifier::String_getHashCode");
__ lw(T0, Address(SP, 0 * kWordSize));
__ lw(V0, FieldAddress(T0, String::hash_offset()));
__ beq(V0, ZR, &fall_through);
@@ -1508,9 +1506,8 @@
}
-// TODO(srdjan): Implement for two and four byte strings as well.
bool Intrinsifier::String_codeUnitAt(Assembler* assembler) {
- Label fall_through;
+ Label fall_through, try_two_byte_string;
__ lw(T1, Address(SP, 0 * kWordSize)); // Index.
__ lw(T0, Address(SP, 1 * kWordSize)); // String.
@@ -1522,7 +1519,7 @@
// Runtime throws exception.
__ BranchUnsignedGreaterEqual(T1, T2, &fall_through);
__ LoadClassId(TMP1, T0); // Class ID check.
- __ BranchNotEqual(TMP1, kOneByteStringCid, &fall_through);
+ __ BranchNotEqual(TMP1, kOneByteStringCid, &try_two_byte_string);
// Grab byte and return.
__ SmiUntag(T1);
@@ -1530,6 +1527,15 @@
__ lbu(V0, FieldAddress(T2, OneByteString::data_offset()));
__ Ret();
__ delay_slot()->SmiTag(V0);
+
+ __ Bind(&try_two_byte_string);
+ __ BranchNotEqual(TMP1, kTwoByteStringCid, &fall_through);
+ ASSERT(kSmiTagShift == 1);
+ __ addu(T2, T0, T1);
+ __ lhu(V0, FieldAddress(T2, OneByteString::data_offset()));
+ __ Ret();
+ __ delay_slot()->SmiTag(V0);
+
__ Bind(&fall_through);
return false;
}
diff --git a/runtime/vm/intrinsifier_x64.cc b/runtime/vm/intrinsifier_x64.cc
index 15bec3d..5daa399 100644
--- a/runtime/vm/intrinsifier_x64.cc
+++ b/runtime/vm/intrinsifier_x64.cc
@@ -189,7 +189,7 @@
__ j(ABOVE_EQUAL, &fall_through);
// Note that RBX is Smi, i.e, times 2.
ASSERT(kSmiTagShift == 1);
- // Destroy RCX as we will not continue in the function.
+ // Destroy RCX (ic data) as we will not continue in the function.
__ StoreIntoObject(RAX,
FieldAddress(RAX, RCX, TIMES_4, Array::data_offset()),
RDX);
@@ -1426,9 +1426,8 @@
}
-// TODO(srdjan): Implement for two and four byte strings as well.
bool Intrinsifier::String_codeUnitAt(Assembler* assembler) {
- Label fall_through;
+ Label fall_through, try_two_byte_string;
__ movq(RCX, Address(RSP, + 1 * kWordSize)); // Index.
__ movq(RAX, Address(RSP, + 2 * kWordSize)); // String.
__ testq(RCX, Immediate(kSmiTagMask));
@@ -1438,11 +1437,20 @@
// Runtime throws exception.
__ j(ABOVE_EQUAL, &fall_through, Assembler::kNearJump);
__ CompareClassId(RAX, kOneByteStringCid);
- __ j(NOT_EQUAL, &fall_through);
+ __ j(NOT_EQUAL, &try_two_byte_string, Assembler::kNearJump);
__ SmiUntag(RCX);
__ movzxb(RAX, FieldAddress(RAX, RCX, TIMES_1, OneByteString::data_offset()));
__ SmiTag(RAX);
__ ret();
+
+ __ Bind(&try_two_byte_string);
+ __ CompareClassId(RAX, kTwoByteStringCid);
+ __ j(NOT_EQUAL, &fall_through, Assembler::kNearJump);
+ ASSERT(kSmiTagShift == 1);
+ __ movzxw(RAX, FieldAddress(RAX, RCX, TIMES_1, OneByteString::data_offset()));
+ __ SmiTag(RAX);
+ __ ret();
+
__ Bind(&fall_through);
return false;
}
diff --git a/runtime/vm/mirrors_api_impl.cc b/runtime/vm/mirrors_api_impl.cc
index 537c9ed..82132be 100644
--- a/runtime/vm/mirrors_api_impl.cc
+++ b/runtime/vm/mirrors_api_impl.cc
@@ -48,24 +48,29 @@
// --- Classes and Interfaces Reflection ---
-DART_EXPORT Dart_Handle Dart_ClassName(Dart_Handle clazz) {
+DART_EXPORT Dart_Handle Dart_ClassName(Dart_Handle object) {
Isolate* isolate = Isolate::Current();
DARTSCOPE(isolate);
- const Class& cls = Api::UnwrapClassHandle(isolate, clazz);
- if (cls.IsNull()) {
- RETURN_TYPE_ERROR(isolate, clazz, Class);
+ const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(object));
+ if (obj.IsType() || obj.IsClass()) {
+ const Class& cls = (obj.IsType()) ?
+ Class::Handle(Type::Cast(obj).type_class()) : Class::Cast(obj);
+ return Api::NewHandle(isolate, cls.UserVisibleName());
+ } else {
+ RETURN_TYPE_ERROR(isolate, object, Class/Type);
}
- return Api::NewHandle(isolate, cls.UserVisibleName());
}
-DART_EXPORT Dart_Handle Dart_ClassGetLibrary(Dart_Handle clazz) {
+DART_EXPORT Dart_Handle Dart_ClassGetLibrary(Dart_Handle object) {
Isolate* isolate = Isolate::Current();
DARTSCOPE(isolate);
- const Class& cls = Api::UnwrapClassHandle(isolate, clazz);
- if (cls.IsNull()) {
- RETURN_TYPE_ERROR(isolate, clazz, Class);
+ const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(object));
+ if (!obj.IsType() && !obj.IsClass()) {
+ RETURN_TYPE_ERROR(isolate, object, Class/Type);
}
+ const Class& cls = (obj.IsType()) ?
+ Class::Handle(Type::Cast(obj).type_class()) : Class::Cast(obj);
#if defined(DEBUG)
const Library& lib = Library::Handle(cls.library());
@@ -81,15 +86,16 @@
}
-DART_EXPORT Dart_Handle Dart_ClassGetInterfaceCount(Dart_Handle clazz,
+DART_EXPORT Dart_Handle Dart_ClassGetInterfaceCount(Dart_Handle object,
intptr_t* count) {
Isolate* isolate = Isolate::Current();
DARTSCOPE(isolate);
- const Class& cls = Api::UnwrapClassHandle(isolate, clazz);
- if (cls.IsNull()) {
- RETURN_TYPE_ERROR(isolate, clazz, Class);
+ const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(object));
+ if (!obj.IsType() && !obj.IsClass()) {
+ RETURN_TYPE_ERROR(isolate, object, Class/Type);
}
-
+ const Class& cls = (obj.IsType()) ?
+ Class::Handle(Type::Cast(obj).type_class()) : Class::Cast(obj);
const Array& interface_types = Array::Handle(isolate, cls.interfaces());
if (interface_types.IsNull()) {
*count = 0;
@@ -100,14 +106,16 @@
}
-DART_EXPORT Dart_Handle Dart_ClassGetInterfaceAt(Dart_Handle clazz,
+DART_EXPORT Dart_Handle Dart_ClassGetInterfaceAt(Dart_Handle object,
intptr_t index) {
Isolate* isolate = Isolate::Current();
DARTSCOPE(isolate);
- const Class& cls = Api::UnwrapClassHandle(isolate, clazz);
- if (cls.IsNull()) {
- RETURN_TYPE_ERROR(isolate, clazz, Class);
+ const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(object));
+ if (!obj.IsType() && !obj.IsClass()) {
+ RETURN_TYPE_ERROR(isolate, object, Class/Type);
}
+ const Class& cls = (obj.IsType()) ?
+ Class::Handle(Type::Cast(obj).type_class()) : Class::Cast(obj);
// Finalize all classes.
Dart_Handle state = Api::CheckIsolateState(isolate);
@@ -131,27 +139,30 @@
}
-DART_EXPORT bool Dart_ClassIsTypedef(Dart_Handle clazz) {
+DART_EXPORT bool Dart_ClassIsTypedef(Dart_Handle object) {
Isolate* isolate = Isolate::Current();
DARTSCOPE(isolate);
- const Class& cls = Api::UnwrapClassHandle(isolate, clazz);
- if (cls.IsNull()) {
- RETURN_TYPE_ERROR(isolate, clazz, Class);
+ const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(object));
+ if (!obj.IsType() && !obj.IsClass()) {
+ RETURN_TYPE_ERROR(isolate, object, Class/Type);
}
+ const Class& cls = (obj.IsType()) ?
+ Class::Handle(Type::Cast(obj).type_class()) : Class::Cast(obj);
// For now we represent typedefs as non-canonical signature classes.
// I anticipate this may change if we make typedefs more general.
return cls.IsSignatureClass() && !cls.IsCanonicalSignatureClass();
}
-DART_EXPORT Dart_Handle Dart_ClassGetTypedefReferent(Dart_Handle clazz) {
+DART_EXPORT Dart_Handle Dart_ClassGetTypedefReferent(Dart_Handle object) {
Isolate* isolate = Isolate::Current();
DARTSCOPE(isolate);
- const Class& cls = Api::UnwrapClassHandle(isolate, clazz);
- if (cls.IsNull()) {
- RETURN_TYPE_ERROR(isolate, clazz, Class);
+ const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(object));
+ if (!obj.IsType() && !obj.IsClass()) {
+ RETURN_TYPE_ERROR(isolate, object, Class/Type);
}
-
+ const Class& cls = (obj.IsType()) ?
+ Class::Handle(Type::Cast(obj).type_class()) : Class::Cast(obj);
if (!cls.IsSignatureClass() && !cls.IsCanonicalSignatureClass()) {
const String& cls_name = String::Handle(cls.UserVisibleName());
return Api::NewError("%s: class '%s' is not a typedef class. "
@@ -164,26 +175,30 @@
}
-DART_EXPORT bool Dart_ClassIsFunctionType(Dart_Handle clazz) {
+DART_EXPORT bool Dart_ClassIsFunctionType(Dart_Handle object) {
Isolate* isolate = Isolate::Current();
DARTSCOPE(isolate);
- const Class& cls = Api::UnwrapClassHandle(isolate, clazz);
- if (cls.IsNull()) {
- RETURN_TYPE_ERROR(isolate, clazz, Class);
+ const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(object));
+ if (!obj.IsType() && !obj.IsClass()) {
+ RETURN_TYPE_ERROR(isolate, object, Class/Type);
}
+ const Class& cls = (obj.IsType()) ?
+ Class::Handle(Type::Cast(obj).type_class()) : Class::Cast(obj);
// A class represents a function type when it is a canonical
// signature class.
return cls.IsCanonicalSignatureClass();
}
-DART_EXPORT Dart_Handle Dart_ClassGetFunctionTypeSignature(Dart_Handle clazz) {
+DART_EXPORT Dart_Handle Dart_ClassGetFunctionTypeSignature(Dart_Handle object) {
Isolate* isolate = Isolate::Current();
DARTSCOPE(isolate);
- const Class& cls = Api::UnwrapClassHandle(isolate, clazz);
- if (cls.IsNull()) {
- RETURN_TYPE_ERROR(isolate, clazz, Class);
+ const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(object));
+ if (!obj.IsType() && !obj.IsClass()) {
+ RETURN_TYPE_ERROR(isolate, object, Class/Type);
}
+ const Class& cls = (obj.IsType()) ?
+ Class::Handle(Type::Cast(obj).type_class()) : Class::Cast(obj);
if (!cls.IsCanonicalSignatureClass()) {
const String& cls_name = String::Handle(cls.UserVisibleName());
return Api::NewError("%s: class '%s' is not a function-type class. "
@@ -221,8 +236,12 @@
Function& func = Function::Handle();
String& name = String::Handle();
- if (obj.IsClass()) {
- const Class& cls = Class::Cast(obj);
+ if (obj.IsType() || obj.IsClass()) {
+ // For backwards compatibility we allow class objects to be passed in
+ // for now. This needs to be removed once all code that uses class
+ // objects to invoke Dart_Invoke is removed.
+ const Class& cls = (obj.IsType()) ?
+ Class::Handle(Type::Cast(obj).type_class()) : Class::Cast(obj);
const Error& error = Error::Handle(isolate, cls.EnsureIsFinalized(isolate));
if (!error.IsNull()) {
return Api::NewHandle(isolate, error.raw());
@@ -283,8 +302,12 @@
Function& func = Function::Handle(isolate);
String& tmp_name = String::Handle(isolate);
- if (obj.IsClass()) {
- const Class& cls = Class::Cast(obj);
+ if (obj.IsType() || obj.IsClass()) {
+ // For backwards compatibility we allow class objects to be passed in
+ // for now. This needs to be removed once all code that uses class
+ // objects to invoke Dart_Invoke is removed.
+ const Class& cls = (obj.IsType()) ?
+ Class::Handle(Type::Cast(obj).type_class()) : Class::Cast(obj);
// Case 1. Lookup the unmodified function name.
func = cls.LookupFunctionAllowPrivate(func_name);
@@ -561,8 +584,12 @@
Field& field = Field::Handle(isolate);
String& name = String::Handle(isolate);
- if (obj.IsClass()) {
- const Class& cls = Class::Cast(obj);
+ if (obj.IsType() || obj.IsClass()) {
+ // For backwards compatibility we allow class objects to be passed in
+ // for now. This needs to be removed once all code that uses class
+ // objects to invoke Dart_Invoke is removed.
+ const Class& cls = (obj.IsType()) ?
+ Class::Handle(Type::Cast(obj).type_class()) : Class::Cast(obj);
const Error& error = Error::Handle(isolate, cls.EnsureIsFinalized(isolate));
if (!error.IsNull()) {
return Api::NewHandle(isolate, error.raw());
@@ -614,8 +641,12 @@
if (var_name.IsNull()) {
RETURN_TYPE_ERROR(isolate, variable_name, String);
}
- if (obj.IsClass()) {
- const Class& cls = Class::Cast(obj);
+ if (obj.IsType() || obj.IsClass()) {
+ // For backwards compatibility we allow class objects to be passed in
+ // for now. This needs to be removed once all code that uses class
+ // objects to invoke Dart_Invoke is removed.
+ const Class& cls = (obj.IsType()) ?
+ Class::Handle(Type::Cast(obj).type_class()) : Class::Cast(obj);
return Api::NewHandle(isolate, cls.LookupField(var_name));
}
if (obj.IsLibrary()) {
@@ -684,14 +715,15 @@
}
-DART_EXPORT Dart_Handle Dart_GetTypeVariableNames(Dart_Handle clazz) {
+DART_EXPORT Dart_Handle Dart_GetTypeVariableNames(Dart_Handle object) {
Isolate* isolate = Isolate::Current();
DARTSCOPE(isolate);
- const Class& cls = Api::UnwrapClassHandle(isolate, clazz);
- if (cls.IsNull()) {
- RETURN_TYPE_ERROR(isolate, clazz, Class);
+ const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(object));
+ if (!obj.IsType() && !obj.IsClass()) {
+ RETURN_TYPE_ERROR(isolate, object, Class/Type);
}
-
+ const Class& cls = (obj.IsType()) ?
+ Class::Handle(Type::Cast(obj).type_class()) : Class::Cast(obj);
const intptr_t num_type_params = cls.NumTypeParameters();
const TypeArguments& type_params =
TypeArguments::Handle(cls.type_parameters());
@@ -710,14 +742,16 @@
DART_EXPORT Dart_Handle Dart_LookupTypeVariable(
- Dart_Handle clazz,
+ Dart_Handle object,
Dart_Handle type_variable_name) {
Isolate* isolate = Isolate::Current();
DARTSCOPE(isolate);
- const Class& cls = Api::UnwrapClassHandle(isolate, clazz);
- if (cls.IsNull()) {
- RETURN_TYPE_ERROR(isolate, clazz, Class);
+ const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(object));
+ if (!obj.IsType() && !obj.IsClass()) {
+ RETURN_TYPE_ERROR(isolate, object, Class/Type);
}
+ const Class& cls = (obj.IsType()) ?
+ Class::Handle(Type::Cast(obj).type_class()) : Class::Cast(obj);
const String& var_name = Api::UnwrapStringHandle(isolate, type_variable_name);
if (var_name.IsNull()) {
RETURN_TYPE_ERROR(isolate, type_variable_name, String);
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 966aa45..b043be0 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -4626,7 +4626,7 @@
const Class& cls = Class::Handle(Owner());
if (IsClosureFunction()) {
- if (IsLocalFunction()) {
+ if (IsLocalFunction() && !IsImplicitClosureFunction()) {
const Function& parent = Function::Handle(parent_function());
tmp = parent.QualifiedUserVisibleName();
} else {
@@ -13289,7 +13289,7 @@
const char* Closure::ToCString(const Instance& closure) {
const Function& fun = Function::Handle(Closure::function(closure));
const bool is_implicit_closure = fun.IsImplicitClosureFunction();
- const char* fun_sig = String::Handle(fun.Signature()).ToCString();
+ const char* fun_sig = String::Handle(fun.UserVisibleSignature()).ToCString();
const char* from = is_implicit_closure ? " from " : "";
const char* fun_desc = is_implicit_closure ? fun.ToCString() : "";
const char* format = "Closure: %s%s%s";
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index b307f6a..3dfc08a 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -1324,6 +1324,17 @@
return BuildSignature(instantiate, kInternalName, TypeArguments::Handle());
}
+ // Build a string of the form '(T, {b: B, c: C}) => R' representing the
+ // user visible signature of the given function. In this example, T and R are
+ // type parameters of class C, the owner of the function.
+ // Implicit parameters are hidden, as well as the prefix denoting the
+ // signature class and its type parameters.
+ RawString* UserVisibleSignature() const {
+ const bool instantiate = false;
+ return BuildSignature(
+ instantiate, kUserVisibleName, TypeArguments::Handle());
+ }
+
// Build a string of the form '(A, {b: B, c: C}) => D' representing the
// signature of the given function, where all generic types (e.g. '<T, R>' in
// 'C<T, R>(T, {b: B, c: C}) => R') are instantiated using the given
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
index 8773376..a3c43dd 100644
--- a/runtime/vm/parser.cc
+++ b/runtime/vm/parser.cc
@@ -131,50 +131,22 @@
}
-LocalVariable* ParsedFunction::GetSavedArgumentsDescriptorVar() const {
- const int num_parameters = function().NumParameters();
- LocalScope* scope = node_sequence()->scope();
- if (scope->num_variables() > num_parameters) {
- LocalVariable* saved_args_desc_var = scope->VariableAt(num_parameters);
- ASSERT(saved_args_desc_var != NULL);
- // The scope of the formal parameters may also contain at this position
- // an alias for the saved arguments descriptor variable of the enclosing
- // function (check its scope owner) or an internal variable such as the
- // expression temp variable or the saved entry context variable (check its
- // name).
- if ((saved_args_desc_var->owner() == scope) &&
- saved_args_desc_var->name().StartsWith(
- Symbols::SavedArgDescVarPrefix())) {
- return saved_args_desc_var;
- }
- }
- return NULL;
-}
-
-
void ParsedFunction::AllocateVariables() {
LocalScope* scope = node_sequence()->scope();
const intptr_t num_fixed_params = function().num_fixed_parameters();
const intptr_t num_opt_params = function().NumOptionalParameters();
- intptr_t num_params = num_fixed_params + num_opt_params;
+ const intptr_t num_params = num_fixed_params + num_opt_params;
// Compute start indices to parameters and locals, and the number of
// parameters to copy.
if (num_opt_params == 0) {
// Parameter i will be at fp[kParamEndSlotFromFp + num_params - i] and
// local variable j will be at fp[kFirstLocalSlotFromFp - j].
- ASSERT(GetSavedArgumentsDescriptorVar() == NULL);
first_parameter_index_ = kParamEndSlotFromFp + num_params;
first_stack_local_index_ = kFirstLocalSlotFromFp;
num_copied_params_ = 0;
} else {
// Parameter i will be at fp[kFirstLocalSlotFromFp - i] and local variable
// j will be at fp[kFirstLocalSlotFromFp - num_params - j].
- // The saved arguments descriptor variable must be allocated similarly to
- // a parameter, so that it gets both a frame slot and a context slot when
- // captured.
- if (GetSavedArgumentsDescriptorVar() != NULL) {
- num_params += 1;
- }
first_parameter_index_ = kFirstLocalSlotFromFp;
first_stack_local_index_ = first_parameter_index_ - num_params;
num_copied_params_ = num_params;
@@ -6417,13 +6389,6 @@
node_to_inline = inner_try_block->GetNodeToInlineFinally(node_index);
tokens_iterator_.SetCurrentPosition(finally_pos);
}
- if (!generic_catch_seen) {
- // No generic catch handler exists so execute this finally block
- // before rethrowing the exception.
- finally_block = ParseFinallyBlock();
- catch_handler_list->Add(finally_block);
- tokens_iterator_.SetCurrentPosition(finally_pos);
- }
finally_block = ParseFinallyBlock();
} else {
if (!catch_seen) {
@@ -8074,97 +8039,6 @@
}
-// Returns true if ident resolves to a formal parameter of the current function
-// or of one of its enclosing functions.
-// Make sure not to capture the formal parameter, since it is not accessed.
-bool Parser::IsFormalParameter(const String& ident,
- Function* owner_function,
- LocalScope** owner_scope,
- intptr_t* local_index) {
- if (current_block_ == NULL) {
- return false;
- }
- if (ident.Equals(Symbols::This())) {
- // 'this' is not a formal parameter that can be tested with '?this'.
- return false;
- }
- // Since an argument definition test does not use the value of the formal
- // parameter, there is no reason to capture it.
- const bool kTestOnly = true; // No capturing.
- LocalVariable* local =
- current_block_->scope->LookupVariable(ident, kTestOnly);
- if ((local == NULL) ||
- (local->owner()->HasContextLevel() &&
- (local->owner()->context_level() < 1))) {
- if ((local == NULL) && !current_function().IsLocalFunction()) {
- // We are not generating code for a local function, so all locals,
- // captured or not, are in scope. However, 'ident' was not found, so it
- // does not exist.
- return false;
- }
- // The formal parameter belongs to an enclosing function and may not have
- // been captured, so it was not included in the context scope and it cannot
- // be found by LookupVariable.
- ASSERT((local == NULL) || local->is_captured());
- // 'ident' necessarily refers to the formal parameter of one of the
- // enclosing functions, or a compile error would have prevented the
- // outermost enclosing function to be executed and we would not be compiling
- // this local function.
- // Therefore, look for ident directly in the formal parameter lists of the
- // enclosing functions.
- // There is no need to return the owner_scope, since the caller will not
- // create the saved_arguments_descriptor variable, which already exists.
- Function& function = Function::Handle(innermost_function().raw());
- String& param_name = String::Handle();
- do {
- const int num_parameters = function.NumParameters();
- for (intptr_t i = 0; i < num_parameters; i++) {
- param_name = function.ParameterNameAt(i);
- if (ident.Equals(param_name)) {
- *owner_function = function.raw();
- *owner_scope = NULL;
- *local_index = i;
- return true;
- }
- }
- function = function.parent_function();
- } while (!function.IsNull());
- UNREACHABLE();
- }
- // Verify that local is a formal parameter of the current function or of one
- // of its enclosing functions.
- // Note that scopes are not yet associated to functions.
- Function& function = Function::Handle(innermost_function().raw());
- LocalScope* scope = current_block_->scope;
- while (scope != NULL) {
- ASSERT(!function.IsNull());
- // Find the top scope for this function level.
- while ((scope->parent() != NULL) &&
- (scope->parent()->function_level() == scope->function_level())) {
- scope = scope->parent();
- }
- if (scope == local->owner()) {
- // Scope contains 'local' and the formal parameters of 'function'.
- const int num_parameters = function.NumParameters();
- for (intptr_t i = 0; i < num_parameters; i++) {
- if (scope->VariableAt(i) == local) {
- *owner_function = function.raw();
- *owner_scope = scope;
- *local_index = i;
- return true;
- }
- }
- // The variable 'local' is not a formal parameter.
- return false;
- }
- scope = scope->parent();
- function = function.parent_function();
- }
- // The variable 'local' does not belong to a function top scope.
- return false;
-}
-
-
void Parser::CheckInstanceFieldAccess(intptr_t field_pos,
const String& field_name) {
// Fields are not accessible from a static function, except from a
@@ -9649,57 +9523,6 @@
}
-AstNode* Parser::ParseArgumentDefinitionTest() {
- const intptr_t test_pos = TokenPos();
- ConsumeToken();
- const intptr_t ident_pos = TokenPos();
- String* ident = ExpectIdentifier("parameter name expected");
- Function& owner_function = Function::Handle();
- LocalScope* owner_scope;
- intptr_t param_index;
- if (!IsFormalParameter(*ident, &owner_function, &owner_scope, ¶m_index)) {
- ErrorMsg(ident_pos, "formal parameter name expected");
- }
- if (param_index < owner_function.num_fixed_parameters()) {
- // The formal parameter is not optional, therefore the corresponding
- // argument is always passed and defined.
- return new LiteralNode(test_pos, Bool::True());
- }
- char name[64];
- OS::SNPrint(name, 64, "%s_%"Pd"",
- Symbols::Name(Symbols::kSavedArgDescVarPrefixId),
- owner_function.token_pos());
- const String& saved_args_desc_name = String::ZoneHandle(Symbols::New(name));
- LocalVariable* saved_args_desc_var = LookupLocalScope(saved_args_desc_name);
- if (saved_args_desc_var == NULL) {
- ASSERT(owner_scope != NULL);
- saved_args_desc_var =
- new LocalVariable(owner_function.token_pos(),
- saved_args_desc_name,
- Type::ZoneHandle(Type::ArrayType()));
- saved_args_desc_var->set_is_final();
- // The saved arguments descriptor variable must be added just after the
- // formal parameters. This simplifies the 2-step saving of a captured
- // arguments descriptor.
- // At this time, the owner scope should only contain formal parameters.
- ASSERT(owner_scope->num_variables() == owner_function.NumParameters());
- bool success = owner_scope->AddVariable(saved_args_desc_var);
- ASSERT(success);
- // Capture the saved arguments descriptor variable if necessary.
- LocalVariable* local = LookupLocalScope(saved_args_desc_name);
- ASSERT(local == saved_args_desc_var);
- }
- // If we currently generate code for the local function of an enclosing owner
- // function, the saved arguments descriptor variable must have been captured
- // by the above lookup.
- ASSERT((owner_function.raw() == innermost_function().raw()) ||
- saved_args_desc_var->is_captured());
- const String& param_name = String::ZoneHandle(Symbols::New(*ident));
- return new ArgumentDefinitionTestNode(
- test_pos, param_index, param_name, saved_args_desc_var);
-}
-
-
AstNode* Parser::ParsePrimary() {
TRACE_PARSER("ParsePrimary");
ASSERT(!is_top_level_);
@@ -9830,8 +9653,6 @@
} else {
primary = new PrimaryNode(TokenPos(), Symbols::Super());
}
- } else if (CurrentToken() == Token::kCONDITIONAL) {
- primary = ParseArgumentDefinitionTest();
} else {
UnexpectedToken();
}
@@ -10031,12 +9852,6 @@
case Token::kINDEX:
SkipCompoundLiteral();
break;
- case Token::kCONDITIONAL:
- ConsumeToken();
- if (IsIdentifier()) {
- ConsumeToken();
- }
- break;
default:
if (IsIdentifier()) {
ConsumeToken(); // Handle pseudo-keyword identifiers.
diff --git a/runtime/vm/parser.h b/runtime/vm/parser.h
index f80c674..6fe1e2e 100644
--- a/runtime/vm/parser.h
+++ b/runtime/vm/parser.h
@@ -87,10 +87,6 @@
saved_entry_context_var_ = saved_entry_context_var;
}
- // Returns NULL if this function does not save the arguments descriptor on
- // entry.
- LocalVariable* GetSavedArgumentsDescriptorVar() const;
-
LocalVariable* expression_temp_var() const {
ASSERT(has_expression_temp_var());
return expression_temp_var_;
@@ -533,7 +529,6 @@
bool is_const,
const AbstractTypeArguments& type_arguments);
AstNode* ParseNewOperator(Token::Kind op_kind);
- AstNode* ParseArgumentDefinitionTest();
// An implicit argument, if non-null, is prepended to the returned list.
ArgumentListNode* ParseActualParameters(ArgumentListNode* implicit_arguments,
@@ -551,10 +546,6 @@
bool consume_cascades);
LocalVariable* LookupLocalScope(const String& ident);
- bool IsFormalParameter(const String& ident,
- Function* owner_function,
- LocalScope** owner_scope,
- intptr_t* local_index);
void CheckInstanceFieldAccess(intptr_t field_pos, const String& field_name);
bool ParsingStaticMember() const;
const Type* ReceiverType(intptr_t type_pos) const;
diff --git a/runtime/vm/resolver.cc b/runtime/vm/resolver.cc
index 78bf848..3c39714 100644
--- a/runtime/vm/resolver.cc
+++ b/runtime/vm/resolver.cc
@@ -76,7 +76,7 @@
// When an expression obj.M is evaluated for the first time and receiver obj
// does not have a getter called M but has a method called M then an extractor
// is created and injected as a getter (under the name get:M) into the class
-// ownining method M.
+// owning method M.
static RawFunction* CreateMethodExtractor(const String& getter_name,
const Function& method) {
const Function& closure_function =
diff --git a/runtime/vm/scopes.cc b/runtime/vm/scopes.cc
index c7b0c05..153ca1e 100644
--- a/runtime/vm/scopes.cc
+++ b/runtime/vm/scopes.cc
@@ -282,7 +282,6 @@
desc.info.index = var->index();
vars->Add(desc);
}
- // The saved arguments descriptor variable is not currently collected.
}
}
LocalScope* child = this->child();
diff --git a/runtime/vm/simulator_arm.cc b/runtime/vm/simulator_arm.cc
index 1401625..07b8383 100644
--- a/runtime/vm/simulator_arm.cc
+++ b/runtime/vm/simulator_arm.cc
@@ -1697,33 +1697,22 @@
}
break;
}
- case 4: {
+ case 4:
// Registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs.
// Format(instr, "umull'cond's 'rd, 'rn, 'rm, 'rs");
- uint64_t left_op = static_cast<uint32_t>(rm_val);
- uint64_t right_op = static_cast<uint32_t>(rs_val);
- uint64_t result = left_op * right_op;
- int32_t hi_res = Utils::High32Bits(result);
- int32_t lo_res = Utils::Low32Bits(result);
- set_register(rd, lo_res);
- set_register(rn, hi_res);
- if (instr->HasS()) {
- if (lo_res != 0) {
- // Collapse bits 0..31 into bit 32 so that 32-bit Z check works.
- hi_res |= 1;
- }
- ASSERT((result == 0) == (hi_res == 0)); // Z bit
- ASSERT(((result & (1LL << 63)) != 0) == (hi_res < 0)); // N bit
- SetNZFlags(hi_res);
- }
- break;
- }
case 6: {
// Registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs.
// Format(instr, "smull'cond's 'rd, 'rn, 'rm, 'rs");
- int64_t left_op = static_cast<int32_t>(rm_val);
- int64_t right_op = static_cast<int32_t>(rs_val);
- int64_t result = left_op * right_op;
+ int64_t result;
+ if (instr->Bits(21, 3) == 4) { // umull
+ uint64_t left_op = static_cast<uint32_t>(rm_val);
+ uint64_t right_op = static_cast<uint32_t>(rs_val);
+ result = left_op * right_op; // Unsigned nultiplication.
+ } else { // smull
+ int64_t left_op = static_cast<int32_t>(rm_val);
+ int64_t right_op = static_cast<int32_t>(rs_val);
+ result = left_op * right_op; // Signed nultiplication.
+ }
int32_t hi_res = Utils::High32Bits(result);
int32_t lo_res = Utils::Low32Bits(result);
set_register(rd, lo_res);
@@ -1739,17 +1728,27 @@
}
break;
}
+ case 5:
+ // Registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs.
+ // Format(instr, "umlal'cond's 'rd, 'rn, 'rm, 'rs");
case 7: {
// Registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs.
// Format(instr, "smlal'cond's 'rd, 'rn, 'rm, 'rs");
int32_t rd_lo_val = get_register(rd);
int32_t rd_hi_val = get_register(rn);
- int64_t left_op = static_cast<int32_t>(rm_val);
- int64_t right_op = static_cast<int32_t>(rs_val);
uint32_t accum_lo = static_cast<uint32_t>(rd_lo_val);
int32_t accum_hi = static_cast<int32_t>(rd_hi_val);
int64_t accum = Utils::LowHighTo64Bits(accum_lo, accum_hi);
- int64_t result = accum + left_op * right_op;
+ int64_t result;
+ if (instr->Bits(21, 3) == 5) { // umlal
+ uint64_t left_op = static_cast<uint32_t>(rm_val);
+ uint64_t right_op = static_cast<uint32_t>(rs_val);
+ result = accum + left_op * right_op; // Unsigned nultiplication.
+ } else { // smlal
+ int64_t left_op = static_cast<int32_t>(rm_val);
+ int64_t right_op = static_cast<int32_t>(rs_val);
+ result = accum + left_op * right_op; // Signed nultiplication.
+ }
int32_t hi_res = Utils::High32Bits(result);
int32_t lo_res = Utils::Low32Bits(result);
set_register(rd, lo_res);
diff --git a/runtime/vm/simulator_mips.cc b/runtime/vm/simulator_mips.cc
index a04d8f1..fd858ec 100644
--- a/runtime/vm/simulator_mips.cc
+++ b/runtime/vm/simulator_mips.cc
@@ -1394,8 +1394,8 @@
uint32_t lo = get_lo_register();
int32_t hi = get_hi_register();
int64_t accum = Utils::LowHighTo64Bits(lo, hi);
- int64_t rs = static_cast<int64_t>(get_register(instr->RsField()));
- int64_t rt = static_cast<int64_t>(get_register(instr->RtField()));
+ int64_t rs = get_register(instr->RsField());
+ int64_t rt = get_register(instr->RtField());
int64_t res = accum + rs * rt;
set_hi_register(Utils::High32Bits(res));
set_lo_register(Utils::Low32Bits(res));
@@ -1408,8 +1408,8 @@
uint32_t lo = get_lo_register();
uint32_t hi = get_hi_register();
uint64_t accum = Utils::LowHighTo64Bits(lo, hi);
- uint64_t rs = static_cast<uint64_t>(get_register(instr->RsField()));
- uint64_t rt = static_cast<uint64_t>(get_register(instr->RtField()));
+ uint64_t rs = static_cast<uint32_t>(get_register(instr->RsField()));
+ uint64_t rt = static_cast<uint32_t>(get_register(instr->RtField()));
uint64_t res = accum + rs * rt;
set_hi_register(Utils::High32Bits(res));
set_lo_register(Utils::Low32Bits(res));
@@ -2028,7 +2028,7 @@
delay_slot_ = true;
icount_++;
Instr* instr = Instr::At(pc_ + Instr::kInstrSize);
- if (icount_ == FLAG_stop_sim_at) {
+ if ((FLAG_stop_sim_at != 0) && (icount_ == FLAG_stop_sim_at)) {
SimulatorDebugger dbg(this);
dbg.Stop(instr, "Instruction count reached");
}
diff --git a/runtime/vm/stub_code.h b/runtime/vm/stub_code.h
index d634fe1..185ca37 100644
--- a/runtime/vm/stub_code.h
+++ b/runtime/vm/stub_code.h
@@ -39,7 +39,8 @@
V(Subtype3TestCache) \
V(GetStackPointer) \
V(JumpToExceptionHandler) \
- V(IdenticalWithNumberCheck) \
+ V(UnoptimizedIdenticalWithNumberCheck) \
+ V(OptimizedIdenticalWithNumberCheck) \
// Is it permitted for the stubs above to refer to Object::null(), which is
// allocated in the VM isolate and shared across all isolates.
@@ -197,6 +198,13 @@
static void GenerateUsageCounterIncrement(Assembler* assembler,
Register temp_reg);
static void GenerateOptimizedUsageCounterIncrement(Assembler* assembler);
+
+ static void GenerateIdenticalWithNumberCheckStub(
+ Assembler* assembler,
+ const Register left,
+ const Register right,
+ const Register temp1 = kNoRegister,
+ const Register temp2 = kNoRegister);
};
} // namespace dart
diff --git a/runtime/vm/stub_code_arm.cc b/runtime/vm/stub_code_arm.cc
index 6e26bd9..4b25872 100644
--- a/runtime/vm/stub_code_arm.cc
+++ b/runtime/vm/stub_code_arm.cc
@@ -1281,8 +1281,12 @@
}
-// The target function was not found, so invoke method
-// "dynamic noSuchMethod(Invocation invocation)".
+// Called for invoking "dynamic noSuchMethod(Invocation invocation)" function
+// from the entry code of a dart function after an error in passed argument
+// name or number is detected.
+// Input parameters:
+// LR : return address.
+// SP : address of last argument.
// R5: inline cache data object.
// R4: arguments descriptor array.
void StubCode::GenerateCallNoSuchMethodFunctionStub(Assembler* assembler) {
@@ -1974,24 +1978,14 @@
// Does identical check (object references are equal or not equal) with special
// checks for boxed numbers.
// LR: return address.
-// SP + 4: left operand.
-// SP + 0: right operand.
// Return Zero condition flag set if equal.
// Note: A Mint cannot contain a value that would fit in Smi, a Bigint
// cannot contain a value that fits in Mint or Smi.
-void StubCode::GenerateIdenticalWithNumberCheckStub(Assembler* assembler) {
- const Register temp = R2;
- const Register left = R1;
- const Register right = R0;
- // Preserve left, right and temp.
- __ PushList((1 << R0) | (1 << R1) | (1 << R2));
- // TOS + 4: left argument.
- // TOS + 3: right argument.
- // TOS + 2: saved temp
- // TOS + 1: saved left
- // TOS + 0: saved right
- __ ldr(left, Address(SP, 4 * kWordSize));
- __ ldr(right, Address(SP, 3 * kWordSize));
+void StubCode::GenerateIdenticalWithNumberCheckStub(Assembler* assembler,
+ const Register left,
+ const Register right,
+ const Register temp,
+ const Register unused) {
Label reference_compare, done, check_mint, check_bigint;
// If any of the arguments is Smi do reference compare.
__ tst(left, ShifterOperand(kSmiTagMask));
@@ -2046,6 +2040,42 @@
__ Bind(&reference_compare);
__ cmp(left, ShifterOperand(right));
__ Bind(&done);
+}
+
+
+// Called only from unoptimized code. All relevant registers have been saved.
+// LR: return address.
+// SP + 4: left operand.
+// SP + 0: right operand.
+// Return Zero condition flag set if equal.
+void StubCode::GenerateUnoptimizedIdenticalWithNumberCheckStub(
+ Assembler* assembler) {
+ const Register temp = R2;
+ const Register left = R1;
+ const Register right = R0;
+ __ ldr(left, Address(SP, 1 * kWordSize));
+ __ ldr(right, Address(SP, 0 * kWordSize));
+ GenerateIdenticalWithNumberCheckStub(assembler, left, right, temp);
+ __ Ret();
+}
+
+
+// Called from otpimzied code only. Must preserve any registers that are
+// destroyed.
+// LR: return address.
+// SP + 4: left operand.
+// SP + 0: right operand.
+// Return Zero condition flag set if equal.
+void StubCode::GenerateOptimizedIdenticalWithNumberCheckStub(
+ Assembler* assembler) {
+ const Register temp = R2;
+ const Register left = R1;
+ const Register right = R0;
+ // Preserve left, right and temp.
+ __ PushList((1 << R0) | (1 << R1) | (1 << R2));
+ __ ldr(left, Address(SP, 4 * kWordSize));
+ __ ldr(right, Address(SP, 3 * kWordSize));
+ GenerateIdenticalWithNumberCheckStub(assembler, left, right, temp);
__ PopList((1 << R0) | (1 << R1) | (1 << R2));
__ Ret();
}
diff --git a/runtime/vm/stub_code_ia32.cc b/runtime/vm/stub_code_ia32.cc
index 3797ffd..30bbf63 100644
--- a/runtime/vm/stub_code_ia32.cc
+++ b/runtime/vm/stub_code_ia32.cc
@@ -227,8 +227,9 @@
// Input parameters:
// EDX: smi-tagged argument count, may be zero.
+// EBP[kParamEndSlotFromFp + 1]: last argument.
// Uses EAX, EBX, ECX, EDX.
-static void PushArgumentsArray(Assembler* assembler, intptr_t arg_offset) {
+static void PushArgumentsArray(Assembler* assembler) {
const Immediate& raw_null =
Immediate(reinterpret_cast<intptr_t>(Object::null()));
@@ -239,8 +240,10 @@
// EAX: newly allocated array.
// EDX: length of the array (was preserved by the stub).
__ pushl(EAX); // Array is in EAX and on top of stack.
- __ leal(EBX, Address(ESP, EDX, TIMES_4, arg_offset)); // Addr of first arg.
+ __ leal(EBX, Address(EBP, EDX, TIMES_4, kParamEndSlotFromFp * kWordSize));
__ leal(ECX, FieldAddress(EAX, Array::data_offset()));
+ // EBX: address of first argument on stack.
+ // ECX: address of first argument in array.
Label loop, loop_condition;
__ jmp(&loop_condition, Assembler::kNearJump);
__ Bind(&loop);
@@ -280,25 +283,12 @@
// Pass the call's arguments array.
__ movl(EDX, EDI); // Smi-tagged arguments array length.
- PushArgumentsArray(assembler, (7 * kWordSize));
- // Stack layout explaining "(7 * kWordSize)" offset.
- // TOS + 0: Arguments array.
- // TOS + 1: Arguments descriptor array.
- // TOS + 2: IC data object.
- // TOS + 3: Receiver.
- // TOS + 4: Space for the result of the runtime call.
- // TOS + 5: Stub's PC marker (0)
- // TOS + 6: Saved FP
- // TOS + 7: Dart code return address
- // TOS + 8: Last argument of caller.
- // ....
+ PushArgumentsArray(assembler);
__ CallRuntime(kInstanceFunctionLookupRuntimeEntry);
+
// Remove arguments.
- __ popl(EAX);
- __ popl(EAX);
- __ popl(EAX);
- __ popl(EAX);
+ __ Drop(4);
__ popl(EAX); // Get result into EAX.
__ LeaveFrame();
__ ret();
@@ -691,22 +681,11 @@
__ pushl(EDX); // Arguments descriptor.
// Load smi-tagged arguments array length, including the non-closure.
__ movl(EDX, FieldAddress(EDX, ArgumentsDescriptor::count_offset()));
- // See stack layout below explaining "wordSize * 5" offset.
- PushArgumentsArray(assembler, (kWordSize * 5));
+ PushArgumentsArray(assembler);
- // Stack:
- // TOS + 0: Argument array.
- // TOS + 1: Arguments descriptor array.
- // TOS + 2: Place for result from the call.
- // TOS + 3: PC marker => RawInstruction object.
- // TOS + 4: Saved EBP of previous frame. <== EBP
- // TOS + 5: Dart code return address
- // TOS + 6: Last argument of caller.
- // ....
__ CallRuntime(kInvokeNonClosureRuntimeEntry);
// Remove arguments.
- __ popl(EAX);
- __ popl(EAX);
+ __ Drop(2);
__ popl(EAX); // Get result into EAX.
// Remove the stub frame as we are about to return.
@@ -1356,58 +1335,37 @@
}
-// Called for invoking noSuchMethod function from the entry code of a dart
-// function after an error in passed named arguments is detected.
+// Called for invoking "dynamic noSuchMethod(Invocation invocation)" function
+// from the entry code of a dart function after an error in passed argument
+// name or number is detected.
// Input parameters:
-// EBP - 4 : PC marker => RawInstruction object.
-// EBP : points to previous frame pointer.
-// EBP + 4 : points to return address.
-// EBP + 8 : address of last argument (arg n-1).
-// EBP + 8 + 4*(n-1) : address of first argument (arg 0).
+// ESP : points to return address.
+// ESP + 4 : address of last argument.
// ECX : ic-data.
// EDX : arguments descriptor array.
// Uses EAX, EBX, EDI as temporary registers.
void StubCode::GenerateCallNoSuchMethodFunctionStub(Assembler* assembler) {
- // The target function was not found, so invoke method
- // "dynamic noSuchMethod(Invocation invocation)".
- const Immediate& raw_null =
- Immediate(reinterpret_cast<intptr_t>(Object::null()));
- __ movl(EDI, FieldAddress(EDX, ArgumentsDescriptor::count_offset()));
- __ movl(EAX, Address(EBP, EDI, TIMES_2, kWordSize)); // Get receiver.
-
- // Create a stub frame as we are pushing some objects on the stack before
- // calling into the runtime.
__ EnterStubFrame();
+ // Load the receiver.
+ __ movl(EDI, FieldAddress(EDX, ArgumentsDescriptor::count_offset()));
+ __ movl(EAX, Address(EBP, EDI, TIMES_2, kParamEndSlotFromFp * kWordSize));
+
+ const Immediate& raw_null =
+ Immediate(reinterpret_cast<intptr_t>(Object::null()));
__ pushl(raw_null); // Setup space on stack for result from noSuchMethod.
__ pushl(EAX); // Receiver.
__ pushl(ECX); // IC data array.
__ pushl(EDX); // Arguments descriptor array.
__ movl(EDX, EDI);
- // See stack layout below explaining "wordSize * 10" offset.
- PushArgumentsArray(assembler, (kWordSize * 10));
+ // EDX: Smi-tagged arguments array length.
+ PushArgumentsArray(assembler);
- // Stack:
- // TOS + 0: Argument array.
- // TOS + 1: Arguments descriptor array.
- // TOS + 2: Ic-data.
- // TOS + 3: Receiver.
- // TOS + 4: Place for result from noSuchMethod.
- // TOS + 5: PC marker => RawInstruction object.
- // TOS + 6: Saved EBP of previous frame. <== EBP
- // TOS + 7: Dart callee (or stub) code return address
- // TOS + 8: PC marker => RawInstruction object of dart caller frame.
- // TOS + 9: Saved EBP of dart caller frame.
- // TOS + 10: Dart caller code return address
- // TOS + 11: Last argument of caller.
- // ....
__ CallRuntime(kInvokeNoSuchMethodFunctionRuntimeEntry);
+
// Remove arguments.
- __ popl(EAX);
- __ popl(EAX);
- __ popl(EAX);
- __ popl(EAX);
+ __ Drop(4);
__ popl(EAX); // Get result into EAX.
// Remove the stub frame as we are about to return.
@@ -2106,26 +2064,14 @@
// Does identical check (object references are equal or not equal) with special
// checks for boxed numbers.
-// Left and right are pushed on stack.
// Return ZF set.
// Note: A Mint cannot contain a value that would fit in Smi, a Bigint
// cannot contain a value that fits in Mint or Smi.
-void StubCode::GenerateIdenticalWithNumberCheckStub(Assembler* assembler) {
- const Register left = EAX;
- const Register right = EDX;
- const Register temp = ECX;
- // Preserve left, right and temp.
- __ pushl(left);
- __ pushl(right);
- __ pushl(temp);
- // TOS + 0: saved temp
- // TOS + 1: saved right
- // TOS + 2: saved left
- // TOS + 3: return address
- // TOS + 4: right argument.
- // TOS + 5: left argument.
- __ movl(left, Address(ESP, 5 * kWordSize));
- __ movl(right, Address(ESP, 4 * kWordSize));
+void StubCode::GenerateIdenticalWithNumberCheckStub(Assembler* assembler,
+ const Register left,
+ const Register right,
+ const Register temp,
+ const Register unused) {
Label reference_compare, done, check_mint, check_bigint;
// If any of the arguments is Smi do reference compare.
__ testl(left, Immediate(kSmiTagMask));
@@ -2177,6 +2123,44 @@
__ Bind(&reference_compare);
__ cmpl(left, right);
__ Bind(&done);
+}
+
+
+// Called only from unoptimized code. All relevant registers have been saved.
+// TOS + 0: return address
+// TOS + 1: right argument.
+// TOS + 2: left argument.
+// Returns ZF set.
+void StubCode::GenerateUnoptimizedIdenticalWithNumberCheckStub(
+ Assembler* assembler) {
+ const Register left = EAX;
+ const Register right = EDX;
+ const Register temp = ECX;
+ __ movl(left, Address(ESP, 2 * kWordSize));
+ __ movl(right, Address(ESP, 1 * kWordSize));
+ GenerateIdenticalWithNumberCheckStub(assembler, left, right, temp);
+ __ ret();
+}
+
+
+// Called from otpimzied code only. Must preserve any registers that are
+// destroyed.
+// TOS + 0: return address
+// TOS + 1: right argument.
+// TOS + 2: left argument.
+// Returns ZF set.
+void StubCode::GenerateOptimizedIdenticalWithNumberCheckStub(
+ Assembler* assembler) {
+ const Register left = EAX;
+ const Register right = EDX;
+ const Register temp = ECX;
+ // Preserve left, right and temp.
+ __ pushl(left);
+ __ pushl(right);
+ __ pushl(temp);
+ __ movl(left, Address(ESP, 5 * kWordSize));
+ __ movl(right, Address(ESP, 4 * kWordSize));
+ GenerateIdenticalWithNumberCheckStub(assembler, left, right, temp);
__ popl(temp);
__ popl(right);
__ popl(left);
diff --git a/runtime/vm/stub_code_mips.cc b/runtime/vm/stub_code_mips.cc
index 659a20b..fef92c4 100644
--- a/runtime/vm/stub_code_mips.cc
+++ b/runtime/vm/stub_code_mips.cc
@@ -1453,8 +1453,12 @@
}
-// The target function was not found, so invoke method
-// "dynamic noSuchMethod(Invocation invocation)".
+// Called for invoking "dynamic noSuchMethod(Invocation invocation)" function
+// from the entry code of a dart function after an error in passed argument
+// name or number is detected.
+// Input parameters:
+// RA : return address.
+// SP : address of last argument.
// S5: inline cache data object.
// S4: arguments descriptor array.
void StubCode::GenerateCallNoSuchMethodFunctionStub(Assembler* assembler) {
@@ -2220,31 +2224,16 @@
// Does identical check (object references are equal or not equal) with special
// checks for boxed numbers.
-// RA: return address.
-// SP + 4: left operand.
-// SP + 0: right operand.
-// Return: CMPRES is zero if equal, non-zero otherwise.
+// Returns: CMPRES is zero if equal, non-zero otherwise.
// Note: A Mint cannot contain a value that would fit in Smi, a Bigint
// cannot contain a value that fits in Mint or Smi.
-void StubCode::GenerateIdenticalWithNumberCheckStub(Assembler* assembler) {
+void StubCode::GenerateIdenticalWithNumberCheckStub(Assembler* assembler,
+ const Register left,
+ const Register right,
+ const Register temp1,
+ const Register temp2) {
__ TraceSimMsg("IdenticalWithNumberCheckStub");
__ Comment("IdenticalWithNumberCheckStub");
- const Register temp1 = T2;
- const Register temp2 = T3;
- const Register left = T1;
- const Register right = T0;
- // Preserve left, right.
- __ addiu(SP, SP, Immediate(-4 * kWordSize));
- __ sw(temp1, Address(SP, 3 * kWordSize));
- __ sw(temp2, Address(SP, 2 * kWordSize));
- __ sw(left, Address(SP, 1 * kWordSize));
- __ sw(right, Address(SP, 0 * kWordSize));
- // TOS + 3: left argument.
- // TOS + 2: right argument.
- // TOS + 1: saved left
- // TOS + 0: saved right
- __ lw(left, Address(SP, 5 * kWordSize));
- __ lw(right, Address(SP, 4 * kWordSize));
Label reference_compare, done, check_mint, check_bigint;
// If any of the arguments is Smi do reference compare.
__ andi(temp1, left, Immediate(kSmiTagMask));
@@ -2313,6 +2302,48 @@
__ Bind(&done);
// A branch or test after this comparison will check CMPRES == TMP1.
__ mov(TMP1, ZR);
+}
+
+
+// Called only from unoptimized code. All relevant registers have been saved.
+// RA: return address.
+// SP + 4: left operand.
+// SP + 0: right operand.
+// Returns: CMPRES is zero if equal, non-zero otherwise.
+void StubCode::GenerateUnoptimizedIdenticalWithNumberCheckStub(
+ Assembler* assembler) {
+ const Register temp1 = T2;
+ const Register temp2 = T3;
+ const Register left = T1;
+ const Register right = T0;
+ // Preserve left, right.
+ __ lw(left, Address(SP, 1 * kWordSize));
+ __ lw(right, Address(SP, 0 * kWordSize));
+ GenerateIdenticalWithNumberCheckStub(assembler, left, right, temp1, temp2);
+ __ Ret();
+}
+
+
+// Called from otpimzied code only. Must preserve any registers that are
+// destroyed.
+// SP + 4: left operand.
+// SP + 0: right operand.
+// Returns: CMPRES is zero if equal, non-zero otherwise.
+void StubCode::GenerateOptimizedIdenticalWithNumberCheckStub(
+ Assembler* assembler) {
+ const Register temp1 = T2;
+ const Register temp2 = T3;
+ const Register left = T1;
+ const Register right = T0;
+ // Preserve left, right.
+ __ addiu(SP, SP, Immediate(-4 * kWordSize));
+ __ sw(temp1, Address(SP, 3 * kWordSize));
+ __ sw(temp2, Address(SP, 2 * kWordSize));
+ __ sw(left, Address(SP, 1 * kWordSize));
+ __ sw(right, Address(SP, 0 * kWordSize));
+ __ lw(left, Address(SP, 5 * kWordSize));
+ __ lw(right, Address(SP, 4 * kWordSize));
+ GenerateIdenticalWithNumberCheckStub(assembler, left, right, temp1, temp2);
__ lw(right, Address(SP, 0 * kWordSize));
__ lw(left, Address(SP, 1 * kWordSize));
__ lw(temp2, Address(SP, 2 * kWordSize));
diff --git a/runtime/vm/stub_code_x64.cc b/runtime/vm/stub_code_x64.cc
index 97e2bbc..c89df162 100644
--- a/runtime/vm/stub_code_x64.cc
+++ b/runtime/vm/stub_code_x64.cc
@@ -224,7 +224,8 @@
// Input parameters:
// R10: smi-tagged argument count, may be zero.
-static void PushArgumentsArray(Assembler* assembler, intptr_t arg_offset) {
+// RBP[kParamEndSlotFromFp + 1]: last argument.
+static void PushArgumentsArray(Assembler* assembler) {
const Immediate& raw_null =
Immediate(reinterpret_cast<intptr_t>(Object::null()));
@@ -235,8 +236,10 @@
// RAX: newly allocated array.
// R10: length of the array (was preserved by the stub).
__ pushq(RAX); // Array is in RAX and on top of stack.
- __ leaq(R12, Address(RSP, R10, TIMES_8, arg_offset)); // Addr of first arg.
+ __ leaq(R12, Address(RBP, R10, TIMES_8, kParamEndSlotFromFp * kWordSize));
__ leaq(RBX, FieldAddress(RAX, Array::data_offset()));
+ // R12: address of first argument on stack.
+ // RBX: address of first argument in array.
Label loop, loop_condition;
__ jmp(&loop_condition, Assembler::kNearJump);
__ Bind(&loop);
@@ -275,25 +278,12 @@
// Pass the call's arguments array.
__ movq(R10, R13); // Smi-tagged arguments array length.
- PushArgumentsArray(assembler, (7 * kWordSize));
- // Stack layout explaining "(7 * kWordSize)" offset.
- // TOS + 0: Arguments array.
- // TOS + 1: Arguments descriptor array.
- // TOS + 2: IC data object.
- // TOS + 3: Receiver.
- // TOS + 4: Space for the result of the runtime call.
- // TOS + 5: Stub's PC marker (0)
- // TOS + 6: Saved FP
- // TOS + 7: Dart code return address
- // TOS + 8: Last argument of caller.
- // ....
+ PushArgumentsArray(assembler);
__ CallRuntime(kInstanceFunctionLookupRuntimeEntry);
+
// Remove arguments.
- __ popq(RAX);
- __ popq(RAX);
- __ popq(RAX);
- __ popq(RAX);
+ __ Drop(4);
__ popq(RAX); // Get result into RAX.
__ LeaveFrame();
__ ret();
@@ -678,22 +668,12 @@
__ pushq(R10); // Arguments descriptor.
// Load smi-tagged arguments array length, including the non-closure.
__ movq(R10, FieldAddress(R10, ArgumentsDescriptor::count_offset()));
- // See stack layout below explaining "wordSize * 5" offset.
- PushArgumentsArray(assembler, (kWordSize * 5));
+ PushArgumentsArray(assembler);
- // Stack:
- // TOS + 0: Argument array.
- // TOS + 1: Arguments descriptor array.
- // TOS + 2: Place for result from the call.
- // TOS + 3: PC marker => RawInstruction object.
- // TOS + 4: Saved RBP of previous frame. <== RBP
- // TOS + 5: Dart code return address
- // TOS + 6: Last argument of caller.
- // ....
__ CallRuntime(kInvokeNonClosureRuntimeEntry);
+
// Remove arguments.
- __ popq(RAX);
- __ popq(RAX);
+ __ Drop(2);
__ popq(RAX); // Get result into RAX.
// Remove the stub frame as we are about to return.
@@ -1341,56 +1321,35 @@
}
-// Called for invoking noSuchMethod function from the entry code of a dart
-// function after an error in passed named arguments is detected.
+// Called for invoking "dynamic noSuchMethod(Invocation invocation)" function
+// from the entry code of a dart function after an error in passed argument
+// name or number is detected.
// Input parameters:
-// RBP - 8 : PC marker => RawInstruction object.
-// RBP : points to previous frame pointer.
-// RBP + 8 : points to return address.
-// RBP + 16 : address of last argument (arg n-1).
-// RBP + 16 + 8*(n-1) : address of first argument (arg 0).
+// RSP : points to return address.
+// RSP + 8 : address of last argument.
// RBX : ic-data.
// R10 : arguments descriptor array.
void StubCode::GenerateCallNoSuchMethodFunctionStub(Assembler* assembler) {
- // The target function was not found, so invoke method
- // "dynamic noSuchMethod(Invocation invocation)".
- const Immediate& raw_null =
- Immediate(reinterpret_cast<intptr_t>(Object::null()));
- __ movq(R13, FieldAddress(R10, ArgumentsDescriptor::count_offset()));
- __ movq(RAX, Address(RBP, R13, TIMES_4, kWordSize)); // Get receiver.
-
- // Create a stub frame.
__ EnterStubFrame();
+ // Load the receiver.
+ __ movq(R13, FieldAddress(R10, ArgumentsDescriptor::count_offset()));
+ __ movq(RAX, Address(RBP, R13, TIMES_4, kParamEndSlotFromFp * kWordSize));
+
+ const Immediate& raw_null =
+ Immediate(reinterpret_cast<intptr_t>(Object::null()));
__ pushq(raw_null); // Setup space on stack for result from noSuchMethod.
__ pushq(RAX); // Receiver.
__ pushq(RBX); // IC data array.
__ pushq(R10); // Arguments descriptor array.
__ movq(R10, R13); // Smi-tagged arguments array length.
- // See stack layout below explaining "wordSize * 10" offset.
- PushArgumentsArray(assembler, (kWordSize * 10));
+ PushArgumentsArray(assembler);
- // Stack:
- // TOS + 0: Argument array.
- // TOS + 1: Arguments descriptor array.
- // TOS + 2: Ic-data array.
- // TOS + 3: Receiver.
- // TOS + 4: Place for result from noSuchMethod.
- // TOS + 5: PC marker => RawInstruction object.
- // TOS + 6: Saved RBP of previous frame. <== RBP
- // TOS + 7: Dart callee (or stub) code return address
- // TOS + 8: PC marker => RawInstruction object of dart caller frame.
- // TOS + 9: Saved RBP of dart caller frame.
- // TOS + 10: Dart caller code return address
- // TOS + 11: Last argument of caller.
- // ....
__ CallRuntime(kInvokeNoSuchMethodFunctionRuntimeEntry);
+
// Remove arguments.
- __ popq(RAX);
- __ popq(RAX);
- __ popq(RAX);
- __ popq(RAX);
+ __ Drop(4);
__ popq(RAX); // Get result into RAX.
// Remove the stub frame as we are about to return.
@@ -2079,19 +2038,11 @@
// Return ZF set.
// Note: A Mint cannot contain a value that would fit in Smi, a Bigint
// cannot contain a value that fits in Mint or Smi.
-void StubCode::GenerateIdenticalWithNumberCheckStub(Assembler* assembler) {
- const Register left = RAX;
- const Register right = RDX;
- // Preserve left, right and temp.
- __ pushq(left);
- __ pushq(right);
- // TOS + 0: saved right
- // TOS + 1: saved left
- // TOS + 2: return address
- // TOS + 3: right argument.
- // TOS + 4: left argument.
- __ movq(left, Address(RSP, 4 * kWordSize));
- __ movq(right, Address(RSP, 3 * kWordSize));
+void StubCode::GenerateIdenticalWithNumberCheckStub(Assembler* assembler,
+ const Register left,
+ const Register right,
+ const Register unused1,
+ const Register unused2) {
Label reference_compare, done, check_mint, check_bigint;
// If any of the arguments is Smi do reference compare.
__ testq(left, Immediate(kSmiTagMask));
@@ -2137,6 +2088,42 @@
__ Bind(&reference_compare);
__ cmpq(left, right);
__ Bind(&done);
+}
+
+
+// Called only from unoptimized code. All relevant registers have been saved.
+// TOS + 0: return address
+// TOS + 1: right argument.
+// TOS + 2: left argument.
+// Returns ZF set.
+void StubCode::GenerateUnoptimizedIdenticalWithNumberCheckStub(
+ Assembler* assembler) {
+ const Register left = RAX;
+ const Register right = RDX;
+
+ __ movq(left, Address(RSP, 2 * kWordSize));
+ __ movq(right, Address(RSP, 1 * kWordSize));
+ GenerateIdenticalWithNumberCheckStub(assembler, left, right);
+ __ ret();
+}
+
+
+// Called from otpimzied code only. Must preserve any registers that are
+// destroyed.
+// TOS + 0: return address
+// TOS + 1: right argument.
+// TOS + 2: left argument.
+// Returns ZF set.
+void StubCode::GenerateOptimizedIdenticalWithNumberCheckStub(
+ Assembler* assembler) {
+ const Register left = RAX;
+ const Register right = RDX;
+ // Preserve left and right.
+ __ pushq(left);
+ __ pushq(right);
+ __ movq(left, Address(RSP, 4 * kWordSize));
+ __ movq(right, Address(RSP, 3 * kWordSize));
+ GenerateIdenticalWithNumberCheckStub(assembler, left, right);
__ popq(right);
__ popq(left);
__ ret();
diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h
index 0fb42e2..d1def31 100644
--- a/runtime/vm/symbols.h
+++ b/runtime/vm/symbols.h
@@ -52,7 +52,6 @@
V(Interpolate, "_interpolate") \
V(GetIterator, "iterator") \
V(NoSuchMethod, "noSuchMethod") \
- V(SavedArgDescVarPrefix, ":saved_args_desc_var") \
V(SavedCurrentContextVar, ":saved_current_context_var") \
V(SavedEntryContextVar, ":saved_entry_context_var") \
V(SavedTryContextVar, ":saved_try_context_var") \
diff --git a/sdk/lib/_collection_dev/list.dart b/sdk/lib/_collection_dev/list.dart
index 7f894bb..1008dc1 100644
--- a/sdk/lib/_collection_dev/list.dart
+++ b/sdk/lib/_collection_dev/list.dart
@@ -267,6 +267,10 @@
void clear() {
throw new UnsupportedError("Cannot modify an unmodifiable map");
}
+
+ void addAll(Map<int, E> other) {
+ throw new UnsupportedError("Cannot modify an unmodifiable map");
+ }
}
class ReversedListIterable<E> extends ListIterable<E> {
diff --git a/sdk/lib/_internal/compiler/implementation/compiler.dart b/sdk/lib/_internal/compiler/implementation/compiler.dart
index e10326a..47cb937 100644
--- a/sdk/lib/_internal/compiler/implementation/compiler.dart
+++ b/sdk/lib/_internal/compiler/implementation/compiler.dart
@@ -370,6 +370,9 @@
// Initialized when symbolImplementationClass has been resolved.
FunctionElement symbolValidatedConstructor;
+ // Initialized when dart:mirrors is loaded.
+ ClassElement deferredLibraryClass;
+
ClassElement jsInvocationMirrorClass;
/// Document class from dart:mirrors.
ClassElement documentClass;
@@ -695,14 +698,30 @@
library.addToScope(dynamicClass, this);
});
}
- if (uri == Uri.parse('dart:mirrors')) {
- mirrorSystemClass = library.find(const SourceString('MirrorSystem'));
- } else if (uri == Uri.parse('dart:_collection-dev')) {
- symbolImplementationClass = library.find(const SourceString('Symbol'));
+ if (uri == new Uri(scheme: 'dart', path: 'dart:mirrors')) {
+ mirrorSystemClass =
+ findRequiredElement(library, const SourceString('MirrorSystem'));
+ } else if (uri == new Uri(scheme: 'dart', path: '_collection-dev')) {
+ symbolImplementationClass =
+ findRequiredElement(library, const SourceString('Symbol'));
+ } else if (uri == new Uri(scheme: 'dart', path: 'async')) {
+ deferredLibraryClass =
+ findRequiredElement(library, const SourceString('DeferredLibrary'));
}
backend.onLibraryScanned(library, uri);
}
+ Element findRequiredElement(LibraryElement library, SourceString name) {
+ var element = library.find(name);
+ if (element == null) {
+ internalErrorOnElement(
+ library,
+ 'The library "${library.canonicalUri}" does not contain required '
+ 'element: ${name.slowToString()}');
+ }
+ return element;
+ }
+
void onClassResolved(ClassElement cls) {
if (mirrorSystemClass == cls) {
mirrorSystemGetNameFunction =
diff --git a/sdk/lib/_internal/compiler/implementation/dart_types.dart b/sdk/lib/_internal/compiler/implementation/dart_types.dart
index fd9ed63..873b926 100644
--- a/sdk/lib/_internal/compiler/implementation/dart_types.dart
+++ b/sdk/lib/_internal/compiler/implementation/dart_types.dart
@@ -94,10 +94,6 @@
*/
bool forEachMalformedType(bool f(MalformedType type)) => true;
- // TODO(ahe): This is implicitly inherited from Object. What is the purpose
- // of duplicating it here?
- bool operator ==(other);
-
/**
* Is [: true :] if this type has no explict type arguments.
*/
@@ -346,10 +342,6 @@
return visitor.visitMalformedType(this, argument);
}
- // TODO(ahe): This is the default implementation that would be inherited if
- // DartType didn't declare an abstract method. What is the purpose?
- bool operator ==(other) => identical(this, other);
-
String toString() {
var sb = new StringBuffer();
if (typeArguments != null) {
@@ -456,7 +448,8 @@
bool operator ==(other) {
if (other is !GenericType) return false;
- return identical(element, other.element)
+ return kind == other.kind
+ && element == other.element
&& typeArguments == other.typeArguments;
}
@@ -465,7 +458,6 @@
GenericType asRaw() => element.rawType;
}
-// TODO(johnniwinther): Add common supertype for InterfaceType and TypedefType.
class InterfaceType extends GenericType {
final ClassElement element;
@@ -553,17 +545,6 @@
return null;
}
- bool operator ==(other) {
- // TODO(johnniwinther,karlklose): This is a bad implementation of
- // operator==. This implementation is not compatible with the
- // implementation in the superclass: another subclass of GenericType might
- // compare equal to an instance of this class if the other subclass forgets
- // to implement operator==. This is brittle and easy to avoid, ask ahe@
- // for concrete suggestions.
- if (other is !InterfaceType) return false;
- return super == other;
- }
-
int get hashCode => super.hashCode;
InterfaceType asRaw() => super.asRaw();
@@ -826,12 +807,6 @@
return definition.subst(typeArguments, declaration.typeArguments);
}
- bool operator ==(other) {
- // TODO(johnniwinther,karlklose): See InterfaceType.operator==.
- if (other is !TypedefType) return false;
- return super == other;
- }
-
int get hashCode => super.hashCode;
TypedefType asRaw() => super.asRaw();
diff --git a/sdk/lib/_internal/compiler/implementation/deferred_load.dart b/sdk/lib/_internal/compiler/implementation/deferred_load.dart
index 1a8d770..38a6245 100644
--- a/sdk/lib/_internal/compiler/implementation/deferred_load.dart
+++ b/sdk/lib/_internal/compiler/implementation/deferred_load.dart
@@ -54,26 +54,7 @@
String get name => 'Deferred Loading';
/// DeferredLibrary from dart:async
- ClassElement get deferredLibraryClass {
- if (cachedDeferredLibraryClass == null) {
- cachedDeferredLibraryClass = findDeferredLibraryClass();
- }
- return cachedDeferredLibraryClass;
- }
-
- ClassElement findDeferredLibraryClass() {
- var uri = new Uri(scheme: 'dart', path: 'async');
- LibraryElement asyncLibrary =
- compiler.libraryLoader.loadLibrary(uri, null, uri);
- var element = asyncLibrary.find(const SourceString('DeferredLibrary'));
- if (element == null) {
- compiler.internalErrorOnElement(
- asyncLibrary,
- 'dart:async library does not contain required class: '
- 'DeferredLibrary');
- }
- return element;
- }
+ ClassElement get deferredLibraryClass => compiler.deferredLibraryClass;
bool isDeferred(Element element) {
element = element.implementation;
diff --git a/sdk/lib/_internal/compiler/implementation/elements/modelx.dart b/sdk/lib/_internal/compiler/implementation/elements/modelx.dart
index 0d78456..79ac960 100644
--- a/sdk/lib/_internal/compiler/implementation/elements/modelx.dart
+++ b/sdk/lib/_internal/compiler/implementation/elements/modelx.dart
@@ -176,8 +176,13 @@
Token position() => null;
Token findMyName(Token token) {
- for (Token t = token; !identical(t.kind, EOF_TOKEN); t = t.next) {
- if (t.value == name) return t;
+ // We search for the token that has the name of this element.
+ // For constructors, that doesn't work because they may have
+ // named formed out of multiple tokens (named constructors) so
+ // for those we search for the class name instead.
+ SourceString needle = isConstructor() ? enclosingElement.name : name;
+ for (Token t = token; EOF_TOKEN != t.kind; t = t.next) {
+ if (needle == t.value) return t;
}
return token;
}
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart b/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart
index 46abf0a..c8fd503 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart
@@ -1403,6 +1403,13 @@
bool retainName(SourceString name) => mustPreserveNames;
bool retainMetadataOf(Element element) {
+ if (mustRetainMetadata) {
+ // TODO(ahe): This is a little hacky, but I'll have to rewrite this when
+ // implementing @MirrorsUsed anyways.
+ compiler.constantHandler.compiledConstants.addAll(
+ compiler.metadataHandler.compiledConstants);
+ compiler.metadataHandler.compiledConstants.clear();
+ }
if (mustRetainMetadata) hasRetainedMetadata = true;
return mustRetainMetadata;
}
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart b/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart
index e502f25..e8abbb2 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart
@@ -85,6 +85,13 @@
final Set<String> recordedMangledNames = new Set<String>();
final Set<String> interceptorInvocationNames = new Set<String>();
+ /// A list of JS expressions that represent metadata, parameter names and
+ /// type, and return types.
+ final List<String> globalMetadata = [];
+
+ /// A map used to canonicalize the entries of globalMetadata.
+ final Map<String, int> globalMetadataMap = <String, int>{};
+
// TODO(ngeoffray): remove this field.
Set<ClassElement> instantiatedClasses;
@@ -1207,11 +1214,8 @@
if (backend.isInterceptedMethod(member)) {
interceptorInvocationNames.add(name);
}
+ code = extendWithMetadata(member, code);
builder.addProperty(name, code);
- var metadata = buildMetadataFunction(member);
- if (metadata != null) {
- builder.addProperty('@$name', metadata);
- }
String reflectionName = getReflectionName(member, name);
if (reflectionName != null) {
builder.addProperty('+$reflectionName', js('0'));
@@ -2056,12 +2060,8 @@
CodeBuffer buffer = bufferForElement(element, eagerBuffer);
jsAst.Expression code = backend.generatedCode[element];
String name = namer.getName(element);
+ code = extendWithMetadata(element, code);
emitStaticFunction(buffer, name, code);
- var metadata = buildMetadataFunction(element);
- if (metadata != null) {
- buffer.write(',$n$n"@$name":$_');
- buffer.write(jsAst.prettyPrint(metadata, compiler));
- }
String reflectionName = getReflectionName(element, name);
if (reflectionName != null) {
buffer.write(',$n$n"+$reflectionName":${_}0');
@@ -2883,16 +2883,6 @@
js.if_(js('receiver instanceof #',
js(namer.isolateAccess(compiler.objectClass))),
js.return_(js('receiver'))));
-
- // TODO(sra): Fold this 'Object' check into the `getNativeInterceptor`
- // check by patching `Object.prototype` with a special hook function.
- // TODO(9556): This test is needed in plain non-browser code because
- // 'holders' are not Dart classes.
- block.statements.add(
- js.if_(
- js('Object.getPrototypeOf(receiver) === Object.prototype'),
- buildReturnInterceptor(backend.jsInterceptorClass)));
-
block.statements.add(
js.return_(
js(namer.isolateAccess(backend.getNativeInterceptorMethod))(
@@ -3272,6 +3262,76 @@
});
}
+ int reifyMetadata(MetadataAnnotation annotation) {
+ Constant value = annotation.value;
+ if (value == null) {
+ compiler.reportInternalError(
+ annotation, 'Internal error: value is null');
+ return -1;
+ }
+ return addGlobalMetadata(
+ jsAst.prettyPrint(constantReference(value), compiler).getText());
+ }
+
+ int reifyType(DartType type) {
+ // TODO(ahe): Handle type variables correctly instead of using "#".
+ String representation = backend.rti.getTypeRepresentation(type, (_) {});
+ return addGlobalMetadata(representation.replaceAll('#', 'null'));
+ }
+
+ int reifyName(SourceString name) {
+ return addGlobalMetadata('"${name.slowToString()}"');
+ }
+
+ int addGlobalMetadata(String string) {
+ return globalMetadataMap.putIfAbsent(string, () {
+ globalMetadata.add(string);
+ return globalMetadata.length - 1;
+ });
+ }
+
+ jsAst.Fun extendWithMetadata(FunctionElement element, jsAst.Fun code) {
+ if (!backend.retainMetadataOf(element)) return code;
+ return compiler.withCurrentElement(element, () {
+ List<int> metadata = <int>[];
+ FunctionSignature signature = element.functionSignature;
+ if (element.isConstructor()) {
+ metadata.add(reifyType(element.getEnclosingClass().thisType));
+ } else {
+ metadata.add(reifyType(signature.returnType));
+ }
+ signature.forEachParameter((Element parameter) {
+ metadata
+ ..add(reifyName(parameter.name))
+ ..add(reifyType(parameter.computeType(compiler)));
+ });
+ Link link = element.metadata;
+ // TODO(ahe): Why is metadata sometimes null?
+ if (link != null) {
+ for (; !link.isEmpty; link = link.tail) {
+ metadata.add(reifyMetadata(link.head));
+ }
+ }
+ code.body.statements.add(js.string(metadata.join(',')).toStatement());
+ return code;
+ });
+ }
+
+ void emitMetadata(CodeBuffer buffer) {
+ buffer.write('init.metadata$_=$_[');
+ for (var metadata in globalMetadata) {
+ if (metadata is String) {
+ if (metadata != 'null') {
+ buffer.write(metadata);
+ }
+ } else {
+ throw 'Unexpected value in metadata: ${Error.safeToString(metadata)}';
+ }
+ buffer.write(',$n');
+ }
+ buffer.write('];$n');
+ }
+
String assembleProgram() {
measure(() {
// Compute the required type checks to know which classes need a
@@ -3430,6 +3490,7 @@
mainBuffer.add(nativeBuffer);
+ emitMetadata(mainBuffer);
isolateProperties = isolatePropertiesName;
// The following code should not use the short-hand for the
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/runtime_types.dart b/sdk/lib/_internal/compiler/implementation/js_backend/runtime_types.dart
index 3adbd63..0ae4696 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/runtime_types.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/runtime_types.dart
@@ -663,6 +663,11 @@
builder.write('null');
}
+ visitVoidType(VoidType type, _) {
+ // TODO(ahe): Reify void type ("null" means "dynamic").
+ builder.write('null');
+ }
+
visitType(DartType type, _) {
compiler.internalError('Unexpected type: $type (${type.kind})');
}
diff --git a/sdk/lib/_internal/compiler/implementation/scanner/partial_parser.dart b/sdk/lib/_internal/compiler/implementation/scanner/partial_parser.dart
index 02f409a..3b666ae 100644
--- a/sdk/lib/_internal/compiler/implementation/scanner/partial_parser.dart
+++ b/sdk/lib/_internal/compiler/implementation/scanner/partial_parser.dart
@@ -34,7 +34,9 @@
(identical(value, ',')) ||
(identical(value, ']')))
return token;
- if (identical(value, '=')) {
+ if (identical(value, '=') ||
+ identical(value, '?') ||
+ identical(value, ':')) {
var nextValue = token.next.stringValue;
if (identical(nextValue, 'const')) {
token = token.next;
@@ -45,6 +47,7 @@
// class Foo {
// var map;
// Foo() : map = {};
+ // Foo.x() : map = true ? {} : {};
// }
BeginGroupToken begin = token.next;
token = (begin.endGroup != null) ? begin.endGroup : token;
@@ -56,6 +59,7 @@
// class Foo {
// var map;
// Foo() : map = <String, Foo>{};
+ // Foo.x() : map = true ? <String, Foo>{} : <String, Foo>{};
// }
BeginGroupToken begin = token.next;
token = (begin.endGroup != null) ? begin.endGroup : token;
diff --git a/sdk/lib/_internal/compiler/implementation/source_file_provider.dart b/sdk/lib/_internal/compiler/implementation/source_file_provider.dart
index b990532..4cbd641 100644
--- a/sdk/lib/_internal/compiler/implementation/source_file_provider.dart
+++ b/sdk/lib/_internal/compiler/implementation/source_file_provider.dart
@@ -94,7 +94,7 @@
// This is used to suppress info about a warning when warnings are
// suppressed, and similar for hints.
var previousKind = lastKind;
- if (previousKind != api.Diagnostic.INFO) {
+ if (kind != api.Diagnostic.INFO) {
lastKind = kind;
}
var color;
diff --git a/sdk/lib/_internal/lib/constant_map.dart b/sdk/lib/_internal/lib/constant_map.dart
index 1647f32..60300fc 100644
--- a/sdk/lib/_internal/lib/constant_map.dart
+++ b/sdk/lib/_internal/lib/constant_map.dart
@@ -51,6 +51,7 @@
V putIfAbsent(String key, V ifAbsent()) => _throwUnmodifiable();
V remove(String key) => _throwUnmodifiable();
void clear() => _throwUnmodifiable();
+ void addAll(Map<String, V> other) => _throwUnmodifiable();
}
// This class has no constructor. This is on purpose since the instantiation
diff --git a/sdk/lib/_internal/lib/js_mirrors.dart b/sdk/lib/_internal/lib/js_mirrors.dart
index d904246..1d1c825 100644
--- a/sdk/lib/_internal/lib/js_mirrors.dart
+++ b/sdk/lib/_internal/lib/js_mirrors.dart
@@ -16,7 +16,9 @@
Null,
Primitives,
RuntimeError,
- createUnmangledInvocationMirror;
+ createRuntimeType,
+ createUnmangledInvocationMirror,
+ runtimeTypeToString;
import 'dart:_interceptors' show Interceptor, JSExtendableArray;
import 'dart:_js_names';
@@ -77,6 +79,9 @@
}
return result;
}
+
+ // TODO(ahe): Implement this.
+ IsolateMirror get isolate => throw new UnimplementedError();
}
abstract class JsMirror {
@@ -85,6 +90,9 @@
abstract String get _prettyName;
String toString() => _prettyName;
+
+ // TODO(ahe): Remove this method from the API.
+ MirrorSystem get mirrors => currentJsMirrorSystem;
}
abstract class JsDeclarationMirror extends JsMirror
@@ -93,11 +101,16 @@
const JsDeclarationMirror(this.simpleName);
+ Symbol get qualifiedName => computeQualifiedName(owner, simpleName);
+
bool get isPrivate => n(simpleName).startsWith('_');
bool get isTopLevel => owner != null && owner is LibraryMirror;
String toString() => "$_prettyName on '${n(simpleName)}'";
+
+ // TODO(ahe): Implement this.
+ SourceLocation get location => throw new UnimplementedError();
}
class JsTypeMirror extends JsDeclarationMirror implements TypeMirror {
@@ -105,6 +118,14 @@
: super(simpleName);
String get _prettyName => 'TypeMirror';
+
+ DeclarationMirror get owner => null;
+
+ // TODO(ahe): Doesn't match the specification, see http://dartbug.com/11569.
+ bool get isTopLevel => true;
+
+ // TODO(ahe): Implement this.
+ List<InstanceMirror> get metadata => throw new UnimplementedError();
}
class JsLibraryMirror extends JsDeclarationMirror with JsObjectMirror
@@ -152,26 +173,20 @@
var result = new List<JsMethodMirror>(_functions.length);
for (int i = 0; i < _functions.length; i++) {
String name = _functions[i];
+ // TODO(ahe): Create accessor for accessing $. It is also
+ // used in js_helper.
+ var jsFunction = JS('', '#[#]', JS_CURRENT_ISOLATE(), name);
String unmangledName = mangledGlobalNames[name];
if (unmangledName == null) unmangledName = name;
- int parameterCount = null; // TODO(ahe): Compute this.
- bool isSetter = false; // TODO(ahe): Compute this.
- bool isGetter = false; // TODO(ahe): Compute this.
bool isConstructor = unmangledName.startsWith('new ');
- bool isStatic = true && !isConstructor; // Top-level functions are
- // static, but constructors are
- // not.
+ bool isStatic = !isConstructor; // Top-level functions are static, but
+ // constructors are not.
if (isConstructor) {
unmangledName = unmangledName.substring(4).replaceAll(r'$', '.');
}
- unmangledName = unmangledName.split(':')[0];
- Symbol symbol = s(unmangledName);
JsMethodMirror mirror =
- // TODO(ahe): Create accessor for accessing $. It is also
- // used in js_helper.
- new JsMethodMirror(
- symbol, JS('', '#[#]', JS_CURRENT_ISOLATE(), name),
- parameterCount, isGetter, isSetter, isStatic, isConstructor);
+ new JsMethodMirror.fromUnmangledName(
+ unmangledName, jsFunction, isStatic, isConstructor);
result[i] = mirror;
mirror._owner = this;
}
@@ -220,6 +235,14 @@
preserveMetadata();
return _metadata.map(reflect).toList();
}
+
+ // TODO(ahe): Implement these.
+ DeclarationMirror get owner => throw new UnimplementedError();
+ InstanceMirror invoke(Symbol memberName,
+ List positionalArguments,
+ [Map<Symbol,dynamic> namedArguments]) {
+ throw new UnimplementedError();
+ }
}
String n(Symbol symbol) => _symbol_dev.Symbol.getName(symbol);
@@ -298,6 +321,13 @@
Future<InstanceMirror> getFieldAsync(Symbol fieldName) {
return new Future<InstanceMirror>(() => this.getField(fieldName));
}
+
+ Future<InstanceMirror> invokeAsync(Symbol memberName,
+ List positionalArguments,
+ [Map<Symbol, dynamic> namedArguments]) {
+ return new Future<InstanceMirror>(
+ () => this.invoke(memberName, positionalArguments, namedArguments));
+ }
}
class JsInstanceMirror extends JsObjectMirror implements InstanceMirror {
@@ -365,6 +395,9 @@
}
String toString() => 'InstanceMirror on ${Error.safeToString(reflectee)}';
+
+ // TODO(ahe): Remove this method from the API.
+ MirrorSystem get mirrors => currentJsMirrorSystem;
}
class JsClassMirror extends JsTypeMirror with JsObjectMirror
@@ -387,8 +420,6 @@
String get _prettyName => 'ClassMirror';
- Symbol get qualifiedName => computeQualifiedName(owner, simpleName);
-
get _jsConstructor {
if (_jsConstructorOrInterceptor is Interceptor) {
return JS('', '#.constructor', _jsConstructorOrInterceptor);
@@ -400,8 +431,7 @@
Map<Symbol, MethodMirror> get constructors {
Map<Symbol, MethodMirror> result = new Map<Symbol, MethodMirror>();
JsLibraryMirror library = owner;
- String unmangledName = mangledGlobalNames[n(simpleName)];
- if (unmangledName == null) unmangledName = n(simpleName);
+ String unmangledName = n(simpleName);
for (JsMethodMirror mirror in library._functionMirrors) {
Symbol name = mirror.simpleName;
if (mirror.isConstructor
@@ -428,7 +458,9 @@
// reflection with metadata.
if (simpleName == null) continue;
var function = JS('', '#[#]', prototype, key);
- var mirror = new JsMethodMirror.fromUnmangledName(simpleName, function);
+ var mirror =
+ new JsMethodMirror.fromUnmangledName(
+ simpleName, function, false, false);
result.add(mirror);
mirror._owner = this;
}
@@ -591,6 +623,21 @@
}
return _superclass == this ? null : _superclass;
}
+
+ // TODO(ahe): Implement these;
+ InstanceMirror invoke(Symbol memberName,
+ List positionalArguments,
+ [Map<Symbol,dynamic> namedArguments]) {
+ throw new UnimplementedError();
+ }
+ List<ClassMirror> get superinterfaces => throw new UnimplementedError();
+ Map<Symbol, TypeVariableMirror> get typeVariables
+ => throw new UnimplementedError();
+ Map<Symbol, TypeMirror> get typeArguments => throw new UnimplementedError();
+ bool get isOriginalDeclaration => throw new UnimplementedError();
+ ClassMirror get originalDeclaration => throw new UnimplementedError();
+ bool get isClass => throw new UnimplementedError();
+ ClassMirror get defaultFactory => throw new UnimplementedError();
}
class JsVariableMirror extends JsDeclarationMirror implements VariableMirror {
@@ -636,8 +683,6 @@
DeclarationMirror get owner => _owner;
- Symbol get qualifiedName => computeQualifiedName(owner, simpleName);
-
List<InstanceMirror> get metadata {
preserveMetadata();
if (_metadata == null) {
@@ -703,6 +748,11 @@
}
String toString() => "ClosureMirror on '${Error.safeToString(reflectee)}'";
+
+ // TODO(ahe): Implement these.
+ String get source => throw new UnimplementedError();
+ Future<InstanceMirror> findInContext(Symbol name)
+ => throw new UnimplementedError();
}
class JsMethodMirror extends JsDeclarationMirror implements MethodMirror {
@@ -714,6 +764,8 @@
final bool isConstructor;
DeclarationMirror _owner;
List _metadata;
+ var _returnType;
+ var _parameters;
JsMethodMirror(Symbol simpleName,
this._jsFunction,
@@ -724,7 +776,10 @@
this.isConstructor)
: super(simpleName);
- factory JsMethodMirror.fromUnmangledName(String name, jsFunction) {
+ factory JsMethodMirror.fromUnmangledName(String name,
+ jsFunction,
+ bool isStatic,
+ bool isConstructor) {
List<String> info = name.split(':');
name = info[0];
bool isSetter = name.endsWith('=');
@@ -744,29 +799,96 @@
}
return new JsMethodMirror(
s(name), jsFunction, requiredParameterCount + optionalParameterCount,
- isGetter, isSetter, false, false);
+ isGetter, isSetter, isStatic, isConstructor);
}
String get _prettyName => 'MethodMirror';
List<ParameterMirror> get parameters {
- // TODO(ahe): Fill the list with parameter mirrors.
- return new List<ParameterMirror>(_parameterCount);
+ metadata; // Compute _parameters as a side-effect of extracting metadata.
+ return new List<ParameterMirror>.from(_parameters);
}
DeclarationMirror get owner => _owner;
- Symbol get qualifiedName => computeQualifiedName(owner, simpleName);
-
- // TODO(ahe): Improve this information and test it.
- TypeMirror get returnType => JsMirrorSystem._dynamicType;
+ TypeMirror get returnType {
+ metadata; // Compute _returnType as a side-effect of extracting metadata.
+ return typeMirrorFromRuntimeTypeRepresentation(_returnType);
+ }
List<InstanceMirror> get metadata {
if (_metadata == null) {
- _metadata = extractMetadata(_jsFunction);
+ var raw = extractMetadata(_jsFunction);
+ _returnType = raw[0];
+ int parameterLength = 1 + _parameterCount * 2;
+ var formals = new List<ParameterMirror>(_parameterCount);
+ int formalsCount = 0;
+ for (int i = 1; i < parameterLength; i += 2) {
+ var name = raw[i];
+ var type = raw[i + 1];
+ formals[formalsCount++] = new JsParameterMirror(name, this, type);
+ }
+ _parameters = formals;
+ _metadata = raw.sublist(parameterLength);
}
return _metadata.map(reflect).toList();
}
+
+ Symbol get constructorName {
+ // TODO(ahe): I believe it is more appropriate to throw an exception or
+ // return null.
+ if (!isConstructor) return const Symbol('');
+ String name = n(simpleName);
+ int index = name.indexOf('.');
+ if (index == -1) return const Symbol('');
+ return s(name.substring(index + 1));
+ }
+
+ // TODO(ahe): Implement these.
+ bool get isAbstract => throw new UnimplementedError();
+ bool get isRegularMethod => throw new UnimplementedError();
+ bool get isOperator => throw new UnimplementedError();
+ bool get isConstConstructor => throw new UnimplementedError();
+ bool get isGenerativeConstructor => throw new UnimplementedError();
+ bool get isRedirectingConstructor => throw new UnimplementedError();
+ bool get isFactoryConstructor => throw new UnimplementedError();
+}
+
+class JsParameterMirror extends JsDeclarationMirror implements ParameterMirror {
+ final JsMethodMirror owner;
+ // A JS object representing the type.
+ final _type;
+
+ JsParameterMirror(String unmangledName, this.owner, this._type)
+ : super(s(unmangledName));
+
+ String get _prettyName => 'ParameterMirror';
+
+ TypeMirror get type => typeMirrorFromRuntimeTypeRepresentation(_type);
+
+ bool get isStatic => owner.isStatic;
+
+ // TODO(ahe): Implement this.
+ bool get isFinal => false;
+
+ // TODO(ahe): Implement this.
+ bool get isOptional => false;
+
+ // TODO(ahe): Implement this.
+ bool get isNamed => false;
+
+ // TODO(ahe): Implement this.
+ bool get hasDefaultValue => false;
+
+ // TODO(ahe): Implement this.
+ get defaultValue => null;
+}
+
+TypeMirror typeMirrorFromRuntimeTypeRepresentation(type) {
+ if (type == null) return JsMirrorSystem._dynamicType;
+ String representation = runtimeTypeToString(type);
+ if (representation == null) return reflectClass(Function);
+ return reflectClass(createRuntimeType(representation));
}
Symbol computeQualifiedName(DeclarationMirror owner, Symbol simpleName) {
@@ -779,6 +901,12 @@
List extractMetadata(victim) {
preserveMetadata();
var metadataFunction = JS('', '#["@"]', victim);
- return (metadataFunction == null)
- ? const [] : JS('', '#()', metadataFunction);
+ if (metadataFunction != null) return JS('', '#()', metadataFunction);
+ String source = JS('String', 'Function.prototype.toString.call(#)', victim);
+ int index = source.lastIndexOf(new RegExp('"[0-9,]*";?[ \n\r]*}'));
+ if (index == -1) return const [];
+ index++;
+ int endQuote = source.indexOf('"', index);
+ return source.substring(index, endQuote).split(',').map(int.parse).map(
+ (int i) => JS('', 'init.metadata[#]', i)).toList();
}
diff --git a/sdk/lib/_internal/lib/js_rti.dart b/sdk/lib/_internal/lib/js_rti.dart
index 01d8ace..4441214 100644
--- a/sdk/lib/_internal/lib/js_rti.dart
+++ b/sdk/lib/_internal/lib/js_rti.dart
@@ -132,9 +132,11 @@
} else if (isJsArray(type)) {
// A list representing a type with arguments.
return getRuntimeTypeAsString(type);
- } else {
+ } else if (isJsFunction(type)) {
// A reference to the constructor.
return getConstructorName(type);
+ } else {
+ return null;
}
}
diff --git a/sdk/lib/_internal/lib/native_helper.dart b/sdk/lib/_internal/lib/native_helper.dart
index 8ad597e..56c098f 100644
--- a/sdk/lib/_internal/lib/native_helper.dart
+++ b/sdk/lib/_internal/lib/native_helper.dart
@@ -17,15 +17,6 @@
String typeNameInWebKitCommon(tag) {
String name = JS('String', '#', tag);
- if (name == 'CanvasPixelArray') return 'Uint8ClampedArray';
- if (name == 'AudioChannelMerger') return 'ChannelMergerNode';
- if (name == 'AudioChannelSplitter') return 'ChannelSplitterNode';
- if (name == 'AudioGainNode') return 'GainNode';
- if (name == 'AudioPannerNode') return 'PannerNode';
- if (name == 'JavaScriptAudioNode') return 'ScriptProcessorNode';
- if (name == 'Oscillator') return 'OscillatorNode';
- if (name == 'RealtimeAnalyserNode') return 'AnalyserNode';
- if (name == 'IDBVersionChangeRequest') return 'IDBOpenDBRequest';
return name;
}
@@ -37,9 +28,7 @@
String typeNameInFirefox(obj) {
String name = JS('String', '#', constructorNameFallback(obj));
if (name == 'BeforeUnloadEvent') return 'Event';
- if (name == 'CSS2Properties') return 'CSSStyleDeclaration';
if (name == 'DataTransfer') return 'Clipboard';
- if (name == 'DragEvent') return 'MouseEvent';
if (name == 'GeoGeolocation') return 'Geolocation';
if (name == 'WorkerMessageEvent') return 'MessageEvent';
if (name == 'XMLDocument') return 'Document';
@@ -55,15 +44,10 @@
return 'HTMLDocument';
}
if (name == 'BeforeUnloadEvent') return 'Event';
- if (name == 'CanvasPixelArray') return 'Uint8ClampedArray';
if (name == 'DataTransfer') return 'Clipboard';
- if (name == 'DragEvent') return 'MouseEvent';
if (name == 'HTMLDDElement') return 'HTMLElement';
if (name == 'HTMLDTElement') return 'HTMLElement';
- if (name == 'HTMLTableDataCellElement') return 'HTMLTableCellElement';
- if (name == 'HTMLTableHeaderCellElement') return 'HTMLTableCellElement';
if (name == 'HTMLPhraseElement') return 'HTMLElement';
- if (name == 'MSStyleCSSProperties') return 'CSSStyleDeclaration';
if (name == 'Position') return 'Geoposition';
// Patches for types which report themselves as Objects.
diff --git a/sdk/lib/_internal/libraries.dart b/sdk/lib/_internal/libraries.dart
index 51e5037..6c6a3a0 100644
--- a/sdk/lib/_internal/libraries.dart
+++ b/sdk/lib/_internal/libraries.dart
@@ -83,12 +83,6 @@
documented: false,
platforms: VM_PLATFORM),
- "mdv_observe_impl": const LibraryInfo(
- "mdv_observe_impl/mdv_observe_impl.dart",
- category: "Client",
- documented: false,
- implementation: true),
-
"typed_data": const LibraryInfo(
"typed_data/typed_data.dart",
dart2jsPath: "typed_data/dart2js/typed_data_dart2js.dart"),
diff --git a/sdk/lib/_internal/pub/lib/src/command.dart b/sdk/lib/_internal/pub/lib/src/command.dart
index 73bf471..6b5f63d 100644
--- a/sdk/lib/_internal/pub/lib/src/command.dart
+++ b/sdk/lib/_internal/pub/lib/src/command.dart
@@ -2,20 +2,22 @@
// 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 pub.command;
+
import 'dart:io';
import 'dart:async';
import 'package:args/args.dart';
import 'package:pathos/path.dart' as path;
-import 'command_cache.dart';
-import 'command_deploy.dart';
-import 'command_help.dart';
-import 'command_install.dart';
-import 'command_lish.dart';
-import 'command_update.dart';
-import 'command_uploader.dart';
-import 'command_version.dart';
+import 'command/cache.dart';
+import 'command/deploy.dart';
+import 'command/help.dart';
+import 'command/install.dart';
+import 'command/lish.dart';
+import 'command/update.dart';
+import 'command/uploader.dart';
+import 'command/version.dart';
import 'entrypoint.dart';
import 'exit_codes.dart' as exit_codes;
import 'http.dart';
diff --git a/sdk/lib/_internal/pub/lib/src/command_cache.dart b/sdk/lib/_internal/pub/lib/src/command/cache.dart
similarity index 91%
rename from sdk/lib/_internal/pub/lib/src/command_cache.dart
rename to sdk/lib/_internal/pub/lib/src/command/cache.dart
index 9beb611..b33a045 100644
--- a/sdk/lib/_internal/pub/lib/src/command_cache.dart
+++ b/sdk/lib/_internal/pub/lib/src/command/cache.dart
@@ -2,15 +2,15 @@
// 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 command_cache;
+library pub.command.cache;
import 'dart:async';
import 'dart:io';
import 'dart:json' as json;
-import 'command.dart';
-import 'exit_codes.dart' as exit_codes;
-import 'log.dart' as log;
+import '../command.dart';
+import '../exit_codes.dart' as exit_codes;
+import '../log.dart' as log;
/// Handles the `cache` pub command.
class CacheCommand extends PubCommand {
diff --git a/sdk/lib/_internal/pub/lib/src/command_deploy.dart b/sdk/lib/_internal/pub/lib/src/command/deploy.dart
similarity index 96%
rename from sdk/lib/_internal/pub/lib/src/command_deploy.dart
rename to sdk/lib/_internal/pub/lib/src/command/deploy.dart
index 7261b12..76904a8 100644
--- a/sdk/lib/_internal/pub/lib/src/command_deploy.dart
+++ b/sdk/lib/_internal/pub/lib/src/command/deploy.dart
@@ -2,7 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-library command_deploy;
+library pub.command.deploy;
import 'dart:async';
import 'dart:math' as math;
@@ -10,11 +10,11 @@
import 'package:analyzer_experimental/analyzer.dart';
import 'package:pathos/path.dart' as path;
-import 'command.dart';
-import 'dart.dart' as dart;
-import 'io.dart';
-import 'log.dart' as log;
-import 'utils.dart';
+import '../command.dart';
+import '../dart.dart' as dart;
+import '../io.dart';
+import '../log.dart' as log;
+import '../utils.dart';
final _arrow = getSpecial('\u2192', '=>');
diff --git a/sdk/lib/_internal/pub/lib/src/command_help.dart b/sdk/lib/_internal/pub/lib/src/command/help.dart
similarity index 82%
rename from sdk/lib/_internal/pub/lib/src/command_help.dart
rename to sdk/lib/_internal/pub/lib/src/command/help.dart
index 25218bc3..a53c575 100644
--- a/sdk/lib/_internal/pub/lib/src/command_help.dart
+++ b/sdk/lib/_internal/pub/lib/src/command/help.dart
@@ -2,17 +2,17 @@
// 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 command_help;
+library pub.command.help;
import 'dart:async';
import 'dart:io' as io;
-import 'command.dart';
-import 'exit_codes.dart' as exit_codes;
-import 'io.dart';
-import 'log.dart' as log;
+import '../command.dart';
+import '../exit_codes.dart' as exit_codes;
+import '../io.dart';
+import '../log.dart' as log;
-/// Handles the `help` pub command.
+/// Handles the `help` pub command.
class HelpCommand extends PubCommand {
String get description => "Display help information for Pub.";
String get usage => 'pub help [command]';
diff --git a/sdk/lib/_internal/pub/lib/src/command_install.dart b/sdk/lib/_internal/pub/lib/src/command/install.dart
similarity index 87%
rename from sdk/lib/_internal/pub/lib/src/command_install.dart
rename to sdk/lib/_internal/pub/lib/src/command/install.dart
index afc9d2f..f5621de 100644
--- a/sdk/lib/_internal/pub/lib/src/command_install.dart
+++ b/sdk/lib/_internal/pub/lib/src/command/install.dart
@@ -2,15 +2,15 @@
// 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 command_install;
+library pub.command.install;
import 'dart:async';
import 'package:args/args.dart';
-import 'command.dart';
-import 'entrypoint.dart';
-import 'log.dart' as log;
+import '../command.dart';
+import '../entrypoint.dart';
+import '../log.dart' as log;
/// Handles the `install` pub command.
class InstallCommand extends PubCommand {
diff --git a/sdk/lib/_internal/pub/lib/src/command_lish.dart b/sdk/lib/_internal/pub/lib/src/command/lish.dart
similarity index 93%
rename from sdk/lib/_internal/pub/lib/src/command_lish.dart
rename to sdk/lib/_internal/pub/lib/src/command/lish.dart
index 8e4e09c..3721522 100644
--- a/sdk/lib/_internal/pub/lib/src/command_lish.dart
+++ b/sdk/lib/_internal/pub/lib/src/command/lish.dart
@@ -2,7 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-library command_lish;
+library pub.command.lish;
import 'dart:async';
import 'dart:io';
@@ -12,17 +12,17 @@
import 'package:http/http.dart' as http;
import 'package:pathos/path.dart' as path;
-import 'command.dart';
-import 'directory_tree.dart';
-import 'exit_codes.dart' as exit_codes;
-import 'git.dart' as git;
-import 'hosted_source.dart';
-import 'http.dart';
-import 'io.dart';
-import 'log.dart' as log;
-import 'oauth2.dart' as oauth2;
-import 'utils.dart';
-import 'validator.dart';
+import '../command.dart';
+import '../directory_tree.dart';
+import '../exit_codes.dart' as exit_codes;
+import '../git.dart' as git;
+import '../http.dart';
+import '../io.dart';
+import '../log.dart' as log;
+import '../oauth2.dart' as oauth2;
+import '../source/hosted.dart';
+import '../utils.dart';
+import '../validator.dart';
/// Handles the `lish` and `publish` pub commands.
class LishCommand extends PubCommand {
diff --git a/sdk/lib/_internal/pub/lib/src/command_update.dart b/sdk/lib/_internal/pub/lib/src/command/update.dart
similarity index 90%
rename from sdk/lib/_internal/pub/lib/src/command_update.dart
rename to sdk/lib/_internal/pub/lib/src/command/update.dart
index 3db7ba8..e47c80b 100644
--- a/sdk/lib/_internal/pub/lib/src/command_update.dart
+++ b/sdk/lib/_internal/pub/lib/src/command/update.dart
@@ -2,15 +2,15 @@
// 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 command_update;
+library pub.command.update;
import 'dart:async';
import 'package:args/args.dart';
-import 'command.dart';
-import 'entrypoint.dart';
-import 'log.dart' as log;
+import '../command.dart';
+import '../entrypoint.dart';
+import '../log.dart' as log;
/// Handles the `update` pub command.
class UpdateCommand extends PubCommand {
diff --git a/sdk/lib/_internal/pub/lib/src/command_uploader.dart b/sdk/lib/_internal/pub/lib/src/command/uploader.dart
similarity index 89%
rename from sdk/lib/_internal/pub/lib/src/command_uploader.dart
rename to sdk/lib/_internal/pub/lib/src/command/uploader.dart
index cb6bf8b..0bae108 100644
--- a/sdk/lib/_internal/pub/lib/src/command_uploader.dart
+++ b/sdk/lib/_internal/pub/lib/src/command/uploader.dart
@@ -2,7 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-library command_uploader;
+library pub.command.uploader;
import 'dart:async';
import 'dart:io';
@@ -10,15 +10,15 @@
import 'package:args/args.dart';
import 'package:pathos/path.dart' as path;
-import 'command.dart';
-import 'entrypoint.dart';
-import 'exit_codes.dart' as exit_codes;
-import 'http.dart';
-import 'hosted_source.dart';
-import 'io.dart';
-import 'log.dart' as log;
-import 'oauth2.dart' as oauth2;
-import 'utils.dart';
+import '../command.dart';
+import '../entrypoint.dart';
+import '../exit_codes.dart' as exit_codes;
+import '../http.dart';
+import '../io.dart';
+import '../log.dart' as log;
+import '../oauth2.dart' as oauth2;
+import '../source/hosted.dart';
+import '../utils.dart';
/// Handles the `uploader` pub command.
class UploaderCommand extends PubCommand {
diff --git a/sdk/lib/_internal/pub/lib/src/command_version.dart b/sdk/lib/_internal/pub/lib/src/command/version.dart
similarity index 75%
rename from sdk/lib/_internal/pub/lib/src/command_version.dart
rename to sdk/lib/_internal/pub/lib/src/command/version.dart
index 457eebd..5fa6026 100644
--- a/sdk/lib/_internal/pub/lib/src/command_version.dart
+++ b/sdk/lib/_internal/pub/lib/src/command/version.dart
@@ -2,15 +2,15 @@
// 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 command_version;
+library pub.command.version;
import 'dart:async';
-import 'command.dart';
-import 'log.dart' as log;
-import 'sdk.dart' as sdk;
+import '../command.dart';
+import '../log.dart' as log;
+import '../sdk.dart' as sdk;
-/// Handles the `version` pub command.
+/// Handles the `version` pub command.
class VersionCommand extends PubCommand {
String get description => 'Print pub version.';
String get usage => 'pub version';
diff --git a/sdk/lib/_internal/pub/lib/src/dart.dart b/sdk/lib/_internal/pub/lib/src/dart.dart
index 0ad59c0..5c27f09 100644
--- a/sdk/lib/_internal/pub/lib/src/dart.dart
+++ b/sdk/lib/_internal/pub/lib/src/dart.dart
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
/// A library for compiling Dart code and manipulating analyzer parse trees.
-library dart;
+library pub.dart;
import 'dart:async';
import 'dart:io';
diff --git a/sdk/lib/_internal/pub/lib/src/directory_tree.dart b/sdk/lib/_internal/pub/lib/src/directory_tree.dart
index a4d501e..7a5f953 100644
--- a/sdk/lib/_internal/pub/lib/src/directory_tree.dart
+++ b/sdk/lib/_internal/pub/lib/src/directory_tree.dart
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
/// A simple library for rendering a list of files as a directory tree.
-library directory_tree;
+library pub.directory_tree;
import 'package:pathos/path.dart' as path;
diff --git a/sdk/lib/_internal/pub/lib/src/entrypoint.dart b/sdk/lib/_internal/pub/lib/src/entrypoint.dart
index a10a0c1..b2c47c2 100644
--- a/sdk/lib/_internal/pub/lib/src/entrypoint.dart
+++ b/sdk/lib/_internal/pub/lib/src/entrypoint.dart
@@ -2,7 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-library entrypoint;
+library pub.entrypoint;
import 'dart:async';
diff --git a/sdk/lib/_internal/pub/lib/src/error_group.dart b/sdk/lib/_internal/pub/lib/src/error_group.dart
index 51fb27d..303628a 100644
--- a/sdk/lib/_internal/pub/lib/src/error_group.dart
+++ b/sdk/lib/_internal/pub/lib/src/error_group.dart
@@ -2,7 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-library error_group;
+library pub.error_group;
import 'dart:async';
diff --git a/sdk/lib/_internal/pub/lib/src/exit_codes.dart b/sdk/lib/_internal/pub/lib/src/exit_codes.dart
index fd39d15..028fd1c 100644
--- a/sdk/lib/_internal/pub/lib/src/exit_codes.dart
+++ b/sdk/lib/_internal/pub/lib/src/exit_codes.dart
@@ -7,7 +7,7 @@
/// appropriate for errors encountered by pub.
///
/// [manpage]: http://www.freebsd.org/cgi/man.cgi?query=sysexits
-library exit_codes;
+library pub.exit_codes;
/// The command was used incorrectly.
final USAGE = 64;
diff --git a/sdk/lib/_internal/pub/lib/src/git.dart b/sdk/lib/_internal/pub/lib/src/git.dart
index 8d996229..9e946e2 100644
--- a/sdk/lib/_internal/pub/lib/src/git.dart
+++ b/sdk/lib/_internal/pub/lib/src/git.dart
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
/// Helper functionality for invoking Git.
-library git;
+library pub.git;
import 'dart:async';
import 'io.dart';
diff --git a/sdk/lib/_internal/pub/lib/src/lock_file.dart b/sdk/lib/_internal/pub/lib/src/lock_file.dart
index 7f69ca1..85b63a8 100644
--- a/sdk/lib/_internal/pub/lib/src/lock_file.dart
+++ b/sdk/lib/_internal/pub/lib/src/lock_file.dart
@@ -2,7 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-library lock_file;
+library pub.lock_file;
import 'dart:collection';
diff --git a/sdk/lib/_internal/pub/lib/src/log.dart b/sdk/lib/_internal/pub/lib/src/log.dart
index 047f621..2d61143 100644
--- a/sdk/lib/_internal/pub/lib/src/log.dart
+++ b/sdk/lib/_internal/pub/lib/src/log.dart
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
/// Message logging.
-library log;
+library pub.log;
import 'dart:io';
import 'dart:async';
diff --git a/sdk/lib/_internal/pub/lib/src/oauth2.dart b/sdk/lib/_internal/pub/lib/src/oauth2.dart
index dd2c7b6..66e5f88 100644
--- a/sdk/lib/_internal/pub/lib/src/oauth2.dart
+++ b/sdk/lib/_internal/pub/lib/src/oauth2.dart
@@ -2,7 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-library oauth2;
+library pub.oauth2;
import 'dart:async';
import 'dart:io';
diff --git a/sdk/lib/_internal/pub/lib/src/package.dart b/sdk/lib/_internal/pub/lib/src/package.dart
index 22d3bee..2979849 100644
--- a/sdk/lib/_internal/pub/lib/src/package.dart
+++ b/sdk/lib/_internal/pub/lib/src/package.dart
@@ -2,7 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-library package;
+library pub.package;
import 'dart:async';
diff --git a/sdk/lib/_internal/pub/lib/src/pubspec.dart b/sdk/lib/_internal/pub/lib/src/pubspec.dart
index 2100cc6..3a7738e 100644
--- a/sdk/lib/_internal/pub/lib/src/pubspec.dart
+++ b/sdk/lib/_internal/pub/lib/src/pubspec.dart
@@ -2,7 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-library pubspec;
+library pub.pubspec;
import 'package:yaml/yaml.dart';
import 'package:pathos/path.dart' as path;
diff --git a/sdk/lib/_internal/pub/lib/src/safe_http_server.dart b/sdk/lib/_internal/pub/lib/src/safe_http_server.dart
index 0f3b9f1..aeb24ac 100644
--- a/sdk/lib/_internal/pub/lib/src/safe_http_server.dart
+++ b/sdk/lib/_internal/pub/lib/src/safe_http_server.dart
@@ -2,7 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-library safe_http_server;
+library pub.safe_http_server;
import 'dart:async';
import 'dart:io';
diff --git a/sdk/lib/_internal/pub/lib/src/sdk.dart b/sdk/lib/_internal/pub/lib/src/sdk.dart
index 7f4e26a..8f86ab4 100644
--- a/sdk/lib/_internal/pub/lib/src/sdk.dart
+++ b/sdk/lib/_internal/pub/lib/src/sdk.dart
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
/// Operations relative to the user's installed Dart SDK.
-library sdk;
+library pub.sdk;
import 'dart:io';
diff --git a/sdk/lib/_internal/pub/lib/src/solver/backtracking_solver.dart b/sdk/lib/_internal/pub/lib/src/solver/backtracking_solver.dart
index 00a6ba2..e318ca2 100644
--- a/sdk/lib/_internal/pub/lib/src/solver/backtracking_solver.dart
+++ b/sdk/lib/_internal/pub/lib/src/solver/backtracking_solver.dart
@@ -31,7 +31,7 @@
/// doing this, traversing and then backtracking when it meets a failure until
/// a valid solution has been found or until all possible options for all
/// speculative choices have been exhausted.
-library solver.backtracking_solver;
+library pub.solver.backtracking_solver;
import 'dart:async';
import 'dart:collection' show Queue;
diff --git a/sdk/lib/_internal/pub/lib/src/solver/version_solver.dart b/sdk/lib/_internal/pub/lib/src/solver/version_solver.dart
index 9a98698..2dc215e 100644
--- a/sdk/lib/_internal/pub/lib/src/solver/version_solver.dart
+++ b/sdk/lib/_internal/pub/lib/src/solver/version_solver.dart
@@ -2,7 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-library version_solver;
+library pub.solver.version_solver;
import 'dart:async';
import 'dart:json' as json;
@@ -196,6 +196,8 @@
return buffer.toString();
}
+ String get message => toString();
+
/// A message describing the specific kind of solve failure.
String get _message {
throw new UnimplementedError("Must override _message or toString().");
diff --git a/sdk/lib/_internal/pub/lib/src/source.dart b/sdk/lib/_internal/pub/lib/src/source.dart
index f72f173..4557fa1 100644
--- a/sdk/lib/_internal/pub/lib/src/source.dart
+++ b/sdk/lib/_internal/pub/lib/src/source.dart
@@ -2,7 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-library source;
+library pub.source;
import 'dart:async';
diff --git a/sdk/lib/_internal/pub/lib/src/git_source.dart b/sdk/lib/_internal/pub/lib/src/source/git.dart
similarity index 96%
rename from sdk/lib/_internal/pub/lib/src/git_source.dart
rename to sdk/lib/_internal/pub/lib/src/source/git.dart
index bccae27..c623cdb 100644
--- a/sdk/lib/_internal/pub/lib/src/git_source.dart
+++ b/sdk/lib/_internal/pub/lib/src/source/git.dart
@@ -2,19 +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 git_source;
+library pub.source.git;
import 'dart:async';
import 'package:pathos/path.dart' as path;
-import 'git.dart' as git;
-import 'io.dart';
-import 'log.dart' as log;
-import 'package.dart';
-import 'source.dart';
-import 'source_registry.dart';
-import 'utils.dart';
+import '../git.dart' as git;
+import '../io.dart';
+import '../log.dart' as log;
+import '../package.dart';
+import '../source.dart';
+import '../source_registry.dart';
+import '../utils.dart';
/// A package source that installs packages from Git repos.
class GitSource extends Source {
diff --git a/sdk/lib/_internal/pub/lib/src/hosted_source.dart b/sdk/lib/_internal/pub/lib/src/source/hosted.dart
similarity index 96%
rename from sdk/lib/_internal/pub/lib/src/hosted_source.dart
rename to sdk/lib/_internal/pub/lib/src/source/hosted.dart
index 6967aa6..f69924f 100644
--- a/sdk/lib/_internal/pub/lib/src/hosted_source.dart
+++ b/sdk/lib/_internal/pub/lib/src/source/hosted.dart
@@ -2,7 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-library hosted_source;
+library pub.source.hosted;
import 'dart:async';
import 'dart:io' as io;
@@ -11,15 +11,15 @@
import 'package:http/http.dart' as http;
import 'package:pathos/path.dart' as path;
-import 'http.dart';
-import 'io.dart';
-import 'log.dart' as log;
-import 'package.dart';
-import 'pubspec.dart';
-import 'source.dart';
-import 'source_registry.dart';
-import 'utils.dart';
-import 'version.dart';
+import '../http.dart';
+import '../io.dart';
+import '../log.dart' as log;
+import '../package.dart';
+import '../pubspec.dart';
+import '../source.dart';
+import '../source_registry.dart';
+import '../utils.dart';
+import '../version.dart';
/// A package source that installs packages from a package hosting site that
/// uses the same API as pub.dartlang.org.
diff --git a/sdk/lib/_internal/pub/lib/src/path_source.dart b/sdk/lib/_internal/pub/lib/src/source/path.dart
similarity index 94%
rename from sdk/lib/_internal/pub/lib/src/path_source.dart
rename to sdk/lib/_internal/pub/lib/src/source/path.dart
index 5972050..a8a5306 100644
--- a/sdk/lib/_internal/pub/lib/src/path_source.dart
+++ b/sdk/lib/_internal/pub/lib/src/source/path.dart
@@ -2,21 +2,21 @@
// 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 path_source;
+library pub.source.path;
import 'dart:async';
import 'dart:io';
import 'package:pathos/path.dart' as path;
-import 'log.dart' as log;
+import '../log.dart' as log;
-import 'io.dart';
-import 'package.dart';
-import 'pubspec.dart';
-import 'version.dart';
-import 'source.dart';
-import 'utils.dart';
+import '../io.dart';
+import '../package.dart';
+import '../pubspec.dart';
+import '../version.dart';
+import '../source.dart';
+import '../utils.dart';
/// A package [Source] that installs packages from a given local file path.
class PathSource extends Source {
diff --git a/sdk/lib/_internal/pub/lib/src/source_registry.dart b/sdk/lib/_internal/pub/lib/src/source_registry.dart
index a963e1d..00deb4a 100644
--- a/sdk/lib/_internal/pub/lib/src/source_registry.dart
+++ b/sdk/lib/_internal/pub/lib/src/source_registry.dart
@@ -2,7 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-library source_registry;
+library pub.source_registry;
import 'source.dart';
diff --git a/sdk/lib/_internal/pub/lib/src/system_cache.dart b/sdk/lib/_internal/pub/lib/src/system_cache.dart
index 63de5dc..08f031d 100644
--- a/sdk/lib/_internal/pub/lib/src/system_cache.dart
+++ b/sdk/lib/_internal/pub/lib/src/system_cache.dart
@@ -2,21 +2,21 @@
// 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 system_cache;
+library pub.system_cache;
import 'dart:io';
import 'dart:async';
import 'package:pathos/path.dart' as path;
-import 'git_source.dart';
-import 'hosted_source.dart';
import 'io.dart';
import 'io.dart' as io show createTempDir;
import 'log.dart' as log;
import 'package.dart';
-import 'path_source.dart';
import 'pubspec.dart';
+import 'source/git.dart';
+import 'source/hosted.dart';
+import 'source/path.dart';
import 'source.dart';
import 'source_registry.dart';
import 'utils.dart';
diff --git a/sdk/lib/_internal/pub/lib/src/utils.dart b/sdk/lib/_internal/pub/lib/src/utils.dart
index d5210f3..8c41b92 100644
--- a/sdk/lib/_internal/pub/lib/src/utils.dart
+++ b/sdk/lib/_internal/pub/lib/src/utils.dart
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
/// Generic utility functions. Stuff that should possibly be in core.
-library utils;
+library pub.utils;
import 'dart:async';
import 'dart:io';
diff --git a/sdk/lib/_internal/pub/lib/src/validator.dart b/sdk/lib/_internal/pub/lib/src/validator.dart
index 4bfff03..c4a258f 100644
--- a/sdk/lib/_internal/pub/lib/src/validator.dart
+++ b/sdk/lib/_internal/pub/lib/src/validator.dart
@@ -2,7 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-library validator;
+library pub.validator;
import 'dart:async';
diff --git a/sdk/lib/_internal/pub/lib/src/validator/compiled_dartdoc.dart b/sdk/lib/_internal/pub/lib/src/validator/compiled_dartdoc.dart
index 45a8fba..94f7031 100644
--- a/sdk/lib/_internal/pub/lib/src/validator/compiled_dartdoc.dart
+++ b/sdk/lib/_internal/pub/lib/src/validator/compiled_dartdoc.dart
@@ -2,7 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-library compiled_dartdoc_validator;
+library pub.validator.compiled_dartdoc;
import 'dart:async';
diff --git a/sdk/lib/_internal/pub/lib/src/validator/dependency.dart b/sdk/lib/_internal/pub/lib/src/validator/dependency.dart
index a1a8f99..b447a8d 100644
--- a/sdk/lib/_internal/pub/lib/src/validator/dependency.dart
+++ b/sdk/lib/_internal/pub/lib/src/validator/dependency.dart
@@ -2,15 +2,15 @@
// 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 dependency_validator;
+library pub.validator.dependency;
import 'dart:async';
import '../entrypoint.dart';
-import '../hosted_source.dart';
import '../http.dart';
import '../package.dart';
-import '../path_source.dart';
+import '../source/hosted.dart';
+import '../source/path.dart';
import '../utils.dart';
import '../validator.dart';
import '../version.dart';
diff --git a/sdk/lib/_internal/pub/lib/src/validator/directory.dart b/sdk/lib/_internal/pub/lib/src/validator/directory.dart
index 5e90437..30f4ddd 100644
--- a/sdk/lib/_internal/pub/lib/src/validator/directory.dart
+++ b/sdk/lib/_internal/pub/lib/src/validator/directory.dart
@@ -2,7 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-library directory_validator;
+library pub.validator.directory;
import 'dart:async';
diff --git a/sdk/lib/_internal/pub/lib/src/validator/lib.dart b/sdk/lib/_internal/pub/lib/src/validator/lib.dart
index 2e72738..42d6366 100644
--- a/sdk/lib/_internal/pub/lib/src/validator/lib.dart
+++ b/sdk/lib/_internal/pub/lib/src/validator/lib.dart
@@ -2,7 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-library lib_validator;
+library pub.validator.lib;
import 'dart:async';
import 'dart:io';
diff --git a/sdk/lib/_internal/pub/lib/src/validator/license.dart b/sdk/lib/_internal/pub/lib/src/validator/license.dart
index 16b202f..844c223 100644
--- a/sdk/lib/_internal/pub/lib/src/validator/license.dart
+++ b/sdk/lib/_internal/pub/lib/src/validator/license.dart
@@ -2,7 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-library license_validator;
+library pub.validator.license;
import 'dart:async';
diff --git a/sdk/lib/_internal/pub/lib/src/validator/name.dart b/sdk/lib/_internal/pub/lib/src/validator/name.dart
index 542d9fd..8df191a 100644
--- a/sdk/lib/_internal/pub/lib/src/validator/name.dart
+++ b/sdk/lib/_internal/pub/lib/src/validator/name.dart
@@ -2,7 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-library name_validator;
+library pub.validator.name;
import 'dart:async';
import 'dart:io';
diff --git a/sdk/lib/_internal/pub/lib/src/validator/pubspec_field.dart b/sdk/lib/_internal/pub/lib/src/validator/pubspec_field.dart
index 03a1b8e..6cb1d83 100644
--- a/sdk/lib/_internal/pub/lib/src/validator/pubspec_field.dart
+++ b/sdk/lib/_internal/pub/lib/src/validator/pubspec_field.dart
@@ -2,7 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-library pubspec_field_validator;
+library pub.validator.pubspec_field;
import 'dart:async';
diff --git a/sdk/lib/_internal/pub/lib/src/validator/size.dart b/sdk/lib/_internal/pub/lib/src/validator/size.dart
index 8014b29..0b8d05f 100644
--- a/sdk/lib/_internal/pub/lib/src/validator/size.dart
+++ b/sdk/lib/_internal/pub/lib/src/validator/size.dart
@@ -2,7 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-library size_validator;
+library pub.validator.size;
import 'dart:async';
import 'dart:math' as math;
diff --git a/sdk/lib/_internal/pub/lib/src/validator/utf8_readme.dart b/sdk/lib/_internal/pub/lib/src/validator/utf8_readme.dart
index cbb85c4..2ae7ad3 100644
--- a/sdk/lib/_internal/pub/lib/src/validator/utf8_readme.dart
+++ b/sdk/lib/_internal/pub/lib/src/validator/utf8_readme.dart
@@ -2,7 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-library utf8_readme_validator;
+library pub.validator.utf8_readme;
import 'dart:async';
import 'dart:utf';
diff --git a/sdk/lib/_internal/pub/lib/src/version.dart b/sdk/lib/_internal/pub/lib/src/version.dart
index 62669e4..c3943a6 100644
--- a/sdk/lib/_internal/pub/lib/src/version.dart
+++ b/sdk/lib/_internal/pub/lib/src/version.dart
@@ -5,7 +5,7 @@
/// Handles version numbers, following the [Semantic Versioning][semver] spec.
///
/// [semver]: http://semver.org/
-library version;
+library pub.version;
import 'dart:math';
diff --git a/sdk/lib/_internal/pub/test/test_pub.dart b/sdk/lib/_internal/pub/test/test_pub.dart
index c35ab69..b3bbc82 100644
--- a/sdk/lib/_internal/pub/test/test_pub.dart
+++ b/sdk/lib/_internal/pub/test/test_pub.dart
@@ -28,13 +28,13 @@
// with the git descriptor method. Maybe we should try to clean up the top level
// scope a bit?
import '../lib/src/git.dart' as gitlib;
-import '../lib/src/git_source.dart';
-import '../lib/src/hosted_source.dart';
import '../lib/src/http.dart';
import '../lib/src/io.dart';
import '../lib/src/log.dart' as log;
-import '../lib/src/path_source.dart';
import '../lib/src/safe_http_server.dart';
+import '../lib/src/source/git.dart';
+import '../lib/src/source/hosted.dart';
+import '../lib/src/source/path.dart';
import '../lib/src/system_cache.dart';
import '../lib/src/utils.dart';
import '../lib/src/validator.dart';
diff --git a/sdk/lib/collection/hash_map.dart b/sdk/lib/collection/hash_map.dart
index ab1f09c..e2f22a6 100644
--- a/sdk/lib/collection/hash_map.dart
+++ b/sdk/lib/collection/hash_map.dart
@@ -18,10 +18,50 @@
class HashMap<K, V> implements Map<K, V> {
external HashMap();
+ /**
+ * Creates a [HashMap] that contains all key value pairs of [other].
+ */
factory HashMap.from(Map<K, V> other) {
return new HashMap<K, V>()..addAll(other);
}
+ /**
+ * Creates a [HashMap] where the keys and values are computed from the
+ * [iterable].
+ *
+ * For each element of the [iterable] this constructor computes a key/value
+ * pair, by applying [key] and [value] respectively.
+ *
+ * The keys of the key/value pairs do not need to be unique. The last
+ * occurrence of a key will simply overwrite any previous value.
+ *
+ * If no values are specified for [key] and [value] the default is the
+ * identity function.
+ */
+ factory HashMap.fromIterable(Iterable<K> iterable,
+ {K key(element), V value(element)}) {
+ HashMap<K, V> map = new HashMap<K, V>();
+ Maps._fillMapWithMappedIterable(map, iterable, key, value);
+ return map;
+ }
+
+ /**
+ * Creates a [HashMap] associating the given [keys] to [values].
+ *
+ * This constructor iterates over [keys] and [values] and maps each element of
+ * [keys] to the corresponding element of [values].
+ *
+ * If [keys] contains the same object multiple times, the last occurrence
+ * overwrites the previous value.
+ *
+ * It is an error if the two [Iterable]s don't have the same length.
+ */
+ factory HashMap.fromIterables(Iterable<K> keys, Iterable<V> values) {
+ HashMap<K, V> map = new HashMap<K, V>();
+ Maps._fillMapWithIterables(map, keys, values);
+ return map;
+ }
+
external int get length;
external bool get isEmpty;
external bool get isNotEmpty;
diff --git a/sdk/lib/collection/linked_hash_map.dart b/sdk/lib/collection/linked_hash_map.dart
index 3082ce0..4ace589 100644
--- a/sdk/lib/collection/linked_hash_map.dart
+++ b/sdk/lib/collection/linked_hash_map.dart
@@ -21,10 +21,50 @@
class LinkedHashMap<K, V> implements Map<K, V> {
external LinkedHashMap();
+ /**
+ * Creates a [LinkedHashMap] that contains all key value pairs of [other].
+ */
factory LinkedHashMap.from(Map<K, V> other) {
return new LinkedHashMap<K, V>()..addAll(other);
}
+ /**
+ * Creates a [LinkedHashMap] where the keys and values are computed from the
+ * [iterable].
+ *
+ * For each element of the [iterable] this constructor computes a key/value
+ * pair, by applying [key] and [value] respectively.
+ *
+ * The keys of the key/value pairs do not need to be unique. The last
+ * occurrence of a key will simply overwrite any previous value.
+ *
+ * If no values are specified for [key] and [value] the default is the
+ * identity function.
+ */
+ factory LinkedHashMap.fromIterable(Iterable<K> iterable,
+ {K key(element), V value(element)}) {
+ LinkedHashMap<K, V> map = new LinkedHashMap<K, V>();
+ Maps._fillMapWithMappedIterable(map, iterable, key, value);
+ return map;
+ }
+
+ /**
+ * Creates a [LinkedHashMap] associating the given [keys] to [values].
+ *
+ * This constructor iterates over [keys] and [values] and maps each element of
+ * [keys] to the corresponding element of [values].
+ *
+ * If [keys] contains the same object multiple times, the last occurrence
+ * overwrites the previous value.
+ *
+ * It is an error if the two [Iterable]s don't have the same length.
+ */
+ factory LinkedHashMap.fromIterables(Iterable<K> keys, Iterable<V> values) {
+ LinkedHashMap<K, V> map = new LinkedHashMap<K, V>();
+ Maps._fillMapWithIterables(map, keys, values);
+ return map;
+ }
+
external bool containsKey(Object key);
external bool containsValue(Object value);
diff --git a/sdk/lib/collection/maps.dart b/sdk/lib/collection/maps.dart
index bd7d755..303008c 100644
--- a/sdk/lib/collection/maps.dart
+++ b/sdk/lib/collection/maps.dart
@@ -77,4 +77,45 @@
* simply return the results of this method applied to the collection.
*/
static String mapToString(Map m) => ToString.mapToString(m);
+
+ static _id(x) => x;
+
+ /**
+ * Fills a map with key/value pairs computed from [iterable].
+ *
+ * This method is used by Map classes in the named constructor fromIterable.
+ */
+ static void _fillMapWithMappedIterable(Map map, Iterable iterable,
+ key(element), value(element)) {
+ if (key == null) key = _id;
+ if (value == null) value = _id;
+
+ for (var element in iterable) {
+ map[key(element)] = value(element);
+ }
+ }
+
+ /**
+ * Fills a map by associating the [keys] to [values].
+ *
+ * This method is used by Map classes in the named constructor fromIterables.
+ */
+ static void _fillMapWithIterables(Map map, Iterable keys,
+ Iterable values) {
+ Iterator keyIterator = keys.iterator;
+ Iterator valueIterator = values.iterator;
+
+ bool hasNextKey = keyIterator.moveNext();
+ bool hasNextValue = valueIterator.moveNext();
+
+ while (hasNextKey && hasNextValue) {
+ map[keyIterator.current] = valueIterator.current;
+ hasNextKey = keyIterator.moveNext();
+ hasNextValue = valueIterator.moveNext();
+ }
+
+ if (hasNextKey || hasNextValue) {
+ throw new ArgumentError("Iterables do not have same length.");
+ }
+ }
}
diff --git a/sdk/lib/collection/splay_tree.dart b/sdk/lib/collection/splay_tree.dart
index 84e61e1..7dac687 100644
--- a/sdk/lib/collection/splay_tree.dart
+++ b/sdk/lib/collection/splay_tree.dart
@@ -248,9 +248,50 @@
SplayTreeMap([int compare(K key1, K key2)])
: _comparator = (compare == null) ? Comparable.compare : compare;
+ /**
+ * Creates a [SplayTreeMap] that contains all key value pairs of [other].
+ */
factory SplayTreeMap.from(Map<K, V> other, [int compare(K key1, K key2)]) =>
new SplayTreeMap(compare)..addAll(other);
+ /**
+ * Creates a [SplayTreeMap] where the keys and values are computed from the
+ * [iterable].
+ *
+ * For each element of the [iterable] this constructor computes a key/value
+ * pair, by applying [key] and [value] respectively.
+ *
+ * The keys of the key/value pairs do not need to be unique. The last
+ * occurrence of a key will simply overwrite any previous value.
+ *
+ * If no values are specified for [key] and [value] the default is the
+ * identity function.
+ */
+ factory SplayTreeMap.fromIterable(Iterable<K> iterable,
+ {K key(element), V value(element), int compare(K key1, K key2)}) {
+ SplayTreeMap<K, V> map = new SplayTreeMap<K, V>(compare);
+ Maps._fillMapWithMappedIterable(map, iterable, key, value);
+ return map;
+ }
+
+ /**
+ * Creates a [SplayTreeMap] associating the given [keys] to [values].
+ *
+ * This constructor iterates over [keys] and [values] and maps each element of
+ * [keys] to the corresponding element of [values].
+ *
+ * If [keys] contains the same object multiple times, the last occurrence
+ * overwrites the previous value.
+ *
+ * It is an error if the two [Iterable]s don't have the same length.
+ */
+ factory SplayTreeMap.fromIterables(Iterable<K> keys, Iterable<V> values,
+ [int compare(K key1, K key2)]) {
+ SplayTreeMap<K, V> map = new SplayTreeMap<K, V>(compare);
+ Maps._fillMapWithIterables(map, keys, values);
+ return map;
+ }
+
int _compare(K key1, K key2) => _comparator(key1, key2);
SplayTreeMap._internal();
diff --git a/sdk/lib/core/map.dart b/sdk/lib/core/map.dart
index 88776c1..e74b936 100644
--- a/sdk/lib/core/map.dart
+++ b/sdk/lib/core/map.dart
@@ -20,6 +20,35 @@
factory Map.from(Map<K, V> other) => new HashMap<K, V>.from(other);
/**
+ * Creates a [Map] where the keys and values are computed from the [iterable].
+ *
+ * For each element of the [iterable] this constructor computes a key/value
+ * pair, by applying [key] and [value] respectively.
+ *
+ * The keys of the key/value pairs do not need to be unique. The last
+ * occurrence of a key will simply overwrite any previous value.
+ *
+ * If no values are specified for [key] and [value] the default is the
+ * identity function.
+ */
+ factory Map.fromIterable(Iterable<K> iterable,
+ {K key(element), V value(element)}) = HashMap<K, V>.fromIterable;
+
+ /**
+ * Creates a [Map] associating the given [keys] to [values].
+ *
+ * This constructor iterates over [keys] and [values] and maps each element of
+ * [keys] to the corresponding element of [values].
+ *
+ * If [keys] contains the same object multiple times, the last occurrence
+ * overwrites the previous value.
+ *
+ * It is an error if the two [Iterable]s don't have the same length.
+ */
+ factory Map.fromIterables(Iterable<K> keys, Iterable<V> values)
+ = HashMap<K, V>.fromIterables;
+
+ /**
* Returns whether this map contains the given [value].
*/
bool containsValue(Object value);
diff --git a/sdk/lib/html/dart2js/html_dart2js.dart b/sdk/lib/html/dart2js/html_dart2js.dart
index 8f155b4..8e307a4 100644
--- a/sdk/lib/html/dart2js/html_dart2js.dart
+++ b/sdk/lib/html/dart2js/html_dart2js.dart
@@ -13,7 +13,6 @@
import 'dart:isolate';
import 'dart:json' as json;
import 'dart:math';
-import 'dart:mdv_observe_impl';
import 'dart:typed_data';
import 'dart:svg' as svg;
import 'dart:web_audio' as web_audio;
@@ -2498,7 +2497,7 @@
@DomName('CSSStyleDeclaration')
-class CssStyleDeclaration native "CSSStyleDeclaration" {
+class CssStyleDeclaration native "CSSStyleDeclaration,MSStyleCSSProperties,CSS2Properties" {
factory CssStyleDeclaration() => new CssStyleDeclaration.css('');
factory CssStyleDeclaration.css(String css) {
@@ -8280,21 +8279,6 @@
throw new UnsupportedError("Not supported on this platform");
}
- @Creates('Null') // Set from Dart code; does not instantiate a native type.
- Map<String, StreamSubscription> _attributeBindings;
-
- // TODO(jmesserly): I'm concerned about adding these to every element.
- // Conceptually all of these belong on TemplateElement. They are here to
- // support browsers that don't have <template> yet.
- // However even in the polyfill they're restricted to certain tags
- // (see [isTemplate]). So we can probably convert it to a (public) mixin, and
- // only mix it in to the elements that need it.
- @Creates('Null') // Set from Dart code; does not instantiate a native type.
- var _model;
-
- @Creates('Null') // Set from Dart code; does not instantiate a native type.
- _TemplateIterator _templateIterator;
-
@Creates('Null') // Set from Dart code; does not instantiate a native type.
Element _templateInstanceRef;
@@ -8304,124 +8288,6 @@
bool _templateIsDecorated;
- // TODO(jmesserly): should path be optional, and default to empty path?
- // It is used that way in at least one path in JS TemplateElement tests
- // (see "BindImperative" test in original JS code).
- @Experimental
- void bind(String name, model, String path) {
- _bindElement(this, name, model, path);
- }
-
- // TODO(jmesserly): this is static to work around http://dartbug.com/10166
- // Similar issue for unbind/unbindAll below.
- static void _bindElement(Element self, String name, model, String path) {
- if (self._bindTemplate(name, model, path)) return;
-
- if (self._attributeBindings == null) {
- self._attributeBindings = new Map<String, StreamSubscription>();
- }
-
- self.xtag.attributes.remove(name);
-
- var changed;
- if (name.endsWith('?')) {
- name = name.substring(0, name.length - 1);
-
- changed = (value) {
- if (_Bindings._toBoolean(value)) {
- self.xtag.attributes[name] = '';
- } else {
- self.xtag.attributes.remove(name);
- }
- };
- } else {
- changed = (value) {
- // TODO(jmesserly): escape value if needed to protect against XSS.
- // See https://github.com/polymer-project/mdv/issues/58
- self.xtag.attributes[name] = value == null ? '' : '$value';
- };
- }
-
- self.unbind(name);
-
- self._attributeBindings[name] =
- new PathObserver(model, path).bindSync(changed);
- }
-
- @Experimental
- void unbind(String name) {
- _unbindElement(this, name);
- }
-
- static _unbindElement(Element self, String name) {
- if (self._unbindTemplate(name)) return;
- if (self._attributeBindings != null) {
- var binding = self._attributeBindings.remove(name);
- if (binding != null) binding.cancel();
- }
- }
-
- @Experimental
- void unbindAll() {
- _unbindAllElement(this);
- }
-
- static void _unbindAllElement(Element self) {
- self._unbindAllTemplate();
-
- if (self._attributeBindings != null) {
- for (var binding in self._attributeBindings.values) {
- binding.cancel();
- }
- self._attributeBindings = null;
- }
- }
-
- // TODO(jmesserly): unlike the JS polyfill, we can't mixin
- // HTMLTemplateElement at runtime into things that are semantically template
- // elements. So instead we implement it here with a runtime check.
- // If the bind succeeds, we return true, otherwise we return false and let
- // the normal Element.bind logic kick in.
- bool _bindTemplate(String name, model, String path) {
- if (isTemplate) {
- switch (name) {
- case 'bind':
- case 'repeat':
- case 'if':
- _ensureTemplate();
- if (_templateIterator == null) {
- _templateIterator = new _TemplateIterator(this);
- }
- _templateIterator.inputs.bind(name, model, path);
- return true;
- }
- }
- return false;
- }
-
- bool _unbindTemplate(String name) {
- if (isTemplate) {
- switch (name) {
- case 'bind':
- case 'repeat':
- case 'if':
- _ensureTemplate();
- if (_templateIterator != null) {
- _templateIterator.inputs.unbind(name);
- }
- return true;
- }
- }
- return false;
- }
-
- void _unbindAllTemplate() {
- if (isTemplate) {
- unbind('bind');
- unbind('repeat');
- unbind('if');
- }
- }
/**
* Gets the template this node refers to.
@@ -8434,7 +8300,19 @@
Element ref = null;
var refId = attributes['ref'];
if (refId != null) {
- ref = document.getElementById(refId);
+ var treeScope = this;
+ while (treeScope.parentNode != null) {
+ treeScope = treeScope.parentNode;
+ }
+
+ // Note: JS code tests that getElementById is present. We can't do that
+ // easily, so instead check for the types known to implement it.
+ if (treeScope is Document ||
+ treeScope is ShadowRoot ||
+ treeScope is svg.SvgSvgElement) {
+
+ ref = treeScope.getElementById(refId);
+ }
}
return ref != null ? ref : _templateInstanceRef;
@@ -8457,38 +8335,20 @@
@Experimental
DocumentFragment createInstance() {
_ensureTemplate();
-
- var template = ref;
- if (template == null) template = this;
-
- var instance = _Bindings._createDeepCloneAndDecorateTemplates(
- template.content, attributes['syntax']);
-
- if (TemplateElement._instanceCreated != null) {
- TemplateElement._instanceCreated.add(instance);
- }
- return instance;
+ return TemplateElement.mdvPackage(this).createInstance();
}
/**
* The data model which is inherited through the tree.
* This is only supported if [isTemplate] is true.
- *
- * Setting this will destructive propagate the value to all descendant nodes,
- * and reinstantiate all of the nodes expanded by this template.
- *
- * Currently this does not support propagation through Shadow DOMs.
*/
@Experimental
- get model => _model;
+ get model => TemplateElement.mdvPackage(this).model;
@Experimental
void set model(value) {
_ensureTemplate();
-
- var syntax = TemplateElement.syntax[attributes['syntax']];
- _model = value;
- _Bindings._addBindings(this, model, syntax);
+ TemplateElement.mdvPackage(this).model = value;
}
// TODO(jmesserly): const set would be better
@@ -8505,7 +8365,8 @@
};
bool get _isAttributeTemplate => attributes.containsKey('template') &&
- (localName == 'option' || _TABLE_TAGS.containsKey(localName));
+ (localName == 'option' || localName == 'optgroup' ||
+ _TABLE_TAGS.containsKey(localName));
/**
* Returns true if this node is a template.
@@ -8514,7 +8375,7 @@
* 'template' attribute and this tag supports attribute form for backwards
* compatibility with existing HTML parsers. The nodes that can use attribute
* form are table elments (THEAD, TBODY, TFOOT, TH, TR, TD, CAPTION, COLGROUP
- * and COL) and OPTION.
+ * and COL), OPTION, and OPTGROUP.
*/
// TODO(jmesserly): this is not a public MDV API, but it seems like a useful
// place to document which tags our polyfill considers to be templates.
@@ -12524,61 +12385,6 @@
return e;
}
- @Creates('Null') // Set from Dart code; does not instantiate a native type.
- _ValueBinding _valueBinding;
-
- @Creates('Null') // Set from Dart code; does not instantiate a native type.
- _CheckedBinding _checkedBinding;
-
- @Experimental
- void bind(String name, model, String path) {
- switch (name) {
- case 'value':
- unbind('value');
- attributes.remove('value');
- _valueBinding = new _ValueBinding(this, model, path);
- break;
- case 'checked':
- unbind('checked');
- attributes.remove('checked');
- _checkedBinding = new _CheckedBinding(this, model, path);
- break;
- default:
- // TODO(jmesserly): this should be "super" (http://dartbug.com/10166).
- // Similar issue for unbind/unbindAll below.
- Element._bindElement(this, name, model, path);
- break;
- }
- }
-
- @Experimental
- void unbind(String name) {
- switch (name) {
- case 'value':
- if (_valueBinding != null) {
- _valueBinding.unbind();
- _valueBinding = null;
- }
- break;
- case 'checked':
- if (_checkedBinding != null) {
- _checkedBinding.unbind();
- _checkedBinding = null;
- }
- break;
- default:
- Element._unbindElement(this, name);
- break;
- }
- }
-
- @Experimental
- void unbindAll() {
- unbind('value');
- unbind('checked');
- Element._unbindAllElement(this);
- }
-
@DomName('HTMLInputElement.webkitSpeechChangeEvent')
@DocsEditable
@@ -15627,7 +15433,7 @@
@DomName('MouseEvent')
-class MouseEvent extends UIEvent native "MouseEvent" {
+class MouseEvent extends UIEvent native "MouseEvent,DragEvent" {
factory MouseEvent(String type,
{Window view, int detail: 0, int screenX: 0, int screenY: 0,
int clientX: 0, int clientY: 0, int button: 0, bool canBubble: true,
@@ -16380,8 +16186,7 @@
if (!identical(otherList._this, _this)) {
// Optimized route for copying between nodes.
for (var i = 0, len = otherList.length; i < len; ++i) {
- // Should use $dom_firstChild, Bug 8886.
- _this.append(otherList[0]);
+ _this.append(otherList._this.firstChild);
}
}
return;
@@ -16439,7 +16244,7 @@
// This implementation of removeWhere/retainWhere is more efficient
// than the default in ListBase. Child nodes can be removed in constant
// time.
- Node child = _this.$dom_firstChild;
+ Node child = _this.firstChild;
while (child != null) {
Node nextChild = child.nextNode;
if (test(child) == removeMatching) {
@@ -16498,6 +16303,27 @@
Node operator[](int index) => _this.$dom_childNodes[index];
}
+/** Information about the instantiated template. */
+class TemplateInstance {
+ // TODO(rafaelw): firstNode & lastNode should be read-synchronous
+ // in cases where script has modified the template instance boundary.
+
+ /** The first node of this template instantiation. */
+ final Node firstNode;
+
+ /**
+ * The last node of this template instantiation.
+ * This could be identical to [firstNode] if the template only expanded to a
+ * single node.
+ */
+ final Node lastNode;
+
+ /** The model used to instantiate the template. */
+ final model;
+
+ TemplateInstance(this.firstNode, this.lastNode, this.model);
+}
+
@DomName('Node')
class Node extends EventTarget native "Node" {
List<Node> get nodes {
@@ -16557,8 +16383,7 @@
// Optimized route for copying between nodes.
for (var i = 0, len = otherList.length; i < len; ++i) {
- // Should use $dom_firstChild, Bug 8886.
- this.insertBefore(otherList[0], refChild);
+ this.insertBefore(otherList._this.firstChild, refChild);
}
} else {
for (var node in newNodes) {
@@ -16578,26 +16403,25 @@
*/
@Experimental
void bind(String name, model, String path) {
- // TODO(jmesserly): should we throw instead?
- window.console.error('Unhandled binding to Node: '
- '$this $name $model $path');
+ TemplateElement.mdvPackage(this).bind(name, model, path);
}
/** Unbinds the attribute [name]. */
@Experimental
- void unbind(String name) {}
+ void unbind(String name) {
+ TemplateElement.mdvPackage(this).unbind(name);
+ }
/** Unbinds all bound attributes. */
@Experimental
- void unbindAll() {}
-
- TemplateInstance _templateInstance;
+ void unbindAll() {
+ TemplateElement.mdvPackage(this).unbindAll();
+ }
/** Gets the template instance that instantiated this node, if any. */
@Experimental
TemplateInstance get templateInstance =>
- _templateInstance != null ? _templateInstance :
- (parent != null ? parent.templateInstance : null);
+ TemplateElement.mdvPackage(this).templateInstance;
@DomName('Node.ATTRIBUTE_NODE')
@@ -16655,15 +16479,13 @@
@Creates('NodeList')
final List<Node> $dom_childNodes;
- @JSName('firstChild')
@DomName('Node.firstChild')
@DocsEditable
- final Node $dom_firstChild;
+ final Node firstChild;
- @JSName('lastChild')
@DomName('Node.lastChild')
@DocsEditable
- final Node $dom_lastChild;
+ final Node lastChild;
@JSName('localName')
@DomName('Node.localName')
@@ -20803,7 +20625,7 @@
@DocsEditable
@DomName('HTMLTableCellElement')
-class TableCellElement extends _HTMLElement native "HTMLTableCellElement" {
+class TableCellElement extends _HTMLElement native "HTMLTableCellElement,HTMLTableDataCellElement,HTMLTableHeaderCellElement" {
@DomName('HTMLTableCellElement.HTMLTableCellElement')
@DocsEditable
@@ -21037,6 +20859,99 @@
// WARNING: Do not edit - generated code.
+
+/**
+ * Model-Driven Views (MDV)'s native features enables a wide-range of use cases,
+ * but (by design) don't attempt to implement a wide array of specialized
+ * behaviors.
+ *
+ * Enabling these features in MDV is a matter of implementing and registering an
+ * MDV Custom Syntax. A Custom Syntax is an object which contains one or more
+ * delegation functions which implement specialized behavior. This object is
+ * registered with MDV via [TemplateElement.syntax]:
+ *
+ *
+ * HTML:
+ * <template bind syntax="MySyntax">
+ * {{ What!Ever('crazy')->thing^^^I+Want(data) }}
+ * </template>
+ *
+ * Dart:
+ * class MySyntax extends CustomBindingSyntax {
+ * getBinding(model, path, name, node) {
+ * // The magic happens here!
+ * }
+ * }
+ *
+ * ...
+ *
+ * TemplateElement.syntax['MySyntax'] = new MySyntax();
+ *
+ * See <https://github.com/polymer-project/mdv/blob/master/docs/syntax.md> for
+ * more information about Custom Syntax.
+ */
+// TODO(jmesserly): if this is just one method, a function type would make it
+// more Dart-friendly.
+@Experimental
+abstract class CustomBindingSyntax {
+ /**
+ * This syntax method allows for a custom interpretation of the contents of
+ * mustaches (`{{` ... `}}`).
+ *
+ * When a template is inserting an instance, it will invoke this method for
+ * each mustache which is encountered. The function is invoked with four
+ * arguments:
+ *
+ * - [model]: The data context for which this instance is being created.
+ * - [path]: The text contents (trimmed of outer whitespace) of the mustache.
+ * - [name]: The context in which the mustache occurs. Within element
+ * attributes, this will be the name of the attribute. Within text,
+ * this will be 'text'.
+ * - [node]: A reference to the node to which this binding will be created.
+ *
+ * If the method wishes to handle binding, it is required to return an object
+ * which has at least a `value` property that can be observed. If it does,
+ * then MDV will call [Node.bind on the node:
+ *
+ * node.bind(name, retval, 'value');
+ *
+ * If the 'getBinding' does not wish to override the binding, it should return
+ * null.
+ */
+ // TODO(jmesserly): I had to remove type annotations from "name" and "node"
+ // Normally they are String and Node respectively. But sometimes it will pass
+ // (int name, CompoundBinding node). That seems very confusing; we may want
+ // to change this API.
+ getBinding(model, String path, name, node) => null;
+
+ /**
+ * This syntax method allows a syntax to provide an alterate model than the
+ * one the template would otherwise use when producing an instance.
+ *
+ * When a template is about to create an instance, it will invoke this method
+ * The function is invoked with two arguments:
+ *
+ * - [template]: The template element which is about to create and insert an
+ * instance.
+ * - [model]: The data context for which this instance is being created.
+ *
+ * The template element will always use the return value of `getInstanceModel`
+ * as the model for the new instance. If the syntax does not wish to override
+ * the value, it should simply return the `model` value it was passed.
+ */
+ getInstanceModel(Element template, model) => model;
+
+ /**
+ * This syntax method allows a syntax to provide an alterate expansion of
+ * the [template] contents. When the template wants to create an instance,
+ * it will call this method with the template element.
+ *
+ * By default this will call `template.createInstance()`.
+ */
+ getInstanceFragment(Element template) => template.createInstance();
+}
+
+
@Experimental
@DomName('HTMLTemplateElement')
@SupportedBrowser(SupportedBrowser.CHROME)
@@ -21062,24 +20977,23 @@
@Experimental
DocumentFragment get content => $dom_content;
- static StreamController<DocumentFragment> _instanceCreated;
/**
- * *Warning*: This is an implementation helper for Model-Driven Views and
- * should not be used in your code.
+ * The MDV package, if available.
*
- * This event is fired whenever a template is instantiated via
- * [createInstance].
+ * This can be used to initialize MDV support via:
+ *
+ * import 'dart:html';
+ * import 'package:mdv/mdv.dart' as mdv;
+ * main() {
+ * mdv.initialize();
+ * }
*/
- // TODO(rafaelw): This is a hack, and is neccesary for the polyfill
- // because custom elements are not upgraded during clone()
- @Experimental
- static Stream<DocumentFragment> get instanceCreated {
- if (_instanceCreated == null) {
- _instanceCreated = new StreamController<DocumentFragment>(sync: true);
- }
- return _instanceCreated.stream;
- }
+ static Function mdvPackage = (node) {
+ throw new UnsupportedError("The MDV package is not available. "
+ "You can enable it with `import 'package:mdv/mdv.dart' as mdv;` and "
+ "`mdv.initialize()`");
+ };
/**
* Ensures proper API and content model for template elements.
@@ -21096,30 +21010,111 @@
// == true check because it starts as a null field.
if (template._templateIsDecorated == true) return false;
- template._templateIsDecorated = true;
-
_injectStylesheet();
- // Create content
- if (template is! TemplateElement) {
- var doc = _Bindings._getTemplateContentsOwner(template.document);
- template._templateContent = doc.createDocumentFragment();
+ var templateElement = template;
+ var isNative = templateElement is TemplateElement;
+ var bootstrapContents = isNative;
+ var liftContents = !isNative;
+ var liftRoot = false;
+
+ if (!isNative && templateElement._isAttributeTemplate) {
+ if (instanceRef != null) {
+ // TODO(jmesserly): this is just an assert in MDV.
+ throw new ArgumentError('instanceRef should not be supplied for '
+ 'attribute templates.');
+ }
+ templateElement = _extractTemplateFromAttributeTemplate(template);
+ isNative = templateElement is TemplateElement;
+ liftRoot = true;
+ }
+
+ templateElement._templateIsDecorated = true;
+
+ if (!isNative) {
+ var doc = _getTemplateContentsOwner(templateElement.document);
+ templateElement._templateContent = doc.createDocumentFragment();
}
if (instanceRef != null) {
- template._templateInstanceRef = instanceRef;
- return true; // content is empty.
- }
-
- if (template is TemplateElement) {
- bootstrap(template.content);
- } else {
- _Bindings._liftNonNativeChildrenIntoContent(template);
+ // template is contained within an instance, its direct content must be
+ // empty
+ templateElement._templateInstanceRef = instanceRef;
+ } else if (liftContents) {
+ _liftNonNativeChildrenIntoContent(templateElement, template, liftRoot);
+ } else if (bootstrapContents) {
+ bootstrap(templateElement.content);
}
return true;
}
+ // http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/templates/index.html#dfn-template-contents-owner
+ static Document _getTemplateContentsOwner(HtmlDocument doc) {
+ if (doc.window == null) {
+ return doc;
+ }
+ var d = doc._templateContentsOwner;
+ if (d == null) {
+ // TODO(arv): This should either be a Document or HTMLDocument depending
+ // on doc.
+ d = doc.implementation.createHtmlDocument('');
+ while (d.lastChild != null) {
+ d.lastChild.remove();
+ }
+ doc._templateContentsOwner = d;
+ }
+ return d;
+ }
+
+ // For non-template browsers, the parser will disallow <template> in certain
+ // locations, so we allow "attribute templates" which combine the template
+ // element with the top-level container node of the content, e.g.
+ //
+ // <tr template repeat="{{ foo }}"" class="bar"><td>Bar</td></tr>
+ //
+ // becomes
+ //
+ // <template repeat="{{ foo }}">
+ // + #document-fragment
+ // + <tr class="bar">
+ // + <td>Bar</td>
+ //
+ static Element _extractTemplateFromAttributeTemplate(Element el) {
+ var template = el.document.$dom_createElement('template');
+ el.parentNode.insertBefore(template, el);
+
+ for (var name in el.attributes.keys.toList()) {
+ switch (name) {
+ case 'template':
+ el.attributes.remove(name);
+ break;
+ case 'repeat':
+ case 'bind':
+ case 'ref':
+ template.attributes[name] = el.attributes.remove(name);
+ break;
+ }
+ }
+
+ return template;
+ }
+
+ static void _liftNonNativeChildrenIntoContent(Element template, Element el,
+ bool useRoot) {
+
+ var content = template.content;
+ if (useRoot) {
+ content.append(el);
+ return;
+ }
+
+ var child;
+ while ((child = el.firstChild) != null) {
+ content.append(child);
+ }
+ }
+
/**
* This used to decorate recursively all templates from a given node.
*
@@ -21130,24 +21125,26 @@
// TODO(rafaelw): Review whether this is the right public API.
@Experimental
static void bootstrap(Node content) {
- _Bindings._bootstrapTemplatesRecursivelyFrom(content);
+ void _bootstrap(template) {
+ if (!TemplateElement.decorate(template)) {
+ bootstrap(template.content);
+ }
+ }
+
+ // Need to do this first as the contents may get lifted if |node| is
+ // template.
+ // TODO(jmesserly): content is DocumentFragment or Element
+ var descendents = (content as dynamic).queryAll(_allTemplatesSelectors);
+ if (content is Element && (content as Element).isTemplate) {
+ _bootstrap(content);
+ }
+
+ descendents.forEach(_bootstrap);
}
- /**
- * Binds all mustaches recursively starting from the [root] node.
- *
- * Note: this is not an official Model-Driven-Views API; it is intended to
- * support binding the [ShadowRoot]'s content to a model.
- */
- // TODO(jmesserly): this is needed to avoid two <template> nodes when using
- // bindings in a custom element's template. See also:
- // https://github.com/polymer-project/polymer/blob/master/src/bindMDV.js#L68
- // Called from:
- // https://github.com/polymer-project/polymer/blob/master/src/register.js#L99
- @Experimental
- static void bindModel(Node root, model, [CustomBindingSyntax syntax]) {
- _Bindings._addBindings(root, model, syntax);
- }
+ static final String _allTemplatesSelectors =
+ 'template, option[template], optgroup[template], ' +
+ Element._TABLE_TAGS.keys.map((k) => "$k[template]").join(", ");
static bool _initStyles;
@@ -21205,42 +21202,6 @@
@DocsEditable
Text splitText(int offset) native;
-
- @Creates('Null') // Set from Dart code; does not instantiate a native type.
- StreamSubscription _textBinding;
-
- @Experimental
- void bind(String name, model, String path) {
- if (name != 'text') {
- super.bind(name, model, path);
- return;
- }
-
- unbind('text');
-
- _textBinding = new PathObserver(model, path).bindSync((value) {
- text = value == null ? '' : '$value';
- });
- }
-
- @Experimental
- void unbind(String name) {
- if (name != 'text') {
- super.unbind(name);
- return;
- }
-
- if (_textBinding == null) return;
-
- _textBinding.cancel();
- _textBinding = null;
- }
-
- @Experimental
- void unbindAll() {
- unbind('text');
- super.unbindAll();
- }
}
// 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
@@ -27706,794 +27667,6 @@
Point get bottomRight => new Point(this.left + this.width,
this.top + this.height);
}
-// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-
-// This code is a port of Model-Driven-Views:
-// https://github.com/polymer-project/mdv
-// The code mostly comes from src/template_element.js
-
-typedef void _ChangeHandler(value);
-
-/**
- * Model-Driven Views (MDV)'s native features enables a wide-range of use cases,
- * but (by design) don't attempt to implement a wide array of specialized
- * behaviors.
- *
- * Enabling these features in MDV is a matter of implementing and registering an
- * MDV Custom Syntax. A Custom Syntax is an object which contains one or more
- * delegation functions which implement specialized behavior. This object is
- * registered with MDV via [TemplateElement.syntax]:
- *
- *
- * HTML:
- * <template bind syntax="MySyntax">
- * {{ What!Ever('crazy')->thing^^^I+Want(data) }}
- * </template>
- *
- * Dart:
- * class MySyntax extends CustomBindingSyntax {
- * getBinding(model, path, name, node) {
- * // The magic happens here!
- * }
- * }
- *
- * ...
- *
- * TemplateElement.syntax['MySyntax'] = new MySyntax();
- *
- * See <https://github.com/polymer-project/mdv/blob/master/docs/syntax.md> for more
- * information about Custom Syntax.
- */
-// TODO(jmesserly): if this is just one method, a function type would make it
-// more Dart-friendly.
-@Experimental
-abstract class CustomBindingSyntax {
- /**
- * This syntax method allows for a custom interpretation of the contents of
- * mustaches (`{{` ... `}}`).
- *
- * When a template is inserting an instance, it will invoke this method for
- * each mustache which is encountered. The function is invoked with four
- * arguments:
- *
- * - [model]: The data context for which this instance is being created.
- * - [path]: The text contents (trimmed of outer whitespace) of the mustache.
- * - [name]: The context in which the mustache occurs. Within element
- * attributes, this will be the name of the attribute. Within text,
- * this will be 'text'.
- * - [node]: A reference to the node to which this binding will be created.
- *
- * If the method wishes to handle binding, it is required to return an object
- * which has at least a `value` property that can be observed. If it does,
- * then MDV will call [Node.bind on the node:
- *
- * node.bind(name, retval, 'value');
- *
- * If the 'getBinding' does not wish to override the binding, it should return
- * null.
- */
- // TODO(jmesserly): I had to remove type annotations from "name" and "node"
- // Normally they are String and Node respectively. But sometimes it will pass
- // (int name, CompoundBinding node). That seems very confusing; we may want
- // to change this API.
- getBinding(model, String path, name, node) => null;
-
- /**
- * This syntax method allows a syntax to provide an alterate model than the
- * one the template would otherwise use when producing an instance.
- *
- * When a template is about to create an instance, it will invoke this method
- * The function is invoked with two arguments:
- *
- * - [template]: The template element which is about to create and insert an
- * instance.
- * - [model]: The data context for which this instance is being created.
- *
- * The template element will always use the return value of `getInstanceModel`
- * as the model for the new instance. If the syntax does not wish to override
- * the value, it should simply return the `model` value it was passed.
- */
- getInstanceModel(Element template, model) => model;
-
- /**
- * This syntax method allows a syntax to provide an alterate expansion of
- * the [template] contents. When the template wants to create an instance,
- * it will call this method with the template element.
- *
- * By default this will call `template.createInstance()`.
- */
- getInstanceFragment(Element template) => template.createInstance();
-}
-
-/** The callback used in the [CompoundBinding.combinator] field. */
-@Experimental
-typedef Object CompoundBindingCombinator(Map objects);
-
-/** Information about the instantiated template. */
-@Experimental
-class TemplateInstance {
- // TODO(rafaelw): firstNode & lastNode should be read-synchronous
- // in cases where script has modified the template instance boundary.
-
- /** The first node of this template instantiation. */
- final Node firstNode;
-
- /**
- * The last node of this template instantiation.
- * This could be identical to [firstNode] if the template only expanded to a
- * single node.
- */
- final Node lastNode;
-
- /** The model used to instantiate the template. */
- final model;
-
- TemplateInstance(this.firstNode, this.lastNode, this.model);
-}
-
-/**
- * Model-Driven Views contains a helper object which is useful for the
- * implementation of a Custom Syntax.
- *
- * var binding = new CompoundBinding((values) {
- * var combinedValue;
- * // compute combinedValue based on the current values which are provided
- * return combinedValue;
- * });
- * binding.bind('name1', obj1, path1);
- * binding.bind('name2', obj2, path2);
- * //...
- * binding.bind('nameN', objN, pathN);
- *
- * CompoundBinding is an object which knows how to listen to multiple path
- * values (registered via [bind]) and invoke its [combinator] when one or more
- * of the values have changed and set its [value] property to the return value
- * of the function. When any value has changed, all current values are provided
- * to the [combinator] in the single `values` argument.
- *
- * See [CustomBindingSyntax] for more information.
- */
-// TODO(jmesserly): what is the public API surface here? I just guessed;
-// most of it seemed non-public.
-@Experimental
-class CompoundBinding extends ObservableBase {
- CompoundBindingCombinator _combinator;
-
- // TODO(jmesserly): ideally these would be String keys, but sometimes we
- // use integers.
- Map<dynamic, StreamSubscription> _bindings = new Map();
- Map _values = new Map();
- bool _scheduled = false;
- bool _disposed = false;
- Object _value;
-
- CompoundBinding([CompoundBindingCombinator combinator]) {
- // TODO(jmesserly): this is a tweak to the original code, it seemed to me
- // that passing the combinator to the constructor should be equivalent to
- // setting it via the property.
- // I also added a null check to the combinator setter.
- this.combinator = combinator;
- }
-
- CompoundBindingCombinator get combinator => _combinator;
-
- set combinator(CompoundBindingCombinator combinator) {
- _combinator = combinator;
- if (combinator != null) _scheduleResolve();
- }
-
- static const _VALUE = const Symbol('value');
-
- get value => _value;
-
- void set value(newValue) {
- _value = notifyPropertyChange(_VALUE, _value, newValue);
- }
-
- // TODO(jmesserly): remove these workarounds when dart2js supports mirrors!
- getValueWorkaround(key) {
- if (key == _VALUE) return value;
- return null;
- }
- setValueWorkaround(key, val) {
- if (key == _VALUE) value = val;
- }
-
- void bind(name, model, String path) {
- unbind(name);
-
- _bindings[name] = new PathObserver(model, path).bindSync((value) {
- _values[name] = value;
- _scheduleResolve();
- });
- }
-
- void unbind(name, {bool suppressResolve: false}) {
- var binding = _bindings.remove(name);
- if (binding == null) return;
-
- binding.cancel();
- _values.remove(name);
- if (!suppressResolve) _scheduleResolve();
- }
-
- // TODO(rafaelw): Is this the right processing model?
- // TODO(rafaelw): Consider having a seperate ChangeSummary for
- // CompoundBindings so to excess dirtyChecks.
- void _scheduleResolve() {
- if (_scheduled) return;
- _scheduled = true;
- queueChangeRecords(resolve);
- }
-
- void resolve() {
- if (_disposed) return;
- _scheduled = false;
-
- if (_combinator == null) {
- throw new StateError(
- 'CompoundBinding attempted to resolve without a combinator');
- }
-
- value = _combinator(_values);
- }
-
- void dispose() {
- for (var binding in _bindings.values) {
- binding.cancel();
- }
- _bindings.clear();
- _values.clear();
-
- _disposed = true;
- value = null;
- }
-}
-
-abstract class _InputBinding {
- final InputElement element;
- PathObserver binding;
- StreamSubscription _pathSub;
- StreamSubscription _eventSub;
-
- _InputBinding(this.element, model, String path) {
- binding = new PathObserver(model, path);
- _pathSub = binding.bindSync(valueChanged);
- _eventSub = _getStreamForInputType(element).listen(updateBinding);
- }
-
- void valueChanged(newValue);
-
- void updateBinding(e);
-
- void unbind() {
- binding = null;
- _pathSub.cancel();
- _eventSub.cancel();
- }
-
-
- static Stream<Event> _getStreamForInputType(InputElement element) {
- switch (element.type) {
- case 'checkbox':
- return element.onClick;
- case 'radio':
- case 'select-multiple':
- case 'select-one':
- return element.onChange;
- default:
- return element.onInput;
- }
- }
-}
-
-class _ValueBinding extends _InputBinding {
- _ValueBinding(element, model, path) : super(element, model, path);
-
- void valueChanged(value) {
- element.value = value == null ? '' : '$value';
- }
-
- void updateBinding(e) {
- binding.value = element.value;
- }
-}
-
-class _CheckedBinding extends _InputBinding {
- _CheckedBinding(element, model, path) : super(element, model, path);
-
- void valueChanged(value) {
- element.checked = _Bindings._toBoolean(value);
- }
-
- void updateBinding(e) {
- binding.value = element.checked;
-
- // Only the radio button that is getting checked gets an event. We
- // therefore find all the associated radio buttons and update their
- // CheckedBinding manually.
- if (element is InputElement && element.type == 'radio') {
- for (var r in _getAssociatedRadioButtons(element)) {
- var checkedBinding = r._checkedBinding;
- if (checkedBinding != null) {
- // Set the value directly to avoid an infinite call stack.
- checkedBinding.binding.value = false;
- }
- }
- }
- }
-
- // |element| is assumed to be an HTMLInputElement with |type| == 'radio'.
- // Returns an array containing all radio buttons other than |element| that
- // have the same |name|, either in the form that |element| belongs to or,
- // if no form, in the document tree to which |element| belongs.
- //
- // This implementation is based upon the HTML spec definition of a
- // "radio button group":
- // http://www.whatwg.org/specs/web-apps/current-work/multipage/number-state.html#radio-button-group
- //
- static Iterable _getAssociatedRadioButtons(element) {
- if (!_isNodeInDocument(element)) return [];
- if (element.form != null) {
- return element.form.nodes.where((el) {
- return el != element &&
- el is InputElement &&
- el.type == 'radio' &&
- el.name == element.name;
- });
- } else {
- var radios = element.document.queryAll(
- 'input[type="radio"][name="${element.name}"]');
- return radios.where((el) => el != element && el.form == null);
- }
- }
-
- // TODO(jmesserly): polyfill document.contains API instead of doing it here
- static bool _isNodeInDocument(Node node) {
- // On non-IE this works:
- // return node.document.contains(node);
- var document = node.document;
- if (node == document || node.parentNode == document) return true;
- return document.documentElement.contains(node);
- }
-}
-
-class _Bindings {
- // TODO(jmesserly): not sure what kind of boolean conversion rules to
- // apply for template data-binding. HTML attributes are true if they're
- // present. However Dart only treats "true" as true. Since this is HTML we'll
- // use something closer to the HTML rules: null (missing) and false are false,
- // everything else is true. See: https://github.com/polymer-project/mdv/issues/59
- static bool _toBoolean(value) => null != value && false != value;
-
- static Node _createDeepCloneAndDecorateTemplates(Node node, String syntax) {
- var clone = node.clone(false); // Shallow clone.
- if (clone is Element && clone.isTemplate) {
- TemplateElement.decorate(clone, node);
- if (syntax != null) {
- clone.attributes.putIfAbsent('syntax', () => syntax);
- }
- }
-
- for (var c = node.$dom_firstChild; c != null; c = c.nextNode) {
- clone.append(_createDeepCloneAndDecorateTemplates(c, syntax));
- }
- return clone;
- }
-
- // http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/templates/index.html#dfn-template-contents-owner
- static Document _getTemplateContentsOwner(HtmlDocument doc) {
- if (doc.window == null) {
- return doc;
- }
- var d = doc._templateContentsOwner;
- if (d == null) {
- // TODO(arv): This should either be a Document or HTMLDocument depending
- // on doc.
- d = doc.implementation.createHtmlDocument('');
- while (d.$dom_lastChild != null) {
- d.$dom_lastChild.remove();
- }
- doc._templateContentsOwner = d;
- }
- return d;
- }
-
- static Element _cloneAndSeperateAttributeTemplate(Element templateElement) {
- var clone = templateElement.clone(false);
- var attributes = templateElement.attributes;
- for (var name in attributes.keys.toList()) {
- switch (name) {
- case 'template':
- case 'repeat':
- case 'bind':
- case 'ref':
- clone.attributes.remove(name);
- break;
- default:
- attributes.remove(name);
- break;
- }
- }
-
- return clone;
- }
-
- static void _liftNonNativeChildrenIntoContent(Element templateElement) {
- var content = templateElement.content;
-
- if (!templateElement._isAttributeTemplate) {
- var child;
- while ((child = templateElement.$dom_firstChild) != null) {
- content.append(child);
- }
- return;
- }
-
- // For attribute templates we copy the whole thing into the content and
- // we move the non template attributes into the content.
- //
- // <tr foo template>
- //
- // becomes
- //
- // <tr template>
- // + #document-fragment
- // + <tr foo>
- //
- var newRoot = _cloneAndSeperateAttributeTemplate(templateElement);
- var child;
- while ((child = templateElement.$dom_firstChild) != null) {
- newRoot.append(child);
- }
- content.append(newRoot);
- }
-
- static void _bootstrapTemplatesRecursivelyFrom(Node node) {
- void bootstrap(template) {
- if (!TemplateElement.decorate(template)) {
- _bootstrapTemplatesRecursivelyFrom(template.content);
- }
- }
-
- // Need to do this first as the contents may get lifted if |node| is
- // template.
- // TODO(jmesserly): node is DocumentFragment or Element
- var descendents = (node as dynamic).queryAll(_allTemplatesSelectors);
- if (node is Element && (node as Element).isTemplate) bootstrap(node);
-
- descendents.forEach(bootstrap);
- }
-
- static final String _allTemplatesSelectors = 'template, option[template], ' +
- Element._TABLE_TAGS.keys.map((k) => "$k[template]").join(", ");
-
- static void _addBindings(Node node, model, [CustomBindingSyntax syntax]) {
- if (node is Element) {
- _addAttributeBindings(node, model, syntax);
- } else if (node is Text) {
- _parseAndBind(node, 'text', node.text, model, syntax);
- }
-
- for (var c = node.$dom_firstChild; c != null; c = c.nextNode) {
- _addBindings(c, model, syntax);
- }
- }
-
- static void _addAttributeBindings(Element element, model, syntax) {
- element.attributes.forEach((name, value) {
- if (value == '' && (name == 'bind' || name == 'repeat')) {
- value = '{{}}';
- }
- _parseAndBind(element, name, value, model, syntax);
- });
- }
-
- static void _parseAndBind(Node node, String name, String text, model,
- CustomBindingSyntax syntax) {
-
- var tokens = _parseMustacheTokens(text);
- if (tokens.length == 0 || (tokens.length == 1 && tokens[0].isText)) {
- return;
- }
-
- // If this is a custom element, give the .xtag a change to bind.
- node = _nodeOrCustom(node);
-
- if (tokens.length == 1 && tokens[0].isBinding) {
- _bindOrDelegate(node, name, model, tokens[0].value, syntax);
- return;
- }
-
- var replacementBinding = new CompoundBinding();
- for (var i = 0; i < tokens.length; i++) {
- var token = tokens[i];
- if (token.isBinding) {
- _bindOrDelegate(replacementBinding, i, model, token.value, syntax);
- }
- }
-
- replacementBinding.combinator = (values) {
- var newValue = new StringBuffer();
-
- for (var i = 0; i < tokens.length; i++) {
- var token = tokens[i];
- if (token.isText) {
- newValue.write(token.value);
- } else {
- var value = values[i];
- if (value != null) {
- newValue.write(value);
- }
- }
- }
-
- return newValue.toString();
- };
-
- node.bind(name, replacementBinding, 'value');
- }
-
- static void _bindOrDelegate(node, name, model, String path,
- CustomBindingSyntax syntax) {
-
- if (syntax != null) {
- var delegateBinding = syntax.getBinding(model, path, name, node);
- if (delegateBinding != null) {
- model = delegateBinding;
- path = 'value';
- }
- }
-
- node.bind(name, model, path);
- }
-
- /**
- * Gets the [node]'s custom [Element.xtag] if present, otherwise returns
- * the node. This is used so nodes can override [Node.bind], [Node.unbind],
- * and [Node.unbindAll] like InputElement does.
- */
- // TODO(jmesserly): remove this when we can extend Element for real.
- static _nodeOrCustom(node) => node is Element ? node.xtag : node;
-
- static List<_BindingToken> _parseMustacheTokens(String s) {
- var result = [];
- var length = s.length;
- var index = 0, lastIndex = 0;
- while (lastIndex < length) {
- index = s.indexOf('{{', lastIndex);
- if (index < 0) {
- result.add(new _BindingToken(s.substring(lastIndex)));
- break;
- } else {
- // There is a non-empty text run before the next path token.
- if (index > 0 && lastIndex < index) {
- result.add(new _BindingToken(s.substring(lastIndex, index)));
- }
- lastIndex = index + 2;
- index = s.indexOf('}}', lastIndex);
- if (index < 0) {
- var text = s.substring(lastIndex - 2);
- if (result.length > 0 && result.last.isText) {
- result.last.value += text;
- } else {
- result.add(new _BindingToken(text));
- }
- break;
- }
-
- var value = s.substring(lastIndex, index).trim();
- result.add(new _BindingToken(value, isBinding: true));
- lastIndex = index + 2;
- }
- }
- return result;
- }
-
- static void _addTemplateInstanceRecord(fragment, model) {
- if (fragment.$dom_firstChild == null) {
- return;
- }
-
- var instanceRecord = new TemplateInstance(
- fragment.$dom_firstChild, fragment.$dom_lastChild, model);
-
- var node = instanceRecord.firstNode;
- while (node != null) {
- node._templateInstance = instanceRecord;
- node = node.nextNode;
- }
- }
-
- static void _removeAllBindingsRecursively(Node node) {
- _nodeOrCustom(node).unbindAll();
- for (var c = node.$dom_firstChild; c != null; c = c.nextNode) {
- _removeAllBindingsRecursively(c);
- }
- }
-
- static void _removeChild(Node parent, Node child) {
- child._templateInstance = null;
- if (child is Element && (child as Element).isTemplate) {
- Element childElement = child;
- // Make sure we stop observing when we remove an element.
- var templateIterator = childElement._templateIterator;
- if (templateIterator != null) {
- templateIterator.abandon();
- childElement._templateIterator = null;
- }
- }
- child.remove();
- _removeAllBindingsRecursively(child);
- }
-}
-
-class _BindingToken {
- final String value;
- final bool isBinding;
-
- _BindingToken(this.value, {this.isBinding: false});
-
- bool get isText => !isBinding;
-}
-
-class _TemplateIterator {
- final Element _templateElement;
- final List<Node> terminators = [];
- final CompoundBinding inputs;
- List iteratedValue;
-
- StreamSubscription _sub;
- StreamSubscription _valueBinding;
-
- _TemplateIterator(this._templateElement)
- : inputs = new CompoundBinding(resolveInputs) {
-
- _valueBinding = new PathObserver(inputs, 'value').bindSync(valueChanged);
- }
-
- static Object resolveInputs(Map values) {
- if (values.containsKey('if') && !_Bindings._toBoolean(values['if'])) {
- return null;
- }
-
- if (values.containsKey('repeat')) {
- return values['repeat'];
- }
-
- if (values.containsKey('bind')) {
- return [values['bind']];
- }
-
- return null;
- }
-
- void valueChanged(value) {
- clear();
- if (value is! List) return;
-
- iteratedValue = value;
-
- if (value is Observable) {
- _sub = value.changes.listen(_handleChanges);
- }
-
- int len = iteratedValue.length;
- if (len > 0) {
- _handleChanges([new ListChangeRecord(0, addedCount: len)]);
- }
- }
-
- Node getTerminatorAt(int index) {
- if (index == -1) return _templateElement;
- var terminator = terminators[index];
- if (terminator is! Element) return terminator;
-
- var subIterator = terminator._templateIterator;
- if (subIterator == null) return terminator;
-
- return subIterator.getTerminatorAt(subIterator.terminators.length - 1);
- }
-
- void insertInstanceAt(int index, Node fragment) {
- var previousTerminator = getTerminatorAt(index - 1);
- var terminator = fragment.$dom_lastChild;
- if (terminator == null) terminator = previousTerminator;
-
- terminators.insert(index, terminator);
- var parent = _templateElement.parentNode;
- parent.insertBefore(fragment, previousTerminator.nextNode);
- }
-
- void removeInstanceAt(int index) {
- var previousTerminator = getTerminatorAt(index - 1);
- var terminator = getTerminatorAt(index);
- terminators.removeAt(index);
-
- var parent = _templateElement.parentNode;
- while (terminator != previousTerminator) {
- var node = terminator;
- terminator = node.previousNode;
- _Bindings._removeChild(parent, node);
- }
- }
-
- void removeAllInstances() {
- if (terminators.length == 0) return;
-
- var previousTerminator = _templateElement;
- var terminator = getTerminatorAt(terminators.length - 1);
- terminators.length = 0;
-
- var parent = _templateElement.parentNode;
- while (terminator != previousTerminator) {
- var node = terminator;
- terminator = node.previousNode;
- _Bindings._removeChild(parent, node);
- }
- }
-
- void clear() {
- unobserve();
- removeAllInstances();
- iteratedValue = null;
- }
-
- getInstanceModel(model, syntax) {
- if (syntax != null) {
- return syntax.getInstanceModel(_templateElement, model);
- }
- return model;
- }
-
- getInstanceFragment(syntax) {
- if (syntax != null) {
- return syntax.getInstanceFragment(_templateElement);
- }
- return _templateElement.createInstance();
- }
-
- void _handleChanges(List<ListChangeRecord> splices) {
- var syntax = TemplateElement.syntax[_templateElement.attributes['syntax']];
-
- for (var splice in splices) {
- if (splice is! ListChangeRecord) continue;
-
- for (int i = 0; i < splice.removedCount; i++) {
- removeInstanceAt(splice.index);
- }
-
- for (var addIndex = splice.index;
- addIndex < splice.index + splice.addedCount;
- addIndex++) {
-
- var model = getInstanceModel(iteratedValue[addIndex], syntax);
-
- var fragment = getInstanceFragment(syntax);
-
- _Bindings._addBindings(fragment, model, syntax);
- _Bindings._addTemplateInstanceRecord(fragment, model);
-
- insertInstanceAt(addIndex, fragment);
- }
- }
- }
-
- void unobserve() {
- if (_sub == null) return;
- _sub.cancel();
- _sub = null;
- }
-
- void abandon() {
- unobserve();
- _valueBinding.cancel();
- inputs.dispose();
- }
-}
// 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.
diff --git a/sdk/lib/html/dartium/html_dartium.dart b/sdk/lib/html/dartium/html_dartium.dart
index 0e28ef6..c31f588 100644
--- a/sdk/lib/html/dartium/html_dartium.dart
+++ b/sdk/lib/html/dartium/html_dartium.dart
@@ -14,7 +14,6 @@
import 'dart:json' as json;
import 'dart:math';
import 'dart:nativewrappers';
-import 'dart:mdv_observe_impl';
import 'dart:typed_data';
import 'dart:web_gl' as gl;
import 'dart:web_sql';
@@ -8698,18 +8697,6 @@
}
- Map<String, StreamSubscription> _attributeBindings;
-
- // TODO(jmesserly): I'm concerned about adding these to every element.
- // Conceptually all of these belong on TemplateElement. They are here to
- // support browsers that don't have <template> yet.
- // However even in the polyfill they're restricted to certain tags
- // (see [isTemplate]). So we can probably convert it to a (public) mixin, and
- // only mix it in to the elements that need it.
- var _model;
-
- _TemplateIterator _templateIterator;
-
Element _templateInstanceRef;
// Note: only used if `this is! TemplateElement`
@@ -8717,124 +8704,6 @@
bool _templateIsDecorated;
- // TODO(jmesserly): should path be optional, and default to empty path?
- // It is used that way in at least one path in JS TemplateElement tests
- // (see "BindImperative" test in original JS code).
- @Experimental
- void bind(String name, model, String path) {
- _bindElement(this, name, model, path);
- }
-
- // TODO(jmesserly): this is static to work around http://dartbug.com/10166
- // Similar issue for unbind/unbindAll below.
- static void _bindElement(Element self, String name, model, String path) {
- if (self._bindTemplate(name, model, path)) return;
-
- if (self._attributeBindings == null) {
- self._attributeBindings = new Map<String, StreamSubscription>();
- }
-
- self.xtag.attributes.remove(name);
-
- var changed;
- if (name.endsWith('?')) {
- name = name.substring(0, name.length - 1);
-
- changed = (value) {
- if (_Bindings._toBoolean(value)) {
- self.xtag.attributes[name] = '';
- } else {
- self.xtag.attributes.remove(name);
- }
- };
- } else {
- changed = (value) {
- // TODO(jmesserly): escape value if needed to protect against XSS.
- // See https://github.com/polymer-project/mdv/issues/58
- self.xtag.attributes[name] = value == null ? '' : '$value';
- };
- }
-
- self.unbind(name);
-
- self._attributeBindings[name] =
- new PathObserver(model, path).bindSync(changed);
- }
-
- @Experimental
- void unbind(String name) {
- _unbindElement(this, name);
- }
-
- static _unbindElement(Element self, String name) {
- if (self._unbindTemplate(name)) return;
- if (self._attributeBindings != null) {
- var binding = self._attributeBindings.remove(name);
- if (binding != null) binding.cancel();
- }
- }
-
- @Experimental
- void unbindAll() {
- _unbindAllElement(this);
- }
-
- static void _unbindAllElement(Element self) {
- self._unbindAllTemplate();
-
- if (self._attributeBindings != null) {
- for (var binding in self._attributeBindings.values) {
- binding.cancel();
- }
- self._attributeBindings = null;
- }
- }
-
- // TODO(jmesserly): unlike the JS polyfill, we can't mixin
- // HTMLTemplateElement at runtime into things that are semantically template
- // elements. So instead we implement it here with a runtime check.
- // If the bind succeeds, we return true, otherwise we return false and let
- // the normal Element.bind logic kick in.
- bool _bindTemplate(String name, model, String path) {
- if (isTemplate) {
- switch (name) {
- case 'bind':
- case 'repeat':
- case 'if':
- _ensureTemplate();
- if (_templateIterator == null) {
- _templateIterator = new _TemplateIterator(this);
- }
- _templateIterator.inputs.bind(name, model, path);
- return true;
- }
- }
- return false;
- }
-
- bool _unbindTemplate(String name) {
- if (isTemplate) {
- switch (name) {
- case 'bind':
- case 'repeat':
- case 'if':
- _ensureTemplate();
- if (_templateIterator != null) {
- _templateIterator.inputs.unbind(name);
- }
- return true;
- }
- }
- return false;
- }
-
- void _unbindAllTemplate() {
- if (isTemplate) {
- unbind('bind');
- unbind('repeat');
- unbind('if');
- }
- }
/**
* Gets the template this node refers to.
@@ -8847,7 +8716,19 @@
Element ref = null;
var refId = attributes['ref'];
if (refId != null) {
- ref = document.getElementById(refId);
+ var treeScope = this;
+ while (treeScope.parentNode != null) {
+ treeScope = treeScope.parentNode;
+ }
+
+ // Note: JS code tests that getElementById is present. We can't do that
+ // easily, so instead check for the types known to implement it.
+ if (treeScope is Document ||
+ treeScope is ShadowRoot ||
+ treeScope is svg.SvgSvgElement) {
+
+ ref = treeScope.getElementById(refId);
+ }
}
return ref != null ? ref : _templateInstanceRef;
@@ -8870,38 +8751,20 @@
@Experimental
DocumentFragment createInstance() {
_ensureTemplate();
-
- var template = ref;
- if (template == null) template = this;
-
- var instance = _Bindings._createDeepCloneAndDecorateTemplates(
- template.content, attributes['syntax']);
-
- if (TemplateElement._instanceCreated != null) {
- TemplateElement._instanceCreated.add(instance);
- }
- return instance;
+ return TemplateElement.mdvPackage(this).createInstance();
}
/**
* The data model which is inherited through the tree.
* This is only supported if [isTemplate] is true.
- *
- * Setting this will destructive propagate the value to all descendant nodes,
- * and reinstantiate all of the nodes expanded by this template.
- *
- * Currently this does not support propagation through Shadow DOMs.
*/
@Experimental
- get model => _model;
+ get model => TemplateElement.mdvPackage(this).model;
@Experimental
void set model(value) {
_ensureTemplate();
-
- var syntax = TemplateElement.syntax[attributes['syntax']];
- _model = value;
- _Bindings._addBindings(this, model, syntax);
+ TemplateElement.mdvPackage(this).model = value;
}
// TODO(jmesserly): const set would be better
@@ -8918,7 +8781,8 @@
};
bool get _isAttributeTemplate => attributes.containsKey('template') &&
- (localName == 'option' || _TABLE_TAGS.containsKey(localName));
+ (localName == 'option' || localName == 'optgroup' ||
+ _TABLE_TAGS.containsKey(localName));
/**
* Returns true if this node is a template.
@@ -8927,7 +8791,7 @@
* 'template' attribute and this tag supports attribute form for backwards
* compatibility with existing HTML parsers. The nodes that can use attribute
* form are table elments (THEAD, TBODY, TFOOT, TH, TR, TD, CAPTION, COLGROUP
- * and COL) and OPTION.
+ * and COL), OPTION, and OPTGROUP.
*/
// TODO(jmesserly): this is not a public MDV API, but it seems like a useful
// place to document which tags our polyfill considers to be templates.
@@ -13170,59 +13034,6 @@
return e;
}
- _ValueBinding _valueBinding;
-
- _CheckedBinding _checkedBinding;
-
- @Experimental
- void bind(String name, model, String path) {
- switch (name) {
- case 'value':
- unbind('value');
- attributes.remove('value');
- _valueBinding = new _ValueBinding(this, model, path);
- break;
- case 'checked':
- unbind('checked');
- attributes.remove('checked');
- _checkedBinding = new _CheckedBinding(this, model, path);
- break;
- default:
- // TODO(jmesserly): this should be "super" (http://dartbug.com/10166).
- // Similar issue for unbind/unbindAll below.
- Element._bindElement(this, name, model, path);
- break;
- }
- }
-
- @Experimental
- void unbind(String name) {
- switch (name) {
- case 'value':
- if (_valueBinding != null) {
- _valueBinding.unbind();
- _valueBinding = null;
- }
- break;
- case 'checked':
- if (_checkedBinding != null) {
- _checkedBinding.unbind();
- _checkedBinding = null;
- }
- break;
- default:
- Element._unbindElement(this, name);
- break;
- }
- }
-
- @Experimental
- void unbindAll() {
- unbind('value');
- unbind('checked');
- Element._unbindAllElement(this);
- }
-
InputElement.internal() : super.internal();
@DomName('HTMLInputElement.webkitSpeechChangeEvent')
@@ -17527,12 +17338,12 @@
Node get first {
- Node result = _this.$dom_firstChild;
+ Node result = _this.firstChild;
if (result == null) throw new StateError("No elements");
return result;
}
Node get last {
- Node result = _this.$dom_lastChild;
+ Node result = _this.lastChild;
if (result == null) throw new StateError("No elements");
return result;
}
@@ -17540,7 +17351,7 @@
int l = this.length;
if (l == 0) throw new StateError("No elements");
if (l > 1) throw new StateError("More than one element");
- return _this.$dom_firstChild;
+ return _this.firstChild;
}
void add(Node value) {
@@ -17553,8 +17364,7 @@
if (!identical(otherList._this, _this)) {
// Optimized route for copying between nodes.
for (var i = 0, len = otherList.length; i < len; ++i) {
- // Should use $dom_firstChild, Bug 8886.
- _this.append(otherList[0]);
+ _this.append(otherList._this.firstChild);
}
}
return;
@@ -17612,7 +17422,7 @@
// This implementation of removeWhere/retainWhere is more efficient
// than the default in ListBase. Child nodes can be removed in constant
// time.
- Node child = _this.$dom_firstChild;
+ Node child = _this.firstChild;
while (child != null) {
Node nextChild = child.nextNode;
if (test(child) == removeMatching) {
@@ -17671,6 +17481,27 @@
Node operator[](int index) => _this.$dom_childNodes[index];
}
+/** Information about the instantiated template. */
+class TemplateInstance {
+ // TODO(rafaelw): firstNode & lastNode should be read-synchronous
+ // in cases where script has modified the template instance boundary.
+
+ /** The first node of this template instantiation. */
+ final Node firstNode;
+
+ /**
+ * The last node of this template instantiation.
+ * This could be identical to [firstNode] if the template only expanded to a
+ * single node.
+ */
+ final Node lastNode;
+
+ /** The model used to instantiate the template. */
+ final model;
+
+ TemplateInstance(this.firstNode, this.lastNode, this.model);
+}
+
@DomName('Node')
class Node extends EventTarget {
List<Node> get nodes {
@@ -17730,8 +17561,7 @@
// Optimized route for copying between nodes.
for (var i = 0, len = otherList.length; i < len; ++i) {
- // Should use $dom_firstChild, Bug 8886.
- this.insertBefore(otherList[0], refChild);
+ this.insertBefore(otherList._this.firstChild, refChild);
}
} else {
for (var node in newNodes) {
@@ -17751,26 +17581,25 @@
*/
@Experimental
void bind(String name, model, String path) {
- // TODO(jmesserly): should we throw instead?
- window.console.error('Unhandled binding to Node: '
- '$this $name $model $path');
+ TemplateElement.mdvPackage(this).bind(name, model, path);
}
/** Unbinds the attribute [name]. */
@Experimental
- void unbind(String name) {}
+ void unbind(String name) {
+ TemplateElement.mdvPackage(this).unbind(name);
+ }
/** Unbinds all bound attributes. */
@Experimental
- void unbindAll() {}
-
- TemplateInstance _templateInstance;
+ void unbindAll() {
+ TemplateElement.mdvPackage(this).unbindAll();
+ }
/** Gets the template instance that instantiated this node, if any. */
@Experimental
TemplateInstance get templateInstance =>
- _templateInstance != null ? _templateInstance :
- (parent != null ? parent.templateInstance : null);
+ TemplateElement.mdvPackage(this).templateInstance;
Node.internal() : super.internal();
@@ -17828,11 +17657,11 @@
@DomName('Node.firstChild')
@DocsEditable
- Node get $dom_firstChild native "Node_firstChild_Getter";
+ Node get firstChild native "Node_firstChild_Getter";
@DomName('Node.lastChild')
@DocsEditable
- Node get $dom_lastChild native "Node_lastChild_Getter";
+ Node get lastChild native "Node_lastChild_Getter";
@DomName('Node.localName')
@DocsEditable
@@ -22727,6 +22556,99 @@
// WARNING: Do not edit - generated code.
+
+/**
+ * Model-Driven Views (MDV)'s native features enables a wide-range of use cases,
+ * but (by design) don't attempt to implement a wide array of specialized
+ * behaviors.
+ *
+ * Enabling these features in MDV is a matter of implementing and registering an
+ * MDV Custom Syntax. A Custom Syntax is an object which contains one or more
+ * delegation functions which implement specialized behavior. This object is
+ * registered with MDV via [TemplateElement.syntax]:
+ *
+ *
+ * HTML:
+ * <template bind syntax="MySyntax">
+ * {{ What!Ever('crazy')->thing^^^I+Want(data) }}
+ * </template>
+ *
+ * Dart:
+ * class MySyntax extends CustomBindingSyntax {
+ * getBinding(model, path, name, node) {
+ * // The magic happens here!
+ * }
+ * }
+ *
+ * ...
+ *
+ * TemplateElement.syntax['MySyntax'] = new MySyntax();
+ *
+ * See <https://github.com/polymer-project/mdv/blob/master/docs/syntax.md> for
+ * more information about Custom Syntax.
+ */
+// TODO(jmesserly): if this is just one method, a function type would make it
+// more Dart-friendly.
+@Experimental
+abstract class CustomBindingSyntax {
+ /**
+ * This syntax method allows for a custom interpretation of the contents of
+ * mustaches (`{{` ... `}}`).
+ *
+ * When a template is inserting an instance, it will invoke this method for
+ * each mustache which is encountered. The function is invoked with four
+ * arguments:
+ *
+ * - [model]: The data context for which this instance is being created.
+ * - [path]: The text contents (trimmed of outer whitespace) of the mustache.
+ * - [name]: The context in which the mustache occurs. Within element
+ * attributes, this will be the name of the attribute. Within text,
+ * this will be 'text'.
+ * - [node]: A reference to the node to which this binding will be created.
+ *
+ * If the method wishes to handle binding, it is required to return an object
+ * which has at least a `value` property that can be observed. If it does,
+ * then MDV will call [Node.bind on the node:
+ *
+ * node.bind(name, retval, 'value');
+ *
+ * If the 'getBinding' does not wish to override the binding, it should return
+ * null.
+ */
+ // TODO(jmesserly): I had to remove type annotations from "name" and "node"
+ // Normally they are String and Node respectively. But sometimes it will pass
+ // (int name, CompoundBinding node). That seems very confusing; we may want
+ // to change this API.
+ getBinding(model, String path, name, node) => null;
+
+ /**
+ * This syntax method allows a syntax to provide an alterate model than the
+ * one the template would otherwise use when producing an instance.
+ *
+ * When a template is about to create an instance, it will invoke this method
+ * The function is invoked with two arguments:
+ *
+ * - [template]: The template element which is about to create and insert an
+ * instance.
+ * - [model]: The data context for which this instance is being created.
+ *
+ * The template element will always use the return value of `getInstanceModel`
+ * as the model for the new instance. If the syntax does not wish to override
+ * the value, it should simply return the `model` value it was passed.
+ */
+ getInstanceModel(Element template, model) => model;
+
+ /**
+ * This syntax method allows a syntax to provide an alterate expansion of
+ * the [template] contents. When the template wants to create an instance,
+ * it will call this method with the template element.
+ *
+ * By default this will call `template.createInstance()`.
+ */
+ getInstanceFragment(Element template) => template.createInstance();
+}
+
+
@Experimental
@DomName('HTMLTemplateElement')
@SupportedBrowser(SupportedBrowser.CHROME)
@@ -22752,24 +22674,23 @@
@Experimental
DocumentFragment get content => $dom_content;
- static StreamController<DocumentFragment> _instanceCreated;
/**
- * *Warning*: This is an implementation helper for Model-Driven Views and
- * should not be used in your code.
+ * The MDV package, if available.
*
- * This event is fired whenever a template is instantiated via
- * [createInstance].
+ * This can be used to initialize MDV support via:
+ *
+ * import 'dart:html';
+ * import 'package:mdv/mdv.dart' as mdv;
+ * main() {
+ * mdv.initialize();
+ * }
*/
- // TODO(rafaelw): This is a hack, and is neccesary for the polyfill
- // because custom elements are not upgraded during clone()
- @Experimental
- static Stream<DocumentFragment> get instanceCreated {
- if (_instanceCreated == null) {
- _instanceCreated = new StreamController<DocumentFragment>(sync: true);
- }
- return _instanceCreated.stream;
- }
+ static Function mdvPackage = (node) {
+ throw new UnsupportedError("The MDV package is not available. "
+ "You can enable it with `import 'package:mdv/mdv.dart' as mdv;` and "
+ "`mdv.initialize()`");
+ };
/**
* Ensures proper API and content model for template elements.
@@ -22786,30 +22707,111 @@
// == true check because it starts as a null field.
if (template._templateIsDecorated == true) return false;
- template._templateIsDecorated = true;
-
_injectStylesheet();
- // Create content
- if (template is! TemplateElement) {
- var doc = _Bindings._getTemplateContentsOwner(template.document);
- template._templateContent = doc.createDocumentFragment();
+ var templateElement = template;
+ var isNative = templateElement is TemplateElement;
+ var bootstrapContents = isNative;
+ var liftContents = !isNative;
+ var liftRoot = false;
+
+ if (!isNative && templateElement._isAttributeTemplate) {
+ if (instanceRef != null) {
+ // TODO(jmesserly): this is just an assert in MDV.
+ throw new ArgumentError('instanceRef should not be supplied for '
+ 'attribute templates.');
+ }
+ templateElement = _extractTemplateFromAttributeTemplate(template);
+ isNative = templateElement is TemplateElement;
+ liftRoot = true;
+ }
+
+ templateElement._templateIsDecorated = true;
+
+ if (!isNative) {
+ var doc = _getTemplateContentsOwner(templateElement.document);
+ templateElement._templateContent = doc.createDocumentFragment();
}
if (instanceRef != null) {
- template._templateInstanceRef = instanceRef;
- return true; // content is empty.
- }
-
- if (template is TemplateElement) {
- bootstrap(template.content);
- } else {
- _Bindings._liftNonNativeChildrenIntoContent(template);
+ // template is contained within an instance, its direct content must be
+ // empty
+ templateElement._templateInstanceRef = instanceRef;
+ } else if (liftContents) {
+ _liftNonNativeChildrenIntoContent(templateElement, template, liftRoot);
+ } else if (bootstrapContents) {
+ bootstrap(templateElement.content);
}
return true;
}
+ // http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/templates/index.html#dfn-template-contents-owner
+ static Document _getTemplateContentsOwner(HtmlDocument doc) {
+ if (doc.window == null) {
+ return doc;
+ }
+ var d = doc._templateContentsOwner;
+ if (d == null) {
+ // TODO(arv): This should either be a Document or HTMLDocument depending
+ // on doc.
+ d = doc.implementation.createHtmlDocument('');
+ while (d.lastChild != null) {
+ d.lastChild.remove();
+ }
+ doc._templateContentsOwner = d;
+ }
+ return d;
+ }
+
+ // For non-template browsers, the parser will disallow <template> in certain
+ // locations, so we allow "attribute templates" which combine the template
+ // element with the top-level container node of the content, e.g.
+ //
+ // <tr template repeat="{{ foo }}"" class="bar"><td>Bar</td></tr>
+ //
+ // becomes
+ //
+ // <template repeat="{{ foo }}">
+ // + #document-fragment
+ // + <tr class="bar">
+ // + <td>Bar</td>
+ //
+ static Element _extractTemplateFromAttributeTemplate(Element el) {
+ var template = el.document.$dom_createElement('template');
+ el.parentNode.insertBefore(template, el);
+
+ for (var name in el.attributes.keys.toList()) {
+ switch (name) {
+ case 'template':
+ el.attributes.remove(name);
+ break;
+ case 'repeat':
+ case 'bind':
+ case 'ref':
+ template.attributes[name] = el.attributes.remove(name);
+ break;
+ }
+ }
+
+ return template;
+ }
+
+ static void _liftNonNativeChildrenIntoContent(Element template, Element el,
+ bool useRoot) {
+
+ var content = template.content;
+ if (useRoot) {
+ content.append(el);
+ return;
+ }
+
+ var child;
+ while ((child = el.firstChild) != null) {
+ content.append(child);
+ }
+ }
+
/**
* This used to decorate recursively all templates from a given node.
*
@@ -22820,24 +22822,26 @@
// TODO(rafaelw): Review whether this is the right public API.
@Experimental
static void bootstrap(Node content) {
- _Bindings._bootstrapTemplatesRecursivelyFrom(content);
+ void _bootstrap(template) {
+ if (!TemplateElement.decorate(template)) {
+ bootstrap(template.content);
+ }
+ }
+
+ // Need to do this first as the contents may get lifted if |node| is
+ // template.
+ // TODO(jmesserly): content is DocumentFragment or Element
+ var descendents = (content as dynamic).queryAll(_allTemplatesSelectors);
+ if (content is Element && (content as Element).isTemplate) {
+ _bootstrap(content);
+ }
+
+ descendents.forEach(_bootstrap);
}
- /**
- * Binds all mustaches recursively starting from the [root] node.
- *
- * Note: this is not an official Model-Driven-Views API; it is intended to
- * support binding the [ShadowRoot]'s content to a model.
- */
- // TODO(jmesserly): this is needed to avoid two <template> nodes when using
- // bindings in a custom element's template. See also:
- // https://github.com/polymer-project/polymer/blob/master/src/bindMDV.js#L68
- // Called from:
- // https://github.com/polymer-project/polymer/blob/master/src/register.js#L99
- @Experimental
- static void bindModel(Node root, model, [CustomBindingSyntax syntax]) {
- _Bindings._addBindings(root, model, syntax);
- }
+ static final String _allTemplatesSelectors =
+ 'template, option[template], optgroup[template], ' +
+ Element._TABLE_TAGS.keys.map((k) => "$k[template]").join(", ");
static bool _initStyles;
@@ -22896,41 +22900,6 @@
@DocsEditable
Text splitText(int offset) native "Text_splitText_Callback";
-
- StreamSubscription _textBinding;
-
- @Experimental
- void bind(String name, model, String path) {
- if (name != 'text') {
- super.bind(name, model, path);
- return;
- }
-
- unbind('text');
-
- _textBinding = new PathObserver(model, path).bindSync((value) {
- text = value == null ? '' : '$value';
- });
- }
-
- @Experimental
- void unbind(String name) {
- if (name != 'text') {
- super.unbind(name);
- return;
- }
-
- if (_textBinding == null) return;
-
- _textBinding.cancel();
- _textBinding = null;
- }
-
- @Experimental
- void unbindAll() {
- unbind('text');
- super.unbindAll();
- }
}
// 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
@@ -29705,794 +29674,6 @@
// BSD-style license that can be found in the LICENSE file.
-// This code is a port of Model-Driven-Views:
-// https://github.com/polymer-project/mdv
-// The code mostly comes from src/template_element.js
-
-typedef void _ChangeHandler(value);
-
-/**
- * Model-Driven Views (MDV)'s native features enables a wide-range of use cases,
- * but (by design) don't attempt to implement a wide array of specialized
- * behaviors.
- *
- * Enabling these features in MDV is a matter of implementing and registering an
- * MDV Custom Syntax. A Custom Syntax is an object which contains one or more
- * delegation functions which implement specialized behavior. This object is
- * registered with MDV via [TemplateElement.syntax]:
- *
- *
- * HTML:
- * <template bind syntax="MySyntax">
- * {{ What!Ever('crazy')->thing^^^I+Want(data) }}
- * </template>
- *
- * Dart:
- * class MySyntax extends CustomBindingSyntax {
- * getBinding(model, path, name, node) {
- * // The magic happens here!
- * }
- * }
- *
- * ...
- *
- * TemplateElement.syntax['MySyntax'] = new MySyntax();
- *
- * See <https://github.com/polymer-project/mdv/blob/master/docs/syntax.md> for more
- * information about Custom Syntax.
- */
-// TODO(jmesserly): if this is just one method, a function type would make it
-// more Dart-friendly.
-@Experimental
-abstract class CustomBindingSyntax {
- /**
- * This syntax method allows for a custom interpretation of the contents of
- * mustaches (`{{` ... `}}`).
- *
- * When a template is inserting an instance, it will invoke this method for
- * each mustache which is encountered. The function is invoked with four
- * arguments:
- *
- * - [model]: The data context for which this instance is being created.
- * - [path]: The text contents (trimmed of outer whitespace) of the mustache.
- * - [name]: The context in which the mustache occurs. Within element
- * attributes, this will be the name of the attribute. Within text,
- * this will be 'text'.
- * - [node]: A reference to the node to which this binding will be created.
- *
- * If the method wishes to handle binding, it is required to return an object
- * which has at least a `value` property that can be observed. If it does,
- * then MDV will call [Node.bind on the node:
- *
- * node.bind(name, retval, 'value');
- *
- * If the 'getBinding' does not wish to override the binding, it should return
- * null.
- */
- // TODO(jmesserly): I had to remove type annotations from "name" and "node"
- // Normally they are String and Node respectively. But sometimes it will pass
- // (int name, CompoundBinding node). That seems very confusing; we may want
- // to change this API.
- getBinding(model, String path, name, node) => null;
-
- /**
- * This syntax method allows a syntax to provide an alterate model than the
- * one the template would otherwise use when producing an instance.
- *
- * When a template is about to create an instance, it will invoke this method
- * The function is invoked with two arguments:
- *
- * - [template]: The template element which is about to create and insert an
- * instance.
- * - [model]: The data context for which this instance is being created.
- *
- * The template element will always use the return value of `getInstanceModel`
- * as the model for the new instance. If the syntax does not wish to override
- * the value, it should simply return the `model` value it was passed.
- */
- getInstanceModel(Element template, model) => model;
-
- /**
- * This syntax method allows a syntax to provide an alterate expansion of
- * the [template] contents. When the template wants to create an instance,
- * it will call this method with the template element.
- *
- * By default this will call `template.createInstance()`.
- */
- getInstanceFragment(Element template) => template.createInstance();
-}
-
-/** The callback used in the [CompoundBinding.combinator] field. */
-@Experimental
-typedef Object CompoundBindingCombinator(Map objects);
-
-/** Information about the instantiated template. */
-@Experimental
-class TemplateInstance {
- // TODO(rafaelw): firstNode & lastNode should be read-synchronous
- // in cases where script has modified the template instance boundary.
-
- /** The first node of this template instantiation. */
- final Node firstNode;
-
- /**
- * The last node of this template instantiation.
- * This could be identical to [firstNode] if the template only expanded to a
- * single node.
- */
- final Node lastNode;
-
- /** The model used to instantiate the template. */
- final model;
-
- TemplateInstance(this.firstNode, this.lastNode, this.model);
-}
-
-/**
- * Model-Driven Views contains a helper object which is useful for the
- * implementation of a Custom Syntax.
- *
- * var binding = new CompoundBinding((values) {
- * var combinedValue;
- * // compute combinedValue based on the current values which are provided
- * return combinedValue;
- * });
- * binding.bind('name1', obj1, path1);
- * binding.bind('name2', obj2, path2);
- * //...
- * binding.bind('nameN', objN, pathN);
- *
- * CompoundBinding is an object which knows how to listen to multiple path
- * values (registered via [bind]) and invoke its [combinator] when one or more
- * of the values have changed and set its [value] property to the return value
- * of the function. When any value has changed, all current values are provided
- * to the [combinator] in the single `values` argument.
- *
- * See [CustomBindingSyntax] for more information.
- */
-// TODO(jmesserly): what is the public API surface here? I just guessed;
-// most of it seemed non-public.
-@Experimental
-class CompoundBinding extends ObservableBase {
- CompoundBindingCombinator _combinator;
-
- // TODO(jmesserly): ideally these would be String keys, but sometimes we
- // use integers.
- Map<dynamic, StreamSubscription> _bindings = new Map();
- Map _values = new Map();
- bool _scheduled = false;
- bool _disposed = false;
- Object _value;
-
- CompoundBinding([CompoundBindingCombinator combinator]) {
- // TODO(jmesserly): this is a tweak to the original code, it seemed to me
- // that passing the combinator to the constructor should be equivalent to
- // setting it via the property.
- // I also added a null check to the combinator setter.
- this.combinator = combinator;
- }
-
- CompoundBindingCombinator get combinator => _combinator;
-
- set combinator(CompoundBindingCombinator combinator) {
- _combinator = combinator;
- if (combinator != null) _scheduleResolve();
- }
-
- static const _VALUE = const Symbol('value');
-
- get value => _value;
-
- void set value(newValue) {
- _value = notifyPropertyChange(_VALUE, _value, newValue);
- }
-
- // TODO(jmesserly): remove these workarounds when dart2js supports mirrors!
- getValueWorkaround(key) {
- if (key == _VALUE) return value;
- return null;
- }
- setValueWorkaround(key, val) {
- if (key == _VALUE) value = val;
- }
-
- void bind(name, model, String path) {
- unbind(name);
-
- _bindings[name] = new PathObserver(model, path).bindSync((value) {
- _values[name] = value;
- _scheduleResolve();
- });
- }
-
- void unbind(name, {bool suppressResolve: false}) {
- var binding = _bindings.remove(name);
- if (binding == null) return;
-
- binding.cancel();
- _values.remove(name);
- if (!suppressResolve) _scheduleResolve();
- }
-
- // TODO(rafaelw): Is this the right processing model?
- // TODO(rafaelw): Consider having a seperate ChangeSummary for
- // CompoundBindings so to excess dirtyChecks.
- void _scheduleResolve() {
- if (_scheduled) return;
- _scheduled = true;
- queueChangeRecords(resolve);
- }
-
- void resolve() {
- if (_disposed) return;
- _scheduled = false;
-
- if (_combinator == null) {
- throw new StateError(
- 'CompoundBinding attempted to resolve without a combinator');
- }
-
- value = _combinator(_values);
- }
-
- void dispose() {
- for (var binding in _bindings.values) {
- binding.cancel();
- }
- _bindings.clear();
- _values.clear();
-
- _disposed = true;
- value = null;
- }
-}
-
-abstract class _InputBinding {
- final InputElement element;
- PathObserver binding;
- StreamSubscription _pathSub;
- StreamSubscription _eventSub;
-
- _InputBinding(this.element, model, String path) {
- binding = new PathObserver(model, path);
- _pathSub = binding.bindSync(valueChanged);
- _eventSub = _getStreamForInputType(element).listen(updateBinding);
- }
-
- void valueChanged(newValue);
-
- void updateBinding(e);
-
- void unbind() {
- binding = null;
- _pathSub.cancel();
- _eventSub.cancel();
- }
-
-
- static Stream<Event> _getStreamForInputType(InputElement element) {
- switch (element.type) {
- case 'checkbox':
- return element.onClick;
- case 'radio':
- case 'select-multiple':
- case 'select-one':
- return element.onChange;
- default:
- return element.onInput;
- }
- }
-}
-
-class _ValueBinding extends _InputBinding {
- _ValueBinding(element, model, path) : super(element, model, path);
-
- void valueChanged(value) {
- element.value = value == null ? '' : '$value';
- }
-
- void updateBinding(e) {
- binding.value = element.value;
- }
-}
-
-class _CheckedBinding extends _InputBinding {
- _CheckedBinding(element, model, path) : super(element, model, path);
-
- void valueChanged(value) {
- element.checked = _Bindings._toBoolean(value);
- }
-
- void updateBinding(e) {
- binding.value = element.checked;
-
- // Only the radio button that is getting checked gets an event. We
- // therefore find all the associated radio buttons and update their
- // CheckedBinding manually.
- if (element is InputElement && element.type == 'radio') {
- for (var r in _getAssociatedRadioButtons(element)) {
- var checkedBinding = r._checkedBinding;
- if (checkedBinding != null) {
- // Set the value directly to avoid an infinite call stack.
- checkedBinding.binding.value = false;
- }
- }
- }
- }
-
- // |element| is assumed to be an HTMLInputElement with |type| == 'radio'.
- // Returns an array containing all radio buttons other than |element| that
- // have the same |name|, either in the form that |element| belongs to or,
- // if no form, in the document tree to which |element| belongs.
- //
- // This implementation is based upon the HTML spec definition of a
- // "radio button group":
- // http://www.whatwg.org/specs/web-apps/current-work/multipage/number-state.html#radio-button-group
- //
- static Iterable _getAssociatedRadioButtons(element) {
- if (!_isNodeInDocument(element)) return [];
- if (element.form != null) {
- return element.form.nodes.where((el) {
- return el != element &&
- el is InputElement &&
- el.type == 'radio' &&
- el.name == element.name;
- });
- } else {
- var radios = element.document.queryAll(
- 'input[type="radio"][name="${element.name}"]');
- return radios.where((el) => el != element && el.form == null);
- }
- }
-
- // TODO(jmesserly): polyfill document.contains API instead of doing it here
- static bool _isNodeInDocument(Node node) {
- // On non-IE this works:
- // return node.document.contains(node);
- var document = node.document;
- if (node == document || node.parentNode == document) return true;
- return document.documentElement.contains(node);
- }
-}
-
-class _Bindings {
- // TODO(jmesserly): not sure what kind of boolean conversion rules to
- // apply for template data-binding. HTML attributes are true if they're
- // present. However Dart only treats "true" as true. Since this is HTML we'll
- // use something closer to the HTML rules: null (missing) and false are false,
- // everything else is true. See: https://github.com/polymer-project/mdv/issues/59
- static bool _toBoolean(value) => null != value && false != value;
-
- static Node _createDeepCloneAndDecorateTemplates(Node node, String syntax) {
- var clone = node.clone(false); // Shallow clone.
- if (clone is Element && clone.isTemplate) {
- TemplateElement.decorate(clone, node);
- if (syntax != null) {
- clone.attributes.putIfAbsent('syntax', () => syntax);
- }
- }
-
- for (var c = node.$dom_firstChild; c != null; c = c.nextNode) {
- clone.append(_createDeepCloneAndDecorateTemplates(c, syntax));
- }
- return clone;
- }
-
- // http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/templates/index.html#dfn-template-contents-owner
- static Document _getTemplateContentsOwner(HtmlDocument doc) {
- if (doc.window == null) {
- return doc;
- }
- var d = doc._templateContentsOwner;
- if (d == null) {
- // TODO(arv): This should either be a Document or HTMLDocument depending
- // on doc.
- d = doc.implementation.createHtmlDocument('');
- while (d.$dom_lastChild != null) {
- d.$dom_lastChild.remove();
- }
- doc._templateContentsOwner = d;
- }
- return d;
- }
-
- static Element _cloneAndSeperateAttributeTemplate(Element templateElement) {
- var clone = templateElement.clone(false);
- var attributes = templateElement.attributes;
- for (var name in attributes.keys.toList()) {
- switch (name) {
- case 'template':
- case 'repeat':
- case 'bind':
- case 'ref':
- clone.attributes.remove(name);
- break;
- default:
- attributes.remove(name);
- break;
- }
- }
-
- return clone;
- }
-
- static void _liftNonNativeChildrenIntoContent(Element templateElement) {
- var content = templateElement.content;
-
- if (!templateElement._isAttributeTemplate) {
- var child;
- while ((child = templateElement.$dom_firstChild) != null) {
- content.append(child);
- }
- return;
- }
-
- // For attribute templates we copy the whole thing into the content and
- // we move the non template attributes into the content.
- //
- // <tr foo template>
- //
- // becomes
- //
- // <tr template>
- // + #document-fragment
- // + <tr foo>
- //
- var newRoot = _cloneAndSeperateAttributeTemplate(templateElement);
- var child;
- while ((child = templateElement.$dom_firstChild) != null) {
- newRoot.append(child);
- }
- content.append(newRoot);
- }
-
- static void _bootstrapTemplatesRecursivelyFrom(Node node) {
- void bootstrap(template) {
- if (!TemplateElement.decorate(template)) {
- _bootstrapTemplatesRecursivelyFrom(template.content);
- }
- }
-
- // Need to do this first as the contents may get lifted if |node| is
- // template.
- // TODO(jmesserly): node is DocumentFragment or Element
- var descendents = (node as dynamic).queryAll(_allTemplatesSelectors);
- if (node is Element && (node as Element).isTemplate) bootstrap(node);
-
- descendents.forEach(bootstrap);
- }
-
- static final String _allTemplatesSelectors = 'template, option[template], ' +
- Element._TABLE_TAGS.keys.map((k) => "$k[template]").join(", ");
-
- static void _addBindings(Node node, model, [CustomBindingSyntax syntax]) {
- if (node is Element) {
- _addAttributeBindings(node, model, syntax);
- } else if (node is Text) {
- _parseAndBind(node, 'text', node.text, model, syntax);
- }
-
- for (var c = node.$dom_firstChild; c != null; c = c.nextNode) {
- _addBindings(c, model, syntax);
- }
- }
-
- static void _addAttributeBindings(Element element, model, syntax) {
- element.attributes.forEach((name, value) {
- if (value == '' && (name == 'bind' || name == 'repeat')) {
- value = '{{}}';
- }
- _parseAndBind(element, name, value, model, syntax);
- });
- }
-
- static void _parseAndBind(Node node, String name, String text, model,
- CustomBindingSyntax syntax) {
-
- var tokens = _parseMustacheTokens(text);
- if (tokens.length == 0 || (tokens.length == 1 && tokens[0].isText)) {
- return;
- }
-
- // If this is a custom element, give the .xtag a change to bind.
- node = _nodeOrCustom(node);
-
- if (tokens.length == 1 && tokens[0].isBinding) {
- _bindOrDelegate(node, name, model, tokens[0].value, syntax);
- return;
- }
-
- var replacementBinding = new CompoundBinding();
- for (var i = 0; i < tokens.length; i++) {
- var token = tokens[i];
- if (token.isBinding) {
- _bindOrDelegate(replacementBinding, i, model, token.value, syntax);
- }
- }
-
- replacementBinding.combinator = (values) {
- var newValue = new StringBuffer();
-
- for (var i = 0; i < tokens.length; i++) {
- var token = tokens[i];
- if (token.isText) {
- newValue.write(token.value);
- } else {
- var value = values[i];
- if (value != null) {
- newValue.write(value);
- }
- }
- }
-
- return newValue.toString();
- };
-
- node.bind(name, replacementBinding, 'value');
- }
-
- static void _bindOrDelegate(node, name, model, String path,
- CustomBindingSyntax syntax) {
-
- if (syntax != null) {
- var delegateBinding = syntax.getBinding(model, path, name, node);
- if (delegateBinding != null) {
- model = delegateBinding;
- path = 'value';
- }
- }
-
- node.bind(name, model, path);
- }
-
- /**
- * Gets the [node]'s custom [Element.xtag] if present, otherwise returns
- * the node. This is used so nodes can override [Node.bind], [Node.unbind],
- * and [Node.unbindAll] like InputElement does.
- */
- // TODO(jmesserly): remove this when we can extend Element for real.
- static _nodeOrCustom(node) => node is Element ? node.xtag : node;
-
- static List<_BindingToken> _parseMustacheTokens(String s) {
- var result = [];
- var length = s.length;
- var index = 0, lastIndex = 0;
- while (lastIndex < length) {
- index = s.indexOf('{{', lastIndex);
- if (index < 0) {
- result.add(new _BindingToken(s.substring(lastIndex)));
- break;
- } else {
- // There is a non-empty text run before the next path token.
- if (index > 0 && lastIndex < index) {
- result.add(new _BindingToken(s.substring(lastIndex, index)));
- }
- lastIndex = index + 2;
- index = s.indexOf('}}', lastIndex);
- if (index < 0) {
- var text = s.substring(lastIndex - 2);
- if (result.length > 0 && result.last.isText) {
- result.last.value += text;
- } else {
- result.add(new _BindingToken(text));
- }
- break;
- }
-
- var value = s.substring(lastIndex, index).trim();
- result.add(new _BindingToken(value, isBinding: true));
- lastIndex = index + 2;
- }
- }
- return result;
- }
-
- static void _addTemplateInstanceRecord(fragment, model) {
- if (fragment.$dom_firstChild == null) {
- return;
- }
-
- var instanceRecord = new TemplateInstance(
- fragment.$dom_firstChild, fragment.$dom_lastChild, model);
-
- var node = instanceRecord.firstNode;
- while (node != null) {
- node._templateInstance = instanceRecord;
- node = node.nextNode;
- }
- }
-
- static void _removeAllBindingsRecursively(Node node) {
- _nodeOrCustom(node).unbindAll();
- for (var c = node.$dom_firstChild; c != null; c = c.nextNode) {
- _removeAllBindingsRecursively(c);
- }
- }
-
- static void _removeChild(Node parent, Node child) {
- child._templateInstance = null;
- if (child is Element && (child as Element).isTemplate) {
- Element childElement = child;
- // Make sure we stop observing when we remove an element.
- var templateIterator = childElement._templateIterator;
- if (templateIterator != null) {
- templateIterator.abandon();
- childElement._templateIterator = null;
- }
- }
- child.remove();
- _removeAllBindingsRecursively(child);
- }
-}
-
-class _BindingToken {
- final String value;
- final bool isBinding;
-
- _BindingToken(this.value, {this.isBinding: false});
-
- bool get isText => !isBinding;
-}
-
-class _TemplateIterator {
- final Element _templateElement;
- final List<Node> terminators = [];
- final CompoundBinding inputs;
- List iteratedValue;
-
- StreamSubscription _sub;
- StreamSubscription _valueBinding;
-
- _TemplateIterator(this._templateElement)
- : inputs = new CompoundBinding(resolveInputs) {
-
- _valueBinding = new PathObserver(inputs, 'value').bindSync(valueChanged);
- }
-
- static Object resolveInputs(Map values) {
- if (values.containsKey('if') && !_Bindings._toBoolean(values['if'])) {
- return null;
- }
-
- if (values.containsKey('repeat')) {
- return values['repeat'];
- }
-
- if (values.containsKey('bind')) {
- return [values['bind']];
- }
-
- return null;
- }
-
- void valueChanged(value) {
- clear();
- if (value is! List) return;
-
- iteratedValue = value;
-
- if (value is Observable) {
- _sub = value.changes.listen(_handleChanges);
- }
-
- int len = iteratedValue.length;
- if (len > 0) {
- _handleChanges([new ListChangeRecord(0, addedCount: len)]);
- }
- }
-
- Node getTerminatorAt(int index) {
- if (index == -1) return _templateElement;
- var terminator = terminators[index];
- if (terminator is! Element) return terminator;
-
- var subIterator = terminator._templateIterator;
- if (subIterator == null) return terminator;
-
- return subIterator.getTerminatorAt(subIterator.terminators.length - 1);
- }
-
- void insertInstanceAt(int index, Node fragment) {
- var previousTerminator = getTerminatorAt(index - 1);
- var terminator = fragment.$dom_lastChild;
- if (terminator == null) terminator = previousTerminator;
-
- terminators.insert(index, terminator);
- var parent = _templateElement.parentNode;
- parent.insertBefore(fragment, previousTerminator.nextNode);
- }
-
- void removeInstanceAt(int index) {
- var previousTerminator = getTerminatorAt(index - 1);
- var terminator = getTerminatorAt(index);
- terminators.removeAt(index);
-
- var parent = _templateElement.parentNode;
- while (terminator != previousTerminator) {
- var node = terminator;
- terminator = node.previousNode;
- _Bindings._removeChild(parent, node);
- }
- }
-
- void removeAllInstances() {
- if (terminators.length == 0) return;
-
- var previousTerminator = _templateElement;
- var terminator = getTerminatorAt(terminators.length - 1);
- terminators.length = 0;
-
- var parent = _templateElement.parentNode;
- while (terminator != previousTerminator) {
- var node = terminator;
- terminator = node.previousNode;
- _Bindings._removeChild(parent, node);
- }
- }
-
- void clear() {
- unobserve();
- removeAllInstances();
- iteratedValue = null;
- }
-
- getInstanceModel(model, syntax) {
- if (syntax != null) {
- return syntax.getInstanceModel(_templateElement, model);
- }
- return model;
- }
-
- getInstanceFragment(syntax) {
- if (syntax != null) {
- return syntax.getInstanceFragment(_templateElement);
- }
- return _templateElement.createInstance();
- }
-
- void _handleChanges(List<ListChangeRecord> splices) {
- var syntax = TemplateElement.syntax[_templateElement.attributes['syntax']];
-
- for (var splice in splices) {
- if (splice is! ListChangeRecord) continue;
-
- for (int i = 0; i < splice.removedCount; i++) {
- removeInstanceAt(splice.index);
- }
-
- for (var addIndex = splice.index;
- addIndex < splice.index + splice.addedCount;
- addIndex++) {
-
- var model = getInstanceModel(iteratedValue[addIndex], syntax);
-
- var fragment = getInstanceFragment(syntax);
-
- _Bindings._addBindings(fragment, model, syntax);
- _Bindings._addTemplateInstanceRecord(fragment, model);
-
- insertInstanceAt(addIndex, fragment);
- }
- }
- }
-
- void unobserve() {
- if (_sub == null) return;
- _sub.cancel();
- _sub = null;
- }
-
- void abandon() {
- unobserve();
- _valueBinding.cancel();
- inputs.dispose();
- }
-}
-// 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.
-
-
/**
* Helper class to implement custom events which wrap DOM events.
*/
diff --git a/sdk/lib/indexed_db/dart2js/indexed_db_dart2js.dart b/sdk/lib/indexed_db/dart2js/indexed_db_dart2js.dart
index e8ab65e..fa39c0b 100644
--- a/sdk/lib/indexed_db/dart2js/indexed_db_dart2js.dart
+++ b/sdk/lib/indexed_db/dart2js/indexed_db_dart2js.dart
@@ -1056,7 +1056,7 @@
@DocsEditable
@DomName('IDBOpenDBRequest')
@Unstable
-class OpenDBRequest extends Request implements EventTarget native "IDBOpenDBRequest" {
+class OpenDBRequest extends Request implements EventTarget native "IDBOpenDBRequest,IDBVersionChangeRequest" {
@DomName('IDBOpenDBRequest.blockedEvent')
@DocsEditable
diff --git a/sdk/lib/io/common.dart b/sdk/lib/io/common.dart
index ba5f07d..6ae39cf 100644
--- a/sdk/lib/io/common.dart
+++ b/sdk/lib/io/common.dart
@@ -23,7 +23,7 @@
/**
* Returns an Exception or an Error
*/
-_exceptionFromResponse(response, String message) {
+_exceptionFromResponse(response, String message, String path) {
assert(_isErrorResponse(response));
switch (response[_ERROR_RESPONSE_ERROR_TYPE]) {
case _ILLEGAL_ARGUMENT_RESPONSE:
@@ -31,9 +31,9 @@
case _OSERROR_RESPONSE:
var err = new OSError(response[_OSERROR_RESPONSE_MESSAGE],
response[_OSERROR_RESPONSE_ERROR_CODE]);
- return new FileException(message, err);
+ return new FileException(message, path, err);
case _FILE_CLOSED_RESPONSE:
- return new FileException("File closed");
+ return new FileException("File closed", path);
default:
return new Exception("Unknown error");
}
diff --git a/sdk/lib/io/directory.dart b/sdk/lib/io/directory.dart
index c8423b5..0c9e048 100644
--- a/sdk/lib/io/directory.dart
+++ b/sdk/lib/io/directory.dart
@@ -212,8 +212,8 @@
class DirectoryException implements IOException {
const DirectoryException([String this.message = "",
- String this.path = "",
- OSError this.osError = null]);
+ String this.path = "",
+ OSError this.osError = null]);
String toString() {
StringBuffer sb = new StringBuffer();
sb.write("DirectoryException");
diff --git a/sdk/lib/io/directory_impl.dart b/sdk/lib/io/directory_impl.dart
index 4472fcb..5429a29 100644
--- a/sdk/lib/io/directory_impl.dart
+++ b/sdk/lib/io/directory_impl.dart
@@ -168,8 +168,8 @@
request[1] = _path;
return _directoryService.call(request).then((response) {
if (_isErrorResponse(response)) {
- throw _exceptionOrErrorFromResponse(response,
- "Creation of temporary directory failed");
+ throw _exceptionOrErrorFromResponse(
+ response, "Creation of temporary directory failed");
}
return new Directory(response);
});
@@ -182,8 +182,8 @@
var result = _createTemp(path);
if (result is OSError) {
throw new DirectoryException("Creation of temporary directory failed",
- _path,
- result);
+ _path,
+ result);
}
return new Directory(result);
}
diff --git a/sdk/lib/io/file.dart b/sdk/lib/io/file.dart
index 450a902..2115d31 100644
--- a/sdk/lib/io/file.dart
+++ b/sdk/lib/io/file.dart
@@ -525,21 +525,30 @@
class FileException implements IOException {
+ final String message;
+ final String path;
+ final OSError osError;
const FileException([String this.message = "",
- OSError this.osError = null]);
+ String this.path = "",
+ OSError this.osError]);
+
String toString() {
StringBuffer sb = new StringBuffer();
sb.write("FileException");
if (!message.isEmpty) {
sb.write(": $message");
+ if (path != null) {
+ sb.write(", path = $path");
+ }
if (osError != null) {
sb.write(" ($osError)");
}
} else if (osError != null) {
sb.write(": osError");
+ if (path != null) {
+ sb.write(", path = $path");
+ }
}
return sb.toString();
}
- final String message;
- final OSError osError;
}
diff --git a/sdk/lib/io/file_impl.dart b/sdk/lib/io/file_impl.dart
index 6d15154..bc5aa47 100644
--- a/sdk/lib/io/file_impl.dart
+++ b/sdk/lib/io/file_impl.dart
@@ -253,8 +253,7 @@
request[1] = _path;
return _fileService.call(request).then((response) {
if (_isErrorResponse(response)) {
- throw _exceptionFromResponse(response,
- "Cannot check existence of file '$_path'");
+ throw _exceptionFromResponse(response, "Cannot check existence", _path);
}
return response;
});
@@ -264,7 +263,7 @@
bool existsSync() {
var result = _exists(_path);
- throwIfError(result, "Cannot check existence of file '$_path'");
+ throwIfError(result, "Cannot check existence of file", _path);
return result;
}
@@ -279,7 +278,7 @@
request[1] = _path;
return _fileService.call(request).then((response) {
if (_isErrorResponse(response)) {
- throw _exceptionFromResponse(response, "Cannot create file '$_path'");
+ throw _exceptionFromResponse(response, "Cannot create file", _path);
}
return this;
});
@@ -293,7 +292,7 @@
void createSync() {
var result = _create(_path);
- throwIfError(result, "Cannot create file '$_path'");
+ throwIfError(result, "Cannot create file", _path);
}
Future<File> delete() {
@@ -303,7 +302,7 @@
request[1] = _path;
return _fileService.call(request).then((response) {
if (_isErrorResponse(response)) {
- throw _exceptionFromResponse(response, "Cannot delete file '$_path'");
+ throw _exceptionFromResponse(response, "Cannot delete file", _path);
}
return this;
});
@@ -315,7 +314,7 @@
void deleteSync() {
var result = _delete(_path);
- throwIfError(result, "Cannot delete file '$_path'");
+ throwIfError(result, "Cannot delete file", _path);
}
Future<File> rename(String newPath) {
@@ -327,7 +326,7 @@
return _fileService.call(request).then((response) {
if (_isErrorResponse(response)) {
throw _exceptionFromResponse(
- response, "Cannot rename file '$_path' to '$newPath'");
+ response, "Cannot rename file to '$newPath'", _path);
}
return new File(newPath);
});
@@ -339,7 +338,7 @@
File renameSync(String newPath) {
var result = _rename(_path, newPath);
- throwIfError(result, "Cannot rename file '$_path' to '$newPath'");
+ throwIfError(result, "Cannot rename file to '$newPath'", _path);
return new File(newPath);
}
@@ -361,7 +360,7 @@
request[2] = mode._mode; // Direct int value for serialization.
return _fileService.call(request).then((response) {
if (_isErrorResponse(response)) {
- throw _exceptionFromResponse(response, "Cannot open file '$_path'");
+ throw _exceptionFromResponse(response, "Cannot open file", _path);
}
return new _RandomAccessFile(response, _path);
});
@@ -375,8 +374,8 @@
return _fileService.call(request).then((response) {
if (_isErrorResponse(response)) {
throw _exceptionFromResponse(response,
- "Cannot retrieve length of "
- "file '$_path'");
+ "Cannot retrieve length of file",
+ _path);
}
return response;
});
@@ -387,7 +386,7 @@
int lengthSync() {
var result = _lengthFromPath(_path);
- throwIfError(result, "Cannot retrieve length of file '$_path'");
+ throwIfError(result, "Cannot retrieve length of file", _path);
return result;
}
@@ -399,8 +398,8 @@
return _fileService.call(request).then((response) {
if (_isErrorResponse(response)) {
throw _exceptionFromResponse(response,
- "Cannot retrieve modification time "
- "for file '$_path'");
+ "Cannot retrieve modification time",
+ _path);
}
return new DateTime.fromMillisecondsSinceEpoch(response);
});
@@ -410,7 +409,7 @@
DateTime lastModifiedSync() {
var ms = _lastModified(path);
- throwIfError(ms, "Cannot retrieve modification time for file '$_path'");
+ throwIfError(ms, "Cannot retrieve modification time", _path);
return new DateTime.fromMillisecondsSinceEpoch(ms);
}
@@ -421,10 +420,11 @@
mode != FileMode.WRITE &&
mode != FileMode.APPEND) {
throw new FileException("Unknown file mode. Use FileMode.READ, "
- "FileMode.WRITE or FileMode.APPEND.");
+ "FileMode.WRITE or FileMode.APPEND.",
+ _path);
}
var id = _open(_path, mode._mode);
- throwIfError(id, "Cannot open file '$_path'");
+ throwIfError(id, "Cannot open file", _path);
return new _RandomAccessFile(id, _path);
}
@@ -446,8 +446,8 @@
return _fileService.call(request).then((response) {
if (_isErrorResponse(response)) {
throw _exceptionFromResponse(response,
- "Cannot retrieve full path"
- " for '$_path'");
+ "Cannot retrieve full path",
+ _path);
}
return response;
});
@@ -457,7 +457,7 @@
String fullPathSync() {
var result = _fullPath(_path);
- throwIfError(result, "Cannot retrieve full path for file '$_path'");
+ throwIfError(result, "Cannot retrieve full path", _path);
return result;
}
@@ -469,7 +469,7 @@
Encoding encoding: Encoding.UTF_8}) {
if (mode != FileMode.WRITE &&
mode != FileMode.APPEND) {
- throw new FileException(
+ throw new ArgumentError(
"Wrong FileMode. Use FileMode.WRITE or FileMode.APPEND");
}
var consumer = new _FileStreamConsumer(this, mode);
@@ -584,9 +584,9 @@
}
}
- static throwIfError(Object result, String msg) {
+ static throwIfError(Object result, String msg, String path) {
if (result is OSError) {
- throw new FileException(msg, result);
+ throw new FileException(msg, path, result);
}
}
@@ -613,7 +613,7 @@
_id = result;
return this;
} else {
- throw new FileException("Cannot close file '$_path'");
+ throw new FileException("Cannot close file", _path);
}
});
}
@@ -624,7 +624,7 @@
_checkNotClosed();
var id = _close(_id);
if (id == -1) {
- throw new FileException("Cannot close file '$_path'");
+ throw new FileException("Cannot close file", _path);
}
_id = id;
}
@@ -637,8 +637,7 @@
request[1] = _id;
return _fileService.call(request).then((response) {
if (_isErrorResponse(response)) {
- throw _exceptionFromResponse(response,
- "readByte failed for file '$_path'");
+ throw _exceptionFromResponse(response, "readByte failed", _path);
}
return response;
});
@@ -650,7 +649,7 @@
_checkNotClosed();
var result = _readByte(_id);
if (result is OSError) {
- throw new FileException("readByte failed for file '$_path'", result);
+ throw new FileException("readByte failed", _path, result);
}
return result;
}
@@ -658,8 +657,7 @@
Future<List<int>> read(int bytes) {
_ensureFileService();
if (bytes is !int) {
- return new Future.error(new FileException(
- "Invalid arguments to read for file '$_path'"));
+ throw new ArgumentError(bytes);
}
if (closed) return _closedException();
List request = new List(3);
@@ -668,8 +666,7 @@
request[2] = bytes;
return _fileService.call(request).then((response) {
if (_isErrorResponse(response)) {
- throw _exceptionFromResponse(response,
- "read failed for file '$_path'");
+ throw _exceptionFromResponse(response, "read failed", _path);
}
return response[1];
});
@@ -680,13 +677,11 @@
List<int> readSync(int bytes) {
_checkNotClosed();
if (bytes is !int) {
- throw new FileException(
- "Invalid arguments to readSync for file '$_path'");
+ throw new ArgumentError(bytes);
}
var result = _read(_id, bytes);
if (result is OSError) {
- throw new FileException("readSync failed for file '$_path'",
- result);
+ throw new FileException("readSync failed",_path, result);
}
return result;
}
@@ -696,9 +691,8 @@
if (buffer is !List ||
(start != null && start is !int) ||
(end != null && end is !int)) {
- return new Future.error(new FileException(
- "Invalid arguments to readInto for file '$_path'"));
- };
+ throw new ArgumentError();
+ }
if (closed) return _closedException();
List request = new List(3);
if (start == null) start = 0;
@@ -708,8 +702,7 @@
request[2] = end - start;
return _fileService.call(request).then((response) {
if (_isErrorResponse(response)) {
- throw _exceptionFromResponse(response,
- "readInto failed for file '$_path'");
+ throw _exceptionFromResponse(response, "readInto failed", _path);
}
var read = response[1];
var data = response[2];
@@ -733,8 +726,7 @@
if (buffer is !List ||
(start != null && start is !int) ||
(end != null && end is !int)) {
- throw new FileException(
- "Invalid arguments to readInto for file '$_path'");
+ throw new ArgumentError();
}
if (start == null) start = 0;
if (end == null) end = buffer.length;
@@ -742,8 +734,7 @@
_checkReadWriteListArguments(buffer.length, start, end);
var result = _readInto(_id, buffer, start, end);
if (result is OSError) {
- throw new FileException("readInto failed for file '$_path'",
- result);
+ throw new FileException("readInto failed", _path, result);
}
return result;
}
@@ -751,8 +742,7 @@
Future<RandomAccessFile> writeByte(int value) {
_ensureFileService();
if (value is !int) {
- return new Future.error(new FileException(
- "Invalid argument to writeByte for file '$_path'"));
+ throw new ArgumentError(value);
}
if (closed) return _closedException();
List request = new List(3);
@@ -761,8 +751,7 @@
request[2] = value;
return _fileService.call(request).then((response) {
if (_isErrorResponse(response)) {
- throw _exceptionFromResponse(response,
- "writeByte failed for file '$_path'");
+ throw _exceptionFromResponse(response, "writeByte failed",_path);
}
return this;
});
@@ -773,13 +762,11 @@
int writeByteSync(int value) {
_checkNotClosed();
if (value is !int) {
- throw new FileException(
- "Invalid argument to writeByte for file '$_path'");
+ throw new ArgumentError(value);
}
var result = _writeByte(_id, value);
if (result is OSError) {
- throw new FileException("writeByte failed for file '$_path'",
- result);
+ throw new FileException("writeByte failed", _path, result);
}
return result;
}
@@ -789,8 +776,7 @@
if ((buffer is !List && buffer is !ByteData) ||
(start != null && start is !int) ||
(end != null && end is !int)) {
- return new Future.error(new FileException(
- "Invalid arguments to writeFrom for file '$_path'"));
+ throw new ArgumentError("Invalid arguments to writeFrom");
}
if (closed) return _closedException();
@@ -810,8 +796,7 @@
request[4] = end - (start - result.start);
return _fileService.call(request).then((response) {
if (_isErrorResponse(response)) {
- throw _exceptionFromResponse(response,
- "writeFrom failed for file '$_path'");
+ throw _exceptionFromResponse(response, "writeFrom failed", _path);
}
return this;
});
@@ -824,8 +809,7 @@
if (buffer is !List ||
(start != null && start is !int) ||
(end != null && end is !int)) {
- throw new FileException(
- "Invalid arguments to writeFrom for file '$_path'");
+ throw new ArgumentError("Invalid arguments to writeFromSync");
}
if (start == null) start = 0;
if (end == null) end = buffer.length;
@@ -838,15 +822,14 @@
bufferAndStart.start,
end - (start - bufferAndStart.start));
if (result is OSError) {
- throw new FileException("writeFrom failed for file '$_path'", result);
+ throw new FileException("writeFrom failed", _path, result);
}
}
Future<RandomAccessFile> writeString(String string,
{Encoding encoding: Encoding.UTF_8}) {
if (encoding is! Encoding) {
- return new Future.error(new FileException(
- "Invalid encoding in writeString: $encoding"));
+ throw new ArgumentError(encoding);
}
var data = _encodeString(string, encoding);
return writeFrom(data, 0, data.length);
@@ -854,8 +837,7 @@
void writeStringSync(String string, {Encoding encoding: Encoding.UTF_8}) {
if (encoding is! Encoding) {
- throw new FileException(
- "Invalid encoding in writeStringSync: $encoding");
+ throw new ArgumentError(encoding);
}
var data = _encodeString(string, encoding);
writeFromSync(data, 0, data.length);
@@ -869,8 +851,7 @@
request[1] = _id;
return _fileService.call(request).then((response) {
if (_isErrorResponse(response)) {
- throw _exceptionFromResponse(response,
- "position failed for file '$_path'");
+ throw _exceptionFromResponse(response, "position failed", _path);
}
return response;
});
@@ -882,7 +863,7 @@
_checkNotClosed();
var result = _position(_id);
if (result is OSError) {
- throw new FileException("position failed for file '$_path'", result);
+ throw new FileException("position failed", _path, result);
}
return result;
}
@@ -896,8 +877,7 @@
request[2] = position;
return _fileService.call(request).then((response) {
if (_isErrorResponse(response)) {
- throw _exceptionFromResponse(response,
- "setPosition failed for file '$_path'");
+ throw _exceptionFromResponse(response, "setPosition failed", _path);
}
return this;
});
@@ -909,7 +889,7 @@
_checkNotClosed();
var result = _setPosition(_id, position);
if (result is OSError) {
- throw new FileException("setPosition failed for file '$_path'", result);
+ throw new FileException("setPosition failed", _path, result);
}
}
@@ -922,8 +902,7 @@
request[2] = length;
return _fileService.call(request).then((response) {
if (_isErrorResponse(response)) {
- throw _exceptionFromResponse(response,
- "truncate failed for file '$_path'");
+ throw _exceptionFromResponse(response, "truncate failed", _path);
}
return this;
});
@@ -935,7 +914,7 @@
_checkNotClosed();
var result = _truncate(_id, length);
if (result is OSError) {
- throw new FileException("truncate failed for file '$_path'", result);
+ throw new FileException("truncate failed", _path, result);
}
}
@@ -947,8 +926,7 @@
request[1] = _id;
return _fileService.call(request).then((response) {
if (_isErrorResponse(response)) {
- throw _exceptionFromResponse(response,
- "length failed for file '$_path'");
+ throw _exceptionFromResponse(response, "length failed", _path);
}
return response;
});
@@ -960,7 +938,7 @@
_checkNotClosed();
var result = _length(_id);
if (result is OSError) {
- throw new FileException("length failed for file '$_path'", result);
+ throw new FileException("length failed", _path, result);
}
return result;
}
@@ -974,7 +952,8 @@
return _fileService.call(request).then((response) {
if (_isErrorResponse(response)) {
throw _exceptionFromResponse(response,
- "flush failed for file '$_path'");
+ "flush failed",
+ _path);
}
return this;
});
@@ -986,7 +965,7 @@
_checkNotClosed();
var result = _flush(_id);
if (result is OSError) {
- throw new FileException("flush failed for file '$_path'", result);
+ throw new FileException("flush failed", _path, result);
}
}
@@ -1002,12 +981,12 @@
void _checkNotClosed() {
if (closed) {
- throw new FileException("File closed '$_path'");
+ throw new FileException("File closed", _path);
}
}
Future _closedException() {
- return new Future.error(new FileException("File closed '$_path'"));
+ return new Future.error(new FileException("File closed", _path));
}
final String _path;
diff --git a/sdk/lib/io/file_system_entity.dart b/sdk/lib/io/file_system_entity.dart
index 1723508..b764f04 100644
--- a/sdk/lib/io/file_system_entity.dart
+++ b/sdk/lib/io/file_system_entity.dart
@@ -79,7 +79,8 @@
return service.call(request).then((response) {
if (_isErrorResponse(response)) {
throw _exceptionFromResponse(response,
- "Error getting stat of '$path'");
+ "Error getting stat",
+ path);
}
// Unwrap the real list from the "I'm not an error" wrapper.
List data = response[1];
@@ -185,8 +186,7 @@
request[2] = followLinks;
return service.call(request).then((response) {
if (_isErrorResponse(response)) {
- throw _exceptionFromResponse(response,
- "Error getting type of '$path'");
+ throw _exceptionFromResponse(response, "Error getting type", path);
}
return response;
});
@@ -214,7 +214,7 @@
return service.call(request).then((response) {
if (_isErrorResponse(response)) {
throw _exceptionFromResponse(response,
- "Error in FileSystemEntity.identical($path1, $path2)");
+ "Error in FileSystemEntity.identical($path1, $path2)", "");
}
return response;
});
@@ -271,6 +271,27 @@
bool existsSync();
/**
+ * Renames this file system entity. Returns a `Future<FileSystemEntity>`
+ * that completes with a [FileSystemEntity] instance for the renamed
+ * file system entity.
+ *
+ * If [newPath] identifies an existing entity of the same type, that entity
+ * is replaced. If [newPath] identifies an existing entity of a different
+ * type, the operation fails and the future completes with an exception.
+ */
+ Future<FileSystemEntity> rename(String newPath);
+
+ /**
+ * Synchronously renames this file system entity. Returns a [FileSystemEntity]
+ * instance for the renamed entity.
+ *
+ * If [newPath] identifies an existing entity of the same type, that entity
+ * is replaced. If [newPath] identifies an existing entity of a different
+ * type, the operation fails and an exception is thrown.
+ */
+ FileSystemEntity renameSync(String newPath);
+
+ /**
* Calls the operating system's stat() function on the [path] of this
* [FileSystemEntity]. Identical to [:FileStat.stat(this.path):].
*
diff --git a/sdk/lib/io/http.dart b/sdk/lib/io/http.dart
index 29d561d..09b7d8c 100644
--- a/sdk/lib/io/http.dart
+++ b/sdk/lib/io/http.dart
@@ -55,11 +55,31 @@
/**
- * HTTP server.
+ * The [HttpServer] class implements the server side of the HTTP
+ * protocol. The [HttpServer] is a [Stream] of [HttpRequest]s. Each
+ * [HttpRequest] has an associated [HttpResponse] object as its
+ * [HttpRequest.response] member, and the server responds to a request by
+ * writing to that [HttpResponse] object.
+ *
+ * Incomplete requests where all or parts of the header is missing, are
+ * ignored and no exceptions or [HttpRequest] objects are generated for them.
+ * Likewise, when writing to a [HttpResponse], any [Socket] exceptions are
+ * ignored and any future writes are ignored.
+ *
+ * The [HttpRequest] exposes the request headers, and provides the request body,
+ * if it exists, as a stream of data. If the body is unread, it'll be drained
+ * when the [HttpResponse] is being written to or closed.
+ *
+ * The following example shows how to bind a [HttpServer] to a IPv6
+ * [InternetAddress] on port 80, and listening to requests.
+ *
+ * HttpServer.bind(InternetAddress.ANY_IP_V6, 80).then((server) {
+ * server.listen((HttpRequest request) {
+ * // Handle requests.
+ * });
+ * });
*/
abstract class HttpServer implements Stream<HttpRequest> {
- // TODO(ajohnsen): Document with example, once the stream API is final.
- // TODO(ajohnsen): Add HttpServer.secure.
/**
* Starts listening for HTTP requests on the specified [address] and
* [port].
diff --git a/sdk/lib/io/io_sink.dart b/sdk/lib/io/io_sink.dart
index 4dab40f..351a30b 100644
--- a/sdk/lib/io/io_sink.dart
+++ b/sdk/lib/io/io_sink.dart
@@ -26,7 +26,9 @@
Encoding encoding;
/**
- * Writes the bytes uninterpreted to the consumer.
+ * Writes the bytes uninterpreted to the consumer. While the call is
+ * synchronous, the data may be buffered until the underlying resource is
+ * ready. The data should not be modified after a call to [add].
*/
void add(List<int> data);
diff --git a/sdk/lib/io/link.dart b/sdk/lib/io/link.dart
index 0be5994..4fc0312 100644
--- a/sdk/lib/io/link.dart
+++ b/sdk/lib/io/link.dart
@@ -154,8 +154,8 @@
request[2] = target;
return _fileService.call(request).then((response) {
if (_isErrorResponse(response)) {
- throw _exceptionFromResponse(response,
- "Cannot create link '$path' to target '$target'");
+ throw _exceptionFromResponse(
+ response, "Cannot create link to target '$target'", path);
}
return this;
});
@@ -204,7 +204,7 @@
request[1] = path;
return _fileService.call(request).then((response) {
if (_isErrorResponse(response)) {
- throw _exceptionFromResponse(response, "Cannot delete link '$path'");
+ throw _exceptionFromResponse(response, "Cannot delete link", path);
}
return this;
});
@@ -224,7 +224,7 @@
return _fileService.call(request).then((response) {
if (_isErrorResponse(response)) {
throw _exceptionFromResponse(
- response, "Cannot rename link '$path' to '$newPath'");
+ response, "Cannot rename link to '$newPath'", path);
}
return new Link(newPath);
});
@@ -243,8 +243,8 @@
request[1] = path;
return _fileService.call(request).then((response) {
if (_isErrorResponse(response)) {
- throw _exceptionFromResponse(response,
- "Cannot get target of link '$path'");
+ throw _exceptionFromResponse(
+ response, "Cannot get target of link", path);
}
return response;
});
@@ -272,7 +272,7 @@
}
}
- _exceptionFromResponse(response, String message) {
+ _exceptionFromResponse(response, String message, String path) {
assert(_isErrorResponse(response));
switch (response[_ERROR_RESPONSE_ERROR_TYPE]) {
case _ILLEGAL_ARGUMENT_RESPONSE:
@@ -280,7 +280,7 @@
case _OSERROR_RESPONSE:
var err = new OSError(response[_OSERROR_RESPONSE_MESSAGE],
response[_OSERROR_RESPONSE_ERROR_CODE]);
- return new LinkException(message, err);
+ return new LinkException(message, path, err);
default:
return new Exception("Unknown error");
}
diff --git a/sdk/lib/io/secure_server_socket.dart b/sdk/lib/io/secure_server_socket.dart
index e9da3c6..8ae021e 100644
--- a/sdk/lib/io/secure_server_socket.dart
+++ b/sdk/lib/io/secure_server_socket.dart
@@ -212,9 +212,17 @@
}
void _onData(RawSocket connection) {
+ var remotePort;
+ try {
+ remotePort = connection.remotePort;
+ } catch (e) {
+ // If connection is already closed, remotePort throws an exception.
+ // Do nothing - connection is closed.
+ return;
+ }
_RawSecureSocket.connect(
connection.address,
- connection.remotePort,
+ remotePort,
certificateName,
is_server: true,
socket: connection,
diff --git a/sdk/lib/io/timer_impl.dart b/sdk/lib/io/timer_impl.dart
index 5a7981e..73c7cae 100644
--- a/sdk/lib/io/timer_impl.dart
+++ b/sdk/lib/io/timer_impl.dart
@@ -144,7 +144,8 @@
// null.
if (timer._callback != null) {
timer._callback(timer);
- if (timer._repeating) {
+ // Re-insert repeating timer if not canceled.
+ if (timer._repeating && timer._callback != null) {
timer._advanceWakeupTime();
timer._addTimerToList();
}
diff --git a/sdk/lib/mirrors/mirrors.dart b/sdk/lib/mirrors/mirrors.dart
index e29c225..fd91660 100644
--- a/sdk/lib/mirrors/mirrors.dart
+++ b/sdk/lib/mirrors/mirrors.dart
@@ -1111,21 +1111,19 @@
*
* Example usage:
*
- * [:
- * @MirrorsUsed(symbols: 'foo', override: '*')
- * import 'dart:mirrors';
+ * @MirrorsUsed(symbols: 'foo', override: '*')
+ * import 'dart:mirrors';
*
- * class Foo {
- * noSuchMethod(Invocation invocation) {
- * print(Mirrors.getName(invocation.memberName));
- * }
- * }
+ * class Foo {
+ * noSuchMethod(Invocation invocation) {
+ * print(Mirrors.getName(invocation.memberName));
+ * }
+ * }
*
- * main() {
- * new Foo().foo(); // Prints "foo".
- * new Foo().bar(); // Might print an arbitrary (mangled) name, "bar".
- * }
- * :]
+ * main() {
+ * new Foo().foo(); // Prints "foo".
+ * new Foo().bar(); // Might print an arbitrary (mangled) name, "bar".
+ * }
*/
// TODO(ahe): Remove ", override: '*'" when it isn't necessary anymore.
class MirrorsUsed {
diff --git a/sdk/lib/typed_data/dart2js/typed_data_dart2js.dart b/sdk/lib/typed_data/dart2js/typed_data_dart2js.dart
index 41e2450..b38c130 100644
--- a/sdk/lib/typed_data/dart2js/typed_data_dart2js.dart
+++ b/sdk/lib/typed_data/dart2js/typed_data_dart2js.dart
@@ -1786,7 +1786,7 @@
// -- end List<int> mixins.
}
-class Uint8ClampedList extends Uint8List implements JavaScriptIndexingBehavior, List<int> native "Uint8ClampedArray" {
+class Uint8ClampedList extends Uint8List implements JavaScriptIndexingBehavior, List<int> native "Uint8ClampedArray,CanvasPixelArray" {
factory Uint8ClampedList(int length) =>
_TypedArrayFactoryProvider.createUint8ClampedList(length);
diff --git a/sdk/lib/web_audio/dart2js/web_audio_dart2js.dart b/sdk/lib/web_audio/dart2js/web_audio_dart2js.dart
index a61c68d..3cec0dd 100644
--- a/sdk/lib/web_audio/dart2js/web_audio_dart2js.dart
+++ b/sdk/lib/web_audio/dart2js/web_audio_dart2js.dart
@@ -25,7 +25,7 @@
@DomName('AnalyserNode')
// https://dvcs.w3.org/hg/audio/raw-file/tip/webaudio/specification.html#AnalyserNode
@Experimental
-class AnalyserNode extends AudioNode native "AnalyserNode" {
+class AnalyserNode extends AudioNode native "AnalyserNode,RealtimeAnalyserNode" {
@DomName('AnalyserNode.fftSize')
@DocsEditable
@@ -626,7 +626,7 @@
@DomName('ChannelMergerNode')
// https://dvcs.w3.org/hg/audio/raw-file/tip/webaudio/specification.html#ChannelMergerNode-section
@Experimental
-class ChannelMergerNode extends AudioNode native "ChannelMergerNode" {
+class ChannelMergerNode extends AudioNode native "ChannelMergerNode,AudioChannelMerger" {
}
// 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
@@ -637,7 +637,7 @@
@DomName('ChannelSplitterNode')
// https://dvcs.w3.org/hg/audio/raw-file/tip/webaudio/specification.html#ChannelSplitterNode-section
@Experimental
-class ChannelSplitterNode extends AudioNode native "ChannelSplitterNode" {
+class ChannelSplitterNode extends AudioNode native "ChannelSplitterNode,AudioChannelSplitter" {
}
// 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
@@ -717,7 +717,7 @@
@DomName('GainNode')
// https://dvcs.w3.org/hg/audio/raw-file/tip/webaudio/specification.html#GainNode
@Experimental
-class GainNode extends AudioNode native "GainNode" {
+class GainNode extends AudioNode native "GainNode,AudioGainNode" {
@DomName('GainNode.gain')
@DocsEditable
@@ -811,7 +811,7 @@
@DomName('OscillatorNode')
// https://dvcs.w3.org/hg/audio/raw-file/tip/webaudio/specification.html#dfn-OscillatorNode
@Experimental
-class OscillatorNode extends AudioSourceNode native "OscillatorNode" {
+class OscillatorNode extends AudioSourceNode native "OscillatorNode,Oscillator" {
@DomName('OscillatorNode.CUSTOM')
@DocsEditable
@@ -904,7 +904,7 @@
@DomName('PannerNode')
// https://dvcs.w3.org/hg/audio/raw-file/tip/webaudio/specification.html#PannerNode
@Experimental
-class PannerNode extends AudioNode native "PannerNode" {
+class PannerNode extends AudioNode native "PannerNode,AudioPannerNode" {
@DomName('PannerNode.EQUALPOWER')
@DocsEditable
@@ -994,7 +994,7 @@
@DomName('ScriptProcessorNode')
// https://dvcs.w3.org/hg/audio/raw-file/tip/webaudio/specification.html#ScriptProcessorNode
@Experimental
-class ScriptProcessorNode extends AudioNode native "ScriptProcessorNode" {
+class ScriptProcessorNode extends AudioNode native "ScriptProcessorNode,JavaScriptAudioNode" {
Stream<AudioProcessingEvent> _eventStream;
/**
diff --git a/sdk/lib/web_gl/dart2js/web_gl_dart2js.dart b/sdk/lib/web_gl/dart2js/web_gl_dart2js.dart
index eb14d3a..1858391 100644
--- a/sdk/lib/web_gl/dart2js/web_gl_dart2js.dart
+++ b/sdk/lib/web_gl/dart2js/web_gl_dart2js.dart
@@ -2351,8 +2351,8 @@
@DomName('WebGLRenderingContext.getShaderParameter')
@DocsEditable
- @Creates('int|Null')
- @Returns('int|Null')
+ @Creates('int|bool|Null')
+ @Returns('int|bool|Null')
Object getShaderParameter(Shader shader, int pname) native;
@DomName('WebGLRenderingContext.getShaderPrecisionFormat')
diff --git a/tests/co19/co19-analyzer.status b/tests/co19/co19-analyzer.status
index 98b0881..3a34dff 100644
--- a/tests/co19/co19-analyzer.status
+++ b/tests/co19/co19-analyzer.status
@@ -3,38 +3,29 @@
# BSD-style license that can be found in the LICENSE file.
[ $compiler == dartanalyzer ]
-Language/05_Variables/05_Variables_A05_t04: fail
-Language/06_Functions/2_Formal_Parameters/1_Required_Formals_A02_t06: fail
-Language/06_Functions/2_Formal_Parameters/1_Required_Formals_A02_t07: fail
-Language/06_Functions/2_Formal_Parameters/2_Optional_Formals_A03_t03: fail
+
+# not clear: g([var foo = foo + 10]) is parameter 'foo' in the scope of its own initialzer?
Language/06_Functions/2_Formal_Parameters_A02_t02: fail
+
+# not clear: null..[1](1)[2](2).foo(3, bar: 4)=5 - it seems that verything before =5 it not assignable
Language/07_Classes/6_Constructors/1_Generative_Constructors_A04_t15: fail
+
+# not initialized final instance variable, should be static warning
Language/07_Classes/6_Constructors/1_Generative_Constructors_A09_t01: fail
+
+# invalid argument for constant constructor
Language/07_Classes/6_Constructors/3_Constant_Constructors_A05_t02: fail
-Language/11_Expressions/01_Constants_A16_t01: fail
-Language/11_Expressions/01_Constants_A16_t02: fail
Language/11_Expressions/01_Constants_A16_t03: fail
+
+# final instance variable created instance of the enclosing class
Language/11_Expressions/01_Constants_A17_t03: fail
-Language/11_Expressions/05_Strings_A02_t46: fail
-Language/11_Expressions/05_Strings_A02_t48: fail
-Language/11_Expressions/11_Instance_Creation/1_New_A13_t02: fail
-Language/11_Expressions/11_Instance_Creation_A05_t02: fail
-Language/11_Expressions/22_Equality_A01_t15: fail
-Language/11_Expressions/22_Equality_A01_t16: fail
-Language/13_Libraries_and_Scripts/1_Imports_A05_t01: fail
-Language/13_Libraries_and_Scripts/5_URIs_A01_t24: fail
-Language/13_Libraries_and_Scripts/5_URIs_A01_t25: fail
-Language/14_Types/3_Type_Declarations/1_Typedef_A07_t01: fail
-Language/14_Types/3_Type_Declarations/1_Typedef_A07_t02: fail
-Language/14_Types/3_Type_Declarations/1_Typedef_A07_t03: fail
-Language/14_Types/3_Type_Declarations/1_Typedef_A07_t04: fail
-Language/15_Reference/1_Lexical_Rules/1_Reserved_Words_A40_t04: fail
-Language/15_Reference/1_Lexical_Rules_A02_t06: fail
-
-# fails locally, passes on bot
+# analyzer problem: forward reference of typedef with type parameters
Language/13_Libraries_and_Scripts/3_Parts_A02_t03: skip
+
+
+
# co19 issue #380, Strings class has been removed
LibTest/core/RegExp/Pattern_semantics/firstMatch_CharacterClassEscape_A03_t01: fail, OK
LibTest/core/RegExp/Pattern_semantics/firstMatch_CharacterClassEscape_A04_t01: fail, OK
@@ -104,7 +95,7 @@
Language/11_Expressions/08_Throw_A05_t02: fail, OK
Language/11_Expressions/08_Throw_A05_t03: fail, OK
-# infinite loop
+# analyzer issue https://code.google.com/p/dart/issues/detail?id=11534
Language/14_Types/4_Interface_Types_A11_t01: skip
Language/14_Types/4_Interface_Types_A11_t02: skip
@@ -189,8 +180,28 @@
Language/11_Expressions/33_Argument_Definition_Test_A01_t14: fail, OK
Language/11_Expressions/33_Argument_Definition_Test_A01_t18: fail, OK
-# co19 issue #435, AssertioError has not properties
+# co19 issue #435, AssertionError has not properties
LibTest/core/AssertionError/column_A01_t02: fail, OK
LibTest/core/AssertionError/failedAssertion_A01_t01: fail, OK
LibTest/core/AssertionError/line_A01_t02: fail, OK
LibTest/core/AssertionError/url_A01_t01: fail, OK
+
+# co19 issue #437, annotation should be constant _variable_ or constant constructor invocation
+Language/07_Classes/07_Classes_A01_t20: fail, OK
+Language/07_Classes/07_Classes_A02_t34: fail, OK
+Language/07_Classes/07_Classes_A03_t10: fail, OK
+Language/13_Libraries_and_Scripts/2_Exports_A01_t17: fail, OK
+
+# co19 issue 438, Static variables are initialized lazily, need not be constants
+Language/11_Expressions/01_Constants_A16_t01: fail, OK
+Language/11_Expressions/01_Constants_A16_t02: fail, OK
+
+# co19 issue 439, it is warning, not error to import two different libraries with the same name
+Language/13_Libraries_and_Scripts/1_Imports_A05_t01: fail, OK
+
+# co19 issue #440, adj strings is not a string interpolation
+Language/13_Libraries_and_Scripts/5_URIs_A01_t24: fail, OK
+Language/13_Libraries_and_Scripts/5_URIs_A01_t25: fail, OK
+
+# co19 issue #441, assignment in constructor is not initializing
+Language/05_Variables/05_Variables_A05_t04: fail, OK
diff --git a/tests/co19/co19-dart2dart.status b/tests/co19/co19-dart2dart.status
index 41e881a..8dddc20 100644
--- a/tests/co19/co19-dart2dart.status
+++ b/tests/co19/co19-dart2dart.status
@@ -335,7 +335,6 @@
Language/12_Statements/09_Switch_A06_t02: Fail # Inherited from VM (does not throw NSME).
Language/12_Statements/10_Try_A06_t01: Fail, Pass # Passes in conservative renaming mode. Test depends on function names.
Language/12_Statements/10_Try_A07_t03: Fail # Test depends on out file name.
-Language/12_Statements/10_Try_A11_t01: Fail # Inherited from VM.
Language/12_Statements/11_Return_A05_t01: Fail # Inherited from dart2js
Language/12_Statements/11_Return_A05_t02: Fail # Inherited from dart2js
Language/12_Statements/11_Return_A05_t03: Fail # Inherited from dart2js
diff --git a/tests/co19/co19-runtime.status b/tests/co19/co19-runtime.status
index 9ec08cd..8cae6ca 100644
--- a/tests/co19/co19-runtime.status
+++ b/tests/co19/co19-runtime.status
@@ -2,6 +2,13 @@
# for details. All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE file.
+[ $compiler == none]
+Language/11_Expressions/33_Argument_Definition_Test_A01_t02: Fail, OK # co19 issue 436
+Language/11_Expressions/33_Argument_Definition_Test_A02_t01: Fail, OK # co19 issue 436
+Language/11_Expressions/33_Argument_Definition_Test_A02_t02: Fail, OK # co19 issue 436
+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
+
[ $runtime == vm && $system == windows ]
LibTest/core/Stopwatch/elapsed_A01_t01: Pass, Fail # Issue 11382.
@@ -142,7 +149,6 @@
Language/12_Statements/10_Try_A03_t01: Fail # Dart issue 7311
Language/12_Statements/10_Try_A03_t02: Fail # Dart issue 7311
Language/12_Statements/10_Try_A03_t03: Fail # Dart issue 7311
-Language/12_Statements/10_Try_A11_t01: Fail # Dart issue 430
Language/12_Statements/12_Labels_A01_t03: Fail # Dart issue 2238
Language/13_Libraries_and_Scripts/13_Libraries_and_Scripts_A05_t04: Fail # Dart issue 5839
Language/13_Libraries_and_Scripts/1_Imports_A05_t01: Fail # Dart issue 3206
@@ -161,7 +167,6 @@
LibTest/math/pow_A01_t01: Fail # Dart issue 7318
LibTest/math/pow_A11_t01: Fail # Dart issue 449
LibTest/math/pow_A13_t01: Fail # Dart issue 449
-LibTest/math/sin_A01_t01: Fail # Dart issue 7318
Language/05_Variables/05_Variables_A05_t04: Fail # Dart issue 5881
Language/05_Variables/05_Variables_A05_t11: Fail # Dart issue 5885
@@ -263,7 +268,7 @@
LibTest/core/double/toRadixString_A01_t01: Fail # Issue 463
LibTest/core/int/toRadixString_A01_t01: Fail # Issue 461
-LibTest/math/sin_A01_t01: Fail, OK # Issue co19 - 44
+LibTest/math/sin_A01_t01: Pass, Fail, OK # Issue co19 - 44
LibTest/core/Date/toString_A02_t01: Fail # Argument error. Year 999999 is out of range. Needs to be specified (and then potentially reported to co19): issue 1878.
LibTest/core/Date/year_A01_t01: Fail # Year out of range. Needs to be specified: issue 8808. Possibly a co19 bug.
@@ -480,7 +485,6 @@
[ $compiler == none && $runtime == vm && $mode == debug ]
LibTest/isolate/isolate_api/spawnFunction_A02_t01: Crash
-
[ $compiler == none && $runtime == vm && $system == macos ]
LibTest/math/exp_A01_t01: Fail, OK # Issue co19 - 44
LibTest/math/acos_A01_t01: Fail, OK # Issue co19 - 44
@@ -488,64 +492,35 @@
LibTest/math/atan_A01_t01: Fail, OK # Issue co19 - 44
LibTest/math/tan_A01_t01: Fail, OK # Issue co19 - 44
-
[ $compiler == none && $runtime == vm && $system == linux ]
LibTest/math/exp_A01_t01: Fail
-
-[ $compiler == none && $runtime == vm && $system == linux && $arch == ia32 ]
-LibTest/math/sin_A01_t01: Fail
+[ $compiler == none && $runtime == vm && $system != windows && $arch != x64 && $arch != arm ]
LibTest/math/tan_A01_t01: Fail
-
-[ $compiler == none && $runtime == vm && $arch == x64 && $mode == debug ]
-LibTest/core/Map/Map_class_A01_t04: Skip # Timeout
-
-
-[ $compiler == none && $runtime == vm && $arch == ia32 ]
+[ $compiler == none && $runtime == vm && $arch != x64 ]
LibTest/core/int/operator_left_shift_A01_t02: Fail # co19 issue 129
-[ $compiler == none && $runtime == vm && $arch == arm ]
-LibTest/math/tan_A01_t01: Pass, Fail
-LibTest/math/sin_A01_t01: Pass, Fail
-LibTest/core/int/operator_left_shift_A01_t02: Fail # co19 issue 129
-LibTest/core/int/operator_unary_minus_A01_t01: Pass, Fail
-
-
[ $compiler == none && $runtime == vm && $arch == arm && $mode == debug ]
-LibTest/core/List/sort_A01_t05: Crash
-LibTest/core/List/sort_A01_t06: Crash
+LibTest/core/List/sort_A01_t05: Crash # Too far relative jump.
+LibTest/core/List/sort_A01_t06: Crash # Too far relative jump.
-[ $compiler == none && $runtime == vm && $arch == simarm && $mode == release ]
-LibTest/math/tan_A01_t01: Fail
+[ $compiler == none && $runtime == vm && $arch == simarm ]
LibTest/math/cos_A01_t01: Pass, Fail # Fail on Mac
-LibTest/core/int/operator_left_shift_A01_t02: Fail # co19 issue 129
-LibTest/core/int/operator_unary_minus_A01_t01: Fail
[ $compiler == none && $runtime == vm && $arch == simarm && $mode == debug ]
-LibTest/math/tan_A01_t01: Fail
-LibTest/math/cos_A01_t01: Pass, Fail # Fail on Mac
-LibTest/core/List/sort_A01_t05: Crash
-LibTest/core/List/sort_A01_t06: Crash
-LibTest/core/int/operator_left_shift_A01_t02: Fail # co19 issue 129
-LibTest/core/int/operator_unary_minus_A01_t01: Fail
+LibTest/core/List/sort_A01_t05: Crash # Too far relative jump.
+LibTest/core/List/sort_A01_t06: Crash # Too far relative jump.
+
[ $compiler == none && $runtime == vm && $arch == mips ]
*: Skip
-
-[ $compiler == none && $runtime == vm && $arch == simmips && $mode == release ]
-LibTest/math/tan_A01_t01: Fail
+[ $compiler == none && $runtime == vm && $arch == simmips ]
LibTest/math/cos_A01_t01: Pass, Fail # Fail on Mac
-LibTest/core/int/operator_left_shift_A01_t02: Fail # co19 issue 129
-LibTest/core/int/operator_unary_minus_A01_t01: Fail
[ $compiler == none && $runtime == vm && $arch == simmips && $mode == debug ]
-LibTest/math/tan_A01_t01: Fail
-LibTest/math/cos_A01_t01: Pass, Fail # Fail on Mac
LibTest/core/List/sort_A01_t04: Crash # Too far relative jump.
LibTest/core/List/sort_A01_t05: Crash
LibTest/core/List/sort_A01_t06: Crash
-LibTest/core/int/operator_unary_minus_A01_t01: Fail
-LibTest/core/int/operator_left_shift_A01_t02: Fail # co19 issue 129
diff --git a/tests/compiler/dart2js/analyze_api_test.dart b/tests/compiler/dart2js/analyze_api_test.dart
index e7d7e24..3c5c9e7 100644
--- a/tests/compiler/dart2js/analyze_api_test.dart
+++ b/tests/compiler/dart2js/analyze_api_test.dart
@@ -20,16 +20,13 @@
// TODO(johnniwinther): Support canonical URIs as keys and message kinds as
// values.
const Map<String, List<String>> WHITE_LIST = const {
- 'path_observer.dart':
- const ['Hint: Using "new Symbol"', // Issue 10565.
- ],
'sdk/lib/html/dart2js/html_dart2js.dart':
const ['Hint: The class "Rect" overrides "operator==", '
- 'but not "get hashCode".',
+ 'but not "get hashCode".', // http://dartbug.com/11613
'Hint: The class "Point" overrides "operator==", '
- 'but not "get hashCode".',
+ 'but not "get hashCode".', // http://dartbug.com/11613
'Hint: The class "_ClientRect" overrides "operator==", '
- 'but not "get hashCode".',
+ 'but not "get hashCode".', // http://dartbug.com/11613
],
};
diff --git a/tests/compiler/dart2js/find_my_name_test.dart b/tests/compiler/dart2js/find_my_name_test.dart
index 1c24d17..d5e7d0f 100644
--- a/tests/compiler/dart2js/find_my_name_test.dart
+++ b/tests/compiler/dart2js/find_my_name_test.dart
@@ -7,18 +7,36 @@
import "mock_compiler.dart";
import "parser_helper.dart";
-main() {
- MockCompiler compiler = new MockCompiler();
-
- String code = '''
+String TEST_0 = '''
class Foo {
+ Foo();
+ Foo.named();
+ factory Foo._internal() => null;
operator+(other) => null;
}
''';
- ClassElement foo = parseUnit(code, compiler, compiler.mainApp).head;
- foo.parseNode(compiler);
- for (Element e in foo.localMembers) {
- Expect.equals(code.indexOf(e.name.slowToString()), e.position().charOffset);
+String TEST_1 = '''
+class Bar {
+ const Bar();
+ const Bar.named();
+ Map<int, List<int>> baz() => null;
+}
+''';
+
+main() {
+ MockCompiler compiler = new MockCompiler();
+ testClass(TEST_0, compiler);
+ testClass(TEST_1, compiler);
+}
+
+testClass(String code, MockCompiler compiler) {
+ int skip = code.indexOf('{');
+ ClassElement cls = parseUnit(code, compiler, compiler.mainApp).head;
+ cls.parseNode(compiler);
+ for (Element e in cls.localMembers) {
+ String name = e.name.slowToString();
+ if (e.isConstructor()) name = name.replaceFirst(r'$', '.');
+ Expect.equals(code.indexOf(name, skip), e.position().charOffset);
}
}
diff --git a/tests/compiler/dart2js/type_equals_test.dart b/tests/compiler/dart2js/type_equals_test.dart
index 0c283db..2493d8c 100644
--- a/tests/compiler/dart2js/type_equals_test.dart
+++ b/tests/compiler/dart2js/type_equals_test.dart
@@ -8,7 +8,7 @@
import "parser_helper.dart";
bool test(compiler, String name1, String name2, {bool expect}) {
- Expect.isTrue(?expect, 'required parameter "expect" not given');
+ Expect.isTrue((expect != null), 'required parameter "expect" not given');
var clazz = findElement(compiler, "Class");
clazz.ensureResolved(compiler);
var element1 = clazz.buildScope().lookup(buildSourceString(name1));
diff --git a/tests/corelib/apply_test.dart b/tests/corelib/apply_test.dart
index d872227..e06cf6d 100644
--- a/tests/corelib/apply_test.dart
+++ b/tests/corelib/apply_test.dart
@@ -16,9 +16,6 @@
int test2(int i, int j) => i + j;
int test2a(int i, int j, {int a}) => i + j + a;
-bool testPassed1([int x]) => ?x;
-bool testPassedX({int x}) => ?x;
-
class C {
int x = 10;
int foo(y) => this.x + y;
@@ -60,14 +57,6 @@
testList(42, test2, [20, 22]);
test(42, test2a, [10, 15], {"a" : 17});
- testList(false, testPassed1, null);
- testList(false, testPassed1, []);
- testList(true, testPassed1, [42]);
-
- testMap(false, testPassedX, null);
- testMap(false, testPassedX, {});
- testMap(true, testPassedX, {"x": 42});
-
// Test that "this" is correct when calling closurized functions.
var cfoo = new C().foo;
testList(42, cfoo, [32]);
diff --git a/tests/corelib/corelib.status b/tests/corelib/corelib.status
index 7a3c170..77edb53 100644
--- a/tests/corelib/corelib.status
+++ b/tests/corelib/corelib.status
@@ -53,11 +53,6 @@
string_replace_func_test: Skip # Bug 6554 - doesn't terminate.
-[ $compiler == dart2js || $compiler == dart2dart ]
-apply_test: Fail, OK # Depends on ?parameter check.
-iterable_join_test: Fail, OK # Depends on ?parameter check.
-list_fill_range_test: Fail, OK # Depends on ?parameter check.
-
[ $compiler == dart2js && $runtime == none ]
*: Fail, Pass # TODO(ahe): Triage these tests.
@@ -108,6 +103,9 @@
list_insert_test: fail
list_removeat_test: fail
+[ $arch == arm ]
+collection_to_string_test: Pass, Crash # Issue: 11207
+
[ $arch == simarm && $mode == debug ]
collection_to_string_test: Pass, Crash # Issue: 11207
@@ -119,7 +117,7 @@
[ $arch == simmips && $checked ]
hash_map2_test: Crash # Too far PC relative branch.
-collection_length_test: Skip # Timeout.
+collection_length_test: Pass, Timeout
[ $arch == simmips && $mode == debug ]
collection_to_string_test: Pass, Crash # Issue: 11207
diff --git a/tests/corelib/iterable_join_test.dart b/tests/corelib/iterable_join_test.dart
index e374be4..d2c750f 100644
--- a/tests/corelib/iterable_join_test.dart
+++ b/tests/corelib/iterable_join_test.dart
@@ -9,8 +9,8 @@
String toString() => "${count++}";
}
-testJoin(String expect, Iterable iterable, [String separator = ""]) {
- if (?separator) {
+testJoin(String expect, Iterable iterable, [String separator]) {
+ if (separator != null) {
Expect.equals(expect, iterable.join(separator));
} else {
Expect.equals(expect, iterable.join());
diff --git a/tests/corelib/linked_hash_map_from_iterable_test.dart b/tests/corelib/linked_hash_map_from_iterable_test.dart
new file mode 100644
index 0000000..d581532
--- /dev/null
+++ b/tests/corelib/linked_hash_map_from_iterable_test.dart
@@ -0,0 +1,118 @@
+// 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";
+import 'dart:collection';
+
+main() {
+ defaultFunctionValuesTest();
+ defaultKeyFunctionTest();
+ defaultValueFunctionTest();
+ noDefaultValuesTest();
+ emptyIterableTest();
+ equalElementsTest();
+ genericTypeTest();
+}
+
+void defaultFunctionValuesTest() {
+ var map = new LinkedHashMap.fromIterable([1, 2, 3]);
+
+ Expect.isTrue(map is Map);
+ Expect.isTrue(map is LinkedHashMap);
+ Expect.isFalse(map is HashMap);
+
+ Expect.equals(3, map.length);
+ Expect.equals(3, map.keys.length);
+ Expect.equals(3, map.values.length);
+
+ Expect.equals(1, map[1]);
+ Expect.equals(2, map[2]);
+ Expect.equals(3, map[3]);
+}
+
+void defaultKeyFunctionTest() {
+ var map = new LinkedHashMap.fromIterable([1, 2, 3], value: (x) => x + 1);
+
+ Expect.isTrue(map is Map);
+ Expect.isTrue(map is LinkedHashMap);
+ Expect.isFalse(map is HashMap);
+
+ Expect.equals(3, map.length);
+ Expect.equals(3, map.keys.length);
+ Expect.equals(3, map.values.length);
+
+ Expect.equals(2, map[1]);
+ Expect.equals(3, map[2]);
+ Expect.equals(4, map[3]);
+}
+
+void defaultValueFunctionTest() {
+ var map = new LinkedHashMap.fromIterable([1, 2, 3], key: (x) => x + 1);
+
+ Expect.isTrue(map is Map);
+ Expect.isTrue(map is LinkedHashMap);
+ Expect.isFalse(map is HashMap);
+
+ Expect.equals(3, map.length);
+ Expect.equals(3, map.keys.length);
+ Expect.equals(3, map.values.length);
+
+ Expect.equals(1, map[2]);
+ Expect.equals(2, map[3]);
+ Expect.equals(3, map[4]);
+}
+
+void noDefaultValuesTest() {
+ var map = new LinkedHashMap.fromIterable([1, 2, 3],
+ key: (x) => x + 1, value: (x) => x - 1);
+
+ Expect.isTrue(map is Map);
+ Expect.isTrue(map is LinkedHashMap);
+ Expect.isFalse(map is HashMap);
+
+ Expect.equals(3, map.length);
+ Expect.equals(3, map.keys.length);
+ Expect.equals(3, map.values.length);
+
+ Expect.equals(0, map[2]);
+ Expect.equals(1, map[3]);
+ Expect.equals(2, map[4]);
+}
+
+void emptyIterableTest() {
+ var map = new LinkedHashMap.fromIterable([]);
+ Expect.isTrue(map is Map);
+ Expect.isTrue(map is LinkedHashMap);
+ Expect.isFalse(map is HashMap);
+
+ Expect.equals(0, map.length);
+ Expect.equals(0, map.keys.length);
+ Expect.equals(0, map.values.length);
+}
+
+void equalElementsTest() {
+ var map = new LinkedHashMap.fromIterable([1, 2, 2], key: (x) => x + 1);
+
+ Expect.isTrue(map is Map);
+ Expect.isTrue(map is LinkedHashMap);
+ Expect.isFalse(map is HashMap);
+
+ Expect.equals(2, map.length);
+ Expect.equals(2, map.keys.length);
+ Expect.equals(2, map.values.length);
+
+ Expect.equals(1, map[2]);
+ Expect.equals(2, map[3]);
+}
+
+void genericTypeTest() {
+ var map = new LinkedHashMap<int, String>.fromIterable([1, 2, 3], value: (x) => '$x');
+ Expect.isTrue(map is Map<int, String>);
+ Expect.isTrue(map is LinkedHashMap<int, String>);
+
+ // Make sure it is not just LinkedHashMap<dynamic, dynamic>.
+ Expect.isFalse(map is LinkedHashMap<String, dynamic>);
+ Expect.isFalse(map is LinkedHashMap<dynamic, int>);
+}
+
diff --git a/tests/corelib/linked_hash_map_from_iterables_test.dart b/tests/corelib/linked_hash_map_from_iterables_test.dart
new file mode 100644
index 0000000..0212dd4
--- /dev/null
+++ b/tests/corelib/linked_hash_map_from_iterables_test.dart
@@ -0,0 +1,83 @@
+// 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";
+import 'dart:collection';
+
+main() {
+ positiveTest();
+ emptyMapTest();
+ fewerKeysIterableTest();
+ fewerValuesIterableTest();
+ equalElementsTest();
+ genericTypeTest();
+}
+
+void positiveTest() {
+ var map = new LinkedHashMap.fromIterables([1, 2, 3], ["one", "two", "three"]);
+ Expect.isTrue(map is Map);
+ Expect.isTrue(map is LinkedHashMap);
+ Expect.isFalse(map is HashMap);
+
+ Expect.equals(3, map.length);
+ Expect.equals(3, map.keys.length);
+ Expect.equals(3, map.values.length);
+
+ Expect.equals("one", map[1]);
+ Expect.equals("two", map[2]);
+ Expect.equals("three", map[3]);
+}
+
+void emptyMapTest() {
+ var map = new LinkedHashMap.fromIterables([], []);
+ Expect.isTrue(map is Map);
+ Expect.isTrue(map is LinkedHashMap);
+ Expect.isFalse(map is HashMap);
+
+ Expect.equals(0, map.length);
+ Expect.equals(0, map.keys.length);
+ Expect.equals(0, map.values.length);
+}
+
+void fewerValuesIterableTest() {
+ Expect.throws(() => new LinkedHashMap.fromIterables([1,2], [0]));
+}
+
+void fewerKeysIterableTest() {
+ Expect.throws(() => new LinkedHashMap.fromIterables([1], [0,2]));
+}
+
+void equalElementsTest() {
+ var map = new LinkedHashMap.fromIterables([1, 2, 2], ["one", "two", "three"]);
+ Expect.isTrue(map is Map);
+ Expect.isTrue(map is LinkedHashMap);
+ Expect.isFalse(map is HashMap);
+
+ Expect.equals(2, map.length);
+ Expect.equals(2, map.keys.length);
+ Expect.equals(2, map.values.length);
+
+ Expect.equals("one", map[1]);
+ Expect.equals("three", map[2]);
+}
+
+
+void genericTypeTest() {
+ var map = new LinkedHashMap<int, String>.fromIterables(
+ [1, 2, 3], ["one", "two", "three"]);
+ Expect.isTrue(map is Map<int, String>);
+ Expect.isTrue(map is LinkedHashMap<int, String>);
+
+ // Make sure it is not just LinkedHashMap<dynamic, dynamic>.
+ Expect.isFalse(map is LinkedHashMap<String, dynamic>);
+ Expect.isFalse(map is LinkedHashMap<dynamic, int>);
+
+ Expect.equals(3, map.length);
+ Expect.equals(3, map.keys.length);
+ Expect.equals(3, map.values.length);
+
+ Expect.equals("one", map[1]);
+ Expect.equals("two", map[2]);
+ Expect.equals("three", map[3]);
+}
diff --git a/tests/corelib/list_fill_range_test.dart b/tests/corelib/list_fill_range_test.dart
index cd0e023..4553e43 100644
--- a/tests/corelib/list_fill_range_test.dart
+++ b/tests/corelib/list_fill_range_test.dart
@@ -7,11 +7,7 @@
test(List list, int start, int end, [fillValue]) {
List copy = list.toList();
- if (?fillValue) {
- list.fillRange(start, end, fillValue);
- } else {
- list.fillRange(start, end, fillValue);
- }
+ list.fillRange(start, end, fillValue);
Expect.equals(copy.length, list.length);
for (int i = 0; i < start; i++) {
Expect.equals(copy[i], list[i]);
diff --git a/tests/corelib/map_from_iterable_test.dart b/tests/corelib/map_from_iterable_test.dart
new file mode 100644
index 0000000..4d0468d
--- /dev/null
+++ b/tests/corelib/map_from_iterable_test.dart
@@ -0,0 +1,112 @@
+// 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";
+import 'dart:collection';
+
+main() {
+ defaultFunctionValuesTest();
+ defaultKeyFunctionTest();
+ defaultValueFunctionTest();
+ noDefaultValuesTest();
+ emptyIterableTest();
+ equalElementsTest();
+ genericTypeTest();
+}
+
+void defaultFunctionValuesTest() {
+ var map = new Map.fromIterable([1, 2, 3]);
+
+ Expect.isTrue(map is Map);
+ Expect.isTrue(map is HashMap);
+
+ Expect.equals(3, map.length);
+ Expect.equals(3, map.keys.length);
+ Expect.equals(3, map.values.length);
+
+ Expect.equals(1, map[1]);
+ Expect.equals(2, map[2]);
+ Expect.equals(3, map[3]);
+}
+
+void defaultKeyFunctionTest() {
+ var map = new Map.fromIterable([1, 2, 3], value: (x) => x + 1);
+
+ Expect.isTrue(map is Map);
+ Expect.isTrue(map is HashMap);
+
+ Expect.equals(3, map.length);
+ Expect.equals(3, map.keys.length);
+ Expect.equals(3, map.values.length);
+
+ Expect.equals(2, map[1]);
+ Expect.equals(3, map[2]);
+ Expect.equals(4, map[3]);
+}
+
+void defaultValueFunctionTest() {
+ var map = new Map.fromIterable([1, 2, 3], key: (x) => x + 1);
+
+ Expect.isTrue(map is Map);
+ Expect.isTrue(map is HashMap);
+
+ Expect.equals(3, map.length);
+ Expect.equals(3, map.keys.length);
+ Expect.equals(3, map.values.length);
+
+ Expect.equals(1, map[2]);
+ Expect.equals(2, map[3]);
+ Expect.equals(3, map[4]);
+}
+
+void noDefaultValuesTest() {
+ var map = new Map.fromIterable([1, 2, 3],
+ key: (x) => x + 1, value: (x) => x - 1);
+
+
+ Expect.isTrue(map is Map);
+ Expect.isTrue(map is HashMap);
+
+ Expect.equals(3, map.length);
+ Expect.equals(3, map.keys.length);
+ Expect.equals(3, map.values.length);
+
+ Expect.equals(0, map[2]);
+ Expect.equals(1, map[3]);
+ Expect.equals(2, map[4]);
+}
+
+void emptyIterableTest() {
+ var map = new Map.fromIterable([]);
+ Expect.isTrue(map is Map);
+ Expect.isTrue(map is HashMap);
+
+ Expect.equals(0, map.length);
+ Expect.equals(0, map.keys.length);
+ Expect.equals(0, map.values.length);
+}
+
+void equalElementsTest() {
+ var map = new Map.fromIterable([1, 2, 2], key: (x) => x + 1);
+
+ Expect.isTrue(map is Map);
+ Expect.isTrue(map is HashMap);
+
+ Expect.equals(2, map.length);
+ Expect.equals(2, map.keys.length);
+ Expect.equals(2, map.values.length);
+
+ Expect.equals(1, map[2]);
+ Expect.equals(2, map[3]);
+}
+
+void genericTypeTest() {
+ var map = new Map<int, String>.fromIterable([1, 2, 3], value: (x) => '$x');
+ Expect.isTrue(map is Map<int, String>);
+
+ // Make sure it is not just Map<dynamic, dynamic>.
+ Expect.isFalse(map is Map<String, dynamic>);
+ Expect.isFalse(map is Map<dynamic, int>);
+}
+
diff --git a/tests/corelib/map_from_iterables_test.dart b/tests/corelib/map_from_iterables_test.dart
new file mode 100644
index 0000000..8c21e9f
--- /dev/null
+++ b/tests/corelib/map_from_iterables_test.dart
@@ -0,0 +1,79 @@
+// 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";
+import 'dart:collection';
+
+main() {
+ positiveTest();
+ emptyMapTest();
+ fewerKeysIterableTest();
+ fewerValuesIterableTest();
+ equalElementsTest();
+ genericTypeTest();
+}
+
+void positiveTest() {
+ var map = new Map.fromIterables([1, 2, 3], ["one", "two", "three"]);
+ Expect.isTrue(map is Map);
+ Expect.isTrue(map is HashMap);
+
+ Expect.equals(3, map.length);
+ Expect.equals(3, map.keys.length);
+ Expect.equals(3, map.values.length);
+
+ Expect.equals("one", map[1]);
+ Expect.equals("two", map[2]);
+ Expect.equals("three", map[3]);
+}
+
+void emptyMapTest() {
+ var map = new Map.fromIterables([], []);
+ Expect.isTrue(map is Map);
+ Expect.isTrue(map is HashMap);
+
+ Expect.equals(0, map.length);
+ Expect.equals(0, map.keys.length);
+ Expect.equals(0, map.values.length);
+}
+
+void fewerValuesIterableTest() {
+ Expect.throws(() => new Map.fromIterables([1,2], [0]));
+}
+
+void fewerKeysIterableTest() {
+ Expect.throws(() => new Map.fromIterables([1], [0,2]));
+}
+
+void equalElementsTest() {
+ var map = new Map.fromIterables([1, 2, 2], ["one", "two", "three"]);
+ Expect.isTrue(map is Map);
+ Expect.isTrue(map is HashMap);
+
+ Expect.equals(2, map.length);
+ Expect.equals(2, map.keys.length);
+ Expect.equals(2, map.values.length);
+
+ Expect.equals("one", map[1]);
+ Expect.equals("three", map[2]);
+}
+
+
+void genericTypeTest() {
+ var map = new Map<int, String>.fromIterables(
+ [1, 2, 3], ["one", "two", "three"]);
+ Expect.isTrue(map is Map<int, String>);
+
+ // Make sure it is not just Map<dynamic, dynamic>.
+ Expect.isFalse(map is Map<String, dynamic>);
+ Expect.isFalse(map is Map<dynamic, int>);
+
+ Expect.equals(3, map.length);
+ Expect.equals(3, map.keys.length);
+ Expect.equals(3, map.values.length);
+
+ Expect.equals("one", map[1]);
+ Expect.equals("two", map[2]);
+ Expect.equals("three", map[3]);
+}
diff --git a/tests/corelib/splay_tree_from_iterable_test.dart b/tests/corelib/splay_tree_from_iterable_test.dart
new file mode 100644
index 0000000..18d0106
--- /dev/null
+++ b/tests/corelib/splay_tree_from_iterable_test.dart
@@ -0,0 +1,119 @@
+// 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";
+import 'dart:collection';
+
+main() {
+ defaultFunctionValuesTest();
+ defaultKeyFunctionTest();
+ defaultValueFunctionTest();
+ noDefaultValuesTest();
+ emptyIterableTest();
+ equalElementsTest();
+ genericTypeTest();
+}
+
+void defaultFunctionValuesTest() {
+ var map = new SplayTreeMap.fromIterable([1, 2, 3]);
+
+ Expect.isTrue(map is Map);
+ Expect.isTrue(map is SplayTreeMap);
+ Expect.isFalse(map is HashMap);
+
+ Expect.equals(3, map.length);
+ Expect.equals(3, map.keys.length);
+ Expect.equals(3, map.values.length);
+
+ Expect.equals(1, map[1]);
+ Expect.equals(2, map[2]);
+ Expect.equals(3, map[3]);
+}
+
+void defaultKeyFunctionTest() {
+ var map = new SplayTreeMap.fromIterable([1, 2, 3], value: (x) => x + 1);
+
+ Expect.isTrue(map is Map);
+ Expect.isTrue(map is SplayTreeMap);
+ Expect.isFalse(map is HashMap);
+
+ Expect.equals(3, map.length);
+ Expect.equals(3, map.keys.length);
+ Expect.equals(3, map.values.length);
+
+ Expect.equals(2, map[1]);
+ Expect.equals(3, map[2]);
+ Expect.equals(4, map[3]);
+}
+
+void defaultValueFunctionTest() {
+ var map = new SplayTreeMap.fromIterable([1, 2, 3], key: (x) => x + 1);
+
+ Expect.isTrue(map is Map);
+ Expect.isTrue(map is SplayTreeMap);
+ Expect.isFalse(map is HashMap);
+
+ Expect.equals(3, map.length);
+ Expect.equals(3, map.keys.length);
+ Expect.equals(3, map.values.length);
+
+ Expect.equals(1, map[2]);
+ Expect.equals(2, map[3]);
+ Expect.equals(3, map[4]);
+}
+
+void noDefaultValuesTest() {
+ var map = new SplayTreeMap.fromIterable([1, 2, 3],
+ key: (x) => x + 1, value: (x) => x - 1);
+
+ Expect.isTrue(map is Map);
+ Expect.isTrue(map is SplayTreeMap);
+ Expect.isFalse(map is HashMap);
+
+ Expect.equals(3, map.length);
+ Expect.equals(3, map.keys.length);
+ Expect.equals(3, map.values.length);
+
+ Expect.equals(0, map[2]);
+ Expect.equals(1, map[3]);
+ Expect.equals(2, map[4]);
+}
+
+void emptyIterableTest() {
+ var map = new SplayTreeMap.fromIterable([]);
+
+ Expect.isTrue(map is Map);
+ Expect.isTrue(map is SplayTreeMap);
+ Expect.isFalse(map is HashMap);
+
+ Expect.equals(0, map.length);
+ Expect.equals(0, map.keys.length);
+ Expect.equals(0, map.values.length);
+}
+
+void equalElementsTest() {
+ var map = new SplayTreeMap.fromIterable([1, 2, 2], key: (x) => x + 1);
+
+ Expect.isTrue(map is Map);
+ Expect.isTrue(map is SplayTreeMap);
+ Expect.isFalse(map is HashMap);
+
+ Expect.equals(2, map.length);
+ Expect.equals(2, map.keys.length);
+ Expect.equals(2, map.values.length);
+
+ Expect.equals(1, map[2]);
+ Expect.equals(2, map[3]);
+}
+
+void genericTypeTest() {
+ var map = new SplayTreeMap<int, String>.fromIterable([1, 2, 3], value: (x) => '$x');
+ Expect.isTrue(map is Map<int, String>);
+ Expect.isTrue(map is SplayTreeMap<int, String>);
+
+ // Make sure it is not just SplayTreeMap<dynamic, dynamic>.
+ Expect.isFalse(map is SplayTreeMap<String, dynamic>);
+ Expect.isFalse(map is SplayTreeMap<dynamic, int>);
+}
+
diff --git a/tests/corelib/splay_tree_from_iterables_test.dart b/tests/corelib/splay_tree_from_iterables_test.dart
new file mode 100644
index 0000000..5ac195f
--- /dev/null
+++ b/tests/corelib/splay_tree_from_iterables_test.dart
@@ -0,0 +1,86 @@
+// 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";
+import 'dart:collection';
+
+main() {
+ positiveTest();
+ emptyMapTest();
+ fewerKeysIterableTest();
+ fewerValuesIterableTest();
+ equalElementsTest();
+ genericTypeTest();
+}
+
+void positiveTest() {
+ var map = new SplayTreeMap.fromIterables([1, 2, 3], ["one", "two", "three"]);
+
+ Expect.isTrue(map is Map);
+ Expect.isTrue(map is SplayTreeMap);
+ Expect.isFalse(map is HashMap);
+
+ Expect.equals(3, map.length);
+ Expect.equals(3, map.keys.length);
+ Expect.equals(3, map.values.length);
+
+ Expect.equals("one", map[1]);
+ Expect.equals("two", map[2]);
+ Expect.equals("three", map[3]);
+}
+
+void emptyMapTest() {
+ var map = new SplayTreeMap.fromIterables([], []);
+
+ Expect.isTrue(map is Map);
+ Expect.isTrue(map is SplayTreeMap);
+ Expect.isFalse(map is HashMap);
+
+ Expect.equals(0, map.length);
+ Expect.equals(0, map.keys.length);
+ Expect.equals(0, map.values.length);
+}
+
+void fewerValuesIterableTest() {
+ Expect.throws(() => new SplayTreeMap.fromIterables([1,2], [0]));
+}
+
+void fewerKeysIterableTest() {
+ Expect.throws(() => new SplayTreeMap.fromIterables([1], [0,2]));
+}
+
+void equalElementsTest() {
+ var map = new SplayTreeMap.fromIterables([1, 2, 2], ["one", "two", "three"]);
+
+ Expect.isTrue(map is Map);
+ Expect.isTrue(map is SplayTreeMap);
+ Expect.isFalse(map is HashMap);
+
+ Expect.equals(2, map.length);
+ Expect.equals(2, map.keys.length);
+ Expect.equals(2, map.values.length);
+
+ Expect.equals("one", map[1]);
+ Expect.equals("three", map[2]);
+}
+
+
+void genericTypeTest() {
+ var map = new SplayTreeMap<int, String>.fromIterables(
+ [1, 2, 3], ["one", "two", "three"]);
+ Expect.isTrue(map is Map<int, String>);
+ Expect.isTrue(map is SplayTreeMap<int, String>);
+
+ // Make sure it is not just SplayTreeMap<dynamic, dynamic>.
+ Expect.isFalse(map is SplayTreeMap<String, dynamic>);
+ Expect.isFalse(map is SplayTreeMap<dynamic, int>);
+
+ Expect.equals(3, map.length);
+ Expect.equals(3, map.keys.length);
+ Expect.equals(3, map.values.length);
+
+ Expect.equals("one", map[1]);
+ Expect.equals("two", map[2]);
+ Expect.equals("three", map[3]);
+}
diff --git a/tests/html/html.status b/tests/html/html.status
index 9aa3976..e16c75d 100644
--- a/tests/html/html.status
+++ b/tests/html/html.status
@@ -308,6 +308,7 @@
websql_test/supported: Fail
[ $runtime == ff ]
+xhr_test/xhr: Pass, Fail # Issue 11602
dart_object_local_storage_test: Skip # sessionStorage NS_ERROR_DOM_NOT_SUPPORTED_ERR
dromaeo_smoke_test: Pass, Fail # Issue: 8257
webgl_1_test: Pass, Fail # Issue 8219
diff --git a/tests/html/indexeddb_1_test.dart b/tests/html/indexeddb_1_test.dart
index 7fb41fb..63b9156 100644
--- a/tests/html/indexeddb_1_test.dart
+++ b/tests/html/indexeddb_1_test.dart
@@ -27,9 +27,8 @@
}).then((_) {
return html.window.indexedDB.open(dbName, version: 2,
onUpgradeNeeded: (e) {
- // Bug 8265, we're getting the wrong type here.
- //expect(e.oldVersion, 1);
- //expect(e.newVersion, 2);
+ expect(e.oldVersion, 1);
+ expect(e.newVersion, 2);
upgraded = true;
});
}).then((_) {
diff --git a/tests/html/safe_dom_test.dart b/tests/html/safe_dom_test.dart
index 5e7ae35..686c4e0 100644
--- a/tests/html/safe_dom_test.dart
+++ b/tests/html/safe_dom_test.dart
@@ -76,8 +76,8 @@
} else {
contextElement.innerHtml = html;
var fragment = new DocumentFragment();;
- while (contextElement.$dom_firstChild != null) {
- fragment.append(contextElement.$dom_firstChild);
+ while (contextElement.firstChild != null) {
+ fragment.append(contextElement.firstChild);
}
return fragment;
}
diff --git a/tests/language/allocation_sinking_vm_test.dart b/tests/language/allocation_sinking_vm_test.dart
index 2320df3..89ad287 100644
--- a/tests/language/allocation_sinking_vm_test.dart
+++ b/tests/language/allocation_sinking_vm_test.dart
@@ -103,6 +103,41 @@
return a.x - a.y;
}
+class WithFinal {
+ final _x;
+ WithFinal(this._x);
+}
+
+testInitialValueForFinalField(x) {
+ new WithFinal(x);
+}
+
+testFinalField() {
+ for (var i = 0; i < 10000; i++) {
+ testInitialValueForFinalField(1);
+ }
+}
+
+class V {
+ var x = 0;
+}
+
+test_vm_field() {
+ var obj;
+ inner() => obj.x = 42;
+ var a = new V();
+ obj = a;
+ var t1 = a.x;
+ var t2 = inner();
+ return a.x + t1 + t2;
+}
+
+testVMField() {
+ Expect.equals(84, test_vm_field());
+ for (var i=0; i<15000; i++) test_vm_field();
+ Expect.equals(84, test_vm_field());
+}
+
main() {
var c = new C(new Point(0.1, 0.2));
@@ -147,4 +182,7 @@
final z2 = testIdentity(new F(c.p));
Expect.equals(z0, z1);
Expect.equals(z0, z2);
+
+ testFinalField();
+ testVMField();
}
diff --git a/tests/language/argument_definition2_test.dart b/tests/language/argument_definition2_test.dart
deleted file mode 100644
index cd458f0..0000000
--- a/tests/language/argument_definition2_test.dart
+++ /dev/null
@@ -1,82 +0,0 @@
-// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import "package:expect/expect.dart";
-
-test1(bool passed, [a = 42]) {
- if (passed) {
- Expect.equals(54, a);
- Expect.isTrue(?a);
- } else {
- Expect.equals(42, a);
- Expect.isFalse(?a);
- }
- Expect.isTrue(?passed);
-}
-
-test2() {
- var closure = (passed, [a = 42]) {
- if (passed) {
- Expect.equals(54, a);
- Expect.isTrue(?a);
- } else {
- Expect.equals(42, a);
- Expect.isFalse(?a);
- }
- Expect.isTrue(?passed);
- };
- closure(true, 54);
- closure(false);
-}
-
-class A {
- test3(bool passed, [a = 42]) {
- if (passed) {
- Expect.equals(54, a);
- Expect.isTrue(?a);
- } else {
- Expect.equals(42, a);
- Expect.isFalse(?a);
- }
- Expect.isTrue(?passed);
- }
-}
-
-
-test4(bool passed, [a]) {
- if (passed) {
- Expect.equals(54, a);
- Expect.isTrue(?a);
- } else {
- Expect.equals(null, a);
- Expect.isFalse(?a);
- }
- Expect.isTrue(?passed);
-}
-
-int inscrutable(int x) => x == 0 ? 0 : x | inscrutable(x & (x - 1));
-
-main() {
- test1(true, 54);
- test1(false);
- test2();
- new A().test3(true, 54);
- new A().test3(false);
-
- var things = [test1, test2, new A().test3];
-
- var closure = things[inscrutable(0)];
- closure(true, 54);
- closure(false);
-
- closure = things[inscrutable(1)];
- closure();
-
- closure = things[inscrutable(2)];
- closure(true, 54);
- closure(false);
-
- test4(true, 54);
- test4(false);
-}
diff --git a/tests/language/argument_definition3_test.dart b/tests/language/argument_definition3_test.dart
deleted file mode 100644
index 0f9a125..0000000
--- a/tests/language/argument_definition3_test.dart
+++ /dev/null
@@ -1,78 +0,0 @@
-// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import "package:expect/expect.dart";
-
-main() {
- new Param.test1(false);
- new Param.test1(true, 42);
-
- new Param.test2(false);
- new Param.test2(true, 42);
-
- new Param.test3(false);
- new Param.test3(true, 42);
-
- new Param.test4();
- new Param.test5();
-
- new Param.test6(false);
- new Param.test6(true, 42);
-
- new Param.test7();
- new Param.test8();
-}
-
-class Super {
- var superField;
- var otherSuperField;
-
- Super();
- Super.withParameters(passed, op, value) {
- Expect.equals(passed, op);
- Expect.equals(passed ? 42 : 0, value);
- }
-
- Super.withOptional(passed, [int a]) : superField = ?a {
- Expect.equals(passed, ?a);
- Expect.equals(passed, superField);
- }
-
- Super.withUpdate(passed, [int a = 0])
- : superField = ?a, otherSuperField = a++ {
- Expect.equals(passed, ?a);
- Expect.equals(passed, superField);
- Expect.equals(passed ? 43 : 1, a);
- }
-}
-
-class Param extends Super {
- var field;
- var otherField;
-
- Param.test1(a_check, [int a]) {
- Expect.equals(a_check, ?a);
- }
-
- Param.test2(passed, [int a]) : field = ?a {
- Expect.equals(passed, ?a);
- Expect.equals(passed, field);
- }
-
- Param.test3(passed, [int a = 0]) : super.withParameters(passed, ?a, a) {
- Expect.equals(passed, ?a);
- }
-
- Param.test4() : super.withOptional(true, 42);
- Param.test5() : super.withOptional(false);
-
- Param.test6(passed, [int a = 0]) : field = ?a, otherField = a++ {
- Expect.equals(passed, ?a);
- Expect.equals(passed, field);
- Expect.equals(passed ? 43 : 1, a);
- }
-
- Param.test7() : super.withUpdate(true, 42);
- Param.test8() : super.withUpdate(false);
-}
diff --git a/tests/language/argument_definition4_test.dart b/tests/language/argument_definition4_test.dart
deleted file mode 100644
index 69ed794..0000000
--- a/tests/language/argument_definition4_test.dart
+++ /dev/null
@@ -1,82 +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 "package:expect/expect.dart";
-
-test1(bool passed, {a: 42}) {
- if (passed) {
- Expect.equals(54, a);
- Expect.isTrue(?a);
- } else {
- Expect.equals(42, a);
- Expect.isFalse(?a);
- }
- Expect.isTrue(?passed);
-}
-
-test2() {
- var closure = (passed, {a: 42}) {
- if (passed) {
- Expect.equals(54, a);
- Expect.isTrue(?a);
- } else {
- Expect.equals(42, a);
- Expect.isFalse(?a);
- }
- Expect.isTrue(?passed);
- };
- closure(true, a:54);
- closure(false);
-}
-
-class A {
- test3(bool passed, {a: 42}) {
- if (passed) {
- Expect.equals(54, a);
- Expect.isTrue(?a);
- } else {
- Expect.equals(42, a);
- Expect.isFalse(?a);
- }
- Expect.isTrue(?passed);
- }
-}
-
-
-test4(bool passed, {a}) {
- if (passed) {
- Expect.equals(54, a);
- Expect.isTrue(?a);
- } else {
- Expect.equals(null, a);
- Expect.isFalse(?a);
- }
- Expect.isTrue(?passed);
-}
-
-int inscrutable(int x) => x == 0 ? 0 : x | inscrutable(x & (x - 1));
-
-main() {
- test1(true, a:54);
- test1(false);
- test2();
- new A().test3(true, a:54);
- new A().test3(false);
-
- var things = [test1, test2, new A().test3];
-
- var closure = things[inscrutable(0)];
- closure(true, a:54);
- closure(false);
-
- closure = things[inscrutable(1)];
- closure();
-
- closure = things[inscrutable(2)];
- closure(true, a:54);
- closure(false);
-
- test4(true, a:54);
- test4(false);
-}
diff --git a/tests/language/argument_definition5_test.dart b/tests/language/argument_definition5_test.dart
deleted file mode 100644
index ae8af0a..0000000
--- a/tests/language/argument_definition5_test.dart
+++ /dev/null
@@ -1,33 +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 "package:expect/expect.dart";
-
-var x = "";
-
-test(String str, [onError(String)]) {
- return (() {
- try {
- throw "";
- } catch(e) {
- if (?onError) {
- onError(str);
- } else {
- x = "${str} error";
- }
- }
- });
-}
-
-ignoreError(String str) {
- x = "${str} error ignored";
-}
-
-main() {
- Expect.equals("", x);
- test("test")();
- Expect.equals("test error", x);
- test("test", ignoreError)();
- Expect.equals("test error ignored", x);
-}
diff --git a/tests/language/argument_definition6_test.dart b/tests/language/argument_definition6_test.dart
deleted file mode 100644
index 5ac86b4..0000000
--- a/tests/language/argument_definition6_test.dart
+++ /dev/null
@@ -1,27 +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.
-
-// Regression test for
-// https://code.google.com/p/dart/issues/detail?id=9090.
-// Parameters used to be passed in the wrong order in a constructor in the
-// presence of parameter checks.
-
-import 'package:expect/expect.dart';
-
-class A {
- A(expect1, expect2, value1, value2, {layers, serviceUrl}) {
- Expect.equals(expect1, ?layers);
- Expect.equals(expect2, ?serviceUrl);
- Expect.equals(value1, layers);
- Expect.equals(value2, serviceUrl);
- }
-}
-
-main() {
- new A(false, false, null, null);
- new A(true, false, 42, null, layers: 42);
- new A(false, true, null, 43, serviceUrl: 43);
- new A(true, true, 42, 43, layers: 42, serviceUrl: 43);
- new A(true, true, 42, 43, serviceUrl: 43, layers: 42);
-}
diff --git a/tests/language/argument_definition_test.dart b/tests/language/argument_definition_test.dart
index 31d8431d..2fa1f1a 100644
--- a/tests/language/argument_definition_test.dart
+++ b/tests/language/argument_definition_test.dart
@@ -1,78 +1,16 @@
// 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.
-// Dart test program for testing argument definition test.
+// Dart test program for testing that the argument definition test has been
+// removed.
import "package:expect/expect.dart";
-int test(int a, {int b: 2, int c: 3}) {
- int result = 0;
- ?b;
- ?result; /// 01: compile-time error
- if (?a) {
- result += 100;
- }
- if (?b) {
- result += 20;
- }
- if (?c) {
- var b; ?b; /// 02: compile-time error
- result += 3;
- }
- if ((!?a?!?b:!?c) == (?a??b:?c)) {
- result += 200;
- }
- if (!?a?!?b:!?c == ?a??b:?c) {
- result += 400;
- }
- return result;
+int test(a, {b, c}) {
+ if (?b) return b; /// 01: compile-time error
+ return a + b + c;
}
-closure_test(int a, {int b: 2, int c: 3}) {
- var x = 0;
- return () {
- int result = 0;
- ?b;
- ?result; /// 03: compile-time error
- ?x; /// 04: compile-time error
- if (?a) {
- result += 100;
- }
- if (?b) {
- result += 20;
- }
- if (?c) {
- var b; ?b; /// 05: compile-time error
- result += 3;
- }
- // Equivalent to: (!?c) == ?b.
- if ((!?a?!?b:!?c) == (?a??b:?c)) {
- result += 200;
- }
- // Equivalent to: (!?c) ? ?b : ?c.
- if (!?a?!?b:!?c == ?a??b:?c) {
- result += 400;
- }
- return result;
- };
-}
-
-tl_test([a]) => ?a;
-
main() {
- // Use a loop to test optimized version as well.
- for (int i = 0; i < 1000; i++) {
- Expect.equals(100, test(1));
- Expect.equals(720, test(1, b: 2));
- Expect.equals(523, test(1, b: 2, c: 3));
- Expect.equals(703, test(1, c: 3));
-
- Expect.equals(100, closure_test(1)());
- Expect.equals(720, closure_test(1, b: 2)());
- Expect.equals(523, closure_test(1, b: 2, c: 3)());
- Expect.equals(703, closure_test(1, c: 3)());
-
- Expect.equals(true, tl_test(0));
- Expect.equals(false, tl_test());
- }
+ Expect.equals(6, test(1, b: 2, c:3));
}
diff --git a/tests/language/class_syntax2_test.dart b/tests/language/class_syntax2_test.dart
new file mode 100644
index 0000000..e884c23
--- /dev/null
+++ b/tests/language/class_syntax2_test.dart
@@ -0,0 +1,28 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Regression test for dart2js bug http://dartbug.com/11570.
+
+import 'package:expect/expect.dart';
+
+void main() {
+ var c = new Cool(true);
+ Expect.stringEquals('{}', '${c.thing}');
+
+ c = new Cool(false);
+ Expect.stringEquals('[]', '${c.thing}');
+
+ c = new Cool.alt(true);
+ Expect.stringEquals('{}', '${c.thing}');
+
+ c = new Cool.alt(false);
+ Expect.stringEquals('[]', '${c.thing}');
+}
+
+class Cool {
+ final thing;
+
+ Cool(bool option) : thing = option ? <String, String>{} : <String>[];
+ Cool.alt(bool option) : thing = !option ? <String>[] : <String, String>{};
+}
diff --git a/tests/language/constructor8_test.dart b/tests/language/constructor8_test.dart
index 9f05e14..e11d757 100644
--- a/tests/language/constructor8_test.dart
+++ b/tests/language/constructor8_test.dart
@@ -9,12 +9,6 @@
class A {
var b;
- // The parameter check here used to confuse the SSA builder when it
- // created the call to the constructor body.
- A([Map a]) : b = ?a {
- Expect.isTrue(b);
- }
-
// The closure in the constructor body used to confuse the SSA builder
// when it created the call to the constructor body.
A.withClosure(Map a) {
@@ -27,8 +21,6 @@
}
main() {
- new A(null);
- new A({});
new A.withClosure(null);
new A.withClosure({});
}
diff --git a/tests/language/language.status b/tests/language/language.status
index 34b57d0..e409ff6 100644
--- a/tests/language/language.status
+++ b/tests/language/language.status
@@ -85,9 +85,6 @@
type_variable_field_initializer_closure_test: Crash # issue 8847
-execute_finally10_test: Fail # Issue 430
-execute_finally11_test: Fail # Issue 430
-
[ $compiler == none && $unchecked ]
# Only checked mode reports an error on type assignment
@@ -405,9 +402,6 @@
bad_constructor_test/05: Fail
bad_constructor_test/06: Fail
argument_definition_test/*: Skip # Not implemented.
-argument_definition2_test: Skip # Not implemented. Fails in minified tests.
-argument_definition3_test: Skip # Not implemented. Fails in minified tests.
-argument_definition4_test: Skip # Not implemented. Fails in minified tests.
const_var_test: Pass, Fail # Map literals take 2 type arguments.
map_literal3_test: Fail # Map literals take 2 type arguments.
class_cycle_negative_test: Fail, OK # Bad test: assumes eager loading.
@@ -508,9 +502,6 @@
type_variable_field_initializer_closure_test: Crash # VM bug: issue 8847
-execute_finally10_test: Fail # VM bug: issue 430
-execute_finally11_test: Fail # VM bug: issue 430
-
bound_closure_equality_test: Fail # Issue 10849
[ $compiler == dart2dart && $minified ]
@@ -570,8 +561,6 @@
[ $arch == simarm || $arch == arm ]
-deopt_smi_op_test: Fail
-gc_test: Crash
stack_overflow_test: Crash, Pass # Passes on HW in release mode.
stack_overflow_stacktrace_test: Crash, Pass # Passes on HW in release mode.
@@ -582,11 +571,6 @@
[ $arch == simmips ]
arithmetic_test: Crash # Too far relative branch.
-deopt_smi_op_test: Fail
-gc_test: Crash
-invocation_mirror_test: Fail
-large_implicit_getter_test: Crash
-load_to_load_forwarding_vm_test: Fail
-named_parameters_with_conversions_test: Pass, Crash
+large_implicit_getter_test: Crash # Too far relative branch.
stack_overflow_test: Crash
stack_overflow_stacktrace_test: Crash
diff --git a/tests/language/language_analyzer.status b/tests/language/language_analyzer.status
index 2d51605..c63c228 100644
--- a/tests/language/language_analyzer.status
+++ b/tests/language/language_analyzer.status
@@ -3,6 +3,7 @@
# BSD-style license that can be found in the LICENSE file.
[ $compiler == dartanalyzer ]
+argument_definition_test/01: fail # issue 11565
abstract_factory_constructor_test/00: fail
assign_instance_method_negative_test: fail
assign_static_type_test/06: fail
@@ -71,9 +72,6 @@
final_variable_assignment_test/04: fail
first_class_types_constants_test: fail
for_in2_test: fail
-function_type_alias5_test/00: fail
-function_type_alias5_test/01: fail
-function_type_alias5_test/02: fail
getter_no_setter2_test/00: fail
getter_no_setter2_test/03: fail
getter_no_setter_test/00: fail
@@ -233,6 +231,18 @@
const_escape_frog_test: fail
compile_time_constant_test/none: fail
+# Test issue 11544, using @TypeName as annotation is not valid
+inferrer_constructor2_test: fail
+inferrer_constructor3_test: fail
+multiple_field_assignment_constructor_test: fail
+
+# Test issue 11545, using not existing constructor name in annotation
+metadata_test: fail
+
+# Test issue 11564, named parameter starts with '_'
+named_parameters_with_object_property_names_test: fail
+
+
[ $compiler == dartanalyzer && $checked ]
factory1_test/00: fail
factory1_test/01: fail
diff --git a/tests/language/language_dart2js.status b/tests/language/language_dart2js.status
index 2d90fec..e3d7687 100644
--- a/tests/language/language_dart2js.status
+++ b/tests/language/language_dart2js.status
@@ -27,24 +27,7 @@
class_literal_test/28: Fail # Class literals are expression now; delete this test.
class_literal_test/29: Fail # Class literals are expression now; delete this test.
-argument_definition2_test: Fail, OK # Depends on ?parameter check.
-argument_definition3_test: Fail, OK # Depends on ?parameter check.
-argument_definition4_test: Fail, OK # Depends on ?parameter check.
-argument_definition5_test: Fail, OK # Depends on ?parameter check.
-argument_definition6_test: Fail, OK # Depends on ?parameter check.
-argument_definition_test/none: Fail, OK # Depends on ?parameter check.
-constructor8_test: Fail, OK # Depends on ?parameter check.
constructor_initializer_test: Fail, OK # Depends on ?parameter check.
-optional_named_parameters_test/01: Fail, OK # Depends on ?parameter check.
-optional_named_parameters_test/02: Fail, OK # Depends on ?parameter check.
-optional_named_parameters_test/03: Fail, OK # Depends on ?parameter check.
-optional_named_parameters_test/04: Fail, OK # Depends on ?parameter check.
-optional_named_parameters_test/05: Fail, OK # Depends on ?parameter check.
-optional_named_parameters_test/06: Fail, OK # Depends on ?parameter check.
-optional_named_parameters_test/07: Fail, OK # Depends on ?parameter check.
-optional_named_parameters_test/08: Fail, OK # Depends on ?parameter check.
-optional_named_parameters_test/09: Fail, OK # Depends on ?parameter check.
-optional_named_parameters_test/none: Fail, OK # Depends on ?parameter check.
# Fails due to inlining. Not all expected frames are in the trace.
full_stacktrace1_test: Pass, Fail # issue 9895
diff --git a/tests/language/load_to_load_forwarding_vm_test.dart b/tests/language/load_to_load_forwarding_vm_test.dart
index 2f0a766..c62b66a 100644
--- a/tests/language/load_to_load_forwarding_vm_test.dart
+++ b/tests/language/load_to_load_forwarding_vm_test.dart
@@ -3,6 +3,8 @@
// BSD-style license that can be found in the LICENSE file.
// Test correctness of side effects tracking used by load to load forwarding.
+// VMOptions=--optimization-counter-threshold=10
+
import "package:expect/expect.dart";
import "dart:typed_data";
@@ -206,7 +208,7 @@
final obj = new X(new X(new X(null)));
- for (var i = 0; i < 2000; i++) {
+ for (var i = 0; i < 20; i++) {
Expect.listEquals([0x02010000, 0x03020100], foo(new A(0, 0)));
Expect.listEquals([0x02010000, 0x03020100], bar(new A(0, 0), false));
Expect.listEquals([0x04020000, 0x03020100], bar(new A(0, 0), true));
diff --git a/tests/language/optional_named_parameters_test.dart b/tests/language/optional_named_parameters_test.dart
index 70b770a..770e732 100644
--- a/tests/language/optional_named_parameters_test.dart
+++ b/tests/language/optional_named_parameters_test.dart
@@ -49,11 +49,11 @@
}
static int F41(int a, {int b: 20, int c, int d: 40}) {
- return 100*(100*(100*a + b) + (?c ? c : 0)) + d;
+ return 100*(100*(100*a + b) + ((c != null) ? c : 0)) + d;
}
int f52(int a, {int b: 20, int c, int d: 40}) {
- return 100*(100*(100*a + b) + (?c ? c : 0)) + d;
+ return 100*(100*(100*a + b) + ((c != null) ? c : 0)) + d;
}
static void test() {
diff --git a/tests/lib/lib.status b/tests/lib/lib.status
index 2488346..bedba2b 100644
--- a/tests/lib/lib.status
+++ b/tests/lib/lib.status
@@ -102,6 +102,8 @@
mirrors/superclass_test: Fail # http://dartbug.com/11142
mirrors/reflectively_instantiate_uninstantiated_class_test: Fail # http://dartbug.com/11187
mirrors/reflect_model_test: Fail # http://dartbug.com/11219
+mirrors/parameter_test: Fail # http://dartbug.com/11567
+mirrors/metadata_constructed_constant_test: Fail # http://dartbug.com/11609
[ $compiler == none && $runtime == drt ]
async/timer_isolate_test: Skip # See Issue 4997
@@ -116,10 +118,16 @@
[ $arch == arm || $arch == simarm ]
-*: Skip
+typed_data/float32x4_unbox_regress_test: Crash # Unimplemented
+typed_data/float32x4_unbox_phi_test: Crash # Unimplemented
+typed_data/float32x4_list_test: Crash # Unimplemented
+typed_data/float32x4_test: Crash # Unimplemented
[ $arch == mips ]
*: Skip
[ $arch == simmips ]
-*: Skip
+typed_data/float32x4_unbox_regress_test: Crash # Unimplemented
+typed_data/float32x4_unbox_phi_test: Crash # Unimplemented
+typed_data/float32x4_list_test: Crash # Unimplemented
+typed_data/float32x4_test: Crash # Unimplemented
diff --git a/tests/lib/mirrors/constructors_test.dart b/tests/lib/mirrors/constructors_test.dart
index 1a717a7..b42472f 100644
--- a/tests/lib/mirrors/constructors_test.dart
+++ b/tests/lib/mirrors/constructors_test.dart
@@ -8,7 +8,7 @@
import 'package:expect/expect.dart';
-import 'reflect_model_test.dart';
+import 'stringify.dart';
class Foo {
}
@@ -45,4 +45,21 @@
' Biz.named: Method(s(Biz.named) in s(Biz), constructor)}',
bizConstructors);
print(bizConstructors);
+
+ expect('[]', fooConstructors.values.single.parameters);
+ expect('[]', barConstructors.values.single.parameters);
+ expect('[]', bazConstructors.values.single.parameters);
+ for (var constructor in bizConstructors.values) {
+ expect('[]', constructor.parameters);
+ }
+
+ expect('[s()]',
+ fooConstructors.values.map((m) => m.constructorName).toList());
+ expect('[s()]',
+ barConstructors.values.map((m) => m.constructorName).toList());
+ expect('[s(named)]',
+ bazConstructors.values.map((m) => m.constructorName).toList());
+ expect('[s(), s(named)]',
+ bizConstructors.values.map((m) => m.constructorName).toList()
+ ..sort(compareSymbols));
}
diff --git a/tests/lib/mirrors/intercepted_class_test.dart b/tests/lib/mirrors/intercepted_class_test.dart
index a17b7e9..2fde1b7 100644
--- a/tests/lib/mirrors/intercepted_class_test.dart
+++ b/tests/lib/mirrors/intercepted_class_test.dart
@@ -8,7 +8,7 @@
import 'dart:mirrors';
-import 'reflect_model_test.dart' show stringify, expect;
+import 'stringify.dart' show stringify, expect;
checkClassMirror(ClassMirror cls, String name) {
expect('s($name)', cls.simpleName);
diff --git a/tests/lib/mirrors/intercepted_object_test.dart b/tests/lib/mirrors/intercepted_object_test.dart
index 26016e1..17c9783 100644
--- a/tests/lib/mirrors/intercepted_object_test.dart
+++ b/tests/lib/mirrors/intercepted_object_test.dart
@@ -8,7 +8,7 @@
import 'dart:mirrors';
-import 'reflect_model_test.dart' show stringify, expect;
+import 'stringify.dart' show stringify, expect;
import 'intercepted_class_test.dart' show checkClassMirror;
diff --git a/tests/lib/mirrors/metadata_constructed_constant_test.dart b/tests/lib/mirrors/metadata_constructed_constant_test.dart
new file mode 100644
index 0000000..df74ff1
--- /dev/null
+++ b/tests/lib/mirrors/metadata_constructed_constant_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.
+
+library test.metadata_constructed_constant_test;
+
+import 'dart:mirrors';
+
+import 'package:expect/expect.dart';
+
+class ConstructedConstant {
+ final value;
+ const ConstructedConstant(this.value);
+ toString() => 'ConstructedConstant($value)';
+}
+
+class Foo {
+ @ConstructedConstant(StateError)
+ m() {}
+}
+
+main() {
+ var value =
+ reflectClass(Foo).methods[const Symbol("m")].metadata.single.reflectee;
+ Expect.stringEquals('ConstructedConstant($StateError)', '$value');
+}
diff --git a/tests/lib/mirrors/parameter_test.dart b/tests/lib/mirrors/parameter_test.dart
new file mode 100644
index 0000000..3f97939
--- /dev/null
+++ b/tests/lib/mirrors/parameter_test.dart
@@ -0,0 +1,50 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// Test of [ParameterMirror].
+library test.parameter_test;
+
+@MirrorsUsed(targets: 'test.parameter_test', override: '*')
+import 'dart:mirrors';
+
+import 'stringify.dart';
+
+class B {
+ B();
+ B.foo(int x);
+ B.bar(int z, x);
+}
+
+main() {
+ var constructors = reflectClass(B).constructors;
+
+ expect('{B: Method(s(B) in s(B), constructor), '
+ 'B.bar: Method(s(B.bar) in s(B), constructor), '
+ 'B.foo: Method(s(B.foo) in s(B), constructor)}',
+ constructors);
+
+ var unnamedConstructor = constructors[new Symbol('B')];
+
+ expect('[]', unnamedConstructor.parameters);
+ expect('Type(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))]',
+ fooConstructor.parameters);
+ expect('Type(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)), '
+ '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)',
+ barConstructor.returnType);
+
+ print(constructors);
+}
diff --git a/tests/lib/mirrors/reflect_model_test.dart b/tests/lib/mirrors/reflect_model_test.dart
index 567651c..e5eabdf 100644
--- a/tests/lib/mirrors/reflect_model_test.dart
+++ b/tests/lib/mirrors/reflect_model_test.dart
@@ -9,67 +9,10 @@
import 'package:expect/expect.dart';
import 'model.dart';
+import 'stringify.dart';
isNoSuchMethodError(e) => e is NoSuchMethodError;
-name(DeclarationMirror mirror) {
- return (mirror == null) ? '<null>' : stringify(mirror.simpleName);
-}
-
-stringifyMap(Map map) {
- var buffer = new StringBuffer('{');
- bool first = true;
- for (String key in map.keys.map(MirrorSystem.getName).toList()..sort()) {
- if (!first) buffer.write(', ');
- first = false;
- buffer.write(key);
- buffer.write(': ');
- buffer.write(stringify(map[new Symbol(key)]));
- }
- return (buffer..write('}')).toString();
-}
-
-stringifySymbol(Symbol symbol) => 's(${MirrorSystem.getName(symbol)})';
-
-writeDeclarationOn(DeclarationMirror mirror, StringBuffer buffer) {
- buffer.write(stringify(mirror.simpleName));
- if (mirror.owner != null) {
- buffer.write(' in ');
- buffer.write(name(mirror.owner));
- }
- if (mirror.isPrivate) buffer.write(', private');
- if (mirror.isTopLevel) buffer.write(', top-level');
-}
-
-stringifyVariable(VariableMirror variable) {
- var buffer = new StringBuffer('Variable(');
- writeDeclarationOn(variable, buffer);
- if (variable.isStatic) buffer.write(', static');
- if (variable.isFinal) buffer.write(', final');
- return (buffer..write(')')).toString();
-}
-
-stringifyMethod(MethodMirror method) {
- var buffer = new StringBuffer('Method(');
- writeDeclarationOn(method, buffer);
- if (method.isStatic) buffer.write(', static');
- if (method.isGetter) buffer.write(', getter');
- if (method.isSetter) buffer.write(', setter');
- if (method.isConstructor) buffer.write(', constructor');
- return (buffer..write(')')).toString();
-}
-
-stringify(value) {
- if (value is Map) return stringifyMap(value);
- if (value is VariableMirror) return stringifyVariable(value);
- if (value is MethodMirror) return stringifyMethod(value);
- if (value is Symbol) return stringifySymbol(value);
- if (value == null) return '<null>';
- throw 'Unexpected value: $value';
-}
-
-expect(expected, actual) => Expect.stringEquals(expected, stringify(actual));
-
main() {
var unnamed = new Symbol('');
var field = new Symbol('field');
diff --git a/tests/lib/mirrors/return_type_test.dart b/tests/lib/mirrors/return_type_test.dart
new file mode 100644
index 0000000..db4ad76
--- /dev/null
+++ b/tests/lib/mirrors/return_type_test.dart
@@ -0,0 +1,42 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// Test of [MethodMirror.returnType].
+library test.return_type_test;
+
+@MirrorsUsed(targets: 'test.return_type_test', override: '*')
+import 'dart:mirrors';
+
+import 'stringify.dart';
+
+class B {
+ f() {}
+ int g() {}
+ List h() {}
+ B i() {}
+
+ // TODO(ahe): Test this when dart2js handles parameterized types.
+ // List<int> j() {}
+}
+
+main() {
+ var methods = reflectClass(B).methods;
+
+ expect('{f: Method(s(f) in s(B)), '
+ 'g: Method(s(g) in s(B)), '
+ 'h: Method(s(h) in s(B)), '
+ 'i: Method(s(i) in s(B))}', methods);
+
+ var f = methods[const Symbol('f')];
+ var g = methods[const Symbol('g')];
+ var h = methods[const Symbol('h')];
+ 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);
+
+ print(methods);
+}
diff --git a/tests/lib/mirrors/stringify.dart b/tests/lib/mirrors/stringify.dart
new file mode 100644
index 0000000..e8c31a8
--- /dev/null
+++ b/tests/lib/mirrors/stringify.dart
@@ -0,0 +1,109 @@
+// 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.
+
+/// Helper methods for converting a [Mirror] to a [String].
+library test.stringify;
+
+import 'dart:mirrors';
+
+import 'package:expect/expect.dart';
+
+name(DeclarationMirror mirror) {
+ return (mirror == null) ? '<null>' : stringify(mirror.simpleName);
+}
+
+stringifyMap(Map map) {
+ var buffer = new StringBuffer();
+ bool first = true;
+ for (String key in map.keys.map(MirrorSystem.getName).toList()..sort()) {
+ if (!first) buffer.write(', ');
+ first = false;
+ buffer.write(key);
+ buffer.write(': ');
+ buffer.write(stringify(map[new Symbol(key)]));
+ }
+ return '{$buffer}';
+}
+
+stringifyList(List list) {
+ var buffer = new StringBuffer();
+ bool first = true;
+ for (String value in list.map(stringify)) {
+ if (!first) buffer.write(', ');
+ first = false;
+ buffer.write(value);
+ }
+ return '[$buffer]';
+}
+
+stringifySymbol(Symbol symbol) => 's(${MirrorSystem.getName(symbol)})';
+
+writeDeclarationOn(DeclarationMirror mirror, StringBuffer buffer) {
+ buffer.write(stringify(mirror.simpleName));
+ if (mirror.owner != null) {
+ buffer.write(' in ');
+ buffer.write(name(mirror.owner));
+ }
+ if (mirror.isPrivate) buffer.write(', private');
+ if (mirror.isTopLevel) buffer.write(', top-level');
+}
+
+writeVariableOn(VariableMirror variable, StringBuffer buffer) {
+ writeDeclarationOn(variable, buffer);
+ if (variable.isStatic) buffer.write(', static');
+ if (variable.isFinal) buffer.write(', final');
+}
+
+stringifyVariable(VariableMirror variable) {
+ var buffer = new StringBuffer();
+ writeVariableOn(variable, buffer);
+ return 'Variable($buffer)';
+}
+
+stringifyParameter(ParameterMirror parameter) {
+ var buffer = new StringBuffer();
+ writeVariableOn(parameter, buffer);
+ if (parameter.isOptional) buffer.write(', optional');
+ if (parameter.isNamed) buffer.write(', named');
+ if (parameter.hasDefaultValue) {
+ buffer.write(', value = ${stringify(parameter.defaultValue)}');
+ }
+ // TODO(ahe): Move to writeVariableOn.
+ buffer.write(', type = ${stringifyType(parameter.type)}');
+ return 'Parameter($buffer)';
+}
+
+stringifyType(TypeMirror type) {
+ var buffer = new StringBuffer();
+ writeDeclarationOn(type, buffer);
+ return 'Type($buffer)';
+}
+
+stringifyMethod(MethodMirror method) {
+ var buffer = new StringBuffer();
+ writeDeclarationOn(method, buffer);
+ if (method.isStatic) buffer.write(', static');
+ if (method.isGetter) buffer.write(', getter');
+ if (method.isSetter) buffer.write(', setter');
+ if (method.isConstructor) buffer.write(', constructor');
+ return 'Method($buffer)';
+}
+
+stringify(value) {
+ if (value is Map) return stringifyMap(value);
+ if (value is List) return stringifyList(value);
+ if (value is ParameterMirror) return stringifyParameter(value);
+ if (value is VariableMirror) return stringifyVariable(value);
+ if (value is MethodMirror) return stringifyMethod(value);
+ if (value is Symbol) return stringifySymbol(value);
+ if (value is TypeMirror) return stringifyType(value);
+ if (value == null) return '<null>';
+ throw 'Unexpected value: $value';
+}
+
+expect(expected, actual) => Expect.stringEquals(expected, stringify(actual));
+
+compareSymbols(Symbol a, Symbol b) {
+ return MirrorSystem.getName(a).compareTo(MirrorSystem.getName(b));
+}
diff --git a/tests/standalone/io/file_invalid_arguments_test.dart b/tests/standalone/io/file_invalid_arguments_test.dart
index 3ae9a9c..846e882 100644
--- a/tests/standalone/io/file_invalid_arguments_test.dart
+++ b/tests/standalone/io/file_invalid_arguments_test.dart
@@ -8,127 +8,53 @@
import "dart:isolate";
void testReadInvalidArgs(arg) {
- var port = new ReceivePort();
String filename = getFilename("tests/vm/data/fixed_length_file");
var file = (new File(filename)).openSync();
- try {
- file.readSync(arg);
- Expect.fail('exception expected');
- } catch (e) {
- Expect.isTrue(e is FileException);
- Expect.isTrue(e.toString().contains('Invalid arguments'));
- }
+ Expect.throws(() => file.readSync(arg),
+ (e) => e is ArgumentError);
- var errors = 0;
- var readFuture = file.read(arg);
- readFuture.then((bytes) {
- Expect.fail('exception expected');
- }).catchError((error) {
- errors++;
- Expect.isTrue(error is FileException);
- Expect.isTrue(error.toString().contains('Invalid arguments'));
- file.close().then((ignore) {
- Expect.equals(1, errors);
- port.close();
- });
- });
+ Expect.throws(() => file.read(arg),
+ (e) => e is ArgumentError);
}
void testReadIntoInvalidArgs(buffer, start, end) {
- var port = new ReceivePort();
String filename = getFilename("tests/vm/data/fixed_length_file");
var file = (new File(filename)).openSync();
- try {
- file.readIntoSync(buffer, start, end);
- Expect.fail('exception expected');
- } catch (e) {
- Expect.isTrue(e is FileException);
- Expect.isTrue(e.toString().contains('Invalid arguments'));
- }
+ Expect.throws(() => file.readIntoSync(buffer, start, end),
+ (e) => e is ArgumentError);
- var errors = 0;
- var readIntoFuture = file.readInto(buffer, start, end);
- readIntoFuture.then((bytes) {
- Expect.fail('exception expected');
- }).catchError((error) {
- errors++;
- Expect.isTrue(error is FileException);
- Expect.isTrue(error.toString().contains('Invalid arguments'));
- file.close().then((ignore) {
- Expect.equals(1, errors);
- port.close();
- });
- });
+ Expect.throws(() => file.readInto(buffer, start, end),
+ (e) => e is ArgumentError);
}
void testWriteByteInvalidArgs(value) {
- var port = new ReceivePort();
String filename = getFilename("tests/vm/data/fixed_length_file");
var file = (new File("${filename}_out")).openSync(mode: FileMode.WRITE);
- try {
- file.writeByteSync(value);
- Expect.fail('exception expected');
- } catch (e) {
- Expect.isTrue(e is FileException);
- Expect.isTrue(e.toString().contains('Invalid argument'));
- }
+ Expect.throws(() => file.writeByteSync(value),
+ (e) => e is ArgumentError);
- var writeByteFuture = file.writeByte(value);
- writeByteFuture.then((ignore) {
- Expect.fail('exception expected');
- }).catchError((error) {
- Expect.isTrue(error is FileException);
- Expect.isTrue(error.toString().contains('Invalid argument'));
- file.close().then((ignore) {
- port.close();
- });
- });
+ Expect.throws(() => file.writeByte(value),
+ (e) => e is ArgumentError);
}
void testWriteFromInvalidArgs(buffer, start, end) {
- var port = new ReceivePort();
String filename = getFilename("tests/vm/data/fixed_length_file");
var file = (new File("${filename}_out")).openSync(mode: FileMode.WRITE);
- try {
- file.writeFromSync(buffer, start, end);
- Expect.fail('exception expected');
- } catch (e) {
- Expect.isTrue(e is FileException);
- Expect.isTrue(e.toString().contains('Invalid arguments'));
- }
+ Expect.throws(() => file.writeFromSync(buffer, start, end),
+ (e) => e is ArgumentError);
- var writeFromFuture = file.writeFrom(buffer, start, end);
- writeFromFuture.then((ignore) {
- Expect.fail('exception expected');
- }).catchError((error) {
- Expect.isTrue(error is FileException);
- Expect.isTrue(error.toString().contains('Invalid arguments'));
- file.close().then((ignore) {
- port.close();
- });
- });
+ Expect.throws(() => file.writeFrom(buffer, start, end),
+ (e) => e is ArgumentError);
}
void testWriteStringInvalidArgs(string, encoding) {
- var port = new ReceivePort();
String filename = getFilename("tests/vm/data/fixed_length_file");
var file = new File("${filename}_out").openSync(mode: FileMode.WRITE);
- try {
- file.writeStringSync(string, encoding: encoding);
- Expect.fail('exception expected');
- } catch (e) {
- Expect.isTrue(e is FileException);
- }
+ Expect.throws(() => file.writeStringSync(string, encoding: encoding),
+ (e) => e is ArgumentError);
- var writeStringFuture = file.writeString(string, encoding: encoding);
- writeStringFuture.then((ignore) {
- Expect.fail('exception expected');
- }).catchError((error) {
- Expect.isTrue(error is FileException);
- file.close().then((ignore) {
- port.close();
- });
- });
+ Expect.throws(() => file.writeString(string, encoding: encoding),
+ (e) => e is ArgumentError);
}
Future futureThrows(Future result) {
diff --git a/tests/standalone/io/skipping_dart2js_compilations_helper.dart b/tests/standalone/io/skipping_dart2js_compilations_helper.dart
index 88a26c2..1728e3a 100644
--- a/tests/standalone/io/skipping_dart2js_compilations_helper.dart
+++ b/tests/standalone/io/skipping_dart2js_compilations_helper.dart
@@ -5,7 +5,7 @@
import 'dart:io';
main() {
- var outputFile = Platform.arguments[0];
+ var outputFile = new Options().arguments[0];
var file = new File(outputFile);
file.createSync();
}
diff --git a/tests/standalone/io/stdout_close_test.dart b/tests/standalone/io/stdout_close_test.dart
new file mode 100644
index 0000000..6587bbc
--- /dev/null
+++ b/tests/standalone/io/stdout_close_test.dart
@@ -0,0 +1,21 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+import "dart:io";
+
+void main() {
+ var dir = new Directory('').createTempSync();
+ stdout.close().then((_) {
+ var file = new File('${dir.path}/file');
+ var io = file.openSync(mode: FileMode.WRITE);
+ print("to file");
+ io.closeSync();
+ var content = file.readAsStringSync();
+ file.deleteSync();
+ dir.deleteSync();
+ Expect.equals("", content);
+ });
+}
+
diff --git a/tests/standalone/io/test_runner_exit_code_script.dart b/tests/standalone/io/test_runner_exit_code_script.dart
index 02ca770..1cfe603 100644
--- a/tests/standalone/io/test_runner_exit_code_script.dart
+++ b/tests/standalone/io/test_runner_exit_code_script.dart
@@ -10,7 +10,7 @@
import "../../../tools/testing/dart/test_options.dart";
main() {
- var progressType = Platform.arguments[0];
+ var progressType = new Options().arguments[0];
// Build a progress indicator.
var startTime = new DateTime.now();
var progress =
diff --git a/tests/standalone/io/test_runner_test.dart b/tests/standalone/io/test_runner_test.dart
index fa276c2..79a8522 100644
--- a/tests/standalone/io/test_runner_test.dart
+++ b/tests/standalone/io/test_runner_test.dart
@@ -109,7 +109,7 @@
// Run the test_runner_test if there are no command-line options.
// Otherwise, run one of the component tests that always pass,
// fail, or timeout.
- var arguments = Platform.arguments;
+ var arguments = new Options().arguments;
if (arguments.isEmpty) {
testProcessQueue();
} else {
diff --git a/tests/standalone/standalone.status b/tests/standalone/standalone.status
index c855cff..afb2a39 100644
--- a/tests/standalone/standalone.status
+++ b/tests/standalone/standalone.status
@@ -10,11 +10,6 @@
package/invalid_uri_test: Fail, OK # Fails intentionally
[ $runtime == vm ]
-# Fails because checked-in dart executable is not up to date.
-io/test_runner_test: Fail
-# Fails because checked-in dart executable is not up to date.
-# Skip this because it is leaving temp directories behind when it fails.
-io/skipping_dart2js_compilations_test: Skip
io/web_socket_test: Pass, Crash # Issue 11502
[ $runtime == vm ]
@@ -64,8 +59,6 @@
# package test issue 7392
package/package1_test: Fail
package/package_test: Fail
-io/test_runner_test: Fail # Library dart:uri removed.
-io/skipping_dart2js_compilations_test: Skip # Library dart:uri removed.
# The dart:io library is created at build time from separate files, and
@@ -100,11 +93,6 @@
# This is runtime test.
io/process_exit_negative_test: Skip
-# Fails because checked-in dart executable is not up to date.
-io/test_runner_test: fail
-io/skipping_dart2js_compilations_test: fail
-
-
[ $compiler == dart2analyzer ]
io/file_constructor_test: fail
io/http_cookie_date_test: fail
@@ -115,13 +103,7 @@
io/web_socket_protocol_processor_test: fail
53bit_overflow_literal_test/01: fail, ok
-# Fails because checked-in dart executable is not up to date.
-io/test_runner_test: fail
-io/skipping_dart2js_compilations_test: fail
-
-
[ $compiler == dart2js ]
-io/test_runner_test: Fail # Import Uri does not work
number_identity_test: Skip # Bigints and int/double diff. not supported.
typed_data_test: Skip # dart:typed_data support needed.
bytedata_test: Skip # dart:typed_data support needed.
@@ -140,7 +122,6 @@
debugger/*: Skip # Do not run standalone vm debugger tests with dart2js.
left_shift_bit_and_op_test: Skip # Integers exceed dart2js precision.
pow_test: Skip # Precision > 53 bits.
-io/skipping_dart2js_compilations_test: Skip # Library dart:uri removed.
http_launch_test: Skip
53bit_overflow_test: Skip
53bit_overflow_literal_test: Skip
@@ -169,12 +150,16 @@
# Skip until we stabilize language tests.
*: Skip
-[ $arch == arm || $arch == simarm ]
-*: Skip # Many of these tests are still flaky on arm, so skipping until we
- # actually start working on implementing the needed features.
+[ $arch == arm ]
+*: Skip # Shared libraries problem.
+
+[ $arch == simarm ]
+out_of_memory_test: Crash
[ $arch == mips ]
*: Skip
[ $arch == simmips ]
-*: Skip
+io/file_fuzz_test: Pass, Timeout
+out_of_memory_test: Crash
+
diff --git a/tests/standalone/typed_data_test.dart b/tests/standalone/typed_data_test.dart
index f8f28aa..3ea844b 100644
--- a/tests/standalone/typed_data_test.dart
+++ b/tests/standalone/typed_data_test.dart
@@ -4,6 +4,8 @@
//
// Dart test program for testing typed data.
+// VMOptions=--optimization_counter_threshold=10
+
// Library tag to be able to run in html test framework.
library TypedDataTest;
@@ -319,7 +321,7 @@
}
main() {
- for (int i = 0; i < 2000; i++) {
+ for (int i = 0; i < 20; i++) {
testCreateUint8TypedData();
testCreateClampedUint8TypedData();
testTypedDataRange(false);
diff --git a/tools/VERSION b/tools/VERSION
index a18058b2..9bd3426 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -1,4 +1,4 @@
MAJOR 0
MINOR 6
-BUILD 1
+BUILD 2
PATCH 0
diff --git a/tools/bots/android.py b/tools/bots/android.py
index 55732da..39cbb25 100644
--- a/tools/bots/android.py
+++ b/tools/bots/android.py
@@ -51,7 +51,7 @@
# broken on Android.
if os.path.exists('./out/lastHooksTargetOS.txt'):
os.remove('./out/lastHooksTargetOS.txt')
- targets = ['samples']
+ targets = ['runtime']
args = [sys.executable, './tools/build.py', '--mode=' + build_info.mode,
'--os=android'] + targets
print 'Building Android: %s' % (' '.join(args))
diff --git a/tools/create_sdk.py b/tools/create_sdk.py
index 1ae2fd1..ab5b51b 100755
--- a/tools/create_sdk.py
+++ b/tools/create_sdk.py
@@ -38,7 +38,6 @@
# ......isolate/
# ......json/
# ......math/
-# ......mdv_observe_impl/
# ......mirrors/
# ......utf/
# ......typed_data/
@@ -204,7 +203,7 @@
join('html', 'dart2js'), join('html', 'dartium'),
join('html', 'html_common'),
join('indexed_db', 'dart2js'), join('indexed_db', 'dartium'),
- 'json', 'math', 'mdv_observe_impl', 'mirrors', 'typed_data',
+ '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/dartmetadata.py b/tools/dom/scripts/dartmetadata.py
index 4d1b866..6bd98a6 100644
--- a/tools/dom/scripts/dartmetadata.py
+++ b/tools/dom/scripts/dartmetadata.py
@@ -261,8 +261,8 @@
],
'WebGLRenderingContext.getShaderParameter': [
- "@Creates('int|Null')",
- "@Returns('int|Null')",
+ "@Creates('int|bool|Null')",
+ "@Returns('int|bool|Null')",
],
'WebGLRenderingContext.getTexParameter': [
diff --git a/tools/dom/scripts/generator.py b/tools/dom/scripts/generator.py
index da2a88f..4908556 100644
--- a/tools/dom/scripts/generator.py
+++ b/tools/dom/scripts/generator.py
@@ -78,6 +78,7 @@
interface_factories = monitored.Dict('generator.interface_factories', {
})
+
#
# Custom native specs for the dart2js dom.
#
@@ -88,13 +89,36 @@
# tags here provided there is not conflict in usage (e.g. browser X has tag
# T and no other browser has tag T).
+ 'AnalyserNode': 'AnalyserNode,RealtimeAnalyserNode',
+
+ 'ChannelMergerNode': 'ChannelMergerNode,AudioChannelMerger',
+ 'ChannelSplitterNode': 'ChannelSplitterNode,AudioChannelSplitter',
+
+ 'CSSStyleDeclaration':
+ # IE Firefox
+ 'CSSStyleDeclaration,MSStyleCSSProperties,CSS2Properties',
+
'DOMApplicationCache':
'ApplicationCache,DOMApplicationCache,OfflineResourceList',
+ 'HTMLTableCellElement':
+ 'HTMLTableCellElement,HTMLTableDataCellElement,HTMLTableHeaderCellElement',
+
+ 'GainNode': 'GainNode,AudioGainNode',
+
+ 'IDBOpenDBRequest':
+ 'IDBOpenDBRequest,IDBVersionChangeRequest',
+
+ 'MouseEvent': 'MouseEvent,DragEvent',
+
'MutationObserver': 'MutationObserver,WebKitMutationObserver',
'NodeList': 'NodeList,RadioNodeList',
+ 'OscillatorNode': 'OscillatorNode,Oscillator',
+
+ 'PannerNode': 'PannerNode,AudioPannerNode',
+
'RTCPeerConnection': 'RTCPeerConnection,mozRTCPeerConnection',
'RTCIceCandidate': 'RTCIceCandidate,mozRTCIceCandidate',
@@ -103,6 +127,8 @@
'RTCDataChannel': 'RTCDataChannel,DataChannel',
+ 'ScriptProcessorNode': 'ScriptProcessorNode,JavaScriptAudioNode',
+
'TransitionEvent': 'TransitionEvent,WebKitTransitionEvent',
'WebKitCSSKeyframeRule':
diff --git a/tools/dom/scripts/htmlrenamer.py b/tools/dom/scripts/htmlrenamer.py
index 3d013e4..5e9eef4 100644
--- a/tools/dom/scripts/htmlrenamer.py
+++ b/tools/dom/scripts/htmlrenamer.py
@@ -265,8 +265,6 @@
'MutationEvent.initMutationEvent',
'Node.attributes',
'Node.childNodes',
- 'Node.firstChild',
- 'Node.lastChild',
'Node.localName',
'Node.namespaceURI',
'Node.removeChild',
diff --git a/tools/dom/src/TemplateBindings.dart b/tools/dom/src/TemplateBindings.dart
deleted file mode 100644
index 5f379da..0000000
--- a/tools/dom/src/TemplateBindings.dart
+++ /dev/null
@@ -1,789 +0,0 @@
-// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-part of html;
-
-// This code is a port of Model-Driven-Views:
-// https://github.com/polymer-project/mdv
-// The code mostly comes from src/template_element.js
-
-typedef void _ChangeHandler(value);
-
-/**
- * Model-Driven Views (MDV)'s native features enables a wide-range of use cases,
- * but (by design) don't attempt to implement a wide array of specialized
- * behaviors.
- *
- * Enabling these features in MDV is a matter of implementing and registering an
- * MDV Custom Syntax. A Custom Syntax is an object which contains one or more
- * delegation functions which implement specialized behavior. This object is
- * registered with MDV via [TemplateElement.syntax]:
- *
- *
- * HTML:
- * <template bind syntax="MySyntax">
- * {{ What!Ever('crazy')->thing^^^I+Want(data) }}
- * </template>
- *
- * Dart:
- * class MySyntax extends CustomBindingSyntax {
- * getBinding(model, path, name, node) {
- * // The magic happens here!
- * }
- * }
- *
- * ...
- *
- * TemplateElement.syntax['MySyntax'] = new MySyntax();
- *
- * See <https://github.com/polymer-project/mdv/blob/master/docs/syntax.md> for more
- * information about Custom Syntax.
- */
-// TODO(jmesserly): if this is just one method, a function type would make it
-// more Dart-friendly.
-@Experimental
-abstract class CustomBindingSyntax {
- /**
- * This syntax method allows for a custom interpretation of the contents of
- * mustaches (`{{` ... `}}`).
- *
- * When a template is inserting an instance, it will invoke this method for
- * each mustache which is encountered. The function is invoked with four
- * arguments:
- *
- * - [model]: The data context for which this instance is being created.
- * - [path]: The text contents (trimmed of outer whitespace) of the mustache.
- * - [name]: The context in which the mustache occurs. Within element
- * attributes, this will be the name of the attribute. Within text,
- * this will be 'text'.
- * - [node]: A reference to the node to which this binding will be created.
- *
- * If the method wishes to handle binding, it is required to return an object
- * which has at least a `value` property that can be observed. If it does,
- * then MDV will call [Node.bind on the node:
- *
- * node.bind(name, retval, 'value');
- *
- * If the 'getBinding' does not wish to override the binding, it should return
- * null.
- */
- // TODO(jmesserly): I had to remove type annotations from "name" and "node"
- // Normally they are String and Node respectively. But sometimes it will pass
- // (int name, CompoundBinding node). That seems very confusing; we may want
- // to change this API.
- getBinding(model, String path, name, node) => null;
-
- /**
- * This syntax method allows a syntax to provide an alterate model than the
- * one the template would otherwise use when producing an instance.
- *
- * When a template is about to create an instance, it will invoke this method
- * The function is invoked with two arguments:
- *
- * - [template]: The template element which is about to create and insert an
- * instance.
- * - [model]: The data context for which this instance is being created.
- *
- * The template element will always use the return value of `getInstanceModel`
- * as the model for the new instance. If the syntax does not wish to override
- * the value, it should simply return the `model` value it was passed.
- */
- getInstanceModel(Element template, model) => model;
-
- /**
- * This syntax method allows a syntax to provide an alterate expansion of
- * the [template] contents. When the template wants to create an instance,
- * it will call this method with the template element.
- *
- * By default this will call `template.createInstance()`.
- */
- getInstanceFragment(Element template) => template.createInstance();
-}
-
-/** The callback used in the [CompoundBinding.combinator] field. */
-@Experimental
-typedef Object CompoundBindingCombinator(Map objects);
-
-/** Information about the instantiated template. */
-@Experimental
-class TemplateInstance {
- // TODO(rafaelw): firstNode & lastNode should be read-synchronous
- // in cases where script has modified the template instance boundary.
-
- /** The first node of this template instantiation. */
- final Node firstNode;
-
- /**
- * The last node of this template instantiation.
- * This could be identical to [firstNode] if the template only expanded to a
- * single node.
- */
- final Node lastNode;
-
- /** The model used to instantiate the template. */
- final model;
-
- TemplateInstance(this.firstNode, this.lastNode, this.model);
-}
-
-/**
- * Model-Driven Views contains a helper object which is useful for the
- * implementation of a Custom Syntax.
- *
- * var binding = new CompoundBinding((values) {
- * var combinedValue;
- * // compute combinedValue based on the current values which are provided
- * return combinedValue;
- * });
- * binding.bind('name1', obj1, path1);
- * binding.bind('name2', obj2, path2);
- * //...
- * binding.bind('nameN', objN, pathN);
- *
- * CompoundBinding is an object which knows how to listen to multiple path
- * values (registered via [bind]) and invoke its [combinator] when one or more
- * of the values have changed and set its [value] property to the return value
- * of the function. When any value has changed, all current values are provided
- * to the [combinator] in the single `values` argument.
- *
- * See [CustomBindingSyntax] for more information.
- */
-// TODO(jmesserly): what is the public API surface here? I just guessed;
-// most of it seemed non-public.
-@Experimental
-class CompoundBinding extends ObservableBase {
- CompoundBindingCombinator _combinator;
-
- // TODO(jmesserly): ideally these would be String keys, but sometimes we
- // use integers.
- Map<dynamic, StreamSubscription> _bindings = new Map();
- Map _values = new Map();
- bool _scheduled = false;
- bool _disposed = false;
- Object _value;
-
- CompoundBinding([CompoundBindingCombinator combinator]) {
- // TODO(jmesserly): this is a tweak to the original code, it seemed to me
- // that passing the combinator to the constructor should be equivalent to
- // setting it via the property.
- // I also added a null check to the combinator setter.
- this.combinator = combinator;
- }
-
- CompoundBindingCombinator get combinator => _combinator;
-
- set combinator(CompoundBindingCombinator combinator) {
- _combinator = combinator;
- if (combinator != null) _scheduleResolve();
- }
-
- static const _VALUE = const Symbol('value');
-
- get value => _value;
-
- void set value(newValue) {
- _value = notifyPropertyChange(_VALUE, _value, newValue);
- }
-
- // TODO(jmesserly): remove these workarounds when dart2js supports mirrors!
- getValueWorkaround(key) {
- if (key == _VALUE) return value;
- return null;
- }
- setValueWorkaround(key, val) {
- if (key == _VALUE) value = val;
- }
-
- void bind(name, model, String path) {
- unbind(name);
-
- _bindings[name] = new PathObserver(model, path).bindSync((value) {
- _values[name] = value;
- _scheduleResolve();
- });
- }
-
- void unbind(name, {bool suppressResolve: false}) {
- var binding = _bindings.remove(name);
- if (binding == null) return;
-
- binding.cancel();
- _values.remove(name);
- if (!suppressResolve) _scheduleResolve();
- }
-
- // TODO(rafaelw): Is this the right processing model?
- // TODO(rafaelw): Consider having a seperate ChangeSummary for
- // CompoundBindings so to excess dirtyChecks.
- void _scheduleResolve() {
- if (_scheduled) return;
- _scheduled = true;
- queueChangeRecords(resolve);
- }
-
- void resolve() {
- if (_disposed) return;
- _scheduled = false;
-
- if (_combinator == null) {
- throw new StateError(
- 'CompoundBinding attempted to resolve without a combinator');
- }
-
- value = _combinator(_values);
- }
-
- void dispose() {
- for (var binding in _bindings.values) {
- binding.cancel();
- }
- _bindings.clear();
- _values.clear();
-
- _disposed = true;
- value = null;
- }
-}
-
-abstract class _InputBinding {
- final InputElement element;
- PathObserver binding;
- StreamSubscription _pathSub;
- StreamSubscription _eventSub;
-
- _InputBinding(this.element, model, String path) {
- binding = new PathObserver(model, path);
- _pathSub = binding.bindSync(valueChanged);
- _eventSub = _getStreamForInputType(element).listen(updateBinding);
- }
-
- void valueChanged(newValue);
-
- void updateBinding(e);
-
- void unbind() {
- binding = null;
- _pathSub.cancel();
- _eventSub.cancel();
- }
-
-
- static Stream<Event> _getStreamForInputType(InputElement element) {
- switch (element.type) {
- case 'checkbox':
- return element.onClick;
- case 'radio':
- case 'select-multiple':
- case 'select-one':
- return element.onChange;
- default:
- return element.onInput;
- }
- }
-}
-
-class _ValueBinding extends _InputBinding {
- _ValueBinding(element, model, path) : super(element, model, path);
-
- void valueChanged(value) {
- element.value = value == null ? '' : '$value';
- }
-
- void updateBinding(e) {
- binding.value = element.value;
- }
-}
-
-class _CheckedBinding extends _InputBinding {
- _CheckedBinding(element, model, path) : super(element, model, path);
-
- void valueChanged(value) {
- element.checked = _Bindings._toBoolean(value);
- }
-
- void updateBinding(e) {
- binding.value = element.checked;
-
- // Only the radio button that is getting checked gets an event. We
- // therefore find all the associated radio buttons and update their
- // CheckedBinding manually.
- if (element is InputElement && element.type == 'radio') {
- for (var r in _getAssociatedRadioButtons(element)) {
- var checkedBinding = r._checkedBinding;
- if (checkedBinding != null) {
- // Set the value directly to avoid an infinite call stack.
- checkedBinding.binding.value = false;
- }
- }
- }
- }
-
- // |element| is assumed to be an HTMLInputElement with |type| == 'radio'.
- // Returns an array containing all radio buttons other than |element| that
- // have the same |name|, either in the form that |element| belongs to or,
- // if no form, in the document tree to which |element| belongs.
- //
- // This implementation is based upon the HTML spec definition of a
- // "radio button group":
- // http://www.whatwg.org/specs/web-apps/current-work/multipage/number-state.html#radio-button-group
- //
- static Iterable _getAssociatedRadioButtons(element) {
- if (!_isNodeInDocument(element)) return [];
- if (element.form != null) {
- return element.form.nodes.where((el) {
- return el != element &&
- el is InputElement &&
- el.type == 'radio' &&
- el.name == element.name;
- });
- } else {
- var radios = element.document.queryAll(
- 'input[type="radio"][name="${element.name}"]');
- return radios.where((el) => el != element && el.form == null);
- }
- }
-
- // TODO(jmesserly): polyfill document.contains API instead of doing it here
- static bool _isNodeInDocument(Node node) {
- // On non-IE this works:
- // return node.document.contains(node);
- var document = node.document;
- if (node == document || node.parentNode == document) return true;
- return document.documentElement.contains(node);
- }
-}
-
-class _Bindings {
- // TODO(jmesserly): not sure what kind of boolean conversion rules to
- // apply for template data-binding. HTML attributes are true if they're
- // present. However Dart only treats "true" as true. Since this is HTML we'll
- // use something closer to the HTML rules: null (missing) and false are false,
- // everything else is true. See: https://github.com/polymer-project/mdv/issues/59
- static bool _toBoolean(value) => null != value && false != value;
-
- static Node _createDeepCloneAndDecorateTemplates(Node node, String syntax) {
- var clone = node.clone(false); // Shallow clone.
- if (clone is Element && clone.isTemplate) {
- TemplateElement.decorate(clone, node);
- if (syntax != null) {
- clone.attributes.putIfAbsent('syntax', () => syntax);
- }
- }
-
- for (var c = node.$dom_firstChild; c != null; c = c.nextNode) {
- clone.append(_createDeepCloneAndDecorateTemplates(c, syntax));
- }
- return clone;
- }
-
- // http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/templates/index.html#dfn-template-contents-owner
- static Document _getTemplateContentsOwner(HtmlDocument doc) {
- if (doc.window == null) {
- return doc;
- }
- var d = doc._templateContentsOwner;
- if (d == null) {
- // TODO(arv): This should either be a Document or HTMLDocument depending
- // on doc.
- d = doc.implementation.createHtmlDocument('');
- while (d.$dom_lastChild != null) {
- d.$dom_lastChild.remove();
- }
- doc._templateContentsOwner = d;
- }
- return d;
- }
-
- static Element _cloneAndSeperateAttributeTemplate(Element templateElement) {
- var clone = templateElement.clone(false);
- var attributes = templateElement.attributes;
- for (var name in attributes.keys.toList()) {
- switch (name) {
- case 'template':
- case 'repeat':
- case 'bind':
- case 'ref':
- clone.attributes.remove(name);
- break;
- default:
- attributes.remove(name);
- break;
- }
- }
-
- return clone;
- }
-
- static void _liftNonNativeChildrenIntoContent(Element templateElement) {
- var content = templateElement.content;
-
- if (!templateElement._isAttributeTemplate) {
- var child;
- while ((child = templateElement.$dom_firstChild) != null) {
- content.append(child);
- }
- return;
- }
-
- // For attribute templates we copy the whole thing into the content and
- // we move the non template attributes into the content.
- //
- // <tr foo template>
- //
- // becomes
- //
- // <tr template>
- // + #document-fragment
- // + <tr foo>
- //
- var newRoot = _cloneAndSeperateAttributeTemplate(templateElement);
- var child;
- while ((child = templateElement.$dom_firstChild) != null) {
- newRoot.append(child);
- }
- content.append(newRoot);
- }
-
- static void _bootstrapTemplatesRecursivelyFrom(Node node) {
- void bootstrap(template) {
- if (!TemplateElement.decorate(template)) {
- _bootstrapTemplatesRecursivelyFrom(template.content);
- }
- }
-
- // Need to do this first as the contents may get lifted if |node| is
- // template.
- // TODO(jmesserly): node is DocumentFragment or Element
- var descendents = (node as dynamic).queryAll(_allTemplatesSelectors);
- if (node is Element && (node as Element).isTemplate) bootstrap(node);
-
- descendents.forEach(bootstrap);
- }
-
- static final String _allTemplatesSelectors = 'template, option[template], ' +
- Element._TABLE_TAGS.keys.map((k) => "$k[template]").join(", ");
-
- static void _addBindings(Node node, model, [CustomBindingSyntax syntax]) {
- if (node is Element) {
- _addAttributeBindings(node, model, syntax);
- } else if (node is Text) {
- _parseAndBind(node, 'text', node.text, model, syntax);
- }
-
- for (var c = node.$dom_firstChild; c != null; c = c.nextNode) {
- _addBindings(c, model, syntax);
- }
- }
-
- static void _addAttributeBindings(Element element, model, syntax) {
- element.attributes.forEach((name, value) {
- if (value == '' && (name == 'bind' || name == 'repeat')) {
- value = '{{}}';
- }
- _parseAndBind(element, name, value, model, syntax);
- });
- }
-
- static void _parseAndBind(Node node, String name, String text, model,
- CustomBindingSyntax syntax) {
-
- var tokens = _parseMustacheTokens(text);
- if (tokens.length == 0 || (tokens.length == 1 && tokens[0].isText)) {
- return;
- }
-
- // If this is a custom element, give the .xtag a change to bind.
- node = _nodeOrCustom(node);
-
- if (tokens.length == 1 && tokens[0].isBinding) {
- _bindOrDelegate(node, name, model, tokens[0].value, syntax);
- return;
- }
-
- var replacementBinding = new CompoundBinding();
- for (var i = 0; i < tokens.length; i++) {
- var token = tokens[i];
- if (token.isBinding) {
- _bindOrDelegate(replacementBinding, i, model, token.value, syntax);
- }
- }
-
- replacementBinding.combinator = (values) {
- var newValue = new StringBuffer();
-
- for (var i = 0; i < tokens.length; i++) {
- var token = tokens[i];
- if (token.isText) {
- newValue.write(token.value);
- } else {
- var value = values[i];
- if (value != null) {
- newValue.write(value);
- }
- }
- }
-
- return newValue.toString();
- };
-
- node.bind(name, replacementBinding, 'value');
- }
-
- static void _bindOrDelegate(node, name, model, String path,
- CustomBindingSyntax syntax) {
-
- if (syntax != null) {
- var delegateBinding = syntax.getBinding(model, path, name, node);
- if (delegateBinding != null) {
- model = delegateBinding;
- path = 'value';
- }
- }
-
- node.bind(name, model, path);
- }
-
- /**
- * Gets the [node]'s custom [Element.xtag] if present, otherwise returns
- * the node. This is used so nodes can override [Node.bind], [Node.unbind],
- * and [Node.unbindAll] like InputElement does.
- */
- // TODO(jmesserly): remove this when we can extend Element for real.
- static _nodeOrCustom(node) => node is Element ? node.xtag : node;
-
- static List<_BindingToken> _parseMustacheTokens(String s) {
- var result = [];
- var length = s.length;
- var index = 0, lastIndex = 0;
- while (lastIndex < length) {
- index = s.indexOf('{{', lastIndex);
- if (index < 0) {
- result.add(new _BindingToken(s.substring(lastIndex)));
- break;
- } else {
- // There is a non-empty text run before the next path token.
- if (index > 0 && lastIndex < index) {
- result.add(new _BindingToken(s.substring(lastIndex, index)));
- }
- lastIndex = index + 2;
- index = s.indexOf('}}', lastIndex);
- if (index < 0) {
- var text = s.substring(lastIndex - 2);
- if (result.length > 0 && result.last.isText) {
- result.last.value += text;
- } else {
- result.add(new _BindingToken(text));
- }
- break;
- }
-
- var value = s.substring(lastIndex, index).trim();
- result.add(new _BindingToken(value, isBinding: true));
- lastIndex = index + 2;
- }
- }
- return result;
- }
-
- static void _addTemplateInstanceRecord(fragment, model) {
- if (fragment.$dom_firstChild == null) {
- return;
- }
-
- var instanceRecord = new TemplateInstance(
- fragment.$dom_firstChild, fragment.$dom_lastChild, model);
-
- var node = instanceRecord.firstNode;
- while (node != null) {
- node._templateInstance = instanceRecord;
- node = node.nextNode;
- }
- }
-
- static void _removeAllBindingsRecursively(Node node) {
- _nodeOrCustom(node).unbindAll();
- for (var c = node.$dom_firstChild; c != null; c = c.nextNode) {
- _removeAllBindingsRecursively(c);
- }
- }
-
- static void _removeChild(Node parent, Node child) {
- child._templateInstance = null;
- if (child is Element && (child as Element).isTemplate) {
- Element childElement = child;
- // Make sure we stop observing when we remove an element.
- var templateIterator = childElement._templateIterator;
- if (templateIterator != null) {
- templateIterator.abandon();
- childElement._templateIterator = null;
- }
- }
- child.remove();
- _removeAllBindingsRecursively(child);
- }
-}
-
-class _BindingToken {
- final String value;
- final bool isBinding;
-
- _BindingToken(this.value, {this.isBinding: false});
-
- bool get isText => !isBinding;
-}
-
-class _TemplateIterator {
- final Element _templateElement;
- final List<Node> terminators = [];
- final CompoundBinding inputs;
- List iteratedValue;
-
- StreamSubscription _sub;
- StreamSubscription _valueBinding;
-
- _TemplateIterator(this._templateElement)
- : inputs = new CompoundBinding(resolveInputs) {
-
- _valueBinding = new PathObserver(inputs, 'value').bindSync(valueChanged);
- }
-
- static Object resolveInputs(Map values) {
- if (values.containsKey('if') && !_Bindings._toBoolean(values['if'])) {
- return null;
- }
-
- if (values.containsKey('repeat')) {
- return values['repeat'];
- }
-
- if (values.containsKey('bind')) {
- return [values['bind']];
- }
-
- return null;
- }
-
- void valueChanged(value) {
- clear();
- if (value is! List) return;
-
- iteratedValue = value;
-
- if (value is Observable) {
- _sub = value.changes.listen(_handleChanges);
- }
-
- int len = iteratedValue.length;
- if (len > 0) {
- _handleChanges([new ListChangeRecord(0, addedCount: len)]);
- }
- }
-
- Node getTerminatorAt(int index) {
- if (index == -1) return _templateElement;
- var terminator = terminators[index];
- if (terminator is! Element) return terminator;
-
- var subIterator = terminator._templateIterator;
- if (subIterator == null) return terminator;
-
- return subIterator.getTerminatorAt(subIterator.terminators.length - 1);
- }
-
- void insertInstanceAt(int index, Node fragment) {
- var previousTerminator = getTerminatorAt(index - 1);
- var terminator = fragment.$dom_lastChild;
- if (terminator == null) terminator = previousTerminator;
-
- terminators.insert(index, terminator);
- var parent = _templateElement.parentNode;
- parent.insertBefore(fragment, previousTerminator.nextNode);
- }
-
- void removeInstanceAt(int index) {
- var previousTerminator = getTerminatorAt(index - 1);
- var terminator = getTerminatorAt(index);
- terminators.removeAt(index);
-
- var parent = _templateElement.parentNode;
- while (terminator != previousTerminator) {
- var node = terminator;
- terminator = node.previousNode;
- _Bindings._removeChild(parent, node);
- }
- }
-
- void removeAllInstances() {
- if (terminators.length == 0) return;
-
- var previousTerminator = _templateElement;
- var terminator = getTerminatorAt(terminators.length - 1);
- terminators.length = 0;
-
- var parent = _templateElement.parentNode;
- while (terminator != previousTerminator) {
- var node = terminator;
- terminator = node.previousNode;
- _Bindings._removeChild(parent, node);
- }
- }
-
- void clear() {
- unobserve();
- removeAllInstances();
- iteratedValue = null;
- }
-
- getInstanceModel(model, syntax) {
- if (syntax != null) {
- return syntax.getInstanceModel(_templateElement, model);
- }
- return model;
- }
-
- getInstanceFragment(syntax) {
- if (syntax != null) {
- return syntax.getInstanceFragment(_templateElement);
- }
- return _templateElement.createInstance();
- }
-
- void _handleChanges(List<ListChangeRecord> splices) {
- var syntax = TemplateElement.syntax[_templateElement.attributes['syntax']];
-
- for (var splice in splices) {
- if (splice is! ListChangeRecord) continue;
-
- for (int i = 0; i < splice.removedCount; i++) {
- removeInstanceAt(splice.index);
- }
-
- for (var addIndex = splice.index;
- addIndex < splice.index + splice.addedCount;
- addIndex++) {
-
- var model = getInstanceModel(iteratedValue[addIndex], syntax);
-
- var fragment = getInstanceFragment(syntax);
-
- _Bindings._addBindings(fragment, model, syntax);
- _Bindings._addTemplateInstanceRecord(fragment, model);
-
- insertInstanceAt(addIndex, fragment);
- }
- }
- }
-
- void unobserve() {
- if (_sub == null) return;
- _sub.cancel();
- _sub = null;
- }
-
- void abandon() {
- unobserve();
- _valueBinding.cancel();
- inputs.dispose();
- }
-}
diff --git a/tools/dom/templates/html/dart2js/html_dart2js.darttemplate b/tools/dom/templates/html/dart2js/html_dart2js.darttemplate
index e213565..eae9aa2 100644
--- a/tools/dom/templates/html/dart2js/html_dart2js.darttemplate
+++ b/tools/dom/templates/html/dart2js/html_dart2js.darttemplate
@@ -21,7 +21,6 @@
import 'dart:isolate';
import 'dart:json' as json;
import 'dart:math';
-import 'dart:mdv_observe_impl';
import 'dart:typed_data';
// Not actually used, but imported since dart:html can generate these objects.
import 'dart:svg' as svg;
@@ -49,7 +48,6 @@
part '$AUXILIARY_DIR/Point.dart';
part '$AUXILIARY_DIR/ReadyState.dart';
part '$AUXILIARY_DIR/Rectangle.dart';
-part '$AUXILIARY_DIR/TemplateBindings.dart';
part '$AUXILIARY_DIR/_HttpRequestUtils.dart';
part '$AUXILIARY_DIR/Isolates.dart';
part '$AUXILIARY_DIR/Microtask.dart';
diff --git a/tools/dom/templates/html/dartium/html_dartium.darttemplate b/tools/dom/templates/html/dartium/html_dartium.darttemplate
index 2cdb23b..54903e0 100644
--- a/tools/dom/templates/html/dartium/html_dartium.darttemplate
+++ b/tools/dom/templates/html/dartium/html_dartium.darttemplate
@@ -21,7 +21,6 @@
import 'dart:json' as json;
import 'dart:math';
import 'dart:nativewrappers';
-import 'dart:mdv_observe_impl';
import 'dart:typed_data';
import 'dart:web_gl' as gl;
import 'dart:web_sql';
@@ -45,7 +44,6 @@
part '$AUXILIARY_DIR/Point.dart';
part '$AUXILIARY_DIR/ReadyState.dart';
part '$AUXILIARY_DIR/Rectangle.dart';
-part '$AUXILIARY_DIR/TemplateBindings.dart';
part '$AUXILIARY_DIR/WrappedEvent.dart';
part '$AUXILIARY_DIR/WrappedList.dart';
part '$AUXILIARY_DIR/_HttpRequestUtils.dart';
diff --git a/tools/dom/templates/html/impl/impl_Element.darttemplate b/tools/dom/templates/html/impl/impl_Element.darttemplate
index c5bf740..8e4757c 100644
--- a/tools/dom/templates/html/impl/impl_Element.darttemplate
+++ b/tools/dom/templates/html/impl/impl_Element.darttemplate
@@ -664,27 +664,6 @@
$endif
$if DART2JS
- @Creates('Null') // Set from Dart code; does not instantiate a native type.
-$endif
- Map<String, StreamSubscription> _attributeBindings;
-
- // TODO(jmesserly): I'm concerned about adding these to every element.
- // Conceptually all of these belong on TemplateElement. They are here to
- // support browsers that don't have <template> yet.
- // However even in the polyfill they're restricted to certain tags
- // (see [isTemplate]). So we can probably convert it to a (public) mixin, and
- // only mix it in to the elements that need it.
-$if DART2JS
- @Creates('Null') // Set from Dart code; does not instantiate a native type.
-$endif
- var _model;
-
-$if DART2JS
- @Creates('Null') // Set from Dart code; does not instantiate a native type.
-$endif
- _TemplateIterator _templateIterator;
-
-$if DART2JS
@Creates('Null') // Set from Dart code; does not instantiate a native type.
$endif
Element _templateInstanceRef;
@@ -697,124 +676,6 @@
bool _templateIsDecorated;
- // TODO(jmesserly): should path be optional, and default to empty path?
- // It is used that way in at least one path in JS TemplateElement tests
- // (see "BindImperative" test in original JS code).
- @Experimental
- void bind(String name, model, String path) {
- _bindElement(this, name, model, path);
- }
-
- // TODO(jmesserly): this is static to work around http://dartbug.com/10166
- // Similar issue for unbind/unbindAll below.
- static void _bindElement(Element self, String name, model, String path) {
- if (self._bindTemplate(name, model, path)) return;
-
- if (self._attributeBindings == null) {
- self._attributeBindings = new Map<String, StreamSubscription>();
- }
-
- self.xtag.attributes.remove(name);
-
- var changed;
- if (name.endsWith('?')) {
- name = name.substring(0, name.length - 1);
-
- changed = (value) {
- if (_Bindings._toBoolean(value)) {
- self.xtag.attributes[name] = '';
- } else {
- self.xtag.attributes.remove(name);
- }
- };
- } else {
- changed = (value) {
- // TODO(jmesserly): escape value if needed to protect against XSS.
- // See https://github.com/polymer-project/mdv/issues/58
- self.xtag.attributes[name] = value == null ? '' : '$value';
- };
- }
-
- self.unbind(name);
-
- self._attributeBindings[name] =
- new PathObserver(model, path).bindSync(changed);
- }
-
- @Experimental
- void unbind(String name) {
- _unbindElement(this, name);
- }
-
- static _unbindElement(Element self, String name) {
- if (self._unbindTemplate(name)) return;
- if (self._attributeBindings != null) {
- var binding = self._attributeBindings.remove(name);
- if (binding != null) binding.cancel();
- }
- }
-
- @Experimental
- void unbindAll() {
- _unbindAllElement(this);
- }
-
- static void _unbindAllElement(Element self) {
- self._unbindAllTemplate();
-
- if (self._attributeBindings != null) {
- for (var binding in self._attributeBindings.values) {
- binding.cancel();
- }
- self._attributeBindings = null;
- }
- }
-
- // TODO(jmesserly): unlike the JS polyfill, we can't mixin
- // HTMLTemplateElement at runtime into things that are semantically template
- // elements. So instead we implement it here with a runtime check.
- // If the bind succeeds, we return true, otherwise we return false and let
- // the normal Element.bind logic kick in.
- bool _bindTemplate(String name, model, String path) {
- if (isTemplate) {
- switch (name) {
- case 'bind':
- case 'repeat':
- case 'if':
- _ensureTemplate();
- if (_templateIterator == null) {
- _templateIterator = new _TemplateIterator(this);
- }
- _templateIterator.inputs.bind(name, model, path);
- return true;
- }
- }
- return false;
- }
-
- bool _unbindTemplate(String name) {
- if (isTemplate) {
- switch (name) {
- case 'bind':
- case 'repeat':
- case 'if':
- _ensureTemplate();
- if (_templateIterator != null) {
- _templateIterator.inputs.unbind(name);
- }
- return true;
- }
- }
- return false;
- }
-
- void _unbindAllTemplate() {
- if (isTemplate) {
- unbind('bind');
- unbind('repeat');
- unbind('if');
- }
- }
/**
* Gets the template this node refers to.
@@ -827,7 +688,19 @@
Element ref = null;
var refId = attributes['ref'];
if (refId != null) {
- ref = document.getElementById(refId);
+ var treeScope = this;
+ while (treeScope.parentNode != null) {
+ treeScope = treeScope.parentNode;
+ }
+
+ // Note: JS code tests that getElementById is present. We can't do that
+ // easily, so instead check for the types known to implement it.
+ if (treeScope is Document ||
+ treeScope is ShadowRoot ||
+ treeScope is svg.SvgSvgElement) {
+
+ ref = treeScope.getElementById(refId);
+ }
}
return ref != null ? ref : _templateInstanceRef;
@@ -850,38 +723,20 @@
@Experimental
DocumentFragment createInstance() {
_ensureTemplate();
-
- var template = ref;
- if (template == null) template = this;
-
- var instance = _Bindings._createDeepCloneAndDecorateTemplates(
- template.content, attributes['syntax']);
-
- if (TemplateElement._instanceCreated != null) {
- TemplateElement._instanceCreated.add(instance);
- }
- return instance;
+ return TemplateElement.mdvPackage(this).createInstance();
}
/**
* The data model which is inherited through the tree.
* This is only supported if [isTemplate] is true.
- *
- * Setting this will destructive propagate the value to all descendant nodes,
- * and reinstantiate all of the nodes expanded by this template.
- *
- * Currently this does not support propagation through Shadow DOMs.
*/
@Experimental
- get model => _model;
+ get model => TemplateElement.mdvPackage(this).model;
@Experimental
void set model(value) {
_ensureTemplate();
-
- var syntax = TemplateElement.syntax[attributes['syntax']];
- _model = value;
- _Bindings._addBindings(this, model, syntax);
+ TemplateElement.mdvPackage(this).model = value;
}
// TODO(jmesserly): const set would be better
@@ -898,7 +753,8 @@
};
bool get _isAttributeTemplate => attributes.containsKey('template') &&
- (localName == 'option' || _TABLE_TAGS.containsKey(localName));
+ (localName == 'option' || localName == 'optgroup' ||
+ _TABLE_TAGS.containsKey(localName));
/**
* Returns true if this node is a template.
@@ -907,7 +763,7 @@
* 'template' attribute and this tag supports attribute form for backwards
* compatibility with existing HTML parsers. The nodes that can use attribute
* form are table elments (THEAD, TBODY, TFOOT, TH, TR, TD, CAPTION, COLGROUP
- * and COL) and OPTION.
+ * and COL), OPTION, and OPTGROUP.
*/
// TODO(jmesserly): this is not a public MDV API, but it seems like a useful
// place to document which tags our polyfill considers to be templates.
diff --git a/tools/dom/templates/html/impl/impl_HTMLInputElement.darttemplate b/tools/dom/templates/html/impl/impl_HTMLInputElement.darttemplate
index a376140..68a3e9f 100644
--- a/tools/dom/templates/html/impl/impl_HTMLInputElement.darttemplate
+++ b/tools/dom/templates/html/impl/impl_HTMLInputElement.darttemplate
@@ -39,65 +39,6 @@
return e;
}
-$if DART2JS
- @Creates('Null') // Set from Dart code; does not instantiate a native type.
-$endif
- _ValueBinding _valueBinding;
-
-$if DART2JS
- @Creates('Null') // Set from Dart code; does not instantiate a native type.
-$endif
- _CheckedBinding _checkedBinding;
-
- @Experimental
- void bind(String name, model, String path) {
- switch (name) {
- case 'value':
- unbind('value');
- attributes.remove('value');
- _valueBinding = new _ValueBinding(this, model, path);
- break;
- case 'checked':
- unbind('checked');
- attributes.remove('checked');
- _checkedBinding = new _CheckedBinding(this, model, path);
- break;
- default:
- // TODO(jmesserly): this should be "super" (http://dartbug.com/10166).
- // Similar issue for unbind/unbindAll below.
- Element._bindElement(this, name, model, path);
- break;
- }
- }
-
- @Experimental
- void unbind(String name) {
- switch (name) {
- case 'value':
- if (_valueBinding != null) {
- _valueBinding.unbind();
- _valueBinding = null;
- }
- break;
- case 'checked':
- if (_checkedBinding != null) {
- _checkedBinding.unbind();
- _checkedBinding = null;
- }
- break;
- default:
- Element._unbindElement(this, name);
- break;
- }
- }
-
- @Experimental
- void unbindAll() {
- unbind('value');
- unbind('checked');
- Element._unbindAllElement(this);
- }
-
$!MEMBERS
}
diff --git a/tools/dom/templates/html/impl/impl_HTMLTemplateElement.darttemplate b/tools/dom/templates/html/impl/impl_HTMLTemplateElement.darttemplate
index 3ee3646..618df8c 100644
--- a/tools/dom/templates/html/impl/impl_HTMLTemplateElement.darttemplate
+++ b/tools/dom/templates/html/impl/impl_HTMLTemplateElement.darttemplate
@@ -6,6 +6,99 @@
part of $LIBRARYNAME;
+
+/**
+ * Model-Driven Views (MDV)'s native features enables a wide-range of use cases,
+ * but (by design) don't attempt to implement a wide array of specialized
+ * behaviors.
+ *
+ * Enabling these features in MDV is a matter of implementing and registering an
+ * MDV Custom Syntax. A Custom Syntax is an object which contains one or more
+ * delegation functions which implement specialized behavior. This object is
+ * registered with MDV via [TemplateElement.syntax]:
+ *
+ *
+ * HTML:
+ * <template bind syntax="MySyntax">
+ * {{ What!Ever('crazy')->thing^^^I+Want(data) }}
+ * </template>
+ *
+ * Dart:
+ * class MySyntax extends CustomBindingSyntax {
+ * getBinding(model, path, name, node) {
+ * // The magic happens here!
+ * }
+ * }
+ *
+ * ...
+ *
+ * TemplateElement.syntax['MySyntax'] = new MySyntax();
+ *
+ * See <https://github.com/polymer-project/mdv/blob/master/docs/syntax.md> for
+ * more information about Custom Syntax.
+ */
+// TODO(jmesserly): if this is just one method, a function type would make it
+// more Dart-friendly.
+@Experimental
+abstract class CustomBindingSyntax {
+ /**
+ * This syntax method allows for a custom interpretation of the contents of
+ * mustaches (`{{` ... `}}`).
+ *
+ * When a template is inserting an instance, it will invoke this method for
+ * each mustache which is encountered. The function is invoked with four
+ * arguments:
+ *
+ * - [model]: The data context for which this instance is being created.
+ * - [path]: The text contents (trimmed of outer whitespace) of the mustache.
+ * - [name]: The context in which the mustache occurs. Within element
+ * attributes, this will be the name of the attribute. Within text,
+ * this will be 'text'.
+ * - [node]: A reference to the node to which this binding will be created.
+ *
+ * If the method wishes to handle binding, it is required to return an object
+ * which has at least a `value` property that can be observed. If it does,
+ * then MDV will call [Node.bind on the node:
+ *
+ * node.bind(name, retval, 'value');
+ *
+ * If the 'getBinding' does not wish to override the binding, it should return
+ * null.
+ */
+ // TODO(jmesserly): I had to remove type annotations from "name" and "node"
+ // Normally they are String and Node respectively. But sometimes it will pass
+ // (int name, CompoundBinding node). That seems very confusing; we may want
+ // to change this API.
+ getBinding(model, String path, name, node) => null;
+
+ /**
+ * This syntax method allows a syntax to provide an alterate model than the
+ * one the template would otherwise use when producing an instance.
+ *
+ * When a template is about to create an instance, it will invoke this method
+ * The function is invoked with two arguments:
+ *
+ * - [template]: The template element which is about to create and insert an
+ * instance.
+ * - [model]: The data context for which this instance is being created.
+ *
+ * The template element will always use the return value of `getInstanceModel`
+ * as the model for the new instance. If the syntax does not wish to override
+ * the value, it should simply return the `model` value it was passed.
+ */
+ getInstanceModel(Element template, model) => model;
+
+ /**
+ * This syntax method allows a syntax to provide an alterate expansion of
+ * the [template] contents. When the template wants to create an instance,
+ * it will call this method with the template element.
+ *
+ * By default this will call `template.createInstance()`.
+ */
+ getInstanceFragment(Element template) => template.createInstance();
+}
+
+
@Experimental
$(ANNOTATIONS)class $CLASSNAME$EXTENDS$IMPLEMENTS$NATIVESPEC {
$!MEMBERS
@@ -15,24 +108,23 @@
@Experimental
DocumentFragment get content => $dom_content;
- static StreamController<DocumentFragment> _instanceCreated;
/**
- * *Warning*: This is an implementation helper for Model-Driven Views and
- * should not be used in your code.
+ * The MDV package, if available.
*
- * This event is fired whenever a template is instantiated via
- * [createInstance].
+ * This can be used to initialize MDV support via:
+ *
+ * import 'dart:html';
+ * import 'package:mdv/mdv.dart' as mdv;
+ * main() {
+ * mdv.initialize();
+ * }
*/
- // TODO(rafaelw): This is a hack, and is neccesary for the polyfill
- // because custom elements are not upgraded during clone()
- @Experimental
- static Stream<DocumentFragment> get instanceCreated {
- if (_instanceCreated == null) {
- _instanceCreated = new StreamController<DocumentFragment>(sync: true);
- }
- return _instanceCreated.stream;
- }
+ static Function mdvPackage = (node) {
+ throw new UnsupportedError("The MDV package is not available. "
+ "You can enable it with `import 'package:mdv/mdv.dart' as mdv;` and "
+ "`mdv.initialize()`");
+ };
/**
* Ensures proper API and content model for template elements.
@@ -49,30 +141,111 @@
// == true check because it starts as a null field.
if (template._templateIsDecorated == true) return false;
- template._templateIsDecorated = true;
-
_injectStylesheet();
- // Create content
- if (template is! TemplateElement) {
- var doc = _Bindings._getTemplateContentsOwner(template.document);
- template._templateContent = doc.createDocumentFragment();
+ var templateElement = template;
+ var isNative = templateElement is TemplateElement;
+ var bootstrapContents = isNative;
+ var liftContents = !isNative;
+ var liftRoot = false;
+
+ if (!isNative && templateElement._isAttributeTemplate) {
+ if (instanceRef != null) {
+ // TODO(jmesserly): this is just an assert in MDV.
+ throw new ArgumentError('instanceRef should not be supplied for '
+ 'attribute templates.');
+ }
+ templateElement = _extractTemplateFromAttributeTemplate(template);
+ isNative = templateElement is TemplateElement;
+ liftRoot = true;
+ }
+
+ templateElement._templateIsDecorated = true;
+
+ if (!isNative) {
+ var doc = _getTemplateContentsOwner(templateElement.document);
+ templateElement._templateContent = doc.createDocumentFragment();
}
if (instanceRef != null) {
- template._templateInstanceRef = instanceRef;
- return true; // content is empty.
- }
-
- if (template is TemplateElement) {
- bootstrap(template.content);
- } else {
- _Bindings._liftNonNativeChildrenIntoContent(template);
+ // template is contained within an instance, its direct content must be
+ // empty
+ templateElement._templateInstanceRef = instanceRef;
+ } else if (liftContents) {
+ _liftNonNativeChildrenIntoContent(templateElement, template, liftRoot);
+ } else if (bootstrapContents) {
+ bootstrap(templateElement.content);
}
return true;
}
+ // http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/templates/index.html#dfn-template-contents-owner
+ static Document _getTemplateContentsOwner(HtmlDocument doc) {
+ if (doc.window == null) {
+ return doc;
+ }
+ var d = doc._templateContentsOwner;
+ if (d == null) {
+ // TODO(arv): This should either be a Document or HTMLDocument depending
+ // on doc.
+ d = doc.implementation.createHtmlDocument('');
+ while (d.lastChild != null) {
+ d.lastChild.remove();
+ }
+ doc._templateContentsOwner = d;
+ }
+ return d;
+ }
+
+ // For non-template browsers, the parser will disallow <template> in certain
+ // locations, so we allow "attribute templates" which combine the template
+ // element with the top-level container node of the content, e.g.
+ //
+ // <tr template repeat="{{ foo }}"" class="bar"><td>Bar</td></tr>
+ //
+ // becomes
+ //
+ // <template repeat="{{ foo }}">
+ // + #document-fragment
+ // + <tr class="bar">
+ // + <td>Bar</td>
+ //
+ static Element _extractTemplateFromAttributeTemplate(Element el) {
+ var template = el.document.$dom_createElement('template');
+ el.parentNode.insertBefore(template, el);
+
+ for (var name in el.attributes.keys.toList()) {
+ switch (name) {
+ case 'template':
+ el.attributes.remove(name);
+ break;
+ case 'repeat':
+ case 'bind':
+ case 'ref':
+ template.attributes[name] = el.attributes.remove(name);
+ break;
+ }
+ }
+
+ return template;
+ }
+
+ static void _liftNonNativeChildrenIntoContent(Element template, Element el,
+ bool useRoot) {
+
+ var content = template.content;
+ if (useRoot) {
+ content.append(el);
+ return;
+ }
+
+ var child;
+ while ((child = el.firstChild) != null) {
+ content.append(child);
+ }
+ }
+
/**
* This used to decorate recursively all templates from a given node.
*
@@ -83,24 +256,26 @@
// TODO(rafaelw): Review whether this is the right public API.
@Experimental
static void bootstrap(Node content) {
- _Bindings._bootstrapTemplatesRecursivelyFrom(content);
+ void _bootstrap(template) {
+ if (!TemplateElement.decorate(template)) {
+ bootstrap(template.content);
+ }
+ }
+
+ // Need to do this first as the contents may get lifted if |node| is
+ // template.
+ // TODO(jmesserly): content is DocumentFragment or Element
+ var descendents = (content as dynamic).queryAll(_allTemplatesSelectors);
+ if (content is Element && (content as Element).isTemplate) {
+ _bootstrap(content);
+ }
+
+ descendents.forEach(_bootstrap);
}
- /**
- * Binds all mustaches recursively starting from the [root] node.
- *
- * Note: this is not an official Model-Driven-Views API; it is intended to
- * support binding the [ShadowRoot]'s content to a model.
- */
- // TODO(jmesserly): this is needed to avoid two <template> nodes when using
- // bindings in a custom element's template. See also:
- // https://github.com/polymer-project/polymer/blob/master/src/bindMDV.js#L68
- // Called from:
- // https://github.com/polymer-project/polymer/blob/master/src/register.js#L99
- @Experimental
- static void bindModel(Node root, model, [CustomBindingSyntax syntax]) {
- _Bindings._addBindings(root, model, syntax);
- }
+ static final String _allTemplatesSelectors =
+ 'template, option[template], optgroup[template], ' +
+ Element._TABLE_TAGS.keys.map((k) => "$k[template]").join(", ");
static bool _initStyles;
diff --git a/tools/dom/templates/html/impl/impl_Node.darttemplate b/tools/dom/templates/html/impl/impl_Node.darttemplate
index 02edf51..b17787c 100644
--- a/tools/dom/templates/html/impl/impl_Node.darttemplate
+++ b/tools/dom/templates/html/impl/impl_Node.darttemplate
@@ -34,12 +34,12 @@
}
$else
Node get first {
- Node result = _this.$dom_firstChild;
+ Node result = _this.firstChild;
if (result == null) throw new StateError("No elements");
return result;
}
Node get last {
- Node result = _this.$dom_lastChild;
+ Node result = _this.lastChild;
if (result == null) throw new StateError("No elements");
return result;
}
@@ -47,7 +47,7 @@
int l = this.length;
if (l == 0) throw new StateError("No elements");
if (l > 1) throw new StateError("More than one element");
- return _this.$dom_firstChild;
+ return _this.firstChild;
}
$endif
@@ -61,8 +61,7 @@
if (!identical(otherList._this, _this)) {
// Optimized route for copying between nodes.
for (var i = 0, len = otherList.length; i < len; ++i) {
- // Should use $dom_firstChild, Bug 8886.
- _this.append(otherList[0]);
+ _this.append(otherList._this.firstChild);
}
}
return;
@@ -120,7 +119,7 @@
// This implementation of removeWhere/retainWhere is more efficient
// than the default in ListBase. Child nodes can be removed in constant
// time.
- Node child = _this.$dom_firstChild;
+ Node child = _this.firstChild;
while (child != null) {
Node nextChild = child.nextNode;
if (test(child) == removeMatching) {
@@ -179,6 +178,27 @@
Node operator[](int index) => _this.$dom_childNodes[index];
}
+/** Information about the instantiated template. */
+class TemplateInstance {
+ // TODO(rafaelw): firstNode & lastNode should be read-synchronous
+ // in cases where script has modified the template instance boundary.
+
+ /** The first node of this template instantiation. */
+ final Node firstNode;
+
+ /**
+ * The last node of this template instantiation.
+ * This could be identical to [firstNode] if the template only expanded to a
+ * single node.
+ */
+ final Node lastNode;
+
+ /** The model used to instantiate the template. */
+ final model;
+
+ TemplateInstance(this.firstNode, this.lastNode, this.model);
+}
+
$(ANNOTATIONS)class $CLASSNAME$EXTENDS$IMPLEMENTS$NATIVESPEC {
List<Node> get nodes {
return new _ChildNodeListLazy(this);
@@ -237,8 +257,7 @@
// Optimized route for copying between nodes.
for (var i = 0, len = otherList.length; i < len; ++i) {
- // Should use $dom_firstChild, Bug 8886.
- this.insertBefore(otherList[0], refChild);
+ this.insertBefore(otherList._this.firstChild, refChild);
}
} else {
for (var node in newNodes) {
@@ -258,26 +277,25 @@
*/
@Experimental
void bind(String name, model, String path) {
- // TODO(jmesserly): should we throw instead?
- window.console.error('Unhandled binding to Node: '
- '$this $name $model $path');
+ TemplateElement.mdvPackage(this).bind(name, model, path);
}
/** Unbinds the attribute [name]. */
@Experimental
- void unbind(String name) {}
+ void unbind(String name) {
+ TemplateElement.mdvPackage(this).unbind(name);
+ }
/** Unbinds all bound attributes. */
@Experimental
- void unbindAll() {}
-
- TemplateInstance _templateInstance;
+ void unbindAll() {
+ TemplateElement.mdvPackage(this).unbindAll();
+ }
/** Gets the template instance that instantiated this node, if any. */
@Experimental
TemplateInstance get templateInstance =>
- _templateInstance != null ? _templateInstance :
- (parent != null ? parent.templateInstance : null);
+ TemplateElement.mdvPackage(this).templateInstance;
$!MEMBERS
}
diff --git a/tools/dom/templates/html/impl/impl_Text.darttemplate b/tools/dom/templates/html/impl/impl_Text.darttemplate
index 2675d8b..45fb721 100644
--- a/tools/dom/templates/html/impl/impl_Text.darttemplate
+++ b/tools/dom/templates/html/impl/impl_Text.darttemplate
@@ -9,42 +9,4 @@
$(ANNOTATIONS)class $CLASSNAME$EXTENDS$IMPLEMENTS$NATIVESPEC {
factory $CLASSNAME(String data) => document.$dom_createTextNode(data);
$!MEMBERS
-
-$if DART2JS
- @Creates('Null') // Set from Dart code; does not instantiate a native type.
-$endif
- StreamSubscription _textBinding;
-
- @Experimental
- void bind(String name, model, String path) {
- if (name != 'text') {
- super.bind(name, model, path);
- return;
- }
-
- unbind('text');
-
- _textBinding = new PathObserver(model, path).bindSync((value) {
- text = value == null ? '' : '$value';
- });
- }
-
- @Experimental
- void unbind(String name) {
- if (name != 'text') {
- super.unbind(name);
- return;
- }
-
- if (_textBinding == null) return;
-
- _textBinding.cancel();
- _textBinding = null;
- }
-
- @Experimental
- void unbindAll() {
- unbind('text');
- super.unbindAll();
- }
}
diff --git a/tools/release/version.dart b/tools/release/version.dart
index 8e7af38..cec7a3f 100644
--- a/tools/release/version.dart
+++ b/tools/release/version.dart
@@ -149,21 +149,22 @@
Future<int> getRevision() {
if (repositoryType == RepositoryType.UNKNOWN) {
- return new Future.immediate(0);
+ return new Future.value(0);
}
var isSvn = repositoryType == RepositoryType.SVN;
var command = isSvn ? "svn" : "git";
command = "$command${getExecutableSuffix()}";
var arguments = isSvn ? ["info"] : ["svn", "info"];
- ProcessOptions options = new ProcessOptions();
// Run the command from the root to get the last changed revision for this
// "branch". Since we have both trunk and bleeding edge in the same
// repository and since we always build TOT we need this to get the
// right version number.
Path toolsDirectory = new Path(_versionFileName).directoryPath;
Path root = toolsDirectory.join(new Path(".."));
- options.workingDirectory = root.toNativePath();
- return Process.run(command, arguments, options).then((result) {
+ var workingDirectory = root.toNativePath();
+ return Process.run(command,
+ arguments,
+ workingDirectory: workingDirectory).then((result) {
if (result.exitCode != 0) {
return 0;
}
@@ -201,7 +202,7 @@
return "$absolutePath" == '/';
}
- var currentPath = new Path(new Directory.current().path);
+ var currentPath = new Path(Directory.current.path);
while (true) {
if (hasDirectory(currentPath, '.svn')) {
return RepositoryType.SVN;
diff --git a/tools/test.dart b/tools/test.dart
index fc789bf..787a1db 100755
--- a/tools/test.dart
+++ b/tools/test.dart
@@ -238,9 +238,9 @@
var printFailureSummary = progressIndicator != 'buildbot';
eventListener.add(new TestFailurePrinter(printFailureSummary, formatter));
}
- eventListener.add(new ProgressIndicator.fromName(progressIndicator,
- startTime,
- formatter));
+ eventListener.add(progressIndicatorFromName(progressIndicator,
+ startTime,
+ formatter));
if (printTiming) {
eventListener.add(new TimingPrinter(startTime));
}
@@ -302,7 +302,7 @@
}
}
}
- }, onDone: completer.complete());
+ }, onDone: completer.complete);
} else {
completer.complete();
}
diff --git a/tools/testing/dart/android.dart b/tools/testing/dart/android.dart
index 328cd07..8f79ab4 100644
--- a/tools/testing/dart/android.dart
+++ b/tools/testing/dart/android.dart
@@ -35,11 +35,8 @@
List<String> args,
[String stdin = ""]) {
Future<String> getOutput(Stream<List<int>> stream) {
- return stream.transform(new StringDecoder())
- .reduce(new StringBuffer(), (buf, data) {
- buf.write(data);
- return buf;
- }).then((buf) => buf.toString());
+ return stream.transform(new StringDecoder()).toList()
+ .then((data) => data.join(""));
}
DebugLogger.info("Running: '\$ $executable ${args.join(' ')}'");
diff --git a/tools/testing/dart/browser_controller.dart b/tools/testing/dart/browser_controller.dart
index f3d0acc..c1e696c 100644
--- a/tools/testing/dart/browser_controller.dart
+++ b/tools/testing/dart/browser_controller.dart
@@ -98,7 +98,7 @@
return done;
} else {
_logEvent("The process is already dead.");
- return new Future.immediate(true);
+ return new Future.value(true);
}
}
@@ -171,12 +171,13 @@
* The binary used to run safari - changing this can be nececcary for
* testing or using non standard safari installation.
*/
- const String binary = "/Applications/Safari.app/Contents/MacOS/Safari";
+ static const String binary = "/Applications/Safari.app/Contents/MacOS/Safari";
/**
* We get the safari version by parsing a version file
*/
- const String versionFile = "/Applications/Safari.app/Contents/version.plist";
+ static const String versionFile =
+ "/Applications/Safari.app/Contents/version.plist";
/**
* Directories where safari stores state. We delete these if the deleteCache
@@ -205,7 +206,7 @@
}
Future<bool> deleteIfExists(Iterator<String> paths) {
- if (!paths.moveNext()) return new Future.immediate(true);
+ if (!paths.moveNext()) return new Future.value(true);
Directory directory = new Directory(paths.current);
return directory.exists().then((exists) {
if (exists) {
@@ -226,7 +227,7 @@
// Clears the cache if the static deleteCache flag is set.
// Returns false if the command to actually clear the cache did not complete.
Future<bool> clearCache() {
- if (!deleteCache) return new Future.immediate(true);
+ if (!deleteCache) return new Future.value(true);
var home = Platform.environment['HOME'];
Iterator iterator = CACHE_DIRECTORIES.map((s) => "$home/$s").iterator;
return deleteIfExists(iterator);
@@ -267,7 +268,7 @@
void _createLaunchHTML(var path, var url) {
var file = new File("${path}/launch.html");
- var randomFile = file.openSync(FileMode.WRITE);
+ var randomFile = file.openSync(mode: FileMode.WRITE);
var content = '<script language="JavaScript">location = "$url"</script>';
randomFile.writeStringSync(content);
randomFile.close();
@@ -315,7 +316,7 @@
* The binary used to run chrome - changing this can be nececcary for
* testing or using non standard chrome installation.
*/
- const String binary = "google-chrome";
+ static const String binary = "google-chrome";
Future<bool> start(String url) {
_logEvent("Starting chrome browser on: $url");
@@ -324,7 +325,7 @@
if (versionResult.exitCode != 0) {
_logEvent("Failed to chrome get version");
_logEvent("Make sure $binary is a valid program for running chrome");
- return new Future.immediate(false);
+ return new Future.value(false);
}
version = versionResult.stdout;
_logEvent("Got version: $version");
@@ -347,12 +348,12 @@
}
class AndroidChrome extends Browser {
- const String viewAction = 'android.intent.action.VIEW';
- const String mainAction = 'android.intent.action.MAIN';
- const String chromePackage = 'com.android.chrome';
- const String browserPackage = 'com.android.browser';
- const String firefoxPackage = 'org.mozilla.firefox';
- const String turnScreenOnPackage = 'com.google.dart.turnscreenon';
+ static const String viewAction = 'android.intent.action.VIEW';
+ static const String mainAction = 'android.intent.action.MAIN';
+ static const String chromePackage = 'com.android.chrome';
+ static const String browserPackage = 'com.android.browser';
+ static const String firefoxPackage = 'org.mozilla.firefox';
+ static const String turnScreenOnPackage = 'com.google.dart.turnscreenon';
AndroidEmulator _emulator;
AdbDevice _adbDevice;
@@ -406,7 +407,7 @@
return _adbDevice.killAll().then((_) => true);
});
}
- return new Future.immediate(true);
+ return new Future.value(true);
}
String toString() => "chromeOnAndroid";
@@ -417,16 +418,16 @@
* The binary used to run firefox - changing this can be nececcary for
* testing or using non standard firefox installation.
*/
- const String binary = "firefox";
+ static const String binary = "firefox";
- const String enablePopUp =
+ static const String enablePopUp =
'user_pref("dom.disable_open_during_load", false);';
- const String disableDefaultCheck =
+ static const String disableDefaultCheck =
'user_pref("browser.shell.checkDefaultBrowser", false);';
Future _createPreferenceFile(var path) {
var file = new File("${path.toString()}/user.js");
- var randomFile = file.openSync(FileMode.WRITE);
+ var randomFile = file.openSync(mode: FileMode.WRITE);
randomFile.writeStringSync(enablePopUp);
randomFile.writeStringSync(disableDefaultCheck);
randomFile.close();
@@ -440,7 +441,7 @@
if (versionResult.exitCode != 0) {
_logEvent("Failed to firefox get version");
_logEvent("Make sure $binary is a valid program for running firefox");
- return new Future.immediate(false);
+ return new Future.value(false);
}
version = versionResult.stdout;
_logEvent("Got version: $version");
@@ -776,11 +777,11 @@
final String local_ip;
- const String driverPath = "/driver";
- const String nextTestPath = "/next_test";
- const String reportPath = "/report";
- const String waitSignal = "WAIT";
- const String terminateSignal = "TERMINATE";
+ static const String driverPath = "/driver";
+ static const String nextTestPath = "/next_test";
+ static const String reportPath = "/report";
+ static const String waitSignal = "WAIT";
+ static const String terminateSignal = "TERMINATE";
var testCount = 0;
var httpServer;
@@ -800,8 +801,8 @@
DebugLogger.info("Handling request to: ${request.uri.path}");
if (request.uri.path.startsWith(reportPath)) {
var browserId = request.uri.path.substring(reportPath.length + 1);
- var testId = int.parse(request.queryParameters["id"].split("=")[1]);
-
+ var testId =
+ int.parse(request.uri.queryParameters["id"].split("=")[1]);
handleReport(request, browserId, testId);
// handleReport will asynchroniously fetch the data and will handle
// the closing of the streams.
@@ -932,7 +933,6 @@
// Don't do anything, we will be killed shortly.
} else {
var elapsed = new Date() - start;
- reportError('Done getting task at: ' + elapsed);
// TODO(ricow): Do something more clever here.
if (nextTask != undefined) alert('This is really bad');
// The task is send to us as:
@@ -940,6 +940,7 @@
var split = this.responseText.split('#');
var nextTask = split[0];
current_id = split[1];
+ reportError('Done getting task : ' + elapsed);
did_start = false;
run(nextTask);
}
diff --git a/tools/testing/dart/http_server.dart b/tools/testing/dart/http_server.dart
index 986bd53..b222d87 100644
--- a/tools/testing/dart/http_server.dart
+++ b/tools/testing/dart/http_server.dart
@@ -7,7 +7,6 @@
import 'dart:async';
import 'dart:io';
import 'dart:isolate';
-import 'dart:uri';
import 'test_suite.dart'; // For TestUtils.
// TODO(efortuna): Rewrite to not use the args library and simply take an
// expected number of arguments, so test.dart doesn't rely on the args library?
@@ -208,8 +207,11 @@
void _handleWebSocketRequest(HttpRequest request) {
WebSocketTransformer.upgrade(request).then((websocket) {
+ // We ignore failures to write to the socket, this happens if the browser
+ // closes the connection.
+ websocket.done.catchError((_) {});
websocket.listen((data) {
- websocket.send(data);
+ websocket.add(data);
websocket.close();
}, onError: (e) {
DebugLogger.warning('HttpServer: error while echoing to WebSocket', e);
@@ -314,10 +316,10 @@
var headerOrigin = request.headers.value('Origin');
var allowedOrigin;
if (headerOrigin != null) {
- var origin = new Uri(headerOrigin);
+ var origin = Uri.parse(headerOrigin);
// Allow loading from http://*:$allowedPort in browsers.
allowedOrigin =
- '${origin.scheme}://${origin.domain}:${allowedPort}';
+ '${origin.scheme}://${origin.host}:${allowedPort}';
} else {
// IE10 appears to be bugged and is not sending the Origin header
// when making CORS requests to the same domain but different port.
diff --git a/tools/testing/dart/multitest.dart b/tools/testing/dart/multitest.dart
index 1af62b2..11e5ce1 100644
--- a/tools/testing/dart/multitest.dart
+++ b/tools/testing/dart/multitest.dart
@@ -124,7 +124,7 @@
// Copy all the tests into the output map tests, as multiline strings.
for (String key in testsAsLines.keys) {
- tests[key] = testsAsLines[key].join(line_separator).concat(line_separator);
+ tests[key] = testsAsLines[key].join(line_separator) + line_separator;
}
}
@@ -220,7 +220,7 @@
final File file = new File.fromPath(multitestFilename);
file.createSync();
- RandomAccessFile openedFile = file.openSync(FileMode.WRITE);
+ RandomAccessFile openedFile = file.openSync(mode: FileMode.WRITE);
openedFile.writeStringSync(tests[key]);
openedFile.closeSync();
Set<String> outcome = outcomes[key];
diff --git a/tools/testing/dart/record_and_replay.dart b/tools/testing/dart/record_and_replay.dart
index fd5df68..c2ba7c9 100644
--- a/tools/testing/dart/record_and_replay.dart
+++ b/tools/testing/dart/record_and_replay.dart
@@ -41,7 +41,7 @@
var _cwd;
TestCaseRecorder(this._outputPath) {
- _cwd = new Directory.current().path;
+ _cwd = Directory.current.path;
}
void nextTestCase(TestCase testCase) {
diff --git a/tools/testing/dart/test_progress.dart b/tools/testing/dart/test_progress.dart
index 8c8d7830..b288db5 100644
--- a/tools/testing/dart/test_progress.dart
+++ b/tools/testing/dart/test_progress.dart
@@ -188,7 +188,7 @@
void _appendToFlakyFile(String msg) {
var file = new File(TestUtils.flakyFileName());
- var fd = file.openSync(FileMode.APPEND);
+ var fd = file.openSync(mode: FileMode.APPEND);
fd.writeStringSync(msg);
fd.closeSync();
}
@@ -343,7 +343,7 @@
}
}
-class LineProgressIndicator extends EventListener implements ProgressIndicator {
+class LineProgressIndicator extends EventListener {
void done(TestCase test) {
var status = 'pass';
if (test.lastCommandOutput.unexpectedOutput) {
@@ -395,25 +395,6 @@
class ProgressIndicator extends EventListener {
ProgressIndicator(this._startTime);
- factory ProgressIndicator.fromName(String name,
- DateTime startTime,
- Formatter formatter) {
- switch (name) {
- case 'compact':
- return new CompactProgressIndicator(startTime, formatter);
- case 'line':
- return new LineProgressIndicator();
- case 'verbose':
- return new VerboseProgressIndicator(startTime);
- case 'status':
- return new ProgressIndicator(startTime);
- case 'buildbot':
- return new BuildbotProgressIndicator(startTime);
- default:
- assert(false);
- break;
- }
- }
void testAdded() { _foundTests++; }
@@ -542,3 +523,24 @@
print(_buildSummaryEnd(_failedTests));
}
}
+
+
+EventListener progressIndicatorFromName(String name,
+ DateTime startTime,
+ Formatter formatter) {
+ switch (name) {
+ case 'compact':
+ return new CompactProgressIndicator(startTime, formatter);
+ case 'line':
+ return new LineProgressIndicator();
+ case 'verbose':
+ return new VerboseProgressIndicator(startTime);
+ case 'status':
+ return new ProgressIndicator(startTime);
+ case 'buildbot':
+ return new BuildbotProgressIndicator(startTime);
+ default:
+ assert(false);
+ break;
+ }
+}
diff --git a/tools/testing/dart/test_runner.dart b/tools/testing/dart/test_runner.dart
index 73c9cba..1cae1d7 100644
--- a/tools/testing/dart/test_runner.dart
+++ b/tools/testing/dart/test_runner.dart
@@ -17,7 +17,6 @@
// CommandOutput.exitCode in subclasses of CommandOutput.
import "dart:io" as io;
import "dart:isolate";
-import "dart:uri";
import "browser_controller.dart";
import "http_server.dart" as http_server;
import "status_file_parser.dart";
@@ -123,7 +122,7 @@
String toString() => commandLine;
- Future<bool> get outputIsUpToDate => new Future.immediate(false);
+ Future<bool> get outputIsUpToDate => new Future.value(false);
io.Path get expectedOutputFile => null;
bool get isPixelTest => false;
}
@@ -141,19 +140,19 @@
: super(executable, arguments);
Future<bool> get outputIsUpToDate {
- if (_neverSkipCompilation) return new Future.immediate(false);
+ if (_neverSkipCompilation) return new Future.value(false);
Future<List<Uri>> readDepsFile(String path) {
var file = new io.File(new io.Path(path).toNativePath());
if (!file.existsSync()) {
- return new Future.immediate(null);
+ return new Future.value(null);
}
return file.readAsLines().then((List<String> lines) {
var dependencies = new List<Uri>();
for (var line in lines) {
line = line.trim();
if (line.length > 0) {
- dependencies.add(new Uri(line));
+ dependencies.add(Uri.parse(line));
}
}
return dependencies;
@@ -164,7 +163,7 @@
if (dependencies != null) {
dependencies.addAll(_bootstrapDependencies);
var jsOutputLastModified = TestUtils.lastModifiedCache.getLastModified(
- new Uri.fromComponents(scheme: 'file', path: _outputFile));
+ new Uri(scheme: 'file', path: _outputFile));
if (jsOutputLastModified != null) {
for (var dependency in dependencies) {
var dependencyLastModified =
@@ -985,7 +984,6 @@
return argument;
}
}).toList();
- return;
}
@@ -1029,12 +1027,13 @@
compilationSkipped = true;
_commandComplete(0);
} else {
- var processOptions = _createProcessOptions();
+ var processEnvironment = _createProcessEnvironment();
var commandArguments = _modifySeleniumTimeout(command.arguments,
testCase.timeout);
- Future processFuture = io.Process.start(command.executable,
- commandArguments,
- processOptions);
+ Future processFuture =
+ io.Process.start(command.executable,
+ commandArguments,
+ environment: processEnvironment);
processFuture.then((io.Process process) {
// Close stdin so that tests that try to block on input will fail.
process.stdin.close();
@@ -1088,19 +1087,18 @@
source.listen(destination.addAll);
}
- io.ProcessOptions _createProcessOptions() {
+ Map<String, String> _createProcessEnvironment() {
var baseEnvironment = command.environment != null ?
command.environment : io.Platform.environment;
- io.ProcessOptions options = new io.ProcessOptions();
- options.environment = new Map<String, String>.from(baseEnvironment);
- options.environment['DART_CONFIGURATION'] =
+ var environment = new Map<String, String>.from(baseEnvironment);
+ environment['DART_CONFIGURATION'] =
TestUtils.configurationDir(testCase.configuration);
for (var excludedEnvironmentVariable in EXCLUDED_ENVIRONMENT_VARIABLES) {
- options.environment.remove(excludedEnvironmentVariable);
+ environment.remove(excludedEnvironmentVariable);
}
- return options;
+ return environment;
}
}
@@ -1160,7 +1158,7 @@
}
Future terminate() {
- if (_process == null) return new Future.immediate(true);
+ if (_process == null) return new Future.value(true);
Completer completer = new Completer();
Timer killTimer;
_processExitHandler = (_) {
@@ -1208,7 +1206,7 @@
String _createArgumentsLine(List<String> arguments, int timeout) {
arguments = _modifySeleniumTimeout(arguments, timeout);
- return arguments.join(' ').concat('\n');
+ return arguments.join(' ') + '\n';
}
void _reportResult() {
@@ -1664,7 +1662,7 @@
io.exit(1);
});
}
- return new Future.immediate(_browserTestRunners[runtime]);
+ return new Future.value(_browserTestRunners[runtime]);
}
void _startBrowserControllerTest(var test) {
@@ -1763,7 +1761,9 @@
_numBrowserProcesses--;
}
eventFinishedTestCase(test_arg);
- if (test_arg is BrowserTestCase) test_arg.notifyObservers();
+ if (test_arg is BrowserTestCase) {
+ (test_arg as BrowserTestCase).notifyObservers();
+ }
oldCallback(test_arg);
_tryRunTest();
};
@@ -1790,7 +1790,9 @@
if (isTestCaseFinished(testCase)) {
testCase.completed();
eventFinishedTestCase(testCase);
- if (testCase is BrowserTestCase) testCase.notifyObservers();
+ if (testCase is BrowserTestCase) {
+ (testCase as BrowserTestCase).notifyObservers();
+ }
} else {
_tests.addFirst(testCase);
}
diff --git a/tools/testing/dart/test_suite.dart b/tools/testing/dart/test_suite.dart
index 1e1e051..41bdf2f 100644
--- a/tools/testing/dart/test_suite.dart
+++ b/tools/testing/dart/test_suite.dart
@@ -17,7 +17,6 @@
import "dart:async";
import "dart:io";
import "dart:isolate";
-import "dart:uri";
import "drt_updater.dart";
import "multitest.dart";
import "status_file_parser.dart";
@@ -49,7 +48,7 @@
* completes immediately with `null`.
*/
Future asynchronously(function()) {
- if (function == null) return new Future.immediate(null);
+ if (function == null) return new Future.value(null);
var completer = new Completer();
Timer.run(() => completer.complete(function()));
@@ -61,7 +60,7 @@
// TODO(rnystrom): Copied from web_components. Remove from here when it gets
// added to dart:core. (See #6626.)
class FutureGroup {
- const _FINISHED = -1;
+ static const _FINISHED = -1;
int _pending = 0;
Completer<List> _completer = new Completer<List>();
final List<Future> futures = <Future>[];
@@ -490,7 +489,7 @@
var snapshotPath = TestUtils.absolutePath(new Path(buildDir).join(
new Path('dart-sdk/bin/snapshots/'
'utils_wrapper.dart.snapshot'))).toString();
- return [new Uri.fromComponents(scheme: 'file', path: snapshotPath)];
+ return [new Uri(scheme: 'file', path: snapshotPath)];
}
/**
@@ -540,7 +539,7 @@
var completer = new Completer();
var updater = runtimeUpdater(configuration);
if (updater == null || updater.updated) {
- return new Future.immediate(null);
+ return new Future.value(null);
}
assert(updater.isActive);
@@ -590,7 +589,7 @@
return dir.exists().then((exists) {
if (!exists) {
print('Directory containing tests missing: ${suiteDir.toNativePath()}');
- return new Future.immediate(null);
+ return new Future.value(null);
} else {
var group = new FutureGroup();
enqueueDirectory(dir, group);
@@ -883,7 +882,7 @@
void _createWrapperFile(String dartWrapperFilename, dartLibraryFilename) {
File file = new File(dartWrapperFilename);
- RandomAccessFile dartWrapper = file.openSync(FileMode.WRITE);
+ RandomAccessFile dartWrapper = file.openSync(mode: FileMode.WRITE);
var usePackageImport = dartLibraryFilename.segments().contains("pkg");
var libraryPathComponent = _createUrlPathFromFile(dartLibraryFilename);
@@ -908,7 +907,7 @@
*/
void enqueueBrowserTest(TestInformation info,
String testName,
- Object expectations,
+ expectations,
bool isWrappingRequired) {
// TODO(kustermann/ricow): This method should be refactored.
Map optionsFromFile = info.optionsFromFile;
@@ -946,7 +945,8 @@
scriptPath = _createUrlPathFromFile(new Path(scriptPath));
// Create the HTML file for the test.
- RandomAccessFile htmlTest = new File(htmlPath).openSync(FileMode.WRITE);
+ RandomAccessFile htmlTest =
+ new File(htmlPath).openSync(mode: FileMode.WRITE);
String content = null;
Path dir = filePath.directoryPath;
String nameNoExt = filePath.filenameWithoutExtension;
@@ -999,7 +999,7 @@
// Variables for browser multi-tests.
List<String> subtestNames = info.optionsFromFile['subtestNames'];
- TestCase multitestParentTest;
+ BrowserTestCase multitestParentTest;
int subtestIndex = 0;
// Construct the command that executes the browser test
do {
@@ -1729,7 +1729,7 @@
static String testScriptPath = new Options().script;
static LastModifiedCache lastModifiedCache = new LastModifiedCache();
static Path currentWorkingDirectory =
- new Path(new Directory.current().path);
+ new Path(Directory.current.path);
/**
* Creates a directory using a [relativePath] to an existing
* [base] directory if that [relativePath] does not already exist.
diff --git a/tools/testing/dart/vendored_pkg/args/args.dart b/tools/testing/dart/vendored_pkg/args/args.dart
index 32793dd..6fb0363 100644
--- a/tools/testing/dart/vendored_pkg/args/args.dart
+++ b/tools/testing/dart/vendored_pkg/args/args.dart
@@ -397,6 +397,6 @@
}
/** Get the names of the options as a [Collection]. */
- Collection<String> get options => _options.keys.toList();
+ List<String> get options => _options.keys.toList();
}
diff --git a/utils/apidoc/apidoc.gyp b/utils/apidoc/apidoc.gyp
index 67e31b2..f5ddde0 100644
--- a/utils/apidoc/apidoc.gyp
+++ b/utils/apidoc/apidoc.gyp
@@ -85,6 +85,7 @@
'--package-root=<(PRODUCT_DIR)/packages',
'--mode=static',
'--exclude-lib=analyzer_experimental',
+ '--exclude-lib=barback',
'--exclude-lib=browser',
'--exclude-lib=dartdoc',
'--exclude-lib=docgen',