| // Copyright (c) 2018, the R8 project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| package inlining; |
| |
| @NoHorizontalClassMerging |
| class Nullability { |
| private final int f; |
| public final int publicField; |
| |
| Nullability(int f) { |
| this.f = f; |
| this.publicField = f; |
| } |
| |
| int inlinable(A a) { |
| // NPE is preserved when the receiver is null. |
| return this.f + a.a(); |
| } |
| |
| int inlinableWithPublicField(A a) { |
| // NPE is preserved when the receiver is null. |
| return this.publicField + a.a(); |
| } |
| |
| int inlinableWithControlFlow(A a) { |
| // NPE is always preserved when the receiver is null. |
| return a != null ? this.f : this.publicField; |
| } |
| |
| int notInlinableDueToMissingNpe(A a) { |
| // NPE is not preserved when the receiver is null and 'a' is null. |
| return a != null ? this.f : -1; |
| } |
| |
| @KeepConstantArguments |
| int notInlinableDueToSideEffect(A a) { |
| // NPE is not preserved when the receiver is null and a is not null. |
| return a != null ? a.a() : this.f; |
| } |
| |
| int notInlinable(A a) { |
| // a.a() is still invoked even though the receiver could be null. |
| return a.a() + this.f; |
| } |
| |
| int conditionalOperator(A a) { |
| // a is not null when a.b() is invoked. |
| return a != null ? a.b() : -1; |
| } |
| |
| @NoMethodStaticizing |
| int notInlinableOnThrow(Throwable t) throws Throwable { |
| // NPE is not preserved if t is not a NullPointerException. |
| throw t; |
| } |
| |
| int notInlinableBecauseHidesNpe() { |
| try { |
| return publicField; |
| } catch (NullPointerException e) { |
| return -1; |
| } |
| } |
| |
| @NoMethodStaticizing |
| public int notInlinableDueToMissingNpeBeforeThrow(Throwable t) throws Throwable { |
| try { |
| throw t; |
| } catch (UnusedException e) { |
| return this.publicField; |
| } |
| } |
| |
| static class UnusedException extends Throwable {} |
| |
| enum Factor { |
| ONE, TWO, THREE, SIX |
| } |
| |
| int moreControlFlows(A a, Factor b) { |
| int result; |
| switch (b) { |
| case ONE: |
| result = 1; |
| break; |
| case TWO: |
| result = 2; |
| break; |
| case THREE: |
| result = 3; |
| break; |
| case SIX: |
| result = 6; |
| break; |
| default: |
| result = 0; |
| break; |
| } |
| // When reaching here, the nullability analysis should know that all possible paths do not have |
| // instructions with side effects. |
| if (a != null && result != 0) { |
| // Thus, the invocation below is the first instruction with side effect. |
| // Also, a is not null here, hence a.b() is inlinable. |
| result *= a.b(); |
| } |
| return result; |
| } |
| } |