| Index: pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/operations.dart
|
| diff --git a/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/operations.dart b/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/operations.dart
|
| index 913860a3b4aa8b5bf870d628fc1a5a298cbdd95d..ba0dbc662b8cca7f558a38849e0b79aa130d8eeb 100644
|
| --- a/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/operations.dart
|
| +++ b/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/operations.dart
|
| @@ -19,15 +19,13 @@ class InvocationImpl extends Invocation {
|
| this.isMethod: false,
|
| this.isGetter: false,
|
| this.isSetter: false})
|
| - : memberName = _dartSymbol(memberName),
|
| - namedArguments = _namedArgsToSymbols(namedArguments);
|
| + : memberName = _dartSymbol(memberName),
|
| + namedArguments = _namedArgsToSymbols(namedArguments);
|
|
|
| static Map<Symbol, dynamic> _namedArgsToSymbols(namedArgs) {
|
| if (namedArgs == null) return {};
|
| - return new Map.fromIterable(
|
| - getOwnPropertyNames(namedArgs),
|
| - key: _dartSymbol,
|
| - value: (k) => JS('', '#[#]', namedArgs, k));
|
| + return new Map.fromIterable(getOwnPropertyNames(namedArgs),
|
| + key: _dartSymbol, value: (k) => JS('', '#[#]', namedArgs, k));
|
| }
|
| }
|
|
|
| @@ -38,8 +36,8 @@ dload(obj, field) {
|
| if (hasMethod(obj, f)) return bind(obj, f, JS('', 'void 0'));
|
| return JS('', '#[#]', obj, f);
|
| }
|
| - return noSuchMethod(obj,
|
| - new InvocationImpl(field, JS('', '[]'), isGetter: true));
|
| + return noSuchMethod(
|
| + obj, new InvocationImpl(field, JS('', '[]'), isGetter: true));
|
| }
|
|
|
| dput(obj, field, value) {
|
| @@ -48,13 +46,15 @@ dput(obj, field, value) {
|
| if (f != null) {
|
| return JS('', '#[#] = #', obj, f, value);
|
| }
|
| - return noSuchMethod(obj,
|
| - new InvocationImpl(field, JS('', '[#]', value), isSetter: true));
|
| + return noSuchMethod(
|
| + obj, new InvocationImpl(field, JS('', '[#]', value), isSetter: true));
|
| }
|
|
|
| /// Check that a function of a given type can be applied to
|
| /// actuals.
|
| -_checkApply(type, actuals) => JS('', '''(() => {
|
| +_checkApply(type, actuals) => JS(
|
| + '',
|
| + '''(() => {
|
| if ($actuals.length < $type.args.length) return false;
|
| let index = 0;
|
| for(let i = 0; i < $type.args.length; ++i) {
|
| @@ -97,15 +97,17 @@ Symbol _dartSymbol(name) =>
|
| extractNamedArgs(args) {
|
| if (JS('bool', '#.length > 0', args)) {
|
| var last = JS('', '#[#.length - 1]', args, args);
|
| - if (JS('bool', '# != null && #.__proto__ === Object.prototype',
|
| - last, last)) {
|
| + if (JS(
|
| + 'bool', '# != null && #.__proto__ === Object.prototype', last, last)) {
|
| return JS('', '#.pop()', args);
|
| }
|
| }
|
| return null;
|
| }
|
|
|
| -_checkAndCall(f, ftype, obj, typeArgs, args, name) => JS('', '''(() => {
|
| +_checkAndCall(f, ftype, obj, typeArgs, args, name) => JS(
|
| + '',
|
| + '''(() => {
|
| $_trackCall($obj);
|
|
|
| let originalTarget = obj === void 0 ? f : obj;
|
| @@ -176,12 +178,68 @@ _checkAndCall(f, ftype, obj, typeArgs, args, name) => JS('', '''(() => {
|
| return callNSM();
|
| })()''');
|
|
|
| -dcall(f, @rest args) => _checkAndCall(
|
| - f, _getRuntimeType(f), JS('', 'void 0'), null, args, 'call');
|
| +dcall(f, @rest args) =>
|
| + _checkAndCall(f, _getRuntimeType(f), JS('', 'void 0'), null, args, 'call');
|
|
|
| dgcall(f, typeArgs, @rest args) => _checkAndCall(
|
| f, _getRuntimeType(f), JS('', 'void 0'), typeArgs, args, 'call');
|
|
|
| +/// Helper for REPL dynamic invocation variants that make a best effort to
|
| +/// enable accessing private members across library boundaries.
|
| +_dhelperRepl(object, field, callback) => JS(
|
| + '',
|
| + '''(() => {
|
| + let rawField = $field;
|
| + if (typeof(field) == 'symbol') {
|
| + // test if the specified field exists in which case it is safe to use it.
|
| + if ($field in $object) return $callback($field);
|
| +
|
| + // Symbol is from a different library. Make a best effort to
|
| + $field = $field.toString();
|
| + $field = $field.substring('Symbol('.length, field.length - 1);
|
| +
|
| + } else if ($field.charAt(0) != '_') {
|
| + // Not a private member so default call path is safe.
|
| + return $callback($field);
|
| + }
|
| +
|
| + // If the exact field name is present, invoke callback with it.
|
| + if ($field in $object) return $callback($field);
|
| +
|
| + // TODO(jacobr): warn if there are multiple private members with the same
|
| + // name which could happen if super classes in different libraries have
|
| + // the same private member name.
|
| + let proto = $object;
|
| + while (proto !== null) {
|
| + // Private field (indicated with "_").
|
| + let symbols = Object.getOwnPropertySymbols(proto);
|
| + let target = 'Symbol(' + $field + ')';
|
| +
|
| + for (let s = 0; s < symbols.length; s++) {
|
| + let sym = symbols[s];
|
| + if (target == sym.toString()) return $callback(sym);
|
| + }
|
| + proto = proto.__proto__;
|
| + }
|
| + // We didn't find a plausible alternate private symbol so just fall back
|
| + // to the regular field.
|
| + return $callback(rawField);
|
| +})()''');
|
| +
|
| +dloadRepl(obj, field) =>
|
| + _dhelperRepl(obj, field, (resolvedField) => dload(obj, resolvedField));
|
| +
|
| +dputRepl(obj, field, value) => _dhelperRepl(
|
| + obj, field, (resolvedField) => dput(obj, resolvedField, value));
|
| +
|
| +_callMethodRepl(obj, method, typeArgs, args) => _dhelperRepl(obj, method,
|
| + (resolvedField) => _callMethod(obj, resolvedField, typeArgs, args, method));
|
| +
|
| +dsendRepl(obj, method, @rest args) => _callMethodRepl(obj, method, null, args);
|
| +
|
| +dgsendRepl(obj, typeArgs, method, @rest args) =>
|
| + _callMethodRepl(obj, method, typeArgs, args);
|
| +
|
| class _MethodStats {
|
| final String typeName;
|
| final String frame;
|
| @@ -199,8 +257,8 @@ List<List<Object>> getDynamicStats() {
|
|
|
| var keys = _callMethodStats.keys.toList();
|
|
|
| - keys.sort((a, b) => _callMethodStats[b].count.compareTo(
|
| - _callMethodStats[a].count));
|
| + keys.sort(
|
| + (a, b) => _callMethodStats[b].count.compareTo(_callMethodStats[a].count));
|
| for (var key in keys) {
|
| var stats = _callMethodStats[key];
|
| ret.add([stats.typeName, stats.frame, stats.count]);
|
| @@ -231,16 +289,18 @@ _trackCall(obj) {
|
| }
|
|
|
| var actualTypeName = typeName(actual);
|
| - _callMethodStats.putIfAbsent("$actualTypeName <$src>",
|
| - () => new _MethodStats(actualTypeName, src)).count++;
|
| + _callMethodStats
|
| + .putIfAbsent(
|
| + "$actualTypeName <$src>", () => new _MethodStats(actualTypeName, src))
|
| + .count++;
|
| }
|
|
|
| /// Shared code for dsend, dindex, and dsetindex.
|
| _callMethod(obj, name, typeArgs, args, displayName) {
|
| var symbol = _canonicalMember(obj, name);
|
| if (symbol == null) {
|
| - return noSuchMethod(obj,
|
| - new InvocationImpl(displayName, args, isMethod: true));
|
| + return noSuchMethod(
|
| + obj, new InvocationImpl(displayName, args, isMethod: true));
|
| }
|
| var f = obj != null ? JS('', '#[#]', obj, symbol) : null;
|
| var ftype = getMethodType(obj, symbol);
|
| @@ -260,7 +320,9 @@ dsetindex(obj, index, value) =>
|
| /// TODO(leafp): This duplicates code in types.dart.
|
| /// I haven't found a way to factor it out that makes the
|
| /// code generator happy though.
|
| -_ignoreMemo(f) => JS('', '''(() => {
|
| +_ignoreMemo(f) => JS(
|
| + '',
|
| + '''(() => {
|
| let memo = new Map();
|
| return (t1, t2) => {
|
| let map = memo.get(t1);
|
| @@ -277,7 +339,9 @@ _ignoreMemo(f) => JS('', '''(() => {
|
| };
|
| })()''');
|
|
|
| -final _ignoreTypeFailure = JS('', '''(() => {
|
| +final _ignoreTypeFailure = JS(
|
| + '',
|
| + '''(() => {
|
| return $_ignoreMemo((actual, type) => {
|
| // TODO(vsm): Remove this hack ...
|
| // This is primarily due to the lack of generic methods,
|
| @@ -302,7 +366,9 @@ final _ignoreTypeFailure = JS('', '''(() => {
|
| /// and strong mode
|
| /// Returns null if [obj] is not an instance of [type] in strong mode
|
| /// but might be in spec mode
|
| -bool strongInstanceOf(obj, type, ignoreFromWhiteList) => JS('', '''(() => {
|
| +bool strongInstanceOf(obj, type, ignoreFromWhiteList) => JS(
|
| + '',
|
| + '''(() => {
|
| let actual = $getReifiedType($obj);
|
| let result = $isSubtype(actual, $type);
|
| if (result || actual == $jsobject ||
|
| @@ -316,14 +382,18 @@ bool strongInstanceOf(obj, type, ignoreFromWhiteList) => JS('', '''(() => {
|
| /// Returns true if [obj] is null or an instance of [type]
|
| /// Returns false if [obj] is non-null and not an instance of [type]
|
| /// in strong mode
|
| -instanceOfOrNull(obj, type) => JS('', '''(() => {
|
| +instanceOfOrNull(obj, type) => JS(
|
| + '',
|
| + '''(() => {
|
| // If strongInstanceOf returns null, convert to false here.
|
| if (($obj == null) || $strongInstanceOf($obj, $type, true)) return true;
|
| return false;
|
| })()''');
|
|
|
| @JSExportName('is')
|
| -instanceOf(obj, type) => JS('', '''(() => {
|
| +instanceOf(obj, type) => JS(
|
| + '',
|
| + '''(() => {
|
| let result = $strongInstanceOf($obj, $type);
|
| if (result !== null) return result;
|
| let actual = $getReifiedType($obj);
|
| @@ -389,7 +459,9 @@ asInt(obj) {
|
| /// Adds type type test predicates to a constructor for a non-parameterized
|
| /// type. Non-parameterized types can use `instanceof` for subclass checks and
|
| /// fall through to a helper for subtype tests.
|
| -addSimpleTypeTests(ctor) => JS('', '''(() => {
|
| +addSimpleTypeTests(ctor) => JS(
|
| + '',
|
| + '''(() => {
|
| $ctor.is = function is_C(object) {
|
| // This is incorrect for classes [Null] and [Object], so we do not use
|
| // [addSimpleTypeTests] for these classes.
|
| @@ -409,7 +481,9 @@ addSimpleTypeTests(ctor) => JS('', '''(() => {
|
| /// Adds type type test predicates to a constructor. Used for parmeterized
|
| /// types. We avoid `instanceof` for, e.g. `x is ListQueue` since there is
|
| /// no common class for `ListQueue<int>` and `ListQueue<String>`.
|
| -addTypeTests(ctor) => JS('', '''(() => {
|
| +addTypeTests(ctor) => JS(
|
| + '',
|
| + '''(() => {
|
| $ctor.as = function as_G(object) {
|
| return dart.as(object, this);
|
| };
|
| @@ -421,7 +495,9 @@ addTypeTests(ctor) => JS('', '''(() => {
|
| };
|
| })()''');
|
|
|
| -equals(x, y) => JS('', '''(() => {
|
| +equals(x, y) => JS(
|
| + '',
|
| + '''(() => {
|
| if ($x == null || $y == null) return $x == $y;
|
| let eq = $x['=='];
|
| return eq ? eq.call($x, $y) : $x === $y;
|
| @@ -449,7 +525,9 @@ notNull(x) {
|
| // TODO(jmesserly): this could be faster
|
| // TODO(jmesserly): we can use default values `= dynamic` once #417 is fixed.
|
| // TODO(jmesserly): move this to classes for consistentcy with list literals?
|
| -map(values, [K, V]) => JS('', '''(() => {
|
| +map(values, [K, V]) => JS(
|
| + '',
|
| + '''(() => {
|
| if ($K == null) $K = $dynamic;
|
| if ($V == null) $V = $dynamic;
|
| let map = ${getGenericClass(LinkedHashMap)}($K, $V).new();
|
| @@ -468,13 +546,17 @@ map(values, [K, V]) => JS('', '''(() => {
|
| })()''');
|
|
|
| @JSExportName('assert')
|
| -assert_(condition) => JS('', '''(() => {
|
| +assert_(condition) => JS(
|
| + '',
|
| + '''(() => {
|
| if (!$condition) $throwAssertionError();
|
| })()''');
|
|
|
| final _stack = JS('', 'new WeakMap()');
|
| @JSExportName('throw')
|
| -throw_(obj) => JS('', '''(() => {
|
| +throw_(obj) => JS(
|
| + '',
|
| + '''(() => {
|
| if ($obj != null && (typeof $obj == 'object' || typeof $obj == 'function')) {
|
| // TODO(jmesserly): couldn't we store the most recent stack in a single
|
| // variable? There should only be one active stack trace. That would
|
| @@ -484,19 +566,25 @@ throw_(obj) => JS('', '''(() => {
|
| throw $obj;
|
| })()''');
|
|
|
| -getError(exception) => JS('', '''(() => {
|
| +getError(exception) => JS(
|
| + '',
|
| + '''(() => {
|
| var stack = $_stack.get($exception);
|
| return stack !== void 0 ? stack : $exception;
|
| })()''');
|
|
|
| // This is a utility function: it is only intended to be called from dev
|
| // tools.
|
| -stackPrint(exception) => JS('', '''(() => {
|
| +stackPrint(exception) => JS(
|
| + '',
|
| + '''(() => {
|
| var error = $getError($exception);
|
| console.log(error.stack ? error.stack : 'No stack trace for: ' + error);
|
| })()''');
|
|
|
| -stackTrace(exception) => JS('', '''(() => {
|
| +stackTrace(exception) => JS(
|
| + '',
|
| + '''(() => {
|
| var error = $getError($exception);
|
| return $getTraceFromException(error);
|
| })()''');
|
| @@ -507,7 +595,9 @@ stackTrace(exception) => JS('', '''(() => {
|
| /// Will call each successive callback, unless one returns null, which stops
|
| /// the sequence.
|
| ///
|
| -nullSafe(obj, @rest callbacks) => JS('', '''(() => {
|
| +nullSafe(obj, @rest callbacks) => JS(
|
| + '',
|
| + '''(() => {
|
| if ($obj == null) return $obj;
|
| for (let callback of $callbacks) {
|
| $obj = callback($obj);
|
| @@ -517,6 +607,7 @@ nullSafe(obj, @rest callbacks) => JS('', '''(() => {
|
| })()''');
|
|
|
| final _value = JS('', 'Symbol("_value")');
|
| +
|
| ///
|
| /// Looks up a sequence of [keys] in [map], recursively, and
|
| /// returns the result. If the value is not found, [valueFn] will be called to
|
| @@ -529,7 +620,9 @@ final _value = JS('', 'Symbol("_value")');
|
| ///
|
| /// { 1: { 2: { 'hi ': { 'there ': 'world' } } } }
|
| ///
|
| -multiKeyPutIfAbsent(map, keys, valueFn) => JS('', '''(() => {
|
| +multiKeyPutIfAbsent(map, keys, valueFn) => JS(
|
| + '',
|
| + '''(() => {
|
| for (let k of $keys) {
|
| let value = $map.get(k);
|
| if (!value) {
|
| @@ -561,7 +654,9 @@ final constants = JS('', 'new Map()');
|
| /// - nested values of the object are themselves already canonicalized.
|
| ///
|
| @JSExportName('const')
|
| -const_(obj) => JS('', '''(() => {
|
| +const_(obj) => JS(
|
| + '',
|
| + '''(() => {
|
| // TODO(leafp): This table gets quite large in apps.
|
| // Keeping the paths is probably expensive. It would probably
|
| // be more space efficient to just use a direct hash table with
|
| @@ -612,7 +707,9 @@ final constantLists = JS('', 'new Map()');
|
| /// Canonicalize a constant list
|
| ///
|
| @JSExportName('constList')
|
| -constList_(elements, elementType) => JS('', '''(() => {
|
| +constList_(elements, elementType) => JS(
|
| + '',
|
| + '''(() => {
|
| function lookupNonTerminal(map, key) {
|
| let result = map.get(key);
|
| if (result !== void 0) return result;
|
| @@ -639,7 +736,7 @@ hashCode(obj) {
|
|
|
| switch (JS('String', 'typeof #', obj)) {
|
| case "number":
|
| - return JS('','# & 0x1FFFFFFF', obj);
|
| + return JS('', '# & 0x1FFFFFFF', obj);
|
| case "boolean":
|
| // From JSBool.hashCode, see comment there.
|
| return JS('', '# ? (2 * 3 * 23 * 3761) : (269 * 811)', obj);
|
| @@ -664,8 +761,8 @@ String _toString(obj) {
|
| return JS('String', '#[dartx.toString]()', obj);
|
| }
|
| if (JS('bool', 'typeof # == "function"', obj)) {
|
| - return JS('String', r'"Closure: " + # + " from: " + #',
|
| - getReifiedType(obj), obj);
|
| + return JS(
|
| + 'String', r'"Closure: " + # + " from: " + #', getReifiedType(obj), obj);
|
| }
|
| // TODO(jmesserly): restore this faster path once ES Symbol is treated as
|
| // an extension type (and thus hits the above code path).
|
| @@ -677,11 +774,8 @@ String _toString(obj) {
|
| // TODO(jmesserly): is the argument type verified statically?
|
| noSuchMethod(obj, Invocation invocation) {
|
| if (obj == null || JS('bool', 'typeof # == "function"', obj)) {
|
| - throw new NoSuchMethodError(
|
| - obj,
|
| - invocation.memberName,
|
| - invocation.positionalArguments,
|
| - invocation.namedArguments);
|
| + throw new NoSuchMethodError(obj, invocation.memberName,
|
| + invocation.positionalArguments, invocation.namedArguments);
|
| }
|
| // Delegate to the (possibly user-defined) method on the object.
|
| var extension = getExtensionType(obj);
|
| @@ -712,7 +806,9 @@ runtimeType(obj) {
|
| /// Implements Dart's interpolated strings as ES2015 tagged template literals.
|
| ///
|
| /// For example: dart.str`hello ${name}`
|
| -String str(strings, @rest values) => JS('', '''(() => {
|
| +String str(strings, @rest values) => JS(
|
| + '',
|
| + '''(() => {
|
| let s = $strings[0];
|
| for (let i = 0, len = $values.length; i < len; ) {
|
| s += $notNull($_toString($values[i])) + $strings[++i];
|
| @@ -720,8 +816,9 @@ String str(strings, @rest values) => JS('', '''(() => {
|
| return s;
|
| })()''');
|
|
|
| -
|
| -final JsIterator = JS('', '''
|
| +final JsIterator = JS(
|
| + '',
|
| + '''
|
| class JsIterator {
|
| constructor(dartIterator) {
|
| this.dartIterator = dartIterator;
|
|
|