| // Copyright (c) 2019, 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 com.android.tools.r8.ir.optimize.info; |
| |
| import com.android.tools.r8.graph.AppInfoWithClassHierarchy; |
| import com.android.tools.r8.graph.AppView; |
| import com.android.tools.r8.graph.DexType; |
| import com.android.tools.r8.graph.GraphLens; |
| import com.android.tools.r8.ir.analysis.inlining.NeverSimpleInliningConstraint; |
| import com.android.tools.r8.ir.analysis.inlining.SimpleInliningConstraint; |
| import com.android.tools.r8.ir.analysis.type.ClassTypeElement; |
| import com.android.tools.r8.ir.analysis.type.TypeElement; |
| import com.android.tools.r8.ir.analysis.value.AbstractValue; |
| import com.android.tools.r8.ir.analysis.value.UnknownValue; |
| import com.android.tools.r8.ir.code.InvokeDirect; |
| import com.android.tools.r8.ir.optimize.classinliner.constraint.ClassInlinerMethodConstraint; |
| import com.android.tools.r8.ir.optimize.info.bridge.BridgeInfo; |
| import com.android.tools.r8.ir.optimize.info.initializer.InstanceInitializerInfo; |
| import com.android.tools.r8.ir.optimize.info.initializer.InstanceInitializerInfoCollection; |
| import com.android.tools.r8.shaking.AppInfoWithLiveness; |
| import com.android.tools.r8.utils.BooleanUtils; |
| import java.util.BitSet; |
| import java.util.Set; |
| |
| public class UpdatableMethodOptimizationInfo extends MethodOptimizationInfo { |
| |
| private Set<DexType> initializedClassesOnNormalExit = |
| DefaultMethodOptimizationInfo.UNKNOWN_INITIALIZED_CLASSES_ON_NORMAL_EXIT; |
| private int returnedArgument = DefaultMethodOptimizationInfo.UNKNOWN_RETURNED_ARGUMENT; |
| private AbstractValue abstractReturnValue = |
| DefaultMethodOptimizationInfo.UNKNOWN_ABSTRACT_RETURN_VALUE; |
| private ClassInlinerMethodConstraint classInlinerConstraint = |
| ClassInlinerMethodConstraint.alwaysFalse(); |
| private TypeElement returnsObjectWithUpperBoundType = DefaultMethodOptimizationInfo.UNKNOWN_TYPE; |
| private ClassTypeElement returnsObjectWithLowerBoundType = |
| DefaultMethodOptimizationInfo.UNKNOWN_CLASS_TYPE; |
| private InlinePreference inlining = InlinePreference.Default; |
| // Stores information about instance methods and constructors for |
| // class inliner, null value indicates that the method is not eligible. |
| private BridgeInfo bridgeInfo = null; |
| private InstanceInitializerInfoCollection instanceInitializerInfoCollection = |
| InstanceInitializerInfoCollection.empty(); |
| // Stores information about nullability hint per parameter. If set, that means, the method |
| // somehow (e.g., null check, such as arg != null, or using checkParameterIsNotNull) ensures |
| // the corresponding parameter is not null, or throws NPE before any other side effects. |
| // This info is used by {@link UninstantiatedTypeOptimization#rewriteInvoke} that replaces an |
| // invocation with null throwing code if an always-null argument is passed. Also used by Inliner |
| // to give a credit to null-safe code, e.g., Kotlin's null safe argument. |
| // Note that this bit set takes into account the receiver for instance methods. |
| private BitSet nonNullParamOrThrow = |
| DefaultMethodOptimizationInfo.NO_NULL_PARAMETER_OR_THROW_FACTS; |
| // Stores information about nullability facts per parameter. If set, that means, the method |
| // somehow (e.g., null check, such as arg != null, or NPE-throwing instructions such as array |
| // access or another invocation) ensures the corresponding parameter is not null, and that is |
| // guaranteed until the normal exits. That is, if the invocation of this method is finished |
| // normally, the recorded parameter is definitely not null. These facts are used to propagate |
| // non-null information through {@link NonNullTracker}. |
| // Note that this bit set takes into account the receiver for instance methods. |
| private BitSet nonNullParamOnNormalExits = |
| DefaultMethodOptimizationInfo.NO_NULL_PARAMETER_ON_NORMAL_EXITS_FACTS; |
| |
| private SimpleInliningConstraint simpleInliningConstraint = |
| NeverSimpleInliningConstraint.getInstance(); |
| |
| // To reduce the memory footprint of UpdatableMethodOptimizationInfo, all the boolean fields are |
| // merged into a flag int field. The various static final FLAG fields indicate which bit is |
| // used by each boolean. DEFAULT_FLAGS encodes the default value for efficient instantiation and |
| // is computed during class initialization from the default method optimization info. The |
| // methods setFlag, clearFlag and isFlagSet are used to access the booleans. |
| private static final int CANNOT_BE_KEPT_FLAG = 0x1; |
| private static final int CLASS_INITIALIZER_MAY_BE_POSTPONED_FLAG = 0x2; |
| private static final int HAS_BEEN_INLINED_INTO_SINGLE_CALL_SITE_FLAG = 0x4; |
| private static final int MAY_HAVE_SIDE_EFFECT_FLAG = 0x8; |
| private static final int RETURN_VALUE_ONLY_DEPENDS_ON_ARGUMENTS_FLAG = 0x10; |
| private static final int UNUSED_FLAG_1 = 0x20; |
| private static final int NEVER_RETURNS_NORMALLY_FLAG = 0x40; |
| private static final int UNUSED_FLAG_2 = 0x80; |
| private static final int CHECKS_NULL_RECEIVER_BEFORE_ANY_SIDE_EFFECT_FLAG = 0x100; |
| private static final int TRIGGERS_CLASS_INIT_BEFORE_ANY_SIDE_EFFECT_FLAG = 0x200; |
| private static final int INITIALIZER_ENABLING_JAVA_ASSERTIONS_FLAG = 0x400; |
| private static final int REACHABILITY_SENSITIVE_FLAG = 0x800; |
| private static final int RETURN_VALUE_HAS_BEEN_PROPAGATED_FLAG = 0x1000; |
| |
| private static final int DEFAULT_FLAGS; |
| |
| static { |
| int defaultFlags = 0; |
| MethodOptimizationInfo defaultOptInfo = DefaultMethodOptimizationInfo.DEFAULT_INSTANCE; |
| defaultFlags |= BooleanUtils.intValue(defaultOptInfo.cannotBeKept()) * CANNOT_BE_KEPT_FLAG; |
| defaultFlags |= |
| BooleanUtils.intValue(defaultOptInfo.classInitializerMayBePostponed()) |
| * CLASS_INITIALIZER_MAY_BE_POSTPONED_FLAG; |
| defaultFlags |= |
| BooleanUtils.intValue(defaultOptInfo.hasBeenInlinedIntoSingleCallSite()) |
| * HAS_BEEN_INLINED_INTO_SINGLE_CALL_SITE_FLAG; |
| defaultFlags |= |
| BooleanUtils.intValue(defaultOptInfo.mayHaveSideEffects()) * MAY_HAVE_SIDE_EFFECT_FLAG; |
| defaultFlags |= |
| BooleanUtils.intValue(defaultOptInfo.returnValueOnlyDependsOnArguments()) |
| * RETURN_VALUE_ONLY_DEPENDS_ON_ARGUMENTS_FLAG; |
| defaultFlags |= 0 * UNUSED_FLAG_1; |
| defaultFlags |= |
| BooleanUtils.intValue(defaultOptInfo.neverReturnsNormally()) * NEVER_RETURNS_NORMALLY_FLAG; |
| defaultFlags |= 0 * UNUSED_FLAG_2; |
| defaultFlags |= |
| BooleanUtils.intValue(defaultOptInfo.checksNullReceiverBeforeAnySideEffect()) |
| * CHECKS_NULL_RECEIVER_BEFORE_ANY_SIDE_EFFECT_FLAG; |
| defaultFlags |= |
| BooleanUtils.intValue(defaultOptInfo.triggersClassInitBeforeAnySideEffect()) |
| * TRIGGERS_CLASS_INIT_BEFORE_ANY_SIDE_EFFECT_FLAG; |
| defaultFlags |= |
| BooleanUtils.intValue(defaultOptInfo.isInitializerEnablingJavaVmAssertions()) |
| * INITIALIZER_ENABLING_JAVA_ASSERTIONS_FLAG; |
| defaultFlags |= |
| BooleanUtils.intValue(defaultOptInfo.isReachabilitySensitive()) |
| * REACHABILITY_SENSITIVE_FLAG; |
| defaultFlags |= |
| BooleanUtils.intValue(defaultOptInfo.returnValueHasBeenPropagated()) |
| * RETURN_VALUE_HAS_BEEN_PROPAGATED_FLAG; |
| DEFAULT_FLAGS = defaultFlags; |
| } |
| |
| private int flags = DEFAULT_FLAGS; |
| |
| UpdatableMethodOptimizationInfo() { |
| // Intentionally left empty, just use the default values. |
| } |
| |
| // Copy constructor used to create a mutable copy. Do not forget to copy from template when a new |
| // field is added. |
| private UpdatableMethodOptimizationInfo(UpdatableMethodOptimizationInfo template) { |
| flags = template.flags; |
| initializedClassesOnNormalExit = template.initializedClassesOnNormalExit; |
| returnedArgument = template.returnedArgument; |
| abstractReturnValue = template.abstractReturnValue; |
| returnsObjectWithUpperBoundType = template.returnsObjectWithUpperBoundType; |
| returnsObjectWithLowerBoundType = template.returnsObjectWithLowerBoundType; |
| inlining = template.inlining; |
| simpleInliningConstraint = template.simpleInliningConstraint; |
| bridgeInfo = template.bridgeInfo; |
| instanceInitializerInfoCollection = template.instanceInitializerInfoCollection; |
| nonNullParamOrThrow = template.nonNullParamOrThrow; |
| nonNullParamOnNormalExits = template.nonNullParamOnNormalExits; |
| } |
| |
| public UpdatableMethodOptimizationInfo fixupClassTypeReferences( |
| AppView<? extends AppInfoWithClassHierarchy> appView, GraphLens lens) { |
| if (returnsObjectWithUpperBoundType != null) { |
| returnsObjectWithUpperBoundType = |
| returnsObjectWithUpperBoundType.rewrittenWithLens(appView, lens); |
| } |
| if (returnsObjectWithLowerBoundType != null) { |
| TypeElement returnsObjectWithLowerBoundType = |
| this.returnsObjectWithLowerBoundType.rewrittenWithLens(appView, lens); |
| if (returnsObjectWithLowerBoundType.isClassType()) { |
| this.returnsObjectWithLowerBoundType = returnsObjectWithLowerBoundType.asClassType(); |
| } else { |
| assert returnsObjectWithLowerBoundType.isPrimitiveType(); |
| this.returnsObjectWithUpperBoundType = DefaultMethodOptimizationInfo.UNKNOWN_TYPE; |
| this.returnsObjectWithLowerBoundType = DefaultMethodOptimizationInfo.UNKNOWN_CLASS_TYPE; |
| } |
| } |
| return this; |
| } |
| |
| public UpdatableMethodOptimizationInfo fixupAbstractReturnValue( |
| AppView<AppInfoWithLiveness> appView, GraphLens lens) { |
| abstractReturnValue = abstractReturnValue.rewrittenWithLens(appView, lens); |
| return this; |
| } |
| |
| public UpdatableMethodOptimizationInfo fixupInstanceInitializerInfo( |
| AppView<AppInfoWithLiveness> appView, GraphLens lens) { |
| instanceInitializerInfoCollection = |
| instanceInitializerInfoCollection.rewrittenWithLens(appView, lens); |
| return this; |
| } |
| |
| private void setFlag(int flag, boolean value) { |
| if (value) { |
| setFlag(flag); |
| } else { |
| clearFlag(flag); |
| } |
| } |
| |
| private void setFlag(int flag) { |
| flags |= flag; |
| } |
| |
| private void clearFlag(int flag) { |
| flags &= ~flag; |
| } |
| |
| private boolean isFlagSet(int flag) { |
| return (flags & flag) != 0; |
| } |
| |
| @Override |
| public boolean isDefaultMethodOptimizationInfo() { |
| return false; |
| } |
| |
| @Override |
| public boolean isUpdatableMethodOptimizationInfo() { |
| return true; |
| } |
| |
| @Override |
| public UpdatableMethodOptimizationInfo asUpdatableMethodOptimizationInfo() { |
| return this; |
| } |
| |
| @Override |
| public boolean cannotBeKept() { |
| return isFlagSet(CANNOT_BE_KEPT_FLAG); |
| } |
| |
| // TODO(b/140214568): Should be package-private. |
| public void markCannotBeKept() { |
| setFlag(CANNOT_BE_KEPT_FLAG); |
| } |
| |
| @Override |
| public boolean classInitializerMayBePostponed() { |
| return isFlagSet(CLASS_INITIALIZER_MAY_BE_POSTPONED_FLAG); |
| } |
| |
| void markClassInitializerMayBePostponed() { |
| setFlag(CLASS_INITIALIZER_MAY_BE_POSTPONED_FLAG); |
| } |
| |
| @Override |
| public ClassInlinerMethodConstraint getClassInlinerMethodConstraint() { |
| return classInlinerConstraint; |
| } |
| |
| void setClassInlinerMethodConstraint(ClassInlinerMethodConstraint classInlinerConstraint) { |
| this.classInlinerConstraint = classInlinerConstraint; |
| } |
| |
| @Override |
| public TypeElement getDynamicUpperBoundType() { |
| return returnsObjectWithUpperBoundType; |
| } |
| |
| @Override |
| public ClassTypeElement getDynamicLowerBoundType() { |
| return returnsObjectWithLowerBoundType; |
| } |
| |
| @Override |
| public Set<DexType> getInitializedClassesOnNormalExit() { |
| return initializedClassesOnNormalExit; |
| } |
| |
| @Override |
| public InstanceInitializerInfo getContextInsensitiveInstanceInitializerInfo() { |
| return instanceInitializerInfoCollection.getContextInsensitive(); |
| } |
| |
| @Override |
| public InstanceInitializerInfo getInstanceInitializerInfo(InvokeDirect invoke) { |
| return instanceInitializerInfoCollection.get(invoke); |
| } |
| |
| @Override |
| public BitSet getNonNullParamOrThrow() { |
| return nonNullParamOrThrow; |
| } |
| |
| @Override |
| public BitSet getNonNullParamOnNormalExits() { |
| return nonNullParamOnNormalExits; |
| } |
| |
| @Override |
| public boolean hasBeenInlinedIntoSingleCallSite() { |
| return isFlagSet(HAS_BEEN_INLINED_INTO_SINGLE_CALL_SITE_FLAG); |
| } |
| |
| void markInlinedIntoSingleCallSite() { |
| setFlag(HAS_BEEN_INLINED_INTO_SINGLE_CALL_SITE_FLAG); |
| } |
| |
| @Override |
| public boolean isReachabilitySensitive() { |
| return isFlagSet(REACHABILITY_SENSITIVE_FLAG); |
| } |
| |
| @Override |
| public boolean returnsArgument() { |
| return returnedArgument != -1; |
| } |
| |
| @Override |
| public int getReturnedArgument() { |
| assert returnsArgument(); |
| return returnedArgument; |
| } |
| |
| @Override |
| public boolean neverReturnsNormally() { |
| return isFlagSet(NEVER_RETURNS_NORMALLY_FLAG); |
| } |
| |
| @Override |
| public BridgeInfo getBridgeInfo() { |
| return bridgeInfo; |
| } |
| |
| void setBridgeInfo(BridgeInfo bridgeInfo) { |
| this.bridgeInfo = bridgeInfo; |
| } |
| |
| @Override |
| public AbstractValue getAbstractReturnValue() { |
| return abstractReturnValue; |
| } |
| |
| @Override |
| public SimpleInliningConstraint getSimpleInliningConstraint() { |
| return simpleInliningConstraint; |
| } |
| |
| @Override |
| public boolean isInitializerEnablingJavaVmAssertions() { |
| return isFlagSet(INITIALIZER_ENABLING_JAVA_ASSERTIONS_FLAG); |
| } |
| |
| @Override |
| public boolean forceInline() { |
| return inlining == InlinePreference.ForceInline; |
| } |
| |
| @Override |
| public boolean neverInline() { |
| return inlining == InlinePreference.NeverInline; |
| } |
| |
| @Override |
| public boolean checksNullReceiverBeforeAnySideEffect() { |
| return isFlagSet(CHECKS_NULL_RECEIVER_BEFORE_ANY_SIDE_EFFECT_FLAG); |
| } |
| |
| @Override |
| public boolean triggersClassInitBeforeAnySideEffect() { |
| return isFlagSet(TRIGGERS_CLASS_INIT_BEFORE_ANY_SIDE_EFFECT_FLAG); |
| } |
| |
| @Override |
| public boolean mayHaveSideEffects() { |
| return isFlagSet(MAY_HAVE_SIDE_EFFECT_FLAG); |
| } |
| |
| @Override |
| public boolean returnValueOnlyDependsOnArguments() { |
| return isFlagSet(RETURN_VALUE_ONLY_DEPENDS_ON_ARGUMENTS_FLAG); |
| } |
| |
| void setNonNullParamOrThrow(BitSet facts) { |
| this.nonNullParamOrThrow = facts; |
| } |
| |
| void setNonNullParamOnNormalExits(BitSet facts) { |
| this.nonNullParamOnNormalExits = facts; |
| } |
| |
| public void setReachabilitySensitive(boolean reachabilitySensitive) { |
| setFlag(REACHABILITY_SENSITIVE_FLAG, reachabilitySensitive); |
| } |
| |
| void setSimpleInliningConstraint(SimpleInliningConstraint constraint) { |
| this.simpleInliningConstraint = constraint; |
| } |
| |
| void setInstanceInitializerInfoCollection( |
| InstanceInitializerInfoCollection instanceInitializerInfoCollection) { |
| this.instanceInitializerInfoCollection = instanceInitializerInfoCollection; |
| } |
| |
| void setInitializerEnablingJavaAssertions() { |
| setFlag(INITIALIZER_ENABLING_JAVA_ASSERTIONS_FLAG); |
| } |
| |
| void markInitializesClassesOnNormalExit(Set<DexType> initializedClassesOnNormalExit) { |
| this.initializedClassesOnNormalExit = initializedClassesOnNormalExit; |
| } |
| |
| void markReturnsArgument(int argument) { |
| assert argument >= 0; |
| assert returnedArgument == -1 || returnedArgument == argument; |
| returnedArgument = argument; |
| } |
| |
| void markMayNotHaveSideEffects() { |
| clearFlag(MAY_HAVE_SIDE_EFFECT_FLAG); |
| } |
| |
| void markReturnValueOnlyDependsOnArguments() { |
| setFlag(RETURN_VALUE_ONLY_DEPENDS_ON_ARGUMENTS_FLAG); |
| } |
| |
| void markNeverReturnsNormally() { |
| setFlag(NEVER_RETURNS_NORMALLY_FLAG); |
| } |
| |
| void markReturnsAbstractValue(AbstractValue value) { |
| assert !abstractReturnValue.isSingleValue() || abstractReturnValue.equals(value) |
| : "return single value changed from " + abstractReturnValue + " to " + value; |
| abstractReturnValue = value; |
| } |
| |
| void unsetAbstractReturnValue() { |
| abstractReturnValue = UnknownValue.getInstance(); |
| } |
| |
| void markReturnsObjectWithUpperBoundType(AppView<?> appView, TypeElement type) { |
| assert type != null; |
| // We may get more precise type information if the method is reprocessed (e.g., due to |
| // optimization info collected from all call sites), and hence the |
| // `returnsObjectWithUpperBoundType` is allowed to become more precise. |
| // TODO(b/142559221): non-materializable assume instructions? |
| // Nullability could be less precise, though. For example, suppose a value is known to be |
| // non-null after a safe invocation, hence recorded with the non-null variant. If that call is |
| // inlined and the method is reprocessed, such non-null assumption cannot be made again. |
| assert returnsObjectWithUpperBoundType == DefaultMethodOptimizationInfo.UNKNOWN_TYPE |
| || type.lessThanOrEqualUpToNullability(returnsObjectWithUpperBoundType, appView) |
| : "upper bound type changed from " + returnsObjectWithUpperBoundType + " to " + type; |
| returnsObjectWithUpperBoundType = type; |
| if (type.isNullType()) { |
| returnsObjectWithLowerBoundType = null; |
| } |
| } |
| |
| void markReturnsObjectWithLowerBoundType(ClassTypeElement type) { |
| assert type != null; |
| // Currently, we only have a lower bound type when we have _exact_ runtime type information. |
| // Thus, the type should never become more precise (although the nullability could). |
| assert returnsObjectWithLowerBoundType == DefaultMethodOptimizationInfo.UNKNOWN_CLASS_TYPE |
| || type.equalUpToNullability(returnsObjectWithLowerBoundType) |
| : "lower bound type changed from " + returnsObjectWithLowerBoundType + " to " + type; |
| returnsObjectWithLowerBoundType = type; |
| } |
| |
| // TODO(b/140214568): Should be package-private. |
| public void markForceInline() { |
| // For concurrent scenarios we should allow the flag to be already set |
| assert inlining == InlinePreference.Default || inlining == InlinePreference.ForceInline; |
| inlining = InlinePreference.ForceInline; |
| } |
| |
| // TODO(b/140214568): Should be package-private. |
| public void unsetForceInline() { |
| // For concurrent scenarios we should allow the flag to be already unset |
| assert inlining == InlinePreference.Default || inlining == InlinePreference.ForceInline; |
| inlining = InlinePreference.Default; |
| } |
| |
| // TODO(b/140214568): Should be package-private. |
| public void markNeverInline() { |
| // For concurrent scenarios we should allow the flag to be already set |
| assert inlining == InlinePreference.Default || inlining == InlinePreference.NeverInline; |
| inlining = InlinePreference.NeverInline; |
| } |
| |
| void markCheckNullReceiverBeforeAnySideEffect(boolean mark) { |
| setFlag(CHECKS_NULL_RECEIVER_BEFORE_ANY_SIDE_EFFECT_FLAG, mark); |
| } |
| |
| void markTriggerClassInitBeforeAnySideEffect(boolean mark) { |
| setFlag(TRIGGERS_CLASS_INIT_BEFORE_ANY_SIDE_EFFECT_FLAG, mark); |
| } |
| |
| // TODO(b/140214568): Should be package-private. |
| public void markAsPropagated() { |
| setFlag(RETURN_VALUE_HAS_BEEN_PROPAGATED_FLAG); |
| } |
| |
| @Override |
| public boolean returnValueHasBeenPropagated() { |
| return isFlagSet(RETURN_VALUE_HAS_BEEN_PROPAGATED_FLAG); |
| } |
| |
| @Override |
| public UpdatableMethodOptimizationInfo mutableCopy() { |
| return new UpdatableMethodOptimizationInfo(this); |
| } |
| |
| public void adjustOptimizationInfoAfterRemovingThisParameter() { |
| classInlinerConstraint = classInlinerConstraint.fixupAfterRemovingThisParameter(); |
| // cannotBeKept: doesn't depend on `this` |
| // classInitializerMayBePostponed: `this` could trigger <clinit> of the previous holder. |
| clearFlag(CLASS_INITIALIZER_MAY_BE_POSTPONED_FLAG); |
| // hasBeenInlinedIntoSingleCallSite: then it should not be staticized. |
| clearFlag(HAS_BEEN_INLINED_INTO_SINGLE_CALL_SITE_FLAG); |
| // initializedClassesOnNormalExit: `this` could trigger <clinit> of the previous holder. |
| initializedClassesOnNormalExit = |
| DefaultMethodOptimizationInfo.UNKNOWN_INITIALIZED_CLASSES_ON_NORMAL_EXIT; |
| // At least, `this` pointer is not used in `returnedArgument`. |
| assert returnedArgument == DefaultMethodOptimizationInfo.UNKNOWN_RETURNED_ARGUMENT |
| || returnedArgument > 0; |
| returnedArgument = |
| returnedArgument == DefaultMethodOptimizationInfo.UNKNOWN_RETURNED_ARGUMENT |
| ? DefaultMethodOptimizationInfo.UNKNOWN_RETURNED_ARGUMENT : returnedArgument - 1; |
| // mayHaveSideEffects: `this` Argument didn't have side effects, so removing it doesn't affect |
| // whether or not the method may have side effects. |
| // returnValueOnlyDependsOnArguments: |
| // if the method did before, so it does even after removing `this` Argument |
| // code is not changed, and thus the following *return* info is not changed either. |
| // * neverReturnsNull |
| // * neverReturnsNormally |
| // * constantValue |
| // * returnsObjectWithUpperBoundType |
| // * returnsObjectWithLowerBoundType |
| // inlining: it is not inlined, and thus staticized. No more chance of inlining, though. |
| inlining = InlinePreference.Default; |
| // checksNullReceiverBeforeAnySideEffect: no more receiver. |
| markCheckNullReceiverBeforeAnySideEffect( |
| DefaultMethodOptimizationInfo.UNKNOWN_CHECKS_NULL_RECEIVER_BEFORE_ANY_SIDE_EFFECT); |
| // triggersClassInitBeforeAnySideEffect: code is not changed. |
| markTriggerClassInitBeforeAnySideEffect( |
| DefaultMethodOptimizationInfo.UNKNOWN_TRIGGERS_CLASS_INIT_BEFORE_ANY_SIDE_EFFECT); |
| // initializerInfo: the computed initializer info may become invalid. |
| instanceInitializerInfoCollection = InstanceInitializerInfoCollection.empty(); |
| // initializerEnablingJavaAssertions: `this` could trigger <clinit> of the previous holder. |
| setFlag( |
| INITIALIZER_ENABLING_JAVA_ASSERTIONS_FLAG, |
| DefaultMethodOptimizationInfo.UNKNOWN_INITIALIZER_ENABLING_JAVA_ASSERTIONS); |
| nonNullParamOrThrow = |
| nonNullParamOrThrow == DefaultMethodOptimizationInfo.NO_NULL_PARAMETER_OR_THROW_FACTS |
| ? DefaultMethodOptimizationInfo.NO_NULL_PARAMETER_OR_THROW_FACTS |
| : nonNullParamOrThrow.get(1, nonNullParamOrThrow.length()); |
| nonNullParamOnNormalExits = |
| nonNullParamOnNormalExits |
| == DefaultMethodOptimizationInfo.NO_NULL_PARAMETER_ON_NORMAL_EXITS_FACTS |
| ? DefaultMethodOptimizationInfo.NO_NULL_PARAMETER_ON_NORMAL_EXITS_FACTS |
| : nonNullParamOnNormalExits.get(1, nonNullParamOnNormalExits.length()); |
| // reachabilitySensitive: doesn't depend on `this` |
| // returnValueHasBeenPropagated: doesn't depend on `this` |
| } |
| } |