Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(749)

Unified Diff: dart/sdk/lib/_internal/lib/js_helper.dart

Issue 57773002: Repro for OOM bug in test.dart (applies to r29345). (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 7 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « dart/sdk/lib/_internal/lib/collection_dev_patch.dart ('k') | dart/sdk/lib/_internal/lib/js_rti.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: dart/sdk/lib/_internal/lib/js_helper.dart
diff --git a/dart/sdk/lib/_internal/lib/js_helper.dart b/dart/sdk/lib/_internal/lib/js_helper.dart
index ff0cf493b32e7ca4331741af2107beaf45320721..a28ab4fe0365b865f919bf0a0589eb4b34789cc5 100644
--- a/dart/sdk/lib/_internal/lib/js_helper.dart
+++ b/dart/sdk/lib/_internal/lib/js_helper.dart
@@ -31,6 +31,7 @@ import 'dart:_interceptors';
import 'dart:_collection-dev' as _symbol_dev;
import 'dart:_js_names' show
+ extractKeys,
mangledNames,
unmangleGlobalNameIfPreservedAnyways;
@@ -281,6 +282,42 @@ class Primitives {
static computeGlobalThis() => JS('', 'function() { return this; }()');
+ /**
+ * This is the low-level method that is used to implement
+ * [print]. It is possible to override this function from JavaScript
+ * by defining a function in JavaScript called "dartPrint".
+ */
+ static void printString(String string) {
+ if (JS('bool', r'typeof dartPrint == "function"')) {
+ // Support overriding print from JavaScript.
+ JS('void', r'dartPrint(#)', string);
+ return;
+ }
+
+ // Inside browser or nodejs.
+ if (JS('bool', r'typeof console == "object"') &&
+ JS('bool', r'typeof console.log == "function"')) {
+ JS('void', r'console.log(#)', string);
+ return;
+ }
+
+ // Don't throw inside IE, the console is only defined if dev tools is open.
+ if (JS('bool', r'typeof window == "object"')) {
+ return;
+ }
+
+ // Running in d8, the V8 developer shell, or in Firefox' js-shell.
+ if (JS('bool', r'typeof print == "function"')) {
+ JS('void', r'print(#)', string);
+ return;
+ }
+
+ // This is somewhat nasty, but we don't want to drag in a bunch of
+ // dependencies to handle a situation that cannot happen. So we
+ // avoid using Dart [:throw:] and Dart [toString].
+ JS('void', 'throw "Unable to print message: " + String(#)', string);
+ }
+
static _throwFormatException(String string) {
throw new FormatException(string);
}
@@ -2006,3 +2043,335 @@ class RuntimeError extends Error {
RuntimeError(this.message);
String toString() => "RuntimeError: $message";
}
+
+abstract class RuntimeType {
+ const RuntimeType();
+
+ bool isTest(expression);
+
+ toRti();
+}
+
+// TODO(ahe): Remove this class.
+class DummyRuntimeType extends RuntimeType {
+ final String impl;
+
+ DummyRuntimeType(this.impl);
+
+ bool isTest(expression) {
+ throw "<<is-test with '$impl' not implemented>>";
+ }
+
+ String toString() => 'DummyRuntimeType($impl)';
+}
+
+// TODO(ahe): Delete this method.
+DummyRuntimeType buildDummyType(String impl) => new DummyRuntimeType(impl);
+
+class RuntimeFunctionType extends RuntimeType {
+ final RuntimeType returnType;
+ final List<RuntimeType> parameterTypes;
+ final List<RuntimeType> optionalParameterTypes;
+ final namedParameters;
+
+ static var /* bool */ inAssert = false;
+
+ RuntimeFunctionType(this.returnType,
+ this.parameterTypes,
+ this.optionalParameterTypes,
+ this.namedParameters);
+
+ // TODO(ahe): Implement this.
+ bool get isVoid => returnType is VoidRuntimeType;
+
+ /// Called from generated code. [expression] is a Dart object and this method
+ /// returns true if [this] is a supertype of [expression].
+ bool _isTest(expression) {
+ // Type inferrer don't think this is called with dynamic arguments.
+ expression = JS('', '#', expression);
+
+ var interceptor = getInterceptor(expression);
+ if (!JS('bool', '# in #', JS_SIGNATURE_NAME(), interceptor)) return false;
+ var functionTypeObject = JS('', '#[#]()', interceptor, JS_SIGNATURE_NAME());
+ bool result = isFunctionSubtype(functionTypeObject, toRti());
+
+ // DEBUG REMOVE
+ var pretty = new FunctionTypeInfoDecoderRing(functionTypeObject).toString();
+ var self = new FunctionTypeInfoDecoderRing(toRti()).toString();
+ Primitives.printString("<<$pretty is $this (${self}) [$result]>>");
+
+ return result;
+ }
+
+ _asCheck(expression) {
+ // Type inferrer don't think this is called with dynamic arguments.
+ return _check(JS('', '#', expression), true);
+ }
+
+ _assertCheck(expression) {
+ if (inAssert) return;
+ inAssert = true; // Don't try to check this library itself.
+ try {
+ // Type inferrer don't think this is called with dynamic arguments.
+ return _check(JS('', '#', expression), false);
+ } finally {
+ inAssert = false;
+ }
+ }
+
+ _check(expression, bool isCast) {
+ if (expression == null) return null;
+ if (_isTest(expression)) return expression;
+
+ var self = new FunctionTypeInfoDecoderRing(toRti()).toString();
+ if (isCast) {
+ var interceptor = getInterceptor(expression);
+ var pretty;
+ if (JS('bool', '# in #', JS_SIGNATURE_NAME(), interceptor)) {
+ var functionTypeObject =
+ JS('', '#[#]()', interceptor, JS_SIGNATURE_NAME());
+ pretty = new FunctionTypeInfoDecoderRing(functionTypeObject).toString();
+ } else {
+ pretty = Primitives.objectTypeName(expression);
+ }
+ throw new CastErrorImplementation(pretty, self);
+ } else {
+ // TODO(ahe): Pass "pretty" function-type to TypeErrorImplementation?
+ throw new TypeErrorImplementation(expression, self);
+ }
+ }
+
+ toRti() {
+ var result = JS('=Object', '{ #: "dynafunc" }', JS_FUNCTION_TYPE_TAG());
+ if (isVoid) {
+ JS('', '#[#] = true', result, JS_FUNCTION_TYPE_VOID_RETURN_TAG());
+ } else {
+ if (returnType is! DynamicRuntimeType) {
+ JS('', '#[#] = #', result, JS_FUNCTION_TYPE_RETURN_TYPE_TAG(),
+ returnType.toRti());
+ }
+ }
+ if (parameterTypes.length > 0) {
+ JS('', '#[#] = #', result, JS_FUNCTION_TYPE_REQUIRED_PARAMETERS_TAG(),
+ listToRti(parameterTypes));
+ }
+
+ if (optionalParameterTypes != null && !optionalParameterTypes.isEmpty) {
+ JS('', '#[#] = #', result, JS_FUNCTION_TYPE_OPTIONAL_PARAMETERS_TAG(),
+ listToRti(optionalParameterTypes));
+ }
+
+ if (namedParameters != null) {
+ var namedRti = JS('=Object', '{}');
+ for (var name in extractKeys(namedParameters)) {
+ var rti = JS('', '#[#]', namedParameters, name).toRti();
+ JS('', '#[#] = #', namedRti, name, rti);
+ }
+ JS('', '#[#] = #', result, JS_FUNCTION_TYPE_NAMED_PARAMETERS_TAG(),
+ namedRti);
+ }
+
+ return result;
+ }
+
+ static listToRti(list) {
+ list = JS('JSFixedArray', '#', list);
+ var result = JS('JSExtendableArray', '[]');
+ for (var i = 0; i < list.length; i++) {
+ JS('', '#.push(#)', result, list[i].toRti());
+ }
+ return result;
+ }
+
+ String toString() {
+ String result = '(';
+ bool needsComma = false;
+ for (RuntimeType type in parameterTypes) {
+ if (needsComma) result += ', ';
+ result += '$type';
+ needsComma = true;
+ }
+ if (optionalParameterTypes != null && !optionalParameterTypes.isEmpty) {
+ if (needsComma) result += ', ';
+ needsComma = false;
+ result += '[';
+ for (RuntimeType type in optionalParameterTypes) {
+ if (needsComma) result += ', ';
+ result += '$type';
+ needsComma = true;
+ }
+ result += ']';
+ }
+ result += ') -> $returnType';
+ return result;
+ }
+}
+
+RuntimeFunctionType buildFunctionType(RuntimeType returnType,
+ List parameterTypes,
+ List optionalParameterTypes) {
+ return new RuntimeFunctionType(
+ returnType, parameterTypes, optionalParameterTypes, null);
+}
+
+RuntimeFunctionType buildNamedFunctionType(RuntimeType returnType,
+ List parameterTypes,
+ namedParameters) {
+ return new RuntimeFunctionType(
+ returnType, parameterTypes, null, namedParameters);
+}
+
+RuntimeType buildInterfaceType(rti, List typeArguments) {
+ String name = JS('String|Null', r'#.name', rti);
+ typeArguments = JS('JSFixedArray', '#', typeArguments);
+ if (typeArguments.isEmpty) return new RuntimeTypePlain(name);
+ return new RuntimeTypeGeneric(name, typeArguments, null);
+}
+
+class DynamicRuntimeType extends RuntimeType {
+ const DynamicRuntimeType();
+
+ String toString() => 'dynamic';
+
+ toRti() => null;
+}
+
+RuntimeType getDynamicRuntimeType() => const DynamicRuntimeType();
+
+class VoidRuntimeType extends RuntimeType {
+ const VoidRuntimeType();
+
+ String toString() => 'void';
+
+ toRti() => throw 'internal error';
+}
+
+RuntimeType getVoidRuntimeType() => const VoidRuntimeType();
+
+RuntimeType convertRtiToRuntimeType(rti) {
+ if (rti == null) {
+ return getDynamicRuntimeType();
+ } else if (JS('bool', 'typeof # == "function"', rti)) {
+ return new RuntimeTypePlain(JS('String', r'rti.name'));
+ } else if (JS('bool', '#.constructor == Array', rti)) {
+ List list = JS('JSFixedArray', '#', rti);
+ String name = JS('String', r'#.name', list[0]);
+ List arguments = [];
+ for (int i = 1; i < list.length; i++) {
+ arguments.add(convertRtiToRuntimeType(list[i]));
+ }
+ return new RuntimeTypeGeneric(name, arguments, rti);
+ } else {
+ return new DummyRuntimeType("${JS('String', 'JSON.stringify(#)', rti)}");
+ }
+}
+
+class RuntimeTypePlain extends RuntimeType {
+ final String name;
+
+ RuntimeTypePlain(this.name);
+
+ toRti() {
+ var rti = JS('', 'init.allClasses[#]', name);
+ if (rti == null) throw "no type for '$name'";
+ return rti;
+ }
+
+ String toString() => name;
+}
+
+class RuntimeTypeGeneric extends RuntimeType {
+ final String name;
+ final List<RuntimeType> arguments;
+ var rti;
+
+ RuntimeTypeGeneric(this.name, this.arguments, this.rti);
+
+ toRti() {
+ if (rti != null) return rti;
+ var result = JS('JSExtendableArray', '[init.allClasses[#]]', name);
+ if (result[0] == null) {
+ throw "no type for '$name<...>'";
+ }
+ for (RuntimeType argument in arguments) {
+ JS('', '#.push(#)', result, argument.toRti());
+ }
+ return rti = result;
+ }
+
+ String toString() => '$name<${arguments.join(", ")}>';
+}
+
+class FunctionTypeInfoDecoderRing {
+ final _typeData;
+ String _cachedToString;
+
+ FunctionTypeInfoDecoderRing(this._typeData);
+
+ bool get _hasReturnType => JS('bool', '"ret" in #', _typeData);
+ get _returnType => JS('', '#.ret', _typeData);
+
+ bool get _isVoid => JS('bool', '!!#.void', _typeData);
+
+ bool get _hasArguments => JS('bool', '"args" in #', _typeData);
+ List get _arguments => JS('JSExtendableArray', '#.args', _typeData);
+
+ bool get _hasOptionalArguments => JS('bool', '"opt" in #', _typeData);
+ List get _optionalArguments => JS('JSExtendableArray', '#.opt', _typeData);
+
+ bool get _hasNamedArguments => JS('bool', '"named" in #', _typeData);
+ get _namedArguments => JS('=Object', '#.named', _typeData);
+
+ String _convert(type) {
+ String result = runtimeTypeToString(type);
+ if (result != null) return result;
+ if (JS('bool', '"func" in #', type)) {
+ return new FunctionTypeInfoDecoderRing(type).toString();
+ } else {
+ throw 'bad type';
+ }
+ }
+
+ String toString() {
+ if (_cachedToString != null) return _cachedToString;
+ var s = "(";
+ var sep = '';
+ if (_hasArguments) {
+ for (var argument in _arguments) {
+ s += sep;
+ s += _convert(argument);
+ sep = ', ';
+ }
+ }
+ if (_hasOptionalArguments) {
+ s += '$sep[';
+ sep = '';
+ for (var argument in _optionalArguments) {
+ s += sep;
+ s += _convert(argument);
+ sep = ', ';
+ }
+ s += ']';
+ }
+ if (_hasNamedArguments) {
+ s += '$sep{';
+ sep = '';
+ for (var name in extractKeys(_namedArguments)) {
+ s += sep;
+ s += '$name: ';
+ s += _convert(JS('', '#[#]', _namedArguments, name));
+ sep = ', ';
+ }
+ s += '}';
+ }
+ s += ') -> ';
+ if (_isVoid) {
+ s += 'void';
+ } else if (_hasReturnType) {
+ s += _convert(_returnType);
+ } else {
+ s += 'dynamic';
+ }
+ return _cachedToString = "$s";
+ }
+}
« no previous file with comments | « dart/sdk/lib/_internal/lib/collection_dev_patch.dart ('k') | dart/sdk/lib/_internal/lib/js_rti.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698