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

Side by Side 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 unified diff | 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 »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 /// This library defines runtime operations on objects used by the code 5 /// This library defines runtime operations on objects used by the code
6 /// generator. 6 /// generator.
7 part of dart._runtime; 7 part of dart._runtime;
8 8
9 class InvocationImpl extends Invocation { 9 class InvocationImpl extends Invocation {
10 final Symbol memberName; 10 final Symbol memberName;
11 final List positionalArguments; 11 final List positionalArguments;
12 final Map<Symbol, dynamic> namedArguments; 12 final Map<Symbol, dynamic> namedArguments;
13 final bool isMethod; 13 final bool isMethod;
14 final bool isGetter; 14 final bool isGetter;
15 final bool isSetter; 15 final bool isSetter;
16 16
17 InvocationImpl(String memberName, this.positionalArguments, 17 InvocationImpl(String memberName, this.positionalArguments,
18 {namedArguments, 18 {namedArguments,
19 this.isMethod: false, 19 this.isMethod: false,
20 this.isGetter: false, 20 this.isGetter: false,
21 this.isSetter: false}) 21 this.isSetter: false})
22 : memberName = _dartSymbol(memberName), 22 : memberName = _dartSymbol(memberName),
23 namedArguments = _namedArgsToSymbols(namedArguments); 23 namedArguments = _namedArgsToSymbols(namedArguments);
24 24
25 static Map<Symbol, dynamic> _namedArgsToSymbols(namedArgs) { 25 static Map<Symbol, dynamic> _namedArgsToSymbols(namedArgs) {
26 if (namedArgs == null) return {}; 26 if (namedArgs == null) return {};
27 return new Map.fromIterable( 27 return new Map.fromIterable(getOwnPropertyNames(namedArgs),
28 getOwnPropertyNames(namedArgs), 28 key: _dartSymbol, value: (k) => JS('', '#[#]', namedArgs, k));
29 key: _dartSymbol,
30 value: (k) => JS('', '#[#]', namedArgs, k));
31 } 29 }
32 } 30 }
33 31
34 dload(obj, field) { 32 dload(obj, field) {
35 var f = _canonicalMember(obj, field); 33 var f = _canonicalMember(obj, field);
36 _trackCall(obj); 34 _trackCall(obj);
37 if (f != null) { 35 if (f != null) {
38 if (hasMethod(obj, f)) return bind(obj, f, JS('', 'void 0')); 36 if (hasMethod(obj, f)) return bind(obj, f, JS('', 'void 0'));
39 return JS('', '#[#]', obj, f); 37 return JS('', '#[#]', obj, f);
40 } 38 }
41 return noSuchMethod(obj, 39 return noSuchMethod(
42 new InvocationImpl(field, JS('', '[]'), isGetter: true)); 40 obj, new InvocationImpl(field, JS('', '[]'), isGetter: true));
43 } 41 }
44 42
45 dput(obj, field, value) { 43 dput(obj, field, value) {
46 var f = _canonicalMember(obj, field); 44 var f = _canonicalMember(obj, field);
47 _trackCall(obj); 45 _trackCall(obj);
48 if (f != null) { 46 if (f != null) {
49 return JS('', '#[#] = #', obj, f, value); 47 return JS('', '#[#] = #', obj, f, value);
50 } 48 }
51 return noSuchMethod(obj, 49 return noSuchMethod(
52 new InvocationImpl(field, JS('', '[#]', value), isSetter: true)); 50 obj, new InvocationImpl(field, JS('', '[#]', value), isSetter: true));
53 } 51 }
54 52
55 /// Check that a function of a given type can be applied to 53 /// Check that a function of a given type can be applied to
56 /// actuals. 54 /// actuals.
57 _checkApply(type, actuals) => JS('', '''(() => { 55 _checkApply(type, actuals) => JS(
56 '',
57 '''(() => {
58 if ($actuals.length < $type.args.length) return false; 58 if ($actuals.length < $type.args.length) return false;
59 let index = 0; 59 let index = 0;
60 for(let i = 0; i < $type.args.length; ++i) { 60 for(let i = 0; i < $type.args.length; ++i) {
61 if (!$instanceOfOrNull($actuals[i], $type.args[i])) return false; 61 if (!$instanceOfOrNull($actuals[i], $type.args[i])) return false;
62 ++index; 62 ++index;
63 } 63 }
64 if ($actuals.length == $type.args.length) return true; 64 if ($actuals.length == $type.args.length) return true;
65 let extras = $actuals.length - $type.args.length; 65 let extras = $actuals.length - $type.args.length;
66 if ($type.optionals.length > 0) { 66 if ($type.optionals.length > 0) {
67 if (extras > $type.optionals.length) return false; 67 if (extras > $type.optionals.length) return false;
(...skipping 22 matching lines...) Expand all
90 })()'''); 90 })()''');
91 91
92 Symbol _dartSymbol(name) => 92 Symbol _dartSymbol(name) =>
93 JS('', '#(#.new(#.toString()))', const_, Symbol, name); 93 JS('', '#(#.new(#.toString()))', const_, Symbol, name);
94 94
95 /// Extracts the named argument array from a list of arguments, and returns it. 95 /// Extracts the named argument array from a list of arguments, and returns it.
96 // TODO(jmesserly): we need to handle named arguments better. 96 // TODO(jmesserly): we need to handle named arguments better.
97 extractNamedArgs(args) { 97 extractNamedArgs(args) {
98 if (JS('bool', '#.length > 0', args)) { 98 if (JS('bool', '#.length > 0', args)) {
99 var last = JS('', '#[#.length - 1]', args, args); 99 var last = JS('', '#[#.length - 1]', args, args);
100 if (JS('bool', '# != null && #.__proto__ === Object.prototype', 100 if (JS(
101 last, last)) { 101 'bool', '# != null && #.__proto__ === Object.prototype', last, last)) {
102 return JS('', '#.pop()', args); 102 return JS('', '#.pop()', args);
103 } 103 }
104 } 104 }
105 return null; 105 return null;
106 } 106 }
107 107
108 _checkAndCall(f, ftype, obj, typeArgs, args, name) => JS('', '''(() => { 108 _checkAndCall(f, ftype, obj, typeArgs, args, name) => JS(
109 '',
110 '''(() => {
109 $_trackCall($obj); 111 $_trackCall($obj);
110 112
111 let originalTarget = obj === void 0 ? f : obj; 113 let originalTarget = obj === void 0 ? f : obj;
112 114
113 function callNSM() { 115 function callNSM() {
114 return $noSuchMethod(originalTarget, new $InvocationImpl( 116 return $noSuchMethod(originalTarget, new $InvocationImpl(
115 $name, $args, 117 $name, $args,
116 {namedArguments: $extractNamedArgs($args), isMethod: true})); 118 {namedArguments: $extractNamedArgs($args), isMethod: true}));
117 } 119 }
118 if (!($f instanceof Function)) { 120 if (!($f instanceof Function)) {
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
169 } 171 }
170 return $f.apply($obj, $args); 172 return $f.apply($obj, $args);
171 } 173 }
172 174
173 // TODO(leafp): throw a type error (rather than NSM) 175 // TODO(leafp): throw a type error (rather than NSM)
174 // if the arity matches but the types are wrong. 176 // if the arity matches but the types are wrong.
175 // TODO(jmesserly): nSM should include type args? 177 // TODO(jmesserly): nSM should include type args?
176 return callNSM(); 178 return callNSM();
177 })()'''); 179 })()''');
178 180
179 dcall(f, @rest args) => _checkAndCall( 181 dcall(f, @rest args) =>
180 f, _getRuntimeType(f), JS('', 'void 0'), null, args, 'call'); 182 _checkAndCall(f, _getRuntimeType(f), JS('', 'void 0'), null, args, 'call');
181 183
182 dgcall(f, typeArgs, @rest args) => _checkAndCall( 184 dgcall(f, typeArgs, @rest args) => _checkAndCall(
183 f, _getRuntimeType(f), JS('', 'void 0'), typeArgs, args, 'call'); 185 f, _getRuntimeType(f), JS('', 'void 0'), typeArgs, args, 'call');
184 186
187 /// Helper for REPL dynamic invocation variants that make a best effort to
188 /// enable accessing private members across library boundaries.
189 _dhelperRepl(object, field, callback) => JS(
190 '',
191 '''(() => {
192 let rawField = $field;
193 if (typeof(field) == 'symbol') {
194 // test if the specified field exists in which case it is safe to use it.
195 if ($field in $object) return $callback($field);
196
197 // Symbol is from a different library. Make a best effort to
198 $field = $field.toString();
199 $field = $field.substring('Symbol('.length, field.length - 1);
200
201 } else if ($field.charAt(0) != '_') {
202 // Not a private member so default call path is safe.
203 return $callback($field);
204 }
205
206 // If the exact field name is present, invoke callback with it.
207 if ($field in $object) return $callback($field);
208
209 // TODO(jacobr): warn if there are multiple private members with the same
210 // name which could happen if super classes in different libraries have
211 // the same private member name.
212 let proto = $object;
213 while (proto !== null) {
214 // Private field (indicated with "_").
215 let symbols = Object.getOwnPropertySymbols(proto);
216 let target = 'Symbol(' + $field + ')';
217
218 for (let s = 0; s < symbols.length; s++) {
219 let sym = symbols[s];
220 if (target == sym.toString()) return $callback(sym);
221 }
222 proto = proto.__proto__;
223 }
224 // We didn't find a plausible alternate private symbol so just fall back
225 // to the regular field.
226 return $callback(rawField);
227 })()''');
228
229 dloadRepl(obj, field) =>
230 _dhelperRepl(obj, field, (resolvedField) => dload(obj, resolvedField));
231
232 dputRepl(obj, field, value) => _dhelperRepl(
233 obj, field, (resolvedField) => dput(obj, resolvedField, value));
234
235 _callMethodRepl(obj, method, typeArgs, args) => _dhelperRepl(obj, method,
236 (resolvedField) => _callMethod(obj, resolvedField, typeArgs, args, method));
237
238 dsendRepl(obj, method, @rest args) => _callMethodRepl(obj, method, null, args);
239
240 dgsendRepl(obj, typeArgs, method, @rest args) =>
241 _callMethodRepl(obj, method, typeArgs, args);
242
185 class _MethodStats { 243 class _MethodStats {
186 final String typeName; 244 final String typeName;
187 final String frame; 245 final String frame;
188 int count; 246 int count;
189 247
190 _MethodStats(this.typeName, this.frame) { 248 _MethodStats(this.typeName, this.frame) {
191 count = 0; 249 count = 0;
192 } 250 }
193 } 251 }
194 252
195 Map<String, _MethodStats> _callMethodStats = new Map(); 253 Map<String, _MethodStats> _callMethodStats = new Map();
196 254
197 List<List<Object>> getDynamicStats() { 255 List<List<Object>> getDynamicStats() {
198 List<List<Object>> ret = []; 256 List<List<Object>> ret = [];
199 257
200 var keys = _callMethodStats.keys.toList(); 258 var keys = _callMethodStats.keys.toList();
201 259
202 keys.sort((a, b) => _callMethodStats[b].count.compareTo( 260 keys.sort(
203 _callMethodStats[a].count)); 261 (a, b) => _callMethodStats[b].count.compareTo(_callMethodStats[a].count));
204 for (var key in keys) { 262 for (var key in keys) {
205 var stats = _callMethodStats[key]; 263 var stats = _callMethodStats[key];
206 ret.add([stats.typeName, stats.frame, stats.count]); 264 ret.add([stats.typeName, stats.frame, stats.count]);
207 } 265 }
208 266
209 return ret; 267 return ret;
210 } 268 }
211 269
212 clearDynamicStats() { 270 clearDynamicStats() {
213 _callMethodStats.clear(); 271 _callMethodStats.clear();
(...skipping 10 matching lines...) Expand all
224 var src = ''; 282 var src = '';
225 for (int i = 2; i < stack.length; ++i) { 283 for (int i = 2; i < stack.length; ++i) {
226 var frame = stack[i]; 284 var frame = stack[i];
227 if (!frame.contains('dart_sdk.js')) { 285 if (!frame.contains('dart_sdk.js')) {
228 src = frame; 286 src = frame;
229 break; 287 break;
230 } 288 }
231 } 289 }
232 290
233 var actualTypeName = typeName(actual); 291 var actualTypeName = typeName(actual);
234 _callMethodStats.putIfAbsent("$actualTypeName <$src>", 292 _callMethodStats
235 () => new _MethodStats(actualTypeName, src)).count++; 293 .putIfAbsent(
294 "$actualTypeName <$src>", () => new _MethodStats(actualTypeName, src))
295 .count++;
236 } 296 }
237 297
238 /// Shared code for dsend, dindex, and dsetindex. 298 /// Shared code for dsend, dindex, and dsetindex.
239 _callMethod(obj, name, typeArgs, args, displayName) { 299 _callMethod(obj, name, typeArgs, args, displayName) {
240 var symbol = _canonicalMember(obj, name); 300 var symbol = _canonicalMember(obj, name);
241 if (symbol == null) { 301 if (symbol == null) {
242 return noSuchMethod(obj, 302 return noSuchMethod(
243 new InvocationImpl(displayName, args, isMethod: true)); 303 obj, new InvocationImpl(displayName, args, isMethod: true));
244 } 304 }
245 var f = obj != null ? JS('', '#[#]', obj, symbol) : null; 305 var f = obj != null ? JS('', '#[#]', obj, symbol) : null;
246 var ftype = getMethodType(obj, symbol); 306 var ftype = getMethodType(obj, symbol);
247 return _checkAndCall(f, ftype, obj, typeArgs, args, displayName); 307 return _checkAndCall(f, ftype, obj, typeArgs, args, displayName);
248 } 308 }
249 309
250 dsend(obj, method, @rest args) => _callMethod(obj, method, null, args, method); 310 dsend(obj, method, @rest args) => _callMethod(obj, method, null, args, method);
251 311
252 dgsend(obj, typeArgs, method, @rest args) => 312 dgsend(obj, typeArgs, method, @rest args) =>
253 _callMethod(obj, method, typeArgs, args, method); 313 _callMethod(obj, method, typeArgs, args, method);
254 314
255 dindex(obj, index) => _callMethod(obj, 'get', null, JS('', '[#]', index), '[]'); 315 dindex(obj, index) => _callMethod(obj, 'get', null, JS('', '[#]', index), '[]');
256 316
257 dsetindex(obj, index, value) => 317 dsetindex(obj, index, value) =>
258 _callMethod(obj, 'set', null, JS('', '[#, #]', index, value), '[]='); 318 _callMethod(obj, 'set', null, JS('', '[#, #]', index, value), '[]=');
259 319
260 /// TODO(leafp): This duplicates code in types.dart. 320 /// TODO(leafp): This duplicates code in types.dart.
261 /// I haven't found a way to factor it out that makes the 321 /// I haven't found a way to factor it out that makes the
262 /// code generator happy though. 322 /// code generator happy though.
263 _ignoreMemo(f) => JS('', '''(() => { 323 _ignoreMemo(f) => JS(
324 '',
325 '''(() => {
264 let memo = new Map(); 326 let memo = new Map();
265 return (t1, t2) => { 327 return (t1, t2) => {
266 let map = memo.get(t1); 328 let map = memo.get(t1);
267 let result; 329 let result;
268 if (map) { 330 if (map) {
269 result = map.get(t2); 331 result = map.get(t2);
270 if (result !== void 0) return result; 332 if (result !== void 0) return result;
271 } else { 333 } else {
272 memo.set(t1, map = new Map()); 334 memo.set(t1, map = new Map());
273 } 335 }
274 result = $f(t1, t2); 336 result = $f(t1, t2);
275 map.set(t2, result); 337 map.set(t2, result);
276 return result; 338 return result;
277 }; 339 };
278 })()'''); 340 })()''');
279 341
280 final _ignoreTypeFailure = JS('', '''(() => { 342 final _ignoreTypeFailure = JS(
343 '',
344 '''(() => {
281 return $_ignoreMemo((actual, type) => { 345 return $_ignoreMemo((actual, type) => {
282 // TODO(vsm): Remove this hack ... 346 // TODO(vsm): Remove this hack ...
283 // This is primarily due to the lack of generic methods, 347 // This is primarily due to the lack of generic methods,
284 // but we need to triage all the types. 348 // but we need to triage all the types.
285 if (!!$isSubtype(type, $Iterable) && !!$isSubtype(actual, $Iterable) || 349 if (!!$isSubtype(type, $Iterable) && !!$isSubtype(actual, $Iterable) ||
286 !!$isSubtype(type, $Future) && !!$isSubtype(actual, $Future) || 350 !!$isSubtype(type, $Future) && !!$isSubtype(actual, $Future) ||
287 !!$isSubtype(type, $Map) && !!$isSubtype(actual, $Map) || 351 !!$isSubtype(type, $Map) && !!$isSubtype(actual, $Map) ||
288 $isFunctionType(type) && $isFunctionType(actual) || 352 $isFunctionType(type) && $isFunctionType(actual) ||
289 !!$isSubtype(type, $Stream) && !!$isSubtype(actual, $Stream) || 353 !!$isSubtype(type, $Stream) && !!$isSubtype(actual, $Stream) ||
290 !!$isSubtype(type, $StreamSubscription) && 354 !!$isSubtype(type, $StreamSubscription) &&
291 !!$isSubtype(actual, $StreamSubscription)) { 355 !!$isSubtype(actual, $StreamSubscription)) {
292 console.warn('Ignoring cast fail from ' + $typeName(actual) + 356 console.warn('Ignoring cast fail from ' + $typeName(actual) +
293 ' to ' + $typeName(type)); 357 ' to ' + $typeName(type));
294 return true; 358 return true;
295 } 359 }
296 return false; 360 return false;
297 }); 361 });
298 })()'''); 362 })()''');
299 363
300 /// Returns true if [obj] is an instance of [type] 364 /// Returns true if [obj] is an instance of [type]
301 /// Returns false if [obj] is not an instance of [type] in both spec 365 /// Returns false if [obj] is not an instance of [type] in both spec
302 /// and strong mode 366 /// and strong mode
303 /// Returns null if [obj] is not an instance of [type] in strong mode 367 /// Returns null if [obj] is not an instance of [type] in strong mode
304 /// but might be in spec mode 368 /// but might be in spec mode
305 bool strongInstanceOf(obj, type, ignoreFromWhiteList) => JS('', '''(() => { 369 bool strongInstanceOf(obj, type, ignoreFromWhiteList) => JS(
370 '',
371 '''(() => {
306 let actual = $getReifiedType($obj); 372 let actual = $getReifiedType($obj);
307 let result = $isSubtype(actual, $type); 373 let result = $isSubtype(actual, $type);
308 if (result || actual == $jsobject || 374 if (result || actual == $jsobject ||
309 actual == $int && type == $double) return true; 375 actual == $int && type == $double) return true;
310 if (result === false) return false; 376 if (result === false) return false;
311 if ($ignoreFromWhiteList == void 0) return result; 377 if ($ignoreFromWhiteList == void 0) return result;
312 if ($_ignoreTypeFailure(actual, $type)) return true; 378 if ($_ignoreTypeFailure(actual, $type)) return true;
313 return result; 379 return result;
314 })()'''); 380 })()''');
315 381
316 /// Returns true if [obj] is null or an instance of [type] 382 /// Returns true if [obj] is null or an instance of [type]
317 /// Returns false if [obj] is non-null and not an instance of [type] 383 /// Returns false if [obj] is non-null and not an instance of [type]
318 /// in strong mode 384 /// in strong mode
319 instanceOfOrNull(obj, type) => JS('', '''(() => { 385 instanceOfOrNull(obj, type) => JS(
386 '',
387 '''(() => {
320 // If strongInstanceOf returns null, convert to false here. 388 // If strongInstanceOf returns null, convert to false here.
321 if (($obj == null) || $strongInstanceOf($obj, $type, true)) return true; 389 if (($obj == null) || $strongInstanceOf($obj, $type, true)) return true;
322 return false; 390 return false;
323 })()'''); 391 })()''');
324 392
325 @JSExportName('is') 393 @JSExportName('is')
326 instanceOf(obj, type) => JS('', '''(() => { 394 instanceOf(obj, type) => JS(
395 '',
396 '''(() => {
327 let result = $strongInstanceOf($obj, $type); 397 let result = $strongInstanceOf($obj, $type);
328 if (result !== null) return result; 398 if (result !== null) return result;
329 let actual = $getReifiedType($obj); 399 let actual = $getReifiedType($obj);
330 $throwStrongModeError('Strong mode is-check failure: ' + 400 $throwStrongModeError('Strong mode is-check failure: ' +
331 $typeName(actual) + ' does not soundly subtype ' + 401 $typeName(actual) + ' does not soundly subtype ' +
332 $typeName($type)); 402 $typeName($type));
333 })()'''); 403 })()''');
334 404
335 @JSExportName('as') 405 @JSExportName('as')
336 cast(obj, type) { 406 cast(obj, type) {
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
382 452
383 if (JS('bool', 'Math.floor(#) != #', obj, obj)) { 453 if (JS('bool', 'Math.floor(#) != #', obj, obj)) {
384 throwCastError(obj, getReifiedType(obj), JS('', '#', int)); 454 throwCastError(obj, getReifiedType(obj), JS('', '#', int));
385 } 455 }
386 return obj; 456 return obj;
387 } 457 }
388 458
389 /// Adds type type test predicates to a constructor for a non-parameterized 459 /// Adds type type test predicates to a constructor for a non-parameterized
390 /// type. Non-parameterized types can use `instanceof` for subclass checks and 460 /// type. Non-parameterized types can use `instanceof` for subclass checks and
391 /// fall through to a helper for subtype tests. 461 /// fall through to a helper for subtype tests.
392 addSimpleTypeTests(ctor) => JS('', '''(() => { 462 addSimpleTypeTests(ctor) => JS(
463 '',
464 '''(() => {
393 $ctor.is = function is_C(object) { 465 $ctor.is = function is_C(object) {
394 // This is incorrect for classes [Null] and [Object], so we do not use 466 // This is incorrect for classes [Null] and [Object], so we do not use
395 // [addSimpleTypeTests] for these classes. 467 // [addSimpleTypeTests] for these classes.
396 if (object instanceof this) return true; 468 if (object instanceof this) return true;
397 return dart.is(object, this); 469 return dart.is(object, this);
398 }; 470 };
399 $ctor.as = function as_C(object) { 471 $ctor.as = function as_C(object) {
400 if (object instanceof this) return object; 472 if (object instanceof this) return object;
401 return dart.as(object, this); 473 return dart.as(object, this);
402 }; 474 };
403 $ctor._check = function check_C(object) { 475 $ctor._check = function check_C(object) {
404 if (object instanceof this) return object; 476 if (object instanceof this) return object;
405 return dart.check(object, this); 477 return dart.check(object, this);
406 }; 478 };
407 })()'''); 479 })()''');
408 480
409 /// Adds type type test predicates to a constructor. Used for parmeterized 481 /// Adds type type test predicates to a constructor. Used for parmeterized
410 /// types. We avoid `instanceof` for, e.g. `x is ListQueue` since there is 482 /// types. We avoid `instanceof` for, e.g. `x is ListQueue` since there is
411 /// no common class for `ListQueue<int>` and `ListQueue<String>`. 483 /// no common class for `ListQueue<int>` and `ListQueue<String>`.
412 addTypeTests(ctor) => JS('', '''(() => { 484 addTypeTests(ctor) => JS(
485 '',
486 '''(() => {
413 $ctor.as = function as_G(object) { 487 $ctor.as = function as_G(object) {
414 return dart.as(object, this); 488 return dart.as(object, this);
415 }; 489 };
416 $ctor.is = function is_G(object) { 490 $ctor.is = function is_G(object) {
417 return dart.is(object, this); 491 return dart.is(object, this);
418 }; 492 };
419 $ctor._check = function check_G(object) { 493 $ctor._check = function check_G(object) {
420 return dart.check(object, this); 494 return dart.check(object, this);
421 }; 495 };
422 })()'''); 496 })()''');
423 497
424 equals(x, y) => JS('', '''(() => { 498 equals(x, y) => JS(
499 '',
500 '''(() => {
425 if ($x == null || $y == null) return $x == $y; 501 if ($x == null || $y == null) return $x == $y;
426 let eq = $x['==']; 502 let eq = $x['=='];
427 return eq ? eq.call($x, $y) : $x === $y; 503 return eq ? eq.call($x, $y) : $x === $y;
428 })()'''); 504 })()''');
429 505
430 /// Checks that `x` is not null or undefined. */ 506 /// Checks that `x` is not null or undefined. */
431 notNull(x) { 507 notNull(x) {
432 if (x == null) throwNullValueError(); 508 if (x == null) throwNullValueError();
433 return x; 509 return x;
434 } 510 }
435 511
436 /// 512 ///
437 /// Creates a dart:collection LinkedHashMap. 513 /// Creates a dart:collection LinkedHashMap.
438 /// 514 ///
439 /// For a map with string keys an object literal can be used, for example 515 /// For a map with string keys an object literal can be used, for example
440 /// `map({'hi': 1, 'there': 2})`. 516 /// `map({'hi': 1, 'there': 2})`.
441 /// 517 ///
442 /// Otherwise an array should be used, for example `map([1, 2, 3, 4])` will 518 /// Otherwise an array should be used, for example `map([1, 2, 3, 4])` will
443 /// create a map with keys [1, 3] and values [2, 4]. Each key-value pair 519 /// create a map with keys [1, 3] and values [2, 4]. Each key-value pair
444 /// should be adjacent entries in the array. 520 /// should be adjacent entries in the array.
445 /// 521 ///
446 /// For a map with no keys the function can be called with no arguments, for 522 /// For a map with no keys the function can be called with no arguments, for
447 /// example `map()`. 523 /// example `map()`.
448 /// 524 ///
449 // TODO(jmesserly): this could be faster 525 // TODO(jmesserly): this could be faster
450 // TODO(jmesserly): we can use default values `= dynamic` once #417 is fixed. 526 // TODO(jmesserly): we can use default values `= dynamic` once #417 is fixed.
451 // TODO(jmesserly): move this to classes for consistentcy with list literals? 527 // TODO(jmesserly): move this to classes for consistentcy with list literals?
452 map(values, [K, V]) => JS('', '''(() => { 528 map(values, [K, V]) => JS(
529 '',
530 '''(() => {
453 if ($K == null) $K = $dynamic; 531 if ($K == null) $K = $dynamic;
454 if ($V == null) $V = $dynamic; 532 if ($V == null) $V = $dynamic;
455 let map = ${getGenericClass(LinkedHashMap)}($K, $V).new(); 533 let map = ${getGenericClass(LinkedHashMap)}($K, $V).new();
456 if (Array.isArray($values)) { 534 if (Array.isArray($values)) {
457 for (let i = 0, end = $values.length - 1; i < end; i += 2) { 535 for (let i = 0, end = $values.length - 1; i < end; i += 2) {
458 let key = $values[i]; 536 let key = $values[i];
459 let value = $values[i + 1]; 537 let value = $values[i + 1];
460 map.set(key, value); 538 map.set(key, value);
461 } 539 }
462 } else if (typeof $values === 'object') { 540 } else if (typeof $values === 'object') {
463 for (let key of $getOwnPropertyNames($values)) { 541 for (let key of $getOwnPropertyNames($values)) {
464 map.set(key, $values[key]); 542 map.set(key, $values[key]);
465 } 543 }
466 } 544 }
467 return map; 545 return map;
468 })()'''); 546 })()''');
469 547
470 @JSExportName('assert') 548 @JSExportName('assert')
471 assert_(condition) => JS('', '''(() => { 549 assert_(condition) => JS(
550 '',
551 '''(() => {
472 if (!$condition) $throwAssertionError(); 552 if (!$condition) $throwAssertionError();
473 })()'''); 553 })()''');
474 554
475 final _stack = JS('', 'new WeakMap()'); 555 final _stack = JS('', 'new WeakMap()');
476 @JSExportName('throw') 556 @JSExportName('throw')
477 throw_(obj) => JS('', '''(() => { 557 throw_(obj) => JS(
558 '',
559 '''(() => {
478 if ($obj != null && (typeof $obj == 'object' || typeof $obj == 'function')) { 560 if ($obj != null && (typeof $obj == 'object' || typeof $obj == 'function')) {
479 // TODO(jmesserly): couldn't we store the most recent stack in a single 561 // TODO(jmesserly): couldn't we store the most recent stack in a single
480 // variable? There should only be one active stack trace. That would 562 // variable? There should only be one active stack trace. That would
481 // allow it to work for things like strings and numbers. 563 // allow it to work for things like strings and numbers.
482 $_stack.set($obj, new Error()); 564 $_stack.set($obj, new Error());
483 } 565 }
484 throw $obj; 566 throw $obj;
485 })()'''); 567 })()''');
486 568
487 getError(exception) => JS('', '''(() => { 569 getError(exception) => JS(
570 '',
571 '''(() => {
488 var stack = $_stack.get($exception); 572 var stack = $_stack.get($exception);
489 return stack !== void 0 ? stack : $exception; 573 return stack !== void 0 ? stack : $exception;
490 })()'''); 574 })()''');
491 575
492 // This is a utility function: it is only intended to be called from dev 576 // This is a utility function: it is only intended to be called from dev
493 // tools. 577 // tools.
494 stackPrint(exception) => JS('', '''(() => { 578 stackPrint(exception) => JS(
579 '',
580 '''(() => {
495 var error = $getError($exception); 581 var error = $getError($exception);
496 console.log(error.stack ? error.stack : 'No stack trace for: ' + error); 582 console.log(error.stack ? error.stack : 'No stack trace for: ' + error);
497 })()'''); 583 })()''');
498 584
499 stackTrace(exception) => JS('', '''(() => { 585 stackTrace(exception) => JS(
586 '',
587 '''(() => {
500 var error = $getError($exception); 588 var error = $getError($exception);
501 return $getTraceFromException(error); 589 return $getTraceFromException(error);
502 })()'''); 590 })()''');
503 591
504 /// 592 ///
505 /// Implements a sequence of .? operations. 593 /// Implements a sequence of .? operations.
506 /// 594 ///
507 /// Will call each successive callback, unless one returns null, which stops 595 /// Will call each successive callback, unless one returns null, which stops
508 /// the sequence. 596 /// the sequence.
509 /// 597 ///
510 nullSafe(obj, @rest callbacks) => JS('', '''(() => { 598 nullSafe(obj, @rest callbacks) => JS(
599 '',
600 '''(() => {
511 if ($obj == null) return $obj; 601 if ($obj == null) return $obj;
512 for (let callback of $callbacks) { 602 for (let callback of $callbacks) {
513 $obj = callback($obj); 603 $obj = callback($obj);
514 if ($obj == null) break; 604 if ($obj == null) break;
515 } 605 }
516 return $obj; 606 return $obj;
517 })()'''); 607 })()''');
518 608
519 final _value = JS('', 'Symbol("_value")'); 609 final _value = JS('', 'Symbol("_value")');
610
520 /// 611 ///
521 /// Looks up a sequence of [keys] in [map], recursively, and 612 /// Looks up a sequence of [keys] in [map], recursively, and
522 /// returns the result. If the value is not found, [valueFn] will be called to 613 /// returns the result. If the value is not found, [valueFn] will be called to
523 /// add it. For example: 614 /// add it. For example:
524 /// 615 ///
525 /// let map = new Map(); 616 /// let map = new Map();
526 /// putIfAbsent(map, [1, 2, 'hi ', 'there '], () => 'world'); 617 /// putIfAbsent(map, [1, 2, 'hi ', 'there '], () => 'world');
527 /// 618 ///
528 /// ... will create a Map with a structure like: 619 /// ... will create a Map with a structure like:
529 /// 620 ///
530 /// { 1: { 2: { 'hi ': { 'there ': 'world' } } } } 621 /// { 1: { 2: { 'hi ': { 'there ': 'world' } } } }
531 /// 622 ///
532 multiKeyPutIfAbsent(map, keys, valueFn) => JS('', '''(() => { 623 multiKeyPutIfAbsent(map, keys, valueFn) => JS(
624 '',
625 '''(() => {
533 for (let k of $keys) { 626 for (let k of $keys) {
534 let value = $map.get(k); 627 let value = $map.get(k);
535 if (!value) { 628 if (!value) {
536 // TODO(jmesserly): most of these maps are very small (e.g. 1 item), 629 // TODO(jmesserly): most of these maps are very small (e.g. 1 item),
537 // so it may be worth optimizing for that. 630 // so it may be worth optimizing for that.
538 $map.set(k, value = new Map()); 631 $map.set(k, value = new Map());
539 } 632 }
540 $map = value; 633 $map = value;
541 } 634 }
542 if ($map.has($_value)) return $map.get($_value); 635 if ($map.has($_value)) return $map.get($_value);
(...skipping 11 matching lines...) Expand all
554 final constants = JS('', 'new Map()'); 647 final constants = JS('', 'new Map()');
555 648
556 /// 649 ///
557 /// Canonicalize a constant object. 650 /// Canonicalize a constant object.
558 /// 651 ///
559 /// Preconditions: 652 /// Preconditions:
560 /// - `obj` is an objects or array, not a primitive. 653 /// - `obj` is an objects or array, not a primitive.
561 /// - nested values of the object are themselves already canonicalized. 654 /// - nested values of the object are themselves already canonicalized.
562 /// 655 ///
563 @JSExportName('const') 656 @JSExportName('const')
564 const_(obj) => JS('', '''(() => { 657 const_(obj) => JS(
658 '',
659 '''(() => {
565 // TODO(leafp): This table gets quite large in apps. 660 // TODO(leafp): This table gets quite large in apps.
566 // Keeping the paths is probably expensive. It would probably 661 // Keeping the paths is probably expensive. It would probably
567 // be more space efficient to just use a direct hash table with 662 // be more space efficient to just use a direct hash table with
568 // an appropriately defined structural equality function. 663 // an appropriately defined structural equality function.
569 function lookupNonTerminal(map, key) { 664 function lookupNonTerminal(map, key) {
570 let result = map.get(key); 665 let result = map.get(key);
571 if (result !== void 0) return result; 666 if (result !== void 0) return result;
572 map.set(key, result = new Map()); 667 map.set(key, result = new Map());
573 return result; 668 return result;
574 }; 669 };
(...skipping 30 matching lines...) Expand all
605 /// This maps the number of elements in the list (n) 700 /// This maps the number of elements in the list (n)
606 /// to a path of length n of maps indexed by the value 701 /// to a path of length n of maps indexed by the value
607 /// of the field. The final map is indexed by the element 702 /// of the field. The final map is indexed by the element
608 /// type and contains the canonical version of the list. 703 /// type and contains the canonical version of the list.
609 final constantLists = JS('', 'new Map()'); 704 final constantLists = JS('', 'new Map()');
610 705
611 /// 706 ///
612 /// Canonicalize a constant list 707 /// Canonicalize a constant list
613 /// 708 ///
614 @JSExportName('constList') 709 @JSExportName('constList')
615 constList_(elements, elementType) => JS('', '''(() => { 710 constList_(elements, elementType) => JS(
711 '',
712 '''(() => {
616 function lookupNonTerminal(map, key) { 713 function lookupNonTerminal(map, key) {
617 let result = map.get(key); 714 let result = map.get(key);
618 if (result !== void 0) return result; 715 if (result !== void 0) return result;
619 map.set(key, result = new Map()); 716 map.set(key, result = new Map());
620 return result; 717 return result;
621 }; 718 };
622 let count = $elements.length; 719 let count = $elements.length;
623 let map = lookupNonTerminal($constantLists, count); 720 let map = lookupNonTerminal($constantLists, count);
624 for (let i = 0; i < count; i++) { 721 for (let i = 0; i < count; i++) {
625 map = lookupNonTerminal(map, elements[i]); 722 map = lookupNonTerminal(map, elements[i]);
626 } 723 }
627 let value = map.get($elementType); 724 let value = map.get($elementType);
628 if (value) return value; 725 if (value) return value;
629 value = $list($elements, $elementType); 726 value = $list($elements, $elementType);
630 map.set($elementType, value); 727 map.set($elementType, value);
631 return value; 728 return value;
632 })()'''); 729 })()''');
633 730
634 // The following are helpers for Object methods when the receiver 731 // The following are helpers for Object methods when the receiver
635 // may be null or primitive. These should only be generated by 732 // may be null or primitive. These should only be generated by
636 // the compiler. 733 // the compiler.
637 hashCode(obj) { 734 hashCode(obj) {
638 if (obj == null) return 0; 735 if (obj == null) return 0;
639 736
640 switch (JS('String', 'typeof #', obj)) { 737 switch (JS('String', 'typeof #', obj)) {
641 case "number": 738 case "number":
642 return JS('','# & 0x1FFFFFFF', obj); 739 return JS('', '# & 0x1FFFFFFF', obj);
643 case "boolean": 740 case "boolean":
644 // From JSBool.hashCode, see comment there. 741 // From JSBool.hashCode, see comment there.
645 return JS('', '# ? (2 * 3 * 23 * 3761) : (269 * 811)', obj); 742 return JS('', '# ? (2 * 3 * 23 * 3761) : (269 * 811)', obj);
646 case "function": 743 case "function":
647 // TODO(jmesserly): this doesn't work for method tear-offs. 744 // TODO(jmesserly): this doesn't work for method tear-offs.
648 return Primitives.objectHashCode(obj); 745 return Primitives.objectHashCode(obj);
649 } 746 }
650 747
651 var extension = getExtensionType(obj); 748 var extension = getExtensionType(obj);
652 if (extension != null) { 749 if (extension != null) {
653 return JS('', '#[dartx.hashCode]', obj); 750 return JS('', '#[dartx.hashCode]', obj);
654 } 751 }
655 return JS('', '#.hashCode', obj); 752 return JS('', '#.hashCode', obj);
656 } 753 }
657 754
658 @JSExportName('toString') 755 @JSExportName('toString')
659 String _toString(obj) { 756 String _toString(obj) {
660 if (obj == null) return "null"; 757 if (obj == null) return "null";
661 758
662 var extension = getExtensionType(obj); 759 var extension = getExtensionType(obj);
663 if (extension != null) { 760 if (extension != null) {
664 return JS('String', '#[dartx.toString]()', obj); 761 return JS('String', '#[dartx.toString]()', obj);
665 } 762 }
666 if (JS('bool', 'typeof # == "function"', obj)) { 763 if (JS('bool', 'typeof # == "function"', obj)) {
667 return JS('String', r'"Closure: " + # + " from: " + #', 764 return JS(
668 getReifiedType(obj), obj); 765 'String', r'"Closure: " + # + " from: " + #', getReifiedType(obj), obj);
669 } 766 }
670 // TODO(jmesserly): restore this faster path once ES Symbol is treated as 767 // TODO(jmesserly): restore this faster path once ES Symbol is treated as
671 // an extension type (and thus hits the above code path). 768 // an extension type (and thus hits the above code path).
672 // See https://github.com/dart-lang/dev_compiler/issues/578. 769 // See https://github.com/dart-lang/dev_compiler/issues/578.
673 // return JS('', '"" + #', obj); 770 // return JS('', '"" + #', obj);
674 return JS('String', '#.toString()', obj); 771 return JS('String', '#.toString()', obj);
675 } 772 }
676 773
677 // TODO(jmesserly): is the argument type verified statically? 774 // TODO(jmesserly): is the argument type verified statically?
678 noSuchMethod(obj, Invocation invocation) { 775 noSuchMethod(obj, Invocation invocation) {
679 if (obj == null || JS('bool', 'typeof # == "function"', obj)) { 776 if (obj == null || JS('bool', 'typeof # == "function"', obj)) {
680 throw new NoSuchMethodError( 777 throw new NoSuchMethodError(obj, invocation.memberName,
681 obj, 778 invocation.positionalArguments, invocation.namedArguments);
682 invocation.memberName,
683 invocation.positionalArguments,
684 invocation.namedArguments);
685 } 779 }
686 // Delegate to the (possibly user-defined) method on the object. 780 // Delegate to the (possibly user-defined) method on the object.
687 var extension = getExtensionType(obj); 781 var extension = getExtensionType(obj);
688 if (extension != null) { 782 if (extension != null) {
689 return JS('', '#[dartx.noSuchMethod](#)', obj, invocation); 783 return JS('', '#[dartx.noSuchMethod](#)', obj, invocation);
690 } 784 }
691 return JS('', '#.noSuchMethod(#)', obj, invocation); 785 return JS('', '#.noSuchMethod(#)', obj, invocation);
692 } 786 }
693 787
694 constFn(x) => JS('', '() => x'); 788 constFn(x) => JS('', '() => x');
(...skipping 10 matching lines...) Expand all
705 } 799 }
706 if (JS('bool', 'typeof # == "function"', obj)) { 800 if (JS('bool', 'typeof # == "function"', obj)) {
707 return wrapType(getReifiedType(obj)); 801 return wrapType(getReifiedType(obj));
708 } 802 }
709 return JS('', '#.runtimeType', obj); 803 return JS('', '#.runtimeType', obj);
710 } 804 }
711 805
712 /// Implements Dart's interpolated strings as ES2015 tagged template literals. 806 /// Implements Dart's interpolated strings as ES2015 tagged template literals.
713 /// 807 ///
714 /// For example: dart.str`hello ${name}` 808 /// For example: dart.str`hello ${name}`
715 String str(strings, @rest values) => JS('', '''(() => { 809 String str(strings, @rest values) => JS(
810 '',
811 '''(() => {
716 let s = $strings[0]; 812 let s = $strings[0];
717 for (let i = 0, len = $values.length; i < len; ) { 813 for (let i = 0, len = $values.length; i < len; ) {
718 s += $notNull($_toString($values[i])) + $strings[++i]; 814 s += $notNull($_toString($values[i])) + $strings[++i];
719 } 815 }
720 return s; 816 return s;
721 })()'''); 817 })()''');
722 818
723 819 final JsIterator = JS(
724 final JsIterator = JS('', ''' 820 '',
821 '''
725 class JsIterator { 822 class JsIterator {
726 constructor(dartIterator) { 823 constructor(dartIterator) {
727 this.dartIterator = dartIterator; 824 this.dartIterator = dartIterator;
728 } 825 }
729 next() { 826 next() {
730 let i = this.dartIterator; 827 let i = this.dartIterator;
731 let done = !i.moveNext(); 828 let done = !i.moveNext();
732 return { done: done, value: done ? void 0 : i.current }; 829 return { done: done, value: done ? void 0 : i.current };
733 } 830 }
734 } 831 }
735 '''); 832 ''');
736 833
737 _canonicalMember(obj, name) { 834 _canonicalMember(obj, name) {
738 // Private names are symbols and are already canonical. 835 // Private names are symbols and are already canonical.
739 if (JS('bool', 'typeof # === "symbol"', name)) return name; 836 if (JS('bool', 'typeof # === "symbol"', name)) return name;
740 837
741 if (obj != null && getExtensionType(obj) != null) { 838 if (obj != null && getExtensionType(obj) != null) {
742 return JS('', 'dartx.#', name); 839 return JS('', 'dartx.#', name);
743 } 840 }
744 841
745 // Check for certain names that we can't use in JS 842 // Check for certain names that we can't use in JS
746 if (name == 'constructor' || name == 'prototype') { 843 if (name == 'constructor' || name == 'prototype') {
747 name = '+' + name; 844 name = '+' + name;
748 } 845 }
749 return name; 846 return name;
750 } 847 }
OLDNEW
« 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