Reapply "Avoid wrapping/unwrapping array object state"
This reverts commit 14d89c1b8dddfb1bd29870c80603ed154bdfe240.
Change-Id: Ie85593c1fef8f1a0df0383837bd2f9de3cc26736
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/StaticFieldValueAnalysis.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/StaticFieldValueAnalysis.java
index 80a4124..21c51a6 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/StaticFieldValueAnalysis.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/StaticFieldValueAnalysis.java
@@ -26,7 +26,6 @@
import com.android.tools.r8.ir.analysis.value.UnknownValue;
import com.android.tools.r8.ir.analysis.value.objectstate.EnumValuesObjectState;
import com.android.tools.r8.ir.analysis.value.objectstate.ObjectState;
-import com.android.tools.r8.ir.analysis.value.objectstate.ObjectStateAnalysis;
import com.android.tools.r8.ir.code.ArrayPut;
import com.android.tools.r8.ir.code.FieldInstruction;
import com.android.tools.r8.ir.code.IRCode;
@@ -196,7 +195,7 @@
}
return appView
.abstractValueFactory()
- .createSingleFieldValue(field.getReference(), computeObjectState(value));
+ .createSingleFieldValue(field.getReference(), value.computeObjectState(appView, context));
}
/**
@@ -352,9 +351,8 @@
// TODO(b/169050248): We could consider analysing these to answer the object state here.
return false;
}
- ObjectState objectState =
- definition.isNewInstance() ? computeObjectState(definition.outValue()) : null;
- if (objectState == null || objectState.isEmpty()) {
+ ObjectState objectState = root.computeObjectState(appView, context);
+ if (objectState.isEmpty()) {
// We need the state of all fields for the analysis to be valuable.
return false;
}
@@ -446,12 +444,8 @@
return appView
.abstractValueFactory()
- .createSingleFieldValue(enumField.getReference(), computeObjectState(value));
- }
-
- private ObjectState computeObjectState(Value value) {
- // TODO(b/204159267): Move this logic into Instruction#getAbstractValue in NewInstance.
- return ObjectStateAnalysis.computeObjectState(value, appView, context);
+ .createSingleFieldValue(
+ enumField.getReference(), value.computeObjectState(appView, context));
}
private boolean isEnumValuesArray(Value value) {
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/objectstate/ObjectStateAnalysis.java b/src/main/java/com/android/tools/r8/ir/analysis/value/objectstate/ObjectStateNewInstanceAnalysis.java
similarity index 66%
rename from src/main/java/com/android/tools/r8/ir/analysis/value/objectstate/ObjectStateAnalysis.java
rename to src/main/java/com/android/tools/r8/ir/analysis/value/objectstate/ObjectStateNewInstanceAnalysis.java
index f694589..df44057 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/objectstate/ObjectStateAnalysis.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/objectstate/ObjectStateNewInstanceAnalysis.java
@@ -7,8 +7,7 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexClassAndMethod;
import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.ir.analysis.value.AbstractValue;
-import com.android.tools.r8.ir.code.Instruction;
+import com.android.tools.r8.ir.code.AbstractValueSupplier;
import com.android.tools.r8.ir.code.InvokeDirect;
import com.android.tools.r8.ir.code.NewInstance;
import com.android.tools.r8.ir.code.Value;
@@ -16,34 +15,13 @@
import com.android.tools.r8.ir.optimize.info.field.InstanceFieldInitializationInfoCollection;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
-public class ObjectStateAnalysis {
+public class ObjectStateNewInstanceAnalysis {
- public static ObjectState computeObjectState(
- Value value, AppView<AppInfoWithLiveness> appView, ProgramMethod context) {
- Value valueRoot = value.getAliasedValue();
- if (valueRoot.isDefinedByInstructionSatisfying(
- i -> i.isNewArrayEmpty() || i.isNewArrayFilledData() || i.isNewArrayFilled())) {
- return computeNewArrayObjectState(valueRoot, appView, context);
- }
- if (valueRoot.isDefinedByInstructionSatisfying(Instruction::isNewInstance)) {
- return computeNewInstanceObjectState(valueRoot, appView, context);
- }
- return ObjectState.empty();
- }
-
- private static ObjectState computeNewArrayObjectState(
- Value value, AppView<AppInfoWithLiveness> appView, ProgramMethod context) {
- AbstractValue abstractValue = value.getAbstractValue(appView, context);
- if (abstractValue.isStatefulObjectValue()) {
- // TODO(b/204272377): Avoid wrapping and unwrapping the object state.
- return abstractValue.asStatefulObjectValue().getObjectState();
- }
- return ObjectState.empty();
- }
-
- private static ObjectState computeNewInstanceObjectState(
- Value value, AppView<AppInfoWithLiveness> appView, ProgramMethod context) {
- NewInstance newInstance = value.definition.asNewInstance();
+ public static ObjectState computeNewInstanceObjectState(
+ NewInstance newInstance,
+ AppView<AppInfoWithLiveness> appView,
+ ProgramMethod context,
+ AbstractValueSupplier abstractValueSupplier) {
InvokeDirect uniqueConstructorInvoke =
newInstance.getUniqueConstructorInvoke(appView.dexItemFactory());
if (uniqueConstructorInvoke == null) {
@@ -84,7 +62,8 @@
initializationInfo.asArgumentInitializationInfo();
Value argument =
uniqueConstructorInvoke.getArgument(argumentInitializationInfo.getArgumentIndex());
- builder.recordFieldHasValue(field, argument.getAbstractValue(appView, context));
+ builder.recordFieldHasValue(
+ field, abstractValueSupplier.getAbstractValue(argument, appView, context));
} else if (initializationInfo.isSingleValue()) {
builder.recordFieldHasValue(field, initializationInfo.asSingleValue());
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/Assume.java b/src/main/java/com/android/tools/r8/ir/code/Assume.java
index e29df9f..0a55c89 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Assume.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Assume.java
@@ -14,11 +14,13 @@
import com.android.tools.r8.ir.analysis.type.DynamicTypeWithUpperBound;
import com.android.tools.r8.ir.analysis.type.Nullability;
import com.android.tools.r8.ir.analysis.type.TypeElement;
+import com.android.tools.r8.ir.analysis.value.objectstate.ObjectState;
import com.android.tools.r8.ir.conversion.CfBuilder;
import com.android.tools.r8.ir.conversion.DexBuilder;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.lightir.LirBuilder;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
import java.util.Set;
public class Assume extends Instruction {
@@ -114,6 +116,14 @@
}
@Override
+ public ObjectState computeObjectState(
+ AppView<AppInfoWithLiveness> appView,
+ ProgramMethod context,
+ AbstractValueSupplier abstractValueSupplier) {
+ return src().computeObjectState(appView, context, abstractValueSupplier);
+ }
+
+ @Override
public boolean couldIntroduceAnAlias(AppView<?> appView, Value root) {
assert root != null && root.getType().isReferenceType();
assert outValue != null;
diff --git a/src/main/java/com/android/tools/r8/ir/code/Instruction.java b/src/main/java/com/android/tools/r8/ir/code/Instruction.java
index 565e62f..e410c59 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Instruction.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Instruction.java
@@ -25,6 +25,7 @@
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.analysis.value.objectstate.ObjectState;
import com.android.tools.r8.ir.conversion.CfBuilder;
import com.android.tools.r8.ir.conversion.DexBuilder;
import com.android.tools.r8.ir.conversion.MethodConversionOptions;
@@ -206,6 +207,13 @@
return oldOutValue;
}
+ public ObjectState computeObjectState(
+ AppView<AppInfoWithLiveness> appView,
+ ProgramMethod context,
+ AbstractValueSupplier abstractValueSupplier) {
+ return ObjectState.empty();
+ }
+
public AbstractValue getAbstractValue(
AppView<?> appView, ProgramMethod context, AbstractValueSupplier abstractValueSupplier) {
assert hasOutValue();
diff --git a/src/main/java/com/android/tools/r8/ir/code/NewArrayEmpty.java b/src/main/java/com/android/tools/r8/ir/code/NewArrayEmpty.java
index 0eb198e..de0aa46 100644
--- a/src/main/java/com/android/tools/r8/ir/code/NewArrayEmpty.java
+++ b/src/main/java/com/android/tools/r8/ir/code/NewArrayEmpty.java
@@ -18,13 +18,14 @@
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.StatefulObjectValue;
-import com.android.tools.r8.ir.analysis.value.UnknownValue;
+import com.android.tools.r8.ir.analysis.value.objectstate.ObjectState;
import com.android.tools.r8.ir.conversion.CfBuilder;
import com.android.tools.r8.ir.conversion.DexBuilder;
import com.android.tools.r8.ir.optimize.DeadCodeRemover.DeadInstructionResult;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.lightir.LirBuilder;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
public class NewArrayEmpty extends Instruction {
@@ -100,18 +101,31 @@
return sizeIfConst() < 0;
}
- @Override
- public AbstractValue getAbstractValue(
+ private ObjectState internalComputeObjectState(
AppView<?> appView, ProgramMethod context, AbstractValueSupplier abstractValueSupplier) {
if (!instructionMayHaveSideEffects(appView, context, abstractValueSupplier)
&& size().getType().isInt()) {
assert !instructionInstanceCanThrow(appView, context, abstractValueSupplier);
- return StatefulObjectValue.create(
- appView
- .abstractValueFactory()
- .createKnownLengthArrayState(size().definition.asConstNumber().getIntValue()));
+ return appView
+ .abstractValueFactory()
+ .createKnownLengthArrayState(size().definition.asConstNumber().getIntValue());
}
- return UnknownValue.getInstance();
+ return ObjectState.empty();
+ }
+
+ @Override
+ public ObjectState computeObjectState(
+ AppView<AppInfoWithLiveness> appView,
+ ProgramMethod context,
+ AbstractValueSupplier abstractValueSupplier) {
+ return internalComputeObjectState(appView, context, abstractValueSupplier);
+ }
+
+ @Override
+ public AbstractValue getAbstractValue(
+ AppView<?> appView, ProgramMethod context, AbstractValueSupplier abstractValueSupplier) {
+ return StatefulObjectValue.create(
+ internalComputeObjectState(appView, context, abstractValueSupplier));
}
@Override
diff --git a/src/main/java/com/android/tools/r8/ir/code/NewArrayFilled.java b/src/main/java/com/android/tools/r8/ir/code/NewArrayFilled.java
index bdaeb21..01855e3 100644
--- a/src/main/java/com/android/tools/r8/ir/code/NewArrayFilled.java
+++ b/src/main/java/com/android/tools/r8/ir/code/NewArrayFilled.java
@@ -21,12 +21,13 @@
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.StatefulObjectValue;
-import com.android.tools.r8.ir.analysis.value.UnknownValue;
+import com.android.tools.r8.ir.analysis.value.objectstate.ObjectState;
import com.android.tools.r8.ir.conversion.CfBuilder;
import com.android.tools.r8.ir.conversion.DexBuilder;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.lightir.LirBuilder;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
import java.util.List;
public class NewArrayFilled extends Invoke {
@@ -152,15 +153,28 @@
throw new Unreachable("InvokeNewArray (non-empty) not supported when compiling to classfiles.");
}
- @Override
- public AbstractValue getAbstractValue(
+ private ObjectState internalComputeObjectState(
AppView<?> appView, ProgramMethod context, AbstractValueSupplier abstractValueSupplier) {
if (!instructionMayHaveSideEffects(appView, context, abstractValueSupplier)) {
int size = inValues.size();
- return StatefulObjectValue.create(
- appView.abstractValueFactory().createKnownLengthArrayState(size));
+ return appView.abstractValueFactory().createKnownLengthArrayState(size);
}
- return UnknownValue.getInstance();
+ return ObjectState.empty();
+ }
+
+ @Override
+ public ObjectState computeObjectState(
+ AppView<AppInfoWithLiveness> appView,
+ ProgramMethod context,
+ AbstractValueSupplier abstractValueSupplier) {
+ return internalComputeObjectState(appView, context, abstractValueSupplier);
+ }
+
+ @Override
+ public AbstractValue getAbstractValue(
+ AppView<?> appView, ProgramMethod context, AbstractValueSupplier abstractValueSupplier) {
+ return StatefulObjectValue.create(
+ internalComputeObjectState(appView, context, abstractValueSupplier));
}
@Override
diff --git a/src/main/java/com/android/tools/r8/ir/code/NewArrayFilledData.java b/src/main/java/com/android/tools/r8/ir/code/NewArrayFilledData.java
index 33a0b7d..c2b38ed 100644
--- a/src/main/java/com/android/tools/r8/ir/code/NewArrayFilledData.java
+++ b/src/main/java/com/android/tools/r8/ir/code/NewArrayFilledData.java
@@ -12,12 +12,13 @@
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.analysis.value.AbstractValue;
import com.android.tools.r8.ir.analysis.value.StatefulObjectValue;
-import com.android.tools.r8.ir.analysis.value.UnknownValue;
+import com.android.tools.r8.ir.analysis.value.objectstate.ObjectState;
import com.android.tools.r8.ir.conversion.CfBuilder;
import com.android.tools.r8.ir.conversion.DexBuilder;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.lightir.LirBuilder;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
import java.util.Arrays;
public class NewArrayFilledData extends Instruction {
@@ -132,16 +133,29 @@
return appView.options().debug || src().getType().isNullable();
}
- @Override
- public AbstractValue getAbstractValue(
+ private ObjectState internalComputeObjectState(
AppView<?> appView, ProgramMethod context, AbstractValueSupplier abstractValueSupplier) {
if (!instructionMayHaveSideEffects(appView, context, abstractValueSupplier)
&& size <= Integer.MAX_VALUE) {
assert !instructionInstanceCanThrow(appView, context, abstractValueSupplier);
- return StatefulObjectValue.create(
- appView.abstractValueFactory().createKnownLengthArrayState((int) size));
+ return appView.abstractValueFactory().createKnownLengthArrayState((int) size);
}
- return UnknownValue.getInstance();
+ return ObjectState.empty();
+ }
+
+ @Override
+ public ObjectState computeObjectState(
+ AppView<AppInfoWithLiveness> appView,
+ ProgramMethod context,
+ AbstractValueSupplier abstractValueSupplier) {
+ return internalComputeObjectState(appView, context, abstractValueSupplier);
+ }
+
+ @Override
+ public AbstractValue getAbstractValue(
+ AppView<?> appView, ProgramMethod context, AbstractValueSupplier abstractValueSupplier) {
+ return StatefulObjectValue.create(
+ internalComputeObjectState(appView, context, abstractValueSupplier));
}
@Override
diff --git a/src/main/java/com/android/tools/r8/ir/code/NewInstance.java b/src/main/java/com/android/tools/r8/ir/code/NewInstance.java
index a3f05e0..9c6416c 100644
--- a/src/main/java/com/android/tools/r8/ir/code/NewInstance.java
+++ b/src/main/java/com/android/tools/r8/ir/code/NewInstance.java
@@ -25,6 +25,8 @@
import com.android.tools.r8.ir.analysis.VerifyTypesHelper;
import com.android.tools.r8.ir.analysis.type.Nullability;
import com.android.tools.r8.ir.analysis.type.TypeElement;
+import com.android.tools.r8.ir.analysis.value.objectstate.ObjectState;
+import com.android.tools.r8.ir.analysis.value.objectstate.ObjectStateNewInstanceAnalysis;
import com.android.tools.r8.ir.conversion.CfBuilder;
import com.android.tools.r8.ir.conversion.DexBuilder;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
@@ -245,6 +247,15 @@
}
@Override
+ public ObjectState computeObjectState(
+ AppView<AppInfoWithLiveness> appView,
+ ProgramMethod context,
+ AbstractValueSupplier abstractValueSupplier) {
+ return ObjectStateNewInstanceAnalysis.computeNewInstanceObjectState(
+ this, appView, context, abstractValueSupplier);
+ }
+
+ @Override
void internalRegisterUse(UseRegistry<?> registry, DexClassAndMethod context) {
registry.registerNewInstance(clazz);
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/Phi.java b/src/main/java/com/android/tools/r8/ir/code/Phi.java
index 7bafe1b..c59e4ca 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Phi.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Phi.java
@@ -16,10 +16,12 @@
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.analysis.type.Nullability;
import com.android.tools.r8.ir.analysis.type.TypeElement;
+import com.android.tools.r8.ir.analysis.value.objectstate.ObjectState;
import com.android.tools.r8.ir.code.BasicBlock.EdgeType;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.conversion.TypeConstraintResolver;
import com.android.tools.r8.ir.optimize.AffectedValues;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.DequeUtils;
import com.android.tools.r8.utils.ListUtils;
import com.android.tools.r8.utils.Reporter;
@@ -100,6 +102,14 @@
}
@Override
+ public ObjectState computeObjectState(
+ AppView<AppInfoWithLiveness> appView,
+ ProgramMethod context,
+ AbstractValueSupplier abstractValueSupplier) {
+ return ObjectState.empty();
+ }
+
+ @Override
public void constrainType(
ValueTypeConstraint constraint, ProgramMethod method, Reporter reporter) {
if (readType == RegisterReadType.DEBUG) {
diff --git a/src/main/java/com/android/tools/r8/ir/code/Value.java b/src/main/java/com/android/tools/r8/ir/code/Value.java
index d782e2b..0610feb 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Value.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Value.java
@@ -28,6 +28,7 @@
import com.android.tools.r8.ir.analysis.value.AbstractValue;
import com.android.tools.r8.ir.analysis.value.NumberFromIntervalValue;
import com.android.tools.r8.ir.analysis.value.UnknownValue;
+import com.android.tools.r8.ir.analysis.value.objectstate.ObjectState;
import com.android.tools.r8.ir.optimize.AffectedValues;
import com.android.tools.r8.ir.regalloc.LiveIntervals;
import com.android.tools.r8.position.MethodPosition;
@@ -879,6 +880,18 @@
return definition.isOutConstant() && !hasLocalInfo();
}
+ public final ObjectState computeObjectState(
+ AppView<AppInfoWithLiveness> appView, ProgramMethod context) {
+ return computeObjectState(appView, context, AbstractValueSupplier.shallow());
+ }
+
+ public ObjectState computeObjectState(
+ AppView<AppInfoWithLiveness> appView,
+ ProgramMethod context,
+ AbstractValueSupplier abstractValueSupplier) {
+ return definition.computeObjectState(appView, context, abstractValueSupplier);
+ }
+
public final AbstractValue getAbstractValue(AppView<?> appView, ProgramMethod context) {
return getAbstractValue(appView, context, AbstractValueSupplier.unknown());
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java b/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java
index fd48de4..415e7bf 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java
@@ -66,7 +66,6 @@
import com.android.tools.r8.ir.analysis.value.AbstractValue;
import com.android.tools.r8.ir.analysis.value.StatefulObjectValue;
import com.android.tools.r8.ir.analysis.value.objectstate.ObjectState;
-import com.android.tools.r8.ir.analysis.value.objectstate.ObjectStateAnalysis;
import com.android.tools.r8.ir.code.AbstractValueSupplier;
import com.android.tools.r8.ir.code.AliasedValueConfiguration;
import com.android.tools.r8.ir.code.Argument;
@@ -222,9 +221,7 @@
}
} else if (returnValue.getType().isReferenceType()) {
// TODO(b/204159267): Move this logic into Instruction#getAbstractValue in NewInstance.
- ObjectState objectState =
- ObjectStateAnalysis.computeObjectState(aliasedValue, appView, context);
- // TODO(b/204272377): Avoid wrapping and unwrapping the object state.
+ ObjectState objectState = aliasedValue.computeObjectState(appView, context);
feedback.methodReturnsAbstractValue(
method, appView, StatefulObjectValue.create(objectState));
}
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorCodeScanner.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorCodeScanner.java
index 5f33057..5012849 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorCodeScanner.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorCodeScanner.java
@@ -23,7 +23,6 @@
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.objectstate.ObjectState;
-import com.android.tools.r8.ir.analysis.value.objectstate.ObjectStateAnalysis;
import com.android.tools.r8.ir.code.AbstractValueSupplier;
import com.android.tools.r8.ir.code.AliasedValueConfiguration;
import com.android.tools.r8.ir.code.Argument;
@@ -373,7 +372,7 @@
if (abstractValue.isUnknown()) {
abstractValue =
getFallbackAbstractValueForField(
- field, () -> ObjectStateAnalysis.computeObjectState(value, appView, context));
+ field, () -> value.computeObjectState(appView, context));
}
if (field.getType().isClassType()) {
DynamicType dynamicType =