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

Unified Diff: pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/operations.dart

Issue 2423313002: Emulate compiling a source file in the context of an existing library. Add --debugger-compile flag … (Closed)
Patch Set: Code review comments. Created 4 years, 2 months 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 | « pkg/dev_compiler/lib/src/compiler/compiler.dart ('k') | pkg/dev_compiler/web/main.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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;
« no previous file with comments | « pkg/dev_compiler/lib/src/compiler/compiler.dart ('k') | pkg/dev_compiler/web/main.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698