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

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

Powered by Google App Engine
This is Rietveld 408576698