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

Side by Side Diff: pkg/compiler/lib/src/cps_ir/insert_refinements.dart

Issue 1571953002: cps_ir: add refinement on "success" arguments for a set of whitelisted methods (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 years, 11 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 | « no previous file | tests/compiler/dart2js/js_backend_cps_ir.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 library cps_ir.optimization.insert_refinements; 5 library cps_ir.optimization.insert_refinements;
6 6
7 import 'optimizers.dart' show Pass; 7 import 'optimizers.dart' show Pass;
8 import 'cps_ir_nodes.dart'; 8 import 'cps_ir_nodes.dart';
9 import '../elements/elements.dart';
9 import '../common/names.dart'; 10 import '../common/names.dart';
10 import '../types/types.dart' show TypeMask; 11 import '../types/types.dart' show TypeMask;
12 import '../universe/selector.dart';
11 import 'type_mask_system.dart'; 13 import 'type_mask_system.dart';
12 14
13 /// Inserts [Refinement] nodes in the IR to allow for sparse path-sensitive 15 /// Inserts [Refinement] nodes in the IR to allow for sparse path-sensitive
14 /// type analysis in the [TypePropagator] pass. 16 /// type analysis in the [TypePropagator] pass.
15 /// 17 ///
16 /// Refinement nodes are inserted at the arms of a [Branch] node with a 18 /// Refinement nodes are inserted at the arms of a [Branch] node with a
17 /// condition of form `x is T` or `x == null`. 19 /// condition of form `x is T` or `x == null`.
18 /// 20 ///
19 /// Refinement nodes are inserted after a method invocation to refine the 21 /// Refinement nodes are inserted after a method invocation to refine the
20 /// receiver to the types that can respond to the given selector. 22 /// receiver to the types that can respond to the given selector.
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
97 99
98 /// Enqueues [cont] for processing in a context where [refined] is the 100 /// Enqueues [cont] for processing in a context where [refined] is the
99 /// current refinement for its value. 101 /// current refinement for its value.
100 void pushRefinement(Continuation cont, Refinement refined) { 102 void pushRefinement(Continuation cont, Refinement refined) {
101 pushAction(() { 103 pushAction(() {
102 applyRefinement(cont, refined); 104 applyRefinement(cont, refined);
103 push(cont); 105 push(cont);
104 }); 106 });
105 } 107 }
106 108
109 /// Refine the type of each argument on [node] according to the provided
110 /// type masks.
111 void _refineArguments(
112 InvocationPrimitive node, List<TypeMask> argumentSuccessTypes) {
asgerf 2016/01/11 16:33:11 I think the dartArgument method from InvokeMethod
Siggi Cherem (dart-lang) 2016/01/11 18:45:37 good idea. done
113 if (argumentSuccessTypes == null) return;
114 int offset = (node.callingConvention == CallingConvention.Intercepted ||
115 node.callingConvention == CallingConvention.Intercepted) ? 1 : 0;
asgerf 2016/01/11 16:33:11 It looks like you have two identical conditions wi
Siggi Cherem (dart-lang) 2016/01/11 18:45:36 This was meant to be DummyIntercepted, bad copy pa
116
117 for (int i = 0; i < argumentSuccessTypes.length; i++) {
118 TypeMask argSuccessType = argumentSuccessTypes[i];
119 // Skip arguments that provide no refinement or optional arguments
120 // that were not passed.
121 if (argSuccessType == types.dynamicType) continue;
122 if (i + offset >= node.arguments.length) continue;
asgerf 2016/01/11 16:33:11 continue -> break
Siggi Cherem (dart-lang) 2016/01/11 18:45:36 Done.
123
124 applyRefinement(node.parent, new Refinement(
125 node.arguments[i + offset].definition, argSuccessType));
126 }
127 }
128
129 void visitInvokeStatic(InvokeStatic node) {
130 _refineArguments(node,
131 _getSuccessTypesForStaticMethod(types, node.target));
132 }
133
107 void visitInvokeMethod(InvokeMethod node) { 134 void visitInvokeMethod(InvokeMethod node) {
108 // Update references to their current refined values. 135 // Update references to their current refined values.
109 processReference(node.receiver); 136 processReference(node.receiver);
110 node.arguments.forEach(processReference); 137 node.arguments.forEach(processReference);
111 138
112 // If the call is intercepted, we want to refine the actual receiver, 139 // If the call is intercepted, we want to refine the actual receiver,
113 // not the interceptor. 140 // not the interceptor.
114 Primitive receiver = unfoldInterceptor(node.receiver.definition); 141 Primitive receiver = unfoldInterceptor(node.receiver.definition);
115 142
116 // Do not try to refine the receiver of closure calls; the class world 143 // Do not try to refine the receiver of closure calls; the class world
117 // does not know about closure classes. 144 // does not know about closure classes.
118 if (!node.selector.isClosureCall) { 145 Selector selector = node.selector;
146 if (!selector.isClosureCall) {
119 // Filter away receivers that throw on this selector. 147 // Filter away receivers that throw on this selector.
120 TypeMask type = types.receiverTypeFor(node.selector, node.mask); 148 TypeMask type = types.receiverTypeFor(selector, node.mask);
121 Refinement refinement = new Refinement(receiver, type); 149 Refinement refinement = new Refinement(receiver, type);
122 LetPrim letPrim = node.parent; 150 LetPrim letPrim = node.parent;
123 applyRefinement(letPrim, refinement); 151 applyRefinement(letPrim, refinement);
152
153 // Refine arguments of methods on numbers which we know will throw on
154 // invalid argument values.
155 _refineArguments(node,
156 _getSuccessTypesForInstanceMethod(types, type, selector));
124 } 157 }
125 } 158 }
126 159
127 void visitTypeCast(TypeCast node) { 160 void visitTypeCast(TypeCast node) {
128 Primitive value = node.value.definition; 161 Primitive value = node.value.definition;
129 162
130 processReference(node.value); 163 processReference(node.value);
131 node.typeArguments.forEach(processReference); 164 node.typeArguments.forEach(processReference);
132 165
133 // Refine the type of the input. 166 // Refine the type of the input.
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
226 Expression traverseLetCont(LetCont node) { 259 Expression traverseLetCont(LetCont node) {
227 for (Continuation cont in node.continuations) { 260 for (Continuation cont in node.continuations) {
228 // Do not push the branch continuations here. visitBranch will do that. 261 // Do not push the branch continuations here. visitBranch will do that.
229 if (!(cont.hasExactlyOneUse && cont.firstRef.parent is Branch)) { 262 if (!(cont.hasExactlyOneUse && cont.firstRef.parent is Branch)) {
230 push(cont); 263 push(cont);
231 } 264 }
232 } 265 }
233 return node.body; 266 return node.body;
234 } 267 }
235 } 268 }
269
270 // TODO(sigmund): ideally this whitelist information should be stored as
271 // metadata annotations on the runtime libraries so we can keep it in sync with
272 // the implementation more easily.
273 // TODO(sigmund): add support for constructors.
274 // TODO(sigmund): add checks for RegExp and DateTime (currently not exposed as
275 // easily in TypeMaskSystem).
276 // TODO(sigmund): after the above TODOs are fixed, add:
277 // ctor JSArray.fixed: [types.uint32Type],
278 // ctor JSArray.growable: [types.uintType],
279 // ctor DateTime': [int, int, int, int, int, int, int],
280 // ctor DateTime.utc': [int, int, int, int, int, int, int],
281 // ctor DateTime._internal': [int, int, int, int, int, int, int, bool],
282 // ctor RegExp': [string, dynamic, dynamic],
283 // method RegExp.allMatches: [string, int],
284 // method RegExp.firstMatch: [string],
285 // method RegExp.hasMatch: [string],
286 _getSuccessTypesForInstanceMethod(
287 TypeMaskSystem types, TypeMask receiver, Selector selector) {
asgerf 2016/01/11 16:33:11 Add a return type please.
Siggi Cherem (dart-lang) 2016/01/11 18:45:36 Done.
288 if (types.isDefinitelyInt(receiver)) {
289 switch (selector.name) {
290 case 'toSigned':
291 case 'toUnsigned':
292 case 'modInverse':
293 case 'gcd':
294 return [types.intType];
295
296 case 'modPow':
297 return [types.intType, types.intType];
298 }
299 // Note: num methods on int values are handled below.
300 }
301
302 if (types.isDefinitelyNum(receiver)) {
303 switch (selector.name) {
304 case 'clamp':
305 return [types.numType, types.numType];
306 case 'toStringAsFixed':
307 case 'toStringAsPrecision':
308 case 'toRadixString':
309 return [types.intType];
310 case 'toStringAsExponential':
311 return [types.intType.nullable()];
312 case 'compareTo':
313 case 'remainder':
314 case '+':
315 case '-':
316 case '/':
317 case '*':
318 case '%':
319 case '~/':
320 case '<<':
321 case '>>':
322 case '&':
323 case '|':
324 case '^':
325 case '<':
326 case '>':
327 case '<=':
328 case '>=':
329 return [types.numType];
330 default:
331 return null;
332 }
333 }
334
335 if (types.isDefinitelyString(receiver)) {
336 switch (selector.name) {
337 case 'allMatches':
338 return [types.stringType, types.intType];
339 case 'endsWith':
340 return [types.stringType];
341 case 'replaceAll':
342 return [types.dynamicType, types.stringType];
343 case 'replaceFirst':
344 return [types.dynamicType, types.stringType, types.intType];
345 case 'replaceFirstMapped':
346 return [
347 types.dynamicType,
348 types.dynamicType.nonNullable(),
349 types.intType
350 ];
351 case 'split':
352 return [types.dynamicType.nonNullable()];
353 case 'replaceRange':
354 return [types.intType, types.intType, types.stringType];
355 case 'startsWith':
356 return [types.dynamicType, types.intType];
357 case 'substring':
358 return [types.intType, types.uintType.nullable()];
359 case 'indexOf':
360 return [types.dynamicType.nonNullable(), types.uintType];
361 case 'lastIndexOf':
362 return [types.dynamicType.nonNullable(), types.uintType.nullable()];
363 case 'contains':
364 return [
365 types.dynamicType.nonNullable(),
366 // TODO(sigmund): update runtime to add check for int?
367 types.dynamicType
368 ];
369 case 'codeUnitAt':
370 return [types.uintType];
371 case '+':
372 return [types.stringType];
373 case '*':
374 return [types.uint32Type];
375 case '[]':
376 return [types.uintType];
377 default:
378 return null;
379 }
380 }
381
382 if (types.isDefinitelyArray(receiver)) {
383 switch (selector.name) {
384 case 'removeAt':
385 case 'insert':
386 return [types.uintType];
387 case 'sublist':
388 return [types.uintType, types.uintType.nullable()];
389 case 'length':
390 return selector.isSetter ? [types.uintType] : null;
391 case '[]':
392 case '[]=':
393 return [types.uintType];
394 default:
395 return null;
396 }
397 }
398 return null;
399 }
400
401 _getSuccessTypesForStaticMethod(TypeMaskSystem types, FunctionElement target) {
402 var lib = target.library;
403 if (lib.isDartCore) {
404 var cls = target.enclosingClass?.name;
405 if (cls == 'int' && target.name == 'parse') {
406 // source, onError, radix
407 return [types.stringType, types.dynamicType, types.uint31Type.nullable()];
408 } else if (cls == 'double' && target.name == 'parse') {
409 return [types.stringType, types.dynamicType];
410 }
411 }
412
413 if (lib.isPlatformLibrary && '${lib.canonicalUri}' == 'dart:math') {
414 switch(target.name) {
415 case 'sqrt':
416 case 'sin':
417 case 'cos':
418 case 'tan':
419 case 'acos':
420 case 'asin':
421 case 'atan':
422 case 'atan2':
423 case 'exp':
424 case 'log':
425 return [types.numType];
426 case 'pow':
427 return [types.numType, types.numType];
428 }
429 }
430
431 return null;
432 }
OLDNEW
« no previous file with comments | « no previous file | tests/compiler/dart2js/js_backend_cps_ir.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698