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

Side by Side Diff: pkg/compiler/lib/src/ssa/optimize.dart

Issue 1182913003: Split TypedSelector into Selector and TypeMask. (Closed) Base URL: https://github.com/dart-lang/sdk.git@master
Patch Set: Created 5 years, 6 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) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, 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 part of ssa; 5 part of ssa;
6 6
7 abstract class OptimizationPhase { 7 abstract class OptimizationPhase {
8 String get name; 8 String get name;
9 void visitGraph(HGraph graph); 9 void visitGraph(HGraph graph);
10 } 10 }
(...skipping 283 matching lines...) Expand 10 before | Expand all | Expand 10 after
294 : foldBinary(operation, node.inputs[1], node.inputs[2]); 294 : foldBinary(operation, node.inputs[1], node.inputs[2]);
295 if (instruction != null) return instruction; 295 if (instruction != null) return instruction;
296 } 296 }
297 297
298 // Try converting the instruction to a builtin instruction. 298 // Try converting the instruction to a builtin instruction.
299 HInstruction instruction = 299 HInstruction instruction =
300 node.specializer.tryConvertToBuiltin(node, compiler); 300 node.specializer.tryConvertToBuiltin(node, compiler);
301 if (instruction != null) return instruction; 301 if (instruction != null) return instruction;
302 302
303 Selector selector = node.selector; 303 Selector selector = node.selector;
304 TypeMask mask = node.mask;
304 HInstruction input = node.inputs[1]; 305 HInstruction input = node.inputs[1];
305 306
306 World world = compiler.world; 307 World world = compiler.world;
308
309 bool applies(Element element) {
310 return selector.applies(element, world) &&
311 (mask == null || mask.canHit(element, selector, world));
312 }
313
307 if (selector.isCall || selector.isOperator) { 314 if (selector.isCall || selector.isOperator) {
308 Element target; 315 Element target;
309 if (input.isExtendableArray(compiler)) { 316 if (input.isExtendableArray(compiler)) {
310 if (selector.applies(backend.jsArrayRemoveLast, world)) { 317 if (applies(backend.jsArrayRemoveLast)) {
311 target = backend.jsArrayRemoveLast; 318 target = backend.jsArrayRemoveLast;
312 } else if (selector.applies(backend.jsArrayAdd, world)) { 319 } else if (applies(backend.jsArrayAdd)) {
313 // The codegen special cases array calls, but does not 320 // The codegen special cases array calls, but does not
314 // inline argument type checks. 321 // inline argument type checks.
315 if (!compiler.enableTypeAssertions) { 322 if (!compiler.enableTypeAssertions) {
316 target = backend.jsArrayAdd; 323 target = backend.jsArrayAdd;
317 } 324 }
318 } 325 }
319 } else if (input.isStringOrNull(compiler)) { 326 } else if (input.isStringOrNull(compiler)) {
320 if (selector.applies(backend.jsStringSplit, world)) { 327 if (applies(backend.jsStringSplit)) {
321 HInstruction argument = node.inputs[2]; 328 HInstruction argument = node.inputs[2];
322 if (argument.isString(compiler)) { 329 if (argument.isString(compiler)) {
323 target = backend.jsStringSplit; 330 target = backend.jsStringSplit;
324 } 331 }
325 } else if (selector.applies(backend.jsStringOperatorAdd, world)) { 332 } else if (applies(backend.jsStringOperatorAdd)) {
326 // `operator+` is turned into a JavaScript '+' so we need to 333 // `operator+` is turned into a JavaScript '+' so we need to
327 // make sure the receiver and the argument are not null. 334 // make sure the receiver and the argument are not null.
328 // TODO(sra): Do this via [node.specializer]. 335 // TODO(sra): Do this via [node.specializer].
329 HInstruction argument = node.inputs[2]; 336 HInstruction argument = node.inputs[2];
330 if (argument.isString(compiler) 337 if (argument.isString(compiler)
331 && !input.canBeNull()) { 338 && !input.canBeNull()) {
332 return new HStringConcat(input, argument, null, 339 return new HStringConcat(input, argument, null,
333 node.instructionType); 340 node.instructionType);
334 } 341 }
335 } else if (selector.applies(backend.jsStringToString, world) 342 } else if (applies(backend.jsStringToString)
336 && !input.canBeNull()) { 343 && !input.canBeNull()) {
337 return input; 344 return input;
338 } 345 }
339 } 346 }
340 if (target != null) { 347 if (target != null) {
341 // TODO(ngeoffray): There is a strong dependency between codegen 348 // TODO(ngeoffray): There is a strong dependency between codegen
342 // and this optimization that the dynamic invoke does not need an 349 // and this optimization that the dynamic invoke does not need an
343 // interceptor. We currently need to keep a 350 // interceptor. We currently need to keep a
344 // HInvokeDynamicMethod and not create a HForeign because 351 // HInvokeDynamicMethod and not create a HForeign because
345 // HForeign is too opaque for the SsaCheckInserter (that adds a 352 // HForeign is too opaque for the SsaCheckInserter (that adds a
346 // bounds check on removeLast). Once we start inlining, the 353 // bounds check on removeLast). Once we start inlining, the
347 // bounds check will become explicit, so we won't need this 354 // bounds check will become explicit, so we won't need this
348 // optimization. 355 // optimization.
349 HInvokeDynamicMethod result = new HInvokeDynamicMethod( 356 HInvokeDynamicMethod result = new HInvokeDynamicMethod(
350 node.selector, node.inputs.sublist(1), node.instructionType); 357 node.selector, node.mask,
358 node.inputs.sublist(1), node.instructionType);
351 result.element = target; 359 result.element = target;
352 return result; 360 return result;
353 } 361 }
354 } else if (selector.isGetter) { 362 } else if (selector.isGetter) {
355 if (selector.asUntyped.applies(backend.jsIndexableLength, world)) { 363 if (selector.applies(backend.jsIndexableLength, world)) {
356 HInstruction optimized = tryOptimizeLengthInterceptedGetter(node); 364 HInstruction optimized = tryOptimizeLengthInterceptedGetter(node);
357 if (optimized != null) return optimized; 365 if (optimized != null) return optimized;
358 } 366 }
359 } 367 }
360 368
361 return node; 369 return node;
362 } 370 }
363 371
364 HInstruction visitInvokeDynamicMethod(HInvokeDynamicMethod node) { 372 HInstruction visitInvokeDynamicMethod(HInvokeDynamicMethod node) {
365 if (node.isInterceptedCall) { 373 if (node.isInterceptedCall) {
366 HInstruction folded = handleInterceptedCall(node); 374 HInstruction folded = handleInterceptedCall(node);
367 if (folded != node) return folded; 375 if (folded != node) return folded;
368 } 376 }
369 377
370 TypeMask receiverType = node.getDartReceiver(compiler).instructionType; 378 TypeMask receiverType = node.getDartReceiver(compiler).instructionType;
371 Selector selector = 379 Element element =
372 new TypedSelector(receiverType, node.selector, compiler.world); 380 compiler.world.locateSingleElement(node.selector, receiverType);
373 Element element = compiler.world.locateSingleElement(selector);
374 // TODO(ngeoffray): Also fold if it's a getter or variable. 381 // TODO(ngeoffray): Also fold if it's a getter or variable.
375 if (element != null 382 if (element != null
376 && element.isFunction 383 && element.isFunction
377 // If we found out that the only target is a [:noSuchMethod:], 384 // If we found out that the only target is a [:noSuchMethod:],
378 // we just ignore it. 385 // we just ignore it.
379 && element.name == selector.name) { 386 && element.name == node.selector.name) {
380 FunctionElement method = element; 387 FunctionElement method = element;
381 388
382 if (method.isNative) { 389 if (method.isNative) {
383 HInstruction folded = tryInlineNativeMethod(node, method); 390 HInstruction folded = tryInlineNativeMethod(node, method);
384 if (folded != null) return folded; 391 if (folded != null) return folded;
385 } else { 392 } else {
386 // TODO(ngeoffray): If the method has optional parameters, 393 // TODO(ngeoffray): If the method has optional parameters,
387 // we should pass the default values. 394 // we should pass the default values.
388 FunctionSignature parameters = method.functionSignature; 395 FunctionSignature parameters = method.functionSignature;
389 if (parameters.optionalParameterCount == 0 396 if (parameters.optionalParameterCount == 0 ||
390 || parameters.parameterCount == node.selector.argumentCount) { 397 parameters.parameterCount ==
398 node.selector.argumentCount) {
391 node.element = element; 399 node.element = element;
392 } 400 }
393 } 401 }
394 } 402 }
395 return node; 403 return node;
396 } 404 }
397 405
398 HInstruction tryInlineNativeMethod(HInvokeDynamicMethod node, 406 HInstruction tryInlineNativeMethod(HInvokeDynamicMethod node,
399 FunctionElement method) { 407 FunctionElement method) {
400 // Enable direct calls to a native method only if we don't run in checked 408 // Enable direct calls to a native method only if we don't run in checked
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
443 451
444 if (!canInline) return null; 452 if (!canInline) return null;
445 453
446 // Strengthen instruction type from annotations to help optimize 454 // Strengthen instruction type from annotations to help optimize
447 // dependent instructions. 455 // dependent instructions.
448 native.NativeBehavior nativeBehavior = 456 native.NativeBehavior nativeBehavior =
449 native.NativeBehavior.ofMethod(method, compiler); 457 native.NativeBehavior.ofMethod(method, compiler);
450 TypeMask returnType = 458 TypeMask returnType =
451 TypeMaskFactory.fromNativeBehavior(nativeBehavior, compiler); 459 TypeMaskFactory.fromNativeBehavior(nativeBehavior, compiler);
452 HInvokeDynamicMethod result = 460 HInvokeDynamicMethod result =
453 new HInvokeDynamicMethod(node.selector, inputs, returnType); 461 new HInvokeDynamicMethod(node.selector, node.mask, inputs, returnType);
454 result.element = method; 462 result.element = method;
455 return result; 463 return result;
456 } 464 }
457 465
458 HInstruction visitBoundsCheck(HBoundsCheck node) { 466 HInstruction visitBoundsCheck(HBoundsCheck node) {
459 HInstruction index = node.index; 467 HInstruction index = node.index;
460 if (index.isInteger(compiler)) return node; 468 if (index.isInteger(compiler)) return node;
461 if (index.isConstant()) { 469 if (index.isConstant()) {
462 HConstant constantInstruction = index; 470 HConstant constantInstruction = index;
463 assert(!constantInstruction.constant.isInt); 471 assert(!constantInstruction.constant.isInt);
(...skipping 258 matching lines...) Expand 10 before | Expand all | Expand 10 after
722 ClassWorld classWorld = compiler.world; 730 ClassWorld classWorld = compiler.world;
723 if (checkedType.containsAll(classWorld)) return node; 731 if (checkedType.containsAll(classWorld)) return node;
724 HInstruction input = node.checkedInput; 732 HInstruction input = node.checkedInput;
725 TypeMask inputType = input.instructionType; 733 TypeMask inputType = input.instructionType;
726 return inputType.isInMask(checkedType, classWorld) ? input : node; 734 return inputType.isInMask(checkedType, classWorld) ? input : node;
727 } 735 }
728 736
729 VariableElement findConcreteFieldForDynamicAccess(HInstruction receiver, 737 VariableElement findConcreteFieldForDynamicAccess(HInstruction receiver,
730 Selector selector) { 738 Selector selector) {
731 TypeMask receiverType = receiver.instructionType; 739 TypeMask receiverType = receiver.instructionType;
732 return compiler.world.locateSingleField( 740 return compiler.world.locateSingleField(selector, receiverType);
733 new TypedSelector(receiverType, selector, compiler.world));
734 } 741 }
735 742
736 HInstruction visitFieldGet(HFieldGet node) { 743 HInstruction visitFieldGet(HFieldGet node) {
737 if (node.isNullCheck) return node; 744 if (node.isNullCheck) return node;
738 var receiver = node.receiver; 745 var receiver = node.receiver;
739 if (node.element == backend.jsIndexableLength) { 746 if (node.element == backend.jsIndexableLength) {
740 JavaScriptItemCompilationContext context = work.compilationContext; 747 JavaScriptItemCompilationContext context = work.compilationContext;
741 if (context.allocatedFixedLists.contains(receiver)) { 748 if (context.allocatedFixedLists.contains(receiver)) {
742 // TODO(ngeoffray): checking if the second input is an integer 749 // TODO(ngeoffray): checking if the second input is an integer
743 // should not be necessary but it currently makes it easier for 750 // should not be necessary but it currently makes it easier for
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
795 } 802 }
796 return node; 803 return node;
797 } 804 }
798 805
799 HInstruction visitInvokeDynamicGetter(HInvokeDynamicGetter node) { 806 HInstruction visitInvokeDynamicGetter(HInvokeDynamicGetter node) {
800 if (node.isInterceptedCall) { 807 if (node.isInterceptedCall) {
801 HInstruction folded = handleInterceptedCall(node); 808 HInstruction folded = handleInterceptedCall(node);
802 if (folded != node) return folded; 809 if (folded != node) return folded;
803 } 810 }
804 HInstruction receiver = node.getDartReceiver(compiler); 811 HInstruction receiver = node.getDartReceiver(compiler);
805 Element field = findConcreteFieldForDynamicAccess(receiver, node.selector); 812 Element field = findConcreteFieldForDynamicAccess(
813 receiver, node.selector);
806 if (field == null) return node; 814 if (field == null) return node;
807 return directFieldGet(receiver, field); 815 return directFieldGet(receiver, field);
808 } 816 }
809 817
810 HInstruction directFieldGet(HInstruction receiver, Element field) { 818 HInstruction directFieldGet(HInstruction receiver, Element field) {
811 bool isAssignable = !compiler.world.fieldNeverChanges(field); 819 bool isAssignable = !compiler.world.fieldNeverChanges(field);
812 820
813 TypeMask type; 821 TypeMask type;
814 if (field.enclosingClass.isNative) { 822 if (field.enclosingClass.isNative) {
815 type = TypeMaskFactory.fromNativeBehavior( 823 type = TypeMaskFactory.fromNativeBehavior(
(...skipping 1481 matching lines...) Expand 10 before | Expand all | Expand 10 after
2297 2305
2298 keyedValues.forEach((receiver, values) { 2306 keyedValues.forEach((receiver, values) {
2299 result.keyedValues[receiver] = 2307 result.keyedValues[receiver] =
2300 new Map<HInstruction, HInstruction>.from(values); 2308 new Map<HInstruction, HInstruction>.from(values);
2301 }); 2309 });
2302 2310
2303 result.nonEscapingReceivers.addAll(nonEscapingReceivers); 2311 result.nonEscapingReceivers.addAll(nonEscapingReceivers);
2304 return result; 2312 return result;
2305 } 2313 }
2306 } 2314 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698