|  | // 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; | 
|  | } | 
|  | } |