Version 0.5.1.0 .
svn merge -r 21754:22069 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
git-svn-id: http://dart.googlecode.com/svn/trunk@22072 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/.gitignore b/.gitignore
index 4da6b24..d82160d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -22,6 +22,7 @@
/*.sln
/*.suo
/*.target.mk
+*.host.mk
/*.vcproj
/*.vcxproj
/*.vcxproj.filters
diff --git a/compiler/java/com/google/dart/compiler/parser/DartParser.java b/compiler/java/com/google/dart/compiler/parser/DartParser.java
index 03e009d..0f60a71 100644
--- a/compiler/java/com/google/dart/compiler/parser/DartParser.java
+++ b/compiler/java/com/google/dart/compiler/parser/DartParser.java
@@ -5628,7 +5628,7 @@
&& !Elements.isLibrarySource(source, "/crypto/crypto.dart")
&& !Elements.isLibrarySource(source, "/uri/uri.dart")
&& !Elements.isLibrarySource(source, "/utf/utf.dart")
- && !Elements.isLibrarySource(source, "/typeddata/typeddata.dart")
+ && !Elements.isLibrarySource(source, "/typed_data/typed_data.dart")
) {
super.reportError(position, errorCode);
}
diff --git a/dart.gyp b/dart.gyp
index 6eea60b..1abc0ef 100644
--- a/dart.gyp
+++ b/dart.gyp
@@ -50,6 +50,7 @@
'dependencies': [
'runtime/dart-runtime.gyp:dart',
'utils/compiler/compiler.gyp:dart2js',
+ 'utils/pub/pub.gyp:pub',
'analyzer',
'compiler',
],
@@ -62,6 +63,7 @@
'tools/create_sdk.py',
'<(PRODUCT_DIR)/<(EXECUTABLE_PREFIX)dart<(EXECUTABLE_SUFFIX)',
'<(SHARED_INTERMEDIATE_DIR)/utils_wrapper.dart.snapshot',
+ '<(SHARED_INTERMEDIATE_DIR)/pub.dart.snapshot',
'<(PRODUCT_DIR)/analyzer/bin/dart_analyzer',
'<(PRODUCT_DIR)/dartanalyzer/dartanalyzer.jar',
],
@@ -72,8 +74,7 @@
'python',
'tools/create_sdk.py',
'--sdk_output_dir', '<(PRODUCT_DIR)/dart-sdk',
- '--utils_snapshot_location',
- '<(SHARED_INTERMEDIATE_DIR)/utils_wrapper.dart.snapshot'
+ '--snapshot_location', '<(SHARED_INTERMEDIATE_DIR)/'
],
'message': 'Creating SDK.',
},
diff --git a/pkg/analyzer_experimental/pubspec.yaml b/pkg/analyzer_experimental/pubspec.yaml
index 5cd79cb..616b361 100644
--- a/pkg/analyzer_experimental/pubspec.yaml
+++ b/pkg/analyzer_experimental/pubspec.yaml
@@ -1,5 +1,4 @@
name: analyzer_experimental
-version: 0.1.5
author: Dart Team <misc@dartlang.org>
description: Experimental static analyzer for Dart.
homepage: http://www.dartlang.org
diff --git a/pkg/args/lib/args.dart b/pkg/args/lib/args.dart
index 1337b46..be1a6ef 100644
--- a/pkg/args/lib/args.dart
+++ b/pkg/args/lib/args.dart
@@ -6,6 +6,19 @@
* This library lets you define parsers for parsing raw command-line arguments
* into a set of options and values using [GNU][] and [POSIX][] style options.
*
+ * ## Installing ##
+ *
+ * Use [pub][] to install this package. Add the following to your `pubspec.yaml`
+ * file.
+ *
+ * dependencies:
+ * args: any
+ *
+ * Then run `pub install`.
+ *
+ * For more information, see the
+ * [args package on pub.dartlang.org](http://pub.dartlang.org/packages/args).
+ *
* ## Defining options ##
*
* To use this library, you create an [ArgParser] object which will contain
@@ -209,6 +222,7 @@
*
* [posix]: http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap12.html#tag_12_02
* [gnu]: http://www.gnu.org/prep/standards/standards.html#Command_002dLine-Interfaces
+ * [pub]: http://pub.dartlang.org
*/
library args;
diff --git a/pkg/http/lib/http.dart b/pkg/http/lib/http.dart
index 07457cd..dda24f24 100644
--- a/pkg/http/lib/http.dart
+++ b/pkg/http/lib/http.dart
@@ -4,6 +4,19 @@
/// A composable, [Future]-based library for making HTTP requests.
///
+/// ## Installing ##
+///
+/// Use [pub][] to install this package. Add the following to your
+/// `pubspec.yaml` file.
+///
+/// dependencies:
+/// http: any
+///
+/// Then run `pub install`.
+///
+/// For more information, see the
+/// [http package on pub.dartlang.org](http://pub.dartlang.org/packages/http).
+///
/// The easiest way to use this library is via the top-level functions. They
/// allow you to make individual HTTP requests with minimal hassle:
///
@@ -50,10 +63,12 @@
/// return _inner.send(request);
/// }
/// }
+///
+/// [pub]: http://pub.dartlang.org
library http;
import 'dart:async';
-import 'dart:typeddata';
+import 'dart:typed_data';
import 'dart:uri';
import 'src/client.dart';
diff --git a/pkg/http/lib/src/base_client.dart b/pkg/http/lib/src/base_client.dart
index eb9fca7..df6e730 100644
--- a/pkg/http/lib/src/base_client.dart
+++ b/pkg/http/lib/src/base_client.dart
@@ -6,7 +6,7 @@
import 'dart:async';
import 'dart:io';
-import 'dart:typeddata';
+import 'dart:typed_data';
import 'dart:uri';
import 'base_request.dart';
diff --git a/pkg/http/lib/src/byte_stream.dart b/pkg/http/lib/src/byte_stream.dart
index f2c6a0b..eba08d4 100644
--- a/pkg/http/lib/src/byte_stream.dart
+++ b/pkg/http/lib/src/byte_stream.dart
@@ -6,7 +6,7 @@
import 'dart:async';
import 'dart:io';
-import 'dart:typeddata';
+import 'dart:typed_data';
import 'utils.dart';
diff --git a/pkg/http/lib/src/client.dart b/pkg/http/lib/src/client.dart
index 302b8c7..bf214c4 100644
--- a/pkg/http/lib/src/client.dart
+++ b/pkg/http/lib/src/client.dart
@@ -6,7 +6,7 @@
import 'dart:async';
import 'dart:io';
-import 'dart:typeddata';
+import 'dart:typed_data';
import 'base_client.dart';
import 'base_request.dart';
diff --git a/pkg/http/lib/src/request.dart b/pkg/http/lib/src/request.dart
index 9d68508..20da3c1 100644
--- a/pkg/http/lib/src/request.dart
+++ b/pkg/http/lib/src/request.dart
@@ -6,7 +6,7 @@
import 'dart:async';
import 'dart:io';
-import 'dart:typeddata';
+import 'dart:typed_data';
import 'dart:uri';
import 'base_request.dart';
diff --git a/pkg/http/lib/src/response.dart b/pkg/http/lib/src/response.dart
index 2376f72..c036fe9 100644
--- a/pkg/http/lib/src/response.dart
+++ b/pkg/http/lib/src/response.dart
@@ -6,7 +6,7 @@
import 'dart:async';
import 'dart:io';
-import 'dart:typeddata';
+import 'dart:typed_data';
import 'base_request.dart';
import 'base_response.dart';
diff --git a/pkg/http/lib/src/utils.dart b/pkg/http/lib/src/utils.dart
index 26b8d0f..d99b9be 100644
--- a/pkg/http/lib/src/utils.dart
+++ b/pkg/http/lib/src/utils.dart
@@ -7,7 +7,7 @@
import 'dart:async';
import 'dart:crypto';
import 'dart:io';
-import 'dart:typeddata';
+import 'dart:typed_data';
import 'dart:uri';
import 'dart:utf';
diff --git a/pkg/http/test/utils.dart b/pkg/http/test/utils.dart
index ab3f5f6..25bb92e 100644
--- a/pkg/http/test/utils.dart
+++ b/pkg/http/test/utils.dart
@@ -27,7 +27,7 @@
/// Starts a new HTTP server.
Future startServer() {
- return SafeHttpServer.bind("127.0.0.1", 0).then((s) {
+ return SafeHttpServer.bind("localhost", 0).then((s) {
_server = s;
s.listen((request) {
var path = request.uri.path;
@@ -108,8 +108,10 @@
/// Stops the current HTTP server.
void stopServer() {
- _server.close();
- _server = null;
+ if (_server != null) {
+ _server.close();
+ _server = null;
+ }
}
/// Removes eight spaces of leading indentation from a multiline string.
diff --git a/pkg/intl/lib/date_format.dart b/pkg/intl/lib/date_format.dart
index 88b54d66..bfc9244 100644
--- a/pkg/intl/lib/date_format.dart
+++ b/pkg/intl/lib/date_format.dart
@@ -16,11 +16,14 @@
* date-time strings under certain locales. Date elements that vary across
* locales include month name, weekname, field, order, etc.
*
- * The actual date for the locales must be obtained. This can currently be done
- * in one of three ways, determined by which library you import. If you only
- * want to use en_US formatting you can use it directly, as a copy of that
- * locale is hard-coded into the formatter. In all other cases,
- * the [initializeDateFormatting] method must be called and will return a future
+ * Formatting dates in the default "en_US" format does not require any
+ * initialization. e.g.
+ * print(new DateFormat.yMMMd().format(new Date.now()));
+ *
+ * But for other locales, the formatting data for the locale must be
+ * obtained. This can currently be done
+ * in one of three ways, determined by which library you import. In all cases,
+ * the "initializeDateFormatting" method must be called and will return a future
* that is complete once the locale data is available. The result of the future
* isn't important, but the data for that locale is available to the date
* formatting and parsing once it completes.
@@ -28,7 +31,7 @@
* The easiest option is that the data may be available locally, imported in a
* library that contains data for all the locales.
* import 'package:intl/date_symbol_data_local.dart';
- * initializeDateFormatting("en_US", null).then((_) => runMyCode());
+ * initializeDateFormatting("fr_FR", null).then((_) => runMyCode());
*
* If we are running outside of a browser, we may want to read the data
* from files in the file system.
@@ -473,7 +476,7 @@
* A series of regular expressions used to parse a format string into its
* component fields.
*/
- static List<Pattern> _matchers = [
+ static List<RegExp> _matchers = [
// Quoted String - anything between single quotes, with escaping
// of single quotes by doubling them.
// e.g. in the pattern "hh 'o''clock'" will match 'o''clock'
diff --git a/pkg/intl/lib/extract_messages.dart b/pkg/intl/lib/extract_messages.dart
index fb57341..47bcbbbeb 100755
--- a/pkg/intl/lib/extract_messages.dart
+++ b/pkg/intl/lib/extract_messages.dart
@@ -32,6 +32,12 @@
import 'package:intl/src/intl_message.dart';
/**
+ * If this is true, print warnings for skipped messages. Otherwise, warnings
+ * are suppressed.
+ */
+bool suppressWarnings = false;
+
+/**
* Parse the dart program represented in [sourceCode] and return a Map from
* message names to [IntlMessage] instances. The [origin] is a string
* describing where the source came from, and is used in error messages.
@@ -195,9 +201,9 @@
void addIntlMessage(MethodInvocation node) {
if (!looksLikeIntlMessage(node)) return;
var reason = checkValidity(node);
- if (!(reason == null)) {
+ if (reason != null && !suppressWarnings) {
print("Skipping invalid Intl.message invocation\n <$node>");
- print(" reason: $reason");
+ print(" reason: $reason");
reportErrorLocation(node);
return;
}
@@ -227,11 +233,11 @@
}
void reportErrorLocation(ASTNode node) {
- if (origin != null) print("from $origin");
+ if (origin != null) print(" from $origin");
LineInfo info = root.lineInfo;
if (info != null) {
LineInfo_Location line = info.getLocation(node.offset);
- print("line: ${line.lineNumber}, column: ${line.columnNumber}");
+ print(" line: ${line.lineNumber}, column: ${line.columnNumber}");
}
}
}
diff --git a/pkg/intl/lib/generate_localized.dart b/pkg/intl/lib/generate_localized.dart
index 26fb304..c40d1f6 100644
--- a/pkg/intl/lib/generate_localized.dart
+++ b/pkg/intl/lib/generate_localized.dart
@@ -47,6 +47,12 @@
List<String> allLocales = [];
/**
+ * If we have more than one set of messages to generate in a particular
+ * directory we may want to prefix some to distinguish them.
+ */
+String generatedFilePrefix = '';
+
+/**
* This represents a message and its translation. We assume that the translation
* has some identifier that allows us to figure out the original message it
* corresponds to, and that it may want to transform the translated text in
@@ -101,13 +107,15 @@
result.write(entries.join(",\n"));
result.write("\n };\n}");
- var output = new File(path.join(targetDir, "messages_$locale.dart"));
+ var output = new File(path.join(targetDir,
+ "${generatedFilePrefix}messages_$locale.dart"));
output.writeAsStringSync(result.toString());
}
/**
- * This returns the mostly constant string used in [generated] for the
- * beginning of the file, parameterized by [locale].
+ * This returns the mostly constant string used in
+ * [generateIndividualMessageFile] for the beginning of the file,
+ * parameterized by [locale].
*/
String prologue(String locale) => """
/**
@@ -136,7 +144,7 @@
var output = new StringBuffer();
output.write(mainPrologue);
for (var each in allLocales) {
- var baseFile = 'messages_$each.dart';
+ var baseFile = '${generatedFilePrefix}messages_$each.dart';
var file = importForGeneratedFile(baseFile);
output.write("import '$file' as ${asLibraryName(each)};\n");
}
@@ -172,7 +180,7 @@
""";
/**
- * Constant string used in [generateMainImportfile] as the end of the file.
+ * Constant string used in [generateMainImportFile] as the end of the file.
*/
const closing = """
default: return null;
diff --git a/pkg/intl/lib/intl.dart b/pkg/intl/lib/intl.dart
index 9a9c529..e0e32ee 100644
--- a/pkg/intl/lib/intl.dart
+++ b/pkg/intl/lib/intl.dart
@@ -7,12 +7,27 @@
* message formatting and replacement, date and number formatting and parsing,
* and utilities for working with Bidirectional text.
*
+ * ## Installing ##
+ *
+ * Use [pub][] to install this package. Add the following to your `pubspec.yaml`
+ * file.
+ *
+ * dependencies:
+ * intl: any
+ *
+ * Then run `pub install`.
+ *
+ * For more information, see the
+ * [intl package on pub.dartlang.org](http://pub.dartlang.org/packages/intl).
+ *
* For things that require locale or other data, there are multiple different
* ways of making that data available, which may require importing different
* libraries. See the class comments for more details.
*
* There is also a simple example application that can be found in the
* `example/basic` directory.
+ *
+ * [pub]: http://pub.dartlang.org
*/
library intl;
@@ -241,7 +256,7 @@
*
* In either case, the purpose of this is to delay calling [message_function]
* until the proper locale has been set. This returns the result of calling
- * [msg_function], which could be of an arbitrary type.
+ * [message_function], which could be of an arbitrary type.
*/
static withLocale(String locale, Function message_function) {
// We have to do this silliness because Locale is not known at compile time,
diff --git a/pkg/intl/lib/message_lookup_by_library.dart b/pkg/intl/lib/message_lookup_by_library.dart
index e3d1fb7..fde0551 100644
--- a/pkg/intl/lib/message_lookup_by_library.dart
+++ b/pkg/intl/lib/message_lookup_by_library.dart
@@ -6,7 +6,7 @@
* Message/plural format library with locale support. This can have different
* implementations based on the mechanism for finding the localized versions
* of messages. This version expects them to be in a library named e.g.
- * 'messages_en_US'. The prefix is set in the [initializeMessages] call, which
+ * 'messages_en_US'. The prefix is set in the "initializeMessages" call, which
* must be made for a locale before any lookups can be done.
*
* See Intl class comment or `tests/message_format_test.dart` for more examples.
diff --git a/pkg/intl/lib/number_format.dart b/pkg/intl/lib/number_format.dart
index 1745178..3f642ca 100644
--- a/pkg/intl/lib/number_format.dart
+++ b/pkg/intl/lib/number_format.dart
@@ -562,7 +562,7 @@
return true;
}
- /** Variables used in [parseTrunk] and [parseTrunkCharacter]. */
+ /** Variables used in [_parseTrunk] and [parseTrunkCharacter]. */
var decimalPos;
var digitLeftCount;
var zeroDigitCount;
diff --git a/pkg/intl/test/data_directory.dart b/pkg/intl/test/data_directory.dart
index de16e00..4a003bf 100644
--- a/pkg/intl/test/data_directory.dart
+++ b/pkg/intl/test/data_directory.dart
@@ -27,7 +27,7 @@
/**
* A helper function that returns false (indicating we should stop iterating)
* if the argument to the previous call was 'intl' and also sets
- * the outer scope [foundIntl].
+ * the outer scope [foundIntlDir].
*/
bool checkForIntlDir(String each) {
if (foundIntlDir) return false;
diff --git a/pkg/intl/test/date_time_format_test_core.dart b/pkg/intl/test/date_time_format_test_core.dart
index a4fb30d..7e007e4 100644
--- a/pkg/intl/test/date_time_format_test_core.dart
+++ b/pkg/intl/test/date_time_format_test_core.dart
@@ -124,7 +124,7 @@
* Exercise all of the formats we have explicitly defined on a particular
* locale. [expectedResults] is a map from ICU format names to the
* expected result of formatting [date] according to that format in
- * [locale].
+ * [localeName].
*/
testLocale(String localeName, Map expectedResults, DateTime date) {
var intl = new Intl(localeName);
diff --git a/pkg/intl/test/message_extraction/extract_to_json.dart b/pkg/intl/test/message_extraction/extract_to_json.dart
index 7d719ee..5b6f316 100644
--- a/pkg/intl/test/message_extraction/extract_to_json.dart
+++ b/pkg/intl/test/message_extraction/extract_to_json.dart
@@ -25,10 +25,19 @@
import 'dart:json' as json;
import 'package:pathos/path.dart' as path;
import 'package:intl/src/intl_message.dart';
-import 'find_output_directory.dart';
+import 'package:args/args.dart';
main() {
var args = new Options().arguments;
+ var targetDir;
+ var parser = new ArgParser();
+ parser.addFlag("suppress-warnings", defaultsTo: false,
+ callback: (x) => suppressWarnings = x);
+
+ void setTargetDir(value) => targetDir = value;
+
+ parser.addOption("output-dir", defaultsTo: '.', callback: setTargetDir);
+ parser.parse(args);
if (args.length == 0) {
print('Usage: extract_to_json [--output-dir=<dir>] [files.dart]');
print('Accepts Dart files and produces intl_messages.json');
@@ -39,7 +48,6 @@
var messages = parseFile(new File(arg));
messages.forEach((k, v) => allMessages.add(toJson(v)));
}
- var targetDir = findOutputDirectory(args);
var file = new File(path.join(targetDir, 'intl_messages.json'));
file.writeAsStringSync(json.stringify(allMessages));
}
diff --git a/pkg/intl/test/message_extraction/find_output_directory.dart b/pkg/intl/test/message_extraction/find_output_directory.dart
deleted file mode 100644
index bb62389..0000000
--- a/pkg/intl/test/message_extraction/find_output_directory.dart
+++ /dev/null
@@ -1,19 +0,0 @@
-/**
- * A shared library for finding the valu eof the --output-dir parameter
- * which all of these programs use.
- */
-library find_output_directory;
-
-const directiveName = '--output-dir=';
-
-_asString(list) => new String.fromCharCodes(list);
-
-findOutputDirectory(List<String> args) {
- var directive = args.firstWhere(
- (x) => x.contains(directiveName),
- orElse: () => null);
- if (directive == null) return '.';
- var file = directive.codeUnits.skip(directiveName.length);
- return _asString(file);
-}
-
diff --git a/pkg/intl/test/message_extraction/generate_from_json.dart b/pkg/intl/test/message_extraction/generate_from_json.dart
index 7bbb878..0759507 100644
--- a/pkg/intl/test/message_extraction/generate_from_json.dart
+++ b/pkg/intl/test/message_extraction/generate_from_json.dart
@@ -22,7 +22,7 @@
import 'package:intl/generate_localized.dart';
import 'dart:json' as json;
import 'package:pathos/path.dart' as path;
-import 'find_output_directory.dart';
+import 'package:args/args.dart';
/**
* Keeps track of all the messages we have processed so far, keyed by message
@@ -31,19 +31,29 @@
Map<String, IntlMessage> messages;
main() {
+ var targetDir;
var args = new Options().arguments;
+ var parser = new ArgParser();
+ parser.addFlag("suppress-warnings", defaultsTo: false,
+ callback: (x) => suppressWarnings = x);
+ parser.addOption("output-dir", defaultsTo: '.',
+ callback: (x) => targetDir = x);
+ parser.addOption("generated-file-prefix", defaultsTo: '',
+ callback: (x) => generatedFilePrefix = x);
+ parser.parse(args);
if (args.length == 0) {
- print('Usage: generate_from_json [--output-dir=<dir>] [originalFiles.dart]'
- ' [translationFiles.json]');
+ print('Usage: generate_from_json [--output-dir=<dir>]'
+ ' [generated-file-prefix=<prefix>] file1.dart file2.dart ...'
+ ' outputFile.json');
exit(0);
}
- var targetDir = findOutputDirectory(args);
- var isDart = new RegExp(r'\.dart');
- var isJson = new RegExp(r'\.json');
- var dartFiles = args.where(isDart.hasMatch).toList();
- var jsonFiles = args.where(isJson.hasMatch).toList();
+ var dartFiles = args.where((x) => x.endsWith("dart")).toList();
+ var jsonFiles = args.where((x) => x.endsWith(".json")).toList();
+ // We're re-parsing the original files to find the corresponding messages,
+ // so if there are warnings extracting the messages, suppress them.
+ suppressWarnings = true;
var allMessages = dartFiles.map((each) => parseFile(new File(each)));
messages = new Map();
@@ -51,11 +61,12 @@
eachMap.forEach((key, value) => messages[key] = value);
}
for (var arg in jsonFiles) {
- var file = new File(path.join(targetDir, arg));
- var translations = generateLocaleFile(file, targetDir);
+ var file = new File(arg);
+ generateLocaleFile(file, targetDir);
}
- var mainImportFile = new File(path.join(targetDir, 'messages_all.dart'));
+ var mainImportFile = new File(path.join(targetDir,
+ '${generatedFilePrefix}messages_all.dart'));
mainImportFile.writeAsStringSync(generateMainImportFile());
}
diff --git a/pkg/intl/test/message_extraction/make_hardcoded_translation.dart b/pkg/intl/test/message_extraction/make_hardcoded_translation.dart
index 3f7977c..f936f11 100644
--- a/pkg/intl/test/message_extraction/make_hardcoded_translation.dart
+++ b/pkg/intl/test/message_extraction/make_hardcoded_translation.dart
@@ -13,7 +13,7 @@
import 'dart:io';
import 'dart:json' as json;
import 'package:pathos/path.dart' as path;
-import 'find_output_directory.dart';
+import 'package:args/args.dart';
/** A list of the French translations that we will produce. */
var french = {
@@ -95,8 +95,11 @@
'[originalFile.dart]');
exit(0);
}
+ var parser = new ArgParser();
+ parser.addOption("output-dir", defaultsTo: '.',
+ callback: (value) => targetDir = value);
+ parser.parse(args);
- targetDir = findOutputDirectory(args);
var fileArgs = args.where((x) => x.contains('.json'));
var messages = json.parse(new File(fileArgs.first).readAsStringSync());
diff --git a/pkg/intl/test/message_extraction/message_extraction_test.dart b/pkg/intl/test/message_extraction/message_extraction_test.dart
index 92aa3e6..24f8fc5 100644
--- a/pkg/intl/test/message_extraction/message_extraction_test.dart
+++ b/pkg/intl/test/message_extraction/message_extraction_test.dart
@@ -48,8 +48,13 @@
* Translate a file path into this test directory, regardless of the
* working directory.
*/
-String dir([String s]) =>
- path.join(intlDirectory, 'test', 'message_extraction', s);
+String dir([String s]) {
+ if (s != null && s.startsWith("--")) { // Don't touch command-line options.
+ return s;
+ } else {
+ return path.join(intlDirectory, 'test', 'message_extraction', s);
+ }
+}
main() {
test("Test round trip message extraction, translation, code generation, "
@@ -68,8 +73,8 @@
void deleteGeneratedFiles() {
var files = [dir('intl_messages.json'), dir('translation_fr.json'),
- dir('messages_fr.dart'), dir('messages_de_DE.dart'),
- dir('translation_de_DE.json'), dir('messages_all.dart')];
+ dir('foo_messages_fr.dart'), dir('foo_messages_de_DE.dart'),
+ dir('translation_de_DE.json'), dir('foo_messages_all.dart')];
files.map((name) => new File(name)).forEach((x) {
if (x.existsSync()) x.deleteSync();});
}
@@ -107,7 +112,7 @@
Future<ProcessResult> extractMessages(ProcessResult previousResult) => run(
previousResult,
- ['extract_to_json.dart', 'sample_with_messages.dart',
+ ['extract_to_json.dart', '--suppress-warnings', 'sample_with_messages.dart',
'part_of_sample_with_messages.dart']);
Future<ProcessResult> generateTranslationFiles(ProcessResult previousResult) =>
@@ -118,7 +123,8 @@
Future<ProcessResult> generateCodeFromTranslation(ProcessResult previousResult)
=> run(
previousResult,
- ['generate_from_json.dart', 'sample_with_messages.dart',
+ ['generate_from_json.dart', '--generated-file-prefix=foo_',
+ 'sample_with_messages.dart',
'part_of_sample_with_messages.dart', 'translation_fr.json',
'translation_de_DE.json' ]);
@@ -135,9 +141,8 @@
var output = results.stdout;
var lines = output.split("\n");
- // If it looks like these are CRLF delimited, then use that. Wish strings
- // just implemented last.
- if (lines.first.codeUnits.last == "\r".codeUnits.first) {
+ // If it looks like these are CRLF delimited, then use that.
+ if (lines.first.endsWith("\r")) {
lines = output.split("\r\n");
}
lineIterator = lines.iterator..moveNext();
diff --git a/pkg/intl/test/message_extraction/sample_with_messages.dart b/pkg/intl/test/message_extraction/sample_with_messages.dart
index ada1d79..a0e334c 100644
--- a/pkg/intl/test/message_extraction/sample_with_messages.dart
+++ b/pkg/intl/test/message_extraction/sample_with_messages.dart
@@ -13,7 +13,7 @@
import "package:intl/message_lookup_by_library.dart";
import "dart:async";
import "package:intl/src/intl_helpers.dart";
-import "messages_all.dart";
+import "foo_messages_all.dart";
part 'part_of_sample_with_messages.dart';
diff --git a/pkg/logging/lib/logging.dart b/pkg/logging/lib/logging.dart
index 222ff1e..94bf5f3 100644
--- a/pkg/logging/lib/logging.dart
+++ b/pkg/logging/lib/logging.dart
@@ -6,6 +6,22 @@
* Provides APIs for debugging and error logging. This library introduces
* abstractions similar to those used in other languages, such as the Closure JS
* Logger and java.util.logging.Logger.
+ *
+ * ## Installing ##
+ *
+ * Use [pub][] to install this package. Add the following to your `pubspec.yaml`
+ * file.
+ *
+ * dependencies:
+ * logging: any
+ *
+ * Then run `pub install`.
+ *
+ * For more information, see the
+ * [logging package on pub.dartlang.org][pkg].
+ *
+ * [pub]: http://pub.dartlang.org
+ * [pkg]: http://pub.dartlang.org/packages/logging
*/
library logging;
diff --git a/pkg/meta/lib/meta.dart b/pkg/meta/lib/meta.dart
index ba49c2b..c86e377 100644
--- a/pkg/meta/lib/meta.dart
+++ b/pkg/meta/lib/meta.dart
@@ -6,6 +6,21 @@
* This library contains the definitions of annotations that provide additional
* semantic information about the program being annotated. These annotations are
* intended to be used by tools to provide a better user experience.
+ *
+ * ## Installing ##
+ *
+ * Use [pub][] to install this package. Add the following to your `pubspec.yaml`
+ * file.
+ *
+ * dependencies:
+ * meta: any
+ *
+ * Then run `pub install`.
+ *
+ * For more information, see the
+ * [meta package on pub.dartlang.org](http://pub.dartlang.org/packages/meta).
+ *
+ * [pub]: http://pub.dartlang.org
*/
library meta;
diff --git a/pkg/oauth2/lib/oauth2.dart b/pkg/oauth2/lib/oauth2.dart
index 7fdb205..592589d 100644
--- a/pkg/oauth2/lib/oauth2.dart
+++ b/pkg/oauth2/lib/oauth2.dart
@@ -6,6 +6,19 @@
/// behalf of a user, and making authorized HTTP requests with the user's OAuth2
/// credentials.
///
+/// ## Installing ##
+///
+/// Use [pub][] to install this package. Add the following to your
+/// `pubspec.yaml` file.
+///
+/// dependencies:
+/// oauth2: any
+///
+/// Then run `pub install`.
+///
+/// For more information, see the
+/// [oauth2 package on pub.dartlang.org][pkg].
+///
/// OAuth2 allows a client (the program using this library) to access and
/// manipulate a resource that's owned by a resource owner (the end user) and
/// lives on a remote server. The client directs the resource owner to an
@@ -100,6 +113,9 @@
/// }).then((file) => file.close()).then((_) => result);
/// });
/// }).then(print);
+///
+/// [pub]: http://pub.dartlang.org
+/// [pkg]: http://pub.dartlang.org/packages/oauth2
library oauth2;
export 'src/authorization_code_grant.dart';
diff --git a/pkg/pathos/lib/path.dart b/pkg/pathos/lib/path.dart
index 5136871..8d83077 100644
--- a/pkg/pathos/lib/path.dart
+++ b/pkg/pathos/lib/path.dart
@@ -3,6 +3,22 @@
// BSD-style license that can be found in the LICENSE file.
/// A comprehensive, cross-platform path manipulation library.
+///
+/// ## Installing ##
+///
+/// Use [pub][] to install this package. Add the following to your
+/// `pubspec.yaml` file.
+///
+/// dependencies:
+/// pathos: any
+///
+/// Then run `pub install`.
+///
+/// For more information, see the
+/// [pathos package on pub.dartlang.org][pkg].
+///
+/// [pub]: http://pub.dartlang.org
+/// [pkg]: http://pub.dartlang.org/packages/pathos
library path;
import 'dart:io' as io;
diff --git a/pkg/pkg.status b/pkg/pkg.status
index d638e12..af3a270 100644
--- a/pkg/pkg.status
+++ b/pkg/pkg.status
@@ -2,9 +2,6 @@
# for details. All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE file.
-serialization/test/*: Skip # http://dartbug.com/9894
-
-
# Run this test manually to verify that the fixnum library produces
# the same results as native ints on a set of directed and random inputs.
# Skip it when running automated tests because it times out. This
@@ -31,9 +28,8 @@
webdriver/test/webdriver_test: Skip
-[ $compiler == dart2js && $runtime == drt ]
-unittest/test/unittest_test: Pass, Fail, Crash # Bug in v8, http://dartbug.com/9407
-
+[ $runtime == d8 || $runtime == jsshell ]
+unittest/test/unittest_test: Pass, Fail # http://dartbug.com/10109
[$compiler == dart2dart]
*: Skip
@@ -129,9 +125,6 @@
unittest/test/mock_test: Fail
unittest/test/mock_regexp_negative_test: Fail
-[ $compiler == dart2js && $csp && $runtime == drt ]
-unittest/test/unittest_test: Pass, Fail, Crash # Bug in v8, http://dartbug.com/9407
-
[ $compiler == none && $runtime == drt ]
dartdoc/test/dartdoc_test: Skip # See dartbug.com/4541.
diff --git a/pkg/scheduled_test/lib/scheduled_test.dart b/pkg/scheduled_test/lib/scheduled_test.dart
index 6e7b754..05beb14 100644
--- a/pkg/scheduled_test/lib/scheduled_test.dart
+++ b/pkg/scheduled_test/lib/scheduled_test.dart
@@ -7,6 +7,19 @@
// TODO(nweiz): Port the non-Pub-specific scheduled test libraries from Pub.
/// A package for writing readable tests of asynchronous behavior.
///
+/// ## Installing ##
+///
+/// Use [pub][] to install this package. Add the following to your
+/// `pubspec.yaml` file.
+///
+/// dependencies:
+/// scheduled_test: any
+///
+/// Then run `pub install`.
+///
+/// For more information, see the
+/// [scheduled_test package on pub.dartlang.org][pkg].
+///
/// This package works by building up a queue of asynchronous tasks called a
/// "schedule", then executing those tasks in order. This allows the tests to
/// read like synchronous, linear code, despite executing asynchronously.
@@ -171,6 +184,9 @@
/// If a single task might take a long time, you can also manually tell the
/// [Schedule] that it's making progress by calling [Schedule.heartbeat], which
/// will reset the timeout whenever it's called.
+///
+/// [pub]: http://pub.dartlang.org
+/// [pkg]: http://pub.dartlang.org/packages/scheduled_test
library scheduled_test;
import 'dart:async';
@@ -242,10 +258,11 @@
/// Creates a new named group of tests. This has the same semantics as
/// [unittest.group].
void group(String description, void body()) {
+ _ensureInitialized();
+ _ensureSetUpForTopLevel();
unittest.group(description, () {
var wasInGroup = _inGroup;
_inGroup = true;
- _setUpScheduledTest();
body();
_inGroup = wasInGroup;
});
@@ -295,20 +312,38 @@
/// Registers callbacks for [unittest.setUp] and [unittest.tearDown] that set up
/// and tear down the scheduled test infrastructure.
void _setUpScheduledTest([void setUpFn()]) {
- if (!_inGroup) _setUpForTopLevel = true;
-
- unittest.setUp(() {
- if (currentSchedule != null) {
- throw new StateError('There seems to be another scheduled test '
- 'still running.');
- }
- _currentSchedule = new Schedule();
- _setUpFn = setUpFn;
- });
-
- unittest.tearDown(() {
- _currentSchedule = null;
- });
+ if (!_inGroup) {
+ _setUpForTopLevel = true;
+ unittest.setUp(() {
+ if (currentSchedule != null) {
+ throw new StateError('There seems to be another scheduled test '
+ 'still running.');
+ }
+ _currentSchedule = new Schedule();
+ if (_setUpFn != null) {
+ var parentFn = _setUpFn;
+ _setUpFn = () { parentFn(); setUpFn(); };
+ } else {
+ _setUpFn = setUpFn;
+ }
+ });
+
+ unittest.tearDown(() {
+ _currentSchedule = null;
+ _setUpFn = null;
+ });
+ } else {
+ unittest.setUp(() {
+ if (currentSchedule == null) {
+ throw new StateError('No schedule allocated.');
+ } else if (_setUpFn != null) {
+ var parentFn = _setUpFn;
+ _setUpFn = () { parentFn(); setUpFn(); };
+ } else {
+ _setUpFn = setUpFn;
+ }
+ });
+ }
}
/// Ensures that the global configuration for `scheduled_test` has been
diff --git a/pkg/scheduled_test/lib/src/schedule.dart b/pkg/scheduled_test/lib/src/schedule.dart
index ecdf4dd..d5eb9af 100644
--- a/pkg/scheduled_test/lib/src/schedule.dart
+++ b/pkg/scheduled_test/lib/src/schedule.dart
@@ -62,7 +62,6 @@
ScheduleState get state => _state;
ScheduleState _state = ScheduleState.SET_UP;
- // TODO(nweiz): make this a read-only view once issue 8321 is fixed.
/// Errors thrown by the task queues.
///
/// When running tasks in [tasks], this will always be empty. If an error
@@ -74,11 +73,13 @@
///
/// Any out-of-band callbacks that throw errors will also have those errors
/// added to this list.
- final errors = <ScheduleError>[];
+ List<ScheduleError> get errors =>
+ new UnmodifiableListView<ScheduleError>(_errors);
+ final _errors = <ScheduleError>[];
- // TODO(nweiz): make this a read-only view once issue 8321 is fixed.
/// Additional debugging info registered via [addDebugInfo].
- final debugInfo = <String>[];
+ List<String> get debugInfo => new UnmodifiableListView<String>(_debugInfo);
+ final _debugInfo = <String>[];
/// The task queue that's currently being run. One of [tasks], [onException],
/// or [onComplete]. This starts as [tasks], and can only be `null` after the
@@ -212,7 +213,7 @@
/// fails. Unlike [signalError], this won't cause the test to fail, nor will
/// it short-circuit the current [TaskQueue]; it's just useful for providing
/// additional information that may not fit cleanly into an existing error.
- void addDebugInfo(String info) => debugInfo.add(info);
+ void addDebugInfo(String info) => _debugInfo.add(info);
/// Notifies the schedule of an error that occurred in a task or out-of-band
/// callback after the appropriate queue has timed out. If this schedule is
@@ -318,7 +319,7 @@
/// [ScheduleError].
void _addError(error) {
if (error is ScheduleError && errors.contains(error)) return;
- errors.add(new ScheduleError.from(this, error));
+ _errors.add(new ScheduleError.from(this, error));
}
}
@@ -346,9 +347,8 @@
/// A queue of asynchronous tasks to execute in order.
class TaskQueue {
- // TODO(nweiz): make this a read-only view when issue 8321 is fixed.
/// The tasks in the queue.
- Iterable<Task> get contents => _contents;
+ List<Task> get contents => new UnmodifiableListView<Task>(_contents);
final _contents = new Queue<Task>();
/// The name of the queue, for debugging purposes.
@@ -377,10 +377,10 @@
/// Whether to stop running after the current task.
bool _aborted = false;
- // TODO(nweiz): make this a read-only view when issue 8321 is fixed.
/// The descriptions of all callbacks that are blocking the completion of
/// [this].
- Iterable<String> get pendingCallbacks => _pendingCallbacks;
+ List<String> get pendingCallbacks =>
+ new UnmodifiableListView<String>(_pendingCallbacks);
final _pendingCallbacks = new Queue<String>();
/// A completer that will be completed once [_pendingCallbacks] becomes empty
diff --git a/pkg/scheduled_test/lib/src/task.dart b/pkg/scheduled_test/lib/src/task.dart
index e77f531..2dfc127 100644
--- a/pkg/scheduled_test/lib/src/task.dart
+++ b/pkg/scheduled_test/lib/src/task.dart
@@ -27,10 +27,10 @@
/// The queue to which this [Task] belongs.
final TaskQueue queue;
- // TODO(nweiz): make this a read-only view when issue 8321 is fixed.
/// Child tasks that have been spawned while running this task. This will be
/// empty if this task is a nested task.
- final children = new Queue<Task>();
+ List<Task> get children => new UnmodifiableListView(_children);
+ final _children = new Queue<Task>();
/// A [FutureGroup] that will complete once all current child tasks are
/// finished running. This will be null if no child tasks are currently
@@ -110,7 +110,7 @@
/// finished.
Future runChild(fn(), String description) {
var task = new Task._child(fn, description, this);
- children.add(task);
+ _children.add(task);
if (_childGroup == null || _childGroup.completed) {
_childGroup = new FutureGroup();
}
diff --git a/pkg/scheduled_test/test/scheduled_test/set_up_test.dart b/pkg/scheduled_test/test/scheduled_test/set_up_test.dart
index 0d83d20..5462f51 100644
--- a/pkg/scheduled_test/test/scheduled_test/set_up_test.dart
+++ b/pkg/scheduled_test/test/scheduled_test/set_up_test.dart
@@ -79,7 +79,7 @@
test('test 2', () => expect(onExceptionRun, isTrue));
}, passing: ['test 2']);
- expectTestsPass("setUp doesn't apply to child groups", () {
+ expectTestsPass("setUp applies to child groups", () {
var setUpRun = false;
setUp(() {
setUpRun = true;
@@ -94,7 +94,7 @@
group('group', () {
test('inner', () {
- expect(setUpRun, isFalse);
+ expect(setUpRun, isTrue);
});
});
});
@@ -140,4 +140,41 @@
});
});
});
-}
\ No newline at end of file
+
+ expectTestsPass("setUp calls are chained", () {
+ var setUpOuterRun = false;
+ var setUpInnerRun = false;
+ group('outer group', () {
+ setUp(() {
+ setUpOuterRun = true;
+ currentSchedule.onComplete.schedule(() {
+ setUpOuterRun = false;
+ });
+ });
+ group('intermediate group with no setUp', () {
+ group('inner group', () {
+ setUp(() {
+ setUpInnerRun = true;
+ currentSchedule.onComplete.schedule(() {
+ setUpInnerRun = false;
+ });
+ });
+ test('inner', () {
+ expect(setUpOuterRun, isTrue);
+ expect(setUpInnerRun, isTrue);
+ });
+ });
+ });
+ test('outer', () {
+ expect(setUpOuterRun, isTrue);
+ expect(setUpInnerRun, isFalse);
+ });
+ });
+
+ test('top', () {
+ expect(setUpOuterRun, isFalse);
+ expect(setUpInnerRun, isFalse);
+ });
+ });
+
+}
diff --git a/pkg/serialization/lib/serialization.dart b/pkg/serialization/lib/serialization.dart
index 130be27..88c30e8 100644
--- a/pkg/serialization/lib/serialization.dart
+++ b/pkg/serialization/lib/serialization.dart
@@ -7,6 +7,19 @@
* [Serialization] is defined in terms of [SerializationRule]s and supports
* reading and writing to different formats.
*
+ * ## Installing ##
+ *
+ * Use [pub][] to install this package. Add the following to your `pubspec.yaml`
+ * file.
+ *
+ * dependencies:
+ * serialization: any
+ *
+ * Then run `pub install`.
+ *
+ * For more information, see the
+ * [serialization package on pub.dartlang.org][pkg].
+ *
* Setup
* =====
* A simple example of usage is
@@ -64,23 +77,25 @@
* }
* }
*
- * The class needs four different methods. The [appliesTo] method tells us if
+ * The class needs four different methods. The [CustomRule.appliesTo]
+ * method tells us if
* the rule should be used to write an object. In this example we use a test
* based on runtimeType. We could also use an "is Address" test, but if Address
* has subclasses that would find those as well, and we want a separate rule
- * for each. The [getState] method should
+ * for each. The [CustomRule.getState] method should
* return all the state of the object that we want to recreate,
* and should be either a Map or a List. If you want to write to human-readable
* formats where it's useful to be able to look at the data as a map from
* field names to values, then it's better to return it as a map. Otherwise it's
* more efficient to return it as a list. You just need to be sure that the
- * [create] and [setState] methods interpret the same way as [getState] does.
+ * [CustomRule.create] and [CustomRule.setState] methods interpret the data the
+ * same way as [CustomRule.getState] does.
*
- * The [create] method will create the new object and return it. While it's
+ * The [CustomRule.create] method will create the new object and return it. While it's
* possible to create the object and set all its state in this one method, that
* increases the likelihood of problems with cycles. So it's better to use the
- * minimum necessary information in [create] and do more of the work in
- * [setState].
+ * minimum necessary information in [CustomRule.create] and do more of the work
+ * in [CustomRule.setState].
*
* The other way to do this is not creating a subclass, but by using a
* [ClosureRule] and giving it functions for how to create
@@ -133,7 +148,8 @@
* isolate.
*
* We can write objects in different formats by passing a [Format] object to
- * the [write] method or by getting a [Writer] object. The available formats
+ * the [Serialization.write] method or by getting a [Writer] object.
+ * The available formats
* include the default, a simple "flat" format that doesn't include field names,
* and a simple JSON format that produces output more suitable for talking to
* services that expect JSON in a predefined format. Examples of these are
@@ -149,7 +165,7 @@
*
* Reading
* =======
- * To read objects, the corresponding [read] method can be used.
+ * To read objects, the corresponding [Serialization.read] method can be used.
*
* Address input = serialization.read(input);
*
@@ -158,13 +174,15 @@
* rules to be different, but they need to be able to read the same
* representation. For most practical purposes right now they should be the
* same. The simplest way to achieve this is by having the serialization
- * variable [selfDescribing] be true. In that case the rules themselves are also
+ * variable [Serialization.selfDescribing] be true. In that case the rules
+ * themselves are also
* stored along with the serialized data, and can be read back on the receiving
* end. Note that this may not work for all rules or all formats. The
- * [selfDescribing] variable is true by default, but the [SimpleJsonFormat] does
- * not support it, since the point is to provide a representation in a form
+ * [Serialization.selfDescribing] variable is true by default, but the
+ * [SimpleJsonFormat] does not support it, since the point is to provide a
+ * representation in a form
* other services might expect. Using CustomRule or ClosureRule also does not
- * yet work with the [selfDescribing] variable.
+ * yet work with the [Serialization.selfDescribing] variable.
*
* Named Objects
* =============
@@ -174,13 +192,16 @@
* take a [ClassMirror] in their constructor, and we cannot serialize those. So
* when we read the rules, we must provide a Map<String, Object> which maps from
* the simple name of classes we are interested in to a [ClassMirror]. This can
- * be provided either in the [namedObjects] variable of the Serialization,
+ * be provided either in the [Serialization.namedObjects],
* or as an additional parameter to the reading and writing methods on the
* [Reader] or [Writer] respectively.
*
* new Serialization()
* ..addRuleFor(new Person(), constructorFields: ["name"])
* ..namedObjects['Person'] = reflect(new Person()).type;
+ *
+ * [pub]: http://pub.dartlang.org
+ * [pkg]: http://pub.dartlang.org/packages/serialization
*/
library serialization;
@@ -319,6 +340,7 @@
// it will always find the first one.
addRule(new ListRuleEssential());
addRule(new MapRule());
+ addRule(new SymbolRule());
}
/**
@@ -445,7 +467,8 @@
'constructorFields', 'regularFields', []],
fields: [])
..addRule(new NamedObjectRule())
- ..addRule(new MirrorRule());
+ ..addRule(new MirrorRule())
+ ..addRule(new SymbolRule());
meta.namedObjects = namedObjects;
return meta;
}
diff --git a/pkg/serialization/lib/src/basic_rule.dart b/pkg/serialization/lib/src/basic_rule.dart
index b3e3a95..dbf54ed 100644
--- a/pkg/serialization/lib/src/basic_rule.dart
+++ b/pkg/serialization/lib/src/basic_rule.dart
@@ -94,7 +94,7 @@
*/
setFieldWith(String fieldName, SetWithFunction setWith) {
fields.addAllByName([fieldName]);
- _NamedField field = fields.named(fieldName);
+ _NamedField field = fields.named(_asSymbol(fieldName));
Function setter = (setWith == null) ? field.defaultSetter : setWith;
field.customSetter = setter;
}
@@ -224,8 +224,8 @@
return mirror.reflectee;
}
- /** For all [state] not required in the constructor, set it in the [object],
- * resolving references in the context of [reader].
+ /** For all [rawState] not required in the constructor, set it in the
+ * [object], resolving references in the context of [reader].
*/
inflateNonEssential(rawState, object, Reader reader) {
InstanceMirror mirror = reflect(object);
@@ -284,7 +284,7 @@
final _FieldList fieldList;
/**
- * Our position in the [contents] collection of [fieldList]. This is used
+ * Our position in the [fieldList._contents] collection. This is used
* to index into the state, so it's extremely important.
*/
int index;
@@ -310,9 +310,9 @@
* [fieldList] models.
*/
static bool _isReallyAField(value, _FieldList fieldList) {
- if (!(value is String)) return false;
- return hasField(value, fieldList.mirror) ||
- hasGetter(value, fieldList.mirror);
+ var symbol = _asSymbol(value);
+ return hasField(symbol, fieldList.mirror) ||
+ hasGetter(symbol, fieldList.mirror);
}
/** Private constructor. */
@@ -332,7 +332,7 @@
/**
* Return true if this field is treated as essential state, either because
* it is used in the constructor, or because it's been designated
- * using [setFieldWith].
+ * using [BasicRule.setFieldWith].
*/
bool get isEssential => usedInConstructor;
@@ -352,20 +352,32 @@
*/
class _NamedField extends _Field {
/** The name of the field (or getter) */
- final name;
+ String _name;
+ Symbol nameSymbol;
- /** The special way to set this value registered, if this has a value. */
+ /**
+ * If this is set, then it is used as a way to set the value rather than
+ * using the default mechanism.
+ */
Function customSetter;
- _NamedField._internal(this.name, fieldList) : super._internal(fieldList);
+ _NamedField._internal(fieldName, fieldList) : super._internal(fieldList) {
+ nameSymbol = _asSymbol(fieldName);
+ if (nameSymbol == null) {
+ throw new SerializationException("Invalid field name $fieldName");
+ }
+ }
- operator ==(x) => x is _NamedField && (name == x.name);
+ String get name =>
+ _name == null ? _name = MirrorSystem.getName(nameSymbol) : _name;
+
+ operator ==(x) => x is _NamedField && (nameSymbol == x.nameSymbol);
int get hashCode => name.hashCode;
/**
* Return true if this field is treated as essential state, either because
* it is used in the constructor, or because it's been designated
- * using [setFieldWith].
+ * using [BasicRule.setFieldWith].
*/
bool get isEssential => super.isEssential || customSetter != null;
@@ -374,16 +386,15 @@
setter(object, value);
}
- valueIn(InstanceMirror mirror) =>
- deprecatedFutureValue(mirror.getFieldAsync(name)).reflectee;
+ valueIn(InstanceMirror mirror) => mirror.getField(nameSymbol).reflectee;
/** Return the function to use to set our value. */
Function get setter =>
(customSetter != null) ? customSetter : defaultSetter;
- /** Return a default setter function. */
+ /** The default setter function. */
void defaultSetter(InstanceMirror object, value) {
- object.setFieldAsync(name, reflect(value));
+ object.setField(nameSymbol, value);
}
String toString() => 'Field($name)';
@@ -421,8 +432,8 @@
*/
class _FieldList extends IterableBase {
/**
- * All of our fields, indexed by name. Note that the names are not
- * necessarily strings.
+ * All of our fields, indexed by name. Note that the names are
+ * typically Symbols, but can also be arbitrary constants.
*/
Map<dynamic, _Field> allFields = new Map<dynamic, _Field>();
@@ -434,7 +445,7 @@
List _constructorFields = const [];
/** The list of fields to exclude if we are computing the list ourselves. */
- List<String> _excludeFields = const [];
+ List<Symbol> _excludedFieldNames = const [];
/** The mirror we will use to compute the fields. */
final ClassMirror mirror;
@@ -448,15 +459,17 @@
_FieldList(this.mirror);
/** Look up a field by [name]. */
- _Field named(String name) => allFields[name];
+ _Field named(name) => allFields[name];
/** Set the fields to be used in the constructor. */
set constructorFields(List fieldNames) {
if (fieldNames == null || fieldNames.isEmpty) return;
_constructorFields = [];
for (var each in fieldNames) {
- var field = new _Field(each, this)..usedInConstructor = true;
- allFields[each] = field;
+ var symbol = _asSymbol(each);
+ var name = _Field._isReallyAField(symbol, this) ? symbol : each;
+ var field = new _Field(name, this)..usedInConstructor = true;
+ allFields[name] = field;
_constructorFields.add(field);
}
invalidate();
@@ -478,7 +491,7 @@
if (allFields.length > _constructorFields.length) {
throw "You can't specify both excludeFields and regular fields";
}
- _excludeFields = fields;
+ _excludedFieldNames = fields.map((x) => new Symbol(x)).toList();
}
int get length => allFields.length;
@@ -487,14 +500,16 @@
void addAllNotExplicitlyExcluded(Iterable<String> aCollection) {
if (aCollection == null) return;
var names = aCollection;
- names = names.where((x) => !_excludeFields.contains(x));
+ names = names.where((x) => !_excludedFieldNames.contains(x));
addAllByName(names);
}
/** Add all the fields with the given names without any special properties. */
void addAllByName(Iterable<String> names) {
for (var each in names) {
- allFields.putIfAbsent(each, () => new _Field(each, this));
+ var symbol = _asSymbol(each);
+ var field = new _Field(symbol, this);
+ allFields.putIfAbsent(symbol, () => new _Field(symbol, this));
}
invalidate();
}
@@ -562,7 +577,8 @@
var fields = publicFields(mirror);
var getters = publicGetters(mirror);
var gettersWithSetters = getters.where( (each)
- => mirror.setters["${each.simpleName}="] != null);
+ => mirror.setters[
+ new Symbol("${MirrorSystem.getName(each.simpleName)}=")] != null);
var gettersThatMatchConstructor = getters.where((each)
=> (named(each.simpleName) != null) &&
(named(each.simpleName).usedInConstructor)).toList();
@@ -590,11 +606,12 @@
/** The name of the constructor to use, if not the default constructor.*/
String name;
+ Symbol nameSymbol;
/**
* The indices of the fields used as constructor arguments. We will look
- * these up in the state by number. These correspond to the index in the
- * [contents] of the FieldList, which will be alphabetically sorted.
+ * these up in the state by number. The index is according to a list of the
+ * fields in alphabetical order by name.
*/
List<int> fieldNumbers;
@@ -604,6 +621,7 @@
*/
Constructor(this.type, this.name, this.fieldNumbers) {
if (name == null) name = '';
+ nameSymbol = new Symbol(name);
if (fieldNumbers == null) fieldNumbers = const [];
}
@@ -614,9 +632,16 @@
constructFrom(state, Reader r) {
// TODO(alanknight): Handle named parameters
Iterable inflated = fieldNumbers.map(
- (x) => (x is int) ? reflect(r.inflateReference(state[x])) : reflect(x));
- var result = type.newInstanceAsync(name, inflated.toList());
- return deprecatedFutureValue(result);
+ (x) => (x is int) ? r.inflateReference(state[x]) : x);
+ var result;
+ try {
+ result = type.newInstance(nameSymbol, inflated.toList());
+ } on MirroredError catch (e) {
+ // Mirrored "compile-time" errors do not get treated as exceptions
+ // in the debugger, so explicitly re-throw. Issue dartbug.com/10054.
+ throw e;
+ }
+ return result;
}
}
@@ -637,3 +662,21 @@
asMap() => _map;
}
+
+/**
+ * Return a symbol corresponding to [value], which may be a String or a
+ * Symbol. If it is any other type, or if the string is an
+ * invalid symbol, return null;
+ */
+_asSymbol(value) {
+ if (value is Symbol) return value;
+ if (value is String) {
+ try {
+ return new Symbol(value);
+ } on ArgumentError {
+ return null;
+ };
+ } else {
+ return null;
+ }
+}
\ No newline at end of file
diff --git a/pkg/serialization/lib/src/format.dart b/pkg/serialization/lib/src/format.dart
index 4e57384..d42707d 100644
--- a/pkg/serialization/lib/src/format.dart
+++ b/pkg/serialization/lib/src/format.dart
@@ -82,7 +82,7 @@
* with nesting of those.
* Note that since the classes of objects aren't normally stored, this isn't
* enough information to read back the objects. However, if the
- * If the [storeRoundTripData] field of the format is set to true, then this
+ * If the [storeRoundTripInfo] field of the format is set to true, then this
* will store the rule number along with the data, allowing reconstruction.
*/
class SimpleJsonFormat extends Format {
@@ -195,7 +195,7 @@
}
/**
- * Convert nested references in [data] into [Reference] objects.
+ * Convert nested references in [input] into [Reference] objects.
*/
recursivelyFixUp(input, Reader r, List result) {
var data = input;
diff --git a/pkg/serialization/lib/src/mirrors_helpers.dart b/pkg/serialization/lib/src/mirrors_helpers.dart
index aeeb509..4058514 100644
--- a/pkg/serialization/lib/src/mirrors_helpers.dart
+++ b/pkg/serialization/lib/src/mirrors_helpers.dart
@@ -30,7 +30,8 @@
/** Return true if the class has a field named [name]. Note that this
* includes private fields, but excludes statics. */
-bool hasField(String name, ClassMirror mirror) {
+bool hasField(Symbol name, ClassMirror mirror) {
+ if (name == null) return false;
var field = mirror.variables[name];
if (field != null && !field.isStatic) return true;
var superclass = mirror.superclass;
@@ -53,7 +54,8 @@
}
/** Return true if the class has a getter named [name] */
-bool hasGetter(String name, ClassMirror mirror) {
+bool hasGetter(Symbol name, ClassMirror mirror) {
+ if (name == null) return false;
var getter = mirror.getters[name];
if (getter != null && !getter.isStatic) return true;
var superclass = mirror.superclass;
diff --git a/pkg/serialization/lib/src/reader_writer.dart b/pkg/serialization/lib/src/reader_writer.dart
index 2209f78..e25a3ec 100644
--- a/pkg/serialization/lib/src/reader_writer.dart
+++ b/pkg/serialization/lib/src/reader_writer.dart
@@ -211,7 +211,8 @@
}
/**
- * Return true if the [namedObjects] collection has a reference to [object].
+ * Return true if the [Serialization.namedObjects] collection has a
+ * reference to [object].
*/
// TODO(alanknight): Should the writer also have its own namedObjects
// collection specific to the particular write, or is that just adding
@@ -219,7 +220,8 @@
hasNameFor(object) => serialization._hasNameFor(object);
/**
- * Return the name we have for this object in the [namedObjects] collection.
+ * Return the name we have for this object in the [Serialization.namedObjects]
+ * collection.
*/
nameFor(object) => serialization._nameFor(object);
@@ -278,7 +280,7 @@
/**
* The resulting objects, indexed according to the same scheme as
- * [data], where each rule has a number, and rules keep track of the objects
+ * _data, where each rule has a number, and rules keep track of the objects
* that they serialize, in order.
*/
List<List> objects;
@@ -579,7 +581,7 @@
/**
* Convert the reference to a map in JSON format. This is specific to the
* custom JSON format we define, and must be consistent with the
- * [asReference] method.
+ * [Reader.asReference] method.
*/
// TODO(alanknight): This is a hack both in defining a toJson specific to a
// particular representation, and the use of a bogus sentinel "__Ref"
diff --git a/pkg/serialization/lib/src/serialization_rule.dart b/pkg/serialization/lib/src/serialization_rule.dart
index d63f07a..0fc6f3e 100644
--- a/pkg/serialization/lib/src/serialization_rule.dart
+++ b/pkg/serialization/lib/src/serialization_rule.dart
@@ -387,24 +387,25 @@
* qualifiedName and attempts to look it up in both the namedObjects
* collection, or if it's not found there, by looking it up in the mirror
* system. When reading, the user is responsible for supplying the appropriate
- * values in [namedObjects] or in the [externals] paramter to
+ * values in [Serialization.namedObjects] or in the [externals] paramter to
* [Serialization.read].
*/
class MirrorRule extends NamedObjectRule {
bool appliesTo(object, Writer writer) => object is DeclarationMirror;
- nameFor(DeclarationMirror object, Writer writer) => object.qualifiedName;
+ nameFor(DeclarationMirror object, Writer writer) =>
+ MirrorSystem.getName(object.qualifiedName);
inflateEssential(state, Reader r) {
var qualifiedName = r.resolveReference(state.first);
var lookupFull = r.objectNamed(qualifiedName, (x) => null);
if (lookupFull != null) return lookupFull;
var separatorIndex = qualifiedName.lastIndexOf(".");
- var lib = qualifiedName.substring(0, separatorIndex);
+ var lib = new Symbol(qualifiedName.substring(0, separatorIndex));
var type = qualifiedName.substring(separatorIndex + 1);
var lookup = r.objectNamed(type, (x) => null);
if (lookup != null) return lookup;
- var libMirror = currentMirrorSystem().libraries[lib];
- return libMirror.classes[type];
+ var libMirror = currentMirrorSystem().findLibrary(lib).first;
+ return libMirror.classes[new Symbol(type)];
}
}
@@ -469,6 +470,16 @@
get hasVariableLengthEntries => true;
}
+/** A hard-coded rule for serializing Symbols. */
+class SymbolRule extends CustomRule {
+ bool appliesTo(instance, _) => instance is Symbol;
+ getState(instance) => [MirrorSystem.getName(instance)];
+ create(state) => new Symbol(state[0]);
+ setState(symbol, state) {}
+ int get dataLength => 1;
+ bool get hasVariableLengthEntries => false;
+}
+
/** Create a lazy list/map that will inflate its items on demand in [r]. */
_lazy(l, Reader r) {
if (l is List) return new _LazyList(l, r);
diff --git a/pkg/serialization/test/serialization_test.dart b/pkg/serialization/test/serialization_test.dart
index 2987fe0..47c8a6ae 100644
--- a/pkg/serialization/test/serialization_test.dart
+++ b/pkg/serialization/test/serialization_test.dart
@@ -123,9 +123,16 @@
var stream = new Stream([3,4,5]);
expect((stream..next()).next(), 4);
expect(stream.position, 2);
+ // The Symbol class does not allow us to create symbols for private
+ // variables. However, the mirror system uses them. So we get the symbol
+ // we want from the mirror.
+ // TODO(alanknight): Either delete this test and decide we shouldn't
+ // attempt to access private variables or fix this properly.
+ var _collectionSym = reflect(stream).type.variables.keys.firstWhere(
+ (x) => MirrorSystem.getName(x) == "_collection");
var s = new Serialization()
..addRuleFor(stream,
- constructorFields: ['_collection']);
+ constructorFields: [_collectionSym]);
var state = states(stream, s).first;
// Define names for the variable offsets to make this more readable.
var _collection = 0, position = 1;
@@ -211,7 +218,7 @@
var w = new Writer(s);
w.trace = new Trace(w);
w.write(n1);
- expect(w.states.length, 5); // prims, lists, essential lists, basic
+ expect(w.states.length, 6); // prims, lists, essential lists, basic, symbol
var children = 0, name = 1, parent = 2;
var nodeRule = s.rules.firstWhere((x) => x is BasicRule);
List rootNode = w.states[nodeRule.number].where(
@@ -510,6 +517,15 @@
expect(new Reader(s).asReference(map["person"]) is Reference, isTrue);
});
+ test("MirrorRule with lookup by qualified name rather than named object", () {
+ var s = new Serialization()..addRule(new MirrorRule());
+ var m = reflectClass(Address);
+ var output = s.write(m);
+ var input = s.read(output);
+ expect(input is ClassMirror, isTrue);
+ expect(MirrorSystem.getName(input.simpleName), "Address");
+ });
+
}
/******************************************************************************
@@ -651,7 +667,7 @@
/**
* Run a round-trip test on a simple tree of nodes, using a serialization
- * that's returned by the [serializerSetup] function.
+ * that's returned by the [serializerSetUp] function.
*/
runRoundTripTest(Function serializerSetUp) {
Node n1 = new Node("1"), n2 = new Node("2"), n3 = new Node("3");
diff --git a/pkg/source_maps/lib/source_maps.dart b/pkg/source_maps/lib/source_maps.dart
index 4e24dea..1594827 100644
--- a/pkg/source_maps/lib/source_maps.dart
+++ b/pkg/source_maps/lib/source_maps.dart
@@ -4,6 +4,21 @@
/// Source maps library.
///
+/// ## Installing ##
+///
+/// Use [pub][] to install this package. Add the following to your
+/// `pubspec.yaml` file.
+///
+/// dependencies:
+/// source_maps: any
+///
+/// Then run `pub install`.
+///
+/// For more information, see the
+/// [source_maps package on pub.dartlang.org][pkg].
+///
+/// ## Using ##
+///
/// Create a source map using [SourceMapBuilder]. For example:
/// var json = (new SourceMapBuilder()
/// ..add(inputSpan1, outputSpan1)
@@ -17,6 +32,9 @@
/// object. For example:
/// var mapping = parse(json);
/// mapping.spanFor(outputSpan1.line, outputSpan1.column)
+///
+/// [pub]: http://pub.dartlang.org
+/// [pkg]: http://pub.dartlang.org/packages/source_maps
library source_maps;
export "builder.dart";
diff --git a/pkg/stack_trace/lib/src/trace.dart b/pkg/stack_trace/lib/src/trace.dart
index fa0c313..54f99db 100644
--- a/pkg/stack_trace/lib/src/trace.dart
+++ b/pkg/stack_trace/lib/src/trace.dart
@@ -4,6 +4,7 @@
library trace;
+import 'dart:collection';
import 'dart:uri';
import 'dart:math' as math;
@@ -13,7 +14,6 @@
/// A stack trace, comprised of a list of stack frames.
class Trace implements StackTrace {
- // TODO(nweiz): make this read-only once issue 8321 is fixed.
/// The stack frames that comprise this stack trace.
final List<Frame> frames;
@@ -63,7 +63,7 @@
/// Returns a new [Trace] comprised of [frames].
Trace(Iterable<Frame> frames)
- : frames = frames.toList();
+ : frames = new UnmodifiableListView<Frame>(frames.toList());
// TODO(nweiz): Keep track of which [Frame]s are part of the partial stack
// trace and only print them.
diff --git a/pkg/stack_trace/lib/src/utils.dart b/pkg/stack_trace/lib/src/utils.dart
index 790dec8..50ccab3 100644
--- a/pkg/stack_trace/lib/src/utils.dart
+++ b/pkg/stack_trace/lib/src/utils.dart
@@ -15,7 +15,14 @@
throw new ArgumentError("Uri $uri must have scheme 'file:'.");
}
if (Platform.operatingSystem != 'windows') return uri.path;
- return uri.path.replaceFirst("/", "").replaceAll("/", "\\");
+ if (uri.path.startsWith("/")) {
+ // Drive-letter paths look like "file:///C:/path/to/file". The replaceFirst
+ // removes the extra initial slash.
+ return uri.path.replaceFirst("/", "").replaceAll("/", "\\");
+ } else {
+ // Network paths look like "file://hostname/path/to/file".
+ return "\\\\${uri.path.replaceAll("/", "\\")}";
+ }
}
/// Converts a local path string to a `file:` [Uri].
@@ -23,7 +30,11 @@
pathString = path.absolute(pathString);
if (Platform.operatingSystem != 'windows') {
return Uri.parse('file://$pathString');
+ } else if (path.rootPrefix(pathString).startsWith('\\\\')) {
+ // Network paths become "file://hostname/path/to/file".
+ return Uri.parse('file:${pathString.replaceAll("\\", "/")}');
} else {
+ // Drive-letter paths become "file:///C:/path/to/file".
return Uri.parse('file:///${pathString.replaceAll("\\", "/")}');
}
}
diff --git a/pkg/stack_trace/lib/stack_trace.dart b/pkg/stack_trace/lib/stack_trace.dart
index 5747b85..f031f95 100644
--- a/pkg/stack_trace/lib/stack_trace.dart
+++ b/pkg/stack_trace/lib/stack_trace.dart
@@ -2,6 +2,23 @@
// 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.
+/**
+ * ## Installing ##
+ *
+ * Use [pub][] to install this package. Add the following to your `pubspec.yaml`
+ * file.
+ *
+ * dependencies:
+ * stack_trace: any
+ *
+ * Then run `pub install`.
+ *
+ * For more information, see the
+ * [stack_trace package on pub.dartlang.org][pkg].
+ *
+ * [pub]: http://pub.dartlang.org
+ * [pkg]: http://pub.dartlang.org/packages/stack_trace
+ */
library stack_trace;
export 'src/trace.dart';
diff --git a/pkg/unittest/lib/matcher.dart b/pkg/unittest/lib/matcher.dart
index 6584198..8110432 100644
--- a/pkg/unittest/lib/matcher.dart
+++ b/pkg/unittest/lib/matcher.dart
@@ -4,6 +4,22 @@
/**
* The matcher library provides a 3rd generation assertion mechanism, drawing
* inspiration from [Hamcrest](http://code.google.com/p/hamcrest/).
+ *
+ * ## Installing ##
+ *
+ * Use [pub][] to install this package. Add the following to your `pubspec.yaml`
+ * file.
+ *
+ * dependencies:
+ * matcher: any
+ *
+ * Then run `pub install`.
+ *
+ * For more information, see the
+ * [matcher package on pub.dartlang.org][pkg].
+ *
+ * [pub]: http://pub.dartlang.org
+ * [pkg]: http://pub.dartlang.org/packages/matcher
*/
library matcher;
diff --git a/pkg/unittest/lib/mock.dart b/pkg/unittest/lib/mock.dart
index 9ee6d8a..cacaec7 100644
--- a/pkg/unittest/lib/mock.dart
+++ b/pkg/unittest/lib/mock.dart
@@ -5,6 +5,21 @@
/**
* A simple mocking/spy library.
*
+ * ## Installing ##
+ *
+ * Use [pub][] to install this package. Add the following to your `pubspec.yaml`
+ * file.
+ *
+ * dependencies:
+ * mock: any
+ *
+ * Then run `pub install`.
+ *
+ * For more information, see the
+ * [mock package on pub.dartlang.org](http://pub.dartlang.org/packages/mock).
+ *
+ * ## Using ##
+ *
* To create a mock objects for some class T, create a new class using:
*
* class MockT extends Mock implements T {};
@@ -87,6 +102,7 @@
* }
* }
*
+ * [pub]: http://pub.dartlang.org
*/
library mock;
diff --git a/pkg/unittest/lib/src/core_matchers.dart b/pkg/unittest/lib/src/core_matchers.dart
index e8606aa..980e7a0 100644
--- a/pkg/unittest/lib/src/core_matchers.dart
+++ b/pkg/unittest/lib/src/core_matchers.dart
@@ -177,9 +177,8 @@
var aType = typeName(actual);
var includeTypes = eType != aType;
// If we have recursed, show the expected value too; if not,
- // expect() will show it for us. As expect will not show type
- // mismatches at the top level we handle those here too.
- if (includeTypes || depth > 1) {
+ // expect() will show it for us.
+ if (depth > 0) {
reason.add('expected ');
if (includeTypes) {
reason.add(eType).add(':');
@@ -191,6 +190,9 @@
reason.add(aType).add(':');
}
reason.addDescriptionOf(actual);
+ if (includeTypes && depth == 0) {
+ reason.add(' (not type ').add(eType).add(')');
+ }
}
}
if (reason != null && location.length > 0) {
@@ -706,8 +708,8 @@
final String _featureName;
final Matcher _matcher;
- const CustomMatcher(this._featureDescription, this._featureName,
- this._matcher);
+ CustomMatcher(this._featureDescription, this._featureName, matcher)
+ : this._matcher = wrapMatcher(matcher);
/** Override this to extract the interesting feature.*/
featureValueOf(actual) => actual;
diff --git a/pkg/unittest/lib/src/test_case.dart b/pkg/unittest/lib/src/test_case.dart
index 13d59f5..8e761f6 100644
--- a/pkg/unittest/lib/src/test_case.dart
+++ b/pkg/unittest/lib/src/test_case.dart
@@ -61,9 +61,9 @@
Completer _testComplete;
TestCase._internal(this.id, this.description, this.testFunction)
- : currentGroup = _currentGroup,
- setUp = _testSetup,
- tearDown = _testTeardown;
+ : currentGroup = _currentContext.fullName,
+ setUp = _currentContext.testSetup,
+ tearDown = _currentContext.testTeardown;
bool get isComplete => !enabled || result != null;
@@ -83,7 +83,10 @@
--_callbackFunctionsOutstanding;
if (f is Future) {
return f.then((_) => _finishTest())
- .catchError((error) => fail("${error}"));
+ .catchError((error) {
+ var stack = getAttachedStackTrace(error);
+ _registerException(this, error, stack);
+ });
} else {
_finishTest();
return null;
@@ -118,7 +121,8 @@
// a failed setUp. There is no right answer, but doing it
// seems to be the more conservative approach, because
// unittest will not stop at a test failure.
- error("$description: Test setup failed: $e");
+ var stack = getAttachedStackTrace(e);
+ error("$description: Test setup failed: $e", "$stack");
});
} else {
var f = _runTest();
diff --git a/pkg/unittest/lib/unittest.dart b/pkg/unittest/lib/unittest.dart
index 50d308b..b2abf069 100644
--- a/pkg/unittest/lib/unittest.dart
+++ b/pkg/unittest/lib/unittest.dart
@@ -5,9 +5,20 @@
/**
* A library for writing dart unit tests.
*
- * To import this library, install the
- * [unittest package](http://pub.dartlang.org/packages/unittest) via the pub
- * package manager. See the [Getting Started](http://pub.dartlang.org/doc)
+ * ## Installing ##
+ *
+ * Use [pub][] to install this package. Add the following to your `pubspec.yaml`
+ * file.
+ *
+ * dependencies:
+ * unittest: any
+ *
+ * Then run `pub install`.
+ *
+ * For more information, see the
+ * [unittest package on pub.dartlang.org][pkg].
+ *
+ * See the [Getting Started](http://pub.dartlang.org/doc)
* guide for more details.
*
* ##Concepts##
@@ -150,6 +161,8 @@
* });
* }
*
+ * [pub]: http://pub.dartlang.org
+ * [pkg]: http://pub.dartlang.org/packages/unittest
*/
library unittest;
@@ -192,24 +205,85 @@
void logMessage(String message) =>
_config.onLogMessage(currentTestCase, message);
-/**
- * Description text of the current test group. If multiple groups are nested,
- * this will contain all of their text concatenated.
- */
-String _currentGroup = '';
-
/** Separator used between group names and test names. */
String groupSep = ' ';
-// TODO(nweiz): present an unmodifiable view of this once issue 8321 is fixed.
+final List<TestCase> _testCases = new List<TestCase>();
+
/** Tests executed in this suite. */
-final List<TestCase> testCases = new List<TestCase>();
+final List<TestCase> testCases = new UnmodifiableListView<TestCase>(_testCases);
-/** Setup function called before each test in a group */
-Function _testSetup;
+/**
+ * Setup and teardown functions for a group and its parents, the latter
+ * for chaining.
+ */
+class GroupContext {
+ final GroupContext parent;
-/** Teardown function called after each test in a group */
-Function _testTeardown;
+ /** Description text of the current test group. */
+ final String _name;
+
+ /** Setup function called before each test in a group. */
+ Function _testSetup;
+
+ get testSetup => _testSetup;
+
+ get parentSetup => (parent == null) ? null : parent.testSetup;
+
+ set testSetup(Function setup) {
+ var preSetup = parentSetup;
+ if (preSetup == null) {
+ _testSetup = setup;
+ } else {
+ _testSetup = () {
+ var f = preSetup();
+ if (f is Future) {
+ return f.then((_) => setup());
+ } else {
+ return setup();
+ }
+ };
+ }
+ }
+
+ /** Teardown function called after each test in a group. */
+ Function _testTeardown;
+
+ get testTeardown => _testTeardown;
+
+ get parentTeardown => (parent == null) ? null : parent.testTeardown;
+
+ set testTeardown(Function teardown) {
+ var postTeardown = parentTeardown;
+ if (postTeardown == null) {
+ _testTeardown = teardown;
+ } else {
+ _testTeardown = () {
+ var f = teardown();
+ if (f is Future) {
+ return f.then((_) => postTeardown());
+ } else {
+ return postTeardown();
+ }
+ };
+ }
+ }
+
+ String get fullName => (parent == null || parent == _rootContext)
+ ? _name
+ : "${parent.fullName}$groupSep$_name";
+
+ GroupContext([this.parent, this._name = '']) {
+ _testSetup = parentSetup;
+ _testTeardown = parentTeardown;
+ }
+}
+
+// We use a 'dummy' context for the top level to eliminate null
+// checks when querying the context. This allows us to easily
+// support top-level setUp/tearDown functions as well.
+GroupContext _rootContext = new GroupContext();
+GroupContext _currentContext = _rootContext;
int _currentTestCaseIndex = 0;
@@ -252,8 +326,8 @@
*/
void test(String spec, TestFunction body) {
ensureInitialized();
- testCases.add(new TestCase._internal(testCases.length + 1, _fullSpec(spec),
- body));
+ _testCases.add(new TestCase._internal(testCases.length + 1, _fullSpec(spec),
+ body));
}
/**
@@ -275,8 +349,9 @@
ensureInitialized();
- _soloTest = new TestCase._internal(testCases.length + 1, _fullSpec(spec), body);
- testCases.add(_soloTest);
+ _soloTest = new TestCase._internal(testCases.length + 1, _fullSpec(spec),
+ body);
+ _testCases.add(_soloTest);
}
/** Sentinel value for [_SpreadArgsHelper]. */
@@ -292,10 +367,9 @@
final int minExpectedCalls;
final int maxExpectedCalls;
final Function isDone;
- final int testNum;
final String id;
int actualCalls = 0;
- TestCase testCase;
+ final TestCase testCase;
bool complete;
static const sentinel = const _Sentinel();
@@ -307,19 +381,14 @@
? minExpected
: maxExpected,
this.isDone = isDone,
- testNum = _currentTestCaseIndex,
+ this.testCase = currentTestCase,
this.id = _makeCallbackId(id, callback) {
ensureInitialized();
- if (!(_currentTestCaseIndex >= 0 &&
- _currentTestCaseIndex < testCases.length &&
- testCases[_currentTestCaseIndex] != null)) {
- print("No valid test, did you forget to run your test inside a call "
- "to test()?");
+ if (testCase == null) {
+ throw new StateError("No valid test. Did you forget to run your test "
+ "inside a call to test()?");
}
- assert(_currentTestCaseIndex >= 0 &&
- _currentTestCaseIndex < testCases.length &&
- testCases[_currentTestCaseIndex] != null);
- testCase = testCases[_currentTestCaseIndex];
+
if (isDone != null || minExpected > 0) {
testCase._callbackFunctionsOutstanding++;
complete = false;
@@ -328,7 +397,7 @@
}
}
- static _makeCallbackId(String id, Function callback) {
+ static String _makeCallbackId(String id, Function callback) {
// Try to create a reasonable id.
if (id != null) {
return "$id ";
@@ -349,7 +418,7 @@
return '';
}
- shouldCallBack() {
+ bool shouldCallBack() {
++actualCalls;
if (testCase.isComplete) {
// Don't run if the test is done. We don't throw here as this is not
@@ -369,7 +438,7 @@
return true;
}
- after() {
+ void after() {
if (!complete) {
if (minExpectedCalls > 0 && actualCalls < minExpectedCalls) return;
if (isDone != null && !isDone()) return;
@@ -381,31 +450,6 @@
}
}
- invoke([arg0 = sentinel, arg1 = sentinel, arg2 = sentinel,
- arg3 = sentinel, arg4 = sentinel]) {
- return _guardAsync(() {
- if (!shouldCallBack()) {
- return;
- } else if (arg0 == sentinel) {
- return callback();
- } else if (arg1 == sentinel) {
- return callback(arg0);
- } else if (arg2 == sentinel) {
- return callback(arg0, arg1);
- } else if (arg3 == sentinel) {
- return callback(arg0, arg1, arg2);
- } else if (arg4 == sentinel) {
- return callback(arg0, arg1, arg2, arg3);
- } else {
- testCase.error(
- 'unittest lib does not support callbacks with more than'
- ' 4 arguments.',
- '');
- }
- },
- after, testNum);
- }
-
invoke0() {
return _guardAsync(
() {
@@ -413,7 +457,7 @@
return callback();
}
},
- after, testNum);
+ after, testCase);
}
invoke1(arg1) {
@@ -423,7 +467,7 @@
return callback(arg1);
}
},
- after, testNum);
+ after, testCase);
}
invoke2(arg1, arg2) {
@@ -433,7 +477,7 @@
return callback(arg1, arg2);
}
},
- after, testNum);
+ after, testCase);
}
}
@@ -441,21 +485,6 @@
* Indicate that [callback] is expected to be called a [count] number of times
* (by default 1). The unittest framework will wait for the callback to run the
* specified [count] times before it continues with the following test. Using
- * [_expectAsync] will also ensure that errors that occur within [callback] are
- * tracked and reported. [callback] should take between 0 and 4 positional
- * arguments (named arguments are not supported here). [id] can be used
- * to provide more descriptive error messages if the callback is called more
- * often than expected.
- */
-Function _expectAsync(Function callback,
- {int count: 1, int max: 0, String id}) {
- return new _SpreadArgsHelper(callback, count, max, null, id).invoke;
-}
-
-/**
- * Indicate that [callback] is expected to be called a [count] number of times
- * (by default 1). The unittest framework will wait for the callback to run the
- * specified [count] times before it continues with the following test. Using
* [expectAsync0] will also ensure that errors that occur within [callback] are
* tracked and reported. [callback] should take 0 positional arguments (named
* arguments are not supported). [id] can be used to provide more
@@ -489,20 +518,6 @@
/**
* Indicate that [callback] is expected to be called until [isDone] returns
- * true. The unittest framework checks [isDone] after each callback and only
- * when it returns true will it continue with the following test. Using
- * [expectAsyncUntil] will also ensure that errors that occur within
- * [callback] are tracked and reported. [callback] should take between 0 and
- * 4 positional arguments (named arguments are not supported). [id] can be
- * used to identify the callback in error messages (for example if it is called
- * after the test case is complete).
- */
-Function _expectAsyncUntil(Function callback, Function isDone, {String id}) {
- return new _SpreadArgsHelper(callback, 0, -1, isDone, id).invoke;
-}
-
-/**
- * Indicate that [callback] is expected to be called until [isDone] returns
* true. The unittest framework check [isDone] after each callback and only
* when it returns true will it continue with the following test. Using
* [expectAsyncUntil0] will also ensure that errors that occur within
@@ -537,19 +552,6 @@
* function will be able to handle exceptions by directing them to the correct
* test. This is thus similar to expectAsync0. Use it to wrap any callbacks that
* might optionally be called but may never be called during the test.
- * [callback] should take between 0 and 4 positional arguments (named arguments
- * are not supported). [id] can be used to identify the callback in error
- * messages (for example if it is called after the test case is complete).
- */
-Function _protectAsync(Function callback, {String id}) {
- return new _SpreadArgsHelper(callback, 0, -1, null, id).invoke;
-}
-
-/**
- * Wraps the [callback] in a new function and returns that function. The new
- * function will be able to handle exceptions by directing them to the correct
- * test. This is thus similar to expectAsync0. Use it to wrap any callbacks that
- * might optionally be called but may never be called during the test.
* [callback] should take 0 positional arguments (named arguments are not
* supported). [id] can be used to identify the callback in error
* messages (for example if it is called after the test case is complete).
@@ -581,46 +583,27 @@
*/
void group(String description, void body()) {
ensureInitialized();
- // Concatenate the new group.
- final parentGroup = _currentGroup;
- if (_currentGroup != '') {
- // Add a space.
- _currentGroup = '$_currentGroup$groupSep$description';
- } else {
- // The first group.
- _currentGroup = description;
- }
-
- // Groups can be nested, so we need to preserve the current
- // settings for test setup/teardown.
- Function parentSetup = _testSetup;
- Function parentTeardown = _testTeardown;
-
+ _currentContext = new GroupContext(_currentContext, description);
try {
- _testSetup = null;
- _testTeardown = null;
body();
} catch (e, trace) {
var stack = (trace == null) ? '' : ': ${trace.toString()}';
_uncaughtErrorMessage = "${e.toString()}$stack";
} finally {
// Now that the group is over, restore the previous one.
- _currentGroup = parentGroup;
- _testSetup = parentSetup;
- _testTeardown = parentTeardown;
+ _currentContext = _currentContext.parent;
}
}
/**
* Register a [setUp] function for a test [group]. This function will
- * be called before each test in the group is run. Note that if groups
- * are nested only the most locally scoped [setUpTest] function will be run.
+ * be called before each test in the group is run.
* [setUp] and [tearDown] should be called within the [group] before any
* calls to [test]. The [setupTest] function can be asynchronous; in this
* case it must return a [Future].
*/
void setUp(Function setupTest) {
- _testSetup = setupTest;
+ _currentContext.testSetup = setupTest;
}
/**
@@ -632,12 +615,12 @@
* case it must return a [Future].
*/
void tearDown(Function teardownTest) {
- _testTeardown = teardownTest;
+ _currentContext.testTeardown = teardownTest;
}
/** Advance to the next test case. */
void _nextTestCase() {
- _defer(() {
+ runAsync(() {
_currentTestCaseIndex++;
_nextBatch();
});
@@ -656,19 +639,6 @@
}
}
-/**
- * Runs [callback] at the end of the event loop. Note that we don't wrap
- * the callback in guardAsync; this is for test framework functions which
- * should not be throwing unexpected exceptions that end up failing test
- * cases! Furthermore, we need the final exception to be thrown but not
- * caught by the test framework if any test cases failed. However, tests
- * that make use of a similar defer function *should* wrap the callback
- * (as we do in unitttest_test.dart).
- */
-_defer(void callback()) {
- (new Future.value()).then((_) => callback());
-}
-
void rerunTests() {
_uncaughtErrorMessage = null;
_initialized = true; // We don't want to reset the test array.
@@ -690,14 +660,13 @@
} else if (testFilter is Function) {
filterFunction = testFilter;
}
- testCases.retainWhere(filterFunction);
+ _testCases.retainWhere(filterFunction);
}
/** Runs all queued tests, one at a time. */
void runTests() {
_ensureInitialized(false);
_currentTestCaseIndex = 0;
- _currentGroup = '';
// If we are soloing a test, remove all the others.
if (_soloTest != null) {
@@ -706,7 +675,7 @@
_config.onStart();
- _defer(() {
+ runAsync(() {
_nextBatch();
});
}
@@ -718,15 +687,15 @@
* The value returned by [tryBody] (if any) is returned by [guardAsync].
*/
guardAsync(Function tryBody) {
- return _guardAsync(tryBody, null, _currentTestCaseIndex);
+ return _guardAsync(tryBody, null, currentTestCase);
}
-_guardAsync(Function tryBody, Function finallyBody, int testNum) {
- assert(testNum >= 0);
+_guardAsync(Function tryBody, Function finallyBody, TestCase testCase) {
+ assert(testCase != null);
try {
return tryBody();
} catch (e, trace) {
- _registerException(testNum, e, trace);
+ _registerException(testCase, e, trace);
} finally {
if (finallyBody != null) finallyBody();
}
@@ -736,19 +705,19 @@
* Registers that an exception was caught for the current test.
*/
void registerException(e, [trace]) {
- _registerException(_currentTestCaseIndex, e, trace);
+ _registerException(currentTestCase, e, trace);
}
/**
* Registers that an exception was caught for the current test.
*/
-void _registerException(testNum, e, [trace]) {
+void _registerException(TestCase testCase, e, [trace]) {
trace = trace == null ? '' : trace.toString();
String message = (e is TestFailure) ? e.message : 'Caught $e';
- if (testCases[testNum].result == null) {
- testCases[testNum].fail(message, trace);
+ if (testCase.result == null) {
+ testCase.fail(message, trace);
} else {
- testCases[testNum].error(message, trace);
+ testCase.error(message, trace);
}
}
@@ -764,7 +733,7 @@
break;
}
final testCase = testCases[_currentTestCaseIndex];
- var f = _guardAsync(testCase._run, null, _currentTestCaseIndex);
+ var f = _guardAsync(testCase._run, null, testCase);
if (f != null) {
f.whenComplete(() {
_nextTestCase(); // Schedule the next test.
@@ -796,8 +765,9 @@
}
String _fullSpec(String spec) {
- if (spec == null) return '$_currentGroup';
- return _currentGroup != '' ? '$_currentGroup$groupSep$spec' : spec;
+ var group = '${_currentContext.fullName}';
+ if (spec == null) return group;
+ return group != '' ? '$group$groupSep$spec' : spec;
}
/**
@@ -825,7 +795,7 @@
if (configAutoStart && _config.autoStart) {
// Immediately queue the suite up. It will run after a timeout (i.e. after
// main() has returned).
- _defer(runTests);
+ runAsync(runTests);
}
}
diff --git a/pkg/unittest/test/matchers_test.dart b/pkg/unittest/test/matchers_test.dart
index be286ea..4f1ae6e 100644
--- a/pkg/unittest/test/matchers_test.dart
+++ b/pkg/unittest/test/matchers_test.dart
@@ -30,7 +30,7 @@
}
class HasPrice extends CustomMatcher {
- const HasPrice(matcher) :
+ HasPrice(matcher) :
super("Widget with a price that is", "price", matcher);
featureValueOf(actual) => actual.price;
}
@@ -237,20 +237,25 @@
shouldPass(b, hasLength(2));
});
- test('type mismatch', () {
- var a = new DateTime.utc(2000);
- var b = a.toString();
- // We should get something like:
- // Expected: '2000-01-01 00:00:00.000Z'
- // but: expected String:'2000-01-01 00:00:00.000Z'
- // but was DateTime:<2000-01-01 00:00:00.000Z>.
- // However, if minification is applied, then the type names
- // will be shortened to two letters. The key thing is that
- // there will be a "but: expected" part in the middle;
- // this only happens with type mismatches or mismatches
- // inside container types.
- shouldFail(a, equals(b),
- matches(new RegExp("^Expected.*but: expected .*but was.*\$")));
+ test('scalar type mismatch', () {
+ shouldFail('error', equals(5.1),
+ matches("^Expected: <5\.1>"
+ " but: was .*:'error' \\(not type .*\\)\.\$"));
+ });
+
+ test('nested type mismatch', () {
+ shouldFail(['error'], equals([5.1]),
+ matches(r"^Expected: <\[5\.1\]>"
+ " but: expected double:<5\.1> "
+ "but was .*:'error' mismatch at position 0\.\$"));
+ });
+
+ test('doubly-nested type mismatch', () {
+ shouldFail([['error']], equals([[5.1]]),
+ matches(r"^Expected: <\[\[5\.1\]\]>"
+ " but: expected double:<5\.1> "
+ "but was .*:'error' mismatch at position 0 "
+ "mismatch at position 0\.\$"));
});
});
@@ -502,7 +507,7 @@
shouldPass(d, orderedEquals([1, 2]));
shouldFail(d, orderedEquals([2, 1]),
"Expected: equals <[2, 1]> ordered "
- "but: was <1> mismatch at position 0.");
+ "but: expected <2> but was <1> mismatch at position 0.");
});
test('unorderedEquals', () {
@@ -702,6 +707,7 @@
test("Feature Matcher", () {
var w = new Widget();
w.price = 10;
+ shouldPass(w, new HasPrice(10));
shouldPass(w, new HasPrice(greaterThan(0)));
shouldFail(w, new HasPrice(greaterThan(10)),
'Expected: Widget with a price that is a value greater than <10> '
diff --git a/pkg/unittest/test/unittest_test.dart b/pkg/unittest/test/unittest_test.dart
index 24ff29d..aa1bd97 100644
--- a/pkg/unittest/test/unittest_test.dart
+++ b/pkg/unittest/test/unittest_test.dart
@@ -68,6 +68,26 @@
}
}
+makeDelayedSetup(index, s) => () {
+ return new Future.delayed(new Duration(milliseconds:1), () {
+ s.write('l$index U ');
+ });
+};
+
+makeDelayedTeardown(index, s) => () {
+ return new Future.delayed(new Duration(milliseconds:1), () {
+ s.write('l$index D ');
+ });
+};
+
+makeImmediateSetup(index, s) => () {
+ s.write('l$index U ');
+};
+
+makeImmediateTeardown(index, s) => () {
+ s.write('l$index D ');
+};
+
runTest() {
port.receive((String testName, sendport) {
var testConfig = new TestConfiguration(sendport);
@@ -292,8 +312,38 @@
});
test('foo6', () {
});
+ } else if (testName == 'testCases immutable') {
+ test(testName, () {
+ expect(() => testCases.clear(), throwsUnsupportedError);
+ expect(() => testCases.removeLast(), throwsUnsupportedError);
+ });
} else if (testName == 'runTests without tests') {
runTests();
+ } else if (testName == 'nested groups setup/teardown') {
+ StringBuffer s = new StringBuffer();
+ group('level 1', () {
+ setUp(makeDelayedSetup(1, s));
+ group('level 2', () {
+ setUp(makeImmediateSetup(2, s));
+ tearDown(makeDelayedTeardown(2, s));
+ group('level 3', () {
+ group('level 4', () {
+ setUp(makeDelayedSetup(4, s));
+ tearDown(makeImmediateTeardown(4, s));
+ group('level 5', () {
+ setUp(makeImmediateSetup(5, s));
+ group('level 6', () {
+ tearDown(makeDelayedTeardown(6, s));
+ test('inner', () {});
+ });
+ });
+ });
+ });
+ });
+ });
+ test('after nest', () {
+ expect(s.toString(), "l1 U l2 U l4 U l5 U l6 D l4 D l2 D ");
+ });
}
});
}
@@ -348,7 +398,12 @@
'fail2:failure:'
'error2:Callback called more times than expected (1).:'
'foo6'),
- 'runTests without tests': buildStatusString(0, 0, 0, null)
+ 'testCases immutable':
+ buildStatusString(1, 0, 0, 'testCases immutable'),
+ 'runTests without tests': buildStatusString(0, 0, 0, null),
+ 'nested groups setup/teardown':
+ buildStatusString(2, 0, 0,
+ 'level 1 level 2 level 3 level 4 level 5 level 6 inner::after nest')
};
tests.forEach((String name, String expected) {
diff --git a/pkg/webdriver/lib/webdriver.dart b/pkg/webdriver/lib/webdriver.dart
index fbae2d3..724332d9 100644
--- a/pkg/webdriver/lib/webdriver.dart
+++ b/pkg/webdriver/lib/webdriver.dart
@@ -14,6 +14,21 @@
/**
* WebDriver bindings for Dart.
*
+* ## Installing ##
+ *
+ * Use [pub][] to install this package. Add the following to your `pubspec.yaml`
+ * file.
+ *
+ * dependencies:
+ * webdriver: any
+ *
+ * Then run `pub install`.
+ *
+ * For more information, see the
+ * [webdriver package on pub.dartlang.org][pkg].
+ *
+ * ## Using ##
+ *
* These bindings are based on the WebDriver JSON wire protocol spec
* (http://code.google.com/p/selenium/wiki/JsonWireProtocol). Not
* all of these commands are implemented yet by WebDriver itself.
@@ -50,6 +65,9 @@
* }).then((_) {
* session = null;
* });
+ *
+ * [pub]: http://pub.dartlang.org
+ * [pkg]: http://pub.dartlang.org/packages/webdriver
*/
void writeStringToFile(String fileName, String contents) {
diff --git a/pkg/yaml/lib/yaml.dart b/pkg/yaml/lib/yaml.dart
index 94e3d42..85861d5 100644
--- a/pkg/yaml/lib/yaml.dart
+++ b/pkg/yaml/lib/yaml.dart
@@ -4,6 +4,21 @@
/// A parser for [YAML](http://www.yaml.org/).
///
+/// ## Installing ##
+///
+/// Use [pub][] to install this package. Add the following to your
+/// `pubspec.yaml` file.
+///
+/// dependencies:
+/// yaml: any
+///
+/// Then run `pub install`.
+///
+/// For more information, see the
+/// [yaml package on pub.dartlang.org][pkg].
+///
+/// ## Using ##
+///
/// Use [loadYaml] to load a single document, or [loadYamlStream] to load a
/// stream of documents. For example:
///
@@ -22,6 +37,9 @@
/// var doc = loadYaml("YAML: YAML Ain't Markup Language");
/// print(json.stringify(doc));
/// }
+///
+/// [pub]: http://pub.dartlang.org
+/// [pkg]: http://pub.dartlang.org/packages/yaml
library yaml;
import 'src/composer.dart';
diff --git a/runtime/bin/bin.gypi b/runtime/bin/bin.gypi
index b910a10..ffc22e2 100644
--- a/runtime/bin/bin.gypi
+++ b/runtime/bin/bin.gypi
@@ -4,19 +4,32 @@
{
'variables': {
- 'io_cc_file': '<(SHARED_INTERMEDIATE_DIR)/io_gen.cc',
- 'io_patch_cc_file': '<(SHARED_INTERMEDIATE_DIR)/io_patch_gen.cc',
+ # We place most generated source files in LIB_DIR (rather than, say
+ # SHARED_INTERMEDIATE_DIR) because it is toolset specific. This avoids
+ # two problems. First, if a generated source file has architecture specific
+ # code, we'll get two different files in two different directories. Second,
+ # if a generated source file is needed to build a target with multiple
+ # toolsets, we avoid having duplicate Makefile targets.
+ 'gen_source_dir': '<(LIB_DIR)',
+
+ 'io_cc_file': '<(gen_source_dir)/io_gen.cc',
+ 'io_patch_cc_file': '<(gen_source_dir)/io_patch_gen.cc',
'builtin_in_cc_file': 'builtin_in.cc',
- 'builtin_cc_file': '<(SHARED_INTERMEDIATE_DIR)/builtin_gen.cc',
+ 'builtin_cc_file': '<(gen_source_dir)/builtin_gen.cc',
'snapshot_in_cc_file': 'snapshot_in.cc',
- 'snapshot_bin_file': '<(SHARED_INTERMEDIATE_DIR)/snapshot_gen.bin',
+ 'snapshot_bin_file': '<(gen_source_dir)/snapshot_gen.bin',
+ 'resources_cc_file': '<(gen_source_dir)/resources_gen.cc',
+
+ # The program that creates snapshot_gen.cc is only built and run on the
+ # host, but it must be available when dart is built for the target. Thus,
+ # we keep it in a shared location.
'snapshot_cc_file': '<(SHARED_INTERMEDIATE_DIR)/snapshot_gen.cc',
- 'resources_cc_file': '<(SHARED_INTERMEDIATE_DIR)/resources_gen.cc',
},
'targets': [
{
'target_name': 'generate_builtin_cc_file',
'type': 'none',
+ 'toolsets':['target','host'],
'includes': [
'builtin_sources.gypi',
],
@@ -37,7 +50,7 @@
'--output', '<(builtin_cc_file)',
'--input_cc', '<(builtin_in_cc_file)',
'--include', 'bin/builtin.h',
- '--var_name', 'Builtin::builtin_source_',
+ '--var_name', 'dart::bin::Builtin::builtin_source_',
'<@(_sources)',
],
'message': 'Generating ''<(builtin_cc_file)'' file.'
@@ -47,8 +60,9 @@
{
'target_name': 'generate_io_cc_file',
'type': 'none',
+ 'toolsets':['target','host'],
'variables': {
- 'io_dart': '<(SHARED_INTERMEDIATE_DIR)/io_gen.dart',
+ 'io_dart': '<(gen_source_dir)/io_gen.dart',
},
'sources': [
'io.dart',
@@ -89,7 +103,7 @@
'--output', '<(io_cc_file)',
'--input_cc', '<(builtin_in_cc_file)',
'--include', 'bin/builtin.h',
- '--var_name', 'Builtin::io_source_',
+ '--var_name', 'dart::bin::Builtin::io_source_',
'<(io_dart)',
],
'message': 'Generating ''<(io_cc_file)'' file.'
@@ -99,6 +113,7 @@
{
'target_name': 'generate_io_patch_cc_file',
'type': 'none',
+ 'toolsets':['target','host'],
'includes': [
'io_sources.gypi',
],
@@ -119,7 +134,7 @@
'--output', '<(io_patch_cc_file)',
'--input_cc', '<(builtin_in_cc_file)',
'--include', 'bin/builtin.h',
- '--var_name', 'Builtin::io_patch_',
+ '--var_name', 'dart::bin::Builtin::io_patch_',
'<@(_sources)',
],
'message': 'Generating ''<(io_patch_cc_file)'' file.'
@@ -129,6 +144,7 @@
{
'target_name': 'libdart_builtin',
'type': 'static_library',
+ 'toolsets':['target','host'],
'dependencies': [
'generate_builtin_cc_file',
'generate_io_cc_file',
@@ -218,6 +234,7 @@
{
'target_name': 'libdart_withcore',
'type': 'static_library',
+ 'toolsets':['target','host'],
'dependencies': [
'libdart_lib_withcore',
'libdart_vm',
@@ -243,6 +260,7 @@
# Completely statically linked binary for generating snapshots.
'target_name': 'gen_snapshot',
'type': 'executable',
+ 'toolsets':['host'],
'dependencies': [
'libdart_withcore',
'libdart_builtin',
@@ -276,8 +294,9 @@
# Generate snapshot bin file.
'target_name': 'generate_snapshot_bin',
'type': 'none',
+ 'toolsets':['host'],
'dependencies': [
- 'gen_snapshot',
+ 'gen_snapshot#host',
],
'actions': [
{
@@ -305,8 +324,9 @@
# Generate snapshot file.
'target_name': 'generate_snapshot_file',
'type': 'none',
+ 'toolsets':['host'],
'dependencies': [
- 'generate_snapshot_bin',
+ 'generate_snapshot_bin#host',
],
'actions': [
{
@@ -365,7 +385,7 @@
'libdart',
'libdart_builtin',
'libdart_io',
- 'generate_snapshot_file',
+ 'generate_snapshot_file#host',
'generate_resources_cc_file',
],
'include_dirs': [
@@ -478,7 +498,7 @@
],
'include_dirs': [
'..',
- '<(SHARED_INTERMEDIATE_DIR)',
+ '<(gen_source_dir)',
],
'sources': [
'run_vm_tests.cc',
diff --git a/runtime/bin/builtin.cc b/runtime/bin/builtin.cc
index 2af1339..a2d646c 100644
--- a/runtime/bin/builtin.cc
+++ b/runtime/bin/builtin.cc
@@ -10,6 +10,9 @@
#include "bin/dartutils.h"
#include "bin/io_natives.h"
+namespace dart {
+namespace bin {
+
Builtin::builtin_lib_props Builtin::builtin_libraries_[] = {
/* { url_, source_, patch_url_, patch_source_, has_natives_ } */
{ DartUtils::kBuiltinLibURL, builtin_source_, NULL, NULL, true },
@@ -64,3 +67,6 @@
DART_CHECK_VALID(library);
return library;
}
+
+} // namespace bin
+} // namespace dart
diff --git a/runtime/bin/builtin.h b/runtime/bin/builtin.h
index 4a33b6c..67fc9fb 100644
--- a/runtime/bin/builtin.h
+++ b/runtime/bin/builtin.h
@@ -12,6 +12,9 @@
#include "platform/assert.h"
#include "platform/globals.h"
+namespace dart {
+namespace bin {
+
#define FUNCTION_NAME(name) Builtin_##name
#define REGISTER_FUNCTION(name, count) \
{ ""#name, FUNCTION_NAME(name), count },
@@ -59,5 +62,7 @@
DISALLOW_IMPLICIT_CONSTRUCTORS(Builtin);
};
+} // namespace bin
+} // namespace dart
#endif // BIN_BUILTIN_H_
diff --git a/runtime/bin/builtin_gen_snapshot.cc b/runtime/bin/builtin_gen_snapshot.cc
index af68759..c76cd55 100644
--- a/runtime/bin/builtin_gen_snapshot.cc
+++ b/runtime/bin/builtin_gen_snapshot.cc
@@ -10,6 +10,9 @@
#include "bin/dartutils.h"
+namespace dart {
+namespace bin {
+
Builtin::builtin_lib_props Builtin::builtin_libraries_[] = {
/* { url_, source_, patch_url_, patch_source_, has_natives_ } */
{ DartUtils::kBuiltinLibURL, builtin_source_, NULL, NULL, true },
@@ -65,3 +68,6 @@
DART_CHECK_VALID(library);
return library;
}
+
+} // namespace bin
+} // namespace dart
diff --git a/runtime/bin/builtin_natives.cc b/runtime/bin/builtin_natives.cc
index 555dfe5..86f9aee 100644
--- a/runtime/bin/builtin_natives.cc
+++ b/runtime/bin/builtin_natives.cc
@@ -12,6 +12,9 @@
#include "platform/assert.h"
+namespace dart {
+namespace bin {
+
// Lists the native functions implementing basic functionality in
// standalone dart, such as printing, file I/O, and platform information.
// Advanced I/O classes like sockets and process management are implemented
@@ -109,3 +112,6 @@
Builtin::PrintString(stdout, Dart_GetNativeArgument(args, 0));
Dart_ExitScope();
}
+
+} // namespace bin
+} // namespace dart
diff --git a/runtime/bin/builtin_nolib.cc b/runtime/bin/builtin_nolib.cc
index 048aa86..6ca4a20 100644
--- a/runtime/bin/builtin_nolib.cc
+++ b/runtime/bin/builtin_nolib.cc
@@ -10,6 +10,10 @@
#include "bin/dartutils.h"
#include "bin/io_natives.h"
+
+namespace dart {
+namespace bin {
+
Builtin::builtin_lib_props Builtin::builtin_libraries_[] = {
/* { url_, source_, patch_url_, patch_source_, has_natives_ } */
{ DartUtils::kBuiltinLibURL, NULL, NULL, NULL, true },
@@ -64,3 +68,6 @@
DART_CHECK_VALID(library);
return library;
}
+
+} // namespace bin
+} // namespace dart
diff --git a/runtime/bin/common.cc b/runtime/bin/common.cc
index 261557d..030fcfa 100644
--- a/runtime/bin/common.cc
+++ b/runtime/bin/common.cc
@@ -6,6 +6,9 @@
#include "bin/isolate_data.h"
#include "include/dart_api.h"
+namespace dart {
+namespace bin {
+
void FUNCTION_NAME(Common_IsBuiltinList)(Dart_NativeArguments args) {
Dart_EnterScope();
Dart_Handle list = Dart_GetNativeArgument(args, 0);
@@ -54,3 +57,6 @@
Dart_SetReturnValue(args, Dart_NewBoolean(builtin_array));
Dart_ExitScope();
}
+
+} // namespace bin
+} // namespace dart
diff --git a/runtime/bin/crypto.cc b/runtime/bin/crypto.cc
index af5886d..cd707dd 100644
--- a/runtime/bin/crypto.cc
+++ b/runtime/bin/crypto.cc
@@ -8,6 +8,9 @@
#include "include/dart_api.h"
+namespace dart {
+namespace bin {
+
void FUNCTION_NAME(Crypto_GetRandomBytes)(Dart_NativeArguments args) {
Dart_EnterScope();
Dart_Handle count_obj = Dart_GetNativeArgument(args, 0);
@@ -34,3 +37,6 @@
delete[] buffer;
Dart_ExitScope();
}
+
+} // namespace bin
+} // namespace dart
diff --git a/runtime/bin/crypto.h b/runtime/bin/crypto.h
index b155972..1feaf9c 100644
--- a/runtime/bin/crypto.h
+++ b/runtime/bin/crypto.h
@@ -9,6 +9,9 @@
#include "bin/utils.h"
+namespace dart {
+namespace bin {
+
class Crypto {
public:
static bool GetRandomBytes(intptr_t count, uint8_t* buffer);
@@ -18,5 +21,8 @@
DISALLOW_IMPLICIT_CONSTRUCTORS(Crypto);
};
+} // namespace bin
+} // namespace dart
+
#endif // BIN_CRYPTO_H_
diff --git a/runtime/bin/crypto_android.cc b/runtime/bin/crypto_android.cc
index 701a208..61b87a1 100644
--- a/runtime/bin/crypto_android.cc
+++ b/runtime/bin/crypto_android.cc
@@ -12,6 +12,9 @@
#include "bin/crypto.h"
+namespace dart {
+namespace bin {
+
bool Crypto::GetRandomBytes(intptr_t count, uint8_t* buffer) {
intptr_t fd = TEMP_FAILURE_RETRY(open("/dev/urandom", O_RDONLY));
if (fd < 0) return false;
@@ -20,4 +23,7 @@
return bytes_read == count;
}
+} // namespace bin
+} // namespace dart
+
#endif // defined(TARGET_OS_ANDROID)
diff --git a/runtime/bin/crypto_linux.cc b/runtime/bin/crypto_linux.cc
index 7ff6b6e..849fe71 100644
--- a/runtime/bin/crypto_linux.cc
+++ b/runtime/bin/crypto_linux.cc
@@ -12,6 +12,9 @@
#include "bin/crypto.h"
+namespace dart {
+namespace bin {
+
bool Crypto::GetRandomBytes(intptr_t count, uint8_t* buffer) {
intptr_t fd = TEMP_FAILURE_RETRY(open("/dev/urandom", O_RDONLY));
if (fd < 0) return false;
@@ -20,4 +23,7 @@
return bytes_read == count;
}
+} // namespace bin
+} // namespace dart
+
#endif // defined(TARGET_OS_LINUX)
diff --git a/runtime/bin/crypto_macos.cc b/runtime/bin/crypto_macos.cc
index 0a44ff8..19745fc 100644
--- a/runtime/bin/crypto_macos.cc
+++ b/runtime/bin/crypto_macos.cc
@@ -12,6 +12,9 @@
#include "bin/crypto.h"
+namespace dart {
+namespace bin {
+
bool Crypto::GetRandomBytes(intptr_t count, uint8_t* buffer) {
intptr_t fd = TEMP_FAILURE_RETRY(open("/dev/urandom", O_RDONLY));
if (fd < 0) return false;
@@ -20,4 +23,7 @@
return bytes_read == count;
}
+} // namespace bin
+} // namespace dart
+
#endif // defined(TARGET_OS_MACOS)
diff --git a/runtime/bin/crypto_win.cc b/runtime/bin/crypto_win.cc
index 8f4952f..01b82a9 100644
--- a/runtime/bin/crypto_win.cc
+++ b/runtime/bin/crypto_win.cc
@@ -10,6 +10,9 @@
#include "bin/crypto.h"
+namespace dart {
+namespace bin {
+
bool Crypto::GetRandomBytes(intptr_t count, uint8_t* buffer) {
uint32_t num;
intptr_t read = 0;
@@ -25,4 +28,7 @@
return true;
}
+} // namespace bin
+} // namespace dart
+
#endif // defined(TARGET_OS_WINDOWS)
diff --git a/runtime/bin/dartutils.cc b/runtime/bin/dartutils.cc
index 37cf816..3379b16 100644
--- a/runtime/bin/dartutils.cc
+++ b/runtime/bin/dartutils.cc
@@ -12,6 +12,9 @@
#include "platform/assert.h"
#include "platform/globals.h"
+namespace dart {
+namespace bin {
+
const char* DartUtils::original_working_directory = NULL;
const char* DartUtils::kDartScheme = "dart:";
const char* DartUtils::kDartExtensionScheme = "dart-ext:";
@@ -391,6 +394,9 @@
return Dart_LoadScriptFromSnapshot(text_buffer, len);
} else {
Dart_Handle source = Dart_NewStringFromUTF8(text_buffer, len);
+ if (Dart_IsError(source)) {
+ return source;
+ }
return Dart_LoadScript(resolved_script_uri, source, 0, 0);
}
}
@@ -746,3 +752,6 @@
result->SetAt(2, error_message);
return result;
}
+
+} // namespace bin
+} // namespace dart
diff --git a/runtime/bin/dartutils.h b/runtime/bin/dartutils.h
index 83457dc..074cc12 100644
--- a/runtime/bin/dartutils.h
+++ b/runtime/bin/dartutils.h
@@ -10,6 +10,9 @@
#include "include/dart_api.h"
#include "platform/globals.h"
+namespace dart {
+namespace bin {
+
// Forward declarations.
class File;
@@ -494,4 +497,7 @@
DISALLOW_COPY_AND_ASSIGN(CObjectExternalUint8Array);
};
+} // namespace bin
+} // namespace dart
+
#endif // BIN_DARTUTILS_H_
diff --git a/runtime/bin/dbg_connection.cc b/runtime/bin/dbg_connection.cc
index 583d737..dc6dc84 100644
--- a/runtime/bin/dbg_connection.cc
+++ b/runtime/bin/dbg_connection.cc
@@ -18,6 +18,9 @@
#include "include/dart_api.h"
+namespace dart {
+namespace bin {
+
int DebuggerConnectionHandler::listener_fd_ = -1;
dart::Monitor DebuggerConnectionHandler::handler_lock_;
@@ -180,7 +183,7 @@
void DebuggerConnectionHandler::HandleMessages() {
static JSONDebuggerCommand generic_debugger_commands[] = {
{ "interrupt", HandleInterruptCmd },
- { "isolates", HandleIsolatesListCmd },
+ { "getIsolateIds", HandleIsolatesListCmd },
{ NULL, NULL }
};
@@ -294,7 +297,11 @@
// listen, accept connections from debuggers, read and handle/dispatch
// debugger commands received on these connections.
ASSERT(listener_fd_ == -1);
- listener_fd_ = ServerSocket::CreateBindListen(address, port_number, 1);
+
+ OSError *os_error;
+ SocketAddresses* addresses = Socket::LookupAddress(address, -1, &os_error);
+ listener_fd_ = ServerSocket::CreateBindListen(
+ addresses->GetAt(0)->addr(), port_number, 1);
DebuggerConnectionImpl::StartHandler(port_number);
}
@@ -404,7 +411,11 @@
MessageParser msg_parser(in_msg->buffer(), in_msg->buffer_len());
int msg_id = msg_parser.MessageId();
ASSERT(msg_id >= 0);
- in_msg->SendErrorReply(msg_id, "isolate list command unimplemented");
+ dart::TextBuffer msg(64);
+ msg.Printf("{ \"id\": %d, \"result\": { \"isolateIds\": [", msg_id);
+ DbgMsgQueueList::ListIsolateIds(&msg);
+ msg.Printf("]}}");
+ in_msg->SendReply(&msg);
}
@@ -438,3 +449,6 @@
// Return true if a connection has been established.
return singleton_handler != NULL;
}
+
+} // namespace bin
+} // namespace dart
diff --git a/runtime/bin/dbg_connection.h b/runtime/bin/dbg_connection.h
index 791ab13..37080fb 100644
--- a/runtime/bin/dbg_connection.h
+++ b/runtime/bin/dbg_connection.h
@@ -27,6 +27,9 @@
#endif
+namespace dart {
+namespace bin {
+
// Forward declarations.
class DbgMessage;
class MessageBuffer;
@@ -105,4 +108,7 @@
DISALLOW_IMPLICIT_CONSTRUCTORS(DebuggerConnectionHandler);
};
+} // namespace bin
+} // namespace dart
+
#endif // BIN_DBG_CONNECTION_H_
diff --git a/runtime/bin/dbg_connection_android.cc b/runtime/bin/dbg_connection_android.cc
index 0fc57ac..92fb7ca5 100644
--- a/runtime/bin/dbg_connection_android.cc
+++ b/runtime/bin/dbg_connection_android.cc
@@ -15,6 +15,10 @@
#include "bin/log.h"
#include "bin/socket.h"
+
+namespace dart {
+namespace bin {
+
int DebuggerConnectionImpl::epoll_fd_ = -1;
int DebuggerConnectionImpl::wakeup_fds_[2] = {-1, -1};
@@ -119,4 +123,7 @@
return TEMP_FAILURE_RETRY(read(socket, buf, len));
}
+} // namespace bin
+} // namespace dart
+
#endif // defined(TARGET_OS_ANDROID)
diff --git a/runtime/bin/dbg_connection_android.h b/runtime/bin/dbg_connection_android.h
index f762c73..c1c16c5 100644
--- a/runtime/bin/dbg_connection_android.h
+++ b/runtime/bin/dbg_connection_android.h
@@ -10,6 +10,9 @@
#include <sys/socket.h>
+namespace dart {
+namespace bin {
+
class DebuggerConnectionImpl {
public:
static void StartHandler(int port_number);
@@ -28,4 +31,7 @@
static int epoll_fd_;
};
+} // namespace bin
+} // namespace dart
+
#endif // BIN_DBG_CONNECTION_ANDROID_H_
diff --git a/runtime/bin/dbg_connection_linux.cc b/runtime/bin/dbg_connection_linux.cc
index c278987f..020b8cb 100644
--- a/runtime/bin/dbg_connection_linux.cc
+++ b/runtime/bin/dbg_connection_linux.cc
@@ -15,6 +15,10 @@
#include "bin/log.h"
#include "bin/socket.h"
+
+namespace dart {
+namespace bin {
+
int DebuggerConnectionImpl::epoll_fd_ = -1;
int DebuggerConnectionImpl::wakeup_fds_[2] = {-1, -1};
@@ -119,4 +123,7 @@
return TEMP_FAILURE_RETRY(read(socket, buf, len));
}
+} // namespace bin
+} // namespace dart
+
#endif // defined(TARGET_OS_LINUX)
diff --git a/runtime/bin/dbg_connection_linux.h b/runtime/bin/dbg_connection_linux.h
index 12b0395..94a9664 100644
--- a/runtime/bin/dbg_connection_linux.h
+++ b/runtime/bin/dbg_connection_linux.h
@@ -10,6 +10,9 @@
#include <sys/socket.h>
+namespace dart {
+namespace bin {
+
class DebuggerConnectionImpl {
public:
static void StartHandler(int port_number);
@@ -28,4 +31,7 @@
static int epoll_fd_;
};
+} // namespace bin
+} // namespace dart
+
#endif // BIN_DBG_CONNECTION_LINUX_H_
diff --git a/runtime/bin/dbg_connection_macos.cc b/runtime/bin/dbg_connection_macos.cc
index a3e17fd..4fd2d1d 100644
--- a/runtime/bin/dbg_connection_macos.cc
+++ b/runtime/bin/dbg_connection_macos.cc
@@ -21,6 +21,9 @@
#include "platform/utils.h"
+namespace dart {
+namespace bin {
+
#define INVALID_FD -1
int DebuggerConnectionImpl::kqueue_fd_ = INVALID_FD;
@@ -173,4 +176,7 @@
return TEMP_FAILURE_RETRY(read(socket, buf, len));
}
+} // namespace bin
+} // namespace dart
+
#endif // defined(TARGET_OS_MACOS)
diff --git a/runtime/bin/dbg_connection_macos.h b/runtime/bin/dbg_connection_macos.h
index f6962ff..9665700 100644
--- a/runtime/bin/dbg_connection_macos.h
+++ b/runtime/bin/dbg_connection_macos.h
@@ -10,6 +10,9 @@
#include <sys/socket.h>
+namespace dart {
+namespace bin {
+
class DebuggerConnectionImpl {
public:
static void StartHandler(int port_number);
@@ -42,5 +45,7 @@
static int kqueue_fd_;
};
+} // namespace bin
+} // namespace dart
#endif // BIN_DBG_CONNECTION_MACOS_H_
diff --git a/runtime/bin/dbg_connection_win.cc b/runtime/bin/dbg_connection_win.cc
index a241c85..bd650a4 100644
--- a/runtime/bin/dbg_connection_win.cc
+++ b/runtime/bin/dbg_connection_win.cc
@@ -9,6 +9,10 @@
#include "bin/eventhandler.h"
+
+namespace dart {
+namespace bin {
+
void DebuggerConnectionImpl::ThreadEntry(uword args) {
ListenSocket* listen_socket =
reinterpret_cast<ListenSocket*>(DebuggerConnectionHandler::listener_fd_);
@@ -43,4 +47,7 @@
return recv(client_socket->socket(), buf, len, 0);
}
+} // namespace bin
+} // namespace dart
+
#endif // defined(TARGET_OS_WINDOWS)
diff --git a/runtime/bin/dbg_connection_win.h b/runtime/bin/dbg_connection_win.h
index 24ac711..2a9feb2 100644
--- a/runtime/bin/dbg_connection_win.h
+++ b/runtime/bin/dbg_connection_win.h
@@ -5,6 +5,9 @@
#ifndef BIN_DBG_CONNECTION_WIN_H_
#define BIN_DBG_CONNECTION_WIN_H_
+namespace dart {
+namespace bin {
+
class DebuggerConnectionImpl {
public:
static void StartHandler(int port_number);
@@ -15,4 +18,7 @@
static void ThreadEntry(uword args);
};
+} // namespace bin
+} // namespace dart
+
#endif // BIN_DBG_CONNECTION_WIN_H_
diff --git a/runtime/bin/dbg_message.cc b/runtime/bin/dbg_message.cc
index 4d9422d..5713657 100644
--- a/runtime/bin/dbg_message.cc
+++ b/runtime/bin/dbg_message.cc
@@ -15,6 +15,10 @@
#include "include/dart_api.h"
+
+namespace dart {
+namespace bin {
+
bool MessageParser::IsValidMessage() const {
if (buf_length_ == 0) {
return false;
@@ -805,7 +809,7 @@
msg.Printf("{ \"id\": %d, ", msg_id);
msg.Printf("\"result\": { \"lines\": [");
Dart_Handle elem;
- bool num_elems = 0;
+ intptr_t num_elems = 0;
for (intptr_t i = 0; i < info_len; i++) {
elem = Dart_ListGetAt(info, i);
if (Dart_IsNull(elem)) {
@@ -1160,6 +1164,21 @@
}
+void DbgMsgQueueList::ListIsolateIds(dart::TextBuffer* msg) {
+ MutexLocker ml(&msg_queue_list_lock_);
+ if (list_ == NULL) {
+ return; // No items in the list.
+ }
+ DbgMsgQueue* queue = list_;
+ msg->Printf("%"Pd64"", queue->isolate_id());
+ queue = queue->next();
+ while (queue != NULL) {
+ msg->Printf(",%"Pd64"", queue->isolate_id());
+ queue = queue->next();
+ }
+}
+
+
void DbgMsgQueueList::BptResolvedHandler(Dart_IsolateId isolate_id,
intptr_t bp_id,
const Dart_CodeLocation& location) {
@@ -1231,3 +1250,6 @@
}
Dart_ExitScope();
}
+
+} // namespace bin
+} // namespace dart
diff --git a/runtime/bin/dbg_message.h b/runtime/bin/dbg_message.h
index e30a421..85be1a5 100644
--- a/runtime/bin/dbg_message.h
+++ b/runtime/bin/dbg_message.h
@@ -15,6 +15,9 @@
#include "platform/thread.h"
+namespace dart {
+namespace bin {
+
// TODO(hausner): Need better error handling.
#define ASSERT_NOT_ERROR(handle) \
ASSERT(!Dart_IsError(handle))
@@ -245,6 +248,9 @@
static void IsolateEventHandler(Dart_IsolateId isolate_id,
Dart_IsolateEvent kind);
+ // Print list of isolate ids of all message queues into text buffer.
+ static void ListIsolateIds(dart::TextBuffer* msg);
+
private:
static DbgMsgQueue* GetIsolateMsgQueueLocked(Dart_IsolateId isolate_id);
@@ -255,4 +261,7 @@
DISALLOW_IMPLICIT_CONSTRUCTORS(DbgMsgQueueList);
};
+} // namespace bin
+} // namespace dart
+
#endif // BIN_DBG_MESSAGE_H_
diff --git a/runtime/bin/directory.cc b/runtime/bin/directory.cc
index c218595..758df5a 100644
--- a/runtime/bin/directory.cc
+++ b/runtime/bin/directory.cc
@@ -10,6 +10,9 @@
#include "platform/assert.h"
+namespace dart {
+namespace bin {
+
// Forward declaration.
static void DirectoryService(Dart_Port, Dart_Port, Dart_CObject*);
@@ -375,3 +378,6 @@
args));
return true;
}
+
+} // namespace bin
+} // namespace dart
diff --git a/runtime/bin/directory.h b/runtime/bin/directory.h
index 331b4c4..a8dde3d 100644
--- a/runtime/bin/directory.h
+++ b/runtime/bin/directory.h
@@ -11,6 +11,10 @@
#include "platform/globals.h"
#include "platform/thread.h"
+
+namespace dart {
+namespace bin {
+
class DirectoryListing {
public:
virtual ~DirectoryListing() {}
@@ -114,5 +118,7 @@
DISALLOW_IMPLICIT_CONSTRUCTORS(Directory);
};
+} // namespace bin
+} // namespace dart
#endif // BIN_DIRECTORY_H_
diff --git a/runtime/bin/directory_android.cc b/runtime/bin/directory_android.cc
index 58060d8..7c30274 100644
--- a/runtime/bin/directory_android.cc
+++ b/runtime/bin/directory_android.cc
@@ -17,6 +17,10 @@
#include "bin/file.h"
#include "bin/platform.h"
+
+namespace dart {
+namespace bin {
+
class PathBuffer {
public:
PathBuffer() : length(0) {
@@ -515,4 +519,7 @@
return (TEMP_FAILURE_RETRY(rename(path, new_path)) == 0);
}
+} // namespace bin
+} // namespace dart
+
#endif // defined(TARGET_OS_ANDROID)
diff --git a/runtime/bin/directory_linux.cc b/runtime/bin/directory_linux.cc
index 2f86f5b..67ac947 100644
--- a/runtime/bin/directory_linux.cc
+++ b/runtime/bin/directory_linux.cc
@@ -17,6 +17,10 @@
#include "bin/file.h"
#include "bin/platform.h"
+
+namespace dart {
+namespace bin {
+
class PathBuffer {
public:
PathBuffer() : length(0) {
@@ -482,4 +486,7 @@
return (TEMP_FAILURE_RETRY(rename(path, new_path)) == 0);
}
+} // namespace bin
+} // namespace dart
+
#endif // defined(TARGET_OS_LINUX)
diff --git a/runtime/bin/directory_macos.cc b/runtime/bin/directory_macos.cc
index ece3685..5c7b115 100644
--- a/runtime/bin/directory_macos.cc
+++ b/runtime/bin/directory_macos.cc
@@ -17,6 +17,10 @@
#include "bin/file.h"
#include "bin/platform.h"
+
+namespace dart {
+namespace bin {
+
class PathBuffer {
public:
PathBuffer() : length(0) {
@@ -482,4 +486,7 @@
return (TEMP_FAILURE_RETRY(rename(path, new_path)) == 0);
}
+} // namespace bin
+} // namespace dart
+
#endif // defined(TARGET_OS_MACOS)
diff --git a/runtime/bin/directory_win.cc b/runtime/bin/directory_win.cc
index 79c7b08..dc6cd69 100644
--- a/runtime/bin/directory_win.cc
+++ b/runtime/bin/directory_win.cc
@@ -13,6 +13,11 @@
#include "bin/log.h"
+#undef DeleteFile
+
+namespace dart {
+namespace bin {
+
class PathBuffer {
public:
PathBuffer() : length(0) {
@@ -524,4 +529,7 @@
return (move_status != 0);
}
+} // namespace bin
+} // namespace dart
+
#endif // defined(TARGET_OS_WINDOWS)
diff --git a/runtime/bin/eventhandler.cc b/runtime/bin/eventhandler.cc
index c1e88e7..94f0778 100644
--- a/runtime/bin/eventhandler.cc
+++ b/runtime/bin/eventhandler.cc
@@ -9,6 +9,9 @@
#include "include/dart_api.h"
+namespace dart {
+namespace bin {
+
static const int kNativeEventHandlerFieldIndex = 0;
static const intptr_t kTimerId = -1;
static const intptr_t kInvalidId = -2;
@@ -76,3 +79,6 @@
event_handler->SendData(id, dart_port, data);
Dart_ExitScope();
}
+
+} // namespace bin
+} // namespace dart
diff --git a/runtime/bin/eventhandler.h b/runtime/bin/eventhandler.h
index c487c52..5d7832e 100644
--- a/runtime/bin/eventhandler.h
+++ b/runtime/bin/eventhandler.h
@@ -8,6 +8,9 @@
#include "bin/builtin.h"
#include "bin/isolate_data.h"
+namespace dart {
+namespace bin {
+
// Flags used to provide information and actions to the eventhandler
// when sending a message about a file descriptor. These flags should
// be kept in sync with the constants in socket_impl.dart. For more
@@ -24,6 +27,8 @@
kPipe = 17,
};
+} // namespace bin
+} // namespace dart
// The event handler delegation class is OS specific.
#if defined(TARGET_OS_ANDROID)
@@ -38,6 +43,9 @@
#error Unknown target os.
#endif
+namespace dart {
+namespace bin {
+
class EventHandler {
public:
void SendData(intptr_t id, Dart_Port dart_port, int64_t data) {
@@ -62,5 +70,7 @@
EventHandlerImplementation delegate_;
};
+} // namespace bin
+} // namespace dart
#endif // BIN_EVENTHANDLER_H_
diff --git a/runtime/bin/eventhandler_android.cc b/runtime/bin/eventhandler_android.cc
index 2a708fd..9f7a8ee 100644
--- a/runtime/bin/eventhandler_android.cc
+++ b/runtime/bin/eventhandler_android.cc
@@ -24,6 +24,9 @@
#include "platform/utils.h"
+namespace dart {
+namespace bin {
+
static const int kInterruptMessageSize = sizeof(InterruptMessage);
static const int kInfinityTimeout = -1;
static const int kTimerId = -1;
@@ -425,4 +428,7 @@
return dart::Utils::WordHash(fd + 1);
}
+} // namespace bin
+} // namespace dart
+
#endif // defined(TARGET_OS_ANDROID)
diff --git a/runtime/bin/eventhandler_android.h b/runtime/bin/eventhandler_android.h
index dfe2ff2..5196023 100644
--- a/runtime/bin/eventhandler_android.h
+++ b/runtime/bin/eventhandler_android.h
@@ -15,6 +15,10 @@
#include "platform/hashmap.h"
+
+namespace dart {
+namespace bin {
+
class InterruptMessage {
public:
intptr_t id;
@@ -118,5 +122,7 @@
int epoll_fd_;
};
+} // namespace bin
+} // namespace dart
#endif // BIN_EVENTHANDLER_ANDROID_H_
diff --git a/runtime/bin/eventhandler_linux.cc b/runtime/bin/eventhandler_linux.cc
index 8cda7927..e2e2746 100644
--- a/runtime/bin/eventhandler_linux.cc
+++ b/runtime/bin/eventhandler_linux.cc
@@ -24,6 +24,9 @@
#include "platform/utils.h"
+namespace dart {
+namespace bin {
+
static const int kInterruptMessageSize = sizeof(InterruptMessage);
static const int kInfinityTimeout = -1;
static const int kTimerId = -1;
@@ -431,4 +434,7 @@
return dart::Utils::WordHash(fd + 1);
}
+} // namespace bin
+} // namespace dart
+
#endif // defined(TARGET_OS_LINUX)
diff --git a/runtime/bin/eventhandler_linux.h b/runtime/bin/eventhandler_linux.h
index e44e283..4c423f2 100644
--- a/runtime/bin/eventhandler_linux.h
+++ b/runtime/bin/eventhandler_linux.h
@@ -10,10 +10,15 @@
#endif
#include <unistd.h>
+#include <sys/epoll.h>
#include <sys/socket.h>
#include "platform/hashmap.h"
+
+namespace dart {
+namespace bin {
+
class InterruptMessage {
public:
intptr_t id;
@@ -117,5 +122,7 @@
int epoll_fd_;
};
+} // namespace bin
+} // namespace dart
#endif // BIN_EVENTHANDLER_LINUX_H_
diff --git a/runtime/bin/eventhandler_macos.cc b/runtime/bin/eventhandler_macos.cc
index 5972cfb..6823ef8 100644
--- a/runtime/bin/eventhandler_macos.cc
+++ b/runtime/bin/eventhandler_macos.cc
@@ -23,6 +23,9 @@
#include "platform/utils.h"
+namespace dart {
+namespace bin {
+
static const int kInterruptMessageSize = sizeof(InterruptMessage);
static const int kInfinityTimeout = -1;
static const int kTimerId = -1;
@@ -435,4 +438,7 @@
return dart::Utils::WordHash(fd + 1);
}
+} // namespace bin
+} // namespace dart
+
#endif // defined(TARGET_OS_MACOS)
diff --git a/runtime/bin/eventhandler_macos.h b/runtime/bin/eventhandler_macos.h
index cbc6040..4303586 100644
--- a/runtime/bin/eventhandler_macos.h
+++ b/runtime/bin/eventhandler_macos.h
@@ -10,10 +10,15 @@
#endif
#include <unistd.h>
+#include <sys/event.h> // NOLINT
#include <sys/socket.h>
#include "platform/hashmap.h"
+
+namespace dart {
+namespace bin {
+
class InterruptMessage {
public:
intptr_t id;
@@ -130,5 +135,7 @@
int kqueue_fd_;
};
+} // namespace bin
+} // namespace dart
#endif // BIN_EVENTHANDLER_MACOS_H_
diff --git a/runtime/bin/eventhandler_win.cc b/runtime/bin/eventhandler_win.cc
index 3ed6e3f..6a43dd5 100644
--- a/runtime/bin/eventhandler_win.cc
+++ b/runtime/bin/eventhandler_win.cc
@@ -20,6 +20,9 @@
#include "platform/thread.h"
+namespace dart {
+namespace bin {
+
static const int kBufferSize = 32 * 1024;
static const int kInfinityTimeout = -1;
@@ -991,4 +994,7 @@
SendData(kShutdownId, 0, 0);
}
+} // namespace bin
+} // namespace dart
+
#endif // defined(TARGET_OS_WINDOWS)
diff --git a/runtime/bin/eventhandler_win.h b/runtime/bin/eventhandler_win.h
index 09044e0..30d229b 100644
--- a/runtime/bin/eventhandler_win.h
+++ b/runtime/bin/eventhandler_win.h
@@ -15,6 +15,9 @@
#include "bin/builtin.h"
+namespace dart {
+namespace bin {
+
// Forward declarations.
class EventHandlerImplementation;
class Handle;
@@ -392,5 +395,7 @@
HANDLE completion_port_;
};
+} // namespace bin
+} // namespace dart
#endif // BIN_EVENTHANDLER_WIN_H_
diff --git a/runtime/bin/extensions.cc b/runtime/bin/extensions.cc
index d8b13f9..71eaeac 100644
--- a/runtime/bin/extensions.cc
+++ b/runtime/bin/extensions.cc
@@ -12,6 +12,10 @@
#include "bin/dartutils.h"
#include "bin/file.h"
+
+namespace dart {
+namespace bin {
+
Dart_Handle Extensions::LoadExtension(const char* extension_url,
Dart_Handle parent_library) {
char* library_path = strdup(extension_url);
@@ -62,3 +66,6 @@
ASSERT(result[size - 1] == '\0');
return result;
}
+
+} // namespace bin
+} // namespace dart
diff --git a/runtime/bin/extensions.h b/runtime/bin/extensions.h
index a233a25..6f3853c 100644
--- a/runtime/bin/extensions.h
+++ b/runtime/bin/extensions.h
@@ -8,6 +8,10 @@
#include "include/dart_api.h"
#include "platform/globals.h"
+
+namespace dart {
+namespace bin {
+
class Extensions {
public:
// TODO(whesse): Make extension load from a relative path relative to
@@ -28,4 +32,7 @@
DISALLOW_IMPLICIT_CONSTRUCTORS(Extensions);
};
+} // namespace bin
+} // namespace dart
+
#endif // BIN_EXTENSIONS_H_
diff --git a/runtime/bin/extensions_android.cc b/runtime/bin/extensions_android.cc
index b136736..72c757f 100644
--- a/runtime/bin/extensions_android.cc
+++ b/runtime/bin/extensions_android.cc
@@ -8,6 +8,10 @@
#include "bin/extensions.h"
#include <dlfcn.h> // NOLINT
+
+namespace dart {
+namespace bin {
+
void* Extensions::LoadExtensionLibrary(const char* library_path,
const char* extension_name) {
const char* strings[] = { library_path, "/lib",
@@ -25,4 +29,7 @@
return result;
}
+} // namespace bin
+} // namespace dart
+
#endif // defined(TARGET_OS_ANDROID)
diff --git a/runtime/bin/extensions_linux.cc b/runtime/bin/extensions_linux.cc
index 8321efe..3920ade 100644
--- a/runtime/bin/extensions_linux.cc
+++ b/runtime/bin/extensions_linux.cc
@@ -8,6 +8,10 @@
#include "bin/extensions.h"
#include <dlfcn.h> // NOLINT
+
+namespace dart {
+namespace bin {
+
void* Extensions::LoadExtensionLibrary(const char* library_path,
const char* extension_name) {
const char* strings[] = { library_path, "/lib",
@@ -25,4 +29,7 @@
return result;
}
+} // namespace bin
+} // namespace dart
+
#endif // defined(TARGET_OS_LINUX)
diff --git a/runtime/bin/extensions_macos.cc b/runtime/bin/extensions_macos.cc
index 6d7842a..bfda5e7 100644
--- a/runtime/bin/extensions_macos.cc
+++ b/runtime/bin/extensions_macos.cc
@@ -8,6 +8,10 @@
#include "bin/extensions.h"
#include <dlfcn.h> // NOLINT
+
+namespace dart {
+namespace bin {
+
void* Extensions::LoadExtensionLibrary(const char* library_path,
const char* extension_name) {
const char* strings[] = { library_path, "/lib",
@@ -25,4 +29,7 @@
return result;
}
+} // namespace bin
+} // namespace dart
+
#endif // defined(TARGET_OS_MACOS)
diff --git a/runtime/bin/extensions_win.cc b/runtime/bin/extensions_win.cc
index 9e8a653..0f764d3 100644
--- a/runtime/bin/extensions_win.cc
+++ b/runtime/bin/extensions_win.cc
@@ -8,6 +8,10 @@
#include "bin/extensions.h"
#include "bin/utils.h"
+
+namespace dart {
+namespace bin {
+
void* Extensions::LoadExtensionLibrary(const char* library_path,
const char* extension_name) {
const char* strings[] = { library_path, "/", extension_name, ".dll", NULL };
@@ -23,4 +27,7 @@
return GetProcAddress(reinterpret_cast<HMODULE>(lib_handle), symbol);
}
+} // namespace bin
+} // namespace dart
+
#endif // defined(TARGET_OS_WINDOWS)
diff --git a/runtime/bin/fdutils.h b/runtime/bin/fdutils.h
index 6771f21..da4fcf5 100644
--- a/runtime/bin/fdutils.h
+++ b/runtime/bin/fdutils.h
@@ -8,6 +8,10 @@
#include "bin/builtin.h"
#include "platform/globals.h"
+
+namespace dart {
+namespace bin {
+
class FDUtils {
public:
static bool SetCloseOnExec(intptr_t fd);
@@ -41,4 +45,7 @@
DISALLOW_IMPLICIT_CONSTRUCTORS(FDUtils);
};
+} // namespace bin
+} // namespace dart
+
#endif // BIN_FDUTILS_H_
diff --git a/runtime/bin/fdutils_android.cc b/runtime/bin/fdutils_android.cc
index 18b4ec3..7a60387 100644
--- a/runtime/bin/fdutils_android.cc
+++ b/runtime/bin/fdutils_android.cc
@@ -13,6 +13,9 @@
#include "bin/fdutils.h"
+namespace dart {
+namespace bin {
+
bool FDUtils::SetCloseOnExec(intptr_t fd) {
intptr_t status;
status = TEMP_FAILURE_RETRY(fcntl(fd, F_GETFD));
@@ -136,4 +139,7 @@
return count;
}
+} // namespace bin
+} // namespace dart
+
#endif // defined(TARGET_OS_ANDROID)
diff --git a/runtime/bin/fdutils_linux.cc b/runtime/bin/fdutils_linux.cc
index 84c2194..a763c9b 100644
--- a/runtime/bin/fdutils_linux.cc
+++ b/runtime/bin/fdutils_linux.cc
@@ -13,6 +13,9 @@
#include "bin/fdutils.h"
+namespace dart {
+namespace bin {
+
bool FDUtils::SetCloseOnExec(intptr_t fd) {
intptr_t status;
status = TEMP_FAILURE_RETRY(fcntl(fd, F_GETFD));
@@ -136,4 +139,7 @@
return count;
}
+} // namespace bin
+} // namespace dart
+
#endif // defined(TARGET_OS_LINUX)
diff --git a/runtime/bin/fdutils_macos.cc b/runtime/bin/fdutils_macos.cc
index 7087add..65f2832 100644
--- a/runtime/bin/fdutils_macos.cc
+++ b/runtime/bin/fdutils_macos.cc
@@ -13,6 +13,9 @@
#include "bin/fdutils.h"
+namespace dart {
+namespace bin {
+
bool FDUtils::SetCloseOnExec(intptr_t fd) {
intptr_t status;
status = TEMP_FAILURE_RETRY(fcntl(fd, F_GETFD));
@@ -137,4 +140,7 @@
return count;
}
+} // namespace bin
+} // namespace dart
+
#endif // defined(TARGET_OS_MACOS)
diff --git a/runtime/bin/file.cc b/runtime/bin/file.cc
index c9fc1b2..de9d1e9 100644
--- a/runtime/bin/file.cc
+++ b/runtime/bin/file.cc
@@ -12,8 +12,10 @@
#include "include/dart_api.h"
-static const int kMSPerSecond = 1000;
+namespace dart {
+namespace bin {
+static const int kMSPerSecond = 1000;
// Forward declaration.
static void FileService(Dart_Port, Dart_Port, Dart_CObject*);
@@ -1169,3 +1171,6 @@
}
Dart_ExitScope();
}
+
+} // namespace bin
+} // namespace dart
diff --git a/runtime/bin/file.h b/runtime/bin/file.h
index 944fd6a..9e12463 100644
--- a/runtime/bin/file.h
+++ b/runtime/bin/file.h
@@ -16,6 +16,10 @@
#include "platform/globals.h"
#include "platform/thread.h"
+
+namespace dart {
+namespace bin {
+
// Forward declaration.
class FileHandle;
@@ -164,4 +168,7 @@
DISALLOW_COPY_AND_ASSIGN(File);
};
+} // namespace bin
+} // namespace dart
+
#endif // BIN_FILE_H_
diff --git a/runtime/bin/file_android.cc b/runtime/bin/file_android.cc
index 2d7c99d..9bb5e1a 100644
--- a/runtime/bin/file_android.cc
+++ b/runtime/bin/file_android.cc
@@ -16,6 +16,10 @@
#include "bin/builtin.h"
#include "bin/log.h"
+
+namespace dart {
+namespace bin {
+
class FileHandle {
public:
explicit FileHandle(int fd) : fd_(fd) { }
@@ -315,4 +319,7 @@
File::kDifferent;
}
+} // namespace bin
+} // namespace dart
+
#endif // defined(TARGET_OS_ANDROID)
diff --git a/runtime/bin/file_linux.cc b/runtime/bin/file_linux.cc
index 8126ff9..26c047d 100644
--- a/runtime/bin/file_linux.cc
+++ b/runtime/bin/file_linux.cc
@@ -16,6 +16,10 @@
#include "bin/builtin.h"
#include "bin/log.h"
+
+namespace dart {
+namespace bin {
+
class FileHandle {
public:
explicit FileHandle(int fd) : fd_(fd) { }
@@ -316,4 +320,7 @@
File::kDifferent;
}
+} // namespace bin
+} // namespace dart
+
#endif // defined(TARGET_OS_LINUX)
diff --git a/runtime/bin/file_macos.cc b/runtime/bin/file_macos.cc
index a5af904..0b99153 100644
--- a/runtime/bin/file_macos.cc
+++ b/runtime/bin/file_macos.cc
@@ -18,6 +18,10 @@
#include "bin/fdutils.h"
#include "bin/log.h"
+
+namespace dart {
+namespace bin {
+
class FileHandle {
public:
explicit FileHandle(int fd) : fd_(fd) { }
@@ -324,4 +328,7 @@
File::kDifferent;
}
+} // namespace bin
+} // namespace dart
+
#endif // defined(TARGET_OS_MACOS)
diff --git a/runtime/bin/file_test.cc b/runtime/bin/file_test.cc
index 5765cf2..20c6bf7 100644
--- a/runtime/bin/file_test.cc
+++ b/runtime/bin/file_test.cc
@@ -8,6 +8,9 @@
#include "vm/unit_test.h"
+namespace dart {
+namespace bin {
+
// Helper method to be able to run the test from the runtime
// directory, or the top directory.
static const char* GetFileName(const char* name) {
@@ -56,3 +59,6 @@
EXPECT_EQ(18, file->Position());
delete file;
}
+
+} // namespace bin
+} // namespace dart
diff --git a/runtime/bin/file_win.cc b/runtime/bin/file_win.cc
index 78074cc..6877fb3 100644
--- a/runtime/bin/file_win.cc
+++ b/runtime/bin/file_win.cc
@@ -17,6 +17,10 @@
#include "bin/builtin.h"
#include "bin/log.h"
+
+namespace dart {
+namespace bin {
+
class FileHandle {
public:
explicit FileHandle(int fd) : fd_(fd) { }
@@ -551,4 +555,7 @@
}
}
+} // namespace bin
+} // namespace dart
+
#endif // defined(TARGET_OS_WINDOWS)
diff --git a/runtime/bin/filter.cc b/runtime/bin/filter.cc
index 1a609c5..a423651 100644
--- a/runtime/bin/filter.cc
+++ b/runtime/bin/filter.cc
@@ -8,6 +8,10 @@
#include "include/dart_api.h"
+
+namespace dart {
+namespace bin {
+
const int kZlibFlagMemUsage = 8;
const int kZLibFlagWindowBits = 15;
const int kZLibFlagUseGZipHeader = 16;
@@ -304,3 +308,5 @@
}
}
+} // namespace bin
+} // namespace dart
diff --git a/runtime/bin/filter.h b/runtime/bin/filter.h
index cc3a0a9..fcfaa0e 100644
--- a/runtime/bin/filter.h
+++ b/runtime/bin/filter.h
@@ -10,6 +10,10 @@
#include "../third_party/zlib/zlib.h"
+
+namespace dart {
+namespace bin {
+
class Filter {
public:
virtual ~Filter() {}
@@ -80,5 +84,7 @@
DISALLOW_COPY_AND_ASSIGN(ZLibInflateFilter);
};
-#endif // BIN_FILTER_H_
+} // namespace bin
+} // namespace dart
+#endif // BIN_FILTER_H_
diff --git a/runtime/bin/gen_snapshot.cc b/runtime/bin/gen_snapshot.cc
index ea69119..d5e0a5e 100644
--- a/runtime/bin/gen_snapshot.cc
+++ b/runtime/bin/gen_snapshot.cc
@@ -18,6 +18,10 @@
#include "platform/globals.h"
+
+namespace dart {
+namespace bin {
+
#define CHECK_RESULT(result) \
if (Dart_IsError(result)) { \
free(snapshot_buffer); \
@@ -296,6 +300,11 @@
return ResolveUri(library_url_string, url_string);
}
+ if (DartUtils::IsDartIOLibURL(url_string) && mapped_url_string == NULL) {
+ // No url mapping for dart:io. Load original version.
+ return Builtin::LoadAndCheckLibrary(Builtin::kIOLibrary);
+ }
+
Dart_Handle resolved_url = url;
if (mapped_url_string != NULL) {
// Mapped urls are relative to working directory.
@@ -428,13 +437,8 @@
static void SetupForGenericSnapshotCreation() {
SetupForUriResolution();
- // TODO(regis): Reenable this code for mips when possible.
-#if defined(TARGET_ARCH_IA32) || \
- defined(TARGET_ARCH_X64) || \
- defined(TARGET_ARCH_ARM)
Dart_Handle library = LoadGenericSnapshotCreationScript(Builtin::kIOLibrary);
VerifyLoaded(library);
-#endif
}
@@ -528,3 +532,10 @@
}
return 0;
}
+
+} // namespace bin
+} // namespace dart
+
+int main(int argc, char** argv) {
+ return dart::bin::main(argc, argv);
+}
diff --git a/runtime/bin/io.dart b/runtime/bin/io.dart
index 4b2e666..2bec045 100644
--- a/runtime/bin/io.dart
+++ b/runtime/bin/io.dart
@@ -14,6 +14,6 @@
import 'dart:json' as JSON;
import "dart:math";
import "dart:nativewrappers";
-import "dart:typeddata";
+import "dart:typed_data";
import "dart:uri";
import "dart:utf";
diff --git a/runtime/bin/io_buffer.cc b/runtime/bin/io_buffer.cc
index b1bc958..65fe234 100644
--- a/runtime/bin/io_buffer.cc
+++ b/runtime/bin/io_buffer.cc
@@ -4,6 +4,10 @@
#include "bin/io_buffer.h"
+
+namespace dart {
+namespace bin {
+
Dart_Handle IOBuffer::Allocate(intptr_t size, uint8_t **buffer) {
uint8_t* data = Allocate(size);
Dart_Handle result = Dart_NewExternalTypedData(kUint8,
@@ -22,3 +26,6 @@
uint8_t* IOBuffer::Allocate(intptr_t size) {
return new uint8_t[size];
}
+
+} // namespace bin
+} // namespace dart
diff --git a/runtime/bin/io_buffer.h b/runtime/bin/io_buffer.h
index 0c73164..06ce0a6 100644
--- a/runtime/bin/io_buffer.h
+++ b/runtime/bin/io_buffer.h
@@ -9,6 +9,10 @@
#include "include/dart_api.h"
+
+namespace dart {
+namespace bin {
+
class IOBuffer {
public:
// Allocate an IO buffer dart object (of type Uint8List) backed by
@@ -37,4 +41,7 @@
DISALLOW_IMPLICIT_CONSTRUCTORS(IOBuffer);
};
+} // namespace bin
+} // namespace dart
+
#endif // BIN_IO_BUFFER_H_
diff --git a/runtime/bin/io_natives.cc b/runtime/bin/io_natives.cc
index a5c6a9f..0b4cedd 100644
--- a/runtime/bin/io_natives.cc
+++ b/runtime/bin/io_natives.cc
@@ -13,6 +13,9 @@
#include "platform/assert.h"
+namespace dart {
+namespace bin {
+
// Lists the native functions implementing advanced dart:io classes.
// Some classes, like File and Directory, list their implementations in
// builtin_natives.cc instead.
@@ -91,3 +94,6 @@
}
return NULL;
}
+
+} // namespace bin
+} // namespace dart
diff --git a/runtime/bin/io_natives.h b/runtime/bin/io_natives.h
index 1745555..dac7fce 100644
--- a/runtime/bin/io_natives.h
+++ b/runtime/bin/io_natives.h
@@ -7,7 +7,14 @@
#include "include/dart_api.h"
+
+namespace dart {
+namespace bin {
+
Dart_NativeFunction IONativeLookup(Dart_Handle name,
int argument_count);
+} // namespace bin
+} // namespace dart
+
#endif // BIN_IO_NATIVES_H_
diff --git a/runtime/bin/isolate_data.h b/runtime/bin/isolate_data.h
index 7824285..9b0806e 100644
--- a/runtime/bin/isolate_data.h
+++ b/runtime/bin/isolate_data.h
@@ -8,6 +8,10 @@
#include "include/dart_api.h"
#include "platform/globals.h"
+
+namespace dart {
+namespace bin {
+
// Forward declaration.
class EventHandler;
@@ -30,4 +34,7 @@
DISALLOW_COPY_AND_ASSIGN(IsolateData);
};
+} // namespace bin
+} // namespace dart
+
#endif // BIN_ISOLATE_DATA_H_
diff --git a/runtime/bin/log.h b/runtime/bin/log.h
index c495840..10629d5 100644
--- a/runtime/bin/log.h
+++ b/runtime/bin/log.h
@@ -9,6 +9,10 @@
#include "platform/globals.h"
+
+namespace dart {
+namespace bin {
+
class Log {
public:
// Print formatted output for debugging.
@@ -34,4 +38,7 @@
DISALLOW_IMPLICIT_CONSTRUCTORS(Log);
};
+} // namespace bin
+} // namespace dart
+
#endif // BIN_LOG_H_
diff --git a/runtime/bin/log_android.cc b/runtime/bin/log_android.cc
index 5f878f2..e8d8e68 100644
--- a/runtime/bin/log_android.cc
+++ b/runtime/bin/log_android.cc
@@ -10,6 +10,10 @@
#include <stdio.h> // NOLINT
#include <android/log.h> // NOLINT
+
+namespace dart {
+namespace bin {
+
// TODO(gram): We should be buffering the data and only outputting
// it when we see a '\n'.
@@ -21,4 +25,7 @@
__android_log_vprint(ANDROID_LOG_ERROR, "Dart", format, args);
}
+} // namespace bin
+} // namespace dart
+
#endif // defined(TARGET_OS_ANDROID)
diff --git a/runtime/bin/log_linux.cc b/runtime/bin/log_linux.cc
index 0b825af..f398c9e 100644
--- a/runtime/bin/log_linux.cc
+++ b/runtime/bin/log_linux.cc
@@ -9,6 +9,10 @@
#include <stdio.h> // NOLINT
+
+namespace dart {
+namespace bin {
+
void Log::VPrint(const char* format, va_list args) {
vfprintf(stdout, format, args);
fflush(stdout);
@@ -19,4 +23,7 @@
fflush(stdout);
}
+} // namespace bin
+} // namespace dart
+
#endif // defined(TARGET_OS_LINUX)
diff --git a/runtime/bin/log_macos.cc b/runtime/bin/log_macos.cc
index 87c9075..3711245 100644
--- a/runtime/bin/log_macos.cc
+++ b/runtime/bin/log_macos.cc
@@ -9,6 +9,10 @@
#include <stdio.h> // NOLINT
+
+namespace dart {
+namespace bin {
+
void Log::VPrint(const char* format, va_list args) {
vfprintf(stdout, format, args);
fflush(stdout);
@@ -19,4 +23,7 @@
fflush(stderr);
}
+} // namespace bin
+} // namespace dart
+
#endif // defined(TARGET_OS_MACOS)
diff --git a/runtime/bin/log_win.cc b/runtime/bin/log_win.cc
index 30c265d..9fb69cf 100644
--- a/runtime/bin/log_win.cc
+++ b/runtime/bin/log_win.cc
@@ -9,6 +9,10 @@
#include <stdio.h> // NOLINT
+
+namespace dart {
+namespace bin {
+
void Log::VPrint(const char* format, va_list args) {
vfprintf(stdout, format, args);
fflush(stdout);
@@ -19,4 +23,7 @@
fflush(stderr);
}
+} // namespace bin
+} // namespace dart
+
#endif // defined(TARGET_OS_WINDOWS)
diff --git a/runtime/bin/main.cc b/runtime/bin/main.cc
index 41f2ba9..96ec295 100644
--- a/runtime/bin/main.cc
+++ b/runtime/bin/main.cc
@@ -23,11 +23,13 @@
#include "bin/vmstats_impl.h"
#include "platform/globals.h"
+namespace dart {
+namespace bin {
+
// snapshot_buffer points to a snapshot if we link in a snapshot otherwise
// it is initialized to NULL.
extern const uint8_t* snapshot_buffer;
-
// Global state that stores a pointer to the application script snapshot.
static bool generate_script_snapshot = false;
static File* snapshot_file = NULL;
@@ -862,3 +864,10 @@
return Process::GlobalExitCode();
}
+
+} // namespace bin
+} // namespace dart
+
+int main(int argc, char** argv) {
+ return dart::bin::main(argc, argv);
+}
diff --git a/runtime/bin/native_service.cc b/runtime/bin/native_service.cc
index 9d4c3e8..37506aa 100644
--- a/runtime/bin/native_service.cc
+++ b/runtime/bin/native_service.cc
@@ -8,6 +8,9 @@
#include "bin/thread.h"
+namespace dart {
+namespace bin {
+
NativeService::NativeService(const char* name,
Dart_NativeMessageHandler handler,
int number_of_ports)
@@ -38,3 +41,6 @@
service_ports_index_ = (service_ports_index_ + 1) % service_ports_size_;
return result;
}
+
+} // namespace bin
+} // namespace dart
diff --git a/runtime/bin/native_service.h b/runtime/bin/native_service.h
index 8bb4330..ff1b0bf 100644
--- a/runtime/bin/native_service.h
+++ b/runtime/bin/native_service.h
@@ -9,6 +9,10 @@
#include "platform/globals.h"
#include "platform/thread.h"
+
+namespace dart {
+namespace bin {
+
// Utility class to set up a native service and allocate Dart native
// ports to interact with it from Dart code. The number of native ports
// allocated for each service is limited.
@@ -42,4 +46,7 @@
DISALLOW_IMPLICIT_CONSTRUCTORS(NativeService);
};
+} // namespace bin
+} // namespace dart
+
#endif // BIN_NATIVE_SERVICE_H_
diff --git a/runtime/bin/platform.cc b/runtime/bin/platform.cc
index 7e76c09..c47194e 100644
--- a/runtime/bin/platform.cc
+++ b/runtime/bin/platform.cc
@@ -6,6 +6,8 @@
#include "bin/platform.h"
#include "include/dart_api.h"
+namespace dart {
+namespace bin {
void FUNCTION_NAME(Platform_NumberOfProcessors)(Dart_NativeArguments args) {
Dart_EnterScope();
@@ -73,3 +75,6 @@
}
Dart_ExitScope();
}
+
+} // namespace bin
+} // namespace dart
diff --git a/runtime/bin/platform.h b/runtime/bin/platform.h
index 9ee2172..54412ba 100644
--- a/runtime/bin/platform.h
+++ b/runtime/bin/platform.h
@@ -7,6 +7,10 @@
#include "bin/builtin.h"
+
+namespace dart {
+namespace bin {
+
class Platform {
public:
// Perform platform specific initialization.
@@ -35,4 +39,7 @@
DISALLOW_IMPLICIT_CONSTRUCTORS(Platform);
};
+} // namespace bin
+} // namespace dart
+
#endif // BIN_PLATFORM_H_
diff --git a/runtime/bin/platform_android.cc b/runtime/bin/platform_android.cc
index 435f16b..e069d5a 100644
--- a/runtime/bin/platform_android.cc
+++ b/runtime/bin/platform_android.cc
@@ -12,6 +12,9 @@
#include <unistd.h> // NOLINT
+namespace dart {
+namespace bin {
+
bool Platform::Initialize() {
// Turn off the signal handler for SIGPIPE as it causes the process
// to terminate on writing to a closed pipe. Without the signal
@@ -69,4 +72,7 @@
delete[] env;
}
+} // namespace bin
+} // namespace dart
+
#endif // defined(TARGET_OS_ANDROID)
diff --git a/runtime/bin/platform_linux.cc b/runtime/bin/platform_linux.cc
index 48f6154..4a70ee5 100644
--- a/runtime/bin/platform_linux.cc
+++ b/runtime/bin/platform_linux.cc
@@ -12,6 +12,9 @@
#include <unistd.h> // NOLINT
+namespace dart {
+namespace bin {
+
bool Platform::Initialize() {
// Turn off the signal handler for SIGPIPE as it causes the process
// to terminate on writing to a closed pipe. Without the signal
@@ -69,4 +72,7 @@
delete[] env;
}
+} // namespace bin
+} // namespace dart
+
#endif // defined(TARGET_OS_LINUX)
diff --git a/runtime/bin/platform_macos.cc b/runtime/bin/platform_macos.cc
index d538eb7..e1b914b 100644
--- a/runtime/bin/platform_macos.cc
+++ b/runtime/bin/platform_macos.cc
@@ -13,6 +13,9 @@
#include <unistd.h> // NOLINT
+namespace dart {
+namespace bin {
+
bool Platform::Initialize() {
// Turn off the signal handler for SIGPIPE as it causes the process
// to terminate on writing to a closed pipe. Without the signal
@@ -74,4 +77,7 @@
delete[] env;
}
+} // namespace bin
+} // namespace dart
+
#endif // defined(TARGET_OS_MACOS)
diff --git a/runtime/bin/platform_win.cc b/runtime/bin/platform_win.cc
index a71a455..3ba9303 100644
--- a/runtime/bin/platform_win.cc
+++ b/runtime/bin/platform_win.cc
@@ -9,6 +9,10 @@
#include "bin/log.h"
#include "bin/socket.h"
+
+namespace dart {
+namespace bin {
+
bool Platform::Initialize() {
// Nothing to do on Windows.
return true;
@@ -59,4 +63,7 @@
delete[] env;
}
+} // namespace bin
+} // namespace dart
+
#endif // defined(TARGET_OS_WINDOWS)
diff --git a/runtime/bin/process.cc b/runtime/bin/process.cc
index c112e85..df53cd5 100644
--- a/runtime/bin/process.cc
+++ b/runtime/bin/process.cc
@@ -9,6 +9,10 @@
#include "include/dart_api.h"
+
+namespace dart {
+namespace bin {
+
static const int kProcessIdNativeField = 0;
int Process::global_exit_code_ = 0;
@@ -260,3 +264,6 @@
Dart_SetReturnValue(args, external_array);
Dart_ExitScope();
}
+
+} // namespace bin
+} // namespace dart
diff --git a/runtime/bin/process.h b/runtime/bin/process.h
index d0ac1bc..c0d8b8b 100644
--- a/runtime/bin/process.h
+++ b/runtime/bin/process.h
@@ -10,6 +10,9 @@
#include "platform/globals.h"
+namespace dart {
+namespace bin {
+
class Process {
public:
// Start a new process providing access to stdin, stdout, stderr and
@@ -59,4 +62,7 @@
DISALLOW_IMPLICIT_CONSTRUCTORS(Process);
};
+} // namespace bin
+} // namespace dart
+
#endif // BIN_PROCESS_H_
diff --git a/runtime/bin/process_android.cc b/runtime/bin/process_android.cc
index f0bbb83..677097b 100644
--- a/runtime/bin/process_android.cc
+++ b/runtime/bin/process_android.cc
@@ -22,6 +22,9 @@
#include "bin/thread.h"
+namespace dart {
+namespace bin {
+
// ProcessInfo is used to map a process id to the file descriptor for
// the pipe used to communicate the exit code of the process to Dart.
// ProcessInfo objects are kept in the static singly-linked
@@ -570,4 +573,7 @@
return static_cast<intptr_t>(getpid());
}
+} // namespace bin
+} // namespace dart
+
#endif // defined(TARGET_OS_ANDROID)
diff --git a/runtime/bin/process_linux.cc b/runtime/bin/process_linux.cc
index 9ff0ce7..838dc27 100644
--- a/runtime/bin/process_linux.cc
+++ b/runtime/bin/process_linux.cc
@@ -23,6 +23,10 @@
extern char **environ;
+
+namespace dart {
+namespace bin {
+
// ProcessInfo is used to map a process id to the file descriptor for
// the pipe used to communicate the exit code of the process to Dart.
// ProcessInfo objects are kept in the static singly-linked
@@ -566,4 +570,7 @@
return static_cast<intptr_t>(getpid());
}
+} // namespace bin
+} // namespace dart
+
#endif // defined(TARGET_OS_LINUX)
diff --git a/runtime/bin/process_macos.cc b/runtime/bin/process_macos.cc
index fb60ecd..0022a8b 100644
--- a/runtime/bin/process_macos.cc
+++ b/runtime/bin/process_macos.cc
@@ -22,6 +22,10 @@
extern char **environ;
+
+namespace dart {
+namespace bin {
+
// ProcessInfo is used to map a process id to the file descriptor for
// the pipe used to communicate the exit code of the process to Dart.
// ProcessInfo objects are kept in the static singly-linked
@@ -564,4 +568,7 @@
return static_cast<intptr_t>(getpid());
}
+} // namespace bin
+} // namespace dart
+
#endif // defined(TARGET_OS_MACOS)
diff --git a/runtime/bin/process_win.cc b/runtime/bin/process_win.cc
index 407dd37..1237f13 100644
--- a/runtime/bin/process_win.cc
+++ b/runtime/bin/process_win.cc
@@ -14,6 +14,10 @@
#include "bin/thread.h"
#include "bin/utils.h"
+
+namespace dart {
+namespace bin {
+
static const int kReadHandle = 0;
static const int kWriteHandle = 1;
@@ -663,4 +667,7 @@
return static_cast<intptr_t>(GetCurrentProcessId());
}
+} // namespace bin
+} // namespace dart
+
#endif // defined(TARGET_OS_WINDOWS)
diff --git a/runtime/bin/resources.h b/runtime/bin/resources.h
index 6279bba..0f3f7c3 100644
--- a/runtime/bin/resources.h
+++ b/runtime/bin/resources.h
@@ -11,6 +11,9 @@
#include "platform/assert.h"
+namespace dart {
+namespace bin {
+
class Resources {
public:
static const int kNoSuchInstance = -1;
@@ -50,4 +53,7 @@
DISALLOW_IMPLICIT_CONSTRUCTORS(Resources);
};
+} // namespace bin
+} // namespace dart
+
#endif // BIN_RESOURCES_H_
diff --git a/runtime/bin/secure_socket.cc b/runtime/bin/secure_socket.cc
index e66ff35..4f7bd6b 100644
--- a/runtime/bin/secure_socket.cc
+++ b/runtime/bin/secure_socket.cc
@@ -30,6 +30,10 @@
#include "include/dart_api.h"
+
+namespace dart {
+namespace bin {
+
bool SSLFilter::library_initialized_ = false;
dart::Mutex SSLFilter::mutex_; // To protect library initialization.
// The password is needed when creating secure server sockets. It can
@@ -560,19 +564,17 @@
// SetPeerAddress
PRNetAddr host_address;
- char host_entry_buffer[PR_NETDB_BUF_SIZE];
- PRHostEnt host_entry;
- PRStatus rv = PR_GetHostByName(host_name, host_entry_buffer,
- PR_NETDB_BUF_SIZE, &host_entry);
- if (rv != PR_SUCCESS) {
- ThrowPRException("Failed PR_GetHostByName call");
+ PRAddrInfo* info = PR_GetAddrInfoByName(host_name,
+ PR_AF_UNSPEC,
+ PR_AI_ADDRCONFIG);
+ if (info == NULL) {
+ ThrowPRException("Failed PR_GetAddrInfoByName call");
}
- int index = PR_EnumerateHostEnt(0, &host_entry, port, &host_address);
- if (index == -1 || index == 0) {
- ThrowPRException("Failed PR_EnumerateHostEnt call");
- }
+ PR_EnumerateAddrInfo(0, info, port, &host_address);
+
memio_SetPeerName(filter_, &host_address);
+ PR_FreeAddrInfo(info);
}
@@ -716,3 +718,6 @@
}
return bytes_processed;
}
+
+} // namespace bin
+} // namespace dart
diff --git a/runtime/bin/secure_socket.h b/runtime/bin/secure_socket.h
index 551fde0..536a77a 100644
--- a/runtime/bin/secure_socket.h
+++ b/runtime/bin/secure_socket.h
@@ -20,6 +20,10 @@
#include "platform/globals.h"
#include "platform/thread.h"
+
+namespace dart {
+namespace bin {
+
static void ThrowException(const char* message) {
Dart_Handle socket_io_exception =
DartUtils::NewDartSocketIOException(message, Dart_Null());
@@ -120,4 +124,7 @@
DISALLOW_COPY_AND_ASSIGN(SSLFilter);
};
+} // namespace bin
+} // namespace dart
+
#endif // BIN_SECURE_SOCKET_H_
diff --git a/runtime/bin/snapshot_empty.cc b/runtime/bin/snapshot_empty.cc
index abc5522..f8c3f95 100644
--- a/runtime/bin/snapshot_empty.cc
+++ b/runtime/bin/snapshot_empty.cc
@@ -13,4 +13,11 @@
#endif
#include <stddef.h>
+
+namespace dart {
+namespace bin {
+
const uint8_t* snapshot_buffer = NULL;
+
+} // namespace bin
+} // namespace dart
diff --git a/runtime/bin/snapshot_in.cc b/runtime/bin/snapshot_in.cc
index b281cd5..2e2a497 100644
--- a/runtime/bin/snapshot_in.cc
+++ b/runtime/bin/snapshot_in.cc
@@ -13,6 +13,10 @@
#endif
#include <stddef.h>
+
+namespace dart {
+namespace bin {
+
// The string on the next line will be filled in with the contents of the
// generated snapshot binary file.
// This string forms the content of a snapshot which is loaded in by dart.
@@ -20,3 +24,6 @@
%s
};
const uint8_t* snapshot_buffer = snapshot_buffer_;
+
+} // namespace bin
+} // namespace dart
diff --git a/runtime/bin/socket.cc b/runtime/bin/socket.cc
index 3a35ea2..2593238 100644
--- a/runtime/bin/socket.cc
+++ b/runtime/bin/socket.cc
@@ -14,6 +14,10 @@
#include "include/dart_api.h"
+
+namespace dart {
+namespace bin {
+
static const int kSocketIdNativeField = 0;
dart::Mutex Socket::mutex_;
@@ -21,19 +25,37 @@
Dart_Port* Socket::service_ports_ = NULL;
int Socket::service_ports_index_ = 0;
+
+static Dart_Handle GetSockAddr(Dart_Handle obj, RawAddr* addr) {
+ Dart_TypedData_Type data_type;
+ uint8_t* data = NULL;
+ intptr_t len;
+ Dart_Handle result = Dart_TypedDataAcquireData(
+ obj, &data_type, reinterpret_cast<void**>(&data), &len);
+ if (Dart_IsError(result)) return result;
+ memmove(reinterpret_cast<void *>(addr), data, len);
+ return Dart_Null();
+}
+
+
void FUNCTION_NAME(Socket_CreateConnect)(Dart_NativeArguments args) {
Dart_EnterScope();
Dart_Handle socket_obj = Dart_GetNativeArgument(args, 0);
- const char* host = DartUtils::GetStringValue(Dart_GetNativeArgument(args, 1));
+ Dart_Handle host_obj = Dart_GetNativeArgument(args, 1);
+ RawAddr addr;
+ Dart_Handle result = GetSockAddr(host_obj, &addr);
int64_t port = 0;
- if (DartUtils::GetInt64Value(Dart_GetNativeArgument(args, 2), &port)) {
- intptr_t socket = Socket::CreateConnect(host, port);
+ if (!Dart_IsError(result) &&
+ DartUtils::GetInt64Value(Dart_GetNativeArgument(args, 2), &port)) {
+ intptr_t socket = Socket::CreateConnect(addr, port);
+ OSError error;
+ Dart_TypedDataReleaseData(host_obj);
if (socket >= 0) {
Dart_Handle err = Socket::SetSocketIdNativeField(socket_obj, socket);
if (Dart_IsError(err)) Dart_PropagateError(err);
Dart_SetReturnValue(args, Dart_True());
} else {
- Dart_SetReturnValue(args, DartUtils::NewDartOSError());
+ Dart_SetReturnValue(args, DartUtils::NewDartOSError(&error));
}
} else {
OSError os_error(-1, "Invalid argument", OSError::kUnknown);
@@ -251,7 +273,8 @@
if (Dart_IsError(err)) Dart_PropagateError(err);
OSError os_error;
intptr_t port = 0;
- char host[INET_ADDRSTRLEN];
+ ASSERT(INET6_ADDRSTRLEN >= INET_ADDRSTRLEN);
+ char host[INET6_ADDRSTRLEN];
if (Socket::GetRemotePeer(socket, host, &port)) {
Dart_Handle list = Dart_NewList(2);
Dart_ListSetAt(list, 0, Dart_NewStringFromCString(host));
@@ -310,17 +333,19 @@
void FUNCTION_NAME(ServerSocket_CreateBindListen)(Dart_NativeArguments args) {
Dart_EnterScope();
Dart_Handle socket_obj = Dart_GetNativeArgument(args, 0);
- Dart_Handle bind_address_obj = Dart_GetNativeArgument(args, 1);
+ Dart_Handle host_obj = Dart_GetNativeArgument(args, 1);
+ RawAddr addr;
+ Dart_Handle result = GetSockAddr(host_obj, &addr);
Dart_Handle port_obj = Dart_GetNativeArgument(args, 2);
Dart_Handle backlog_obj = Dart_GetNativeArgument(args, 3);
int64_t port = 0;
int64_t backlog = 0;
- if (Dart_IsString(bind_address_obj) &&
+ if (!Dart_IsError(result) &&
DartUtils::GetInt64Value(port_obj, &port) &&
DartUtils::GetInt64Value(backlog_obj, &backlog)) {
- const char* bind_address = DartUtils::GetStringValue(bind_address_obj);
- intptr_t socket =
- ServerSocket::CreateBindListen(bind_address, port, backlog);
+ intptr_t socket = ServerSocket::CreateBindListen(addr, port, backlog);
+ OSError error;
+ Dart_TypedDataReleaseData(host_obj);
if (socket >= 0) {
Dart_Handle err = Socket::SetSocketIdNativeField(socket_obj, socket);
if (Dart_IsError(err)) Dart_PropagateError(err);
@@ -330,7 +355,7 @@
OSError os_error(-1, "Invalid host", OSError::kUnknown);
Dart_SetReturnValue(args, DartUtils::NewDartOSError(&os_error));
} else {
- Dart_SetReturnValue(args, DartUtils::NewDartOSError());
+ Dart_SetReturnValue(args, DartUtils::NewDartOSError(&error));
}
}
} else {
@@ -366,15 +391,43 @@
static CObject* LookupRequest(const CObjectArray& request) {
- if (request.Length() == 2 && request[1]->IsString()) {
+ if (request.Length() == 3 &&
+ request[1]->IsString() &&
+ request[2]->IsInt32()) {
CObjectString host(request[1]);
+ CObjectInt32 type(request[2]);
CObject* result = NULL;
OSError* os_error = NULL;
- const char* ip_address =
- Socket::LookupIPv4Address(host.CString(), &os_error);
- if (ip_address != NULL) {
- result = new CObjectString(CObject::NewString(ip_address));
- free(const_cast<char*>(ip_address));
+ SocketAddresses* addresses =
+ Socket::LookupAddress(host.CString(), type.Value(), &os_error);
+ if (addresses != NULL) {
+ CObjectArray* array = new CObjectArray(
+ CObject::NewArray(addresses->count() + 1));
+ array->SetAt(0, new CObjectInt32(CObject::NewInt32(0)));
+ for (intptr_t i = 0; i < addresses->count(); i++) {
+ SocketAddress* addr = addresses->GetAt(i);
+ CObjectArray* entry = new CObjectArray(CObject::NewArray(3));
+
+ CObjectInt32* type = new CObjectInt32(
+ CObject::NewInt32(addr->GetType()));
+ entry->SetAt(0, type);
+
+ CObjectString* as_string = new CObjectString(CObject::NewString(
+ addr->as_string()));
+ entry->SetAt(1, as_string);
+
+ RawAddr raw = addr->addr();
+ CObjectUint8Array* data = new CObjectUint8Array(CObject::NewUint8Array(
+ SocketAddress::GetAddrLength(raw)));
+ memmove(data->Buffer(),
+ reinterpret_cast<void *>(&raw),
+ SocketAddress::GetAddrLength(raw));
+
+ entry->SetAt(2, data);
+ array->SetAt(i + 1, entry);
+ }
+ result = array;
+ delete addresses;
} else {
result = CObject::NewOSError(os_error);
delete os_error;
@@ -480,3 +533,6 @@
Dart_Handle Socket::GetSocketIdNativeField(Dart_Handle socket, intptr_t* id) {
return Dart_GetNativeInstanceField(socket, kSocketIdNativeField, id);
}
+
+} // namespace bin
+} // namespace dart
diff --git a/runtime/bin/socket.h b/runtime/bin/socket.h
index b68b782..aa8d198 100644
--- a/runtime/bin/socket.h
+++ b/runtime/bin/socket.h
@@ -24,6 +24,93 @@
#endif
+namespace dart {
+namespace bin {
+
+union RawAddr {
+ struct sockaddr_in in;
+ struct sockaddr_in6 in6;
+ struct sockaddr_storage ss;
+ struct sockaddr addr;
+};
+
+class SocketAddress {
+ public:
+ enum {
+ TYPE_ANY = -1,
+ TYPE_IPV4,
+ TYPE_IPV6,
+ };
+
+ explicit SocketAddress(struct addrinfo* addrinfo);
+
+ int GetType() {
+ if (addr_.ss.ss_family == AF_INET6) return TYPE_IPV6;
+ return TYPE_IPV4;
+ }
+
+ const char* as_string() const { return as_string_; }
+ const RawAddr& addr() const { return addr_; }
+
+ static intptr_t GetAddrLength(const RawAddr& addr) {
+ return addr.ss.ss_family == AF_INET6 ?
+ sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in);
+ }
+
+ static int16_t FromType(int type) {
+ if (type == TYPE_ANY) return AF_UNSPEC;
+ if (type == TYPE_IPV4) return AF_INET;
+ ASSERT(type == TYPE_IPV6 && "Invalid type");
+ return AF_INET6;
+ }
+
+ static void SetAddrPort(RawAddr* addr, intptr_t port) {
+ if (addr->ss.ss_family == AF_INET) {
+ addr->in.sin_port = htons(port);
+ } else {
+ addr->in6.sin6_port = htons(port);
+ }
+ }
+
+ static intptr_t GetAddrPort(RawAddr* addr) {
+ if (addr->ss.ss_family == AF_INET) {
+ return ntohs(addr->in.sin_port);
+ } else {
+ return ntohs(addr->in6.sin6_port);
+ }
+ }
+
+ private:
+ char as_string_[INET6_ADDRSTRLEN];
+ RawAddr addr_;
+
+ DISALLOW_COPY_AND_ASSIGN(SocketAddress);
+};
+
+class SocketAddresses {
+ public:
+ explicit SocketAddresses(intptr_t count)
+ : count_(count),
+ addresses_(new SocketAddress*[count_]) {}
+
+ ~SocketAddresses() {
+ for (intptr_t i = 0; i < count_; i++) {
+ delete addresses_[i];
+ }
+ delete[] addresses_;
+ }
+
+ intptr_t count() const { return count_; }
+ SocketAddress* GetAt(intptr_t i) const { return addresses_[i]; }
+ void SetAt(intptr_t i, SocketAddress* addr) { addresses_[i] = addr; }
+
+ private:
+ const intptr_t count_;
+ SocketAddress** addresses_;
+
+ DISALLOW_COPY_AND_ASSIGN(SocketAddresses);
+};
+
class Socket {
public:
enum SocketRequest {
@@ -34,7 +121,8 @@
static intptr_t Available(intptr_t fd);
static int Read(intptr_t fd, void* buffer, intptr_t num_bytes);
static int Write(intptr_t fd, const void* buffer, intptr_t num_bytes);
- static intptr_t CreateConnect(const char* host, const intptr_t port);
+ static intptr_t CreateConnect(RawAddr addr,
+ const intptr_t port);
static intptr_t GetPort(intptr_t fd);
static bool GetRemotePeer(intptr_t fd, char* host, intptr_t* port);
static void GetError(intptr_t fd, OSError* os_error);
@@ -45,9 +133,10 @@
static bool SetBlocking(intptr_t fd);
static bool SetNoDelay(intptr_t fd, bool enabled);
- // Perform a IPv4 hostname lookup. Returns the hostname string in
- // IPv4 dotted-decimal format.
- static const char* LookupIPv4Address(char* host, OSError** os_error);
+ // Perform a hostname lookup. Returns the SocketAddresses.
+ static SocketAddresses* LookupAddress(const char* host,
+ int type,
+ OSError** os_error);
static Dart_Port GetServicePort();
@@ -76,7 +165,7 @@
//
// -1: system error (errno set)
// -5: invalid bindAddress
- static intptr_t CreateBindListen(const char* bindAddress,
+ static intptr_t CreateBindListen(RawAddr addr,
intptr_t port,
intptr_t backlog);
@@ -84,4 +173,7 @@
DISALLOW_IMPLICIT_CONSTRUCTORS(ServerSocket);
};
+} // namespace bin
+} // namespace dart
+
#endif // BIN_SOCKET_H_
diff --git a/runtime/bin/socket_android.cc b/runtime/bin/socket_android.cc
index 7e3871d..e4b99bd 100644
--- a/runtime/bin/socket_android.cc
+++ b/runtime/bin/socket_android.cc
@@ -17,18 +17,33 @@
#include "bin/log.h"
+namespace dart {
+namespace bin {
+
+SocketAddress::SocketAddress(struct addrinfo* addrinfo) {
+ ASSERT(INET6_ADDRSTRLEN >= INET_ADDRSTRLEN);
+ RawAddr* raw = reinterpret_cast<RawAddr*>(addrinfo->ai_addr);
+ const char* result = inet_ntop(addrinfo->ai_family,
+ &raw->in.sin_addr,
+ as_string_,
+ INET6_ADDRSTRLEN);
+ if (result == NULL) as_string_[0] = 0;
+ memmove(reinterpret_cast<void *>(&addr_),
+ addrinfo->ai_addr,
+ addrinfo->ai_addrlen);
+}
+
+
bool Socket::Initialize() {
// Nothing to do on Android.
return true;
}
-intptr_t Socket::CreateConnect(const char* host, const intptr_t port) {
+intptr_t Socket::CreateConnect(RawAddr addr, const intptr_t port) {
intptr_t fd;
- struct hostent* server;
- struct sockaddr_in server_address;
- fd = TEMP_FAILURE_RETRY(socket(AF_INET, SOCK_STREAM, 0));
+ fd = TEMP_FAILURE_RETRY(socket(addr.ss.ss_family, SOCK_STREAM, 0));
if (fd < 0) {
Log::PrintErr("Error CreateConnect: %s\n", strerror(errno));
return -1;
@@ -37,24 +52,15 @@
FDUtils::SetCloseOnExec(fd);
Socket::SetNonBlocking(fd);
- server = gethostbyname(host);
- if (server == NULL) {
- TEMP_FAILURE_RETRY(close(fd));
- Log::PrintErr("Error CreateConnect: %s\n", strerror(errno));
- return -1;
- }
-
- server_address.sin_family = AF_INET;
- server_address.sin_port = htons(port);
- bcopy(server->h_addr, &server_address.sin_addr.s_addr, server->h_length);
- memset(&server_address.sin_zero, 0, sizeof(server_address.sin_zero));
+ SocketAddress::SetAddrPort(&addr, port);
intptr_t result = TEMP_FAILURE_RETRY(
connect(fd,
- reinterpret_cast<struct sockaddr *>(&server_address),
- sizeof(server_address)));
+ &addr.addr,
+ SocketAddress::GetAddrLength(addr)));
if (result == 0 || errno == EINPROGRESS) {
return fd;
}
+ TEMP_FAILURE_RETRY(close(fd));
return -1;
}
@@ -92,38 +98,44 @@
intptr_t Socket::GetPort(intptr_t fd) {
ASSERT(fd >= 0);
- struct sockaddr_in socket_address;
- socklen_t size = sizeof(socket_address);
+ RawAddr raw;
+ socklen_t size = sizeof(raw);
if (TEMP_FAILURE_RETRY(
getsockname(fd,
- reinterpret_cast<struct sockaddr *>(&socket_address),
+ &raw.addr,
&size))) {
Log::PrintErr("Error getsockname: %s\n", strerror(errno));
return 0;
}
- return ntohs(socket_address.sin_port);
+ return SocketAddress::GetAddrPort(&raw);
}
bool Socket::GetRemotePeer(intptr_t fd, char *host, intptr_t *port) {
ASSERT(fd >= 0);
- struct sockaddr_in socket_address;
- socklen_t size = sizeof(socket_address);
+ RawAddr raw;
+ socklen_t size = sizeof(raw);
if (TEMP_FAILURE_RETRY(
getpeername(fd,
- reinterpret_cast<struct sockaddr *>(&socket_address),
+ &raw.addr,
&size))) {
Log::PrintErr("Error getpeername: %s\n", strerror(errno));
return false;
}
- if (inet_ntop(socket_address.sin_family,
- reinterpret_cast<const void *>(&socket_address.sin_addr),
+ const void* src;
+ if (raw.ss.ss_family == AF_INET6) {
+ src = reinterpret_cast<const void*>(&raw.in6.sin6_addr);
+ } else {
+ src = reinterpret_cast<const void*>(&raw.in.sin_addr);
+ }
+ if (inet_ntop(raw.ss.ss_family,
+ src,
host,
INET_ADDRSTRLEN) == NULL) {
Log::PrintErr("Error inet_ntop: %s\n", strerror(errno));
return false;
}
- *port = ntohs(socket_address.sin_port);
+ *port = SocketAddress::GetAddrPort(&raw);
return true;
}
@@ -145,12 +157,15 @@
}
-const char* Socket::LookupIPv4Address(char* host, OSError** os_error) {
- // Perform a name lookup for an IPv4 address.
+SocketAddresses* Socket::LookupAddress(const char* host,
+ int type,
+ OSError** os_error) {
+ // Perform a name lookup for a host name.
struct addrinfo hints;
memset(&hints, 0, sizeof(hints));
- hints.ai_family = AF_INET;
+ hints.ai_family = SocketAddress::FromType(type);
hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = 0;
hints.ai_protocol = IPPROTO_TCP;
struct addrinfo* info = NULL;
int status = getaddrinfo(host, 0, &hints, &info);
@@ -161,38 +176,30 @@
OSError::kGetAddressInfo);
return NULL;
}
- // Convert the address into IPv4 dotted decimal notation.
- char* buffer = reinterpret_cast<char*>(malloc(INET_ADDRSTRLEN));
- sockaddr_in *sockaddr = reinterpret_cast<sockaddr_in *>(info->ai_addr);
- const char* result = inet_ntop(AF_INET,
- reinterpret_cast<void *>(&sockaddr->sin_addr),
- buffer,
- INET_ADDRSTRLEN);
- if (result == NULL) {
- free(buffer);
- return NULL;
+ intptr_t count = 0;
+ for (struct addrinfo* c = info; c != NULL; c = c->ai_next) {
+ if (c->ai_family == AF_INET || c->ai_family == AF_INET6) count++;
}
- ASSERT(result == buffer);
- return buffer;
+ SocketAddresses* addresses = new SocketAddresses(count);
+ intptr_t i = 0;
+ for (struct addrinfo* c = info; c != NULL; c = c->ai_next) {
+ if (c->ai_family == AF_INET || c->ai_family == AF_INET6) {
+ addresses->SetAt(i, new SocketAddress(c));
+ i++;
+ }
+ }
+ freeaddrinfo(info);
+ return addresses;
}
-intptr_t ServerSocket::CreateBindListen(const char* host,
+intptr_t ServerSocket::CreateBindListen(RawAddr addr,
intptr_t port,
intptr_t backlog) {
intptr_t fd;
- struct sockaddr_in server_address;
- in_addr_t s_addr = inet_addr(host);
- if (s_addr == INADDR_NONE) {
- return -5;
- }
-
- fd = TEMP_FAILURE_RETRY(socket(AF_INET, SOCK_STREAM, 0));
- if (fd < 0) {
- Log::PrintErr("Error CreateBind: %s\n", strerror(errno));
- return -1;
- }
+ fd = TEMP_FAILURE_RETRY(socket(addr.ss.ss_family, SOCK_STREAM, 0));
+ if (fd < 0) return -1;
FDUtils::SetCloseOnExec(fd);
@@ -200,22 +207,23 @@
TEMP_FAILURE_RETRY(
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)));
- server_address.sin_family = AF_INET;
- server_address.sin_port = htons(port);
- server_address.sin_addr.s_addr = s_addr;
- memset(&server_address.sin_zero, 0, sizeof(server_address.sin_zero));
+ if (addr.ss.ss_family == AF_INET6) {
+ optval = 0;
+ TEMP_FAILURE_RETRY(
+ setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &optval, sizeof(optval)));
+ }
+ SocketAddress::SetAddrPort(&addr, port);
if (TEMP_FAILURE_RETRY(
bind(fd,
- reinterpret_cast<struct sockaddr *>(&server_address),
- sizeof(server_address))) < 0) {
+ &addr.addr,
+ SocketAddress::GetAddrLength(addr))) < 0) {
TEMP_FAILURE_RETRY(close(fd));
- Log::PrintErr("Error Bind: %s\n", strerror(errno));
return -1;
}
- if (TEMP_FAILURE_RETRY(listen(fd, backlog)) != 0) {
- Log::PrintErr("Error Listen: %s\n", strerror(errno));
+ if (TEMP_FAILURE_RETRY(listen(fd, backlog > 0 ? backlog : SOMAXCONN)) != 0) {
+ TEMP_FAILURE_RETRY(close(fd));
return -1;
}
@@ -285,4 +293,7 @@
sizeof(on))) == 0;
}
+} // namespace bin
+} // namespace dart
+
#endif // defined(TARGET_OS_ANDROID)
diff --git a/runtime/bin/socket_linux.cc b/runtime/bin/socket_linux.cc
index 23e492c..e881f5d 100644
--- a/runtime/bin/socket_linux.cc
+++ b/runtime/bin/socket_linux.cc
@@ -19,18 +19,33 @@
#include "bin/socket.h"
+namespace dart {
+namespace bin {
+
+SocketAddress::SocketAddress(struct addrinfo* addrinfo) {
+ ASSERT(INET6_ADDRSTRLEN >= INET_ADDRSTRLEN);
+ RawAddr* raw = reinterpret_cast<RawAddr*>(addrinfo->ai_addr);
+ const char* result = inet_ntop(addrinfo->ai_family,
+ &raw->in.sin_addr,
+ as_string_,
+ INET6_ADDRSTRLEN);
+ if (result == NULL) as_string_[0] = 0;
+ memmove(reinterpret_cast<void *>(&addr_),
+ addrinfo->ai_addr,
+ addrinfo->ai_addrlen);
+}
+
+
bool Socket::Initialize() {
// Nothing to do on Linux.
return true;
}
-intptr_t Socket::CreateConnect(const char* host, const intptr_t port) {
+intptr_t Socket::CreateConnect(RawAddr addr, const intptr_t port) {
intptr_t fd;
- struct hostent server;
- struct sockaddr_in server_address;
- fd = TEMP_FAILURE_RETRY(socket(AF_INET, SOCK_STREAM, 0));
+ fd = TEMP_FAILURE_RETRY(socket(addr.ss.ss_family, SOCK_STREAM, 0));
if (fd < 0) {
Log::PrintErr("Error CreateConnect: %s\n", strerror(errno));
return -1;
@@ -39,28 +54,15 @@
FDUtils::SetCloseOnExec(fd);
Socket::SetNonBlocking(fd);
- static const size_t kTempBufSize = 1024;
- char temp_buf[kTempBufSize];
- struct hostent *unused;
- int err;
- if (gethostbyname_r(
- host, &server, temp_buf, kTempBufSize, &unused, &err) != 0) {
- TEMP_FAILURE_RETRY(close(fd));
- Log::PrintErr("Error CreateConnect: %s\n", strerror(errno));
- return -1;
- }
-
- server_address.sin_family = AF_INET;
- server_address.sin_port = htons(port);
- bcopy(server.h_addr, &server_address.sin_addr.s_addr, server.h_length);
- memset(&server_address.sin_zero, 0, sizeof(server_address.sin_zero));
+ SocketAddress::SetAddrPort(&addr, port);
intptr_t result = TEMP_FAILURE_RETRY(
connect(fd,
- reinterpret_cast<struct sockaddr *>(&server_address),
- sizeof(server_address)));
+ &addr.addr,
+ SocketAddress::GetAddrLength(addr)));
if (result == 0 || errno == EINPROGRESS) {
return fd;
}
+ TEMP_FAILURE_RETRY(close(fd));
return -1;
}
@@ -98,38 +100,44 @@
intptr_t Socket::GetPort(intptr_t fd) {
ASSERT(fd >= 0);
- struct sockaddr_in socket_address;
- socklen_t size = sizeof(socket_address);
+ RawAddr raw;
+ socklen_t size = sizeof(raw);
if (TEMP_FAILURE_RETRY(
getsockname(fd,
- reinterpret_cast<struct sockaddr *>(&socket_address),
+ &raw.addr,
&size))) {
Log::PrintErr("Error getsockname: %s\n", strerror(errno));
return 0;
}
- return ntohs(socket_address.sin_port);
+ return SocketAddress::GetAddrPort(&raw);
}
bool Socket::GetRemotePeer(intptr_t fd, char *host, intptr_t *port) {
ASSERT(fd >= 0);
- struct sockaddr_in socket_address;
- socklen_t size = sizeof(socket_address);
+ RawAddr raw;
+ socklen_t size = sizeof(raw);
if (TEMP_FAILURE_RETRY(
getpeername(fd,
- reinterpret_cast<struct sockaddr *>(&socket_address),
+ &raw.addr,
&size))) {
Log::PrintErr("Error getpeername: %s\n", strerror(errno));
return false;
}
- if (inet_ntop(socket_address.sin_family,
- reinterpret_cast<const void *>(&socket_address.sin_addr),
+ const void* src;
+ if (raw.ss.ss_family == AF_INET6) {
+ src = reinterpret_cast<const void*>(&raw.in6.sin6_addr);
+ } else {
+ src = reinterpret_cast<const void*>(&raw.in.sin_addr);
+ }
+ if (inet_ntop(raw.ss.ss_family,
+ src,
host,
INET_ADDRSTRLEN) == NULL) {
Log::PrintErr("Error inet_ntop: %s\n", strerror(errno));
return false;
}
- *port = ntohs(socket_address.sin_port);
+ *port = SocketAddress::GetAddrPort(&raw);
return true;
}
@@ -161,12 +169,15 @@
}
-const char* Socket::LookupIPv4Address(char* host, OSError** os_error) {
- // Perform a name lookup for an IPv4 address.
+SocketAddresses* Socket::LookupAddress(const char* host,
+ int type,
+ OSError** os_error) {
+ // Perform a name lookup for a host name.
struct addrinfo hints;
memset(&hints, 0, sizeof(hints));
- hints.ai_family = AF_INET;
+ hints.ai_family = SocketAddress::FromType(type);
hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = 0;
hints.ai_protocol = IPPROTO_TCP;
struct addrinfo* info = NULL;
int status = getaddrinfo(host, 0, &hints, &info);
@@ -177,34 +188,29 @@
OSError::kGetAddressInfo);
return NULL;
}
- // Convert the address into IPv4 dotted decimal notation.
- char* buffer = reinterpret_cast<char*>(malloc(INET_ADDRSTRLEN));
- sockaddr_in *sockaddr = reinterpret_cast<sockaddr_in *>(info->ai_addr);
- const char* result = inet_ntop(AF_INET,
- reinterpret_cast<void *>(&sockaddr->sin_addr),
- buffer,
- INET_ADDRSTRLEN);
- if (result == NULL) {
- free(buffer);
- return NULL;
+ intptr_t count = 0;
+ for (struct addrinfo* c = info; c != NULL; c = c->ai_next) {
+ if (c->ai_family == AF_INET || c->ai_family == AF_INET6) count++;
}
- ASSERT(result == buffer);
- return buffer;
+ SocketAddresses* addresses = new SocketAddresses(count);
+ intptr_t i = 0;
+ for (struct addrinfo* c = info; c != NULL; c = c->ai_next) {
+ if (c->ai_family == AF_INET || c->ai_family == AF_INET6) {
+ addresses->SetAt(i, new SocketAddress(c));
+ i++;
+ }
+ }
+ freeaddrinfo(info);
+ return addresses;
}
-intptr_t ServerSocket::CreateBindListen(const char* host,
+intptr_t ServerSocket::CreateBindListen(RawAddr addr,
intptr_t port,
intptr_t backlog) {
intptr_t fd;
- struct sockaddr_in server_address;
- in_addr_t s_addr = inet_addr(host);
- if (s_addr == INADDR_NONE) {
- return -5;
- }
-
- fd = TEMP_FAILURE_RETRY(socket(AF_INET, SOCK_STREAM, 0));
+ fd = TEMP_FAILURE_RETRY(socket(addr.ss.ss_family, SOCK_STREAM, 0));
if (fd < 0) return -1;
FDUtils::SetCloseOnExec(fd);
@@ -213,15 +219,17 @@
TEMP_FAILURE_RETRY(
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)));
- server_address.sin_family = AF_INET;
- server_address.sin_port = htons(port);
- server_address.sin_addr.s_addr = s_addr;
- memset(&server_address.sin_zero, 0, sizeof(server_address.sin_zero));
+ if (addr.ss.ss_family == AF_INET6) {
+ optval = 0;
+ TEMP_FAILURE_RETRY(
+ setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &optval, sizeof(optval)));
+ }
+ SocketAddress::SetAddrPort(&addr, port);
if (TEMP_FAILURE_RETRY(
bind(fd,
- reinterpret_cast<struct sockaddr *>(&server_address),
- sizeof(server_address))) < 0) {
+ &addr.addr,
+ SocketAddress::GetAddrLength(addr))) < 0) {
TEMP_FAILURE_RETRY(close(fd));
return -1;
}
@@ -297,4 +305,7 @@
sizeof(on))) == 0;
}
+} // namespace bin
+} // namespace dart
+
#endif // defined(TARGET_OS_LINUX)
diff --git a/runtime/bin/socket_macos.cc b/runtime/bin/socket_macos.cc
index ff1e28e..bf17056 100644
--- a/runtime/bin/socket_macos.cc
+++ b/runtime/bin/socket_macos.cc
@@ -19,18 +19,33 @@
#include "bin/socket.h"
+namespace dart {
+namespace bin {
+
+SocketAddress::SocketAddress(struct addrinfo* addrinfo) {
+ ASSERT(INET6_ADDRSTRLEN >= INET_ADDRSTRLEN);
+ RawAddr* raw = reinterpret_cast<RawAddr*>(addrinfo->ai_addr);
+ const char* result = inet_ntop(addrinfo->ai_family,
+ &raw->in.sin_addr,
+ as_string_,
+ INET6_ADDRSTRLEN);
+ if (result == NULL) as_string_[0] = 0;
+ memmove(reinterpret_cast<void *>(&addr_),
+ addrinfo->ai_addr,
+ addrinfo->ai_addrlen);
+}
+
+
bool Socket::Initialize() {
// Nothing to do on Mac OS.
return true;
}
-intptr_t Socket::CreateConnect(const char* host, const intptr_t port) {
+intptr_t Socket::CreateConnect(RawAddr addr, const intptr_t port) {
intptr_t fd;
- struct hostent* server;
- struct sockaddr_in server_address;
- fd = TEMP_FAILURE_RETRY(socket(AF_INET, SOCK_STREAM, 0));
+ fd = TEMP_FAILURE_RETRY(socket(addr.ss.ss_family, SOCK_STREAM, 0));
if (fd < 0) {
Log::PrintErr("Error CreateConnect: %s\n", strerror(errno));
return -1;
@@ -39,24 +54,15 @@
FDUtils::SetCloseOnExec(fd);
Socket::SetNonBlocking(fd);
- server = gethostbyname(host);
- if (server == NULL) {
- VOID_TEMP_FAILURE_RETRY(close(fd));
- Log::PrintErr("Error CreateConnect: %s\n", strerror(errno));
- return -1;
- }
-
- server_address.sin_family = AF_INET;
- server_address.sin_port = htons(port);
- bcopy(server->h_addr, &server_address.sin_addr.s_addr, server->h_length);
- memset(&server_address.sin_zero, 0, sizeof(server_address.sin_zero));
+ SocketAddress::SetAddrPort(&addr, port);
intptr_t result = TEMP_FAILURE_RETRY(
connect(fd,
- reinterpret_cast<struct sockaddr *>(&server_address),
- sizeof(server_address)));
+ &addr.addr,
+ SocketAddress::GetAddrLength(addr)));
if (result == 0 || errno == EINPROGRESS) {
return fd;
}
+ VOID_TEMP_FAILURE_RETRY(close(fd));
return -1;
}
@@ -94,38 +100,44 @@
intptr_t Socket::GetPort(intptr_t fd) {
ASSERT(fd >= 0);
- struct sockaddr_in socket_address;
- socklen_t size = sizeof(socket_address);
+ RawAddr raw;
+ socklen_t size = sizeof(raw);
if (TEMP_FAILURE_RETRY(
getsockname(fd,
- reinterpret_cast<struct sockaddr *>(&socket_address),
+ &raw.addr,
&size))) {
Log::PrintErr("Error getsockname: %s\n", strerror(errno));
return 0;
}
- return ntohs(socket_address.sin_port);
+ return SocketAddress::GetAddrPort(&raw);
}
bool Socket::GetRemotePeer(intptr_t fd, char *host, intptr_t *port) {
ASSERT(fd >= 0);
- struct sockaddr_in socket_address;
- socklen_t size = sizeof(socket_address);
+ RawAddr raw;
+ socklen_t size = sizeof(raw);
if (TEMP_FAILURE_RETRY(
getpeername(fd,
- reinterpret_cast<struct sockaddr *>(&socket_address),
+ &raw.addr,
&size))) {
Log::PrintErr("Error getpeername: %s\n", strerror(errno));
return false;
}
- if (inet_ntop(socket_address.sin_family,
- reinterpret_cast<const void *>(&socket_address.sin_addr),
+ const void* src;
+ if (raw.ss.ss_family == AF_INET6) {
+ src = reinterpret_cast<const void*>(&raw.in6.sin6_addr);
+ } else {
+ src = reinterpret_cast<const void*>(&raw.in.sin_addr);
+ }
+ if (inet_ntop(raw.ss.ss_family,
+ src,
host,
INET_ADDRSTRLEN) == NULL) {
Log::PrintErr("Error inet_ntop: %s\n", strerror(errno));
return false;
}
- *port = ntohs(socket_address.sin_port);
+ *port = SocketAddress::GetAddrPort(&raw);
return true;
}
@@ -157,12 +169,15 @@
}
-const char* Socket::LookupIPv4Address(char* host, OSError** os_error) {
- // Perform a name lookup for an IPv4 address.
+SocketAddresses* Socket::LookupAddress(const char* host,
+ int type,
+ OSError** os_error) {
+ // Perform a name lookup for a host name.
struct addrinfo hints;
memset(&hints, 0, sizeof(hints));
- hints.ai_family = AF_INET;
+ hints.ai_family = SocketAddress::FromType(type);
hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = 0;
hints.ai_protocol = IPPROTO_TCP;
struct addrinfo* info = NULL;
int status = getaddrinfo(host, 0, &hints, &info);
@@ -173,34 +188,29 @@
OSError::kGetAddressInfo);
return NULL;
}
- // Convert the address into IPv4 dotted decimal notation.
- char* buffer = reinterpret_cast<char*>(malloc(INET_ADDRSTRLEN));
- sockaddr_in *sockaddr = reinterpret_cast<sockaddr_in *>(info->ai_addr);
- const char* result = inet_ntop(AF_INET,
- reinterpret_cast<void *>(&sockaddr->sin_addr),
- buffer,
- INET_ADDRSTRLEN);
- if (result == NULL) {
- free(buffer);
- return NULL;
+ intptr_t count = 0;
+ for (struct addrinfo* c = info; c != NULL; c = c->ai_next) {
+ if (c->ai_family == AF_INET || c->ai_family == AF_INET6) count++;
}
- ASSERT(result == buffer);
- return buffer;
+ SocketAddresses* addresses = new SocketAddresses(count);
+ intptr_t i = 0;
+ for (struct addrinfo* c = info; c != NULL; c = c->ai_next) {
+ if (c->ai_family == AF_INET || c->ai_family == AF_INET6) {
+ addresses->SetAt(i, new SocketAddress(c));
+ i++;
+ }
+ }
+ freeaddrinfo(info);
+ return addresses;
}
-intptr_t ServerSocket::CreateBindListen(const char* host,
+intptr_t ServerSocket::CreateBindListen(RawAddr addr,
intptr_t port,
intptr_t backlog) {
intptr_t fd;
- struct sockaddr_in server_address;
- in_addr_t s_addr = inet_addr(host);
- if (s_addr == INADDR_NONE) {
- return -5;
- }
-
- fd = TEMP_FAILURE_RETRY(socket(AF_INET, SOCK_STREAM, 0));
+ fd = TEMP_FAILURE_RETRY(socket(addr.ss.ss_family, SOCK_STREAM, 0));
if (fd < 0) return -1;
FDUtils::SetCloseOnExec(fd);
@@ -209,21 +219,23 @@
VOID_TEMP_FAILURE_RETRY(
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)));
- server_address.sin_family = AF_INET;
- server_address.sin_port = htons(port);
- server_address.sin_addr.s_addr = s_addr;
- memset(&server_address.sin_zero, 0, sizeof(server_address.sin_zero));
+ if (addr.ss.ss_family == AF_INET6) {
+ optval = 0;
+ VOID_TEMP_FAILURE_RETRY(
+ setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &optval, sizeof(optval)));
+ }
+ SocketAddress::SetAddrPort(&addr, port);
if (TEMP_FAILURE_RETRY(
bind(fd,
- reinterpret_cast<struct sockaddr *>(&server_address),
- sizeof(server_address))) < 0) {
+ &addr.addr,
+ SocketAddress::GetAddrLength(addr))) < 0) {
VOID_TEMP_FAILURE_RETRY(close(fd));
return -1;
}
if (TEMP_FAILURE_RETRY(listen(fd, backlog > 0 ? backlog : SOMAXCONN)) != 0) {
- TEMP_FAILURE_RETRY(close(fd));
+ VOID_TEMP_FAILURE_RETRY(close(fd));
return -1;
}
@@ -283,4 +295,7 @@
sizeof(on))) == 0;
}
+} // namespace bin
+} // namespace dart
+
#endif // defined(TARGET_OS_MACOS)
diff --git a/runtime/bin/socket_patch.dart b/runtime/bin/socket_patch.dart
index 67fbadf..daa59c6 100644
--- a/runtime/bin/socket_patch.dart
+++ b/runtime/bin/socket_patch.dart
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
patch class RawServerSocket {
- /* patch */ static Future<RawServerSocket> bind([String address = "127.0.0.1",
+ /* patch */ static Future<RawServerSocket> bind([address = "127.0.0.1",
int port = 0,
int backlog = 0]) {
return _RawServerSocket.bind(address, port, backlog);
@@ -12,12 +12,36 @@
patch class RawSocket {
- /* patch */ static Future<RawSocket> connect(String host, int port) {
+ /* patch */ static Future<RawSocket> connect(host, int port) {
return _RawSocket.connect(host, port);
}
}
+patch class InternetAddress {
+ /* patch */ static Future<List<InternetAddress>> lookup(
+ String host, {InternetAddressType type: InternetAddressType.IPv4}) {
+ return _NativeSocket.lookup(host, type: type);
+ }
+}
+
+class _InternetAddress implements InternetAddress {
+ final InternetAddressType type;
+ final String address;
+ final String host;
+ final Uint8List _sockaddr_storage;
+
+ _InternetAddress(InternetAddressType this.type,
+ String this.address,
+ String this.host,
+ List<int> this._sockaddr_storage);
+
+ String toString() {
+ return "InternetAddress('$address', ${type.name})";
+ }
+}
+
+
// The _NativeSocket class encapsulates an OS socket.
class _NativeSocket extends NativeFieldWrapperClass1 {
// Bit flags used when communicating between the eventhandler and
@@ -74,57 +98,95 @@
// Holds the port of the socket, null if not known.
int localPort;
- // Holds the host or address used to connect or bind the socket.
- String localHost;
+ // Holds the address used to connect or bind the socket.
+ InternetAddress address;
// Native port for socket services.
static SendPort socketService;
- static Future<_NativeSocket> connect(String host, int port) {
- var completer = new Completer();
+ static Future<List<InternetAddress>> lookup(
+ String host, {InternetAddressType type: InternetAddressType.IPv4}) {
ensureSocketService();
- socketService.call([HOST_NAME_LOOKUP, host]).then((response) {
- if (isErrorResponse(response)) {
- completer.completeError(
- createError(response, "Failed host name lookup"));
- } else {
- var socket = new _NativeSocket.normal();
- socket.localHost = host;
- var result = socket.nativeCreateConnect(response, port);
- if (result is OSError) {
- completer.completeError(createError(result, "Connection failed"));
- } else {
- // Setup handlers for receiving the first write event which
- // indicate that the socket is fully connected.
- socket.setHandlers(
- write: () {
- socket.setListening(read: false, write: false);
- completer.complete(socket);
- },
- error: (e) {
- socket.close();
- completer.completeError(createError(e, "Connection failed"));
- }
- );
- socket.setListening(read: false, write: true);
- }
- }
- });
- return completer.future;
+ return socketService.call([HOST_NAME_LOOKUP, host, type._value])
+ .then((response) {
+ if (isErrorResponse(response)) {
+ throw createError(response, "Failed host name lookup");
+ } else {
+ return response.skip(1).map((result) {
+ var type = new InternetAddressType._from(result[0]);
+ return new _InternetAddress(type, result[1], host, result[2]);
+ }).toList();
+ }
+ });
}
- static Future<_NativeSocket> bind(String address,
+ static Future<_NativeSocket> connect(host, int port) {
+ return new Future.value(host)
+ .then((host) {
+ if (host is _InternetAddress) return host;
+ return lookup(host)
+ .then((list) {
+ if (list.length == 0) {
+ throw createError(response, "Failed host name lookup");
+ }
+ return list[0];
+ });
+ })
+ .then((address) {
+ ensureSocketService();
+ var socket = new _NativeSocket.normal();
+ socket.address = address;
+ var result = socket.nativeCreateConnect(
+ address._sockaddr_storage, port);
+ if (result is OSError) {
+ throw createError(result, "Connection failed");
+ } else {
+ var completer = new Completer();
+ // Setup handlers for receiving the first write event which
+ // indicate that the socket is fully connected.
+ socket.setHandlers(
+ write: () {
+ socket.setListening(read: false, write: false);
+ completer.complete(socket);
+ },
+ error: (e) {
+ socket.close();
+ completer.completeError(createError(e, "Connection failed"));
+ }
+ );
+ socket.setListening(read: false, write: true);
+ return completer.future;
+ }
+ });
+ }
+
+ static Future<_NativeSocket> bind(host,
int port,
int backlog) {
- var socket = new _NativeSocket.listen();
- socket.localHost = address;
- var result = socket.nativeCreateBindListen(address, port, backlog);
- if (result is OSError) {
- return new Future.error(
- new SocketIOException("Failed to create server socket", result));
- }
- if (port != 0) socket.localPort = port;
- return new Future.value(socket);
+ return new Future.value(host)
+ .then((host) {
+ if (host is _InternetAddress) return host;
+ return lookup(host)
+ .then((list) {
+ if (list.length == 0) {
+ throw createError(response, "Failed host name lookup");
+ }
+ return list[0];
+ });
+ })
+ .then((address) {
+ var socket = new _NativeSocket.listen();
+ socket.address = address;
+ var result = socket.nativeCreateBindListen(address._sockaddr_storage,
+ port,
+ backlog);
+ if (result is OSError) {
+ throw new SocketIOException(
+ "Failed to create server socket", result);
+ }
+ if (port != 0) socket.localPort = port;
+ return socket;
+ });
}
_NativeSocket.normal() : typeFlags = TYPE_NORMAL_SOCKET {
@@ -194,6 +256,8 @@
_NativeSocket accept() {
var socket = new _NativeSocket.normal();
if (nativeAccept(socket) != true) return null;
+ socket.localPort = localPort;
+ socket.address = address;
return socket;
}
@@ -206,8 +270,6 @@
return nativeGetRemotePeer()[1];
}
- String get host => localHost;
-
String get remoteHost {
return nativeGetRemotePeer()[0];
}
@@ -409,8 +471,9 @@
nativeRead(int len) native "Socket_Read";
nativeWrite(List<int> buffer, int offset, int bytes)
native "Socket_WriteList";
- nativeCreateConnect(String host, int port) native "Socket_CreateConnect";
- nativeCreateBindListen(String address, int port, int backlog)
+ nativeCreateConnect(List<int> addr,
+ int port) native "Socket_CreateConnect";
+ nativeCreateBindListen(List<int> addr, int port, int backlog)
native "ServerSocket_CreateBindListen";
nativeAccept(_NativeSocket socket) native "ServerSocket_Accept";
int nativeGetPort() native "Socket_GetPort";
@@ -427,7 +490,7 @@
final _NativeSocket _socket;
StreamController<RawSocket> _controller;
- static Future<_RawServerSocket> bind(String address,
+ static Future<_RawServerSocket> bind(address,
int port,
int backlog) {
if (port < 0 || port > 0xFFFF)
@@ -503,7 +566,7 @@
bool _readEventsEnabled = true;
bool _writeEventsEnabled = true;
- static Future<RawSocket> connect(String host, int port) {
+ static Future<RawSocket> connect(host, int port) {
return _NativeSocket.connect(host, port)
.then((socket) => new _RawSocket(socket));
}
@@ -571,7 +634,7 @@
int get remotePort => _socket.remotePort;
- String get host => _socket.host;
+ InternetAddress get address => _socket.address;
String get remoteHost => _socket.remoteHost;
@@ -621,7 +684,7 @@
patch class ServerSocket {
- /* patch */ static Future<ServerSocket> bind([String address = "127.0.0.1",
+ /* patch */ static Future<ServerSocket> bind([address = "127.0.0.1",
int port = 0,
int backlog = 0]) {
return _ServerSocket.bind(address, port, backlog);
@@ -632,7 +695,7 @@
implements ServerSocket {
final _socket;
- static Future<_ServerSocket> bind(String address,
+ static Future<_ServerSocket> bind(address,
int port,
int backlog) {
return _RawServerSocket.bind(address, port, backlog)
@@ -659,7 +722,7 @@
patch class Socket {
- /* patch */ static Future<Socket> connect(String host, int port) {
+ /* patch */ static Future<Socket> connect(host, int port) {
return RawSocket.connect(host, port).then(
(socket) => new _Socket(socket));
}
@@ -771,6 +834,7 @@
_SocketStreamConsumer _consumer;
IOSink _sink;
var _subscription;
+ var _detachReady;
_Socket(RawSocket this._raw) {
_controller = new StreamController<List<int>>(
@@ -851,6 +915,17 @@
String get remoteHost => _raw.remoteHost;
int get remotePort => _raw.remotePort;
+ Future _detachRaw() {
+ _detachReady = new Completer();
+ _sink.close();
+ return _detachReady.future.then((_) {
+ assert(_consumer.buffer == null);
+ var raw = _raw;
+ _raw = null;
+ return [raw, _subscription];
+ });
+ }
+
// Ensure a subscription on the raw socket. Both the stream and the
// consumer needs a subscription as they share the error and done
// events from the raw socket.
@@ -938,9 +1013,13 @@
}
void _consumerDone() {
- if (_raw != null) {
- _raw.shutdown(SocketDirection.SEND);
- _disableWriteEvent();
+ if (_detachReady != null) {
+ _detachReady.complete(null);
+ } else {
+ if (_raw != null) {
+ _raw.shutdown(SocketDirection.SEND);
+ _disableWriteEvent();
+ }
}
}
}
diff --git a/runtime/bin/socket_win.cc b/runtime/bin/socket_win.cc
index 54f6639..12b76d8 100644
--- a/runtime/bin/socket_win.cc
+++ b/runtime/bin/socket_win.cc
@@ -11,6 +11,31 @@
#include "bin/log.h"
#include "bin/socket.h"
+
+namespace dart {
+namespace bin {
+
+SocketAddress::SocketAddress(struct addrinfo* addrinfo) {
+ ASSERT(INET6_ADDRSTRLEN >= INET_ADDRSTRLEN);
+ RawAddr* raw = reinterpret_cast<RawAddr*>(addrinfo->ai_addr);
+
+ // Clear the port before calling WSAAddressToString as WSAAddressToString
+ // includes the port in the formatted string.
+ DWORD len = INET6_ADDRSTRLEN;
+ int err = WSAAddressToStringA(&raw->addr,
+ sizeof(RawAddr),
+ NULL,
+ as_string_,
+ &len);
+
+ if (err != 0) {
+ as_string_[0] = 0;
+ }
+ memmove(reinterpret_cast<void *>(&addr_),
+ addrinfo->ai_addr,
+ addrinfo->ai_addrlen);
+}
+
bool Socket::Initialize() {
static bool socket_initialized = false;
if (socket_initialized) return true;
@@ -47,36 +72,36 @@
intptr_t Socket::GetPort(intptr_t fd) {
ASSERT(reinterpret_cast<Handle*>(fd)->is_socket());
SocketHandle* socket_handle = reinterpret_cast<SocketHandle*>(fd);
- struct sockaddr_in socket_address;
- socklen_t size = sizeof(socket_address);
+ RawAddr raw;
+ socklen_t size = sizeof(raw);
if (getsockname(socket_handle->socket(),
- reinterpret_cast<struct sockaddr *>(&socket_address),
- &size)) {
- Log::PrintErr("Error getsockname: %s\n", strerror(errno));
+ &raw.addr,
+ &size) == SOCKET_ERROR) {
+ Log::PrintErr("Error getsockname: %d\n", WSAGetLastError());
return 0;
}
- return ntohs(socket_address.sin_port);
+ return SocketAddress::GetAddrPort(&raw);
}
bool Socket::GetRemotePeer(intptr_t fd, char *host, intptr_t *port) {
ASSERT(reinterpret_cast<Handle*>(fd)->is_socket());
SocketHandle* socket_handle = reinterpret_cast<SocketHandle*>(fd);
- struct sockaddr_in socket_address;
- socklen_t size = sizeof(socket_address);
+ RawAddr raw;
+ socklen_t size = sizeof(raw);
if (getpeername(socket_handle->socket(),
- reinterpret_cast<struct sockaddr *>(&socket_address),
+ &raw.addr,
&size)) {
- Log::PrintErr("Error getpeername: %s\n", strerror(errno));
+ Log::PrintErr("Error getpeername: %d\n", WSAGetLastError());
return false;
}
- *port = ntohs(socket_address.sin_port);
+ *port = SocketAddress::GetAddrPort(&raw);
// Clear the port before calling WSAAddressToString as WSAAddressToString
// includes the port in the formatted string.
- socket_address.sin_port = 0;
- DWORD len = INET_ADDRSTRLEN;
- int err = WSAAddressToStringA(reinterpret_cast<LPSOCKADDR>(&socket_address),
- sizeof(socket_address),
+ SocketAddress::SetAddrPort(&raw, 0);
+ DWORD len = INET6_ADDRSTRLEN;
+ int err = WSAAddressToStringA(&raw.addr,
+ sizeof(raw),
NULL,
host,
&len);
@@ -87,8 +112,8 @@
return true;
}
-intptr_t Socket::CreateConnect(const char* host, const intptr_t port) {
- SOCKET s = socket(AF_INET, SOCK_STREAM, 0);
+intptr_t Socket::CreateConnect(RawAddr addr, const intptr_t port) {
+ SOCKET s = socket(addr.ss.ss_family, SOCK_STREAM, 0);
if (s == INVALID_SOCKET) {
return -1;
}
@@ -105,29 +130,11 @@
FATAL("Failed setting SO_LINGER on socket");
}
- // Perform a name lookup for an IPv4 address.
- struct addrinfo hints;
- memset(&hints, 0, sizeof(hints));
- hints.ai_family = AF_INET;
- hints.ai_socktype = SOCK_STREAM;
- hints.ai_protocol = IPPROTO_TCP;
- struct addrinfo* result = NULL;
- status = getaddrinfo(host, 0, &hints, &result);
- if (status != NO_ERROR) {
- return -1;
- }
-
- // Copy IPv4 address and set the port.
- struct sockaddr_in server_address;
- memcpy(&server_address,
- reinterpret_cast<sockaddr_in *>(result->ai_addr),
- sizeof(server_address));
- server_address.sin_port = htons(port);
- freeaddrinfo(result); // Free data allocated by getaddrinfo.
+ SocketAddress::SetAddrPort(&addr, port);
status = connect(
s,
- reinterpret_cast<struct sockaddr*>(&server_address),
- sizeof(server_address));
+ &addr.addr,
+ SocketAddress::GetAddrLength(addr));
if (status == SOCKET_ERROR) {
DWORD rc = WSAGetLastError();
closesocket(s);
@@ -192,13 +199,17 @@
}
-const char* Socket::LookupIPv4Address(char* host, OSError** os_error) {
- // Perform a name lookup for an IPv4 address.
+SocketAddresses* Socket::LookupAddress(const char* host,
+ int type,
+ OSError** os_error) {
Initialize();
+
+ // Perform a name lookup for a host name.
struct addrinfo hints;
memset(&hints, 0, sizeof(hints));
- hints.ai_family = AF_INET;
+ hints.ai_family = SocketAddress::FromType(type);
hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = 0;
hints.ai_protocol = IPPROTO_TCP;
struct addrinfo* info = NULL;
int status = getaddrinfo(host, 0, &hints, &info);
@@ -209,35 +220,27 @@
*os_error = new OSError();
return NULL;
}
- // Convert the address into IPv4 dotted decimal notation.
- char* buffer = reinterpret_cast<char*>(malloc(INET_ADDRSTRLEN));
- sockaddr_in *sockaddr = reinterpret_cast<sockaddr_in *>(info->ai_addr);
-
- // Clear the port before calling WSAAddressToString as WSAAddressToString
- // includes the port in the formatted string.
- DWORD len = INET_ADDRSTRLEN;
- int err = WSAAddressToStringA(reinterpret_cast<LPSOCKADDR>(sockaddr),
- sizeof(sockaddr_in),
- NULL,
- buffer,
- &len);
- if (err != 0) {
- free(buffer);
- return NULL;
+ intptr_t count = 0;
+ for (struct addrinfo* c = info; c != NULL; c = c->ai_next) {
+ if (c->ai_family == AF_INET || c->ai_family == AF_INET6) count++;
}
- return buffer;
+ SocketAddresses* addresses = new SocketAddresses(count);
+ intptr_t i = 0;
+ for (struct addrinfo* c = info; c != NULL; c = c->ai_next) {
+ if (c->ai_family == AF_INET || c->ai_family == AF_INET6) {
+ addresses->SetAt(i, new SocketAddress(c));
+ i++;
+ }
+ }
+ freeaddrinfo(info);
+ return addresses;
}
-intptr_t ServerSocket::CreateBindListen(const char* host,
+intptr_t ServerSocket::CreateBindListen(RawAddr addr,
intptr_t port,
intptr_t backlog) {
- unsigned long socket_addr = inet_addr(host); // NOLINT
- if (socket_addr == INADDR_NONE) {
- return -5;
- }
-
- SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ SOCKET s = socket(addr.ss.ss_family, SOCK_STREAM, IPPROTO_TCP);
if (s == INVALID_SOCKET) {
return -1;
}
@@ -255,14 +258,19 @@
return -1;
}
- sockaddr_in addr;
- memset(&addr, 0, sizeof(addr));
- addr.sin_family = AF_INET;
- addr.sin_addr.s_addr = socket_addr;
- addr.sin_port = htons(port);
+ if (addr.ss.ss_family == AF_INET6) {
+ optval = false;
+ setsockopt(s,
+ IPPROTO_IPV6,
+ IPV6_V6ONLY,
+ reinterpret_cast<const char*>(&optval),
+ sizeof(optval));
+ }
+
+ SocketAddress::SetAddrPort(&addr, port);
status = bind(s,
- reinterpret_cast<struct sockaddr *>(&addr),
- sizeof(addr));
+ &addr.addr,
+ SocketAddress::GetAddrLength(addr));
if (status == SOCKET_ERROR) {
DWORD rc = WSAGetLastError();
closesocket(s);
@@ -321,4 +329,7 @@
sizeof(on)) == 0;
}
+} // namespace bin
+} // namespace dart
+
#endif // defined(TARGET_OS_WINDOWS)
diff --git a/runtime/bin/test_extension.cc b/runtime/bin/test_extension.cc
index c1da730..327f015 100644
--- a/runtime/bin/test_extension.cc
+++ b/runtime/bin/test_extension.cc
@@ -5,6 +5,10 @@
#include "include/dart_api.h"
+
+namespace dart {
+namespace bin {
+
Dart_NativeFunction ResolveName(Dart_Handle name, int argc);
DART_EXPORT Dart_Handle test_extension_Init(Dart_Handle parent_library) {
@@ -50,3 +54,6 @@
}
return NULL;
}
+
+} // namespace bin
+} // namespace dart
diff --git a/runtime/bin/thread.h b/runtime/bin/thread.h
index a3c5a92..23091f0 100644
--- a/runtime/bin/thread.h
+++ b/runtime/bin/thread.h
@@ -8,6 +8,10 @@
#include "platform/assert.h"
#include "platform/thread.h"
+
+namespace dart {
+namespace bin {
+
class MutexLocker {
public:
explicit MutexLocker(dart::Mutex* mutex) : mutex_(mutex) {
@@ -55,4 +59,7 @@
DISALLOW_COPY_AND_ASSIGN(MonitorLocker);
};
+} // namespace bin
+} // namespace dart
+
#endif // BIN_THREAD_H_
diff --git a/runtime/bin/utils.h b/runtime/bin/utils.h
index c0aab6b..60beef1 100644
--- a/runtime/bin/utils.h
+++ b/runtime/bin/utils.h
@@ -11,6 +11,10 @@
#include "include/dart_api.h"
#include "platform/globals.h"
+
+namespace dart {
+namespace bin {
+
class OSError {
public:
enum SubSystem {
@@ -85,4 +89,7 @@
static void Sleep(int64_t millis);
};
+} // namespace bin
+} // namespace dart
+
#endif // BIN_UTILS_H_
diff --git a/runtime/bin/utils_android.cc b/runtime/bin/utils_android.cc
index 180dc39..25022b5 100644
--- a/runtime/bin/utils_android.cc
+++ b/runtime/bin/utils_android.cc
@@ -12,6 +12,10 @@
#include "bin/utils.h"
#include "platform/assert.h"
+
+namespace dart {
+namespace bin {
+
OSError::OSError() : sub_system_(kSystem), code_(0), message_(NULL) {
set_sub_system(kSystem);
set_code(errno);
@@ -91,4 +95,7 @@
usleep(millis * 1000);
}
+} // namespace bin
+} // namespace dart
+
#endif // defined(TARGET_OS_ANDROID)
diff --git a/runtime/bin/utils_linux.cc b/runtime/bin/utils_linux.cc
index 3defd39..e8230c8 100644
--- a/runtime/bin/utils_linux.cc
+++ b/runtime/bin/utils_linux.cc
@@ -12,6 +12,10 @@
#include "bin/utils.h"
#include "platform/assert.h"
+
+namespace dart {
+namespace bin {
+
OSError::OSError() : sub_system_(kSystem), code_(0), message_(NULL) {
set_sub_system(kSystem);
set_code(errno);
@@ -91,4 +95,7 @@
usleep(millis * 1000);
}
+} // namespace bin
+} // namespace dart
+
#endif // defined(TARGET_OS_LINUX)
diff --git a/runtime/bin/utils_macos.cc b/runtime/bin/utils_macos.cc
index f717edd..69c738e 100644
--- a/runtime/bin/utils_macos.cc
+++ b/runtime/bin/utils_macos.cc
@@ -12,6 +12,10 @@
#include "bin/utils.h"
#include "platform/assert.h"
+
+namespace dart {
+namespace bin {
+
OSError::OSError() : sub_system_(kSystem), code_(0), message_(NULL) {
set_sub_system(kSystem);
set_code(errno);
@@ -91,4 +95,7 @@
usleep(millis * 1000);
}
+} // namespace bin
+} // namespace dart
+
#endif // defined(TARGET_OS_MACOS)
diff --git a/runtime/bin/utils_win.cc b/runtime/bin/utils_win.cc
index 6c25d5b..b926dd7 100644
--- a/runtime/bin/utils_win.cc
+++ b/runtime/bin/utils_win.cc
@@ -11,6 +11,10 @@
#include "bin/utils.h"
#include "bin/log.h"
+
+namespace dart {
+namespace bin {
+
static void FormatMessageIntoBuffer(DWORD code,
wchar_t* buffer,
int buffer_length) {
@@ -145,4 +149,7 @@
::Sleep(millis);
}
+} // namespace bin
+} // namespace dart
+
#endif // defined(TARGET_OS_WINDOWS)
diff --git a/runtime/bin/vmstats.h b/runtime/bin/vmstats.h
index 14716e8..6143b95 100644
--- a/runtime/bin/vmstats.h
+++ b/runtime/bin/vmstats.h
@@ -7,6 +7,10 @@
#include "include/dart_api.h"
+
+namespace dart {
+namespace bin {
+
/**
* A VM status callback. Status plug-ins implement and register this
* function using Dart_RegisterStatusPlugin. When Dart_GetVMStatus is
@@ -34,4 +38,7 @@
*/
DART_EXPORT int Dart_RegisterVmStatusPlugin(Dart_VmStatusCallback callback);
+} // namespace bin
+} // namespace dart
+
#endif // BIN_VMSTATS_H_
diff --git a/runtime/bin/vmstats_impl.cc b/runtime/bin/vmstats_impl.cc
index d2e0af6..b73fe64 100644
--- a/runtime/bin/vmstats_impl.cc
+++ b/runtime/bin/vmstats_impl.cc
@@ -14,6 +14,10 @@
#include "include/dart_debugger_api.h"
#include "platform/json.h"
+
+namespace dart {
+namespace bin {
+
#define BUFSIZE 8192
#define RETRY_PAUSE 100 // milliseconds
@@ -55,15 +59,15 @@
// TODO(tball): allow host to be specified.
char* host = const_cast<char*>(DEFAULT_HOST);
OSError* os_error;
- const char* host_ip = Socket::LookupIPv4Address(host, &os_error);
- if (host_ip == NULL) {
+ SocketAddresses* addresses = Socket::LookupAddress(host, -1, &os_error);
+ if (addresses == NULL) {
Log::PrintErr("Failed IP lookup of VmStats host %s: %s\n",
host, os_error->message());
return;
}
-
const intptr_t BACKLOG = 128; // Default value from HttpServer.dart
- int64_t address = ServerSocket::CreateBindListen(host_ip, port, BACKLOG);
+ int64_t address = ServerSocket::CreateBindListen(
+ addresses->GetAt(0)->addr(), port, BACKLOG);
if (address < 0) {
Log::PrintErr("Failed binding VmStats socket: %s:%d\n", host, port);
return;
@@ -472,3 +476,6 @@
}
return NULL;
}
+
+} // namespace bin
+} // namespace dart
diff --git a/runtime/bin/vmstats_impl.h b/runtime/bin/vmstats_impl.h
index a348a7a..ed92e87 100644
--- a/runtime/bin/vmstats_impl.h
+++ b/runtime/bin/vmstats_impl.h
@@ -12,6 +12,10 @@
#include "bin/isolate_data.h"
#include "platform/thread.h"
+
+namespace dart {
+namespace bin {
+
// VmStats is a HTTP singleton service that reports status information
// of the running VM.
@@ -105,4 +109,8 @@
DISALLOW_COPY_AND_ASSIGN(VmStatusService);
};
+
+} // namespace bin
+} // namespace dart
+
#endif // BIN_VMSTATS_IMPL_H_
diff --git a/runtime/bin/vmstats_impl_android.cc b/runtime/bin/vmstats_impl_android.cc
index e460e70..5baa0d4 100644
--- a/runtime/bin/vmstats_impl_android.cc
+++ b/runtime/bin/vmstats_impl_android.cc
@@ -10,6 +10,9 @@
#include <signal.h> // NOLINT
+namespace dart {
+namespace bin {
+
static void sig_handler(int sig, siginfo_t* siginfo, void*) {
if (sig == SIGQUIT) {
VmStats::DumpStack();
@@ -29,5 +32,8 @@
}
}
+} // namespace bin
+} // namespace dart
+
#endif // defined(TARGET_OS_ANDROID)
diff --git a/runtime/bin/vmstats_impl_linux.cc b/runtime/bin/vmstats_impl_linux.cc
index ae2277a..93efbf2 100644
--- a/runtime/bin/vmstats_impl_linux.cc
+++ b/runtime/bin/vmstats_impl_linux.cc
@@ -10,6 +10,9 @@
#include <signal.h> // NOLINT
+namespace dart {
+namespace bin {
+
static void sig_handler(int sig, siginfo_t* siginfo, void*) {
if (sig == SIGQUIT) {
VmStats::DumpStack();
@@ -29,5 +32,7 @@
}
}
-#endif // defined(TARGET_OS_LINUX)
+} // namespace bin
+} // namespace dart
+#endif // defined(TARGET_OS_LINUX)
diff --git a/runtime/bin/vmstats_impl_macos.cc b/runtime/bin/vmstats_impl_macos.cc
index 29686a1..23cf179 100644
--- a/runtime/bin/vmstats_impl_macos.cc
+++ b/runtime/bin/vmstats_impl_macos.cc
@@ -10,6 +10,9 @@
#include <signal.h> // NOLINT
+namespace dart {
+namespace bin {
+
static void sig_handler(int sig, siginfo_t* siginfo, void*) {
if (sig == SIGQUIT) {
VmStats::DumpStack();
@@ -29,5 +32,7 @@
}
}
-#endif // defined(TARGET_OS_MACOS)
+} // namespace bin
+} // namespace dart
+#endif // defined(TARGET_OS_MACOS)
diff --git a/runtime/bin/vmstats_impl_win.cc b/runtime/bin/vmstats_impl_win.cc
index 7ff384c..3157801 100644
--- a/runtime/bin/vmstats_impl_win.cc
+++ b/runtime/bin/vmstats_impl_win.cc
@@ -10,6 +10,9 @@
#include <signal.h> // NOLINT
+namespace dart {
+namespace bin {
+
static void sig_handler(int sig) {
if (sig == SIGBREAK) {
VmStats::DumpStack();
@@ -23,4 +26,7 @@
}
}
+} // namespace bin
+} // namespace dart
+
#endif // defined(TARGET_OS_WINDOWS)
diff --git a/runtime/dart-runtime.gyp b/runtime/dart-runtime.gyp
index db2f10f..7519576 100644
--- a/runtime/dart-runtime.gyp
+++ b/runtime/dart-runtime.gyp
@@ -11,8 +11,9 @@
'third_party/jscre/jscre.gypi',
],
'variables': {
+ 'gen_source_dir': '<(LIB_DIR)',
'version_in_cc_file': 'vm/version_in.cc',
- 'version_cc_file': '<(SHARED_INTERMEDIATE_DIR)/version.cc',
+ 'version_cc_file': '<(gen_source_dir)/version.cc',
# Disable the OpenGLUI embedder by default on desktop OSes. Note,
# to build this on the desktop, you need GLUT installed.
@@ -61,6 +62,7 @@
{
'target_name': 'generate_version_cc_file',
'type': 'none',
+ 'toolsets':['target','host'],
'dependencies': [
'libdart_dependency_helper',
],
@@ -94,8 +96,9 @@
{
'target_name': 'libdart_dependency_helper',
'type': 'executable',
+ 'toolsets':['target','host'],
# The dependencies here are the union of the dependencies of libdart and
- # libdart_withcore.
+ # libdart_withcore.
'dependencies': [
'libdart_lib_withcore',
'libdart_lib',
diff --git a/runtime/embedders/openglui/common/extension.cc b/runtime/embedders/openglui/common/extension.cc
index eb32a3d..3e1885e 100644
--- a/runtime/embedders/openglui/common/extension.cc
+++ b/runtime/embedders/openglui/common/extension.cc
@@ -875,9 +875,10 @@
if (values != NULL) {
Dart_CObject result;
- result.type = Dart_CObject::kUint8Array;
- result.value.as_byte_array.values = values;
- result.value.as_byte_array.length = length;
+ result.type = Dart_CObject::kTypedData;
+ result.value.as_typed_data.type = Dart_CObject::kUint8Array;
+ result.value.as_typed_data.values = values;
+ result.value.as_typed_data.length = length;
Dart_PostCObject(reply_port_id, &result);
free(values);
// It is OK that result is destroyed when function exits.
diff --git a/runtime/embedders/openglui/common/vm_glue.cc b/runtime/embedders/openglui/common/vm_glue.cc
index 77564e54..4836c8a 100644
--- a/runtime/embedders/openglui/common/vm_glue.cc
+++ b/runtime/embedders/openglui/common/vm_glue.cc
@@ -89,7 +89,7 @@
}
// Returns true on success, false on failure.
-bool VMGlue::CreateIsolateAndSetupHelper(const char* script_uri,
+Dart_Isolate VMGlue::CreateIsolateAndSetupHelper(const char* script_uri,
const char* main,
void* data,
char** error) {
@@ -98,7 +98,7 @@
Dart_CreateIsolate(script_uri, main, NULL, data, error);
if (isolate == NULL) {
LOGE("Couldn't create isolate: %s", *error);
- return false;
+ return NULL;
}
LOGI("Entering scope");
@@ -110,10 +110,10 @@
CHECK_RESULT(result);
Dart_ExitScope();
- return true;
+ return isolate;
}
-bool VMGlue::CreateIsolateAndSetup(const char* script_uri,
+Dart_Isolate VMGlue::CreateIsolateAndSetup(const char* script_uri,
const char* main,
void* data, char** error) {
return CreateIsolateAndSetupHelper(script_uri,
diff --git a/runtime/embedders/openglui/common/vm_glue.h b/runtime/embedders/openglui/common/vm_glue.h
index f340b56..8f84377 100644
--- a/runtime/embedders/openglui/common/vm_glue.h
+++ b/runtime/embedders/openglui/common/vm_glue.h
@@ -50,11 +50,11 @@
static Dart_Handle CheckError(Dart_Handle);
- static bool CreateIsolateAndSetupHelper(const char* script_uri,
+ static Dart_Isolate CreateIsolateAndSetupHelper(const char* script_uri,
const char* main,
void* data,
char** error);
- static bool CreateIsolateAndSetup(const char* script_uri,
+ static Dart_Isolate CreateIsolateAndSetup(const char* script_uri,
const char* main,
void* data, char** error);
static Dart_Handle LibraryTagHandler(Dart_LibraryTag tag,
diff --git a/runtime/embedders/openglui/openglui_embedder.gypi b/runtime/embedders/openglui/openglui_embedder.gypi
index dc66642..c3671ee 100644
--- a/runtime/embedders/openglui/openglui_embedder.gypi
+++ b/runtime/embedders/openglui/openglui_embedder.gypi
@@ -176,7 +176,7 @@
'targets': [
{
'target_name': 'emulator_embedder',
- 'type': 'shared_library',
+ 'type': 'static_library',
'dependencies': [
'skia-desktop',
'libdart_lib_withcore',
diff --git a/runtime/include/dart_api.h b/runtime/include/dart_api.h
index 5da6c6a..fcb839d 100755
--- a/runtime/include/dart_api.h
+++ b/runtime/include/dart_api.h
@@ -943,8 +943,8 @@
*
* The string encoding in the 'value.as_string' is UTF-8.
*
- * All the different types from dart:typeddata are exposed as type
- * kTypedData. The specific type from dart:typeddata is in the type
+ * All the different types from dart:typed_data are exposed as type
+ * kTypedData. The specific type from dart:typed_data is in the type
* field of the as_typed_data structure. The length in the
* as_typed_data structure is always in bytes.
*/
diff --git a/runtime/lib/array.dart b/runtime/lib/array.dart
index 1ebc5b7..bb68f0b 100644
--- a/runtime/lib/array.dart
+++ b/runtime/lib/array.dart
@@ -43,7 +43,7 @@
"Cannot remove element of a non-extendable array");
}
- void remove(Object element) {
+ bool remove(Object element) {
throw new UnsupportedError(
"Cannot remove element of a non-extendable array");
}
@@ -67,7 +67,7 @@
if (start < 0 || start > this.length) {
throw new RangeError.range(start, 0, this.length);
}
- if (end < 0 || end > this.length) {
+ if (end < start || end > this.length) {
throw new RangeError.range(end, start, this.length);
}
int length = end - start;
@@ -310,7 +310,7 @@
"Cannot modify an immutable array");
}
- void remove(Object element) {
+ bool remove(Object element) {
throw new UnsupportedError(
"Cannot modify an immutable array");
}
diff --git a/runtime/lib/core_patch.dart b/runtime/lib/core_patch.dart
index 0a27429..3f7f5d2 100644
--- a/runtime/lib/core_patch.dart
+++ b/runtime/lib/core_patch.dart
@@ -3,6 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
import "dart:math";
-import "dart:typeddata";
+import "dart:typed_data";
import "dart:_collection-dev" as _symbol_dev;
diff --git a/runtime/lib/errors_patch.dart b/runtime/lib/errors_patch.dart
index 37ab065..7d763e3 100644
--- a/runtime/lib/errors_patch.dart
+++ b/runtime/lib/errors_patch.dart
@@ -125,10 +125,14 @@
}
var args_mismatch = _existingArgumentNames != null;
StringBuffer msg_buf = new StringBuffer(_developerMessage(args_mismatch));
+ String receiver_str = Error.safeToString(_receiver);
+ if ("Type: class '::'" == receiver_str) {
+ receiver_str = "top-level";
+ }
if (!args_mismatch) {
msg_buf.write(
"NoSuchMethodError : method not found: '$_memberName'\n"
- "Receiver: ${Error.safeToString(_receiver)}\n"
+ "Receiver: $receiver_str\n"
"Arguments: [$actual_buf]");
} else {
String actualParameters = actual_buf.toString();
@@ -143,7 +147,7 @@
msg_buf.write(
"NoSuchMethodError: incorrect number of arguments passed to "
"method named '$_memberName'\n"
- "Receiver: ${Error.safeToString(_receiver)}\n"
+ "Receiver: $receiver_str\n"
"Tried calling: $_memberName($actualParameters)\n"
"Found: $_memberName($formalParameters)");
}
diff --git a/runtime/lib/growable_array.dart b/runtime/lib/growable_array.dart
index 1ebe8c2..f65380b 100644
--- a/runtime/lib/growable_array.dart
+++ b/runtime/lib/growable_array.dart
@@ -43,13 +43,14 @@
return result;
}
- void remove(Object element) {
+ bool remove(Object element) {
for (int i = 0; i < this.length; i++) {
if (this[i] == element) {
removeAt(i);
- return;
+ return true;
}
}
+ return false;
}
void insertAll(int index, Iterable<T> iterable) {
@@ -237,10 +238,10 @@
}
void forEach(f(T element)) {
- // TODO(srdjan): Use IterableMixinWorkaround.forEach(this, f);
- // Accessing the list directly improves DeltaBlue performance by 25%.
+ int initialLength = length;
for (int i = 0; i < length; i++) {
f(this[i]);
+ if (length != initialLength) throw new ConcurrentModificationError(this);
}
}
diff --git a/runtime/lib/integers.cc b/runtime/lib/integers.cc
index f6133dd..d368415 100644
--- a/runtime/lib/integers.cc
+++ b/runtime/lib/integers.cc
@@ -189,15 +189,11 @@
if (len > 0) {
const char* cstr = value.ToCString();
ASSERT(cstr != NULL);
- // Dart differences from strtol:
- // a) '+5' is not a valid integer (leading plus).
- if (cstr[0] != '+') {
- char* p_end = NULL;
- const int64_t int_value = strtol(cstr, &p_end, 10);
- if (p_end == (cstr + len)) {
- if ((Smi::kMinValue <= int_value) && (int_value <= Smi::kMaxValue)) {
- return Smi::New(int_value);
- }
+ char* p_end = NULL;
+ const int64_t int_value = strtoll(cstr, &p_end, 10);
+ if (p_end == (cstr + len)) {
+ if ((int_value != LLONG_MIN) && (int_value != LLONG_MAX)) {
+ return Integer::New(int_value);
}
}
}
diff --git a/runtime/lib/integers_patch.dart b/runtime/lib/integers_patch.dart
index de4abdb..05d47cf 100644
--- a/runtime/lib/integers_patch.dart
+++ b/runtime/lib/integers_patch.dart
@@ -6,7 +6,63 @@
// VM implementation of int.
patch class int {
- static int _parse(String str) native "Integer_parse";
+
+ static bool _isWhitespace(int codePoint) {
+ return
+ (codePoint == 32) || // Space.
+ ((9 <= codePoint) && (codePoint <= 13)); // CR, LF, TAB, etc.
+ }
+
+ static int _tryParseSmi(String str) {
+ if (str.isEmpty) return null;
+ var ix = 0;
+ var endIx = str.length - 1;
+ // Find first and last non-whitespace.
+ while (ix <= endIx) {
+ if (!_isWhitespace(str.codeUnitAt(ix))) break;
+ ix++;
+ }
+ if (endIx < ix) {
+ return null; // Empty.
+ }
+ while (endIx > ix) {
+ if (!_isWhitespace(str.codeUnitAt(endIx))) break;
+ endIx--;
+ }
+
+ var isNegative = false;
+ var c = str.codeUnitAt(ix);
+ // Check for leading '+' or '-'.
+ if ((c == 0x2b) || (c == 0x2d)) {
+ ix++;
+ isNegative = (c == 0x2d);
+ if (ix > endIx) {
+ return null; // Empty.
+ }
+ }
+ if ((endIx - ix) >= 9) {
+ return null; // May not fit into a Smi.
+ }
+ var result = 0;
+ for (int i = ix; i <= endIx; i++) {
+ var c = str.codeUnitAt(i) - 0x30;
+ if ((c > 9) || (c < 0)) {
+ return null;
+ }
+ result = result * 10 + c;
+ }
+ return isNegative ? -result : result;
+ }
+
+ static int _parse(String str) {
+ int res = _tryParseSmi(str);
+ if (res == null) {
+ res = _native_parse(str);
+ }
+ return res;
+ }
+
+ static int _native_parse(String str) native "Integer_parse";
static int _throwFormatException(String source) {
throw new FormatException(source);
diff --git a/runtime/lib/math_patch.dart b/runtime/lib/math_patch.dart
index d17d82e..5682bec 100644
--- a/runtime/lib/math_patch.dart
+++ b/runtime/lib/math_patch.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 "dart:typeddata";
+import "dart:typed_data";
// A VM patch of the dart:math library.
patch num pow(num x, num exponent) {
diff --git a/runtime/lib/mirrors.cc b/runtime/lib/mirrors.cc
index 31c1f4e..62c22e0 100644
--- a/runtime/lib/mirrors.cc
+++ b/runtime/lib/mirrors.cc
@@ -4,7 +4,6 @@
#include "include/dart_api.h"
#include "include/dart_debugger_api.h"
-#include "platform/json.h"
#include "vm/dart_api_impl.h"
#include "vm/bootstrap_natives.h"
#include "vm/dart_entry.h"
@@ -272,7 +271,7 @@
if (Dart_IsLibrary(target)) {
Dart_Handle cls_name = NewString("_LazyLibraryMirror");
Dart_Handle cls = Dart_GetClass(MirrorLib(), cls_name);
- Dart_Handle args[] = { Dart_LibraryName(target) };
+ Dart_Handle args[] = { Dart_LibraryUrl(target) };
return Dart_New(cls, Dart_Null(), ARRAY_SIZE(args), args);
}
@@ -296,13 +295,13 @@
Dart_Handle cls_name = NewString("_LazyTypeMirror");
Dart_Handle cls = Dart_GetClass(MirrorLib(), cls_name);
Dart_Handle lib = Dart_ClassGetLibrary(target);
- Dart_Handle lib_name;
+ Dart_Handle lib_url;
if (Dart_IsNull(lib)) {
- lib_name = Dart_Null();
+ lib_url = Dart_Null();
} else {
- lib_name = Dart_LibraryName(lib);
+ lib_url = Dart_LibraryUrl(lib);
}
- Dart_Handle args[] = { lib_name, Dart_ClassName(target) };
+ Dart_Handle args[] = { lib_url, Dart_ClassName(target) };
return Dart_New(cls, Dart_Null(), ARRAY_SIZE(args), args);
}
}
@@ -871,13 +870,11 @@
if (Dart_IsError(lib)) {
return lib;
}
- Dart_Handle lib_key = Dart_LibraryName(lib);
Dart_Handle lib_mirror = CreateLibraryMirror(lib);
if (Dart_IsError(lib_mirror)) {
return lib_mirror;
}
- // TODO(turnidge): Check for duplicate library names.
- result = MapAdd(map, lib_key, lib_mirror);
+ result = MapAdd(map, lib_url, lib_mirror);
}
return map;
}
diff --git a/runtime/lib/mirrors_impl.dart b/runtime/lib/mirrors_impl.dart
index 4546ab0..614e5589 100644
--- a/runtime/lib/mirrors_impl.dart
+++ b/runtime/lib/mirrors_impl.dart
@@ -62,14 +62,21 @@
return buf.toString();
}
-class _LocalMirrorSystemImpl implements MirrorSystem {
- // TODO(ahe): [libraries] should be Map<Uri, LibraryMirror>.
+Map<Uri, LibraryMirror> _createLibrariesMap(Map<String, LibraryMirror> map) {
+ var result = new Map<Uri, LibraryMirror>();
+ map.forEach((String url, LibraryMirror mirror) {
+ result[Uri.parse(url)] = mirror;
+ });
+ return result;
+}
+
+class _LocalMirrorSystemImpl extends MirrorSystem {
// Change parameter back to "this.libraries" when native code is changed.
_LocalMirrorSystemImpl(Map<String, LibraryMirror> libraries, this.isolate)
- : _functionTypes = new Map<String, FunctionTypeMirror>(),
- this.libraries = _convertStringToSymbolMap(libraries);
+ : this.libraries = _createLibrariesMap(libraries),
+ _functionTypes = new Map<String, FunctionTypeMirror>();
- final Map<Symbol, LibraryMirror> libraries;
+ final Map<Uri, LibraryMirror> libraries;
final IsolateMirror isolate;
TypeMirror _dynamicType = null;
@@ -401,12 +408,11 @@
}
class _LazyTypeMirror {
- _LazyTypeMirror(String libraryName, String typeName)
- : this.libraryName = _s(libraryName),
- this.typeName = _s(typeName);
+ _LazyTypeMirror(String this.libraryUrl, String typeName)
+ : this.typeName = _s(typeName);
TypeMirror resolve(MirrorSystem mirrors) {
- if (libraryName == null) {
+ if (libraryUrl == null) {
if (typeName == const Symbol('dynamic')) {
return mirrors.dynamicType;
} else if (typeName == const Symbol('void')) {
@@ -416,7 +422,7 @@
"Mirror for type '$typeName' is not implemented");
}
}
- var resolved = mirrors.libraries[libraryName].members[typeName];
+ var resolved = mirrors.libraries[Uri.parse(libraryUrl)].members[typeName];
if (resolved == null) {
throw new UnimplementedError(
"Mirror for type '$typeName' is not implemented");
@@ -424,7 +430,7 @@
return resolved;
}
- final Symbol libraryName;
+ final String libraryUrl;
final Symbol typeName;
}
@@ -758,24 +764,24 @@
class _LazyLibraryMirror {
- _LazyLibraryMirror(String libraryName)
- : this.libraryName = _s(libraryName);
+ _LazyLibraryMirror(String this.libraryUrl);
LibraryMirror resolve(MirrorSystem mirrors) {
- return mirrors.libraries[libraryName];
+ return mirrors.libraries[Uri.parse(libraryUrl)];
}
- final Symbol libraryName;
+ final String libraryUrl;
}
class _LocalLibraryMirrorImpl extends _LocalObjectMirrorImpl
implements LibraryMirror {
_LocalLibraryMirrorImpl(ref,
String simpleName,
- this.url,
+ String url,
Map<String, Mirror> members)
: this.simpleName = _s(simpleName),
this.members = _convertStringToSymbolMap(members),
+ this.uri = Uri.parse(url),
super(ref);
final Symbol simpleName;
@@ -797,7 +803,7 @@
'LibraryMirror.location is not implemented');
}
- final String url;
+ final Uri uri;
final Map<Symbol, Mirror> members;
Map<Symbol, ClassMirror> _classes = null;
diff --git a/runtime/lib/simd128.cc b/runtime/lib/simd128.cc
index 25e8db7..81894fe 100644
--- a/runtime/lib/simd128.cc
+++ b/runtime/lib/simd128.cc
@@ -26,6 +26,15 @@
}
+DEFINE_NATIVE_ENTRY(Float32x4_splat, 2) {
+ ASSERT(AbstractTypeArguments::CheckedHandle(
+ arguments->NativeArgAt(0)).IsNull());
+ GET_NON_NULL_NATIVE_ARGUMENT(Double, v, arguments->NativeArgAt(1));
+ float _v = v.value();
+ return Float32x4::New(_v, _v, _v, _v);
+}
+
+
DEFINE_NATIVE_ENTRY(Float32x4_zero, 1) {
ASSERT(AbstractTypeArguments::CheckedHandle(
arguments->NativeArgAt(0)).IsNull());
diff --git a/runtime/lib/typeddata.cc b/runtime/lib/typed_data.cc
similarity index 92%
rename from runtime/lib/typeddata.cc
rename to runtime/lib/typed_data.cc
index 29e7af3..4a47d71 100644
--- a/runtime/lib/typeddata.cc
+++ b/runtime/lib/typed_data.cc
@@ -78,25 +78,32 @@
return Integer::null();
}
-
-#define COPY_DATA(type, dst, src) \
- const type& dst_array = type::Cast(dst); \
- const type& src_array = type::Cast(src); \
- intptr_t element_size_in_bytes = dst_array.ElementSizeInBytes(); \
- intptr_t length_in_bytes = length.Value() * element_size_in_bytes; \
- intptr_t src_offset_in_bytes = src_start.Value() * element_size_in_bytes; \
- intptr_t dst_offset_in_bytes = dst_start.Value() * element_size_in_bytes; \
- SetRangeCheck(src_offset_in_bytes, \
- length_in_bytes, \
- src_array.LengthInBytes(), \
- element_size_in_bytes); \
- SetRangeCheck(dst_offset_in_bytes, \
- length_in_bytes, \
- dst_array.LengthInBytes(), \
- element_size_in_bytes); \
- type::Copy(dst_array, dst_offset_in_bytes, \
- src_array, src_offset_in_bytes, \
- length_in_bytes);
+template <typename DstType, typename SrcType>
+static RawBool* CopyData(const Instance& dst, const Instance& src,
+ const Smi& dst_start, const Smi& src_start,
+ const Smi& length) {
+ const DstType& dst_array = DstType::Cast(dst);
+ const SrcType& src_array = SrcType::Cast(src);
+ intptr_t element_size_in_bytes = dst_array.ElementSizeInBytes();
+ intptr_t dst_offset_in_bytes = dst_start.Value() * element_size_in_bytes;
+ intptr_t src_offset_in_bytes = src_start.Value() * element_size_in_bytes;
+ intptr_t length_in_bytes = length.Value() * element_size_in_bytes;
+ if (dst_array.ElementType() != src_array.ElementType()) {
+ return Bool::False().raw();
+ }
+ SetRangeCheck(src_offset_in_bytes,
+ length_in_bytes,
+ src_array.LengthInBytes(),
+ element_size_in_bytes);
+ SetRangeCheck(dst_offset_in_bytes,
+ length_in_bytes,
+ dst_array.LengthInBytes(),
+ element_size_in_bytes);
+ TypedData::Copy<DstType, SrcType>(dst_array, dst_offset_in_bytes,
+ src_array, src_offset_in_bytes,
+ length_in_bytes);
+ return Bool::True().raw();
+}
DEFINE_NATIVE_ENTRY(TypedData_setRange, 5) {
GET_NON_NULL_NATIVE_ARGUMENT(Instance, dst, arguments->NativeArgAt(0));
@@ -112,17 +119,22 @@
args.SetAt(0, error);
Exceptions::ThrowByType(Exceptions::kArgument, args);
}
- if ((dst.IsTypedData() || dst.IsExternalTypedData()) &&
- (dst.clazz() == src.clazz())) {
- if (dst.IsTypedData()) {
- ASSERT(src.IsTypedData());
- COPY_DATA(TypedData, dst, src);
- } else {
- ASSERT(src.IsExternalTypedData());
- ASSERT(dst.IsExternalTypedData());
- COPY_DATA(ExternalTypedData, dst, src);
+ if (dst.IsTypedData()) {
+ if (src.IsTypedData()) {
+ return CopyData<TypedData, TypedData>(
+ dst, src, dst_start, src_start, length);
+ } else if (src.IsExternalTypedData()) {
+ return CopyData<TypedData, ExternalTypedData>(
+ dst, src, dst_start, src_start, length);
}
- return Bool::True().raw();
+ } else if (dst.IsExternalTypedData()) {
+ if (src.IsTypedData()) {
+ return CopyData<ExternalTypedData, TypedData>(
+ dst, src, dst_start, src_start, length);
+ } else if (src.IsExternalTypedData()) {
+ return CopyData<ExternalTypedData, ExternalTypedData>(
+ dst, src, dst_start, src_start, length);
+ }
}
return Bool::False().raw();
}
diff --git a/runtime/lib/typeddata.dart b/runtime/lib/typed_data.dart
similarity index 95%
rename from runtime/lib/typeddata.dart
rename to runtime/lib/typed_data.dart
index ddf79f4..9fb8f15 100644
--- a/runtime/lib/typeddata.dart
+++ b/runtime/lib/typed_data.dart
@@ -240,6 +240,9 @@
/* patch */ factory Float32x4(double x, double y, double z, double w) {
return new _Float32x4(x, y, z, w);
}
+ /* patch */ factory Float32x4.splat(double v) {
+ return new _Float32x4.splat(v);
+ }
/* patch */ factory Float32x4.zero() {
return new _Float32x4.zero();
}
@@ -373,6 +376,16 @@
"Cannot add to a non-extendable array");
}
+ void insert(int index, value) {
+ throw new UnsupportedError(
+ "Cannot insert into a non-extendable array");
+ }
+
+ void insertAll(int index, Iterable values) {
+ throw new UnsupportedError(
+ "Cannot insert into a non-extendable array");
+ }
+
void sort([int compare(var a, var b)]) {
return IterableMixinWorkaround.sortList(this, compare);
}
@@ -395,7 +408,12 @@
"Cannot remove from a non-extendable array");
}
- void remove(Object element) {
+ bool remove(Object element) {
+ throw new UnsupportedError(
+ "Cannot remove from a non-extendable array");
+ }
+
+ bool removeAt(int index) {
throw new UnsupportedError(
"Cannot remove from a non-extendable array");
}
@@ -446,8 +464,8 @@
"Cannot remove from a non-extendable array");
}
- List toList() {
- return new List.from(this);
+ List toList({bool growable: true}) {
+ return new List.from(this, growable: growable);
}
Set toSet() {
@@ -2015,6 +2033,7 @@
class _Float32x4 implements Float32x4 {
factory _Float32x4(double x, double y, double z, double w)
native "Float32x4_fromDoubles";
+ factory _Float32x4.splat(double v) native "Float32x4_splat";
factory _Float32x4.zero() native "Float32x4_zero";
Float32x4 operator +(Float32x4 other) {
return _add(other);
@@ -2191,7 +2210,7 @@
class _TypedListView extends _TypedListBase implements TypedData {
_TypedListView(ByteBuffer _buffer, int _offset, int _length)
- : _typeddata = _buffer, // This assignment is type safe.
+ : _typedData = _buffer, // This assignment is type safe.
offsetInBytes = _offset,
length = _length {
}
@@ -2204,10 +2223,10 @@
}
ByteBuffer get buffer {
- return _typeddata.buffer;
+ return _typedData.buffer;
}
- final TypedData _typeddata;
+ final TypedData _typedData;
final int offsetInBytes;
final int length;
}
@@ -2232,7 +2251,7 @@
if (index < 0 || index >= length) {
_throwRangeError(index, length);
}
- return _typeddata._getInt8(offsetInBytes +
+ return _typedData._getInt8(offsetInBytes +
(index * Int8List.BYTES_PER_ELEMENT));
}
@@ -2240,7 +2259,7 @@
if (index < 0 || index >= length) {
_throwRangeError(index, length);
}
- _typeddata._setInt8(offsetInBytes + (index * Int8List.BYTES_PER_ELEMENT),
+ _typedData._setInt8(offsetInBytes + (index * Int8List.BYTES_PER_ELEMENT),
_toInt8(value));
}
@@ -2283,7 +2302,7 @@
if (index < 0 || index >= length) {
_throwRangeError(index, length);
}
- return _typeddata._getUint8(offsetInBytes +
+ return _typedData._getUint8(offsetInBytes +
(index * Uint8List.BYTES_PER_ELEMENT));
}
@@ -2291,7 +2310,7 @@
if (index < 0 || index >= length) {
_throwRangeError(index, length);
}
- _typeddata._setUint8(offsetInBytes + (index * Uint8List.BYTES_PER_ELEMENT),
+ _typedData._setUint8(offsetInBytes + (index * Uint8List.BYTES_PER_ELEMENT),
_toUint8(value));
}
@@ -2335,7 +2354,7 @@
if (index < 0 || index >= length) {
_throwRangeError(index, length);
}
- return _typeddata._getUint8(offsetInBytes +
+ return _typedData._getUint8(offsetInBytes +
(index * Uint8List.BYTES_PER_ELEMENT));
}
@@ -2343,7 +2362,7 @@
if (index < 0 || index >= length) {
_throwRangeError(index, length);
}
- _typeddata._setUint8(offsetInBytes + (index * Uint8List.BYTES_PER_ELEMENT),
+ _typedData._setUint8(offsetInBytes + (index * Uint8List.BYTES_PER_ELEMENT),
_toClampedUint8(value));
}
@@ -2386,7 +2405,7 @@
if (index < 0 || index >= length) {
_throwRangeError(index, length);
}
- return _typeddata._getInt16(offsetInBytes +
+ return _typedData._getInt16(offsetInBytes +
(index * Int16List.BYTES_PER_ELEMENT));
}
@@ -2394,7 +2413,7 @@
if (index < 0 || index >= length) {
_throwRangeError(index, length);
}
- _typeddata._setInt16(offsetInBytes + (index * Int16List.BYTES_PER_ELEMENT),
+ _typedData._setInt16(offsetInBytes + (index * Int16List.BYTES_PER_ELEMENT),
_toInt16(value));
}
@@ -2437,7 +2456,7 @@
if (index < 0 || index >= length) {
_throwRangeError(index, length);
}
- return _typeddata._getUint16(offsetInBytes +
+ return _typedData._getUint16(offsetInBytes +
(index * Uint16List.BYTES_PER_ELEMENT));
}
@@ -2445,7 +2464,7 @@
if (index < 0 || index >= length) {
_throwRangeError(index, length);
}
- _typeddata._setUint16(offsetInBytes + (index * Uint16List.BYTES_PER_ELEMENT),
+ _typedData._setUint16(offsetInBytes + (index * Uint16List.BYTES_PER_ELEMENT),
_toUint16(value));
}
@@ -2488,7 +2507,7 @@
if (index < 0 || index >= length) {
_throwRangeError(index, length);
}
- return _typeddata._getInt32(offsetInBytes +
+ return _typedData._getInt32(offsetInBytes +
(index * Int32List.BYTES_PER_ELEMENT));
}
@@ -2496,7 +2515,7 @@
if (index < 0 || index >= length) {
_throwRangeError(index, length);
}
- _typeddata._setInt32(offsetInBytes + (index * Int32List.BYTES_PER_ELEMENT),
+ _typedData._setInt32(offsetInBytes + (index * Int32List.BYTES_PER_ELEMENT),
_toInt32(value));
}
@@ -2539,7 +2558,7 @@
if (index < 0 || index >= length) {
_throwRangeError(index, length);
}
- return _typeddata._getUint32(offsetInBytes +
+ return _typedData._getUint32(offsetInBytes +
(index * Uint32List.BYTES_PER_ELEMENT));
}
@@ -2547,7 +2566,7 @@
if (index < 0 || index >= length) {
_throwRangeError(index, length);
}
- _typeddata._setUint32(offsetInBytes + (index * Uint32List.BYTES_PER_ELEMENT),
+ _typedData._setUint32(offsetInBytes + (index * Uint32List.BYTES_PER_ELEMENT),
_toUint32(value));
}
@@ -2590,7 +2609,7 @@
if (index < 0 || index >= length) {
_throwRangeError(index, length);
}
- return _typeddata._getInt64(offsetInBytes +
+ return _typedData._getInt64(offsetInBytes +
(index * Int64List.BYTES_PER_ELEMENT));
}
@@ -2598,7 +2617,7 @@
if (index < 0 || index >= length) {
_throwRangeError(index, length);
}
- _typeddata._setInt64(offsetInBytes + (index * Int64List.BYTES_PER_ELEMENT),
+ _typedData._setInt64(offsetInBytes + (index * Int64List.BYTES_PER_ELEMENT),
_toInt64(value));
}
@@ -2641,7 +2660,7 @@
if (index < 0 || index >= length) {
_throwRangeError(index, length);
}
- return _typeddata._getUint64(offsetInBytes +
+ return _typedData._getUint64(offsetInBytes +
(index * Uint64List.BYTES_PER_ELEMENT));
}
@@ -2649,7 +2668,7 @@
if (index < 0 || index >= length) {
_throwRangeError(index, length);
}
- _typeddata._setUint64(offsetInBytes + (index * Uint64List.BYTES_PER_ELEMENT),
+ _typedData._setUint64(offsetInBytes + (index * Uint64List.BYTES_PER_ELEMENT),
_toUint64(value));
}
@@ -2692,7 +2711,7 @@
if (index < 0 || index >= length) {
_throwRangeError(index, length);
}
- return _typeddata._getFloat32(offsetInBytes +
+ return _typedData._getFloat32(offsetInBytes +
(index * Float32List.BYTES_PER_ELEMENT));
}
@@ -2700,7 +2719,7 @@
if (index < 0 || index >= length) {
_throwRangeError(index, length);
}
- _typeddata._setFloat32(offsetInBytes +
+ _typedData._setFloat32(offsetInBytes +
(index * Float32List.BYTES_PER_ELEMENT), value);
}
@@ -2743,7 +2762,7 @@
if (index < 0 || index >= length) {
_throwRangeError(index, length);
}
- return _typeddata._getFloat64(offsetInBytes +
+ return _typedData._getFloat64(offsetInBytes +
(index * Float64List.BYTES_PER_ELEMENT));
}
@@ -2751,7 +2770,7 @@
if (index < 0 || index >= length) {
_throwRangeError(index, length);
}
- _typeddata._setFloat64(offsetInBytes +
+ _typedData._setFloat64(offsetInBytes +
(index * Float64List.BYTES_PER_ELEMENT), value);
}
@@ -2794,7 +2813,7 @@
if (index < 0 || index >= length) {
_throwRangeError(index, length);
}
- return _typeddata._getFloat32x4(offsetInBytes +
+ return _typedData._getFloat32x4(offsetInBytes +
(index * Float32x4List.BYTES_PER_ELEMENT));
}
@@ -2802,7 +2821,7 @@
if (index < 0 || index >= length) {
_throwRangeError(index, length);
}
- _typeddata._setFloat32x4(offsetInBytes +
+ _typedData._setFloat32x4(offsetInBytes +
(index * Float32x4List.BYTES_PER_ELEMENT), value);
}
@@ -2828,7 +2847,7 @@
class _ByteDataView implements ByteData {
_ByteDataView(ByteBuffer _buffer, int _offsetInBytes, int _lengthInBytes)
- : _typeddata = _buffer, // _buffer is guaranteed to be a TypedData here.
+ : _typedData = _buffer, // _buffer is guaranteed to be a TypedData here.
_offset = _offsetInBytes,
length = _lengthInBytes {
_rangeCheck(_buffer.lengthInBytes, _offset, length);
@@ -2838,7 +2857,7 @@
// Method(s) implementing TypedData interface.
ByteBuffer get buffer {
- return _typeddata.buffer;
+ return _typedData.buffer;
}
int get lengthInBytes {
@@ -2855,33 +2874,33 @@
if (byteOffset < 0 || byteOffset >= length) {
_throwRangeError(byteOffset, length);
}
- return _typeddata._getInt8(_offset + byteOffset);
+ return _typedData._getInt8(_offset + byteOffset);
}
void setInt8(int byteOffset, int value) {
if (byteOffset < 0 || byteOffset >= length) {
_throwRangeError(byteOffset, length);
}
- _typeddata._setInt8(_offset + byteOffset, _toInt8(value));
+ _typedData._setInt8(_offset + byteOffset, _toInt8(value));
}
int getUint8(int byteOffset) {
if (byteOffset < 0 || byteOffset >= length) {
_throwRangeError(byteOffset, length);
}
- return _typeddata._getUint8(_offset + byteOffset);
+ return _typedData._getUint8(_offset + byteOffset);
}
void setUint8(int byteOffset, int value) {
if (byteOffset < 0 || byteOffset >= length) {
_throwRangeError(byteOffset, length);
}
- _typeddata._setUint8(_offset + byteOffset, _toUint8(value));
+ _typedData._setUint8(_offset + byteOffset, _toUint8(value));
}
int getInt16(int byteOffset, [Endianness endian = Endianness.BIG_ENDIAN]) {
if (byteOffset < 0 || byteOffset >= length) {
_throwRangeError(byteOffset, length);
}
- var result = _typeddata._getInt16(_offset + byteOffset);
+ var result = _typedData._getInt16(_offset + byteOffset);
if (identical(endian, Endianness.HOST_ENDIAN)) {
return result;
}
@@ -2897,14 +2916,14 @@
if (!identical(endian, Endianness.HOST_ENDIAN)) {
set_value = _toEndianInt16(set_value, endian._littleEndian);
}
- _typeddata._setInt16(_offset + byteOffset, set_value);
+ _typedData._setInt16(_offset + byteOffset, set_value);
}
int getUint16(int byteOffset, [Endianness endian = Endianness.BIG_ENDIAN]) {
if (byteOffset < 0 || byteOffset >= length) {
_throwRangeError(byteOffset, length);
}
- var result = _typeddata._getUint16(_offset + byteOffset);
+ var result = _typedData._getUint16(_offset + byteOffset);
if (identical(endian, Endianness.HOST_ENDIAN)) {
return result;
}
@@ -2920,14 +2939,14 @@
if (!identical(endian, Endianness.HOST_ENDIAN)) {
set_value = _toEndianUint16(set_value, endian._littleEndian);
}
- _typeddata._setUint16(_offset + byteOffset, set_value);
+ _typedData._setUint16(_offset + byteOffset, set_value);
}
int getInt32(int byteOffset, [Endianness endian = Endianness.BIG_ENDIAN]) {
if (byteOffset < 0 || byteOffset >= length) {
_throwRangeError(byteOffset, length);
}
- var result = _typeddata._getInt32(_offset + byteOffset);
+ var result = _typedData._getInt32(_offset + byteOffset);
if (identical(endian, Endianness.HOST_ENDIAN)) {
return result;
}
@@ -2943,14 +2962,14 @@
if (!identical(endian, Endianness.HOST_ENDIAN)) {
set_value = _toEndianInt32(set_value, endian._littleEndian);
}
- _typeddata._setInt32(_offset + byteOffset, set_value);
+ _typedData._setInt32(_offset + byteOffset, set_value);
}
int getUint32(int byteOffset, [Endianness endian = Endianness.BIG_ENDIAN]) {
if (byteOffset < 0 || byteOffset >= length) {
_throwRangeError(byteOffset, length);
}
- var result = _typeddata._getUint32(_offset + byteOffset);
+ var result = _typedData._getUint32(_offset + byteOffset);
if (identical(endian, Endianness.HOST_ENDIAN)) {
return result;
}
@@ -2966,14 +2985,14 @@
if (!identical(endian, Endianness.HOST_ENDIAN)) {
set_value = _toEndianUint32(set_value, endian._littleEndian);
}
- _typeddata._setUint32(_offset + byteOffset, set_value);
+ _typedData._setUint32(_offset + byteOffset, set_value);
}
int getInt64(int byteOffset, [Endianness endian = Endianness.BIG_ENDIAN]) {
if (byteOffset < 0 || byteOffset >= length) {
_throwRangeError(byteOffset, length);
}
- var result = _typeddata._getInt64(_offset + byteOffset);
+ var result = _typedData._getInt64(_offset + byteOffset);
if (identical(endian, Endianness.HOST_ENDIAN)) {
return result;
}
@@ -2989,14 +3008,14 @@
if (!identical(endian, Endianness.HOST_ENDIAN)) {
set_value = _toEndianInt64(set_value, endian._littleEndian);
}
- _typeddata._setInt64(_offset + byteOffset, set_value);
+ _typedData._setInt64(_offset + byteOffset, set_value);
}
int getUint64(int byteOffset, [Endianness endian = Endianness.BIG_ENDIAN]) {
if (byteOffset < 0 || byteOffset >= length) {
_throwRangeError(byteOffset, length);
}
- var result = _typeddata._getUint64(_offset + byteOffset);
+ var result = _typedData._getUint64(_offset + byteOffset);
if (identical(endian, Endianness.HOST_ENDIAN)) {
return result;
}
@@ -3012,7 +3031,7 @@
if (!identical(endian, Endianness.HOST_ENDIAN)) {
set_value = _toEndianUint64(set_value, endian._littleEndian);
}
- _typeddata._setUint64(_offset + byteOffset, set_value);
+ _typedData._setUint64(_offset + byteOffset, set_value);
}
double getFloat32(int byteOffset,
@@ -3020,7 +3039,7 @@
if (byteOffset < 0 || byteOffset >= length) {
_throwRangeError(byteOffset, length);
}
- var result = _typeddata._getFloat32(_offset + byteOffset);
+ var result = _typedData._getFloat32(_offset + byteOffset);
if (identical(endian, Endianness.HOST_ENDIAN)) {
return result;
}
@@ -3036,7 +3055,7 @@
if (!identical(endian, Endianness.HOST_ENDIAN)) {
set_value = _toEndianFloat32(set_value, endian._littleEndian);
}
- _typeddata._setFloat32(_offset + byteOffset, set_value);
+ _typedData._setFloat32(_offset + byteOffset, set_value);
}
double getFloat64(int byteOffset,
@@ -3044,7 +3063,7 @@
if (byteOffset < 0 || byteOffset >= length) {
_throwRangeError(byteOffset, length);
}
- var result = _typeddata._getFloat64(_offset + byteOffset);
+ var result = _typedData._getFloat64(_offset + byteOffset);
if (identical(endian, Endianness.HOST_ENDIAN)) {
return result;
}
@@ -3060,7 +3079,7 @@
if (!identical(endian, Endianness.HOST_ENDIAN)) {
set_value = _toEndianFloat64(set_value, endian._littleEndian);
}
- _typeddata._setFloat64(_offset + byteOffset, set_value);
+ _typedData._setFloat64(_offset + byteOffset, set_value);
}
Float32x4 getFloat32x4(int byteOffset,
@@ -3069,7 +3088,7 @@
_throwRangeError(byteOffset, length);
}
// TODO(johnmccutchan) : Need to resolve this for endianity.
- return _typeddata._getFloat32x4(_offset + byteOffset);
+ return _typedData._getFloat32x4(_offset + byteOffset);
}
void setFloat32x4(int byteOffset,
Float32x4 value,
@@ -3078,7 +3097,7 @@
_throwRangeError(byteOffset, length);
}
// TODO(johnmccutchan) : Need to resolve this for endianity.
- _typeddata._setFloat32x4(_offset + byteOffset, value);
+ _typedData._setFloat32x4(_offset + byteOffset, value);
}
@@ -3103,7 +3122,7 @@
native "ByteData_ToEndianFloat64";
- final TypedData _typeddata;
+ final TypedData _typedData;
final int _offset;
final int length;
}
diff --git a/runtime/lib/typeddata_sources.gypi b/runtime/lib/typed_data_sources.gypi
similarity index 74%
rename from runtime/lib/typeddata_sources.gypi
rename to runtime/lib/typed_data_sources.gypi
index fc5ba11..28d6a53 100644
--- a/runtime/lib/typeddata_sources.gypi
+++ b/runtime/lib/typed_data_sources.gypi
@@ -2,12 +2,12 @@
# for details. All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE file.
-# Sources visible via dart:typeddata library.
+# Sources visible via dart:typed_data library.
{
'sources': [
- 'typeddata.cc',
- 'typeddata.dart',
+ 'typed_data.cc',
+ 'typed_data.dart',
'simd128.cc',
],
}
diff --git a/runtime/platform/c99_support_win.h b/runtime/platform/c99_support_win.h
index 2859f0c..71ec127 100644
--- a/runtime/platform/c99_support_win.h
+++ b/runtime/platform/c99_support_win.h
@@ -65,4 +65,10 @@
}
}
+// Windows does not have strtoll defined.
+#if defined(_MSC_VER)
+#define strtoll _strtoi64
+#endif
+
+
#endif // PLATFORM_C99_SUPPORT_WIN_H_
diff --git a/runtime/platform/globals.h b/runtime/platform/globals.h
index 2d566bb..f99e065 100644
--- a/runtime/platform/globals.h
+++ b/runtime/platform/globals.h
@@ -123,13 +123,34 @@
#elif defined(_M_IX86) || defined(__i386__)
#define HOST_ARCH_IA32 1
#define ARCH_IS_32_BIT 1
+#if defined(TARGET_ARCH_ARM) || defined(TARGET_ARCH_MIPS)
+#define kFpuRegisterSize 8
+typedef double fpu_register_t;
+#else
#define kFpuRegisterSize 16
typedef simd128_value_t fpu_register_t;
+#endif
#elif defined(__ARMEL__)
#define HOST_ARCH_ARM 1
#define ARCH_IS_32_BIT 1
#define kFpuRegisterSize 8
typedef double fpu_register_t;
+typedef struct {
+ union {
+ uint32_t u;
+ float f;
+ } data_[4];
+} simd_value_t;
+#define simd_value_safe_load(addr) \
+ (*reinterpret_cast<simd_value_t *>(addr))
+#define simd_value_safe_store(addr, value) \
+ do { \
+ reinterpret_cast<simd_value_t *>(addr)->data_[0] = value.data_[0]; \
+ reinterpret_cast<simd_value_t *>(addr)->data_[1] = value.data_[1]; \
+ reinterpret_cast<simd_value_t *>(addr)->data_[2] = value.data_[2]; \
+ reinterpret_cast<simd_value_t *>(addr)->data_[3] = value.data_[3]; \
+ } while (0)
+
#elif defined(__MIPSEL__)
#define HOST_ARCH_MIPS 1
#define ARCH_IS_32_BIT 1
diff --git a/runtime/tests/vm/dart/byte_array_optimized_test.dart b/runtime/tests/vm/dart/byte_array_optimized_test.dart
index 80bba34..fafef82 100644
--- a/runtime/tests/vm/dart/byte_array_optimized_test.dart
+++ b/runtime/tests/vm/dart/byte_array_optimized_test.dart
@@ -6,7 +6,7 @@
library byte_array_test;
import "package:expect/expect.dart";
-import 'dart:typeddata';
+import 'dart:typed_data';
// This test exercises optimized [] and []= operators
// on byte array views.
diff --git a/runtime/tests/vm/dart/byte_array_test.dart b/runtime/tests/vm/dart/byte_array_test.dart
index f57f551..0f3fe96 100644
--- a/runtime/tests/vm/dart/byte_array_test.dart
+++ b/runtime/tests/vm/dart/byte_array_test.dart
@@ -6,7 +6,7 @@
library byte_array_test;
import "package:expect/expect.dart";
-import 'dart:typeddata';
+import 'dart:typed_data';
class ByteArrayTest {
static testInt8ListImpl(Int8List array) {
diff --git a/runtime/tests/vm/dart/isolate_mirror_local_test.dart b/runtime/tests/vm/dart/isolate_mirror_local_test.dart
index 772ce66..e7927c2 100644
--- a/runtime/tests/vm/dart/isolate_mirror_local_test.dart
+++ b/runtime/tests/vm/dart/isolate_mirror_local_test.dart
@@ -13,6 +13,7 @@
import 'dart:async';
import 'dart:isolate';
import 'dart:mirrors';
+import 'dart:uri';
ReceivePort exit_port;
Set expectedTests;
@@ -115,7 +116,7 @@
lib_mirror.qualifiedName);
Expect.equals(null, lib_mirror.owner);
Expect.isFalse(lib_mirror.isPrivate);
- Expect.isTrue(lib_mirror.url.contains('isolate_mirror_local_test.dart'));
+ Expect.isTrue(lib_mirror.uri.path.contains('isolate_mirror_local_test.dart'));
// TODO(ahe): toString() test disabled for now as Symbols are 100% opaque.
// Expect.equals("LibraryMirror on 'isolate_mirror_local_test'",
// lib_mirror.toString());
@@ -300,10 +301,10 @@
void testLibrariesMap(Map libraries) {
// Just look for a couple of well-known libs.
- LibraryMirror core_lib = libraries[const Symbol('dart.core')];
+ LibraryMirror core_lib = libraries[Uri.parse('dart:core')];
Expect.isTrue(core_lib is LibraryMirror);
- LibraryMirror mirror_lib = libraries[const Symbol('dart.mirrors')];
+ LibraryMirror mirror_lib = libraries[Uri.parse('dart:mirrors')];
Expect.isTrue(mirror_lib is LibraryMirror);
// Lookup an interface from a library and make sure it is sane.
diff --git a/runtime/tests/vm/vm.status b/runtime/tests/vm/vm.status
index 40077cf..6e71bf0 100644
--- a/runtime/tests/vm/vm.status
+++ b/runtime/tests/vm/vm.status
@@ -72,6 +72,7 @@
# Tests missing code generation support.
cc/CorelibCompileAll: Skip
cc/Dart2JSCompileAll: Skip
+cc/Debug_InterruptIsolate: Skip
# Tests needing Dart execution.
dart/*: Skip
diff --git a/runtime/third_party/double-conversion/src/double-conversion.gypi b/runtime/third_party/double-conversion/src/double-conversion.gypi
index 8466d5d..aa474b8 100644
--- a/runtime/third_party/double-conversion/src/double-conversion.gypi
+++ b/runtime/third_party/double-conversion/src/double-conversion.gypi
@@ -5,6 +5,7 @@
{
'target_name': 'libdouble_conversion',
'type': 'static_library',
+ 'toolsets':['target','host'],
'dependencies': [
],
'include_dirs': [
diff --git a/runtime/third_party/jscre/jscre.gypi b/runtime/third_party/jscre/jscre.gypi
index 46ecb7e..acb6d8c 100644
--- a/runtime/third_party/jscre/jscre.gypi
+++ b/runtime/third_party/jscre/jscre.gypi
@@ -5,6 +5,7 @@
{
'target_name': 'libjscre',
'type': 'static_library',
+ 'toolsets':['target','host'],
'dependencies': [
],
'include_dirs': [
diff --git a/runtime/tools/create_resources.py b/runtime/tools/create_resources.py
index f657ea1..d2c0cea 100644
--- a/runtime/tools/create_resources.py
+++ b/runtime/tools/create_resources.py
@@ -62,7 +62,10 @@
''' % date.today().year
cc_text += '#include "bin/resources.h"\n\n'
+ cc_text += 'namespace dart {\n'
+ cc_text += 'namespace bin {\n'
cc_text += makeResources(root_dir, input_files)
+ cc_text += '} // namespace bin\n} // namespace dart\n'
open(output_file, 'w').write(cc_text)
return True
diff --git a/runtime/vm/assembler_arm.cc b/runtime/vm/assembler_arm.cc
index f003889..49d0db2 100644
--- a/runtime/vm/assembler_arm.cc
+++ b/runtime/vm/assembler_arm.cc
@@ -40,19 +40,7 @@
#if defined(USING_SIMULATOR)
integer_division_supported_ = true;
#else
- Assembler assembler;
- __ mrc(R0, 15, 0, 0, 2, 0);
- __ Lsr(R0, R0, 24);
- __ and_(R0, R0, ShifterOperand(0xf));
- __ Ret();
-
- const Code& code =
- Code::Handle(Code::FinalizeCode("DetectCPUFeatures", &assembler));
- Instructions& instructions = Instructions::Handle(code.instructions());
- typedef int32_t (*DetectCPUFeatures)();
- int32_t features =
- reinterpret_cast<DetectCPUFeatures>(instructions.EntryPoint())();
- integer_division_supported_ = features != 0;
+ integer_division_supported_ = false;
#endif // defined(USING_SIMULATOR)
#if defined(DEBUG)
initialized_ = true;
@@ -477,6 +465,13 @@
}
+void Assembler::smull(Register rd_lo, Register rd_hi,
+ Register rn, Register rm, Condition cond) {
+ // Assembler registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs.
+ EmitMulOp(cond, B23 | B22, rd_lo, rd_hi, rn, rm);
+}
+
+
void Assembler::umull(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.
@@ -1236,27 +1231,29 @@
// Uses a code sequence that can easily be decoded.
-void Assembler::LoadWordFromPoolOffset(Register rd, int32_t offset) {
+void Assembler::LoadWordFromPoolOffset(Register rd,
+ int32_t offset,
+ Condition cond) {
ASSERT(rd != PP);
int32_t offset_mask = 0;
if (Address::CanHoldLoadOffset(kLoadWord, offset, &offset_mask)) {
- ldr(rd, Address(PP, offset));
+ ldr(rd, Address(PP, offset), cond);
} else {
int32_t offset_hi = offset & ~offset_mask; // signed
uint32_t offset_lo = offset & offset_mask; // unsigned
// Inline a simplified version of AddImmediate(rd, PP, offset_hi).
ShifterOperand shifter_op;
if (ShifterOperand::CanHold(offset_hi, &shifter_op)) {
- add(rd, PP, shifter_op);
+ add(rd, PP, shifter_op, cond);
} else {
movw(rd, Utils::Low16Bits(offset_hi));
const uint16_t value_high = Utils::High16Bits(offset_hi);
if (value_high != 0) {
- movt(rd, value_high);
+ movt(rd, value_high, cond);
}
- add(rd, PP, ShifterOperand(LR));
+ add(rd, PP, ShifterOperand(LR), cond);
}
- ldr(rd, Address(rd, offset_lo));
+ ldr(rd, Address(rd, offset_lo), cond);
}
}
@@ -1269,24 +1266,24 @@
}
-void Assembler::LoadObject(Register rd, const Object& object) {
+void Assembler::LoadObject(Register rd, const Object& object, Condition cond) {
// Smis and VM heap objects are never relocated; do not use object pool.
if (object.IsSmi()) {
- LoadImmediate(rd, reinterpret_cast<int32_t>(object.raw()));
+ LoadImmediate(rd, reinterpret_cast<int32_t>(object.raw()), cond);
} else if (object.InVMHeap()) {
// Make sure that class CallPattern is able to decode this load immediate.
const int32_t object_raw = reinterpret_cast<int32_t>(object.raw());
- movw(rd, Utils::Low16Bits(object_raw));
+ movw(rd, Utils::Low16Bits(object_raw), cond);
const uint16_t value_high = Utils::High16Bits(object_raw);
if (value_high != 0) {
- movt(rd, value_high);
+ movt(rd, value_high, cond);
}
} else {
// Make sure that class CallPattern is able to decode this load from the
// object pool.
const int32_t offset =
Array::data_offset() + 4*AddObject(object) - kHeapObjectTag;
- LoadWordFromPoolOffset(rd, offset);
+ LoadWordFromPoolOffset(rd, offset, cond);
}
}
diff --git a/runtime/vm/assembler_arm.h b/runtime/vm/assembler_arm.h
index 7875246..7039d8b 100644
--- a/runtime/vm/assembler_arm.h
+++ b/runtime/vm/assembler_arm.h
@@ -393,6 +393,8 @@
Condition cond = AL);
void mls(Register rd, Register rn, Register rm, Register ra,
Condition cond = AL);
+ void smull(Register rd_lo, Register rd_hi, Register rn, Register rm,
+ Condition cond = AL);
void umull(Register rd_lo, Register rd_hi, Register rn, Register rm,
Condition cond = AL);
@@ -552,7 +554,7 @@
void LoadPoolPointer();
- void LoadObject(Register rd, const Object& object);
+ void LoadObject(Register rd, const Object& object, Condition cond = AL);
void PushObject(const Object& object);
void CompareObject(Register rn, const Object& object);
@@ -573,7 +575,7 @@
void LoadClass(Register result, Register object, Register scratch);
void CompareClassId(Register object, intptr_t class_id, Register scratch);
- void LoadWordFromPoolOffset(Register rd, int32_t offset);
+ void LoadWordFromPoolOffset(Register rd, int32_t offset, Condition cond = AL);
void LoadFromOffset(LoadOperandType type,
Register reg,
Register base,
diff --git a/runtime/vm/assembler_arm_test.cc b/runtime/vm/assembler_arm_test.cc
index 93955a80..a7e8f2b 100644
--- a/runtime/vm/assembler_arm_test.cc
+++ b/runtime/vm/assembler_arm_test.cc
@@ -616,7 +616,7 @@
}
-ASSEMBLER_TEST_GENERATE(LongMultiply, assembler) {
+ASSEMBLER_TEST_GENERATE(Multiply64To64, assembler) {
__ Push(R4);
__ Mov(IP, R0);
__ mul(R4, R2, R1);
@@ -628,10 +628,25 @@
}
-ASSEMBLER_TEST_RUN(LongMultiply, test) {
+ASSEMBLER_TEST_RUN(Multiply64To64, test) {
EXPECT(test != NULL);
- typedef int64_t (*LongMultiply)(int64_t operand0, int64_t operand1);
- EXPECT_EQ(6, EXECUTE_TEST_CODE_INT64_LL(LongMultiply, test->entry(), -3, -2));
+ typedef int64_t (*Multiply64To64)(int64_t operand0, int64_t operand1);
+ EXPECT_EQ(6,
+ EXECUTE_TEST_CODE_INT64_LL(Multiply64To64, test->entry(), -3, -2));
+}
+
+
+ASSEMBLER_TEST_GENERATE(Multiply32To64, assembler) {
+ __ smull(R0, R1, R0, R2);
+ __ mov(PC, ShifterOperand(LR));
+}
+
+
+ASSEMBLER_TEST_RUN(Multiply32To64, test) {
+ EXPECT(test != NULL);
+ typedef int64_t (*Multiply32To64)(int64_t operand0, int64_t operand1);
+ EXPECT_EQ(6,
+ EXECUTE_TEST_CODE_INT64_LL(Multiply32To64, test->entry(), -3, -2));
}
diff --git a/runtime/vm/assembler_ia32.cc b/runtime/vm/assembler_ia32.cc
index f293cb9..7442edc 100644
--- a/runtime/vm/assembler_ia32.cc
+++ b/runtime/vm/assembler_ia32.cc
@@ -8,7 +8,6 @@
#include "vm/assembler.h"
#include "vm/code_generator.h"
#include "vm/heap.h"
-#include "vm/heap_trace.h"
#include "vm/memory_region.h"
#include "vm/runtime_entry.h"
#include "vm/stub_code.h"
@@ -1911,7 +1910,6 @@
Register value,
bool can_value_be_smi) {
ASSERT(object != value);
- TraceStoreIntoObject(object, dest, value);
movl(dest, value);
Label done;
if (can_value_be_smi) {
@@ -1933,7 +1931,6 @@
void Assembler::StoreIntoObjectNoBarrier(Register object,
const Address& dest,
Register value) {
- TraceStoreIntoObject(object, dest, value);
movl(dest, value);
#if defined(DEBUG)
Label done;
@@ -1953,7 +1950,6 @@
if (value.IsSmi() || value.InVMHeap()) {
movl(dest, Immediate(reinterpret_cast<int32_t>(value.raw())));
} else {
- // No heap trace for an old object store.
ASSERT(value.IsOld());
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitUint8(0xC7);
@@ -1964,23 +1960,6 @@
}
-void Assembler::TraceStoreIntoObject(Register object,
- const Address& dest,
- Register value) {
- if (HeapTrace::is_enabled()) {
- pushal();
- EnterCallRuntimeFrame(3 * kWordSize);
- movl(Address(ESP, 0 * kWordSize), object);
- leal(EAX, dest);
- movl(Address(ESP, 1 * kWordSize), EAX);
- movl(Address(ESP, 2 * kWordSize), value);
- CallRuntime(kHeapTraceStoreRuntimeEntry);
- LeaveCallRuntimeFrame();
- popal();
- }
-}
-
-
void Assembler::LoadDoubleConstant(XmmRegister dst, double value) {
// TODO(5410843): Need to have a code constants table.
int64_t constant = bit_cast<int64_t, double>(value);
diff --git a/runtime/vm/assembler_ia32.h b/runtime/vm/assembler_ia32.h
index 4ed8c0e..d28f814 100644
--- a/runtime/vm/assembler_ia32.h
+++ b/runtime/vm/assembler_ia32.h
@@ -626,10 +626,6 @@
const Address& dest,
const Object& value);
- void TraceStoreIntoObject(Register object,
- const Address& dest,
- Register value);
-
void DoubleNegate(XmmRegister d);
void FloatNegate(XmmRegister f);
diff --git a/runtime/vm/assembler_mips.cc b/runtime/vm/assembler_mips.cc
index e716dd5..bda9cd0 100644
--- a/runtime/vm/assembler_mips.cc
+++ b/runtime/vm/assembler_mips.cc
@@ -12,6 +12,7 @@
namespace dart {
+DECLARE_FLAG(bool, trace_sim);
DEFINE_FLAG(bool, print_stop_message, false, "Print stop message.");
@@ -330,9 +331,9 @@
addiu(SP, SP, Immediate(-4 * kWordSize));
sw(ZR, Address(SP, 3 * kWordSize)); // PC marker is 0 in stubs.
sw(RA, Address(SP, 2 * kWordSize));
- sw(PP, Address(SP, 1 * kWordSize));
- sw(FP, Address(SP, 0 * kWordSize));
- mov(FP, SP);
+ sw(FP, Address(SP, 1 * kWordSize));
+ sw(PP, Address(SP, 0 * kWordSize));
+ addiu(FP, SP, Immediate(1 * kWordSize));
// Setup pool pointer for this stub.
Label next;
bal(&next);
@@ -355,13 +356,14 @@
void Assembler::LeaveStubFrame(bool uses_pp) {
- mov(SP, FP);
if (uses_pp) {
+ addiu(SP, FP, Immediate(-1 * kWordSize));
lw(RA, Address(SP, 2 * kWordSize));
- lw(PP, Address(SP, 1 * kWordSize));
- lw(FP, Address(SP, 0 * kWordSize));
+ lw(FP, Address(SP, 1 * kWordSize));
+ lw(PP, Address(SP, 0 * kWordSize));
addiu(SP, SP, Immediate(4 * kWordSize));
} else {
+ mov(SP, FP);
lw(RA, Address(SP, 1 * kWordSize));
lw(FP, Address(SP, 0 * kWordSize));
addiu(SP, SP, Immediate(3 * kWordSize));
@@ -448,6 +450,8 @@
2 * kWordSize + // FP and RA.
kDartVolatileFpuRegCount * kWordSize;
+ TraceSimMsg("EnterCallRuntimeFrame");
+
if (prologue_offset_ == -1) {
prologue_offset_ = CodeSize();
}
@@ -490,6 +494,8 @@
2 * kWordSize + // FP and RA.
kDartVolatileFpuRegCount * kWordSize;
+ TraceSimMsg("LeaveCallRuntimeFrame");
+
// SP might have been modified to reserve space for arguments
// and ensure proper alignment of the stack frame.
// We need to restore it before restoring registers.
@@ -543,6 +549,18 @@
break_(Instr::kStopMessageCode);
}
+
+void Assembler::TraceSimMsg(const char* message) {
+ // Don't bother adding in the messages unless tracing is enabled.
+ if (FLAG_trace_sim) {
+ Label msg;
+ b(&msg);
+ Emit(reinterpret_cast<int32_t>(message));
+ Bind(&msg);
+ break_(Instr::kMsgMessageCode);
+ }
+}
+
} // namespace dart
#endif // defined TARGET_ARCH_MIPS
diff --git a/runtime/vm/assembler_mips.h b/runtime/vm/assembler_mips.h
index 0eca796..6402b6e 100644
--- a/runtime/vm/assembler_mips.h
+++ b/runtime/vm/assembler_mips.h
@@ -191,6 +191,10 @@
// Debugging and bringup support.
void Stop(const char* message);
+
+ // TODO(zra): TraceSimMsg enables printing of helpful messages when
+ // --trace_sim is given. Eventually these calls will be changed to Comment.
+ void TraceSimMsg(const char* message);
void Unimplemented(const char* message);
void Untested(const char* message);
void Unreachable(const char* message);
@@ -682,87 +686,91 @@
}
void BranchEqual(Register rd, int32_t value, Label* l) {
- LoadImmediate(TMP1, value);
- beq(rd, TMP1, l);
+ ASSERT(rd != CMPRES);
+ LoadImmediate(CMPRES, value);
+ beq(rd, CMPRES, l);
}
void BranchEqual(Register rd, const Object& object, Label* l) {
- LoadObject(TMP1, object);
- beq(rd, TMP1, l);
+ ASSERT(rd != CMPRES);
+ LoadObject(CMPRES, object);
+ beq(rd, CMPRES, l);
}
void BranchNotEqual(Register rd, int32_t value, Label* l) {
- LoadImmediate(TMP1, value);
- bne(rd, TMP1, l);
+ ASSERT(rd != CMPRES);
+ LoadImmediate(CMPRES, value);
+ bne(rd, CMPRES, l);
}
void BranchNotEqual(Register rd, const Object& object, Label* l) {
- LoadObject(TMP1, object);
- bne(rd, TMP1, l);
+ ASSERT(rd != CMPRES);
+ LoadObject(CMPRES, object);
+ bne(rd, CMPRES, l);
}
void BranchGreater(Register rd, int32_t value, Label* l) {
if (Utils::IsInt(kImmBits, -value)) {
- addiu(TMP1, rd, Immediate(-value));
- bgtz(TMP1, l);
+ addiu(CMPRES, rd, Immediate(-value));
+ bgtz(CMPRES, l);
} else {
- LoadImmediate(TMP1, value);
- subu(TMP1, rd, TMP1);
- bgtz(TMP1, l);
+ LoadImmediate(CMPRES, value);
+ subu(CMPRES, rd, CMPRES);
+ bgtz(CMPRES, l);
}
}
void BranchGreater(Register rd, Register rs, Label* l) {
- subu(TMP1, rd, rs);
- bgtz(TMP1, l);
+ subu(CMPRES, rd, rs);
+ bgtz(CMPRES, l);
}
void BranchGreaterEqual(Register rd, int32_t value, Label* l) {
if (Utils::IsInt(kImmBits, -value)) {
- addiu(TMP1, rd, Immediate(-value));
- bgez(TMP1, l);
+ addiu(CMPRES, rd, Immediate(-value));
+ bgez(CMPRES, l);
} else {
- LoadImmediate(TMP1, value);
- subu(TMP1, rd, TMP1);
- bgez(TMP1, l);
+ LoadImmediate(CMPRES, value);
+ subu(CMPRES, rd, CMPRES);
+ bgez(CMPRES, l);
}
}
void BranchGreaterEqual(Register rd, Register rs, Label* l) {
- subu(TMP1, rd, rs);
- bgez(TMP1, l);
+ subu(CMPRES, rd, rs);
+ bgez(CMPRES, l);
}
void BranchLess(Register rd, int32_t value, Label* l) {
if (Utils::IsInt(kImmBits, -value)) {
- addiu(TMP1, rd, Immediate(-value));
- bltz(TMP1, l);
+ addiu(CMPRES, rd, Immediate(-value));
+ bltz(CMPRES, l);
} else {
- LoadImmediate(TMP1, value);
- subu(TMP1, rd, TMP1);
- bltz(TMP1, l);
+ LoadImmediate(CMPRES, value);
+ subu(CMPRES, rd, CMPRES);
+ bltz(CMPRES, l);
}
}
void BranchLess(Register rd, Register rs, Label* l) {
- subu(TMP1, rd, rs);
- bltz(TMP1, l);
+ subu(CMPRES, rd, rs);
+ bltz(CMPRES, l);
}
void BranchLessEqual(Register rd, int32_t value, Label* l) {
if (Utils::IsInt(kImmBits, -value)) {
- addiu(TMP1, rd, Immediate(-value));
- blez(TMP1, l);
+ addiu(CMPRES, rd, Immediate(-value));
+ blez(CMPRES, l);
} else {
- LoadImmediate(TMP1, value);
- subu(TMP1, rd, TMP1);
- blez(TMP1, l);
+ LoadImmediate(CMPRES, value);
+ subu(CMPRES, rd, CMPRES);
+ blez(CMPRES, l);
}
}
void BranchLessEqual(Register rd, Register rs, Label* l) {
- subu(TMP1, rd, rs);
- blez(TMP1, l);
+ subu(CMPRES, rd, rs);
+ blez(CMPRES, l);
}
void Push(Register rt) {
diff --git a/runtime/vm/benchmark_test.cc b/runtime/vm/benchmark_test.cc
index ef35ba4..837e74b 100644
--- a/runtime/vm/benchmark_test.cc
+++ b/runtime/vm/benchmark_test.cc
@@ -12,6 +12,8 @@
#include "vm/stack_frame.h"
#include "vm/unit_test.h"
+using dart::bin::File;
+
namespace dart {
Benchmark* Benchmark::first_ = NULL;
@@ -400,7 +402,7 @@
"import 'dart:math';\n"
"import 'dart:isolate';\n"
"import 'dart:mirrors';\n"
- "import 'dart:typeddata';\n"
+ "import 'dart:typed_data';\n"
"\n";
// Start an Isolate, load a script and create a full snapshot.
@@ -426,7 +428,7 @@
"import 'dart:math';\n"
"import 'dart:isolate';\n"
"import 'dart:mirrors';\n"
- "import 'dart:typeddata';\n"
+ "import 'dart:typed_data';\n"
"import 'dart:uri';\n"
"import 'dart:utf';\n"
"import 'dart:json';\n"
diff --git a/runtime/vm/bootstrap.cc b/runtime/vm/bootstrap.cc
index d52fc5e..132478c 100644
--- a/runtime/vm/bootstrap.cc
+++ b/runtime/vm/bootstrap.cc
@@ -92,8 +92,8 @@
RawScript* Bootstrap::LoadTypedDataScript(bool patch) {
- const char* url = patch ? "dart:typeddata_patch" : "dart:typeddata";
- const char* source = patch ? typeddata_patch_ : typeddata_source_;
+ const char* url = patch ? "dart:typed_data_patch" : "dart:typed_data";
+ const char* source = patch ? typed_data_patch_ : typed_data_source_;
return LoadScript(url, source, patch);
}
diff --git a/runtime/vm/bootstrap.h b/runtime/vm/bootstrap.h
index 020d819..93619a4 100644
--- a/runtime/vm/bootstrap.h
+++ b/runtime/vm/bootstrap.h
@@ -52,8 +52,8 @@
static const char math_patch_[];
static const char mirrors_source_[];
static const char mirrors_patch_[];
- static const char typeddata_source_[];
- static const char typeddata_patch_[];
+ static const char typed_data_source_[];
+ static const char typed_data_patch_[];
static const char uri_source_[];
static const char utf_source_[];
};
diff --git a/runtime/vm/bootstrap_natives.h b/runtime/vm/bootstrap_natives.h
index fe45457..0a460dd 100644
--- a/runtime/vm/bootstrap_natives.h
+++ b/runtime/vm/bootstrap_natives.h
@@ -170,6 +170,7 @@
V(ByteData_ToEndianFloat32, 2) \
V(ByteData_ToEndianFloat64, 2) \
V(Float32x4_fromDoubles, 5) \
+ V(Float32x4_splat, 2) \
V(Float32x4_zero, 1) \
V(Float32x4_add, 2) \
V(Float32x4_negate, 1) \
diff --git a/runtime/vm/class_finalizer.cc b/runtime/vm/class_finalizer.cc
index 283a09b..673df7a 100644
--- a/runtime/vm/class_finalizer.cc
+++ b/runtime/vm/class_finalizer.cc
@@ -38,10 +38,6 @@
const GrowableArray<intptr_t>& added_subclasses_to_cids) {
ASSERT(FLAG_use_cha);
if (added_subclasses_to_cids.is_empty()) return;
- // TODO(regis): Reenable this code for mips when possible.
-#if defined(TARGET_ARCH_IA32) || \
- defined(TARGET_ARCH_X64) || \
- defined(TARGET_ARCH_ARM)
// Deoptimize all live frames.
DeoptimizeIfOwner(added_subclasses_to_cids);
// Switch all functions' code to unoptimized.
@@ -63,7 +59,6 @@
}
}
}
-#endif
}
@@ -1969,7 +1964,7 @@
field ^= fields_array.At(0);
ASSERT(field.Offset() == TypedDataView::data_offset());
name ^= field.name();
- expected_name ^= String::New("_typeddata");
+ expected_name ^= String::New("_typedData");
ASSERT(String::EqualsIgnoringPrivateKey(name, expected_name));
field ^= fields_array.At(1);
ASSERT(field.Offset() == TypedDataView::offset_in_bytes_offset());
@@ -1988,7 +1983,7 @@
field ^= fields_array.At(0);
ASSERT(field.Offset() == TypedDataView::data_offset());
name ^= field.name();
- expected_name ^= String::New("_typeddata");
+ expected_name ^= String::New("_typedData");
ASSERT(String::EqualsIgnoringPrivateKey(name, expected_name));
field ^= fields_array.At(1);
ASSERT(field.Offset() == TypedDataView::offset_in_bytes_offset());
diff --git a/runtime/vm/class_table.cc b/runtime/vm/class_table.cc
index 2d14cec..3b34490 100644
--- a/runtime/vm/class_table.cc
+++ b/runtime/vm/class_table.cc
@@ -5,7 +5,6 @@
#include "vm/class_table.h"
#include "vm/flags.h"
#include "vm/freelist.h"
-#include "vm/heap_trace.h"
#include "vm/object.h"
#include "vm/raw_object.h"
#include "vm/visitor.h"
@@ -50,9 +49,6 @@
ASSERT(table_[index] == 0);
ASSERT(index < capacity_);
table_[index] = cls.raw();
- if (HeapTrace::is_enabled()) {
- Isolate::Current()->heap()->trace()->TraceRegisterClass(cls);
- }
// Add the vtable for this predefined class into the static vtable registry
// if it has not been setup yet.
cpp_vtable cls_vtable = cls.handle_vtable();
@@ -76,9 +72,6 @@
ASSERT(top_ < capacity_);
cls.set_id(top_);
table_[top_] = cls.raw();
- if (HeapTrace::is_enabled()) {
- Isolate::Current()->heap()->trace()->TraceRegisterClass(cls);
- }
top_++; // Increment next index.
}
}
diff --git a/runtime/vm/class_table.h b/runtime/vm/class_table.h
index 4391b4b..8fe8159 100644
--- a/runtime/vm/class_table.h
+++ b/runtime/vm/class_table.h
@@ -6,7 +6,6 @@
#define VM_CLASS_TABLE_H_
#include "platform/assert.h"
-#include "platform/globals.h"
#include "vm/globals.h"
namespace dart {
diff --git a/runtime/vm/code_descriptors_test.cc b/runtime/vm/code_descriptors_test.cc
index e4fc7b8..d9c5087 100644
--- a/runtime/vm/code_descriptors_test.cc
+++ b/runtime/vm/code_descriptors_test.cc
@@ -4,7 +4,6 @@
#include "platform/assert.h"
#include "vm/globals.h"
-#if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64)
#include "vm/ast.h"
#include "vm/assembler.h"
@@ -284,4 +283,3 @@
} // namespace dart
-#endif // defined TARGET_ARCH_IA32 || defined(TARGET_ARCH_X64)
diff --git a/runtime/vm/code_generator.cc b/runtime/vm/code_generator.cc
index 6ae0afa..9df2cab 100644
--- a/runtime/vm/code_generator.cc
+++ b/runtime/vm/code_generator.cc
@@ -38,8 +38,14 @@
"Trace IC miss in optimized code");
DEFINE_FLAG(bool, trace_patching, false, "Trace patching of code.");
DEFINE_FLAG(bool, trace_runtime_calls, false, "Trace runtime calls");
+#if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64)
DEFINE_FLAG(int, optimization_counter_threshold, 3000,
"Function's usage-counter value before it is optimized, -1 means never");
+#else
+// TODO(regis): Enable optimization on ARM and MIPS.
+DEFINE_FLAG(int, optimization_counter_threshold, -1,
+ "Function's usage-counter value before it is optimized, -1 means never");
+#endif
DECLARE_FLAG(bool, enable_type_checks);
DECLARE_FLAG(bool, trace_type_checks);
DECLARE_FLAG(bool, report_usage_count);
@@ -92,9 +98,11 @@
arguments.SetReturn(array);
AbstractTypeArguments& element_type =
AbstractTypeArguments::CheckedHandle(arguments.ArgAt(1));
- // An Array is raw or takes only one type argument.
+ // An Array is raw or takes one type argument. However, its type argument
+ // vector may be longer than 1 due to a type optimization reusing the type
+ // argument vector of the instantiator.
ASSERT(element_type.IsNull() ||
- ((element_type.Length() == 1) && element_type.IsInstantiated()));
+ ((element_type.Length() >= 1) && element_type.IsInstantiated()));
array.SetTypeArguments(element_type); // May be null.
}
@@ -116,40 +124,29 @@
}
AbstractTypeArguments& type_arguments =
AbstractTypeArguments::CheckedHandle(arguments.ArgAt(1));
- ASSERT(type_arguments.IsNull() ||
- (type_arguments.Length() == cls.NumTypeArguments()));
// If no instantiator is provided, set the type arguments and return.
if (Object::Handle(arguments.ArgAt(2)).IsSmi()) {
ASSERT(Smi::CheckedHandle(arguments.ArgAt(2)).Value() ==
StubCode::kNoInstantiator);
+ // Unless null (for a raw type), the type argument vector may be longer than
+ // necessary due to a type optimization reusing the type argument vector of
+ // the instantiator.
+ ASSERT(type_arguments.IsNull() ||
+ (type_arguments.IsInstantiated() &&
+ (type_arguments.Length() >= cls.NumTypeArguments())));
instance.SetTypeArguments(type_arguments); // May be null.
return;
}
- ASSERT(!type_arguments.IsInstantiated());
+ // A still uninstantiated type argument vector must have the correct length.
+ ASSERT(!type_arguments.IsInstantiated() &&
+ (type_arguments.Length() == cls.NumTypeArguments()));
const AbstractTypeArguments& instantiator =
AbstractTypeArguments::CheckedHandle(arguments.ArgAt(2));
ASSERT(instantiator.IsNull() || instantiator.IsInstantiated());
- if (instantiator.IsNull()) {
- type_arguments =
- InstantiatedTypeArguments::New(type_arguments, instantiator);
- } else if (instantiator.IsTypeArguments()) {
- // Code inlined in the caller should have optimized the case where the
- // instantiator is a TypeArguments and can be used as type argument vector.
- ASSERT(!type_arguments.IsUninstantiatedIdentity() ||
- (instantiator.Length() != type_arguments.Length()));
- type_arguments =
- InstantiatedTypeArguments::New(type_arguments, instantiator);
- } else {
- // If possible, use the instantiator as the type argument vector.
- if (type_arguments.IsUninstantiatedIdentity() &&
- (instantiator.Length() == type_arguments.Length())) {
- type_arguments = instantiator.raw();
- } else {
- type_arguments =
- InstantiatedTypeArguments::New(type_arguments, instantiator);
- }
- }
- ASSERT(type_arguments.IsInstantiated());
+ // Code inlined in the caller should have optimized the case where the
+ // instantiator can be reused as type argument vector.
+ ASSERT(instantiator.IsNull() || !type_arguments.IsUninstantiatedIdentity());
+ type_arguments = InstantiatedTypeArguments::New(type_arguments, instantiator);
instance.SetTypeArguments(type_arguments);
}
@@ -179,38 +176,28 @@
ASSERT(cls.HasTypeArguments());
AbstractTypeArguments& type_arguments =
AbstractTypeArguments::CheckedHandle(arguments.ArgAt(1));
- ASSERT(type_arguments.IsNull() ||
- (type_arguments.Length() == cls.NumTypeArguments()));
if (Object::Handle(arguments.ArgAt(2)).IsSmi()) {
ASSERT(Smi::CheckedHandle(arguments.ArgAt(2)).Value() ==
StubCode::kNoInstantiator);
+ // Unless null (for a raw type), the type argument vector may be longer than
+ // necessary due to a type optimization reusing the type argument vector of
+ // the instantiator.
+ ASSERT(type_arguments.IsNull() ||
+ (type_arguments.IsInstantiated() &&
+ (type_arguments.Length() >= cls.NumTypeArguments())));
} else {
- ASSERT(!type_arguments.IsInstantiated());
+ // A still uninstantiated type argument vector must have the correct length.
+ ASSERT(!type_arguments.IsInstantiated() &&
+ (type_arguments.Length() == cls.NumTypeArguments()));
const AbstractTypeArguments& instantiator =
AbstractTypeArguments::CheckedHandle(arguments.ArgAt(2));
ASSERT(instantiator.IsNull() || instantiator.IsInstantiated());
Error& malformed_error = Error::Handle();
- if (instantiator.IsNull()) {
- type_arguments = type_arguments.InstantiateFrom(instantiator,
- &malformed_error);
- } else if (instantiator.IsTypeArguments()) {
- // Code inlined in the caller should have optimized the case where the
- // instantiator is a TypeArguments and can be used as type argument
- // vector.
- ASSERT(!type_arguments.IsUninstantiatedIdentity() ||
- (instantiator.Length() != type_arguments.Length()));
- type_arguments = type_arguments.InstantiateFrom(instantiator,
- &malformed_error);
- } else {
- // If possible, use the instantiator as the type argument vector.
- if (type_arguments.IsUninstantiatedIdentity() &&
- (instantiator.Length() == type_arguments.Length())) {
- type_arguments = instantiator.raw();
- } else {
- type_arguments = type_arguments.InstantiateFrom(instantiator,
- &malformed_error);
- }
- }
+ // Code inlined in the caller should have optimized the case where the
+ // instantiator can be reused as type argument vector.
+ ASSERT(instantiator.IsNull() || !type_arguments.IsUninstantiatedIdentity());
+ type_arguments = type_arguments.InstantiateFrom(instantiator,
+ &malformed_error);
if (!malformed_error.IsNull()) {
// Throw a dynamic type error.
const intptr_t location = GetCallerLocation();
@@ -241,11 +228,8 @@
ASSERT(!type_arguments.IsNull() && !type_arguments.IsInstantiated());
ASSERT(instantiator.IsNull() || instantiator.IsInstantiated());
// Code inlined in the caller should have optimized the case where the
- // instantiator can be used as type argument vector.
- ASSERT(instantiator.IsNull() ||
- !type_arguments.IsUninstantiatedIdentity() ||
- !instantiator.IsTypeArguments() ||
- (instantiator.Length() != type_arguments.Length()));
+ // instantiator can be reused as type argument vector.
+ ASSERT(instantiator.IsNull() || !type_arguments.IsUninstantiatedIdentity());
type_arguments = InstantiatedTypeArguments::New(type_arguments, instantiator);
ASSERT(type_arguments.IsInstantiated());
arguments.SetReturn(type_arguments);
@@ -1689,22 +1673,6 @@
END_LEAF_RUNTIME_ENTRY
-DEFINE_LEAF_RUNTIME_ENTRY(void,
- HeapTraceStore,
- RawObject* object,
- uword field_addr,
- RawObject* value) {
- if (!(object->IsHeapObject() && value->IsHeapObject())) {
- return;
- }
- HeapTrace* heap_trace = Isolate::Current()->heap()->trace();
- heap_trace->TraceStoreIntoObject(RawObject::ToAddr(object),
- field_addr,
- RawObject::ToAddr(value));
-}
-END_LEAF_RUNTIME_ENTRY
-
-
double DartModulo(double left, double right) {
double remainder = fmod_ieee(left, right);
if (remainder == 0.0) {
diff --git a/runtime/vm/code_generator.h b/runtime/vm/code_generator.h
index 82ecc2d..8b0a59c 100644
--- a/runtime/vm/code_generator.h
+++ b/runtime/vm/code_generator.h
@@ -30,7 +30,6 @@
DECLARE_RUNTIME_ENTRY(CloneContext);
DECLARE_RUNTIME_ENTRY(Deoptimize);
DECLARE_RUNTIME_ENTRY(FixCallersTarget);
-DECLARE_LEAF_RUNTIME_ENTRY(void, HeapTraceStore, RawObject*, uword, RawObject*);
DECLARE_RUNTIME_ENTRY(InlineCacheMissHandlerOneArg);
DECLARE_RUNTIME_ENTRY(InlineCacheMissHandlerTwoArgs);
DECLARE_RUNTIME_ENTRY(InlineCacheMissHandlerThreeArgs);
diff --git a/runtime/vm/code_generator_test.cc b/runtime/vm/code_generator_test.cc
index 86b5ff9..d88e130 100644
--- a/runtime/vm/code_generator_test.cc
+++ b/runtime/vm/code_generator_test.cc
@@ -43,11 +43,6 @@
CODEGEN_TEST2_RUN(SimpleStaticCallCodegen, SmiReturnCodegen, Smi::New(3))
-#if defined(TARGET_ARCH_IA32) || \
- defined(TARGET_ARCH_X64) || \
- defined(TARGET_ARCH_ARM)
-
-
// Helper to allocate and return a LocalVariable.
static LocalVariable* NewTestLocalVariable(const char* name) {
const String& variable_name = String::ZoneHandle(Symbols::New(name));
@@ -563,6 +558,4 @@
EXPECT_EQ(cls.raw(), result.clazz());
}
-#endif // TARGET_ARCH_IA32 || TARGET_ARCH_X64 || TARGET_ARCH_ARM
-
} // namespace dart
diff --git a/runtime/vm/code_patcher_mips.cc b/runtime/vm/code_patcher_mips.cc
index 1268dc7..d355a14 100644
--- a/runtime/vm/code_patcher_mips.cc
+++ b/runtime/vm/code_patcher_mips.cc
@@ -33,7 +33,8 @@
const Code& code,
uword new_target) {
ASSERT(code.ContainsInstructionAt(return_address));
- UNIMPLEMENTED();
+ CallPattern call(return_address, code);
+ call.SetTargetAddress(new_target);
}
diff --git a/runtime/vm/constants_mips.h b/runtime/vm/constants_mips.h
index 198ab77..0668062 100644
--- a/runtime/vm/constants_mips.h
+++ b/runtime/vm/constants_mips.h
@@ -5,6 +5,8 @@
#ifndef VM_CONSTANTS_MIPS_H_
#define VM_CONSTANTS_MIPS_H_
+#include "platform/assert.h"
+
namespace dart {
enum Register {
@@ -152,11 +154,11 @@
// Exception object is passed in this register to the catch handlers when an
// exception is thrown.
-const Register kExceptionObjectReg = A0;
+const Register kExceptionObjectReg = V0;
// Stack trace object is passed in this register to the catch handlers when
// an exception is thrown.
-const Register kStackTraceObjectReg = A1;
+const Register kStackTraceObjectReg = V1;
typedef uint32_t RegList;
@@ -400,6 +402,7 @@
static const int32_t kNopInstruction = 0;
static const int32_t kStopMessageCode = 1;
static const int32_t kRedirectCode = 2;
+ static const int32_t kMsgMessageCode = 3;
// Get the raw instruction bits.
inline int32_t InstructionBits() const {
@@ -411,6 +414,25 @@
*reinterpret_cast<int32_t*>(this) = value;
}
+ inline void SetImmInstrBits(Opcode op, Register rs, Register rt,
+ uint16_t imm) {
+ SetInstructionBits(
+ op << kOpcodeShift |
+ rs << kRsShift |
+ rt << kRtShift |
+ imm << kImmShift);
+ }
+
+ inline void SetSpecialInstrBits(SpecialFunction f,
+ Register rs, Register rt, Register rd) {
+ SetInstructionBits(
+ SPECIAL << kOpcodeShift |
+ f << kFunctionShift |
+ rs << kRsShift |
+ rt << kRtShift |
+ rd << kRdShift);
+ }
+
// Read one particular bit out of the instruction bits.
inline int32_t Bit(int nr) const {
return (InstructionBits() >> nr) & 1;
@@ -501,6 +523,21 @@
// Use the At(pc) function to create references to Instr.
static Instr* At(uword pc) { return reinterpret_cast<Instr*>(pc); }
+#if defined(DEBUG)
+ inline void AssertIsImmInstr(Opcode op, Register rs, Register rt,
+ int32_t imm) {
+ ASSERT((OpcodeField() == op) && (RsField() == rs) && (RtField() == rt) &&
+ (SImmField() == imm));
+ }
+
+ inline void AssertIsSpecialInstr(SpecialFunction f, Register rs, Register rt,
+ Register rd) {
+ ASSERT((OpcodeField() == SPECIAL) && (FunctionField() == f) &&
+ (RsField() == rs) && (RtField() == rt) &&
+ (RdField() == rd));
+ }
+#endif // defined(DEBUG)
+
private:
DISALLOW_ALLOCATION();
DISALLOW_IMPLICIT_CONSTRUCTORS(Instr);
diff --git a/runtime/vm/custom_isolate_test.cc b/runtime/vm/custom_isolate_test.cc
index 2064066..70fb4c7 100644
--- a/runtime/vm/custom_isolate_test.cc
+++ b/runtime/vm/custom_isolate_test.cc
@@ -15,11 +15,6 @@
namespace dart {
-// Only ia32, x64, and arm can run execution tests.
-#if defined(TARGET_ARCH_IA32) || \
- defined(TARGET_ARCH_X64) || \
- defined(TARGET_ARCH_ARM)
-
static void native_echo(Dart_NativeArguments args);
static void CustomIsolateImpl_start(Dart_NativeArguments args);
static Dart_NativeFunction NativeLookup(Dart_Handle name, int argc);
@@ -344,6 +339,4 @@
delete event_queue;
}
-#endif // TARGET_ARCH_IA32 || TARGET_ARCH_X64 || TARGET_ARCH_ARM
-
} // namespace dart
diff --git a/runtime/vm/dart.cc b/runtime/vm/dart.cc
index 5f32e3f..1351152 100644
--- a/runtime/vm/dart.cc
+++ b/runtime/vm/dart.cc
@@ -27,7 +27,6 @@
DEFINE_FLAG(bool, heap_profile_initialize, false,
"Writes a heap profile on isolate initialization.");
-DECLARE_FLAG(bool, heap_trace);
DECLARE_FLAG(bool, print_bootstrap);
DECLARE_FLAG(bool, print_class_table);
DECLARE_FLAG(bool, trace_isolates);
@@ -134,9 +133,6 @@
Isolate::SetInterruptCallback(interrupt);
Isolate::SetUnhandledExceptionCallback(unhandled);
Isolate::SetShutdownCallback(shutdown);
- if (FLAG_heap_trace) {
- HeapTrace::InitOnce(file_open, file_write, file_close);
- }
return NULL;
}
@@ -220,15 +216,8 @@
Object::VerifyBuiltinVtables();
StubCode::Init(isolate);
- // TODO(regis): Reenable this code for mips when possible.
-#if defined(TARGET_ARCH_IA32) || \
- defined(TARGET_ARCH_X64) || \
- defined(TARGET_ARCH_ARM)
isolate->megamorphic_cache_table()->InitMissHandler();
-#endif
- if (FLAG_heap_trace) {
- isolate->heap()->trace()->Init(isolate);
- }
+
isolate->heap()->EnableGrowthControl();
isolate->set_init_callback_data(data);
Api::SetupAcquiredError(isolate);
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index 15958e4..be450c9 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -2442,7 +2442,7 @@
const String& constructor_name,
intptr_t num_args) {
const Library& lib =
- Library::Handle(isolate->object_store()->typeddata_library());
+ Library::Handle(isolate->object_store()->typed_data_library());
ASSERT(!lib.IsNull());
const Class& cls =
Class::Handle(isolate, lib.LookupClassAllowPrivate(Symbols::ByteData()));
diff --git a/runtime/vm/dart_api_impl_test.cc b/runtime/vm/dart_api_impl_test.cc
index a5c682e..1f939b5 100644
--- a/runtime/vm/dart_api_impl_test.cc
+++ b/runtime/vm/dart_api_impl_test.cc
@@ -17,8 +17,9 @@
DECLARE_FLAG(bool, enable_type_checks);
-// Only ia32 and x64 can run execution tests.
-#if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64)
+#if defined(TARGET_ARCH_IA32) || \
+ defined(TARGET_ARCH_X64) || \
+ defined(TARGET_ARCH_ARM)
TEST_CASE(ErrorHandleBasics) {
const char* kScriptChars =
@@ -166,7 +167,7 @@
EXPECT_SUBSTRING("myException", Dart_GetError(result));
}
-#endif
+#endif // TARGET_ARCH_IA32 || TARGET_ARCH_X64 || TARGET_ARCH_ARM
TEST_CASE(Dart_Error) {
@@ -215,8 +216,9 @@
}
-// Only ia32 and x64 can run execution tests.
-#if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64)
+#if defined(TARGET_ARCH_IA32) || \
+ defined(TARGET_ARCH_X64) || \
+ defined(TARGET_ARCH_ARM)
TEST_CASE(ObjectEquals) {
bool equal = false;
@@ -237,7 +239,7 @@
EXPECT(!equal);
}
-#endif
+#endif // TARGET_ARCH_IA32 || TARGET_ARCH_X64 || TARGET_ARCH_ARM
TEST_CASE(InstanceValues) {
@@ -336,8 +338,9 @@
}
-// Only ia32 and x64 can run execution tests.
-#if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64)
+#if defined(TARGET_ARCH_IA32) || \
+ defined(TARGET_ARCH_X64) || \
+ defined(TARGET_ARCH_ARM)
TEST_CASE(NumberValues) {
// TODO(antonm): add various kinds of ints (smi, mint, bigint).
@@ -371,7 +374,7 @@
EXPECT(!Dart_IsNumber(result));
}
-#endif
+#endif // TARGET_ARCH_IA32 || TARGET_ARCH_X64 || TARGET_ARCH_ARM
TEST_CASE(IntegerValues) {
@@ -636,8 +639,9 @@
}
-// Only ia32 and x64 can run execution tests.
-#if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64)
+#if defined(TARGET_ARCH_IA32) || \
+ defined(TARGET_ARCH_X64) || \
+ defined(TARGET_ARCH_ARM)
static void ExternalStringCallbackFinalizer(void* peer) {
*static_cast<int*>(peer) *= 2;
@@ -905,7 +909,7 @@
TEST_CASE(ByteDataAccess) {
const char* kScriptChars =
- "import 'dart:typeddata';\n"
+ "import 'dart:typed_data';\n"
"class Expect {\n"
" static equals(a, b) {\n"
" if (a != b) {\n"
@@ -967,7 +971,7 @@
// TODO(asiva): Once we have getInt16LE and getInt16BE support use the
// appropriate getter instead of the host endian format used now.
const char* kScriptChars =
- "import 'dart:typeddata';\n"
+ "import 'dart:typed_data';\n"
"class Expect {\n"
" static equals(a, b) {\n"
" if (a != b) {\n"
@@ -1086,7 +1090,7 @@
TEST_CASE(TypedDataDirectAccess1) {
const char* kScriptChars =
- "import 'dart:typeddata';\n"
+ "import 'dart:typed_data';\n"
"class Expect {\n"
" static equals(a, b) {\n"
" if (a != b) {\n"
@@ -1133,7 +1137,7 @@
TEST_CASE(TypedDataViewDirectAccess) {
const char* kScriptChars =
- "import 'dart:typeddata';\n"
+ "import 'dart:typed_data';\n"
"class Expect {\n"
" static equals(a, b) {\n"
" if (a != b) {\n"
@@ -1172,7 +1176,7 @@
TEST_CASE(ByteDataDirectAccess) {
const char* kScriptChars =
- "import 'dart:typeddata';\n"
+ "import 'dart:typed_data';\n"
"class Expect {\n"
" static equals(a, b) {\n"
" if (a != b) {\n"
@@ -1377,7 +1381,7 @@
TEST_CASE(Float32x4List) {
const char* kScriptChars =
- "import 'dart:typeddata';\n"
+ "import 'dart:typed_data';\n"
"Float32x4List float32x4() {\n"
" return new Float32x4List(10);\n"
"}\n";
@@ -1408,7 +1412,7 @@
}
-#endif
+#endif // TARGET_ARCH_IA32 || TARGET_ARCH_X64 || TARGET_ARCH_ARM
// Unit test for entering a scope, creating a local handle and exiting
@@ -1543,8 +1547,9 @@
};
-// Only ia32 and x64 can run execution tests.
-#if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64)
+#if defined(TARGET_ARCH_IA32) || \
+ defined(TARGET_ARCH_X64) || \
+ defined(TARGET_ARCH_ARM)
TEST_CASE(WeakPersistentHandle) {
Dart_Handle weak_new_ref = Dart_Null();
@@ -2409,7 +2414,7 @@
EXPECT_EQ(7, global_epilogue_callback_status);
}
-#endif
+#endif // TARGET_ARCH_IA32 || TARGET_ARCH_X64 || TARGET_ARCH_ARM
// Unit test for creating multiple scopes and local handles within them.
@@ -2581,8 +2586,9 @@
}
-// Only ia32 and x64 can run execution tests.
-#if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64)
+#if defined(TARGET_ARCH_IA32) || \
+ defined(TARGET_ARCH_X64) || \
+ defined(TARGET_ARCH_ARM)
TEST_CASE(ClassTypedefsEtc) {
const char* kScriptChars =
@@ -7645,6 +7651,6 @@
EXPECT_EQ(260, value);
}
-#endif // defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64).
+#endif // TARGET_ARCH_IA32 || TARGET_ARCH_X64 || TARGET_ARCH_ARM
} // namespace dart
diff --git a/runtime/vm/dart_api_message.cc b/runtime/vm/dart_api_message.cc
index 5df30aa..c28bd7c 100644
--- a/runtime/vm/dart_api_message.cc
+++ b/runtime/vm/dart_api_message.cc
@@ -244,7 +244,7 @@
object->cls->internal.as_class.library_url->value.as_string;
char* class_name =
object->cls->internal.as_class.class_name->value.as_string;
- if (strcmp("dart:typeddata", library_url) != 0) {
+ if (strcmp("dart:typed_data", library_url) != 0) {
return Dart_CObject::kNumberOfTypedDataTypes;
}
int i = 0;
diff --git a/runtime/vm/dart_api_state.h b/runtime/vm/dart_api_state.h
index a20a940..e1ac24e 100644
--- a/runtime/vm/dart_api_state.h
+++ b/runtime/vm/dart_api_state.h
@@ -733,7 +733,6 @@
private:
ApiZone zone_;
- ThreadLocalKey key_;
};
diff --git a/runtime/vm/datastream.h b/runtime/vm/datastream.h
index 1aa299b..3b76466 100644
--- a/runtime/vm/datastream.h
+++ b/runtime/vm/datastream.h
@@ -8,6 +8,7 @@
#include "platform/assert.h"
#include "platform/utils.h"
#include "vm/allocation.h"
+#include "vm/exceptions.h"
#include "vm/globals.h"
namespace dart {
@@ -148,7 +149,9 @@
*buffer_ = reinterpret_cast<uint8_t*>(alloc_(NULL,
0,
initial_size_));
- ASSERT(*buffer_ != NULL);
+ if (*buffer_ == NULL) {
+ Exceptions::ThrowOOM();
+ }
current_ = *buffer_;
current_size_ = initial_size_;
end_ = *buffer_ + initial_size_;
@@ -243,7 +246,9 @@
*buffer_ = reinterpret_cast<uint8_t*>(alloc_(*buffer_,
current_size_,
new_size));
- ASSERT(*buffer_ != NULL);
+ if (*buffer_ == NULL) {
+ Exceptions::ThrowOOM();
+ }
current_ = *buffer_ + position;
current_size_ = new_size;
end_ = *buffer_ + new_size;
diff --git a/runtime/vm/debugger_api_impl.cc b/runtime/vm/debugger_api_impl.cc
index 6656ba2..43a80d4 100644
--- a/runtime/vm/debugger_api_impl.cc
+++ b/runtime/vm/debugger_api_impl.cc
@@ -111,47 +111,43 @@
Isolate* isolate = Isolate::Current();
ASSERT(isolate != NULL);
ASSERT(isolate->debugger() != NULL);
+ Dart_EnterScope();
Dart_IsolateId isolate_id = isolate->debugger()->GetIsolateId();
if (event->type == Debugger::kBreakpointReached) {
if (legacy_bp_handler != NULL) {
Dart_StackTrace stack_trace =
reinterpret_cast<Dart_StackTrace>(isolate->debugger()->StackTrace());
(*legacy_bp_handler)(isolate_id, NULL, stack_trace);
- return;
+ } else if (paused_event_handler != NULL) {
+ Dart_CodeLocation location;
+ ActivationFrame* top_frame = event->top_frame;
+ location.script_url = Api::NewHandle(isolate, top_frame->SourceUrl());
+ const Library& lib = Library::Handle(top_frame->Library());
+ location.library_id = lib.index();
+ location.token_pos = top_frame->TokenPos();
+ (*paused_event_handler)(isolate_id, location);
}
- if (paused_event_handler == NULL) {
- return;
- }
- Dart_CodeLocation location;
- ActivationFrame* top_frame = event->top_frame;
- location.script_url = Api::NewHandle(isolate, top_frame->SourceUrl());
- const Library& lib = Library::Handle(top_frame->Library());
- location.library_id = lib.index();
- location.token_pos = top_frame->TokenPos();
- (*paused_event_handler)(isolate_id, location);
} else if (event->type == Debugger::kBreakpointResolved) {
- if (bp_resolved_handler == NULL) {
- return;
+ if (bp_resolved_handler != NULL) {
+ SourceBreakpoint* bpt = event->breakpoint;
+ ASSERT(bpt != NULL);
+ Dart_CodeLocation location;
+ Library& library = Library::Handle(isolate);
+ Script& script = Script::Handle(isolate);
+ intptr_t token_pos;
+ bpt->GetCodeLocation(&library, &script, &token_pos);
+ location.script_url = Api::NewHandle(isolate, script.url());
+ location.library_id = library.index();
+ location.token_pos = token_pos;
+ (*bp_resolved_handler)(isolate_id, bpt->id(), location);
}
- SourceBreakpoint* bpt = event->breakpoint;
- ASSERT(bpt != NULL);
- Dart_CodeLocation location;
- Library& library = Library::Handle(isolate);
- Script& script = Script::Handle(isolate);
- intptr_t token_pos;
- bpt->GetCodeLocation(&library, &script, &token_pos);
- location.script_url = Api::NewHandle(isolate, script.url());
- location.library_id = library.index();
- location.token_pos = token_pos;
- (*bp_resolved_handler)(isolate_id, bpt->id(), location);
} else if (event->type == Debugger::kExceptionThrown) {
- if (exc_thrown_handler == NULL) {
- return;
+ if (exc_thrown_handler != NULL) {
+ Dart_Handle exception = Api::NewHandle(isolate, event->exception->raw());
+ Dart_StackTrace trace =
+ reinterpret_cast<Dart_StackTrace>(isolate->debugger()->StackTrace());
+ (*exc_thrown_handler)(isolate_id, exception, trace);
}
- Dart_Handle exception = Api::NewHandle(isolate, event->exception->raw());
- Dart_StackTrace trace =
- reinterpret_cast<Dart_StackTrace>(isolate->debugger()->StackTrace());
- (*exc_thrown_handler)(isolate_id, exception, trace);
} else if (event->type == Debugger::kIsolateCreated) {
if (isolate_event_handler != NULL) {
(*isolate_event_handler)(event->isolate_id, kCreated);
@@ -167,6 +163,7 @@
} else {
UNIMPLEMENTED();
}
+ Dart_ExitScope();
}
diff --git a/runtime/vm/debugger_api_impl_test.cc b/runtime/vm/debugger_api_impl_test.cc
index ad61b39..a10bbeb 100644
--- a/runtime/vm/debugger_api_impl_test.cc
+++ b/runtime/vm/debugger_api_impl_test.cc
@@ -10,9 +10,6 @@
namespace dart {
-// Only ia32 and x64 can run execution tests.
-#if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64)
-
static bool breakpoint_hit = false;
static int breakpoint_hit_counter = 0;
static Dart_Handle script_lib = NULL;
@@ -1533,6 +1530,4 @@
EXPECT_EQ(1, breakpoint_hit_counter);
}
-#endif // defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64).
-
} // namespace dart
diff --git a/runtime/vm/debugger_arm.cc b/runtime/vm/debugger_arm.cc
index 6a4b45c..67a9e97 100644
--- a/runtime/vm/debugger_arm.cc
+++ b/runtime/vm/debugger_arm.cc
@@ -5,30 +5,58 @@
#include "vm/globals.h"
#if defined(TARGET_ARCH_ARM)
+#include "vm/cpu.h"
#include "vm/debugger.h"
+#include "vm/instructions.h"
+#include "vm/stub_code.h"
namespace dart {
+// TODO(hausner): Handle captured variables.
RawInstance* ActivationFrame::GetLocalVarValue(intptr_t slot_index) {
- UNIMPLEMENTED();
- return NULL;
+ uword var_address = fp() + slot_index * kWordSize;
+ return reinterpret_cast<RawInstance*>(
+ *reinterpret_cast<uword*>(var_address));
}
RawInstance* ActivationFrame::GetInstanceCallReceiver(
intptr_t num_actual_args) {
- UNIMPLEMENTED();
- return NULL;
+ ASSERT(num_actual_args > 0); // At minimum we have a receiver on the stack.
+ // Stack pointer points to last argument that was pushed on the stack.
+ uword receiver_addr = sp() + ((num_actual_args - 1) * kWordSize);
+ return reinterpret_cast<RawInstance*>(
+ *reinterpret_cast<uword*>(receiver_addr));
}
void CodeBreakpoint::PatchFunctionReturn() {
- UNIMPLEMENTED();
+ uword* code = reinterpret_cast<uword*>(pc_ - 3 * Instr::kInstrSize);
+ ASSERT(code[0] == 0xe8bd4c00); // ldmia sp!, {pp, fp, lr}
+ ASSERT(code[1] == 0xe28dd004); // add sp, sp, #4
+ ASSERT(code[2] == 0xe12fff1e); // bx lr
+
+ // Smash code with call instruction and target address.
+ uword stub_addr = StubCode::BreakpointReturnEntryPoint();
+ uint16_t target_lo = stub_addr & 0xffff;
+ uint16_t target_hi = stub_addr >> 16;
+ uword movw = 0xe300c000 | ((target_lo >> 12) << 16) | (target_lo & 0xfff);
+ uword movt = 0xe340c000 | ((target_hi >> 12) << 16) | (target_hi & 0xfff);
+ uword blx = 0xe12fff3c;
+ code[0] = movw; // movw ip, #target_lo
+ code[1] = movt; // movt ip, #target_hi
+ code[2] = blx; // blx ip
+ CPU::FlushICache(pc_ - 3 * Instr::kInstrSize, 3 * Instr::kInstrSize);
}
void CodeBreakpoint::RestoreFunctionReturn() {
- UNIMPLEMENTED();
+ uword* code = reinterpret_cast<uword*>(pc_ - 3 * Instr::kInstrSize);
+ ASSERT((code[0] & 0xfff0f000) == 0xe300c000);
+ code[0] = 0xe8bd4c00; // ldmia sp!, {pp, fp, lr}
+ code[1] = 0xe28dd004; // add sp, sp, #4
+ code[2] = 0xe12fff1e; // bx lr
+ CPU::FlushICache(pc_ - 3 * Instr::kInstrSize, 3 * Instr::kInstrSize);
}
} // namespace dart
diff --git a/runtime/vm/debugger_ia32.cc b/runtime/vm/debugger_ia32.cc
index bd3ccb4..bd443ef 100644
--- a/runtime/vm/debugger_ia32.cc
+++ b/runtime/vm/debugger_ia32.cc
@@ -46,7 +46,7 @@
uword stub_addr = StubCode::BreakpointReturnEntryPoint();
code[0] = 0xE8;
*reinterpret_cast<uword*>(&code[1]) = stub_addr - pc_;
- CPU::FlushICache(pc_, 5);
+ CPU::FlushICache(pc_ - 5, 5);
}
@@ -58,7 +58,7 @@
code[2] = 0x5D; // pop ebp
code[3] = 0xC3; // ret
code[4] = 0x90; // nop
- CPU::FlushICache(pc_, 5);
+ CPU::FlushICache(pc_ - 5, 5);
}
diff --git a/runtime/vm/debugger_mips.cc b/runtime/vm/debugger_mips.cc
index 68acf9c..a234dcd 100644
--- a/runtime/vm/debugger_mips.cc
+++ b/runtime/vm/debugger_mips.cc
@@ -5,30 +5,86 @@
#include "vm/globals.h"
#if defined(TARGET_ARCH_MIPS)
+#include "vm/cpu.h"
#include "vm/debugger.h"
+#include "vm/instructions.h"
+#include "vm/stub_code.h"
namespace dart {
+// TODO(hausner): Handle captured variables.
RawInstance* ActivationFrame::GetLocalVarValue(intptr_t slot_index) {
- UNIMPLEMENTED();
- return NULL;
+ uword var_address = fp() + slot_index * kWordSize;
+ return reinterpret_cast<RawInstance*>(
+ *reinterpret_cast<uword*>(var_address));
}
RawInstance* ActivationFrame::GetInstanceCallReceiver(
intptr_t num_actual_args) {
- UNIMPLEMENTED();
- return NULL;
+ ASSERT(num_actual_args > 0); // At minimum we have a receiver on the stack.
+ // Stack pointer points to last argument that was pushed on the stack.
+ uword receiver_addr = sp() + ((num_actual_args - 1) * kWordSize);
+ return reinterpret_cast<RawInstance*>(
+ *reinterpret_cast<uword*>(receiver_addr));
}
void CodeBreakpoint::PatchFunctionReturn() {
- UNIMPLEMENTED();
+ Instr* instr1 = Instr::At(pc_ - 6 * Instr::kInstrSize);
+ Instr* instr2 = Instr::At(pc_ - 5 * Instr::kInstrSize);
+ Instr* instr3 = Instr::At(pc_ - 4 * Instr::kInstrSize);
+ Instr* instr4 = Instr::At(pc_ - 3 * Instr::kInstrSize);
+ Instr* instr5 = Instr::At(pc_ - 2 * Instr::kInstrSize);
+ Instr* instr6 = Instr::At(pc_ - 1 * Instr::kInstrSize);
+
+#if defined(DEBUG)
+
+ instr1->AssertIsImmInstr(LW, SP, RA, 2 * kWordSize);
+ instr2->AssertIsImmInstr(LW, SP, FP, 1 * kWordSize);
+ instr3->AssertIsImmInstr(LW, SP, PP, 0 * kWordSize);
+ instr4->AssertIsImmInstr(ADDIU, SP, SP, 4 * kWordSize);
+ instr5->AssertIsSpecialInstr(JR, RA, ZR, ZR);
+ ASSERT(instr6->InstructionBits() == Instr::kNopInstruction);
+#endif // defined(DEBUG)
+
+ // Smash code with call instruction and target address.
+ uword stub_addr = StubCode::BreakpointReturnEntryPoint();
+ uint16_t target_lo = stub_addr & 0xffff;
+ uint16_t target_hi = stub_addr >> 16;
+
+ // Unlike other architectures, the sequence we are patching in is shorter
+ // than the sequence we are replacing. We pad at the top with nops so that
+ // the end of the new sequence is lined up with the code descriptor.
+ instr1->SetInstructionBits(Instr::kNopInstruction);
+ instr2->SetInstructionBits(Instr::kNopInstruction);
+ instr3->SetImmInstrBits(LUI, ZR, TMP1, target_hi);
+ instr4->SetImmInstrBits(ORI, TMP1, TMP1, target_lo);
+ instr5->SetSpecialInstrBits(JALR, TMP1, ZR, RA);
+ instr6->SetInstructionBits(Instr::kNopInstruction);
+
+ CPU::FlushICache(pc_ - 6 * Instr::kInstrSize, 6 * Instr::kInstrSize);
}
void CodeBreakpoint::RestoreFunctionReturn() {
- UNIMPLEMENTED();
+ Instr* instr1 = Instr::At(pc_ - 6 * Instr::kInstrSize);
+ Instr* instr2 = Instr::At(pc_ - 5 * Instr::kInstrSize);
+ Instr* instr3 = Instr::At(pc_ - 4 * Instr::kInstrSize);
+ Instr* instr4 = Instr::At(pc_ - 3 * Instr::kInstrSize);
+ Instr* instr5 = Instr::At(pc_ - 2 * Instr::kInstrSize);
+ Instr* instr6 = Instr::At(pc_ - 1 * Instr::kInstrSize);
+
+ ASSERT(instr3->OpcodeField() == LUI && instr3->RtField() == TMP1);
+
+ instr1->SetImmInstrBits(LW, SP, RA, 2 * kWordSize);
+ instr2->SetImmInstrBits(LW, SP, FP, 1 * kWordSize);
+ instr3->SetImmInstrBits(LW, SP, PP, 0 * kWordSize);
+ instr4->SetImmInstrBits(ADDIU, SP, SP, 4 * kWordSize);
+ instr5->SetSpecialInstrBits(JR, RA, ZR, ZR);
+ instr6->SetInstructionBits(Instr::kNopInstruction);
+
+ CPU::FlushICache(pc_ - 6 * Instr::kInstrSize, 6 * Instr::kInstrSize);
}
} // namespace dart
diff --git a/runtime/vm/debugger_x64.cc b/runtime/vm/debugger_x64.cc
index 6e64d85..c439640 100644
--- a/runtime/vm/debugger_x64.cc
+++ b/runtime/vm/debugger_x64.cc
@@ -49,7 +49,7 @@
code[10] = 0x41;
code[11] = 0xff;
code[12] = 0xd3;
- CPU::FlushICache(pc_, 5);
+ CPU::FlushICache(pc_ - 13, 13);
}
@@ -69,7 +69,7 @@
code[10] = 0x90; // nop
code[11] = 0x90; // nop
code[12] = 0x90; // nop
- CPU::FlushICache(pc_, 5);
+ CPU::FlushICache(pc_ - 13, 13);
}
} // namespace dart
diff --git a/runtime/vm/disassembler_arm.cc b/runtime/vm/disassembler_arm.cc
index 067f069..a9cc7f0 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 6: {
+ // Registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs.
+ Format(instr, "smull'cond's 'rd, 'rn, 'rm, 'rs");
+ break;
+ }
default: {
Unknown(instr); // Not used.
break;
diff --git a/runtime/vm/disassembler_mips.cc b/runtime/vm/disassembler_mips.cc
index bfa3438..81f35be 100644
--- a/runtime/vm/disassembler_mips.cc
+++ b/runtime/vm/disassembler_mips.cc
@@ -596,6 +596,10 @@
Format(instr, "lh 'rt, 'imms('rs)");
break;
}
+ case LHU: {
+ Format(instr, "lhu 'rt, 'imms('rs)");
+ break;
+ }
case LUI: {
Format(instr, "lui 'rt, 'immu");
break;
diff --git a/runtime/vm/exceptions.cc b/runtime/vm/exceptions.cc
index a5086cf..280bd6e 100644
--- a/runtime/vm/exceptions.cc
+++ b/runtime/vm/exceptions.cc
@@ -535,6 +535,22 @@
}
+void Exceptions::ThrowOOM() {
+ Isolate* isolate = Isolate::Current();
+ const Instance& oom = Instance::Handle(
+ isolate, isolate->object_store()->out_of_memory());
+ Throw(oom);
+}
+
+
+void Exceptions::ThrowStackOverflow() {
+ Isolate* isolate = Isolate::Current();
+ const Instance& stack_overflow = Instance::Handle(
+ isolate, isolate->object_store()->stack_overflow());
+ Throw(stack_overflow);
+}
+
+
RawObject* Exceptions::Create(ExceptionType type, const Array& arguments) {
Library& library = Library::Handle();
const String* class_name = NULL;
diff --git a/runtime/vm/exceptions.h b/runtime/vm/exceptions.h
index 6015369..e74a0db 100644
--- a/runtime/vm/exceptions.h
+++ b/runtime/vm/exceptions.h
@@ -63,6 +63,9 @@
};
static void ThrowByType(ExceptionType type, const Array& arguments);
+ static void ThrowOOM();
+ static void ThrowStackOverflow();
+
// Returns a RawInstance if the exception is successfully created,
// otherwise returns a RawError.
static RawObject* Create(ExceptionType type, const Array& arguments);
diff --git a/runtime/vm/exceptions_test.cc b/runtime/vm/exceptions_test.cc
index 5ccec16..6586435 100644
--- a/runtime/vm/exceptions_test.cc
+++ b/runtime/vm/exceptions_test.cc
@@ -9,11 +9,6 @@
namespace dart {
-// Only ia32, x64, and arm can run execution tests.
-#if defined(TARGET_ARCH_IA32) || \
- defined(TARGET_ARCH_X64) || \
- defined(TARGET_ARCH_ARM)
-
#define FUNCTION_NAME(name) UnhandledExcp_##name
#define REGISTER_FUNCTION(name, count) \
@@ -133,6 +128,5 @@
reinterpret_cast<Dart_NativeEntryResolver>(native_lookup));
EXPECT_VALID(Dart_Invoke(lib, NewString("testMain"), 0, NULL));
}
-#endif // TARGET_ARCH_IA32 || TARGET_ARCH_X64 || TARGET_ARCH_ARM
} // namespace dart
diff --git a/runtime/vm/flags.cc b/runtime/vm/flags.cc
index e18c43e..fdca04e 100644
--- a/runtime/vm/flags.cc
+++ b/runtime/vm/flags.cc
@@ -102,9 +102,12 @@
const char* name,
bool default_value,
const char* comment) {
- ASSERT(Lookup(name) == NULL);
-
- Flag* flag = new Flag(name, comment, addr, Flag::kBoolean);
+ Flag* flag = Lookup(name);
+ if (flag != NULL) {
+ ASSERT(flag->IsUnrecognized());
+ return default_value;
+ }
+ flag = new Flag(name, comment, addr, Flag::kBoolean);
flag->next_ = Flags::flags_;
Flags::flags_ = flag;
@@ -201,7 +204,7 @@
if (flag == NULL) {
// Collect unrecognized flags.
char* new_flag = new char[name_len + 1];
- strncpy(new_flag, name, name_len);
+ strncpy(new_flag, option, name_len);
new_flag[name_len] = '\0';
Flags::Register_bool(NULL, new_flag, true, NULL);
} else {
diff --git a/runtime/vm/flow_graph_builder.cc b/runtime/vm/flow_graph_builder.cc
index cf08e61..76f6469 100644
--- a/runtime/vm/flow_graph_builder.cc
+++ b/runtime/vm/flow_graph_builder.cc
@@ -1917,6 +1917,7 @@
case kTypedDataUint64ArrayCid:
case kTypedDataFloat32ArrayCid:
case kTypedDataFloat64ArrayCid:
+ case kTypedDataFloat32x4ArrayCid:
return function_class.id();
default:
return kDynamicCid; // Unknown.
@@ -2048,22 +2049,22 @@
// List of recognized list factories in core lib:
// (factory-name-symbol, result-cid, fingerprint).
// TODO(srdjan): Store the values in the snapshot instead.
-// TODO(srdjan): Add Float32x4List.
#define RECOGNIZED_LIST_FACTORY_LIST(V) \
V(ObjectArrayFactory, kArrayCid, 97987288) \
V(GrowableObjectArrayWithData, kGrowableObjectArrayCid, 816132033) \
V(GrowableObjectArrayFactory, kGrowableObjectArrayCid, 552407276) \
- V(Int8ListFactory, kTypedDataInt8ArrayCid, 2066002614) \
- V(Uint8ListFactory, kTypedDataUint8ArrayCid, 1883551322) \
- V(Uint8ClampedListFactory, kTypedDataUint8ClampedArrayCid, 244333676) \
- V(Int16ListFactory, kTypedDataInt16ArrayCid, 335889889) \
- V(Uint16ListFactory, kTypedDataUint16ArrayCid, 1552801708) \
- V(Int32ListFactory, kTypedDataInt32ArrayCid, 1615677219) \
- V(Uint32ListFactory, kTypedDataUint32ArrayCid, 1239540305) \
- V(Int64ListFactory, kTypedDataInt64ArrayCid, 993438946) \
- V(Uint64ListFactory, kTypedDataUint64ArrayCid, 1830907325) \
- V(Float64ListFactory, kTypedDataFloat64ArrayCid, 1236037424) \
- V(Float32ListFactory, kTypedDataFloat32ArrayCid, 570814412) \
+ V(Int8ListFactory, kTypedDataInt8ArrayCid, 1299195009) \
+ V(Uint8ListFactory, kTypedDataUint8ArrayCid, 1493118613) \
+ V(Uint8ClampedListFactory, kTypedDataUint8ClampedArrayCid, 642014193) \
+ V(Int16ListFactory, kTypedDataInt16ArrayCid, 1346619471) \
+ V(Uint16ListFactory, kTypedDataUint16ArrayCid, 1374024153) \
+ V(Int32ListFactory, kTypedDataInt32ArrayCid, 1583592980) \
+ V(Uint32ListFactory, kTypedDataUint32ArrayCid, 1940214615) \
+ V(Int64ListFactory, kTypedDataInt64ArrayCid, 108181413) \
+ V(Uint64ListFactory, kTypedDataUint64ArrayCid, 375587484) \
+ V(Float64ListFactory, kTypedDataFloat64ArrayCid, 919047725) \
+ V(Float32ListFactory, kTypedDataFloat32ArrayCid, 1038684997) \
+ V(Float32x4ListFactory, kTypedDataFloat32x4ArrayCid, 801641591) \
// Class that recognizes factories and returns corresponding result cid.
diff --git a/runtime/vm/flow_graph_compiler_arm.cc b/runtime/vm/flow_graph_compiler_arm.cc
index 5b0020b..acd4925 100644
--- a/runtime/vm/flow_graph_compiler_arm.cc
+++ b/runtime/vm/flow_graph_compiler_arm.cc
@@ -285,13 +285,86 @@
}
+// Generates inlined check if 'type' is a type parameter or type itself
+// R0: instance (preserved).
RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest(
intptr_t token_pos,
const AbstractType& type,
Label* is_instance_lbl,
Label* is_not_instance_lbl) {
- UNIMPLEMENTED();
- return NULL;
+ __ Comment("UninstantiatedTypeTest");
+ ASSERT(!type.IsInstantiated());
+ // Skip check if destination is a dynamic type.
+ if (type.IsTypeParameter()) {
+ const TypeParameter& type_param = TypeParameter::Cast(type);
+ // Load instantiator (or null) and instantiator type arguments on stack.
+ __ ldr(R1, Address(SP, 0)); // Get instantiator type arguments.
+ // R1: instantiator type arguments.
+ // Check if type argument is dynamic.
+ __ CompareImmediate(R1, reinterpret_cast<intptr_t>(Object::null()));
+ __ b(is_instance_lbl, EQ);
+ // Can handle only type arguments that are instances of TypeArguments.
+ // (runtime checks canonicalize type arguments).
+ Label fall_through;
+ __ CompareClassId(R1, kTypeArgumentsCid, R2);
+ __ b(&fall_through, NE);
+ __ ldr(R2,
+ FieldAddress(R1, TypeArguments::type_at_offset(type_param.index())));
+ // R2: concrete type of type.
+ // Check if type argument is dynamic.
+ __ CompareObject(R2, Type::ZoneHandle(Type::DynamicType()));
+ __ b(is_instance_lbl, EQ);
+ __ CompareImmediate(R2, reinterpret_cast<intptr_t>(Object::null()));
+ __ b(is_instance_lbl, EQ);
+ const Type& object_type = Type::ZoneHandle(Type::ObjectType());
+ __ CompareObject(R2, object_type);
+ __ b(is_instance_lbl, EQ);
+
+ // For Smi check quickly against int and num interfaces.
+ Label not_smi;
+ __ tst(R0, ShifterOperand(kSmiTagMask)); // Value is Smi?
+ __ b(¬_smi, NE);
+ __ CompareObject(R2, Type::ZoneHandle(Type::IntType()));
+ __ b(is_instance_lbl, EQ);
+ __ CompareObject(R2, Type::ZoneHandle(Type::Number()));
+ __ b(is_instance_lbl, EQ);
+ // Smi must be handled in runtime.
+ __ b(&fall_through);
+
+ __ Bind(¬_smi);
+ // R1: instantiator type arguments.
+ // R0: instance.
+ const Register kInstanceReg = R0;
+ const Register kTypeArgumentsReg = R1;
+ const Register kTempReg = kNoRegister;
+ const SubtypeTestCache& type_test_cache =
+ SubtypeTestCache::ZoneHandle(
+ GenerateCallSubtypeTestStub(kTestTypeThreeArgs,
+ kInstanceReg,
+ kTypeArgumentsReg,
+ kTempReg,
+ is_instance_lbl,
+ is_not_instance_lbl));
+ __ Bind(&fall_through);
+ return type_test_cache.raw();
+ }
+ if (type.IsType()) {
+ const Register kInstanceReg = R0;
+ const Register kTypeArgumentsReg = R1;
+ __ tst(kInstanceReg, ShifterOperand(kSmiTagMask)); // Is instance Smi?
+ __ b(is_not_instance_lbl, EQ);
+ __ ldr(kTypeArgumentsReg, Address(SP, 0)); // Instantiator type args.
+ // Uninstantiated type class is known at compile time, but the type
+ // arguments are determined at runtime by the instantiator.
+ const Register kTempReg = kNoRegister;
+ return GenerateCallSubtypeTestStub(kTestTypeThreeArgs,
+ kInstanceReg,
+ kTypeArgumentsReg,
+ kTempReg,
+ is_instance_lbl,
+ is_not_instance_lbl);
+ }
+ return SubtypeTestCache::null();
}
@@ -394,7 +467,7 @@
// Assignable check is skipped in FlowGraphBuilder, not here.
ASSERT(dst_type.IsMalformed() ||
(!dst_type.IsDynamicType() && !dst_type.IsObjectType()));
- // Preserve instantiator and its type arguments.
+ // Preserve instantiator (R2) and its type arguments (R1).
__ PushList((1 << R1) | (1 << R2));
// A null object is always assignable and is returned as result.
Label is_assignable, runtime_call;
@@ -425,7 +498,7 @@
__ bkpt(0);
__ Bind(&is_assignable); // For a null object.
- // Restore instantiator and its type arguments.
+ // Restore instantiator (R2) and its type arguments (R1).
__ PopList((1 << R1) | (1 << R2));
return;
}
@@ -436,12 +509,12 @@
&is_assignable, &runtime_call);
__ Bind(&runtime_call);
- // Load instantiator and its type arguments.
+ // Load instantiator (R2) and its type arguments (R1).
__ ldm(IA, SP, (1 << R1) | (1 << R2));
__ PushObject(Object::ZoneHandle()); // Make room for the result.
__ Push(R0); // Push the source object.
__ PushObject(dst_type); // Push the type of the destination.
- // Push instantiator and its type arguments.
+ // Push instantiator (R2) and its type arguments (R1).
__ PushList((1 << R1) | (1 << R2));
__ PushObject(dst_name); // Push the name of the destination.
__ LoadObject(R0, test_cache);
@@ -453,7 +526,7 @@
__ Pop(R0);
__ Bind(&is_assignable);
- // Restore instantiator and its type arguments.
+ // Restore instantiator (R2) and its type arguments (R1).
__ PopList((1 << R1) | (1 << R2));
}
@@ -1000,7 +1073,21 @@
intptr_t deopt_id,
intptr_t token_pos,
LocationSummary* locs) {
- UNIMPLEMENTED();
+ // Each ICData propagated from unoptimized to optimized code contains the
+ // function that corresponds to the Dart function of that IC call. Due
+ // to inlining in optimized code, that function may not correspond to the
+ // top-level function (parsed_function().function()) which could be
+ // reoptimized and which counter needs to be incremented.
+ // Pass the function explicitly, it is used in IC stub.
+ __ LoadObject(R6, parsed_function().function());
+ __ LoadObject(R4, arguments_descriptor);
+ __ LoadObject(R5, ic_data);
+ GenerateDartCall(deopt_id,
+ token_pos,
+ target_label,
+ PcDescriptors::kIcCall,
+ locs);
+ __ Drop(argument_count);
}
@@ -1055,7 +1142,17 @@
void FlowGraphCompiler::EmitEqualityRegConstCompare(Register reg,
const Object& obj,
bool needs_number_check) {
- UNIMPLEMENTED();
+ if (needs_number_check &&
+ (obj.IsMint() || obj.IsDouble() || obj.IsBigint())) {
+ __ Push(reg);
+ __ PushObject(obj);
+ __ BranchLink(&StubCode::IdenticalWithNumberCheckLabel());
+ __ Drop(1); // Discard constant.
+ __ Pop(reg); // Restore 'reg'.
+ return;
+ }
+
+ __ CompareObject(reg, obj);
}
diff --git a/runtime/vm/flow_graph_compiler_ia32.cc b/runtime/vm/flow_graph_compiler_ia32.cc
index dce40df..bc3d443 100644
--- a/runtime/vm/flow_graph_compiler_ia32.cc
+++ b/runtime/vm/flow_graph_compiler_ia32.cc
@@ -296,7 +296,7 @@
}
-// Generates inlined check if 'type' is a type parameter or type itsef
+// Generates inlined check if 'type' is a type parameter or type itself
// EAX: instance (preserved).
// Clobbers EDX, EDI, ECX.
RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest(
diff --git a/runtime/vm/flow_graph_compiler_mips.cc b/runtime/vm/flow_graph_compiler_mips.cc
index 75cf6b3..110bc96 100644
--- a/runtime/vm/flow_graph_compiler_mips.cc
+++ b/runtime/vm/flow_graph_compiler_mips.cc
@@ -66,6 +66,7 @@
void FlowGraphCompiler::GenerateBoolToJump(Register bool_register,
Label* is_true,
Label* is_false) {
+ __ TraceSimMsg("BoolToJump");
Label fall_through;
__ BranchEqual(bool_register, reinterpret_cast<intptr_t>(Object::null()),
&fall_through);
@@ -84,6 +85,7 @@
Register temp_reg,
Label* is_instance_lbl,
Label* is_not_instance_lbl) {
+ __ TraceSimMsg("CallSubtypeTestStub");
ASSERT(instance_reg == A0);
ASSERT(temp_reg == kNoRegister); // Unused on MIPS.
const SubtypeTestCache& type_test_cache =
@@ -109,14 +111,67 @@
}
+// Jumps to labels 'is_instance' or 'is_not_instance' respectively, if
+// type test is conclusive, otherwise fallthrough if a type test could not
+// be completed.
+// A0: instance being type checked (preserved).
+// Clobbers T0.
RawSubtypeTestCache*
FlowGraphCompiler::GenerateInstantiatedTypeWithArgumentsTest(
intptr_t token_pos,
const AbstractType& type,
Label* is_instance_lbl,
Label* is_not_instance_lbl) {
- UNIMPLEMENTED();
- return NULL;
+ __ Comment("InstantiatedTypeWithArgumentsTest");
+ ASSERT(type.IsInstantiated());
+ const Class& type_class = Class::ZoneHandle(type.type_class());
+ ASSERT(type_class.HasTypeArguments());
+ const Register kInstanceReg = A0;
+ // A Smi object cannot be the instance of a parameterized class.
+ __ andi(CMPRES, kInstanceReg, Immediate(kSmiTagMask));
+ __ beq(CMPRES, ZR, is_not_instance_lbl);
+ const AbstractTypeArguments& type_arguments =
+ AbstractTypeArguments::ZoneHandle(type.arguments());
+ const bool is_raw_type = type_arguments.IsNull() ||
+ type_arguments.IsRaw(type_arguments.Length());
+ if (is_raw_type) {
+ const Register kClassIdReg = T0;
+ // dynamic type argument, check only classes.
+ __ LoadClassId(kClassIdReg, kInstanceReg);
+ __ BranchEqual(kClassIdReg, type_class.id(), is_instance_lbl);
+ // List is a very common case.
+ if (type_class.IsListClass()) {
+ GenerateListTypeCheck(kClassIdReg, is_instance_lbl);
+ }
+ return GenerateSubtype1TestCacheLookup(
+ token_pos, type_class, is_instance_lbl, is_not_instance_lbl);
+ }
+ // If one type argument only, check if type argument is Object or dynamic.
+ if (type_arguments.Length() == 1) {
+ const AbstractType& tp_argument = AbstractType::ZoneHandle(
+ type_arguments.TypeAt(0));
+ ASSERT(!tp_argument.IsMalformed());
+ if (tp_argument.IsType()) {
+ ASSERT(tp_argument.HasResolvedTypeClass());
+ // Check if type argument is dynamic or Object.
+ const Type& object_type = Type::Handle(Type::ObjectType());
+ if (object_type.IsSubtypeOf(tp_argument, NULL)) {
+ // Instance class test only necessary.
+ return GenerateSubtype1TestCacheLookup(
+ token_pos, type_class, is_instance_lbl, is_not_instance_lbl);
+ }
+ }
+ }
+ // Regular subtype test cache involving instance's type arguments.
+ const Register kTypeArgumentsReg = kNoRegister;
+ const Register kTempReg = kNoRegister;
+ // A0: instance (must be preserved).
+ return GenerateCallSubtypeTestStub(kTestTypeTwoArgs,
+ kInstanceReg,
+ kTypeArgumentsReg,
+ kTempReg,
+ is_instance_lbl,
+ is_not_instance_lbl);
}
@@ -124,6 +179,7 @@
const GrowableArray<intptr_t>& class_ids,
Label* is_equal_lbl,
Label* is_not_equal_lbl) {
+ __ TraceSimMsg("CheckClassIds");
for (intptr_t i = 0; i < class_ids.length(); i++) {
__ BranchEqual(class_id_reg, class_ids[i], is_equal_lbl);
}
@@ -141,6 +197,7 @@
const AbstractType& type,
Label* is_instance_lbl,
Label* is_not_instance_lbl) {
+ __ TraceSimMsg("InstantiatedTypeNoArgumentsTest");
__ Comment("InstantiatedTypeNoArgumentsTest");
ASSERT(type.IsInstantiated());
const Class& type_class = Class::Handle(type.type_class());
@@ -206,6 +263,7 @@
const Class& type_class,
Label* is_instance_lbl,
Label* is_not_instance_lbl) {
+ __ TraceSimMsg("Subtype1TestCacheLookup");
__ Comment("Subtype1TestCacheLookup");
const Register kInstanceReg = A0;
__ LoadClass(T0, kInstanceReg);
@@ -226,13 +284,83 @@
}
+// Generates inlined check if 'type' is a type parameter or type itself
+// A0: instance (preserved).
RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest(
intptr_t token_pos,
const AbstractType& type,
Label* is_instance_lbl,
Label* is_not_instance_lbl) {
- UNIMPLEMENTED();
- return NULL;
+ __ Comment("UninstantiatedTypeTest");
+ ASSERT(!type.IsInstantiated());
+ // Skip check if destination is a dynamic type.
+ if (type.IsTypeParameter()) {
+ const TypeParameter& type_param = TypeParameter::Cast(type);
+ // Load instantiator (or null) and instantiator type arguments on stack.
+ __ lw(A1, Address(SP, 0)); // Get instantiator type arguments.
+ // A1: instantiator type arguments.
+ // Check if type argument is dynamic.
+ __ BranchEqual(A1, reinterpret_cast<intptr_t>(Object::null()),
+ is_instance_lbl);
+ // Can handle only type arguments that are instances of TypeArguments.
+ // (runtime checks canonicalize type arguments).
+ Label fall_through;
+ __ LoadClassId(T2, A1);
+ __ BranchNotEqual(T2, kTypeArgumentsCid, &fall_through);
+ __ lw(T2,
+ FieldAddress(A1, TypeArguments::type_at_offset(type_param.index())));
+ // R2: concrete type of type.
+ // Check if type argument is dynamic.
+ __ BranchEqual(T2, Type::ZoneHandle(Type::DynamicType()), is_instance_lbl);
+ __ BranchEqual(T2, reinterpret_cast<intptr_t>(Object::null()),
+ is_instance_lbl);
+ const Type& object_type = Type::ZoneHandle(Type::ObjectType());
+ __ BranchEqual(T2, object_type, is_instance_lbl);
+
+ // For Smi check quickly against int and num interfaces.
+ Label not_smi;
+ __ andi(CMPRES, A0, Immediate(kSmiTagMask));
+ __ bne(CMPRES, ZR, ¬_smi); // Value is Smi?
+ __ BranchEqual(T2, Type::ZoneHandle(Type::IntType()), is_instance_lbl);
+ __ BranchEqual(T2, Type::ZoneHandle(Type::Number()), is_instance_lbl);
+
+ // Smi must be handled in runtime.
+ __ b(&fall_through);
+
+ __ Bind(¬_smi);
+ // T1: instantiator type arguments.
+ // A0: instance.
+ const Register kInstanceReg = A0;
+ const Register kTypeArgumentsReg = A1;
+ const Register kTempReg = kNoRegister;
+ const SubtypeTestCache& type_test_cache =
+ SubtypeTestCache::ZoneHandle(
+ GenerateCallSubtypeTestStub(kTestTypeThreeArgs,
+ kInstanceReg,
+ kTypeArgumentsReg,
+ kTempReg,
+ is_instance_lbl,
+ is_not_instance_lbl));
+ __ Bind(&fall_through);
+ return type_test_cache.raw();
+ }
+ if (type.IsType()) {
+ const Register kInstanceReg = A0;
+ const Register kTypeArgumentsReg = A1;
+ __ andi(CMPRES, kInstanceReg, Immediate(kSmiTagMask));
+ __ beq(CMPRES, ZR, is_not_instance_lbl); // Is instance Smi?
+ __ lw(kTypeArgumentsReg, Address(SP, 0)); // Instantiator type args.
+ // Uninstantiated type class is known at compile time, but the type
+ // arguments are determined at runtime by the instantiator.
+ const Register kTempReg = kNoRegister;
+ return GenerateCallSubtypeTestStub(kTestTypeThreeArgs,
+ kInstanceReg,
+ kTypeArgumentsReg,
+ kTempReg,
+ is_instance_lbl,
+ is_not_instance_lbl);
+ }
+ return SubtypeTestCache::null();
}
@@ -250,6 +378,7 @@
const AbstractType& type,
Label* is_instance_lbl,
Label* is_not_instance_lbl) {
+ __ TraceSimMsg("InlineInstanceof");
__ Comment("InlineInstanceof");
if (type.IsVoidType()) {
// A non-null value is returned from a void function, which will result in a
@@ -330,6 +459,7 @@
const AbstractType& dst_type,
const String& dst_name,
LocationSummary* locs) {
+ __ TraceSimMsg("AssertAssignable");
ASSERT(token_pos >= 0);
ASSERT(!dst_type.IsNull());
ASSERT(dst_type.IsFinalized());
@@ -355,10 +485,16 @@
const Error& error = Error::Handle(dst_type.malformed_error());
const String& error_message = String::ZoneHandle(
Symbols::New(error.ToErrorCString()));
- __ PushObject(Object::ZoneHandle()); // Make room for the result.
- __ Push(A0); // Push the source object.
- __ PushObject(dst_name); // Push the name of the destination.
- __ PushObject(error_message);
+
+ __ addiu(SP, SP, Immediate(-4 * kWordSize));
+ __ LoadObject(TMP1, Object::ZoneHandle());
+ __ sw(TMP1, Address(SP, 3 * kWordSize)); // Make room for the result.
+ __ sw(A0, Address(SP, 2 * kWordSize)); // Push the source object.
+ __ LoadObject(TMP1, dst_name);
+ __ sw(TMP1, Address(SP, 1 * kWordSize)); // Push the destination name.
+ __ LoadObject(TMP1, error_message);
+ __ sw(TMP1, Address(SP, 0 * kWordSize));
+
GenerateCallRuntime(token_pos,
deopt_id,
kMalformedTypeErrorRuntimeEntry,
@@ -380,25 +516,28 @@
&is_assignable, &runtime_call);
__ Bind(&runtime_call);
- // Load instantiator and its type arguments.
+ // Load instantiator (A2) and its type arguments (A1).
__ lw(A1, Address(SP, 0 * kWordSize));
__ lw(A2, Address(SP, 1 * kWordSize));
- __ addiu(SP, SP, Immediate(2 * kWordSize));
- __ PushObject(Object::ZoneHandle()); // Make room for the result.
- __ Push(A0); // Push the source object.
- __ PushObject(dst_type); // Push the type of the destination.
- // Push instantiator and its type arguments.
- __ addiu(SP, SP, Immediate(-2 * kWordSize));
- __ sw(A2, Address(SP, 1 * kWordSize));
- __ sw(A1, Address(SP, 0 * kWordSize));
- __ PushObject(dst_name); // Push the name of the destination.
+
+ __ addiu(SP, SP, Immediate(-7 * kWordSize));
+ __ LoadObject(TMP1, Object::ZoneHandle());
+ __ sw(TMP1, Address(SP, 6 * kWordSize)); // Make room for the result.
+ __ sw(A0, Address(SP, 5 * kWordSize)); // Push the source object.
+ __ LoadObject(TMP1, dst_type);
+ __ sw(TMP1, Address(SP, 4 * kWordSize)); // Push the type of the destination.
+ __ sw(A2, Address(SP, 3 * kWordSize)); // Push instantiator.
+ __ sw(A1, Address(SP, 2 * kWordSize)); // Push type arguments.
+ __ LoadObject(TMP1, dst_name);
+ __ sw(TMP1, Address(SP, 1 * kWordSize)); // Push the name of the destination.
__ LoadObject(T0, test_cache);
- __ Push(T0);
+ __ sw(T0, Address(SP, 0 * kWordSize));
+
GenerateCallRuntime(token_pos, deopt_id, kTypeCheckRuntimeEntry, locs);
// Pop the parameters supplied to the runtime entry. The result of the
// type check runtime call is the checked value.
- __ Drop(6);
- __ Pop(A0);
+ __ lw(A0, Address(SP, 6 * kWordSize));
+ __ addiu(SP, SP, Immediate(7 * kWordSize));
__ Bind(&is_assignable);
// Restore instantiator and its type arguments.
@@ -442,6 +581,7 @@
// Input parameters:
// S4: arguments descriptor array.
void FlowGraphCompiler::CopyParameters() {
+ __ TraceSimMsg("CopyParameters");
__ Comment("Copy parameters");
const Function& function = parsed_function().function();
LocalScope* scope = parsed_function().node_sequence()->scope();
@@ -482,12 +622,11 @@
// Let T0 point to the last copied positional argument, i.e. to
// fp[kFirstLocalSlotIndex - (num_pos_args - 1)].
__ AddImmediate(T0, FP, (kFirstLocalSlotIndex + 1) * kWordSize);
- __ sll(T3, T2, 1); // T2 is a Smi.
- __ subu(T0, T0, T3);
+ __ sll(T2, T2, 1); // T2 is a Smi.
Label loop, loop_condition;
__ b(&loop_condition);
- __ delay_slot()->SmiUntag(T2);
+ __ delay_slot()->subu(T0, T0, T2);
// We do not use the final allocation index of the variable here, i.e.
// scope->VariableAt(i)->index(), because captured variables still need
// to be copied to the context that is not yet allocated.
@@ -573,7 +712,7 @@
// Check that T0 now points to the null terminator in the array descriptor.
__ lw(T3, Address(T0));
__ BranchEqual(T3, reinterpret_cast<int32_t>(Object::null()),
- &all_arguments_processed);
+ &all_arguments_processed);
} else {
ASSERT(num_opt_pos_params > 0);
__ lw(T2,
@@ -651,15 +790,18 @@
// S4 : arguments descriptor array.
__ lw(T2, FieldAddress(S4, ArgumentsDescriptor::count_offset()));
- __ SmiUntag(T2);
+ __ sll(T2, T2, 1); // T2 is a Smi.
__ LoadImmediate(T0, reinterpret_cast<intptr_t>(Object::null()));
Label null_args_loop, null_args_loop_condition;
+
__ b(&null_args_loop_condition);
__ delay_slot()->addiu(T1, FP, Immediate(kLastParamSlotIndex * kWordSize));
+
__ Bind(&null_args_loop);
__ addu(T3, T1, T2);
__ sw(T0, Address(T3));
+
__ Bind(&null_args_loop_condition);
__ addiu(T2, T2, Immediate(-kWordSize));
__ bgez(T2, &null_args_loop);
@@ -667,16 +809,30 @@
void FlowGraphCompiler::GenerateInlinedGetter(intptr_t offset) {
- UNIMPLEMENTED();
+ // RA: return address.
+ // SP: receiver.
+ // Sequence node has one return node, its input is load field node.
+ __ lw(V0, Address(SP, 0 * kWordSize));
+ __ lw(V0, Address(V0, offset - kHeapObjectTag));
+ __ Ret();
}
void FlowGraphCompiler::GenerateInlinedSetter(intptr_t offset) {
- UNIMPLEMENTED();
+ // RA: return address.
+ // SP+1: receiver.
+ // SP+0: value.
+ // Sequence node has one store node and one return NULL node.
+ __ lw(T0, Address(SP, 1 * kWordSize)); // Receiver.
+ __ lw(T1, Address(SP, 0 * kWordSize)); // Value.
+ __ StoreIntoObject(T0, FieldAddress(T0, offset), T1);
+ __ LoadImmediate(V0, reinterpret_cast<intptr_t>(Object::null()));
+ __ Ret();
}
void FlowGraphCompiler::EmitFrameEntry() {
+ __ TraceSimMsg("FrameEntry");
const Function& function = parsed_function().function();
if (CanOptimizeFunction() && function.is_optimizable()) {
const bool can_optimize = !is_optimizing() || may_reoptimize();
@@ -786,6 +942,7 @@
const bool check_arguments = function.IsClosureFunction();
#endif
if (check_arguments) {
+ __ TraceSimMsg("Check argument count");
__ Comment("Check argument count");
// Check that exactly num_fixed arguments are passed in.
Label correct_num_arguments, wrong_num_arguments;
@@ -858,6 +1015,7 @@
// In unoptimized code, initialize (non-argument) stack allocated slots to
// null. This does not cover the saved_args_desc_var slot.
if (!is_optimizing() && (num_locals > 0)) {
+ __ TraceSimMsg("Initialize spill slots");
__ Comment("Initialize spill slots");
const intptr_t slot_base = parsed_function().first_stack_local_index();
__ LoadImmediate(T0, reinterpret_cast<intptr_t>(Object::null()));
@@ -898,6 +1056,7 @@
const ExternalLabel* label,
PcDescriptors::Kind kind,
LocationSummary* locs) {
+ __ TraceSimMsg("Call");
__ BranchLinkPatchable(label);
AddCurrentDescriptor(kind, Isolate::kNoDeoptId, token_pos);
RecordSafepoint(locs);
@@ -909,6 +1068,7 @@
const ExternalLabel* label,
PcDescriptors::Kind kind,
LocationSummary* locs) {
+ __ TraceSimMsg("DartCall");
__ BranchLinkPatchable(label);
AddCurrentDescriptor(kind, deopt_id, token_pos);
RecordSafepoint(locs);
@@ -931,6 +1091,7 @@
intptr_t deopt_id,
const RuntimeEntry& entry,
LocationSummary* locs) {
+ __ TraceSimMsg("CallRuntime");
__ CallRuntime(entry);
AddCurrentDescriptor(PcDescriptors::kOther, deopt_id, token_pos);
RecordSafepoint(locs);
@@ -948,6 +1109,7 @@
token_pos);
}
}
+ __ TraceSimMsg("CallRuntime return");
}
@@ -970,6 +1132,7 @@
intptr_t deopt_id,
intptr_t token_pos,
LocationSummary* locs) {
+ __ TraceSimMsg("InstanceCall");
__ LoadObject(S4, arguments_descriptor);
__ LoadObject(S5, ic_data);
GenerateDartCall(deopt_id,
@@ -977,6 +1140,7 @@
target_label,
PcDescriptors::kIcCall,
locs);
+ __ TraceSimMsg("InstanceCall return");
__ Drop(argument_count);
}
@@ -998,6 +1162,7 @@
intptr_t deopt_id,
intptr_t token_pos,
LocationSummary* locs) {
+ __ TraceSimMsg("StaticCall");
__ LoadObject(S4, arguments_descriptor);
// Do not use the code from the function, but let the code be patched so that
// we can record the outgoing edges to other code.
@@ -1021,13 +1186,17 @@
void FlowGraphCompiler::EmitEqualityRegRegCompare(Register left,
Register right,
bool needs_number_check) {
+ __ TraceSimMsg("EqualityRegRegCompare");
if (needs_number_check) {
- __ Push(left);
- __ Push(right);
+ __ addiu(SP, SP, Immediate(-2 * kWordSize));
+ __ sw(left, Address(SP, 1 * kWordSize));
+ __ sw(right, Address(SP, 0 * kWordSize));
__ BranchLink(&StubCode::IdenticalWithNumberCheckLabel());
+ __ TraceSimMsg("EqualityRegRegCompare return");
// Stub returns result in CMPRES. If it is 0, then left and right are equal.
- __ Pop(right);
- __ Pop(left);
+ __ lw(right, Address(SP, 0 * kWordSize));
+ __ lw(left, Address(SP, 1 * kWordSize));
+ __ addiu(SP, SP, Immediate(2 * kWordSize));
} else {
__ subu(CMPRES, left, right);
}
@@ -1041,6 +1210,7 @@
void FlowGraphCompiler::SaveLiveRegisters(LocationSummary* locs) {
+ __ TraceSimMsg("SaveLiveRegisters");
// TODO(vegorov): consider saving only caller save (volatile) registers.
const intptr_t fpu_registers = locs->live_registers()->fpu_registers();
if (fpu_registers > 0) {
@@ -1068,6 +1238,7 @@
void FlowGraphCompiler::RestoreLiveRegisters(LocationSummary* locs) {
// General purpose registers have the lowest register number at the
// lowest address.
+ __ TraceSimMsg("RestoreLiveRegisters");
const intptr_t cpu_registers = locs->live_registers()->cpu_registers();
ASSERT((cpu_registers & ~kAllCpuRegistersList) == 0);
const int register_count = Utils::CountOneBits(cpu_registers);
@@ -1172,6 +1343,7 @@
void ParallelMoveResolver::EmitMove(int index) {
+ __ TraceSimMsg("ParallelMoveResolver::EmitMove");
MoveOperands* move = moves_[index];
const Location source = move->src();
const Location destination = move->dest();
@@ -1228,6 +1400,7 @@
void ParallelMoveResolver::EmitSwap(int index) {
+ __ TraceSimMsg("ParallelMoveResolver::EmitSwap");
MoveOperands* move = moves_[index];
const Location source = move->src();
const Location destination = move->dest();
@@ -1303,18 +1476,21 @@
void ParallelMoveResolver::MoveMemoryToMemory(const Address& dst,
const Address& src) {
+ __ TraceSimMsg("ParallelMoveResolver::MoveMemoryToMemory");
__ lw(TMP1, src);
__ sw(TMP1, dst);
}
void ParallelMoveResolver::StoreObject(const Address& dst, const Object& obj) {
+ __ TraceSimMsg("ParallelMoveResolver::StoreObject");
__ LoadObject(TMP1, obj);
__ sw(TMP1, dst);
}
void ParallelMoveResolver::Exchange(Register reg, const Address& mem) {
+ __ TraceSimMsg("ParallelMoveResolver::Exchange ra");
ASSERT(reg != TMP1);
__ mov(TMP1, reg);
__ lw(reg, mem);
@@ -1323,6 +1499,7 @@
void ParallelMoveResolver::Exchange(const Address& mem1, const Address& mem2) {
+ __ TraceSimMsg("ParallelMoveResolver::Exchange aa");
ScratchRegisterScope ensure_scratch(this, TMP1);
__ lw(ensure_scratch.reg(), mem1);
__ lw(TMP1, mem2);
@@ -1332,22 +1509,26 @@
void ParallelMoveResolver::SpillScratch(Register reg) {
+ __ TraceSimMsg("ParallelMoveResolver::SpillScratch");
__ Push(reg);
}
void ParallelMoveResolver::RestoreScratch(Register reg) {
+ __ TraceSimMsg("ParallelMoveResolver::RestoreScratch");
__ Pop(reg);
}
void ParallelMoveResolver::SpillFpuScratch(FpuRegister reg) {
+ __ TraceSimMsg("ParallelMoveResolver::SpillFpuScratch");
__ AddImmediate(SP, -kDoubleSize);
__ sdc1(reg, Address(SP));
}
void ParallelMoveResolver::RestoreFpuScratch(FpuRegister reg) {
+ __ TraceSimMsg("ParallelMoveResolver::RestoreFpuScratch");
__ ldc1(reg, Address(SP));
__ AddImmediate(SP, kDoubleSize);
}
diff --git a/runtime/vm/flow_graph_compiler_x64.cc b/runtime/vm/flow_graph_compiler_x64.cc
index 48d2624..d566fa1 100644
--- a/runtime/vm/flow_graph_compiler_x64.cc
+++ b/runtime/vm/flow_graph_compiler_x64.cc
@@ -295,7 +295,7 @@
}
-// Generates inlined check if 'type' is a type parameter or type itsef
+// Generates inlined check if 'type' is a type parameter or type itself
// RAX: instance (preserved).
// Clobbers RDI, RDX, R10.
RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest(
diff --git a/runtime/vm/flow_graph_optimizer.cc b/runtime/vm/flow_graph_optimizer.cc
index a021388..3170079 100644
--- a/runtime/vm/flow_graph_optimizer.cc
+++ b/runtime/vm/flow_graph_optimizer.cc
@@ -1393,6 +1393,23 @@
}
+bool FlowGraphOptimizer::InlineFloat32x4Getter(InstanceCallInstr* call,
+ MethodRecognizer::Kind getter) {
+ AddCheckClass(call->ArgumentAt(0),
+ ICData::ZoneHandle(
+ call->ic_data()->AsUnaryClassChecksForArgNr(0)),
+ call->deopt_id(),
+ call->env(),
+ call);
+ Float32x4ShuffleInstr* instr = new Float32x4ShuffleInstr(
+ getter,
+ new Value(call->ArgumentAt(0)),
+ call);
+ ReplaceCall(call, instr);
+ return true;
+}
+
+
// Only unique implicit instance getters can be currently handled.
bool FlowGraphOptimizer::TryInlineInstanceGetter(InstanceCallInstr* call) {
ASSERT(call->HasICData());
@@ -1454,6 +1471,19 @@
}
InlineStringIsEmptyGetter(call);
return true;
+ case MethodRecognizer::kFloat32x4ShuffleXXXX:
+ case MethodRecognizer::kFloat32x4ShuffleYYYY:
+ case MethodRecognizer::kFloat32x4ShuffleZZZZ:
+ case MethodRecognizer::kFloat32x4ShuffleWWWW:
+ case MethodRecognizer::kFloat32x4ShuffleX:
+ case MethodRecognizer::kFloat32x4ShuffleY:
+ case MethodRecognizer::kFloat32x4ShuffleZ:
+ case MethodRecognizer::kFloat32x4ShuffleW:
+ if (!ic_data.HasReceiverClassId(kFloat32x4Cid) ||
+ !ic_data.HasOneTarget()) {
+ return false;
+ }
+ return InlineFloat32x4Getter(call, recognized_kind);
default:
ASSERT(recognized_kind == MethodRecognizer::kUnknown);
}
@@ -2077,6 +2107,21 @@
MathSqrtInstr* sqrt =
new MathSqrtInstr(new Value(call->ArgumentAt(0)), call);
ReplaceCall(call, sqrt);
+ } else if (recognized_kind == MethodRecognizer::kFloat32x4Zero) {
+ Float32x4ZeroInstr* zero = new Float32x4ZeroInstr(call);
+ ReplaceCall(call, zero);
+ } else if (recognized_kind == MethodRecognizer::kFloat32x4Splat) {
+ Float32x4SplatInstr* splat =
+ new Float32x4SplatInstr(new Value(call->ArgumentAt(1)), call);
+ ReplaceCall(call, splat);
+ } else if (recognized_kind == MethodRecognizer::kFloat32x4Constructor) {
+ Float32x4ConstructorInstr* con =
+ new Float32x4ConstructorInstr(new Value(call->ArgumentAt(1)),
+ new Value(call->ArgumentAt(2)),
+ new Value(call->ArgumentAt(3)),
+ new Value(call->ArgumentAt(4)),
+ call);
+ ReplaceCall(call, con);
}
}
@@ -3063,52 +3108,216 @@
// in the DominatorBasedCSE pass.
// TODO(fschneider): Extend to other load instructions.
return (def->IsLoadField() && def->AffectedBySideEffect())
- || def->IsLoadIndexed();
+ || def->IsLoadIndexed()
+ || def->IsLoadStaticField()
+ || def->IsCurrentContext();
}
-static intptr_t ComputeLoadOffsetInWords(Definition* defn) {
- if (defn->IsLoadIndexed()) {
- // We are assuming that LoadField is never used to load the first word.
- return 0;
+// Alias represents a family of locations. It is used to capture aliasing
+// between stores and loads. Store can alias another load or store if and only
+// if they have the same alias.
+class Alias : public ValueObject {
+ public:
+ Alias(const Alias& other) : ValueObject(), alias_(other.alias_) { }
+
+ // All indexed load/stores alias each other.
+ // TODO(vegorov): incorporate type of array into alias to disambiguate
+ // different typed data and normal arrays.
+ static Alias Indexes() {
+ return Alias(kIndexesAlias);
}
- LoadFieldInstr* load_field = defn->AsLoadField();
- if (load_field != NULL) {
- const intptr_t idx = load_field->offset_in_bytes() / kWordSize;
- ASSERT(idx > 0);
- return idx;
+ // Field load/stores alias each other when field offset matches.
+ // TODO(vegorov): use field information to disambiguate load/stores into
+ // different fields that by accident share offset.
+ static Alias Field(intptr_t offset_in_bytes) {
+ const intptr_t idx = offset_in_bytes / kWordSize;
+ ASSERT(idx >= kFirstFieldAlias);
+ return Alias(idx * 2);
}
- UNREACHABLE();
- return 0;
-}
-
-
-static bool IsInterferingStore(Instruction* instr,
- intptr_t* offset_in_words) {
- if (instr->IsStoreIndexed()) {
- // We are assuming that LoadField is never used to load the first word.
- *offset_in_words = 0;
- return true;
+ // Static field load/stores alias each other.
+ // AliasedSet assigns ids to static fields during optimization phase.
+ static Alias StaticField(intptr_t id) {
+ ASSERT(id >= kFirstFieldAlias);
+ return Alias(id * 2 + 1);
}
- StoreInstanceFieldInstr* store_instance_field = instr->AsStoreInstanceField();
- if (store_instance_field != NULL) {
- ASSERT(store_instance_field->field().Offset() != 0);
- *offset_in_words = store_instance_field->field().Offset() / kWordSize;
- return true;
+ // Current context load/stores alias each other.
+ static Alias CurrentContext() {
+ return Alias(kCurrentContextAlias);
}
- StoreVMFieldInstr* store_vm_field = instr->AsStoreVMField();
- if (store_vm_field != NULL) {
- ASSERT(store_vm_field->offset_in_bytes() != 0);
- *offset_in_words = store_vm_field->offset_in_bytes() / kWordSize;
- return true;
+ // Operation does not alias anything.
+ static Alias None() {
+ return Alias(kNoneAlias);
}
- return false;
-}
+ bool IsNone() const {
+ return alias_ == kNoneAlias;
+ }
+
+ // Convert this alias to a positive array index.
+ intptr_t ToIndex() const {
+ ASSERT(!IsNone());
+ return alias_ - kAliasBase;
+ }
+
+ private:
+ explicit Alias(intptr_t alias) : alias_(alias) { }
+
+ enum {
+ kNoneAlias = -2,
+ kCurrentContextAlias = -1,
+ kIndexesAlias = 0,
+ kFirstFieldAlias = kIndexesAlias + 1,
+ kAliasBase = kCurrentContextAlias
+ };
+
+ const intptr_t alias_;
+};
+
+
+// Set mapping alias to a list of loads sharing this alias.
+class AliasedSet : public ZoneAllocated {
+ public:
+ explicit AliasedSet(intptr_t max_expr_id)
+ : max_expr_id_(max_expr_id),
+ sets_(),
+ field_ids_(),
+ max_field_id_(0) { }
+
+ Alias ComputeAliasForLoad(Definition* defn) {
+ if (defn->IsLoadIndexed()) {
+ // We are assuming that LoadField is never used to load the first word.
+ return Alias::Indexes();
+ }
+
+ LoadFieldInstr* load_field = defn->AsLoadField();
+ if (load_field != NULL) {
+ return Alias::Field(load_field->offset_in_bytes());
+ }
+
+ if (defn->IsCurrentContext()) {
+ return Alias::CurrentContext();
+ }
+
+ LoadStaticFieldInstr* load_static_field = defn->AsLoadStaticField();
+ if (load_static_field != NULL) {
+ return Alias::StaticField(GetFieldId(load_static_field->field()));
+ }
+
+ UNREACHABLE();
+ return Alias::None();
+ }
+
+ Alias ComputeAliasForStore(Instruction* instr) {
+ if (instr->IsStoreIndexed()) {
+ return Alias::Indexes();
+ }
+
+ StoreInstanceFieldInstr* store_instance_field =
+ instr->AsStoreInstanceField();
+ if (store_instance_field != NULL) {
+ return Alias::Field(store_instance_field->field().Offset());
+ }
+
+ StoreVMFieldInstr* store_vm_field = instr->AsStoreVMField();
+ if (store_vm_field != NULL) {
+ return Alias::Field(store_vm_field->offset_in_bytes());
+ }
+
+ if (instr->IsStoreContext() || instr->IsChainContext()) {
+ return Alias::CurrentContext();
+ }
+
+ StoreStaticFieldInstr* store_static_field = instr->AsStoreStaticField();
+ if (store_static_field != NULL) {
+ return Alias::StaticField(GetFieldId(store_static_field->field()));
+ }
+
+ return Alias::None();
+ }
+
+ bool Contains(const Alias alias) {
+ const intptr_t idx = alias.ToIndex();
+ return (idx < sets_.length()) && (sets_[idx] != NULL);
+ }
+
+ BitVector* Get(const Alias alias) {
+ ASSERT(Contains(alias));
+ return sets_[alias.ToIndex()];
+ }
+
+ void Add(const Alias alias, intptr_t ssa_index) {
+ const intptr_t idx = alias.ToIndex();
+
+ while (sets_.length() <= idx) {
+ sets_.Add(NULL);
+ }
+
+ if (sets_[idx] == NULL) {
+ sets_[idx] = new BitVector(max_expr_id_);
+ }
+
+ sets_[idx]->Add(ssa_index);
+ }
+
+ intptr_t max_expr_id() const { return max_expr_id_; }
+ bool IsEmpty() const { return max_expr_id_ == 0; }
+
+ private:
+ const intptr_t max_expr_id_;
+
+ // Maps alias index to a set of ssa indexes corresponding to loads with the
+ // given alias.
+ GrowableArray<BitVector*> sets_;
+
+ // Get id assigned to the given field. Assign a new id if the field is seen
+ // for the first time.
+ intptr_t GetFieldId(const Field& field) {
+ intptr_t id = field_ids_.Lookup(&field);
+ if (id == 0) {
+ id = ++max_field_id_;
+ field_ids_.Insert(FieldIdPair(&field, id));
+ }
+ return id;
+ }
+
+ class FieldIdPair {
+ public:
+ typedef const Field* Key;
+ typedef intptr_t Value;
+ typedef FieldIdPair Pair;
+
+ FieldIdPair(Key key, Value value) : key_(key), value_(value) { }
+
+ static Key KeyOf(Pair kv) {
+ return kv.key_;
+ }
+
+ static Value ValueOf(Pair kv) {
+ return kv.value_;
+ }
+
+ static intptr_t Hashcode(Key key) {
+ return String::Handle(key->name()).Hash();
+ }
+
+ static inline bool IsKeyEqual(Pair kv, Key key) {
+ return KeyOf(kv)->raw() == key->raw();
+ }
+
+ private:
+ Key key_;
+ Value value_;
+ };
+
+ // Table mapping static field to their id used during optimization pass.
+ DirectChainedHashMap<FieldIdPair> field_ids_;
+ intptr_t max_field_id_;
+};
static Definition* GetStoredValue(Instruction* instr) {
@@ -3126,6 +3335,15 @@
return store_vm_field->value()->definition();
}
+ StoreStaticFieldInstr* store_static_field = instr->AsStoreStaticField();
+ if (store_static_field != NULL) {
+ return store_static_field->value()->definition();
+ }
+
+ if (instr->IsStoreContext() || instr->IsChainContext()) {
+ return instr->InputAt(0)->definition();
+ }
+
UNREACHABLE(); // Should only be called for supported store instructions.
return NULL;
}
@@ -3136,7 +3354,7 @@
class LoadKeyValueTrait {
public:
typedef Definition* Value;
- typedef Definition* Key;
+ typedef Instruction* Key;
typedef Definition* Pair;
static Key KeyOf(Pair kv) {
@@ -3171,6 +3389,16 @@
StoreVMFieldInstr* store_field = key->AsStoreVMField();
object = store_field->dest()->definition()->ssa_temp_index();
location = store_field->offset_in_bytes();
+ } else if (key->IsLoadStaticField()) {
+ LoadStaticFieldInstr* load_static_field = key->AsLoadStaticField();
+ object = String::Handle(load_static_field->field().name()).Hash();
+ } else if (key->IsStoreStaticField()) {
+ StoreStaticFieldInstr* store_static_field = key->AsStoreStaticField();
+ object = String::Handle(store_static_field->field().name()).Hash();
+ } else {
+ ASSERT(key->IsStoreContext() ||
+ key->IsCurrentContext() ||
+ key->IsChainContext());
}
return object * 31 + location;
@@ -3189,6 +3417,20 @@
return false;
}
+ if (kv->IsLoadStaticField()) {
+ if (key->IsStoreStaticField()) {
+ LoadStaticFieldInstr* load_static_field = kv->AsLoadStaticField();
+ StoreStaticFieldInstr* store_static_field = key->AsStoreStaticField();
+ return load_static_field->field().raw() ==
+ store_static_field->field().raw();
+ }
+ return false;
+ }
+
+ if (kv->IsCurrentContext()) {
+ return key->IsStoreContext() || key->IsChainContext();
+ }
+
ASSERT(kv->IsLoadField());
LoadFieldInstr* load_field = kv->AsLoadField();
if (key->IsStoreVMField()) {
@@ -3206,10 +3448,9 @@
};
-static intptr_t NumberLoadExpressions(
+static AliasedSet* NumberLoadExpressions(
FlowGraph* graph,
- DirectChainedHashMap<LoadKeyValueTrait>* map,
- GrowableArray<BitVector*>* kill_by_offs) {
+ DirectChainedHashMap<LoadKeyValueTrait>* map) {
intptr_t expr_id = 0;
// Loads representing different expression ids will be collected and
@@ -3238,35 +3479,24 @@
}
}
- // Build per offset kill sets. Any store interferes only with loads from
- // the same offset.
+ // Build aliasing sets mapping aliases to loads.
+ AliasedSet* aliased_set = new AliasedSet(expr_id);
for (intptr_t i = 0; i < loads.length(); i++) {
Definition* defn = loads[i];
-
- const intptr_t offset_in_words = ComputeLoadOffsetInWords(defn);
- while (kill_by_offs->length() <= offset_in_words) {
- kill_by_offs->Add(NULL);
- }
- if ((*kill_by_offs)[offset_in_words] == NULL) {
- (*kill_by_offs)[offset_in_words] = new BitVector(expr_id);
- }
- (*kill_by_offs)[offset_in_words]->Add(defn->expr_id());
+ aliased_set->Add(aliased_set->ComputeAliasForLoad(defn), defn->expr_id());
}
-
- return expr_id;
+ return aliased_set;
}
class LoadOptimizer : public ValueObject {
public:
LoadOptimizer(FlowGraph* graph,
- intptr_t max_expr_id,
- DirectChainedHashMap<LoadKeyValueTrait>* map,
- const GrowableArray<BitVector*>& kill_by_offset)
+ AliasedSet* aliased_set,
+ DirectChainedHashMap<LoadKeyValueTrait>* map)
: graph_(graph),
map_(map),
- max_expr_id_(max_expr_id),
- kill_by_offset_(kill_by_offset),
+ aliased_set_(aliased_set),
in_(graph_->preorder().length()),
out_(graph_->preorder().length()),
gen_(graph_->preorder().length()),
@@ -3275,24 +3505,26 @@
out_values_(graph_->preorder().length()),
phis_(5),
worklist_(5),
- in_worklist_(NULL) {
+ in_worklist_(NULL),
+ forwarded_(false) {
const intptr_t num_blocks = graph_->preorder().length();
for (intptr_t i = 0; i < num_blocks; i++) {
- out_.Add(new BitVector(max_expr_id_));
- gen_.Add(new BitVector(max_expr_id_));
- kill_.Add(new BitVector(max_expr_id_));
- in_.Add(new BitVector(max_expr_id_));
+ out_.Add(new BitVector(aliased_set_->max_expr_id()));
+ gen_.Add(new BitVector(aliased_set_->max_expr_id()));
+ kill_.Add(new BitVector(aliased_set_->max_expr_id()));
+ in_.Add(new BitVector(aliased_set_->max_expr_id()));
exposed_values_.Add(NULL);
out_values_.Add(NULL);
}
}
- void Optimize() {
+ bool Optimize() {
ComputeInitialSets();
ComputeOutValues();
ForwardLoads();
EmitPhis();
+ return forwarded_;
}
private:
@@ -3320,16 +3552,16 @@
instr_it.Advance()) {
Instruction* instr = instr_it.Current();
- intptr_t offset_in_words = 0;
- if (IsInterferingStore(instr, &offset_in_words)) {
+ const Alias alias = aliased_set_->ComputeAliasForStore(instr);
+ if (!alias.IsNone()) {
// Interfering stores kill only loads from the same offset.
- if ((offset_in_words < kill_by_offset_.length()) &&
- (kill_by_offset_[offset_in_words] != NULL)) {
- kill->AddAll(kill_by_offset_[offset_in_words]);
+ if (aliased_set_->Contains(alias)) {
+ BitVector* killed = aliased_set_->Get(alias);
+ kill->AddAll(killed);
// There is no need to clear out_values when clearing GEN set
// because only those values that are in the GEN set
// will ever be used.
- gen->RemoveAll(kill_by_offset_[offset_in_words]);
+ gen->RemoveAll(killed);
// Only forward stores to normal arrays and float64 arrays
// to loads because other array stores (intXX/uintXX/float32)
@@ -3338,7 +3570,7 @@
if (array_store == NULL ||
array_store->class_id() == kArrayCid ||
array_store->class_id() == kTypedDataFloat64ArrayCid) {
- Definition* load = map_->Lookup(instr->AsDefinition());
+ Definition* load = map_->Lookup(instr);
if (load != NULL) {
// Store has a corresponding numbered load. Try forwarding
// stored value to it.
@@ -3348,7 +3580,7 @@
}
}
}
- ASSERT(instr->IsDefinition() &&
+ ASSERT(!instr->IsDefinition() ||
!IsLoadEliminationCandidate(instr->AsDefinition()));
continue;
}
@@ -3383,6 +3615,7 @@
defn->ReplaceUsesWith(replacement);
instr_it.RemoveCurrentFromGraph();
+ forwarded_ = true;
continue;
} else if (!kill->Contains(expr_id)) {
// This is an exposed load: it is the first representative of a
@@ -3391,7 +3624,8 @@
if (exposed_values == NULL) {
static const intptr_t kMaxExposedValuesInitialSize = 5;
exposed_values = new ZoneGrowableArray<Definition*>(
- Utils::Minimum(kMaxExposedValuesInitialSize, max_expr_id_));
+ Utils::Minimum(kMaxExposedValuesInitialSize,
+ aliased_set_->max_expr_id()));
}
exposed_values->Add(defn);
@@ -3417,7 +3651,7 @@
// These phis are not inserted at the graph immediately because some of them
// might become redundant after load forwarding is done.
void ComputeOutValues() {
- BitVector* temp = new BitVector(max_expr_id_);
+ BitVector* temp = new BitVector(aliased_set_->max_expr_id());
bool changed = true;
while (changed) {
@@ -3591,6 +3825,7 @@
load->ReplaceUsesWith(replacement);
load->RemoveFromGraph();
load->SetReplacement(replacement);
+ forwarded_ = true;
}
}
}
@@ -3668,8 +3903,8 @@
ZoneGrowableArray<Definition*>* CreateBlockOutValues() {
ZoneGrowableArray<Definition*>* out =
- new ZoneGrowableArray<Definition*>(max_expr_id_);
- for (intptr_t i = 0; i < max_expr_id_; i++) {
+ new ZoneGrowableArray<Definition*>(aliased_set_->max_expr_id());
+ for (intptr_t i = 0; i < aliased_set_->max_expr_id(); i++) {
out->Add(NULL);
}
return out;
@@ -3677,11 +3912,10 @@
FlowGraph* graph_;
DirectChainedHashMap<LoadKeyValueTrait>* map_;
- const intptr_t max_expr_id_;
// Mapping between field offsets in words and expression ids of loads from
// that offset.
- const GrowableArray<BitVector*>& kill_by_offset_;
+ AliasedSet* aliased_set_;
// Per block sets of expression ids for loads that are: incoming (available
// on the entry), outgoing (available on the exit), generated and killed.
@@ -3706,6 +3940,9 @@
GrowableArray<PhiInstr*> worklist_;
BitVector* in_worklist_;
+ // True if any load was eliminated.
+ bool forwarded_;
+
DISALLOW_COPY_AND_ASSIGN(LoadOptimizer);
};
@@ -3715,11 +3952,16 @@
if (FLAG_load_cse) {
GrowableArray<BitVector*> kill_by_offs(10);
DirectChainedHashMap<LoadKeyValueTrait> map;
- const intptr_t max_expr_id =
- NumberLoadExpressions(graph, &map, &kill_by_offs);
- if (max_expr_id > 0) {
- LoadOptimizer load_optimizer(graph, max_expr_id, &map, kill_by_offs);
- load_optimizer.Optimize();
+ AliasedSet* aliased_set = NumberLoadExpressions(graph, &map);
+ if (!aliased_set->IsEmpty()) {
+ // If any loads were forwarded return true from Optimize to run load
+ // forwarding again. This will allow to forward chains of loads.
+ // This is especially important for context variables as they are built
+ // as loads from loaded context.
+ // TODO(vegorov): renumber newly discovered congruences during the
+ // forwarding to forward chains without running whole pass twice.
+ LoadOptimizer load_optimizer(graph, aliased_set, &map);
+ changed = load_optimizer.Optimize() || changed;
}
}
@@ -4310,10 +4552,7 @@
SetValue(instr, object);
return;
}
- if (instr->type_arguments().IsUninstantiatedIdentity() &&
- !object.IsNull() &&
- object.IsTypeArguments() &&
- (TypeArguments::Cast(object).Length() == len)) {
+ if (instr->type_arguments().IsUninstantiatedIdentity()) {
SetValue(instr, object);
return;
}
@@ -4502,6 +4741,27 @@
}
+void ConstantPropagator::VisitFloat32x4Constructor(
+ Float32x4ConstructorInstr* instr) {
+ SetValue(instr, non_constant_);
+}
+
+
+void ConstantPropagator::VisitFloat32x4Shuffle(Float32x4ShuffleInstr* instr) {
+ SetValue(instr, non_constant_);
+}
+
+
+void ConstantPropagator::VisitFloat32x4Zero(Float32x4ZeroInstr* instr) {
+ SetValue(instr, non_constant_);
+}
+
+
+void ConstantPropagator::VisitFloat32x4Splat(Float32x4SplatInstr* instr) {
+ SetValue(instr, non_constant_);
+}
+
+
void ConstantPropagator::VisitMathSqrt(MathSqrtInstr* instr) {
const Object& value = instr->value()->definition()->constant_value();
if (IsNonConstant(value)) {
diff --git a/runtime/vm/flow_graph_optimizer.h b/runtime/vm/flow_graph_optimizer.h
index 80c8e7f..4bc64c3 100644
--- a/runtime/vm/flow_graph_optimizer.h
+++ b/runtime/vm/flow_graph_optimizer.h
@@ -132,6 +132,9 @@
bool InstanceCallNeedsClassCheck(InstanceCallInstr* call) const;
bool MethodExtractorNeedsClassCheck(InstanceCallInstr* call) const;
+ bool InlineFloat32x4Getter(InstanceCallInstr* call,
+ MethodRecognizer::Kind getter);
+
void InlineImplicitInstanceGetter(InstanceCallInstr* call);
void InlineArrayLengthGetter(InstanceCallInstr* call,
intptr_t length_offset,
diff --git a/runtime/vm/flow_graph_type_propagator.cc b/runtime/vm/flow_graph_type_propagator.cc
index ec1a880..f3f77f8 100644
--- a/runtime/vm/flow_graph_type_propagator.cc
+++ b/runtime/vm/flow_graph_type_propagator.cc
@@ -734,11 +734,9 @@
return false;
}
- if (value_type->IsMoreSpecificThan(dst_type())) {
- return UpdateType(*value_type);
- }
-
- return false;
+ return UpdateType(value_type->IsMoreSpecificThan(dst_type())
+ ? *value_type
+ : CompileType::FromAbstractType(dst_type()));
}
@@ -967,6 +965,32 @@
}
+CompileType Float32x4ShuffleInstr::ComputeType() const {
+ if ((op_kind() == MethodRecognizer::kFloat32x4ShuffleX) ||
+ (op_kind() == MethodRecognizer::kFloat32x4ShuffleY) ||
+ (op_kind() == MethodRecognizer::kFloat32x4ShuffleZ) ||
+ (op_kind() == MethodRecognizer::kFloat32x4ShuffleW)) {
+ return CompileType::FromCid(kDoubleCid);
+ }
+ return CompileType::FromCid(kFloat32x4Cid);
+}
+
+
+CompileType Float32x4ConstructorInstr::ComputeType() const {
+ return CompileType::FromCid(kFloat32x4Cid);
+}
+
+
+CompileType Float32x4ZeroInstr::ComputeType() const {
+ return CompileType::FromCid(kFloat32x4Cid);
+}
+
+
+CompileType Float32x4SplatInstr::ComputeType() const {
+ return CompileType::FromCid(kFloat32x4Cid);
+}
+
+
CompileType MathSqrtInstr::ComputeType() const {
return CompileType::FromCid(kDoubleCid);
}
diff --git a/runtime/vm/gc_marker.cc b/runtime/vm/gc_marker.cc
index 35d6c62..e15c532 100644
--- a/runtime/vm/gc_marker.cc
+++ b/runtime/vm/gc_marker.cc
@@ -187,10 +187,6 @@
}
marking_stack_->Push(raw_obj);
- // Update the number of used bytes on this page for fast accounting.
- HeapPage* page = PageSpace::PageFor(raw_obj);
- page->AddUsed(raw_obj->Size());
-
// TODO(iposva): Should we mark the classes early?
MarkObject(raw_class, NULL);
}
diff --git a/runtime/vm/gc_sweeper.cc b/runtime/vm/gc_sweeper.cc
index d87ea64..439cdd7 100644
--- a/runtime/vm/gc_sweeper.cc
+++ b/runtime/vm/gc_sweeper.cc
@@ -7,7 +7,6 @@
#include "vm/freelist.h"
#include "vm/globals.h"
#include "vm/heap.h"
-#include "vm/heap_trace.h"
#include "vm/pages.h"
namespace dart {
@@ -15,47 +14,29 @@
intptr_t GCSweeper::SweepPage(HeapPage* page, FreeList* freelist) {
// Keep track of the discovered live object sizes to be able to finish
// sweeping early. Reset the per page in_use count for the next marking phase.
- intptr_t in_use_swept = 0;
- intptr_t in_use = page->used();
- page->set_used(0);
-
- // Whole page is empty. Do not enter anything into the freelist.
- if (in_use == 0) {
- return 0;
- }
+ intptr_t in_use = 0;
bool is_executable = (page->type() == HeapPage::kExecutable);
- uword current = page->object_start();
+ uword start = page->object_start();
uword end = page->object_end();
+ uword current = start;
while (current < end) {
intptr_t obj_size;
- if (in_use_swept == in_use && !HeapTrace::is_enabled()) {
- // No more marked objects will be found on this page.
- obj_size = end - current;
- freelist->Free(current, obj_size);
- break;
- }
RawObject* raw_obj = RawObject::FromAddr(current);
if (raw_obj->IsMarked()) {
// Found marked object. Clear the mark bit and update swept bytes.
raw_obj->ClearMarkBit();
obj_size = raw_obj->Size();
- in_use_swept += obj_size;
+ in_use += obj_size;
} else {
uword free_end = current + raw_obj->Size();
- if (HeapTrace::is_enabled()) {
- heap_->trace()->TraceSweep(current);
- }
while (free_end < end) {
RawObject* next_obj = RawObject::FromAddr(free_end);
if (next_obj->IsMarked()) {
// Reached the end of the free block.
break;
}
- if (HeapTrace::is_enabled()) {
- heap_->trace()->TraceSweep(free_end);
- }
// Expand the free block by the size of this object.
free_end += next_obj->Size();
}
@@ -63,21 +44,22 @@
if (is_executable) {
memset(reinterpret_cast<void*>(current), 0xcc, obj_size);
}
- freelist->Free(current, obj_size);
+ if ((current != start) || (free_end != end)) {
+ // Only add to the free list if not covering the whole page.
+ freelist->Free(current, obj_size);
+ }
}
current += obj_size;
}
+ ASSERT(current == end);
- return in_use_swept;
+ return in_use;
}
intptr_t GCSweeper::SweepLargePage(HeapPage* page) {
RawObject* raw_obj = RawObject::FromAddr(page->object_start());
if (!raw_obj->IsMarked()) {
- if (HeapTrace::is_enabled()) {
- heap_->trace()->TraceSweep(page->object_start());
- }
// The large object was not marked. Used size is zero, which also tells the
// calling code that the large object page can be recycled.
return 0;
diff --git a/runtime/vm/handles_impl.h b/runtime/vm/handles_impl.h
index a856638..95d7515 100644
--- a/runtime/vm/handles_impl.h
+++ b/runtime/vm/handles_impl.h
@@ -6,7 +6,6 @@
#define VM_HANDLES_IMPL_H_
#include "vm/heap.h"
-#include "vm/heap_trace.h"
#include "vm/visitor.h"
namespace dart {
@@ -116,10 +115,6 @@
Handles* handles = isolate->current_zone()->handles();
ASSERT(handles != NULL);
uword address = handles->AllocateHandleInZone();
- if (HeapTrace::is_enabled()) {
- uword zone_addr = reinterpret_cast<uword>(isolate->current_zone());
- isolate->heap()->trace()->TraceAllocateZoneHandle(address, zone_addr);
- }
return address;
}
@@ -153,13 +148,6 @@
zone_blocks_ = NULL;
// Delete all the scoped handle blocks.
- // Do not trace if there is no current isolate. This can happen during
- // isolate shutdown.
- if (HeapTrace::is_enabled() && Isolate::Current() != NULL) {
- Isolate::Current()->heap()->trace()->TraceDeleteScopedHandles();
- }
-
-
scoped_blocks_ = first_scoped_block_.next_block();
DeleteHandleBlocks(scoped_blocks_);
first_scoped_block_.ReInit();
diff --git a/runtime/vm/hash_map.h b/runtime/vm/hash_map.h
index 22efc32..fefd788 100644
--- a/runtime/vm/hash_map.h
+++ b/runtime/vm/hash_map.h
@@ -57,9 +57,12 @@
typename KeyValueTrait::Value
DirectChainedHashMap<KeyValueTrait>::
Lookup(typename KeyValueTrait::Key key) const {
+ const typename KeyValueTrait::Value kNoValue =
+ static_cast<typename KeyValueTrait::Value>(0);
+
uword hash = static_cast<uword>(KeyValueTrait::Hashcode(key));
uword pos = Bound(hash);
- if (KeyValueTrait::ValueOf(array_[pos].kv) != NULL) {
+ if (KeyValueTrait::ValueOf(array_[pos].kv) != kNoValue) {
if (KeyValueTrait::IsKeyEqual(array_[pos].kv, key)) {
return KeyValueTrait::ValueOf(array_[pos].kv);
}
@@ -72,7 +75,7 @@
next = lists_[next].next;
}
}
- return NULL;
+ return kNoValue;
}
@@ -95,6 +98,9 @@
template <typename KeyValueTrait>
void DirectChainedHashMap<KeyValueTrait>::Resize(intptr_t new_size) {
+ const typename KeyValueTrait::Value kNoValue =
+ static_cast<typename KeyValueTrait::Value>(0);
+
ASSERT(new_size > count_);
// Hashing the values into the new array has no more collisions than in the
// old hash map, so we can use the existing lists_ array, if we are careful.
@@ -119,7 +125,7 @@
if (old_array != NULL) {
// Iterate over all the elements in lists, rehashing them.
for (intptr_t i = 0; i < old_size; ++i) {
- if (KeyValueTrait::ValueOf(old_array[i].kv) != NULL) {
+ if (KeyValueTrait::ValueOf(old_array[i].kv) != kNoValue) {
intptr_t current = old_array[i].next;
while (current != kNil) {
Insert(lists_[current].kv);
@@ -166,14 +172,17 @@
template <typename KeyValueTrait>
void DirectChainedHashMap<KeyValueTrait>::
Insert(typename KeyValueTrait::Pair kv) {
- ASSERT(KeyValueTrait::ValueOf(kv) != NULL);
+ const typename KeyValueTrait::Value kNoValue =
+ static_cast<typename KeyValueTrait::Value>(0);
+
+ ASSERT(KeyValueTrait::ValueOf(kv) != kNoValue);
// Resizing when half of the hashtable is filled up.
if (count_ >= array_size_ >> 1) Resize(array_size_ << 1);
ASSERT(count_ < array_size_);
count_++;
uword pos = Bound(
static_cast<uword>(KeyValueTrait::Hashcode(KeyValueTrait::KeyOf(kv))));
- if (KeyValueTrait::ValueOf(array_[pos].kv) == NULL) {
+ if (KeyValueTrait::ValueOf(array_[pos].kv) == kNoValue) {
array_[pos].kv = kv;
array_[pos].next = kNil;
} else {
@@ -186,7 +195,7 @@
lists_[new_element_pos].kv = kv;
lists_[new_element_pos].next = array_[pos].next;
ASSERT(array_[pos].next == kNil ||
- KeyValueTrait::ValueOf(lists_[array_[pos].next].kv) != NULL);
+ KeyValueTrait::ValueOf(lists_[array_[pos].next].kv) != kNoValue);
array_[pos].next = new_element_pos;
}
}
diff --git a/runtime/vm/heap.cc b/runtime/vm/heap.cc
index 0809917..d36c847 100644
--- a/runtime/vm/heap.cc
+++ b/runtime/vm/heap.cc
@@ -8,7 +8,6 @@
#include "platform/utils.h"
#include "vm/flags.h"
#include "vm/heap_profiler.h"
-#include "vm/heap_trace.h"
#include "vm/isolate.h"
#include "vm/object.h"
#include "vm/object_set.h"
@@ -41,7 +40,6 @@
kNewObjectAlignmentOffset);
old_space_ = new PageSpace(this, (FLAG_old_gen_heap_size * MB));
stats_.num_ = 0;
- heap_trace_ = new HeapTrace;
}
@@ -61,9 +59,6 @@
return AllocateOld(size, HeapPage::kData);
}
}
- if (HeapTrace::is_enabled()) {
- heap_trace_->TraceAllocation(addr, size);
- }
return addr;
}
@@ -80,9 +75,6 @@
return 0;
}
}
- if (HeapTrace::is_enabled()) {
- heap_trace_->TraceAllocation(addr, size);
- }
return addr;
}
diff --git a/runtime/vm/heap.h b/runtime/vm/heap.h
index ab0f5db..b85d262 100644
--- a/runtime/vm/heap.h
+++ b/runtime/vm/heap.h
@@ -15,7 +15,6 @@
namespace dart {
// Forward declarations.
-class HeapTrace;
class Isolate;
class ObjectPointerVisitor;
class ObjectSet;
@@ -59,7 +58,7 @@
switch (space) {
case kNew:
// Do not attempt to allocate very large objects in new space.
- if (!PageSpace::IsPageAllocatableSize(size)) {
+ if (!IsAllocatableInNewSpace(size)) {
return AllocateOld(size, HeapPage::kData);
}
return AllocateNew(size);
@@ -151,10 +150,6 @@
// Verify that all pointers in the heap point to the heap.
bool Verify() const;
- // Accessor function to get the HeapTrace used for tracing. There
- // should only ever be one of these per isolate
- HeapTrace* trace() const { return heap_trace_; }
-
// Print heap sizes.
void PrintSizes() const;
@@ -197,6 +192,10 @@
bool gc_in_progress() const { return gc_in_progress_; }
+ static bool IsAllocatableInNewSpace(intptr_t size) {
+ return size <= kNewAllocatableSize;
+ }
+
private:
class GCStats : public ValueObject {
public:
@@ -229,6 +228,8 @@
DISALLOW_COPY_AND_ASSIGN(GCStats);
};
+ static const intptr_t kNewAllocatableSize = 256 * KB;
+
Heap();
uword AllocateNew(intptr_t size);
@@ -246,9 +247,6 @@
// GC stats collection.
GCStats stats_;
- // The active heap trace.
- HeapTrace* heap_trace_;
-
// This heap is in read-only mode: No allocation is allowed.
bool read_only_;
diff --git a/runtime/vm/heap_test.cc b/runtime/vm/heap_test.cc
index 0a487e5..54d0cd7 100644
--- a/runtime/vm/heap_test.cc
+++ b/runtime/vm/heap_test.cc
@@ -9,8 +9,6 @@
namespace dart {
-// Only ia32 and x64 can run execution tests.
-#if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64)
TEST_CASE(OldGC) {
const char* kScriptChars =
"main() {\n"
@@ -48,6 +46,4 @@
Dart_ExitScope();
heap->CollectGarbage(Heap::kOld);
}
-
-#endif // defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64).
}
diff --git a/runtime/vm/heap_trace.cc b/runtime/vm/heap_trace.cc
deleted file mode 100644
index 56282c2..0000000
--- a/runtime/vm/heap_trace.cc
+++ /dev/null
@@ -1,488 +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.
-
-#include "vm/heap_trace.h"
-
-#include "include/dart_api.h"
-#include "vm/dart_api_state.h"
-#include "vm/debugger.h"
-#include "vm/isolate.h"
-#include "vm/object.h"
-#include "vm/object_set.h"
-#include "vm/object_store.h"
-#include "vm/os.h"
-#include "vm/stack_frame.h"
-#include "vm/unicode.h"
-
-namespace dart {
-
-DEFINE_FLAG(bool, heap_trace, false, "Enable heap tracing.");
-
-Dart_FileOpenCallback HeapTrace::open_callback_ = NULL;
-Dart_FileWriteCallback HeapTrace::write_callback_ = NULL;
-Dart_FileCloseCallback HeapTrace::close_callback_ = NULL;
-bool HeapTrace::is_enabled_ = false;
-
-class HeapTraceVisitor : public ObjectPointerVisitor {
- public:
- HeapTraceVisitor(Isolate* isolate,
- HeapTrace* heap_trace,
- ObjectSet* object_set)
- : ObjectPointerVisitor(isolate),
- heap_trace_(heap_trace),
- vm_isolate_(Dart::vm_isolate()),
- object_set_(object_set) {
- }
-
- void VisitPointers(RawObject** first, RawObject** last) {
- for (RawObject** current = first; current <= last; current++) {
- RawObject* raw_obj = *current;
-
- // We only care about objects in the heap
- // Also, since this visitor will frequently be encountering redudant
- // roots, we use an object_set to skip the duplicates.
- if (raw_obj->IsHeapObject() &&
- raw_obj != reinterpret_cast<RawObject*>(0x1) &&
- raw_obj != reinterpret_cast<RawObject*>(0xabababab) &&
- !object_set_->Contains(raw_obj) &&
- !vm_isolate_->heap()->Contains(RawObject::ToAddr(raw_obj))) {
- object_set_->Add(raw_obj);
- uword addr = RawObject::ToAddr(raw_obj);
- heap_trace_->TraceSingleRoot(addr);
- }
- }
- }
-
- private:
- HeapTrace* heap_trace_;
- Isolate* vm_isolate_;
- // TODO(cshapiro): replace with a sparse data structure.
- ObjectSet* object_set_;
- DISALLOW_COPY_AND_ASSIGN(HeapTraceVisitor);
-};
-
-
-class HeapTraceScopedHandleVisitor : public ObjectPointerVisitor {
- public:
- HeapTraceScopedHandleVisitor(Isolate* isolate, HeapTrace* heap_trace)
- : ObjectPointerVisitor(isolate), heap_trace_(heap_trace) {
- }
-
- void VisitPointers(RawObject** first, RawObject** last) {
- for (RawObject** current = first; current <= last; current++) {
- RawObject* raw_obj = *current;
- Heap* heap = isolate()->heap();
-
- // We only care about objects in the heap
- if (raw_obj->IsHeapObject() &&
- raw_obj != reinterpret_cast<RawObject*>(0x1) &&
- raw_obj != reinterpret_cast<RawObject*>(0xabababab) &&
- heap->Contains(RawObject::ToAddr(raw_obj))) {
- uword addr = RawObject::ToAddr(raw_obj);
- heap_trace_->TraceScopedHandle(addr);
- }
- }
- }
-
- private:
- HeapTrace* heap_trace_;
- DISALLOW_COPY_AND_ASSIGN(HeapTraceScopedHandleVisitor);
-};
-
-
-class HeapTraceObjectStoreVisitor : public ObjectPointerVisitor {
- public:
- HeapTraceObjectStoreVisitor(Isolate* isolate, HeapTrace* heap_trace)
- : ObjectPointerVisitor(isolate), heap_trace_(heap_trace) {
- }
-
- void VisitPointers(RawObject** first, RawObject** last) {
- for (RawObject** current = first; current <= last; current++) {
- RawObject* raw_obj = *current;
-
- // We only care about obects in the heap.
- if (raw_obj->IsHeapObject() &&
- raw_obj != reinterpret_cast<RawObject*>(0x1) &&
- raw_obj != reinterpret_cast<RawObject*>(0xabababab)) {
- uword addr = RawObject::ToAddr(raw_obj);
- heap_trace_->TraceObjectStorePointer(addr);
- }
- }
- }
-
- private:
- HeapTrace* heap_trace_;
- DISALLOW_COPY_AND_ASSIGN(HeapTraceObjectStoreVisitor);
-};
-
-
-class HeapTraceInitialHeapVisitor : public ObjectVisitor {
- public:
- HeapTraceInitialHeapVisitor(Isolate* isolate, HeapTrace* heap_trace)
- : ObjectVisitor(isolate), heap_trace_(heap_trace) {}
-
- void VisitObject(RawObject* raw_obj) {
- heap_trace_->TraceSnapshotAlloc(raw_obj, raw_obj->Size());
- }
-
- private:
- HeapTrace* heap_trace_;
- DISALLOW_COPY_AND_ASSIGN(HeapTraceInitialHeapVisitor);
-};
-
-
-HeapTrace::HeapTrace() : isolate_initialized_(false), output_stream_(NULL) {
-}
-
-
-HeapTrace::~HeapTrace() {
- if (isolate_initialized_) {
- (*close_callback_)(output_stream_);
- }
-}
-
-
-void HeapTrace::InitOnce(Dart_FileOpenCallback open_callback,
- Dart_FileWriteCallback write_callback,
- Dart_FileCloseCallback close_callback) {
- ASSERT(open_callback != NULL);
- ASSERT(write_callback != NULL);
- ASSERT(close_callback != NULL);
- HeapTrace::open_callback_ = open_callback;
- HeapTrace::write_callback_ = write_callback;
- HeapTrace::close_callback_ = close_callback;
- HeapTrace::is_enabled_ = true;
-}
-
-
-ObjectSet* HeapTrace::CreateEmptyObjectSet() const {
- Isolate* isolate = Isolate::Current();
- uword start, end;
- isolate->heap()->StartEndAddress(&start, &end);
-
- Isolate* vm_isolate = Dart::vm_isolate();
- uword vm_start, vm_end;
- vm_isolate->heap()->StartEndAddress(&vm_start, &vm_end);
-
- ObjectSet* allocated_set = new ObjectSet(Utils::Minimum(start, vm_start),
- Utils::Maximum(end, vm_end));
-
- return allocated_set;
-}
-
-
-void HeapTrace::ResizeObjectSet() {
- Isolate* isolate = Isolate::Current();
- uword start, end;
- isolate->heap()->StartEndAddress(&start, &end);
- Isolate* vm_isolate = Dart::vm_isolate();
- uword vm_start, vm_end;
- vm_isolate->heap()->StartEndAddress(&vm_start, &vm_end);
- object_set_.Resize(Utils::Minimum(start, vm_start),
- Utils::Maximum(end, vm_end));
-}
-
-
-void HeapTrace::Init(Isolate* isolate) {
- // Do not trace the VM isolate
- if (isolate == Dart::vm_isolate()) {
- return;
- }
- ASSERT(isolate_initialized_ == false);
- const char* format = "%s.htrace";
- intptr_t len = OS::SNPrint(NULL, 0, format, isolate->name());
- char* filename = new char[len + 1];
- OS::SNPrint(filename, len + 1, format, isolate->name());
- output_stream_ = (*open_callback_)(filename);
- ASSERT(output_stream_ != NULL);
- delete[] filename;
- isolate_initialized_ = true;
-
- HeapTraceObjectStoreVisitor object_store_visitor(isolate, this);
- isolate->object_store()->VisitObjectPointers(&object_store_visitor);
-
- // Visit any objects that may have been allocated during startup,
- // before we started tracing.
- HeapTraceInitialHeapVisitor heap_visitor(isolate, this);
- isolate->heap()->IterateObjects(&heap_visitor);
- TraceRoots(isolate);
-}
-
-
-// Allocation Record - 'A' (0x41)
-//
-// Format:
-// 'A'
-// uword - address of allocated object
-// uword - size of allocated object
-void HeapTrace::TraceAllocation(uword addr, intptr_t size) {
- if (isolate_initialized_) {
- {
- AllocationRecord rec(this);
- rec.Write(addr);
- rec.Write(size);
- }
- TraceRoots(Isolate::Current());
- }
-}
-
-
-// Snapshot Allocation Record - 'B' (0x41)
-//
-// Format:
-// 'B'
-// uword - address of allocated object
-// uword - size of allocated object
-void HeapTrace::TraceSnapshotAlloc(RawObject* obj, intptr_t size) {
- if (isolate_initialized_) {
- SnapshotAllocationRecord rec(this);
- rec.Write(RawObject::ToAddr(obj));
- rec.Write(static_cast<uword>(size));
- }
-}
-
-
-// Allocate Zone Handle Record - 'Z' (0x5a)
-//
-// Format:
-// 'Z'
-// uword - handle address (where the handle is pointing)
-// uword - zone address (address of the zone the handle is in)
-void HeapTrace::TraceAllocateZoneHandle(uword handle, uword zone_addr) {
- if (isolate_initialized_) {
- AllocZoneHandleRecord rec(this);
- rec.Write(handle);
- rec.Write(zone_addr);
- }
-}
-
-
-// Delete Zone Record - 'z' (0x7a)
-//
-// Format:
-// 'z'
-// uword - zone address (all the handles in that zone are now gone)
-void HeapTrace::TraceDeleteZone(Zone* zone) {
- if (isolate_initialized_) {
- DeleteZoneRecord rec(this);
- rec.Write(reinterpret_cast<uword>(zone));
- }
-}
-
-
-// Delete Scoped Hanldes Record - 's' (0x73)
-//
-// Format:
-// 's'
-void HeapTrace::TraceDeleteScopedHandles() {
- if (isolate_initialized_) {
- DeleteScopedHandlesRecord rec(this);
- }
-}
-
-
-// Copy Record - 'C' (0x43)
-//
-// Format:
-// 'C'
-// uword - old address
-// uword - new address
-void HeapTrace::TraceCopy(uword from_addr, uword to_addr) {
- if (isolate_initialized_) {
- CopyRecord rec(this);
- rec.Write(from_addr);
- rec.Write(to_addr);
- }
-}
-
-
-// Object Store Recorda - 'O'(0x4f)
-//
-// Format:
-// 'O'
-// uword - address
-void HeapTrace::TraceObjectStorePointer(uword addr) {
- if (isolate_initialized_) {
- ObjectStoreRecord rec(this);
- rec.Write(addr);
- }
-}
-
-
-// Promotion Records - 'P' (0x50)
-//
-// Format:
-// 'P'
-// uword - old address
-// uword - new address
-void HeapTrace::TracePromotion(uword old_addr, uword promoted_addr) {
- if (isolate_initialized_) {
- PromotionRecord rec(this);
- rec.Write(old_addr);
- rec.Write(promoted_addr);
- }
-}
-
-
-// Death Range Record - 'L' (0x4c)
-//
-// Format:
-// 'L'
-// uword - inclusive start address of the space being left
-// uword - exclusive end address of the space being left
-void HeapTrace::TraceDeathRange(uword inclusive_start, uword exclusive_end) {
- if (isolate_initialized_) {
- DeathRangeRecord rec(this);
- rec.Write(inclusive_start);
- rec.Write(exclusive_end);
- }
-}
-
-
-// Register Class Record - 'K' (0x4b)
-//
-// Format:
-// 'K'
-// uword - address ( the address of the class)
-void HeapTrace::TraceRegisterClass(const Class& cls) {
- if (isolate_initialized_) {
- RegisterClassRecord rec(this);
- rec.Write(RawObject::ToAddr(cls.raw()));
- }
-}
-
-
-// Scoped Handle Record - 'H' (0x48)
-//
-// Format:
-// 'H'
-// uword - adress of the scoped handle (where it is pointing)
-void HeapTrace::TraceScopedHandle(uword handle) {
- if (isolate_initialized_) {
- AllocScopedHandleRecord rec(this);
- rec.Write(handle);
- }
-}
-
-
-// Root Record - 'R' (0x52)
-//
-// Format:
-// 'R'
-// uword - address
-void HeapTrace::TraceSingleRoot(uword root_addr) {
- if (isolate_initialized_) {
- RootRecord rec(this);
- rec.Write(root_addr);
- }
-}
-
-
-// Sweep Record - 'S'
-//
-// Format:
-// 'S'
-// uword - address
-void HeapTrace::TraceSweep(uword sweept_addr) {
- if (isolate_initialized_) {
- SweepRecord rec(this);
- rec.Write(sweept_addr);
- }
-}
-
-
-// Does not output any records directly,
-// but does call TraceSingleRoot
-void HeapTrace::TraceRoots(Isolate* isolate) {
- if (isolate_initialized_) {
- ResizeObjectSet();
- HeapTraceVisitor visitor(isolate, this, &object_set_);
- HeapTraceScopedHandleVisitor handle_visitor(isolate, this);
-
- bool visit_prologue_weak_handles = true;
- bool validate_frames = false;
-
- // Visit objects in per isolate stubs.
- StubCode::VisitObjectPointers(&visitor);
-
- // stack
- StackFrameIterator frames_iterator(validate_frames);
- StackFrame* frame = frames_iterator.NextFrame();
- while (frame != NULL) {
- frame->VisitObjectPointers(&visitor);
- frame = frames_iterator.NextFrame();
- }
-
- if (isolate->api_state() != NULL) {
- isolate->api_state()->VisitObjectPointers(&visitor,
- visit_prologue_weak_handles);
- }
-
- // Visit the top context which is stored in the isolate.
- RawContext* top_context = isolate->top_context();
- visitor.VisitPointer(reinterpret_cast<RawObject**>(&top_context));
-
- // Visit the currently active IC data array.
- RawArray* ic_data_array = isolate->ic_data_array();
- visitor.VisitPointer(reinterpret_cast<RawObject**>(&ic_data_array));
-
- // Visit objects in the debugger.
- isolate->debugger()->VisitObjectPointers(&visitor);
-
- isolate->current_zone()->handles()->
- VisitUnvisitedScopedHandles(&handle_visitor);
-
- object_set_.FastClear();
- }
-}
-
-
-// Store Record - 'U' (0x55)
-//
-// Format:
-// 'U'
-// uword - originating object address (where a pointer is being stored)
-// uword - byte offset into origin where the pointer is being stored
-// uword - value of the pointer being stored
-void HeapTrace::TraceStoreIntoObject(uword object,
- uword field_addr,
- uword value) {
- if (isolate_initialized_) {
- // We don't care about pointers into the VM_Islate heap, so skip them.
- // There should not be any pointers /out/ of the VM isolate; so we
- // do not check object.
- if (Isolate::Current()->heap()->Contains(value)) {
- StoreRecord rec(this);
- uword slot_offset = field_addr - object;
-
- rec.Write(object);
- rec.Write(slot_offset);
- rec.Write(value);
- }
- }
-}
-
-
-// Mark Sweep Start Record - '{' (0x7b)
-//
-// Format:
-// '{'
-void HeapTrace::TraceMarkSweepStart() {
- if (isolate_initialized_) {
- MarkSweepStartRecord rec(this);
- }
-}
-
-
-// Mark Sweep Finish Record - '}' (0x7d)
-//
-// Format:
-// '}'
-void HeapTrace::TraceMarkSweepFinish() {
- if (isolate_initialized_) {
- MarkSweepFinishRecord rec(this);
- }
-}
-
-} // namespace dart
diff --git a/runtime/vm/heap_trace.h b/runtime/vm/heap_trace.h
deleted file mode 100644
index 983f7df..0000000
--- a/runtime/vm/heap_trace.h
+++ /dev/null
@@ -1,213 +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.
-
-#ifndef VM_HEAP_TRACE_H_
-#define VM_HEAP_TRACE_H_
-
-#include "include/dart_api.h"
-#include "vm/globals.h"
-#include "vm/object_set.h"
-
-namespace dart {
-
-// Forward declarations.
-class HeapTraceVisitor;
-class Isolate;
-class RawClass;
-class RawObject;
-class RawString;
-class BaseZone;
-
-class HeapTrace {
- public:
- enum RecordSize {
- kRootSize = 5,
- kAllocSize = 9,
- kSnapshotAllocSize = 9,
- kCopySize = 9,
- kStoreSize = 13,
- kSweepSize = 5,
- kDeathRangeSize = 9,
- kPromotionSize = 9,
- kAllocZoneHandleSize = 9,
- kDeleteZoneSize = 5,
- kRegisterClassSize = 5,
- kAllocScopedHandleSize = 5,
- kDeleteScopedHandlesSize = 1,
- kMarkSweepStartSize = 1,
- kMarkSweepFinishSize = 1,
- kObjectStoreSize = 5
- };
-
- enum RecordType {
- kRootType = 'R',
- kAllocType = 'A',
- kSnapshotAllocType = 'B',
- kCopyType = 'C',
- kStoreType = 'U',
- kSweepType = 'S',
- kDeathRangeType = 'L',
- kPromotionType = 'P',
- kAllocZoneHandleType = 'Z',
- kDeleteZoneType = 'z',
- kRegisterClassType = 'K',
- kAllocScopedHandleType = 'H',
- kDeleteScopedHandlesType = 'h',
- kMarkSweepStartType = '{',
- kMarkSweepFinishType = '}',
- kObjectStoreType = 'O'
- };
-
- template <RecordType T, RecordSize N>
- class Record {
- public:
- explicit Record(HeapTrace* trace): cursor_(0), trace_(trace) {
- ASSERT(N >= 1);
- buffer_[0] = T;
- ++cursor_;
- }
- ~Record() {
- (*trace_->write_callback_)(Buffer(), Length(), trace_->output_stream_);
- }
-
- void Write(uword word) {
- ASSERT(cursor_ + sizeof(word) <= N);
- memmove(&buffer_[cursor_], &word, sizeof(word));
- cursor_ += sizeof(word);
- }
-
- intptr_t Length() const { return cursor_; }
-
- const uint8_t* Buffer() const {
- ASSERT(cursor_ == N);
- return buffer_;
- }
-
- private:
- uint8_t buffer_[N];
- intptr_t cursor_;
- HeapTrace* trace_;
- DISALLOW_COPY_AND_ASSIGN(Record);
- };
-
- typedef Record<kRootType, kRootSize> RootRecord;
- typedef Record<kAllocType, kAllocSize> AllocationRecord;
- typedef Record<kSnapshotAllocType, kSnapshotAllocSize>
- SnapshotAllocationRecord;
- typedef Record<kCopyType, kCopySize> CopyRecord;
- typedef Record<kStoreType, kStoreSize> StoreRecord;
- typedef Record<kSweepType, kSweepSize> SweepRecord;
- typedef Record<kDeathRangeType, kDeathRangeSize> DeathRangeRecord;
- typedef Record<kPromotionType, kPromotionSize> PromotionRecord;
- typedef Record<kAllocZoneHandleType, kAllocZoneHandleSize>
- AllocZoneHandleRecord;
- typedef Record<kDeleteZoneType, kDeleteZoneSize>
- DeleteZoneRecord;
- typedef Record<kRegisterClassType, kRegisterClassSize> RegisterClassRecord;
- typedef Record<kAllocScopedHandleType, kAllocScopedHandleSize>
- AllocScopedHandleRecord;
- typedef Record<kDeleteScopedHandlesType, kDeleteScopedHandlesSize>
- DeleteScopedHandlesRecord;
- typedef Record<kMarkSweepStartType, kMarkSweepStartSize> MarkSweepStartRecord;
- typedef Record<kMarkSweepFinishType, kMarkSweepFinishSize>
- MarkSweepFinishRecord;
- typedef Record<kObjectStoreType, kObjectStoreSize> ObjectStoreRecord;
-
- HeapTrace();
- ~HeapTrace();
-
- // Called by the isolate just before EnableGrowthControl. Indicates
- // the Isolate is initialized and enables tracing.
- void Init(Isolate* isolate);
-
- // Called when an object is allocated in the heap.
- void TraceAllocation(uword addr, intptr_t size);
-
- // Invoked after the snapshot is loaded at Isolate startup time.
- void TraceSnapshotAlloc(RawObject* obj, intptr_t size);
-
- // Rename to something like TraceAllocateZoneHandle (or whatever)
- void TraceAllocateZoneHandle(uword handle, uword zone_addr);
-
- // Invoked when a Zone block is deleted.
- void TraceDeleteZone(Zone* zone);
-
- // Invoked whenever the scoped handles are delelted.
- void TraceDeleteScopedHandles();
-
- // Invoked when objects are coped from the from space to the to space
- // by the scavenger.
- void TraceCopy(uword from_addr, uword to_addr);
-
- // Invoked on each pointer in the object store.
- void TraceObjectStorePointer(uword addr);
-
- // Invoked when an object is promoted from the new space to the old space.
- void TracePromotion(uword old_addr, uword promoted_addr);
-
- // Invoked after a scavenge with the addressed range of from-space
- void TraceDeathRange(uword inclusive_start, uword exclusive_end);
-
- // Invoked whenever a class is registered in the class table.
- void TraceRegisterClass(const Class& cls);
-
- // Invoked when an address is swept.
- void TraceSweep(uword sweept_addr);
-
- // Invoked when storing value into origin, and value is an object.
- void TraceStoreIntoObject(uword origin_object_addr,
- uword slot_addr,
- uword value);
-
- // Invoked when starting a mark-sweep collection on old space
- void TraceMarkSweepStart();
-
- // Invoked after finishing a mark sweep collection on old space.
- void TraceMarkSweepFinish();
-
- // Initialize tracing globablly across the VM. Invidual isolates
- // will still have to initialized themselves when they are started.
- static void InitOnce(Dart_FileOpenCallback open_callback,
- Dart_FileWriteCallback write_callback,
- Dart_FileCloseCallback close_callback);
-
- // Returns true if tracign is enabled for the VM.
- static bool is_enabled() { return is_enabled_; }
-
- private:
- ObjectSet* CreateEmptyObjectSet() const;
- void ResizeObjectSet();
-
- void TraceScopedHandle(uword handle);
-
- // A helper for PutRoots, called by HeapTraceVisitor.
- void TraceSingleRoot(uword root);
-
- // Invoked while tracing an allocation.
- void TraceRoots(Isolate* isolate);
-
- // Is the isolate we are tracing initialized?
- bool isolate_initialized_;
-
- void* output_stream_;
-
- ObjectSet object_set_;
-
- static Dart_FileOpenCallback open_callback_;
- static Dart_FileWriteCallback write_callback_;
- static Dart_FileCloseCallback close_callback_;
-
- static bool is_enabled_;
-
- friend class HeapTraceVisitor;
- friend class HeapTraceScopedHandleVisitor;
- friend class HeapTraceObjectStoreVisitor;
- friend class HeapTraceDebugObjectVisitor;
-
- DISALLOW_COPY_AND_ASSIGN(HeapTrace);
-};
-
-} // namespace dart
-
-#endif // VM_HEAP_TRACE_H_
diff --git a/runtime/vm/heap_trace_test.cc b/runtime/vm/heap_trace_test.cc
deleted file mode 100644
index eb0ca6b..0000000
--- a/runtime/vm/heap_trace_test.cc
+++ /dev/null
@@ -1,104 +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.
-
-#include <iostream>
-#include <sstream>
-#include <string>
-#include "vm/dart_api_impl.h"
-#include "vm/growable_array.h"
-#include "vm/heap.h"
-#include "vm/heap_trace.h"
-#include "vm/unit_test.h"
-
-namespace dart {
-
-// only ia32 can run heap trace tests.
-#if defined(TARGET_ARCH_IA32)
-static std::stringstream* global_stream;
-
-static void* OpenTraceFile(const char* name) {
- ASSERT(global_stream == NULL);
- global_stream = new std::stringstream;
- return reinterpret_cast<void*>(global_stream);
-}
-
-
-static void WriteToTraceFile(const void* data, intptr_t length, void* stream) {
- ASSERT(stream == global_stream);
- std::stringstream* sstream = reinterpret_cast<std::stringstream*>(stream);
- sstream->write(reinterpret_cast<const char*>(data), length);
-}
-
-
-static void CloseTraceFile(void *stream) {
- ASSERT(stream == global_stream);
- global_stream = NULL;
- delete reinterpret_cast<std::stringstream*>(stream);
-}
-
-
-bool DoesAllocationRecordExist(uword addr, const std::string& trace_string) {
- const char* raw_trace = trace_string.c_str();
- for (size_t i = 0; i < trace_string.length(); ++i) {
- if ((raw_trace[i] == 'A') && (i + 4 < trace_string.length())) {
- const uword candidate_address =
- *(reinterpret_cast<const uword*>(raw_trace + i + 1));
- if (candidate_address == addr) {
- return true;
- }
- }
- }
- return false;
-}
-
-
-bool DoesSweepRecordExist(uword addr, const std::string& trace_string) {
- const char* raw_trace = trace_string.c_str();
- for (size_t i = 0; i < trace_string.length(); ++i) {
- if ((raw_trace[i] == 'S') && (i + 4 < trace_string.length())) {
- const uword candidate_address =
- *(reinterpret_cast<const uword*>(raw_trace + i + 1));
- if (candidate_address == addr) {
- return true;
- }
- }
- }
- return false;
-}
-
-
-TEST_CASE(GCTraceAllocate) {
- HeapTrace::InitOnce(OpenTraceFile,
- WriteToTraceFile,
- CloseTraceFile);
-
- Isolate* isolate = Isolate::Current();
- isolate->heap()->trace()->Init(isolate);
-
- const int kArrayLen = 5;
- RawArray* raw_arr = Array::New(kArrayLen);
- uword addr = RawObject::ToAddr(raw_arr);
-
- ASSERT(DoesAllocationRecordExist(addr, global_stream->str()));
-}
-
-
-TEST_CASE(GCTraceSweep) {
- HeapTrace::InitOnce(OpenTraceFile,
- WriteToTraceFile,
- CloseTraceFile);
-
- Isolate* isolate = Isolate::Current();
- isolate->heap()->trace()->Init(isolate);
-
- const int kArrayLen = 5;
- RawArray* raw_arr = Array::New(kArrayLen, Heap::kOld);
- uword addr = RawObject::ToAddr(raw_arr);
-
- Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
- DoesSweepRecordExist(addr, global_stream->str());
-}
-#endif
-
-} // namespace dart
diff --git a/runtime/vm/il_printer.cc b/runtime/vm/il_printer.cc
index ce75a13..c0dffcc 100644
--- a/runtime/vm/il_printer.cc
+++ b/runtime/vm/il_printer.cc
@@ -603,6 +603,37 @@
}
+void Float32x4ShuffleInstr::PrintOperandsTo(BufferFormatter* f) const {
+ // TODO(johnmccutchan): Add proper string enumeration of shuffle.
+ f->Print("SHUFFLE ");
+ value()->PrintTo(f);
+}
+
+
+void Float32x4ZeroInstr::PrintOperandsTo(BufferFormatter* f) const {
+ f->Print("ZERO ");
+}
+
+
+void Float32x4SplatInstr::PrintOperandsTo(BufferFormatter* f) const {
+ f->Print("SPLAT ");
+ value()->PrintTo(f);
+}
+
+
+void Float32x4ConstructorInstr::PrintOperandsTo(BufferFormatter* f) const {
+ f->Print("Float32x4(");
+ value0()->PrintTo(f);
+ f->Print(", ");
+ value1()->PrintTo(f);
+ f->Print(", ");
+ value2()->PrintTo(f);
+ f->Print(", ");
+ value3()->PrintTo(f);
+ f->Print(")");
+}
+
+
void BinaryMintOpInstr::PrintOperandsTo(BufferFormatter* f) const {
f->Print("%s, ", Token::Str(op_kind()));
left()->PrintTo(f);
diff --git a/runtime/vm/instructions_mips.cc b/runtime/vm/instructions_mips.cc
index 69e99c2..41648b1 100644
--- a/runtime/vm/instructions_mips.cc
+++ b/runtime/vm/instructions_mips.cc
@@ -73,7 +73,7 @@
instr = Instr::At(reinterpret_cast<uword>(&i));
ASSERT(instr->OpcodeField() == LUI);
ASSERT(instr->RtField() == *reg);
- imm |= instr->UImmField();
+ imm |= (instr->UImmField() << 16);
*value = imm;
return end;
}
diff --git a/runtime/vm/intermediate_language.cc b/runtime/vm/intermediate_language.cc
index 55de520..ea389c7 100644
--- a/runtime/vm/intermediate_language.cc
+++ b/runtime/vm/intermediate_language.cc
@@ -1166,6 +1166,7 @@
case kTypedDataUint64ArrayCid:
case kTypedDataFloat32ArrayCid:
case kTypedDataFloat64ArrayCid:
+ case kTypedDataFloat32x4ArrayCid:
return true;
default:
return false;
diff --git a/runtime/vm/intermediate_language.h b/runtime/vm/intermediate_language.h
index 05b0a21..c8110bb 100644
--- a/runtime/vm/intermediate_language.h
+++ b/runtime/vm/intermediate_language.h
@@ -37,25 +37,25 @@
#define RECOGNIZED_LIST(V) \
V(_ObjectArray, get:length, ObjectArrayLength, 405297088) \
V(_ImmutableArray, get:length, ImmutableArrayLength, 433698233) \
- V(_TypedList, get:length, TypedDataLength, 231908172) \
- V(_TypedList, _getInt8, ByteArrayBaseGetInt8, 380843687) \
- V(_TypedList, _getUint8, ByteArrayBaseGetUint8, 380843687) \
- V(_TypedList, _getInt16, ByteArrayBaseGetInt16, 380843687) \
- V(_TypedList, _getUint16, ByteArrayBaseGetUint16, 380843687) \
- V(_TypedList, _getInt32, ByteArrayBaseGetInt32, 380843687) \
- V(_TypedList, _getUint32, ByteArrayBaseGetUint32, 380843687) \
- V(_TypedList, _getFloat32, ByteArrayBaseGetFloat32, 979971573) \
- V(_TypedList, _getFloat64, ByteArrayBaseGetFloat64, 979971573) \
- V(_TypedList, _getFloat32x4, ByteArrayBaseGetFloat32x4, 690339584) \
- V(_TypedList, _setInt8, ByteArrayBaseSetInt8, 287047804) \
- V(_TypedList, _setUint8, ByteArrayBaseSetUint8, 287047804) \
- V(_TypedList, _setInt16, ByteArrayBaseSetInt16, 287047804) \
- V(_TypedList, _setUint16, ByteArrayBaseSetUint16, 287047804) \
- V(_TypedList, _setInt32, ByteArrayBaseSetInt32, 287047804) \
- V(_TypedList, _setUint32, ByteArrayBaseSetUint32, 287047804) \
- V(_TypedList, _setFloat32, ByteArrayBaseSetFloat32, 1032541114) \
- V(_TypedList, _setFloat64, ByteArrayBaseSetFloat64, 1032541114) \
- V(_TypedList, _setFloat32x4, ByteArrayBaseSetFloat32x4, 1016704782) \
+ V(_TypedList, get:length, TypedDataLength, 1004567191) \
+ V(_TypedList, _getInt8, ByteArrayBaseGetInt8, 728842615) \
+ V(_TypedList, _getUint8, ByteArrayBaseGetUint8, 728842615) \
+ V(_TypedList, _getInt16, ByteArrayBaseGetInt16, 728842615) \
+ V(_TypedList, _getUint16, ByteArrayBaseGetUint16, 728842615) \
+ V(_TypedList, _getInt32, ByteArrayBaseGetInt32, 728842615) \
+ V(_TypedList, _getUint32, ByteArrayBaseGetUint32, 728842615) \
+ V(_TypedList, _getFloat32, ByteArrayBaseGetFloat32, 1067360925) \
+ V(_TypedList, _getFloat64, ByteArrayBaseGetFloat64, 1067360925) \
+ V(_TypedList, _getFloat32x4, ByteArrayBaseGetFloat32x4, 279982060) \
+ V(_TypedList, _setInt8, ByteArrayBaseSetInt8, 427754869) \
+ V(_TypedList, _setUint8, ByteArrayBaseSetUint8, 427754869) \
+ V(_TypedList, _setInt16, ByteArrayBaseSetInt16, 427754869) \
+ V(_TypedList, _setUint16, ByteArrayBaseSetUint16, 427754869) \
+ V(_TypedList, _setInt32, ByteArrayBaseSetInt32, 427754869) \
+ V(_TypedList, _setUint32, ByteArrayBaseSetUint32, 427754869) \
+ V(_TypedList, _setFloat32, ByteArrayBaseSetFloat32, 637235443) \
+ V(_TypedList, _setFloat64, ByteArrayBaseSetFloat64, 637235443) \
+ V(_TypedList, _setFloat32x4, ByteArrayBaseSetFloat32x4, 780994886) \
V(_GrowableObjectArray, get:length, GrowableArrayLength, 725548050) \
V(_GrowableObjectArray, get:_capacity, GrowableArrayCapacity, 725548050) \
V(_StringBase, get:length, StringBaseLength, 320803993) \
@@ -71,6 +71,17 @@
V(_Double, pow, DoublePow, 631903778) \
V(_Double, _modulo, DoubleMod, 437099337) \
V(::, sqrt, MathSqrt, 1662640002) \
+ V(Float32x4, Float32x4., Float32x4Constructor, 1327837070) \
+ V(Float32x4, Float32x4.zero, Float32x4Zero, 927169529) \
+ V(Float32x4, Float32x4.splat, Float32x4Splat, 1778587275) \
+ V(_Float32x4, get:xxxx, Float32x4ShuffleXXXX, 42621627) \
+ V(_Float32x4, get:yyyy, Float32x4ShuffleYYYY, 42621627) \
+ V(_Float32x4, get:zzzz, Float32x4ShuffleZZZZ, 42621627) \
+ V(_Float32x4, get:wwww, Float32x4ShuffleWWWW, 42621627) \
+ V(_Float32x4, get:x, Float32x4ShuffleX, 211144022) \
+ V(_Float32x4, get:y, Float32x4ShuffleY, 211144022) \
+ V(_Float32x4, get:z, Float32x4ShuffleZ, 211144022) \
+ V(_Float32x4, get:w, Float32x4ShuffleW, 211144022) \
// Class that recognizes the name and owner of a function and returns the
// corresponding enum. See RECOGNIZED_LIST above for list of recognizable
@@ -505,6 +516,11 @@
M(GuardField) \
M(IfThenElse) \
M(BinaryFloat32x4Op) \
+ M(Float32x4Shuffle) \
+ M(Float32x4Constructor) \
+ M(Float32x4Zero) \
+ M(Float32x4Splat) \
+
#define FORWARD_DECLARATION(type) class type##Instr;
FOR_EACH_INSTRUCTION(FORWARD_DECLARATION)
@@ -755,6 +771,10 @@
friend class UnboxFloat32x4Instr;
friend class BinaryDoubleOpInstr;
friend class BinaryFloat32x4OpInstr;
+ friend class Float32x4ZeroInstr;
+ friend class Float32x4SplatInstr;
+ friend class Float32x4ShuffleInstr;
+ friend class Float32x4ConstructorInstr;
friend class BinaryMintOpInstr;
friend class BinarySmiOpInstr;
friend class UnarySmiOpInstr;
@@ -1073,7 +1093,7 @@
class ForwardInstructionIterator : public ValueObject {
public:
explicit ForwardInstructionIterator(BlockEntryInstr* block_entry)
- : block_entry_(block_entry), current_(block_entry) {
+ : current_(block_entry) {
Advance();
}
@@ -1090,7 +1110,6 @@
Instruction* Current() const { return current_; }
private:
- BlockEntryInstr* block_entry_;
Instruction* current_;
};
@@ -2319,6 +2338,8 @@
virtual bool HasSideEffect() const { return false; }
+ virtual bool AttributesEqual(Instruction* other) const { return true; }
+
private:
DISALLOW_COPY_AND_ASSIGN(CurrentContextInstr);
};
@@ -4139,6 +4160,194 @@
};
+class Float32x4ShuffleInstr : public TemplateDefinition<1> {
+ public:
+ Float32x4ShuffleInstr(MethodRecognizer::Kind op_kind, Value* value,
+ InstanceCallInstr* instance_call)
+ : op_kind_(op_kind) {
+ SetInputAt(0, value);
+ deopt_id_ = instance_call->deopt_id();
+ }
+
+ Value* value() const { return inputs_[0]; }
+
+ MethodRecognizer::Kind op_kind() const { return op_kind_; }
+
+ virtual void PrintOperandsTo(BufferFormatter* f) const;
+
+ virtual bool CanDeoptimize() const { return false; }
+
+ virtual bool HasSideEffect() const { return false; }
+
+ virtual bool AffectedBySideEffect() const { return false; }
+
+ virtual bool AttributesEqual(Instruction* other) const {
+ return op_kind() == other->AsFloat32x4Shuffle()->op_kind();
+ }
+
+ virtual Representation representation() const {
+ if ((op_kind_ == MethodRecognizer::kFloat32x4ShuffleX) ||
+ (op_kind_ == MethodRecognizer::kFloat32x4ShuffleY) ||
+ (op_kind_ == MethodRecognizer::kFloat32x4ShuffleZ) ||
+ (op_kind_ == MethodRecognizer::kFloat32x4ShuffleW)) {
+ return kUnboxedDouble;
+ }
+ return kUnboxedFloat32x4;
+ }
+
+ virtual Representation RequiredInputRepresentation(intptr_t idx) const {
+ ASSERT(idx == 0);
+ return kUnboxedFloat32x4;
+ }
+
+ virtual intptr_t DeoptimizationTarget() const {
+ // Direct access since this instruction cannot deoptimize, and the deopt-id
+ // was inherited from another instruction that could deoptimize.
+ return deopt_id_;
+ }
+
+ DECLARE_INSTRUCTION(Float32x4Shuffle)
+ virtual CompileType ComputeType() const;
+
+ private:
+ const MethodRecognizer::Kind op_kind_;
+
+ DISALLOW_COPY_AND_ASSIGN(Float32x4ShuffleInstr);
+};
+
+
+class Float32x4ConstructorInstr : public TemplateDefinition<4> {
+ public:
+ Float32x4ConstructorInstr(Value* value0, Value* value1, Value* value2,
+ Value* value3, StaticCallInstr* static_call) {
+ SetInputAt(0, value0);
+ SetInputAt(1, value1);
+ SetInputAt(2, value2);
+ SetInputAt(3, value3);
+ deopt_id_ = static_call->deopt_id();
+ }
+
+ Value* value0() const { return inputs_[0]; }
+ Value* value1() const { return inputs_[1]; }
+ Value* value2() const { return inputs_[2]; }
+ Value* value3() const { return inputs_[3]; }
+
+ virtual void PrintOperandsTo(BufferFormatter* f) const;
+
+ virtual bool CanDeoptimize() const { return false; }
+
+ virtual bool HasSideEffect() const { return false; }
+
+ virtual bool AffectedBySideEffect() const { return false; }
+
+ virtual bool AttributesEqual(Instruction* other) const { return true; }
+
+ virtual Representation representation() const {
+ return kUnboxedFloat32x4;
+ }
+
+ virtual Representation RequiredInputRepresentation(intptr_t idx) const {
+ ASSERT(idx >= 0 && idx < 4);
+ return kUnboxedDouble;
+ }
+
+ virtual intptr_t DeoptimizationTarget() const {
+ // Direct access since this instruction cannot deoptimize, and the deopt-id
+ // was inherited from another instruction that could deoptimize.
+ return deopt_id_;
+ }
+
+ DECLARE_INSTRUCTION(Float32x4Constructor)
+ virtual CompileType ComputeType() const;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Float32x4ConstructorInstr);
+};
+
+
+class Float32x4SplatInstr : public TemplateDefinition<1> {
+ public:
+ Float32x4SplatInstr(Value* value, StaticCallInstr* static_call) {
+ SetInputAt(0, value);
+ deopt_id_ = static_call->deopt_id();
+ }
+
+ Value* value() const { return inputs_[0]; }
+
+ virtual void PrintOperandsTo(BufferFormatter* f) const;
+
+ virtual bool CanDeoptimize() const { return false; }
+
+ virtual bool HasSideEffect() const { return false; }
+
+ virtual bool AffectedBySideEffect() const { return false; }
+
+ virtual bool AttributesEqual(Instruction* other) const { return true; }
+
+ virtual Representation representation() const {
+ return kUnboxedFloat32x4;
+ }
+
+ virtual Representation RequiredInputRepresentation(intptr_t idx) const {
+ ASSERT(idx == 0);
+ return kUnboxedDouble;
+ }
+
+ virtual intptr_t DeoptimizationTarget() const {
+ // Direct access since this instruction cannot deoptimize, and the deopt-id
+ // was inherited from another instruction that could deoptimize.
+ return deopt_id_;
+ }
+
+ DECLARE_INSTRUCTION(Float32x4Splat)
+ virtual CompileType ComputeType() const;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Float32x4SplatInstr);
+};
+
+
+class Float32x4ZeroInstr : public TemplateDefinition<0> {
+ public:
+ explicit Float32x4ZeroInstr(StaticCallInstr* static_call) {
+ deopt_id_ = static_call->deopt_id();
+ }
+
+ Value* value() const { return inputs_[0]; }
+
+ virtual void PrintOperandsTo(BufferFormatter* f) const;
+
+ virtual bool CanDeoptimize() const { return false; }
+
+ virtual bool HasSideEffect() const { return false; }
+
+ virtual bool AffectedBySideEffect() const { return false; }
+
+ virtual bool AttributesEqual(Instruction* other) const { return true; }
+
+ virtual Representation representation() const {
+ return kUnboxedFloat32x4;
+ }
+
+ virtual Representation RequiredInputRepresentation(intptr_t idx) const {
+ UNIMPLEMENTED();
+ return kUnboxedFloat32x4;
+ }
+
+ virtual intptr_t DeoptimizationTarget() const {
+ // Direct access since this instruction cannot deoptimize, and the deopt-id
+ // was inherited from another instruction that could deoptimize.
+ return deopt_id_;
+ }
+
+ DECLARE_INSTRUCTION(Float32x4Zero)
+ virtual CompileType ComputeType() const;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Float32x4ZeroInstr);
+};
+
+
class BinaryMintOpInstr : public TemplateDefinition<2> {
public:
BinaryMintOpInstr(Token::Kind op_kind,
diff --git a/runtime/vm/intermediate_language_arm.cc b/runtime/vm/intermediate_language_arm.cc
index 64e8e39..43043a5 100644
--- a/runtime/vm/intermediate_language_arm.cc
+++ b/runtime/vm/intermediate_language_arm.cc
@@ -95,10 +95,9 @@
__ LeaveDartFrame();
__ Ret();
- // Generate 2 NOP instructions so that the debugger can patch the return
- // pattern (1 instruction) with a call to the debug stub (3 instructions).
- __ nop();
- __ nop();
+ // No need to generate NOP instructions so that the debugger can patch the
+ // return pattern (3 instructions) with a call to the debug stub (also 3
+ // instructions).
compiler->AddCurrentDescriptor(PcDescriptors::kReturn,
Isolate::kNoDeoptId,
token_pos());
@@ -208,8 +207,8 @@
LocationSummary* summary =
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
summary->set_in(0, Location::RegisterLocation(R0)); // Value.
- summary->set_in(1, Location::RegisterLocation(R1)); // Instantiator.
- summary->set_in(2, Location::RegisterLocation(R2)); // Type arguments.
+ summary->set_in(1, Location::RegisterLocation(R2)); // Instantiator.
+ summary->set_in(2, Location::RegisterLocation(R1)); // Type arguments.
summary->set_out(Location::RegisterLocation(R0));
return summary;
}
@@ -344,7 +343,7 @@
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
locs->set_in(0, Location::RegisterLocation(R1));
locs->set_in(1, Location::RegisterLocation(R0));
- locs->set_temp(0, Location::RegisterLocation(R6));
+ locs->set_temp(0, Location::RegisterLocation(R5));
locs->set_out(Location::RegisterLocation(R0));
return locs;
}
@@ -352,7 +351,7 @@
// R1: left.
// R0: right.
-// Uses R6 to load ic_call_data.
+// Uses R5 to load ic_call_data.
static void EmitEqualityAsInstanceCall(FlowGraphCompiler* compiler,
intptr_t deopt_id,
intptr_t token_pos,
@@ -405,13 +404,9 @@
Label equality_done;
if (compiler->is_optimizing()) {
// No need to update IC data.
- Label is_true;
__ cmp(R0, ShifterOperand(R1));
- __ b(&is_true, EQ);
- __ LoadObject(R0, (kind == Token::kEQ) ? Bool::False() : Bool::True());
- __ b(&equality_done);
- __ Bind(&is_true);
- __ LoadObject(R0, (kind == Token::kEQ) ? Bool::True() : Bool::False());
+ __ LoadObject(R0, (kind == Token::kEQ) ? Bool::False() : Bool::True(), NE);
+ __ LoadObject(R0, (kind == Token::kEQ) ? Bool::True() : Bool::False(), EQ);
if (kind == Token::kNE) {
// Skip not-equal result conversion.
__ b(&equality_done);
@@ -420,7 +415,7 @@
// Call stub, load IC data in register. The stub will update ICData if
// necessary.
Register ic_data_reg = locs->temp(0).reg();
- ASSERT(ic_data_reg == R6); // Stub depends on it.
+ ASSERT(ic_data_reg == R5); // Stub depends on it.
__ LoadObject(ic_data_reg, equality_ic_data);
// Pass left in R1 and right in R0.
compiler->GenerateCall(token_pos,
@@ -430,15 +425,10 @@
}
__ Bind(&check_ne);
if (kind == Token::kNE) {
- Label true_label, done;
// Negate the condition: true label returns false and vice versa.
__ CompareObject(R0, Bool::True());
- __ b(&true_label, EQ);
- __ LoadObject(R0, Bool::True());
- __ b(&done);
- __ Bind(&true_label);
- __ LoadObject(R0, Bool::False());
- __ Bind(&done);
+ __ LoadObject(R0, Bool::True(), NE);
+ __ LoadObject(R0, Bool::False(), EQ);
}
__ Bind(&equality_done);
}
@@ -488,6 +478,25 @@
}
+static Condition NegateCondition(Condition condition) {
+ switch (condition) {
+ case EQ: return NE;
+ case NE: return EQ;
+ case LT: return GE;
+ case LE: return GT;
+ case GT: return LE;
+ case GE: return LT;
+ case CC: return CS;
+ case LS: return HI;
+ case HI: return LS;
+ case CS: return CC;
+ default:
+ UNIMPLEMENTED();
+ return EQ;
+ }
+}
+
+
static void EmitSmiComparisonOp(FlowGraphCompiler* compiler,
const LocationSummary& locs,
Token::Kind kind,
@@ -511,13 +520,8 @@
branch->EmitBranchOnCondition(compiler, true_condition);
} else {
Register result = locs.out().reg();
- Label done, is_true;
- __ b(&is_true, true_condition);
- __ LoadObject(result, Bool::False());
- __ b(&done);
- __ Bind(&is_true);
- __ LoadObject(result, Bool::True());
- __ Bind(&done);
+ __ LoadObject(result, Bool::True(), true_condition);
+ __ LoadObject(result, Bool::False(), NegateCondition(true_condition));
}
}
@@ -837,25 +841,192 @@
CompileType LoadIndexedInstr::ComputeType() const {
- UNIMPLEMENTED();
- return CompileType::Dynamic();
+ switch (class_id_) {
+ case kArrayCid:
+ case kImmutableArrayCid:
+ return CompileType::Dynamic();
+
+ case kTypedDataFloat32ArrayCid:
+ case kTypedDataFloat64ArrayCid:
+ return CompileType::FromCid(kDoubleCid);
+ case kTypedDataFloat32x4ArrayCid:
+ return CompileType::FromCid(kFloat32x4Cid);
+
+ case kTypedDataInt8ArrayCid:
+ case kTypedDataUint8ArrayCid:
+ case kTypedDataUint8ClampedArrayCid:
+ case kExternalTypedDataUint8ArrayCid:
+ case kExternalTypedDataUint8ClampedArrayCid:
+ case kTypedDataInt16ArrayCid:
+ case kTypedDataUint16ArrayCid:
+ case kOneByteStringCid:
+ case kTwoByteStringCid:
+ return CompileType::FromCid(kSmiCid);
+
+ case kTypedDataInt32ArrayCid:
+ case kTypedDataUint32ArrayCid:
+ // Result can be Smi or Mint when boxed.
+ // Instruction can deoptimize if we optimistically assumed that the result
+ // fits into Smi.
+ return CanDeoptimize() ? CompileType::FromCid(kSmiCid)
+ : CompileType::Int();
+
+ default:
+ UNIMPLEMENTED();
+ return CompileType::Dynamic();
+ }
}
Representation LoadIndexedInstr::representation() const {
- UNIMPLEMENTED();
- return kTagged;
+ switch (class_id_) {
+ case kArrayCid:
+ case kImmutableArrayCid:
+ case kTypedDataInt8ArrayCid:
+ case kTypedDataUint8ArrayCid:
+ case kTypedDataUint8ClampedArrayCid:
+ case kExternalTypedDataUint8ArrayCid:
+ case kExternalTypedDataUint8ClampedArrayCid:
+ case kTypedDataInt16ArrayCid:
+ case kTypedDataUint16ArrayCid:
+ case kOneByteStringCid:
+ case kTwoByteStringCid:
+ return kTagged;
+ case kTypedDataInt32ArrayCid:
+ case kTypedDataUint32ArrayCid:
+ // Instruction can deoptimize if we optimistically assumed that the result
+ // fits into Smi.
+ return CanDeoptimize() ? kTagged : kUnboxedMint;
+ case kTypedDataFloat32ArrayCid:
+ case kTypedDataFloat64ArrayCid:
+ return kUnboxedDouble;
+ case kTypedDataFloat32x4ArrayCid:
+ return kUnboxedFloat32x4;
+ default:
+ UNIMPLEMENTED();
+ return kTagged;
+ }
}
LocationSummary* LoadIndexedInstr::MakeLocationSummary() const {
- UNIMPLEMENTED();
- return NULL;
+ const intptr_t kNumInputs = 2;
+ const intptr_t kNumTemps = 0;
+ LocationSummary* locs =
+ new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
+ locs->set_in(0, Location::RequiresRegister());
+ // The smi index is either untagged (element size == 1), or it is left smi
+ // tagged (for all element sizes > 1).
+ // TODO(regis): Revisit and see if the index can be immediate.
+ locs->set_in(1, Location::WritableRegister());
+ if (representation() == kUnboxedDouble) {
+ locs->set_out(Location::RequiresFpuRegister());
+ } else {
+ locs->set_out(Location::RequiresRegister());
+ }
+ return locs;
}
void LoadIndexedInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- UNIMPLEMENTED();
+ Register array = locs()->in(0).reg();
+ 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();
+ }
+ __ AddImmediate(index.reg(),
+ FlowGraphCompiler::DataOffsetFor(class_id()) - kHeapObjectTag);
+ element_address = Address(array, index.reg(), LSL, 0);
+ }
+
+ if ((representation() == kUnboxedDouble) ||
+ (representation() == kUnboxedMint) ||
+ (representation() == kUnboxedFloat32x4)) {
+ UNIMPLEMENTED();
+ }
+
+ Register result = locs()->out().reg();
+ if ((index_scale() == 1) && index.IsRegister()) {
+ __ SmiUntag(index.reg());
+ }
+ switch (class_id()) {
+ case kTypedDataInt8ArrayCid:
+ ASSERT(index_scale() == 1);
+ __ ldrsb(result, element_address);
+ __ SmiTag(result);
+ break;
+ case kTypedDataUint8ArrayCid:
+ case kTypedDataUint8ClampedArrayCid:
+ case kExternalTypedDataUint8ArrayCid:
+ case kExternalTypedDataUint8ClampedArrayCid:
+ case kOneByteStringCid:
+ ASSERT(index_scale() == 1);
+ __ ldrb(result, element_address);
+ __ SmiTag(result);
+ break;
+ case kTypedDataInt16ArrayCid:
+ __ ldrsh(result, element_address);
+ __ SmiTag(result);
+ break;
+ case kTypedDataUint16ArrayCid:
+ case kTwoByteStringCid:
+ __ ldrh(result, element_address);
+ __ SmiTag(result);
+ break;
+ case kTypedDataInt32ArrayCid: {
+ Label* deopt = compiler->AddDeoptStub(deopt_id(), kDeoptInt32Load);
+ __ ldr(result, element_address);
+ // Verify that the signed value in 'result' can fit inside a Smi.
+ __ CompareImmediate(result, 0xC0000000);
+ __ b(deopt, MI);
+ __ SmiTag(result);
+ }
+ break;
+ case kTypedDataUint32ArrayCid: {
+ Label* deopt = compiler->AddDeoptStub(deopt_id(), kDeoptUint32Load);
+ __ ldr(result, element_address);
+ // Verify that the unsigned value in 'result' can fit inside a Smi.
+ __ tst(result, ShifterOperand(0xC0000000));
+ __ b(deopt, NE);
+ __ SmiTag(result);
+ }
+ break;
+ default:
+ ASSERT((class_id() == kArrayCid) || (class_id() == kImmutableArrayCid));
+ __ ldr(result, element_address);
+ break;
+ }
}
@@ -1039,28 +1210,25 @@
FieldAddress field_nullability_operand(
field_reg, Field::is_nullable_offset());
+ if (value_cid_reg == kNoRegister) {
+ ASSERT(!compiler->is_optimizing());
+ value_cid_reg = R3;
+ ASSERT((value_cid_reg != value_reg) && (field_reg != value_cid_reg));
+ }
+
if (value_cid == kDynamicCid) {
- if (value_cid_reg == kNoRegister) {
- ASSERT(!compiler->is_optimizing());
- value_cid_reg = R3;
- ASSERT((value_cid_reg != value_reg) && (field_reg != value_cid_reg));
- }
-
LoadValueCid(compiler, value_cid_reg, value_reg);
-
__ ldr(IP, field_cid_operand);
__ cmp(value_cid_reg, ShifterOperand(IP));
__ b(&ok, EQ);
__ ldr(IP, field_nullability_operand);
__ cmp(value_cid_reg, ShifterOperand(IP));
} else if (value_cid == kNullCid) {
- // TODO(regis): IP may conflict. Revisit.
- __ ldr(IP, field_nullability_operand);
- __ CompareImmediate(IP, value_cid);
+ __ ldr(value_cid_reg, field_nullability_operand);
+ __ CompareImmediate(value_cid_reg, value_cid);
} else {
- // TODO(regis): IP may conflict. Revisit.
- __ ldr(IP, field_cid_operand);
- __ CompareImmediate(IP, value_cid);
+ __ ldr(value_cid_reg, field_cid_operand);
+ __ CompareImmediate(value_cid_reg, value_cid);
}
__ b(&ok, EQ);
@@ -1274,11 +1442,10 @@
LocationSummary* InstantiateTypeArgumentsInstr::MakeLocationSummary() const {
const intptr_t kNumInputs = 1;
- const intptr_t kNumTemps = 1;
+ const intptr_t kNumTemps = 0;
LocationSummary* locs =
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
locs->set_in(0, Location::RegisterLocation(R0));
- locs->set_temp(0, Location::RegisterLocation(R1));
locs->set_out(Location::RegisterLocation(R0));
return locs;
}
@@ -1287,48 +1454,34 @@
void InstantiateTypeArgumentsInstr::EmitNativeCode(
FlowGraphCompiler* compiler) {
Register instantiator_reg = locs()->in(0).reg();
- Register temp = locs()->temp(0).reg();
Register result_reg = locs()->out().reg();
// 'instantiator_reg' is the instantiator AbstractTypeArguments object
// (or null).
- // If the instantiator is null and if the type argument vector
- // instantiated from null becomes a vector of dynamic, then use null as
- // the type arguments.
- Label type_arguments_instantiated;
- const intptr_t len = type_arguments().Length();
- if (type_arguments().IsRawInstantiatedRaw(len)) {
- __ LoadImmediate(IP, reinterpret_cast<intptr_t>(Object::null()));
- __ cmp(instantiator_reg, ShifterOperand(IP));
- __ b(&type_arguments_instantiated, EQ);
+ if (!type_arguments().IsUninstantiatedIdentity()) {
+ // If the instantiator is null and if the type argument vector
+ // instantiated from null becomes a vector of dynamic, then use null as
+ // the type arguments.
+ Label type_arguments_instantiated;
+ const intptr_t len = type_arguments().Length();
+ if (type_arguments().IsRawInstantiatedRaw(len)) {
+ __ LoadImmediate(IP, reinterpret_cast<intptr_t>(Object::null()));
+ __ cmp(instantiator_reg, ShifterOperand(IP));
+ __ b(&type_arguments_instantiated, EQ);
+ }
+ // Instantiate non-null type arguments.
+ // A runtime call to instantiate the type arguments is required.
+ __ PushObject(Object::ZoneHandle()); // Make room for the result.
+ __ PushObject(type_arguments());
+ __ Push(instantiator_reg); // Push instantiator type arguments.
+ compiler->GenerateCallRuntime(token_pos(),
+ deopt_id(),
+ kInstantiateTypeArgumentsRuntimeEntry,
+ locs());
+ __ Drop(2); // Drop instantiator and uninstantiated type arguments.
+ __ Pop(result_reg); // Pop instantiated type arguments.
+ __ Bind(&type_arguments_instantiated);
}
- // Instantiate non-null type arguments.
- if (type_arguments().IsUninstantiatedIdentity()) {
- // Check if the instantiator type argument vector is a TypeArguments of a
- // matching length and, if so, use it as the instantiated type_arguments.
- // No need to check the instantiator ('instantiator_reg') for null here,
- // because a null instantiator will have the wrong class (Null instead of
- // TypeArguments).
- Label type_arguments_uninstantiated;
- __ CompareClassId(instantiator_reg, kTypeArgumentsCid, temp);
- __ b(&type_arguments_uninstantiated, NE);
- __ ldr(temp,
- FieldAddress(instantiator_reg, TypeArguments::length_offset()));
- __ CompareImmediate(temp, Smi::RawValue(len));
- __ b(&type_arguments_instantiated, EQ);
- __ Bind(&type_arguments_uninstantiated);
- }
- // A runtime call to instantiate the type arguments is required.
- __ PushObject(Object::ZoneHandle()); // Make room for the result.
- __ PushObject(type_arguments());
- __ Push(instantiator_reg); // Push instantiator type arguments.
- compiler->GenerateCallRuntime(token_pos(),
- deopt_id(),
- kInstantiateTypeArgumentsRuntimeEntry,
- locs());
- __ Drop(2); // Drop instantiator and uninstantiated type arguments.
- __ Pop(result_reg); // Pop instantiated type arguments.
- __ Bind(&type_arguments_instantiated);
ASSERT(instantiator_reg == result_reg);
// 'result_reg': Instantiated type arguments.
}
@@ -1337,12 +1490,11 @@
LocationSummary*
ExtractConstructorTypeArgumentsInstr::MakeLocationSummary() const {
const intptr_t kNumInputs = 1;
- const intptr_t kNumTemps = 1;
+ const intptr_t kNumTemps = 0;
LocationSummary* locs =
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
locs->set_in(0, Location::RequiresRegister());
locs->set_out(Location::SameAsFirstInput());
- locs->set_temp(0, Location::RequiresRegister());
return locs;
}
@@ -1352,40 +1504,28 @@
Register instantiator_reg = locs()->in(0).reg();
Register result_reg = locs()->out().reg();
ASSERT(instantiator_reg == result_reg);
- Register temp_reg = locs()->temp(0).reg();
// instantiator_reg is the instantiator type argument vector, i.e. an
// AbstractTypeArguments object (or null).
- // If the instantiator is null and if the type argument vector
- // instantiated from null becomes a vector of dynamic, then use null as
- // the type arguments.
- Label type_arguments_instantiated;
- const intptr_t len = type_arguments().Length();
- if (type_arguments().IsRawInstantiatedRaw(len)) {
- __ CompareImmediate(instantiator_reg,
- reinterpret_cast<intptr_t>(Object::null()));
- __ b(&type_arguments_instantiated, EQ);
+ if (!type_arguments().IsUninstantiatedIdentity()) {
+ // If the instantiator is null and if the type argument vector
+ // instantiated from null becomes a vector of dynamic, then use null as
+ // the type arguments.
+ Label type_arguments_instantiated;
+ const intptr_t len = type_arguments().Length();
+ if (type_arguments().IsRawInstantiatedRaw(len)) {
+ __ CompareImmediate(instantiator_reg,
+ reinterpret_cast<intptr_t>(Object::null()));
+ __ b(&type_arguments_instantiated, EQ);
+ }
+ // Instantiate non-null type arguments.
+ // In the non-factory case, we rely on the allocation stub to
+ // instantiate the type arguments.
+ __ LoadObject(result_reg, type_arguments());
+ // result_reg: uninstantiated type arguments.
+ __ Bind(&type_arguments_instantiated);
}
- // Instantiate non-null type arguments.
- if (type_arguments().IsUninstantiatedIdentity()) {
- // Check if the instantiator type argument vector is a TypeArguments of a
- // matching length and, if so, use it as the instantiated type_arguments.
- // No need to check instantiator_reg for null here, because a null
- // instantiator will have the wrong class (Null instead of TypeArguments).
- Label type_arguments_uninstantiated;
- __ CompareClassId(instantiator_reg, kTypeArgumentsCid, temp_reg);
- __ b(&type_arguments_uninstantiated, NE);
- __ ldr(temp_reg,
- FieldAddress(instantiator_reg, TypeArguments::length_offset()));
- __ CompareImmediate(temp_reg, Smi::RawValue(type_arguments().Length()));
- __ b(&type_arguments_instantiated, EQ);
- __ Bind(&type_arguments_uninstantiated);
- }
- // In the non-factory case, we rely on the allocation stub to
- // instantiate the type arguments.
- __ LoadObject(result_reg, type_arguments());
- // result_reg: uninstantiated type arguments.
- __ Bind(&type_arguments_instantiated);
+ ASSERT(instantiator_reg == result_reg);
// result_reg: uninstantiated or instantiated type arguments.
}
@@ -1393,12 +1533,11 @@
LocationSummary*
ExtractConstructorInstantiatorInstr::MakeLocationSummary() const {
const intptr_t kNumInputs = 1;
- const intptr_t kNumTemps = 1;
+ const intptr_t kNumTemps = 0;
LocationSummary* locs =
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
locs->set_in(0, Location::RequiresRegister());
locs->set_out(Location::SameAsFirstInput());
- locs->set_temp(0, Location::RequiresRegister());
return locs;
}
@@ -1407,51 +1546,31 @@
FlowGraphCompiler* compiler) {
Register instantiator_reg = locs()->in(0).reg();
ASSERT(locs()->out().reg() == instantiator_reg);
- Register temp_reg = locs()->temp(0).reg();
// instantiator_reg is the instantiator AbstractTypeArguments object
- // (or null). If the instantiator is null and if the type argument vector
- // instantiated from null becomes a vector of dynamic, then use null as
- // the type arguments and do not pass the instantiator.
- Label done;
- const intptr_t len = type_arguments().Length();
- if (type_arguments().IsRawInstantiatedRaw(len)) {
- Label instantiator_not_null;
- __ CompareImmediate(instantiator_reg,
- reinterpret_cast<intptr_t>(Object::null()));
- __ b(&instantiator_not_null, NE);
- // Null was used in VisitExtractConstructorTypeArguments as the
- // instantiated type arguments, no proper instantiator needed.
- __ LoadImmediate(instantiator_reg,
- Smi::RawValue(StubCode::kNoInstantiator));
- __ b(&done);
- __ Bind(&instantiator_not_null);
- }
- // Instantiate non-null type arguments.
+ // (or null).
if (type_arguments().IsUninstantiatedIdentity()) {
- // TODO(regis): The following emitted code is duplicated in
- // VisitExtractConstructorTypeArguments above. The reason is that the code
- // is split between two computations, so that each one produces a
- // single value, rather than producing a pair of values.
- // If this becomes an issue, we should expose these tests at the IL level.
-
- // Check if the instantiator type argument vector is a TypeArguments of a
- // matching length and, if so, use it as the instantiated type_arguments.
- // No need to check the instantiator ('instantiator_reg') for null here,
- // because a null instantiator will have the wrong class (Null instead of
- // TypeArguments).
- __ CompareClassId(instantiator_reg, kTypeArgumentsCid, temp_reg);
- __ b(&done, NE);
- __ ldr(temp_reg,
- FieldAddress(instantiator_reg, TypeArguments::length_offset()));
- __ CompareImmediate(temp_reg, Smi::RawValue(type_arguments().Length()));
- __ b(&done, NE);
// The instantiator was used in VisitExtractConstructorTypeArguments as the
// instantiated type arguments, no proper instantiator needed.
__ LoadImmediate(instantiator_reg,
Smi::RawValue(StubCode::kNoInstantiator));
+ } else {
+ // If the instantiator is null and if the type argument vector
+ // instantiated from null becomes a vector of dynamic, then use null as
+ // the type arguments and do not pass the instantiator.
+ const intptr_t len = type_arguments().Length();
+ if (type_arguments().IsRawInstantiatedRaw(len)) {
+ Label instantiator_not_null;
+ __ CompareImmediate(instantiator_reg,
+ reinterpret_cast<intptr_t>(Object::null()));
+ __ b(&instantiator_not_null, NE);
+ // Null was used in VisitExtractConstructorTypeArguments as the
+ // instantiated type arguments, no proper instantiator needed.
+ __ LoadImmediate(instantiator_reg,
+ Smi::RawValue(StubCode::kNoInstantiator));
+ __ Bind(&instantiator_not_null);
+ }
}
- __ Bind(&done);
// instantiator_reg: instantiator or kNoInstantiator.
}
@@ -1625,14 +1744,24 @@
case Token::kMUL: {
// Keep left value tagged and untag right value.
const intptr_t value = Smi::Cast(constant).Value();
- if (value == 2) {
- __ mov(result, ShifterOperand(left, LSL, 1));
+ if (deopt == NULL) {
+ if (value == 2) {
+ __ mov(result, ShifterOperand(left, LSL, 1));
+ } else {
+ __ LoadImmediate(IP, value);
+ __ mul(result, left, IP);
+ }
} else {
- __ LoadImmediate(IP, value);
- __ mul(result, left, IP);
- }
- if (deopt != NULL) {
- UNIMPLEMENTED();
+ if (value == 2) {
+ __ mov(IP, ShifterOperand(left, ASR, 31)); // IP = sign of left.
+ __ mov(result, ShifterOperand(left, LSL, 1));
+ } else {
+ __ LoadImmediate(IP, value);
+ __ smull(result, IP, left, IP);
+ }
+ // IP: result bits 32..63.
+ __ cmp(IP, ShifterOperand(result, ASR, 31));
+ __ b(deopt, NE);
}
break;
}
@@ -1840,6 +1969,50 @@
}
+LocationSummary* Float32x4ShuffleInstr::MakeLocationSummary() const {
+ UNIMPLEMENTED();
+ return NULL;
+}
+
+
+void Float32x4ShuffleInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+ UNIMPLEMENTED();
+}
+
+
+LocationSummary* Float32x4ConstructorInstr::MakeLocationSummary() const {
+ UNIMPLEMENTED();
+ return NULL;
+}
+
+
+void Float32x4ConstructorInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+ UNIMPLEMENTED();
+}
+
+
+LocationSummary* Float32x4ZeroInstr::MakeLocationSummary() const {
+ UNIMPLEMENTED();
+ return NULL;
+}
+
+
+void Float32x4ZeroInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+ UNIMPLEMENTED();
+}
+
+
+LocationSummary* Float32x4SplatInstr::MakeLocationSummary() const {
+ UNIMPLEMENTED();
+ return NULL;
+}
+
+
+void Float32x4SplatInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+ UNIMPLEMENTED();
+}
+
+
LocationSummary* MathSqrtInstr::MakeLocationSummary() const {
UNIMPLEMENTED();
return NULL;
@@ -1971,13 +2144,56 @@
LocationSummary* CheckClassInstr::MakeLocationSummary() const {
- UNIMPLEMENTED();
- return NULL;
+ const intptr_t kNumInputs = 1;
+ const intptr_t kNumTemps = 0;
+ LocationSummary* summary =
+ new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
+ summary->set_in(0, Location::RequiresRegister());
+ if (!null_check()) {
+ summary->AddTemp(Location::RequiresRegister());
+ }
+ return summary;
}
void CheckClassInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- UNIMPLEMENTED();
+ if (null_check()) {
+ Label* deopt = compiler->AddDeoptStub(deopt_id(),
+ kDeoptCheckClass);
+ __ CompareImmediate(locs()->in(0).reg(),
+ reinterpret_cast<intptr_t>(Object::null()));
+ __ b(deopt, EQ);
+ return;
+ }
+
+ ASSERT((unary_checks().GetReceiverClassIdAt(0) != kSmiCid) ||
+ (unary_checks().NumberOfChecks() > 1));
+ Register value = locs()->in(0).reg();
+ Register temp = locs()->temp(0).reg();
+ Label* deopt = compiler->AddDeoptStub(deopt_id(),
+ kDeoptCheckClass);
+ Label is_ok;
+ intptr_t cix = 0;
+ if (unary_checks().GetReceiverClassIdAt(cix) == kSmiCid) {
+ __ tst(value, ShifterOperand(kSmiTagMask));
+ __ b(&is_ok, EQ);
+ cix++; // Skip first check.
+ } else {
+ __ tst(value, ShifterOperand(kSmiTagMask));
+ __ b(deopt, EQ);
+ }
+ __ LoadClassId(temp, value);
+ const intptr_t num_checks = unary_checks().NumberOfChecks();
+ for (intptr_t i = cix; i < num_checks; i++) {
+ ASSERT(unary_checks().GetReceiverClassIdAt(i) != kSmiCid);
+ __ CompareImmediate(temp, unary_checks().GetReceiverClassIdAt(i));
+ if (i == (num_checks - 1)) {
+ __ b(deopt, NE);
+ } else {
+ __ b(&is_ok, EQ);
+ }
+ }
+ __ Bind(&is_ok);
}
@@ -2001,13 +2217,44 @@
LocationSummary* CheckArrayBoundInstr::MakeLocationSummary() const {
- UNIMPLEMENTED();
- return NULL;
+ const intptr_t kNumInputs = 2;
+ const intptr_t kNumTemps = 0;
+ LocationSummary* locs =
+ new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
+ locs->set_in(0, Location::RegisterOrSmiConstant(length()));
+ locs->set_in(1, Location::RegisterOrSmiConstant(index()));
+ return locs;
}
void CheckArrayBoundInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- UNIMPLEMENTED();
+ Label* deopt = compiler->AddDeoptStub(deopt_id(),
+ kDeoptCheckArrayBound);
+ if (locs()->in(0).IsConstant() && locs()->in(1).IsConstant()) {
+ // Unconditionally deoptimize for constant bounds checks because they
+ // only occur only when index is out-of-bounds.
+ __ b(deopt);
+ return;
+ }
+
+ if (locs()->in(1).IsConstant()) {
+ Register length = locs()->in(0).reg();
+ const Object& constant = locs()->in(1).constant();
+ ASSERT(constant.IsSmi());
+ __ CompareImmediate(length, reinterpret_cast<int32_t>(constant.raw()));
+ __ b(deopt, LS);
+ } else if (locs()->in(0).IsConstant()) {
+ ASSERT(locs()->in(0).constant().IsSmi());
+ const Smi& smi_const = Smi::Cast(locs()->in(0).constant());
+ Register index = locs()->in(1).reg();
+ __ CompareImmediate(index, reinterpret_cast<int32_t>(smi_const.raw()));
+ __ b(deopt, CS);
+ } else {
+ Register length = locs()->in(0).reg();
+ Register index = locs()->in(1).reg();
+ __ cmp(index, ShifterOperand(length));
+ __ b(deopt, CS);
+ }
}
@@ -2120,26 +2367,6 @@
}
-static Condition NegateCondition(Condition condition) {
- switch (condition) {
- case EQ: return NE;
- case NE: return EQ;
- case LT: return GE;
- case LE: return GT;
- case GT: return LE;
- case GE: return LT;
- case CC: return CS;
- case LS: return HI;
- case HI: return LS;
- case CS: return CC;
- default:
- OS::Print("Error %d\n", condition);
- UNIMPLEMENTED();
- return EQ;
- }
-}
-
-
void ControlInstruction::EmitBranchOnValue(FlowGraphCompiler* compiler,
bool value) {
if (value && !compiler->CanFallThroughTo(true_successor())) {
@@ -2221,14 +2448,9 @@
}
Register result = locs()->out().reg();
- Label load_true, done;
Condition true_condition = (kind() == Token::kEQ_STRICT) ? EQ : NE;
- __ b(&load_true, true_condition);
- __ LoadObject(result, Bool::False());
- __ b(&done);
- __ Bind(&load_true);
- __ LoadObject(result, Bool::True());
- __ Bind(&done);
+ __ LoadObject(result, Bool::True(), true_condition);
+ __ LoadObject(result, Bool::False(), NegateCondition(true_condition));
}
@@ -2275,34 +2497,54 @@
Register value = locs()->in(0).reg();
Register result = locs()->out().reg();
- Label done;
__ LoadObject(result, Bool::True());
__ cmp(result, ShifterOperand(value));
- __ b(&done, NE);
- __ LoadObject(result, Bool::False());
- __ Bind(&done);
+ __ LoadObject(result, Bool::False(), EQ);
}
LocationSummary* ChainContextInstr::MakeLocationSummary() const {
- UNIMPLEMENTED();
- return NULL;
+ return LocationSummary::Make(1,
+ Location::NoLocation(),
+ LocationSummary::kNoCall);
}
void ChainContextInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- UNIMPLEMENTED();
+ Register context_value = locs()->in(0).reg();
+
+ // Chain the new context in context_value to its parent in CTX.
+ __ StoreIntoObject(context_value,
+ FieldAddress(context_value, Context::parent_offset()),
+ CTX);
+ // Set new context as current context.
+ __ mov(CTX, ShifterOperand(context_value));
}
LocationSummary* StoreVMFieldInstr::MakeLocationSummary() const {
- UNIMPLEMENTED();
- return NULL;
+ const intptr_t kNumInputs = 2;
+ const intptr_t kNumTemps = 0;
+ LocationSummary* locs =
+ new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
+ locs->set_in(0, value()->NeedsStoreBuffer() ? Location::WritableRegister()
+ : Location::RequiresRegister());
+ locs->set_in(1, Location::RequiresRegister());
+ return locs;
}
void StoreVMFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- UNIMPLEMENTED();
+ Register value_reg = locs()->in(0).reg();
+ Register dest_reg = locs()->in(1).reg();
+
+ if (value()->NeedsStoreBuffer()) {
+ __ StoreIntoObject(dest_reg, FieldAddress(dest_reg, offset_in_bytes()),
+ value_reg);
+ } else {
+ __ StoreIntoObjectNoBarrier(
+ dest_reg, FieldAddress(dest_reg, offset_in_bytes()), value_reg);
+ }
}
diff --git a/runtime/vm/intermediate_language_ia32.cc b/runtime/vm/intermediate_language_ia32.cc
index ad46c62..00cd501 100644
--- a/runtime/vm/intermediate_language_ia32.cc
+++ b/runtime/vm/intermediate_language_ia32.cc
@@ -1859,11 +1859,10 @@
LocationSummary* InstantiateTypeArgumentsInstr::MakeLocationSummary() const {
const intptr_t kNumInputs = 1;
- const intptr_t kNumTemps = 1;
+ const intptr_t kNumTemps = 0;
LocationSummary* locs =
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
locs->set_in(0, Location::RegisterLocation(EAX));
- locs->set_temp(0, Location::RegisterLocation(ECX));
locs->set_out(Location::RegisterLocation(EAX));
return locs;
}
@@ -1872,48 +1871,35 @@
void InstantiateTypeArgumentsInstr::EmitNativeCode(
FlowGraphCompiler* compiler) {
Register instantiator_reg = locs()->in(0).reg();
- Register temp = locs()->temp(0).reg();
Register result_reg = locs()->out().reg();
// 'instantiator_reg' is the instantiator AbstractTypeArguments object
// (or null).
- // If the instantiator is null and if the type argument vector
- // instantiated from null becomes a vector of dynamic, then use null as
- // the type arguments.
- Label type_arguments_instantiated;
- const intptr_t len = type_arguments().Length();
- if (type_arguments().IsRawInstantiatedRaw(len)) {
- const Immediate& raw_null =
- Immediate(reinterpret_cast<intptr_t>(Object::null()));
- __ cmpl(instantiator_reg, raw_null);
- __ j(EQUAL, &type_arguments_instantiated, Assembler::kNearJump);
+ if (!type_arguments().IsUninstantiatedIdentity()) {
+ // If the instantiator is null and if the type argument vector
+ // instantiated from null becomes a vector of dynamic, then use null as
+ // the type arguments.
+ Label type_arguments_instantiated;
+ const intptr_t len = type_arguments().Length();
+ if (type_arguments().IsRawInstantiatedRaw(len)) {
+ const Immediate& raw_null =
+ Immediate(reinterpret_cast<intptr_t>(Object::null()));
+ __ cmpl(instantiator_reg, raw_null);
+ __ j(EQUAL, &type_arguments_instantiated, Assembler::kNearJump);
+ }
+ // Instantiate non-null type arguments.
+ // A runtime call to instantiate the type arguments is required.
+ __ PushObject(Object::ZoneHandle()); // Make room for the result.
+ __ PushObject(type_arguments());
+ __ pushl(instantiator_reg); // Push instantiator type arguments.
+ compiler->GenerateCallRuntime(token_pos(),
+ deopt_id(),
+ kInstantiateTypeArgumentsRuntimeEntry,
+ locs());
+ __ Drop(2); // Drop instantiator and uninstantiated type arguments.
+ __ popl(result_reg); // Pop instantiated type arguments.
+ __ Bind(&type_arguments_instantiated);
}
- // Instantiate non-null type arguments.
- if (type_arguments().IsUninstantiatedIdentity()) {
- // Check if the instantiator type argument vector is a TypeArguments of a
- // matching length and, if so, use it as the instantiated type_arguments.
- // No need to check the instantiator ('instantiator_reg') for null here,
- // because a null instantiator will have the wrong class (Null instead of
- // TypeArguments).
- Label type_arguments_uninstantiated;
- __ CompareClassId(instantiator_reg, kTypeArgumentsCid, temp);
- __ j(NOT_EQUAL, &type_arguments_uninstantiated, Assembler::kNearJump);
- __ cmpl(FieldAddress(instantiator_reg, TypeArguments::length_offset()),
- Immediate(Smi::RawValue(len)));
- __ j(EQUAL, &type_arguments_instantiated, Assembler::kNearJump);
- __ Bind(&type_arguments_uninstantiated);
- }
- // A runtime call to instantiate the type arguments is required.
- __ PushObject(Object::ZoneHandle()); // Make room for the result.
- __ PushObject(type_arguments());
- __ pushl(instantiator_reg); // Push instantiator type arguments.
- compiler->GenerateCallRuntime(token_pos(),
- deopt_id(),
- kInstantiateTypeArgumentsRuntimeEntry,
- locs());
- __ Drop(2); // Drop instantiator and uninstantiated type arguments.
- __ popl(result_reg); // Pop instantiated type arguments.
- __ Bind(&type_arguments_instantiated);
ASSERT(instantiator_reg == result_reg);
// 'result_reg': Instantiated type arguments.
}
@@ -1922,12 +1908,11 @@
LocationSummary*
ExtractConstructorTypeArgumentsInstr::MakeLocationSummary() const {
const intptr_t kNumInputs = 1;
- const intptr_t kNumTemps = 1;
+ const intptr_t kNumTemps = 0;
LocationSummary* locs =
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
locs->set_in(0, Location::RequiresRegister());
locs->set_out(Location::SameAsFirstInput());
- locs->set_temp(0, Location::RequiresRegister());
return locs;
}
@@ -1937,42 +1922,29 @@
Register instantiator_reg = locs()->in(0).reg();
Register result_reg = locs()->out().reg();
ASSERT(instantiator_reg == result_reg);
- Register temp_reg = locs()->temp(0).reg();
// instantiator_reg is the instantiator type argument vector, i.e. an
// AbstractTypeArguments object (or null).
- // If the instantiator is null and if the type argument vector
- // instantiated from null becomes a vector of dynamic, then use null as
- // the type arguments.
- Label type_arguments_instantiated;
- const intptr_t len = type_arguments().Length();
- if (type_arguments().IsRawInstantiatedRaw(len)) {
- const Immediate& raw_null =
- Immediate(reinterpret_cast<intptr_t>(Object::null()));
- __ cmpl(instantiator_reg, raw_null);
- __ j(EQUAL, &type_arguments_instantiated, Assembler::kNearJump);
+ if (!type_arguments().IsUninstantiatedIdentity()) {
+ // If the instantiator is null and if the type argument vector
+ // instantiated from null becomes a vector of dynamic, then use null as
+ // the type arguments.
+ Label type_arguments_instantiated;
+ const intptr_t len = type_arguments().Length();
+ if (type_arguments().IsRawInstantiatedRaw(len)) {
+ const Immediate& raw_null =
+ Immediate(reinterpret_cast<intptr_t>(Object::null()));
+ __ cmpl(instantiator_reg, raw_null);
+ __ j(EQUAL, &type_arguments_instantiated, Assembler::kNearJump);
+ }
+ // Instantiate non-null type arguments.
+ // In the non-factory case, we rely on the allocation stub to
+ // instantiate the type arguments.
+ __ LoadObject(result_reg, type_arguments());
+ // result_reg: uninstantiated type arguments.
+ __ Bind(&type_arguments_instantiated);
}
- // Instantiate non-null type arguments.
- if (type_arguments().IsUninstantiatedIdentity()) {
- // Check if the instantiator type argument vector is a TypeArguments of a
- // matching length and, if so, use it as the instantiated type_arguments.
- // No need to check instantiator_reg for null here, because a null
- // instantiator will have the wrong class (Null instead of TypeArguments).
- Label type_arguments_uninstantiated;
- __ CompareClassId(instantiator_reg, kTypeArgumentsCid, temp_reg);
- __ j(NOT_EQUAL, &type_arguments_uninstantiated, Assembler::kNearJump);
- const Immediate& arguments_length =
- Immediate(Smi::RawValue(type_arguments().Length()));
- __ cmpl(FieldAddress(instantiator_reg, TypeArguments::length_offset()),
- arguments_length);
- __ j(EQUAL, &type_arguments_instantiated, Assembler::kNearJump);
- __ Bind(&type_arguments_uninstantiated);
- }
- // In the non-factory case, we rely on the allocation stub to
- // instantiate the type arguments.
- __ LoadObject(result_reg, type_arguments());
- // result_reg: uninstantiated type arguments.
- __ Bind(&type_arguments_instantiated);
+ ASSERT(instantiator_reg == result_reg);
// result_reg: uninstantiated or instantiated type arguments.
}
@@ -1980,12 +1952,11 @@
LocationSummary*
ExtractConstructorInstantiatorInstr::MakeLocationSummary() const {
const intptr_t kNumInputs = 1;
- const intptr_t kNumTemps = 1;
+ const intptr_t kNumTemps = 0;
LocationSummary* locs =
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
locs->set_in(0, Location::RequiresRegister());
locs->set_out(Location::SameAsFirstInput());
- locs->set_temp(0, Location::RequiresRegister());
return locs;
}
@@ -1994,52 +1965,32 @@
FlowGraphCompiler* compiler) {
Register instantiator_reg = locs()->in(0).reg();
ASSERT(locs()->out().reg() == instantiator_reg);
- Register temp_reg = locs()->temp(0).reg();
// instantiator_reg is the instantiator AbstractTypeArguments object
- // (or null). If the instantiator is null and if the type argument vector
- // instantiated from null becomes a vector of dynamic, then use null as
- // the type arguments and do not pass the instantiator.
- Label done;
- const intptr_t len = type_arguments().Length();
- if (type_arguments().IsRawInstantiatedRaw(len)) {
- const Immediate& raw_null =
- Immediate(reinterpret_cast<intptr_t>(Object::null()));
- Label instantiator_not_null;
- __ cmpl(instantiator_reg, raw_null);
- __ j(NOT_EQUAL, &instantiator_not_null, Assembler::kNearJump);
- // Null was used in VisitExtractConstructorTypeArguments as the
- // instantiated type arguments, no proper instantiator needed.
- __ movl(instantiator_reg,
- Immediate(Smi::RawValue(StubCode::kNoInstantiator)));
- __ jmp(&done);
- __ Bind(&instantiator_not_null);
- }
- // Instantiate non-null type arguments.
+ // (or null).
if (type_arguments().IsUninstantiatedIdentity()) {
- // TODO(regis): The following emitted code is duplicated in
- // VisitExtractConstructorTypeArguments above. The reason is that the code
- // is split between two computations, so that each one produces a
- // single value, rather than producing a pair of values.
- // If this becomes an issue, we should expose these tests at the IL level.
-
- // Check if the instantiator type argument vector is a TypeArguments of a
- // matching length and, if so, use it as the instantiated type_arguments.
- // No need to check the instantiator for null here, because a null
- // instantiator will have the wrong class (Null instead of TypeArguments).
- __ CompareClassId(instantiator_reg, kTypeArgumentsCid, temp_reg);
- __ j(NOT_EQUAL, &done, Assembler::kNearJump);
- const Immediate& arguments_length =
- Immediate(Smi::RawValue(type_arguments().Length()));
- __ cmpl(FieldAddress(instantiator_reg, TypeArguments::length_offset()),
- arguments_length);
- __ j(NOT_EQUAL, &done, Assembler::kNearJump);
// The instantiator was used in VisitExtractConstructorTypeArguments as the
// instantiated type arguments, no proper instantiator needed.
__ movl(instantiator_reg,
Immediate(Smi::RawValue(StubCode::kNoInstantiator)));
+ } else {
+ // If the instantiator is null and if the type argument vector
+ // instantiated from null becomes a vector of dynamic, then use null as
+ // the type arguments and do not pass the instantiator.
+ const intptr_t len = type_arguments().Length();
+ if (type_arguments().IsRawInstantiatedRaw(len)) {
+ const Immediate& raw_null =
+ Immediate(reinterpret_cast<intptr_t>(Object::null()));
+ Label instantiator_not_null;
+ __ cmpl(instantiator_reg, raw_null);
+ __ j(NOT_EQUAL, &instantiator_not_null, Assembler::kNearJump);
+ // Null was used in VisitExtractConstructorTypeArguments as the
+ // instantiated type arguments, no proper instantiator needed.
+ __ movl(instantiator_reg,
+ Immediate(Smi::RawValue(StubCode::kNoInstantiator)));
+ __ Bind(&instantiator_not_null);
+ }
}
- __ Bind(&done);
// instantiator_reg: instantiator or kNoInstantiator.
}
@@ -2843,6 +2794,132 @@
}
}
+
+LocationSummary* Float32x4ShuffleInstr::MakeLocationSummary() const {
+ const intptr_t kNumInputs = 1;
+ const intptr_t kNumTemps = 0;
+ LocationSummary* summary =
+ new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
+ summary->set_in(0, Location::RequiresFpuRegister());
+ summary->set_out(Location::SameAsFirstInput());
+ return summary;
+}
+
+
+void Float32x4ShuffleInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+ XmmRegister value = locs()->in(0).fpu_reg();
+
+ ASSERT(locs()->out().fpu_reg() == value);
+
+ switch (op_kind()) {
+ case MethodRecognizer::kFloat32x4ShuffleXXXX:
+ __ shufps(value, value, Immediate(0x00));
+ break;
+ case MethodRecognizer::kFloat32x4ShuffleYYYY:
+ __ shufps(value, value, Immediate(0x55));
+ break;
+ case MethodRecognizer::kFloat32x4ShuffleZZZZ:
+ __ shufps(value, value, Immediate(0xAA));
+ break;
+ case MethodRecognizer::kFloat32x4ShuffleWWWW:
+ __ shufps(value, value, Immediate(0xFF));
+ break;
+ case MethodRecognizer::kFloat32x4ShuffleX:
+ __ shufps(value, value, Immediate(0x00));
+ __ cvtss2sd(value, value);
+ break;
+ case MethodRecognizer::kFloat32x4ShuffleY:
+ __ shufps(value, value, Immediate(0x55));
+ __ cvtss2sd(value, value);
+ break;
+ case MethodRecognizer::kFloat32x4ShuffleZ:
+ __ shufps(value, value, Immediate(0xAA));
+ __ cvtss2sd(value, value);
+ break;
+ case MethodRecognizer::kFloat32x4ShuffleW:
+ __ shufps(value, value, Immediate(0xFF));
+ __ cvtss2sd(value, value);
+ break;
+
+ default: UNREACHABLE();
+ }
+}
+
+
+LocationSummary* Float32x4ConstructorInstr::MakeLocationSummary() const {
+ const intptr_t kNumInputs = 4;
+ const intptr_t kNumTemps = 0;
+ LocationSummary* summary =
+ new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
+ summary->set_in(0, Location::RequiresFpuRegister());
+ summary->set_in(1, Location::RequiresFpuRegister());
+ summary->set_in(2, Location::RequiresFpuRegister());
+ summary->set_in(3, Location::RequiresFpuRegister());
+ summary->set_out(Location::SameAsFirstInput());
+ return summary;
+}
+
+
+void Float32x4ConstructorInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+ XmmRegister v0 = locs()->in(0).fpu_reg();
+ XmmRegister v1 = locs()->in(1).fpu_reg();
+ XmmRegister v2 = locs()->in(2).fpu_reg();
+ XmmRegister v3 = locs()->in(3).fpu_reg();
+ ASSERT(v0 == locs()->out().fpu_reg());
+ __ subl(ESP, Immediate(16));
+ __ cvtsd2ss(v0, v0);
+ __ movss(Address(ESP, -16), v0);
+ __ movsd(v0, v1);
+ __ cvtsd2ss(v0, v0);
+ __ movss(Address(ESP, -12), v0);
+ __ movsd(v0, v2);
+ __ cvtsd2ss(v0, v0);
+ __ movss(Address(ESP, -8), v0);
+ __ movsd(v0, v3);
+ __ cvtsd2ss(v0, v0);
+ __ movss(Address(ESP, -4), v0);
+ __ movups(v0, Address(ESP, -16));
+ __ addl(ESP, Immediate(16));
+}
+
+
+LocationSummary* Float32x4ZeroInstr::MakeLocationSummary() const {
+ const intptr_t kNumInputs = 0;
+ const intptr_t kNumTemps = 0;
+ LocationSummary* summary =
+ new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
+ summary->set_out(Location::RequiresFpuRegister());
+ return summary;
+}
+
+
+void Float32x4ZeroInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+ XmmRegister value = locs()->out().fpu_reg();
+ __ xorps(value, value);
+}
+
+
+LocationSummary* Float32x4SplatInstr::MakeLocationSummary() const {
+ const intptr_t kNumInputs = 1;
+ const intptr_t kNumTemps = 0;
+ LocationSummary* summary =
+ new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
+ summary->set_in(0, Location::RequiresFpuRegister());
+ summary->set_out(Location::SameAsFirstInput());
+ return summary;
+}
+
+
+void Float32x4SplatInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+ XmmRegister value = locs()->out().fpu_reg();
+ ASSERT(locs()->in(0).fpu_reg() == locs()->out().fpu_reg());
+ // Convert to Float32.
+ __ cvtsd2ss(value, value);
+ // Splat across all lanes.
+ __ shufps(value, value, Immediate(0x00));
+}
+
+
LocationSummary* MathSqrtInstr::MakeLocationSummary() const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
@@ -3599,7 +3676,6 @@
case ABOVE: return BELOW_EQUAL;
case ABOVE_EQUAL: return BELOW;
default:
- OS::Print("Error %d\n", condition);
UNIMPLEMENTED();
return EQUAL;
}
diff --git a/runtime/vm/intermediate_language_mips.cc b/runtime/vm/intermediate_language_mips.cc
index 03b08cf..fa66db3 100644
--- a/runtime/vm/intermediate_language_mips.cc
+++ b/runtime/vm/intermediate_language_mips.cc
@@ -46,6 +46,7 @@
void PushArgumentInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
// In SSA mode, we need an explicit push. Nothing to do in non-SSA mode
// where PushArgument is handled by BindInstr::EmitNativeCode.
+ __ TraceSimMsg("PushArgumentInstr");
if (compiler->is_optimizing()) {
Location value = locs()->in(0);
if (value.IsRegister()) {
@@ -75,6 +76,7 @@
// The entry needs to be patchable, no inlined objects are allowed in the area
// that will be overwritten by the patch instructions: a branch macro sequence.
void ReturnInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+ __ TraceSimMsg("ReturnInstr");
Register result = locs()->in(0).reg();
ASSERT(result == V0);
#if defined(DEBUG)
@@ -85,6 +87,7 @@
if (!compiler->HasFinally()) {
Label stack_ok;
__ Comment("Stack Check");
+ __ TraceSimMsg("Stack Check");
const intptr_t fp_sp_dist =
(kFirstLocalSlotIndex + 1 - compiler->StackSize()) * kWordSize;
ASSERT(fp_sp_dist <= 0);
@@ -96,13 +99,11 @@
__ Bind(&stack_ok);
}
#endif
+ // This sequence is patched by a debugger breakpoint. There is no need for
+ // extra NOP instructions here because the sequence patched in for a
+ // breakpoint is shorter than the sequence here.
__ LeaveDartFrame();
__ Ret();
-
- // Generate 2 NOP instructions so that the debugger can patch the return
- // pattern (1 instruction) with a call to the debug stub (3 instructions).
- __ nop();
- __ nop();
compiler->AddCurrentDescriptor(PcDescriptors::kReturn,
Isolate::kNoDeoptId,
token_pos());
@@ -134,8 +135,31 @@
LocationSummary* ClosureCallInstr::MakeLocationSummary() const {
- UNIMPLEMENTED();
- return NULL;
+ const intptr_t kNumInputs = 0;
+ const intptr_t kNumTemps = 1;
+ LocationSummary* result =
+ new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
+ result->set_out(Location::RegisterLocation(V0));
+ result->set_temp(0, Location::RegisterLocation(S4)); // Arg. descriptor.
+ return result;
+}
+
+
+void ClosureCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+ // The arguments to the stub include the closure, as does the arguments
+ // descriptor.
+ Register temp_reg = locs()->temp(0).reg();
+ int argument_count = ArgumentCount();
+ const Array& arguments_descriptor =
+ Array::ZoneHandle(ArgumentsDescriptor::New(argument_count,
+ argument_names()));
+ __ LoadObject(temp_reg, arguments_descriptor);
+ compiler->GenerateDartCall(deopt_id(),
+ token_pos(),
+ &StubCode::CallClosureFunctionLabel(),
+ PcDescriptors::kOther,
+ locs());
+ __ Drop(argument_count);
}
@@ -147,6 +171,7 @@
void LoadLocalInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+ __ TraceSimMsg("LoadLocalInstr");
Register result = locs()->out().reg();
__ lw(result, Address(FP, local().index() * kWordSize));
}
@@ -160,6 +185,7 @@
void StoreLocalInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+ __ TraceSimMsg("StoreLocalInstr");
Register value = locs()->in(0).reg();
Register result = locs()->out().reg();
ASSERT(result == value); // Assert that register assignment is correct.
@@ -177,6 +203,7 @@
void ConstantInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
// The register allocator drops constant definitions that have no uses.
if (!locs()->out().IsInvalid()) {
+ __ TraceSimMsg("ConstantInstr");
Register result = locs()->out().reg();
__ LoadObject(result, value());
}
@@ -189,8 +216,8 @@
LocationSummary* summary =
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
summary->set_in(0, Location::RegisterLocation(A0)); // Value.
- summary->set_in(1, Location::RegisterLocation(A1)); // Instantiator.
- summary->set_in(2, Location::RegisterLocation(A2)); // Type arguments.
+ summary->set_in(1, Location::RegisterLocation(A2)); // Instantiator.
+ summary->set_in(2, Location::RegisterLocation(A1)); // Type arguments.
summary->set_out(Location::RegisterLocation(A0));
return summary;
}
@@ -234,6 +261,7 @@
Register obj = locs()->in(0).reg();
Register result = locs()->out().reg();
+ __ TraceSimMsg("AssertBooleanInstr");
EmitAssertBoolean(obj, token_pos(), deopt_id(), locs(), compiler);
ASSERT(obj == result);
}
@@ -324,6 +352,7 @@
Token::Kind kind,
LocationSummary* locs,
const ICData& original_ic_data) {
+ __ TraceSimMsg("EmitEqualityAsInstanceCall");
if (!compiler->is_optimizing()) {
compiler->AddCurrentDescriptor(PcDescriptors::kDeopt,
deopt_id,
@@ -411,6 +440,7 @@
Register value_cid_reg,
Register value_reg,
Label* value_is_smi = NULL) {
+ __ TraceSimMsg("LoadValueCid");
Label done;
if (value_is_smi == NULL) {
__ LoadImmediate(value_cid_reg, kSmiCid);
@@ -470,6 +500,7 @@
const LocationSummary& locs,
Token::Kind kind,
BranchInstr* branch) {
+ __ TraceSimMsg("EmitSmiComparisonOp");
Location left = locs.in(0);
Location right = locs.in(1);
ASSERT(!left.IsConstant() || !right.IsConstant());
@@ -577,6 +608,7 @@
void EqualityCompareInstr::EmitBranchCode(FlowGraphCompiler* compiler,
BranchInstr* branch) {
+ __ TraceSimMsg("EqualityCompareInstr");
ASSERT((kind() == Token::kNE) || (kind() == Token::kEQ));
if (receiver_class_id() == kSmiCid) {
// Deoptimizes if both arguments not Smi.
@@ -666,6 +698,7 @@
void RelationalOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+ __ TraceSimMsg("RelationalOpInstr");
if (operands_class_id() == kSmiCid) {
EmitSmiComparisonOp(compiler, *locs(), kind(), NULL);
return;
@@ -684,8 +717,9 @@
// explicitly pushing arguments to the call here.
Register left = locs()->in(0).reg();
Register right = locs()->in(1).reg();
- __ Push(left);
- __ Push(right);
+ __ addiu(SP, SP, Immediate(-2 * kWordSize));
+ __ sw(left, Address(SP, 1 * kWordSize));
+ __ sw(right, Address(SP, 0 * kWordSize));
if (HasICData() && (ic_data()->NumberOfChecks() > 0)) {
Label* deopt = compiler->AddDeoptStub(deopt_id(), kDeoptRelationalOp);
// Load class into A2.
@@ -737,6 +771,7 @@
void RelationalOpInstr::EmitBranchCode(FlowGraphCompiler* compiler,
BranchInstr* branch) {
+ __ TraceSimMsg("RelationalOpInstr");
if (operands_class_id() == kSmiCid) {
EmitSmiComparisonOp(compiler, *locs(), kind(), branch);
return;
@@ -769,6 +804,7 @@
void NativeCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+ __ TraceSimMsg("NativeCallInstr");
ASSERT(locs()->temp(0).reg() == A1);
ASSERT(locs()->temp(1).reg() == A2);
ASSERT(locs()->temp(2).reg() == T5);
@@ -853,57 +889,350 @@
LocationSummary* StoreIndexedInstr::MakeLocationSummary() const {
- UNIMPLEMENTED();
- return NULL;
+ const intptr_t kNumInputs = 3;
+ const intptr_t kNumTemps = 0;
+ LocationSummary* locs =
+ new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
+ locs->set_in(0, Location::RequiresRegister());
+ // The smi index is either untagged (element size == 1), or it is left smi
+ // tagged (for all element sizes > 1).
+ // TODO(regis): Revisit and see if the index can be immediate.
+ locs->set_in(1, Location::WritableRegister());
+ switch (class_id()) {
+ case kArrayCid:
+ locs->set_in(2, ShouldEmitStoreBarrier()
+ ? Location::WritableRegister()
+ : Location::RegisterOrConstant(value()));
+ break;
+ case kExternalTypedDataUint8ArrayCid:
+ case kExternalTypedDataUint8ClampedArrayCid:
+ case kTypedDataInt8ArrayCid:
+ case kTypedDataUint8ArrayCid:
+ case kTypedDataUint8ClampedArrayCid:
+ case kTypedDataInt16ArrayCid:
+ case kTypedDataUint16ArrayCid:
+ case kTypedDataInt32ArrayCid:
+ case kTypedDataUint32ArrayCid:
+ case kTypedDataFloat32ArrayCid:
+ case kTypedDataFloat64ArrayCid:
+ case kTypedDataFloat32x4ArrayCid:
+ UNIMPLEMENTED();
+ break;
+ default:
+ UNREACHABLE();
+ return NULL;
+ }
+ return locs;
}
void StoreIndexedInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- UNIMPLEMENTED();
+ __ TraceSimMsg("StoreIndexedInstr");
+ Register array = locs()->in(0).reg();
+ 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: {
+ __ 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();
+ }
+ __ AddImmediate(index.reg(),
+ FlowGraphCompiler::DataOffsetFor(class_id()) - kHeapObjectTag);
+ __ addu(TMP1, array, index.reg());
+ element_address = Address(TMP1);
+ }
+
+ switch (class_id()) {
+ case kArrayCid:
+ if (ShouldEmitStoreBarrier()) {
+ Register value = locs()->in(2).reg();
+ __ StoreIntoObject(array, element_address, value);
+ } else if (locs()->in(2).IsConstant()) {
+ const Object& constant = locs()->in(2).constant();
+ __ StoreIntoObjectNoBarrier(array, element_address, constant);
+ } else {
+ Register value = locs()->in(2).reg();
+ __ StoreIntoObjectNoBarrier(array, element_address, value);
+ }
+ break;
+ case kTypedDataInt8ArrayCid:
+ case kTypedDataUint8ArrayCid:
+ case kExternalTypedDataUint8ArrayCid:
+ case kTypedDataUint8ClampedArrayCid:
+ case kExternalTypedDataUint8ClampedArrayCid:
+ case kTypedDataInt16ArrayCid:
+ case kTypedDataUint16ArrayCid:
+ case kTypedDataInt32ArrayCid:
+ case kTypedDataUint32ArrayCid:
+ case kTypedDataFloat32ArrayCid:
+ case kTypedDataFloat64ArrayCid:
+ case kTypedDataFloat32x4ArrayCid:
+ UNIMPLEMENTED();
+ break;
+ default:
+ UNREACHABLE();
+ }
}
LocationSummary* GuardFieldInstr::MakeLocationSummary() const {
- UNIMPLEMENTED();
- return NULL;
+ const intptr_t kNumInputs = 1;
+ LocationSummary* summary =
+ new LocationSummary(kNumInputs, 0, LocationSummary::kNoCall);
+ summary->set_in(0, Location::RequiresRegister());
+ if ((value()->Type()->ToCid() == kDynamicCid) &&
+ (field().guarded_cid() != kSmiCid)) {
+ summary->AddTemp(Location::RequiresRegister());
+ }
+ if (field().guarded_cid() == kIllegalCid) {
+ summary->AddTemp(Location::RequiresRegister());
+ }
+ return summary;
}
void GuardFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- UNIMPLEMENTED();
+ __ TraceSimMsg("GuardFieldInstr");
+ const intptr_t field_cid = field().guarded_cid();
+ const intptr_t nullability = field().is_nullable() ? kNullCid : kIllegalCid;
+
+ if (field_cid == kDynamicCid) {
+ ASSERT(!compiler->is_optimizing());
+ return; // Nothing to emit.
+ }
+
+ const intptr_t value_cid = value()->Type()->ToCid();
+
+ Register value_reg = locs()->in(0).reg();
+
+ Register value_cid_reg = ((value_cid == kDynamicCid) &&
+ (field_cid != kSmiCid)) ? locs()->temp(0).reg() : kNoRegister;
+
+ Register field_reg = (field_cid == kIllegalCid) ?
+ locs()->temp(locs()->temp_count() - 1).reg() : kNoRegister;
+
+ Label ok, fail_label;
+
+ Label* deopt = compiler->is_optimizing() ?
+ compiler->AddDeoptStub(deopt_id(), kDeoptGuardField) : NULL;
+
+ Label* fail = (deopt != NULL) ? deopt : &fail_label;
+
+ const bool ok_is_fall_through = (deopt != NULL);
+
+ if (!compiler->is_optimizing() || (field_cid == kIllegalCid)) {
+ if (!compiler->is_optimizing()) {
+ // Currently we can't have different location summaries for optimized
+ // and non-optimized code. So instead we manually pick up a register
+ // that is known to be free because we know how non-optimizing compiler
+ // allocates registers.
+ field_reg = A0;
+ ASSERT((field_reg != value_reg) && (field_reg != value_cid_reg));
+ }
+
+ __ LoadObject(field_reg, Field::ZoneHandle(field().raw()));
+
+ FieldAddress field_cid_operand(field_reg, Field::guarded_cid_offset());
+ FieldAddress field_nullability_operand(
+ field_reg, Field::is_nullable_offset());
+
+ if (value_cid == kDynamicCid) {
+ if (value_cid_reg == kNoRegister) {
+ ASSERT(!compiler->is_optimizing());
+ value_cid_reg = A1;
+ ASSERT((value_cid_reg != value_reg) && (field_reg != value_cid_reg));
+ }
+
+ LoadValueCid(compiler, value_cid_reg, value_reg);
+
+ __ lw(TMP1, field_cid_operand);
+ __ beq(value_cid_reg, TMP1, &ok);
+ __ lw(TMP1, field_nullability_operand);
+ __ subu(CMPRES, value_cid_reg, TMP1);
+ } else if (value_cid == kNullCid) {
+ // TODO(regis): TMP1 may conflict. Revisit.
+ __ lw(TMP1, field_nullability_operand);
+ __ LoadImmediate(TMP2, value_cid);
+ __ subu(CMPRES, TMP1, TMP2);
+ } else {
+ // TODO(regis): TMP1 may conflict. Revisit.
+ __ lw(TMP1, field_cid_operand);
+ __ LoadImmediate(TMP2, value_cid);
+ __ subu(CMPRES, TMP1, TMP2);
+ }
+ __ beq(CMPRES, ZR, &ok);
+
+ __ lw(TMP1, field_cid_operand);
+ __ BranchNotEqual(TMP1, kIllegalCid, fail);
+
+ if (value_cid == kDynamicCid) {
+ __ sw(value_cid_reg, field_cid_operand);
+ __ sw(value_cid_reg, field_nullability_operand);
+ } else {
+ __ LoadImmediate(TMP1, value_cid);
+ __ sw(TMP1, field_cid_operand);
+ __ sw(TMP1, field_nullability_operand);
+ }
+
+ if (!ok_is_fall_through) {
+ __ b(&ok);
+ }
+ } else {
+ if (value_cid == kDynamicCid) {
+ // Field's guarded class id is fixed by value's class id is not known.
+ __ andi(CMPRES, value_reg, Immediate(kSmiTagMask));
+
+ if (field_cid != kSmiCid) {
+ __ beq(CMPRES, ZR, fail);
+ __ LoadClassId(value_cid_reg, value_reg);
+ __ LoadImmediate(TMP1, field_cid);
+ __ subu(CMPRES, value_cid_reg, TMP1);
+ }
+
+ if (field().is_nullable() && (field_cid != kNullCid)) {
+ __ beq(CMPRES, ZR, &ok);
+ __ LoadImmediate(TMP1, reinterpret_cast<intptr_t>(Object::null()));
+ __ subu(CMPRES, value_reg, TMP1);
+ }
+
+ if (ok_is_fall_through) {
+ __ bne(CMPRES, ZR, fail);
+ } else {
+ __ beq(CMPRES, ZR, &ok);
+ }
+ } else {
+ // Both value's and field's class id is known.
+ if ((value_cid != field_cid) && (value_cid != nullability)) {
+ if (ok_is_fall_through) {
+ __ b(fail);
+ }
+ } else {
+ // Nothing to emit.
+ ASSERT(!compiler->is_optimizing());
+ return;
+ }
+ }
+ }
+
+ if (deopt == NULL) {
+ ASSERT(!compiler->is_optimizing());
+ __ Bind(fail);
+
+ __ lw(TMP1, FieldAddress(field_reg, Field::guarded_cid_offset()));
+ __ BranchEqual(TMP1, kDynamicCid, &ok);
+
+ __ addiu(SP, SP, Immediate(-2 * kWordSize));
+ __ sw(field_reg, Address(SP, 1 * kWordSize));
+ __ sw(value_reg, Address(SP, 0 * kWordSize));
+ __ CallRuntime(kUpdateFieldCidRuntimeEntry);
+ __ Drop(2); // Drop the field and the value.
+ }
+
+ __ Bind(&ok);
}
LocationSummary* StoreInstanceFieldInstr::MakeLocationSummary() const {
- UNIMPLEMENTED();
- return NULL;
+ const intptr_t kNumInputs = 2;
+ const intptr_t num_temps = 0;
+ LocationSummary* summary =
+ new LocationSummary(kNumInputs, num_temps, LocationSummary::kNoCall);
+ summary->set_in(0, Location::RequiresRegister());
+ summary->set_in(1, ShouldEmitStoreBarrier()
+ ? Location::WritableRegister()
+ : Location::RegisterOrConstant(value()));
+ return summary;
}
void StoreInstanceFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- UNIMPLEMENTED();
+ Register instance_reg = locs()->in(0).reg();
+ if (ShouldEmitStoreBarrier()) {
+ Register value_reg = locs()->in(1).reg();
+ __ StoreIntoObject(instance_reg,
+ FieldAddress(instance_reg, field().Offset()),
+ value_reg,
+ CanValueBeSmi());
+ } else {
+ if (locs()->in(1).IsConstant()) {
+ __ StoreIntoObjectNoBarrier(
+ instance_reg,