Skip to content

Commit 6615100

Browse files
author
Christian Wimmer
committed
[GR-36029] [GR-36060] Fix problems in case of incompatible class changes.
PullRequest: graal/13397
2 parents f61545c + c515c45 commit 6615100

29 files changed

+446
-128
lines changed

compiler/src/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java

Lines changed: 52 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1595,6 +1595,14 @@ protected GuardingNode maybeEmitExplicitStoreCheck(ValueNode array, JavaKind ele
15951595
return emitBytecodeExceptionCheck(condition, true, BytecodeExceptionKind.ARRAY_STORE, value);
15961596
}
15971597

1598+
protected ValueNode maybeEmitIncompatibleClassChangeErrorCheck(ValueNode receiver, InvokeKind invokeKind, ResolvedJavaType referencedType) {
1599+
if (invokeKind != InvokeKind.Interface || receiver.getStackKind() != JavaKind.Object || !needsIncompatibleClassChangeErrorCheck()) {
1600+
return receiver;
1601+
}
1602+
GraalError.guarantee(referencedType != null, "Interface calls must have a referenceType");
1603+
return emitIncompatibleClassChangeCheck(receiver, referencedType);
1604+
}
1605+
15981606
@Override
15991607
public AbstractBeginNode emitBytecodeExceptionCheck(LogicNode condition, boolean passingOnTrue, BytecodeExceptionKind exceptionKind, ValueNode... arguments) {
16001608
AbstractBeginNode result = GraphBuilderContext.super.emitBytecodeExceptionCheck(condition, passingOnTrue, exceptionKind, arguments);
@@ -1664,7 +1672,7 @@ void genInvokeStatic(JavaMethod target) {
16641672
}
16651673

16661674
ValueNode[] args = frameState.popArguments(resolvedTarget.getSignature().getParameterCount(false));
1667-
Invoke invoke = appendInvoke(InvokeKind.Static, resolvedTarget, args);
1675+
Invoke invoke = appendInvoke(InvokeKind.Static, resolvedTarget, args, null);
16681676
if (invoke != null && classInit[0] != null) {
16691677
invoke.setClassInit(classInit[0]);
16701678
}
@@ -1689,7 +1697,7 @@ protected void genInvokeInterface(int cpi, int opcode) {
16891697
protected void genInvokeInterface(JavaType referencedType, JavaMethod target) {
16901698
if (callTargetIsResolved(target) && (referencedType == null || referencedType instanceof ResolvedJavaType)) {
16911699
ValueNode[] args = frameState.popArguments(target.getSignature().getParameterCount(true));
1692-
Invoke invoke = appendInvoke(InvokeKind.Interface, (ResolvedJavaMethod) target, args);
1700+
Invoke invoke = appendInvoke(InvokeKind.Interface, (ResolvedJavaMethod) target, args, (ResolvedJavaType) referencedType);
16931701
if (invoke != null) {
16941702
invoke.callTarget().setReferencedType((ResolvedJavaType) referencedType);
16951703
}
@@ -1732,7 +1740,7 @@ protected void genInvokeVirtual(ResolvedJavaMethod resolvedTarget) {
17321740
}
17331741

17341742
ValueNode[] args = frameState.popArguments(resolvedTarget.getSignature().getParameterCount(true));
1735-
appendInvoke(InvokeKind.Virtual, resolvedTarget, args);
1743+
appendInvoke(InvokeKind.Virtual, resolvedTarget, args, null);
17361744
}
17371745

17381746
private boolean genDynamicInvokeHelper(ResolvedJavaMethod target, int cpi, int opcode) {
@@ -1751,9 +1759,9 @@ private boolean genDynamicInvokeHelper(ResolvedJavaMethod target, int cpi, int o
17511759
boolean hasReceiver = (opcode == INVOKEDYNAMIC) ? false : !target.isStatic();
17521760
ValueNode[] args = frameState.popArguments(target.getSignature().getParameterCount(hasReceiver));
17531761
if (hasReceiver) {
1754-
appendInvoke(InvokeKind.Virtual, target, args);
1762+
appendInvoke(InvokeKind.Virtual, target, args, null);
17551763
} else {
1756-
appendInvoke(InvokeKind.Static, target, args);
1764+
appendInvoke(InvokeKind.Static, target, args, null);
17571765
}
17581766

17591767
return true;
@@ -1769,7 +1777,7 @@ void genInvokeSpecial(JavaMethod target) {
17691777
assert target != null;
17701778
assert target.getSignature() != null;
17711779
ValueNode[] args = frameState.popArguments(target.getSignature().getParameterCount(true));
1772-
appendInvoke(InvokeKind.Special, (ResolvedJavaMethod) target, args);
1780+
appendInvoke(InvokeKind.Special, (ResolvedJavaMethod) target, args, null);
17731781
} else {
17741782
handleUnresolvedInvoke(target, InvokeKind.Special);
17751783
}
@@ -1816,11 +1824,16 @@ public JavaType getInvokeReturnType() {
18161824

18171825
@Override
18181826
public Invoke handleReplacedInvoke(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] args, boolean inlineEverything) {
1827+
GraalError.guarantee(invokeKind != InvokeKind.Interface, "Interface invoke needs a referencedType");
1828+
return handleReplacedInvoke(invokeKind, targetMethod, args, inlineEverything, null);
1829+
}
1830+
1831+
public Invoke handleReplacedInvoke(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] args, boolean inlineEverything, ResolvedJavaType referencedType) {
18191832
boolean previous = forceInliningEverything;
18201833
forceInliningEverything = previous || inlineEverything;
18211834
try {
18221835
setBciCanBeDuplicated(true);
1823-
return appendInvoke(invokeKind, targetMethod, args);
1836+
return appendInvoke(invokeKind, targetMethod, args, referencedType);
18241837
} finally {
18251838
setBciCanBeDuplicated(false);
18261839
forceInliningEverything = previous;
@@ -1834,7 +1847,20 @@ public void handleReplacedInvoke(CallTargetNode callTarget, JavaKind resultType)
18341847
createNonInlinedInvoke(exceptionEdgeAction, bci(), callTarget, resultType);
18351848
}
18361849

1837-
protected Invoke appendInvoke(InvokeKind initialInvokeKind, ResolvedJavaMethod initialTargetMethod, ValueNode[] args) {
1850+
protected Invoke appendInvoke(InvokeKind initialInvokeKind, ResolvedJavaMethod initialTargetMethod, ValueNode[] args, ResolvedJavaType referencedType) {
1851+
if (!parsingIntrinsic() && DeoptALot.getValue(options)) {
1852+
append(new DeoptimizeNode(DeoptimizationAction.None, RuntimeConstraint));
1853+
JavaKind resultType = initialTargetMethod.getSignature().getReturnKind();
1854+
frameState.pushReturn(resultType, ConstantNode.defaultForKind(resultType, graph));
1855+
return null;
1856+
}
1857+
1858+
if (initialInvokeKind.hasReceiver()) {
1859+
args[0] = maybeEmitExplicitNullCheck(args[0]);
1860+
/* This check must be done before any de-virtualization of the invoke. */
1861+
args[0] = maybeEmitIncompatibleClassChangeErrorCheck(args[0], initialInvokeKind, referencedType);
1862+
}
1863+
18381864
ResolvedJavaMethod targetMethod = initialTargetMethod;
18391865
InvokeKind invokeKind = initialInvokeKind;
18401866
if (initialInvokeKind.isIndirect()) {
@@ -1847,16 +1873,7 @@ protected Invoke appendInvoke(InvokeKind initialInvokeKind, ResolvedJavaMethod i
18471873
}
18481874

18491875
JavaKind resultType = targetMethod.getSignature().getReturnKind();
1850-
if (!parsingIntrinsic() && DeoptALot.getValue(options)) {
1851-
append(new DeoptimizeNode(DeoptimizationAction.None, RuntimeConstraint));
1852-
frameState.pushReturn(resultType, ConstantNode.defaultForKind(resultType, graph));
1853-
return null;
1854-
}
1855-
18561876
JavaType returnType = maybeEagerlyResolve(targetMethod.getSignature().getReturnType(method.getDeclaringClass()), targetMethod.getDeclaringClass());
1857-
if (invokeKind.hasReceiver()) {
1858-
args[0] = maybeEmitExplicitNullCheck(args[0]);
1859-
}
18601877

18611878
if (initialInvokeKind == InvokeKind.Special && !targetMethod.isConstructor()) {
18621879
emitCheckForInvokeSuperSpecial(args);
@@ -1956,11 +1973,7 @@ protected Invoke appendInvoke(InvokeKind initialInvokeKind, ResolvedJavaMethod i
19561973
* declared in a interface
19571974
*/
19581975
private void emitCheckForDeclaringClassChange(ResolvedJavaType declaringClass, ValueNode[] args) {
1959-
ValueNode receiver = args[0];
1960-
TypeReference checkedType = TypeReference.createTrusted(graph.getAssumptions(), declaringClass);
1961-
LogicNode condition = genUnique(createInstanceOf(checkedType, receiver, null));
1962-
FixedGuardNode fixedGuard = append(new FixedGuardNode(condition, ClassCastException, None, false));
1963-
args[0] = append(PiNode.create(receiver, StampFactory.object(checkedType, true), fixedGuard));
1976+
args[0] = emitIncompatibleClassChangeCheck(args[0], declaringClass);
19641977
}
19651978

19661979
/**
@@ -1977,14 +1990,22 @@ protected void emitCheckForInvokeSuperSpecial(ValueNode[] args) {
19771990
ResolvedJavaType callingClass = method.getDeclaringClass();
19781991
callingClass = getHostClass(callingClass);
19791992
if (callingClass.isInterface()) {
1980-
ValueNode receiver = args[0];
1981-
TypeReference checkedType = TypeReference.createTrusted(graph.getAssumptions(), callingClass);
1982-
LogicNode condition = genUnique(createInstanceOf(checkedType, receiver, null));
1983-
FixedGuardNode fixedGuard = append(new FixedGuardNode(condition, ClassCastException, None, false));
1984-
args[0] = append(PiNode.create(receiver, StampFactory.object(checkedType, true), fixedGuard));
1993+
args[0] = emitIncompatibleClassChangeCheck(args[0], callingClass);
19851994
}
19861995
}
19871996

1997+
protected ValueNode emitIncompatibleClassChangeCheck(ValueNode object, ResolvedJavaType checkedType) {
1998+
TypeReference checkedTypeRef = TypeReference.createTrusted(graph.getAssumptions(), checkedType);
1999+
LogicNode condition = genUnique(InstanceOfNode.create(checkedTypeRef, object));
2000+
ValueNode guardingNode;
2001+
if (needsExplicitException()) {
2002+
guardingNode = emitBytecodeExceptionCheck(condition, true, BytecodeExceptionKind.INCOMPATIBLE_CLASS_CHANGE);
2003+
} else {
2004+
guardingNode = append(new FixedGuardNode(condition, ClassCastException, None, false));
2005+
}
2006+
return append(PiNode.create(object, StampFactory.object(checkedTypeRef, true), guardingNode));
2007+
}
2008+
19882009
@SuppressWarnings("deprecation")
19892010
private static ResolvedJavaType getHostClass(ResolvedJavaType type) {
19902011
ResolvedJavaType hostClass = type.getHostClass();
@@ -4723,6 +4744,10 @@ protected boolean needsExplicitStoreCheckException(ValueNode array, ValueNode va
47234744
return needsExplicitException();
47244745
}
47254746

4747+
protected boolean needsIncompatibleClassChangeErrorCheck() {
4748+
return false;
4749+
}
4750+
47264751
@Override
47274752
public boolean needsExplicitException() {
47284753
BytecodeExceptionMode exceptionMode = graphBuilderConfig.getBytecodeExceptionMode();

compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/BytecodeExceptionNode.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,11 @@ public enum BytecodeExceptionKind {
101101
*/
102102
ARRAY_STORE(1, ArrayStoreException.class),
103103

104+
/**
105+
* Represents a {@link IncompatibleClassChangeError}. No arguments are allowed.
106+
*/
107+
INCOMPATIBLE_CLASS_CHANGE(0, IncompatibleClassChangeError.class),
108+
104109
/** Represents a {@link AssertionError} without arguments. */
105110
ASSERTION_ERROR_NULLARY(0, AssertionError.class),
106111

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/BigBang.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,4 +129,9 @@ default void onTypeInitialized(AnalysisType type) {
129129
default void afterAnalysis() {
130130

131131
}
132+
133+
@SuppressWarnings("unused")
134+
default AnalysisMethod fallbackResolveConcreteMethod(AnalysisType resolvingType, AnalysisMethod method) {
135+
return null;
136+
}
132137
}

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/AccessFieldTypeFlow.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ public abstract class AccessFieldTypeFlow extends TypeFlow<BytecodePosition> {
3838

3939
protected AccessFieldTypeFlow(BytecodePosition accessLocation, AnalysisField field) {
4040
/* The declared type of a field access node is the field declared type. */
41-
super(accessLocation, field.getType());
41+
super(accessLocation, filterUncheckedInterface(field.getType()));
4242
this.field = field;
4343
}
4444

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/ActualParameterTypeFlow.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
*/
3535
public class ActualParameterTypeFlow extends TypeFlow<ValueNode> {
3636
public ActualParameterTypeFlow(AnalysisType declaredType) {
37-
super(null, declaredType);
37+
super(null, filterUncheckedInterface(declaredType));
3838
}
3939

4040
@Override

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/ActualReturnTypeFlow.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,11 @@ public class ActualReturnTypeFlow extends TypeFlow<BytecodePosition> {
3333
private InvokeTypeFlow invokeFlow;
3434

3535
public ActualReturnTypeFlow(AnalysisType declaredType) {
36-
super(null, declaredType);
36+
this(null, declaredType);
3737
}
3838

3939
public ActualReturnTypeFlow(BytecodePosition source, AnalysisType declaredType) {
40-
super(source, declaredType);
40+
super(source, filterUncheckedInterface(declaredType));
4141
}
4242

4343
public ActualReturnTypeFlow(ActualReturnTypeFlow original, MethodFlowsGraph methodFlows) {

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/FieldTypeFlow.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ private static TypeState initialFieldState(AnalysisField field) {
6161
private volatile FieldFilterTypeFlow filterFlow;
6262

6363
public FieldTypeFlow(AnalysisField field, AnalysisType type) {
64-
super(field, type, initialFieldState(field));
64+
super(field, filterUncheckedInterface(type), initialFieldState(field));
6565
}
6666

6767
public FieldTypeFlow(AnalysisField field, AnalysisType type, AnalysisObject object) {

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/FormalParamTypeFlow.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ public class FormalParamTypeFlow extends TypeFlow<BytecodePosition> {
3838
protected final int position;
3939

4040
public FormalParamTypeFlow(BytecodePosition sourcePosition, AnalysisType declaredType, int position) {
41-
super(sourcePosition, declaredType);
41+
super(sourcePosition, filterUncheckedInterface(declaredType));
4242
this.position = position;
4343
}
4444

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/FormalReturnTypeFlow.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131

3232
public class FormalReturnTypeFlow extends TypeFlow<BytecodePosition> {
3333
public FormalReturnTypeFlow(BytecodePosition source, AnalysisType declaredType) {
34-
super(source, declaredType);
34+
super(source, filterUncheckedInterface(declaredType));
3535
}
3636

3737
public FormalReturnTypeFlow(FormalReturnTypeFlow original, MethodFlowsGraph methodFlows) {

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/OffsetLoadTypeFlow.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ public String toString() {
144144
public abstract static class AbstractUnsafeLoadTypeFlow extends OffsetLoadTypeFlow {
145145

146146
AbstractUnsafeLoadTypeFlow(BytecodePosition loadLocation, AnalysisType objectType, AnalysisType componentType, TypeFlow<?> objectFlow) {
147-
super(loadLocation, objectType, componentType, objectFlow);
147+
super(loadLocation, objectType, filterUncheckedInterface(componentType), objectFlow);
148148
}
149149

150150
AbstractUnsafeLoadTypeFlow(PointsToAnalysis bb, MethodFlowsGraph methodFlows, AbstractUnsafeLoadTypeFlow original) {

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/OffsetStoreTypeFlow.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ public String toString() {
183183
public abstract static class AbstractUnsafeStoreTypeFlow extends OffsetStoreTypeFlow {
184184

185185
AbstractUnsafeStoreTypeFlow(BytecodePosition storeLocation, AnalysisType objectType, AnalysisType componentType, TypeFlow<?> objectFlow, TypeFlow<?> valueFlow) {
186-
super(storeLocation, objectType, componentType, objectFlow, valueFlow);
186+
super(storeLocation, objectType, filterUncheckedInterface(componentType), objectFlow, valueFlow);
187187
}
188188

189189
AbstractUnsafeStoreTypeFlow(PointsToAnalysis bb, MethodFlowsGraph methodFlows, OffsetStoreTypeFlow original) {

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/TypeFlow.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -568,6 +568,28 @@ public TypeState declaredTypeFilter(PointsToAnalysis bb, TypeState newState) {
568568
return TypeState.forIntersection(bb, newState, declaredType.getAssignableTypes(true));
569569
}
570570

571+
/**
572+
* In Java, interface types are not checked by the bytecode verifier. So even when, e.g., a
573+
* method parameter has the declared type Comparable, any Object can be passed in. We therefore
574+
* need to filter out interface types, as well as arrays of interface types, in many places
575+
* where we use the declared type.
576+
*
577+
* Places where interface types need to be filtered: method parameters, method return values,
578+
* and field loads (including unsafe memory loads).
579+
*
580+
* Places where interface types need not be filtered: array element loads (because all array
581+
* stores have an array store check).
582+
*/
583+
public static AnalysisType filterUncheckedInterface(AnalysisType type) {
584+
if (type != null) {
585+
AnalysisType elementalType = type.getElementalType();
586+
if (elementalType.isInterface()) {
587+
return type.getUniverse().objectType().getArrayClass(type.getArrayDimension());
588+
}
589+
}
590+
return type;
591+
}
592+
571593
public void update(PointsToAnalysis bb) {
572594
TypeState curState = getState();
573595
for (TypeFlow<?> use : getUses()) {

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisType.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,10 @@ public AnalysisType getArrayClass(int dim) {
318318
return result;
319319
}
320320

321+
public int getArrayDimension() {
322+
return dimension;
323+
}
324+
321325
public void cleanupAfterAnalysis() {
322326
instantiatedTypes = null;
323327
instantiatedTypesNonNull = null;
@@ -1015,7 +1019,7 @@ public AnalysisType getComponentType() {
10151019
}
10161020

10171021
@Override
1018-
public ResolvedJavaType getElementalType() {
1022+
public AnalysisType getElementalType() {
10191023
return elementalType;
10201024
}
10211025

@@ -1046,6 +1050,9 @@ public AnalysisMethod resolveConcreteMethod(ResolvedJavaMethod method, ResolvedJ
10461050
ResolvedJavaType substCallerType = substMethod.getDeclaringClass();
10471051

10481052
Object newResolvedMethod = universe.lookup(wrapped.resolveConcreteMethod(substMethod, substCallerType));
1053+
if (newResolvedMethod == null) {
1054+
newResolvedMethod = getUniverse().getBigbang().fallbackResolveConcreteMethod(this, (AnalysisMethod) method);
1055+
}
10491056
if (newResolvedMethod == null) {
10501057
newResolvedMethod = NULL_METHOD;
10511058
}
@@ -1254,7 +1261,7 @@ public ResolvedJavaType getHostClass() {
12541261
return universe.lookup(wrapped.getHostClass());
12551262
}
12561263

1257-
AnalysisUniverse getUniverse() {
1264+
public AnalysisUniverse getUniverse() {
12581265
return universe;
12591266
}
12601267

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/reports/ObjectTreePrinter.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -434,7 +434,7 @@ static class WorkListEntry {
434434
}
435435

436436
private boolean suppressType(AnalysisType type) {
437-
AnalysisType elementalType = (AnalysisType) type.getElementalType();
437+
AnalysisType elementalType = type.getElementalType();
438438
String elementalTypeName = elementalType.toJavaName(true);
439439

440440
if (expandTypeMatcher.matches(elementalTypeName)) {

0 commit comments

Comments
 (0)