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