Skip to content

Commit 7ff5967

Browse files
committed
[GR-54734]Avoid using ClassCastExceptions as control flow in ToEspresso/ToReference nodes.
PullRequest: graal/18535
2 parents 45ff084 + c4579fd commit 7ff5967

File tree

3 files changed

+222
-187
lines changed

3 files changed

+222
-187
lines changed

espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/interop/LookupProxyKlassNode.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ public abstract class LookupProxyKlassNode extends EspressoNode {
5050
LookupProxyKlassNode() {
5151
}
5252

53-
public abstract WrappedProxyKlass execute(Object metaObject, String metaName, Klass targetType) throws ClassCastException;
53+
public abstract WrappedProxyKlass execute(Object metaObject, String metaName, Klass targetType);
5454

5555
@SuppressWarnings("unused")
5656
@Specialization(guards = {"targetType == cachedTargetType", "cachedMetaName.equals(metaName)"}, limit = "LIMIT")
@@ -59,14 +59,14 @@ WrappedProxyKlass doCached(Object metaObject, String metaName, Klass targetType,
5959
@Cached("targetType") Klass cachedTargetType,
6060
@CachedLibrary(limit = "LIMIT") InteropLibrary interop,
6161
@Cached("metaName") String cachedMetaName,
62-
@Cached("doUncached(metaObject, metaName, targetType, interop)") WrappedProxyKlass cachedProxyKlass) throws ClassCastException {
62+
@Cached("doUncached(metaObject, metaName, targetType, interop)") WrappedProxyKlass cachedProxyKlass) {
6363
return cachedProxyKlass;
6464
}
6565

6666
@TruffleBoundary
6767
@Specialization(replaces = "doCached")
6868
WrappedProxyKlass doUncached(Object metaObject, String metaName, Klass targetType,
69-
@CachedLibrary(limit = "LIMIT") InteropLibrary interop) throws ClassCastException {
69+
@CachedLibrary(limit = "LIMIT") InteropLibrary interop) {
7070
if (!getContext().interfaceMappingsEnabled()) {
7171
return null;
7272
}
@@ -79,18 +79,18 @@ WrappedProxyKlass doUncached(Object metaObject, String metaName, Klass targetTyp
7979
if (parentInterfaces.isEmpty()) {
8080
if (superKlass != getMeta().java_lang_Object) {
8181
if (!targetType.isAssignableFrom(superKlass)) {
82-
throw new ClassCastException("super klass is not instance of expected type: " + targetType.getName());
82+
return null;
8383
}
8484
return new WrappedProxyKlass(superKlass);
8585
}
8686
return null;
8787
}
88-
proxyBytes = EspressoForeignProxyGenerator.getProxyKlassBytes(metaName, parentInterfaces.toArray(new ObjectKlass[parentInterfaces.size()]), superKlass, getContext());
88+
proxyBytes = EspressoForeignProxyGenerator.getProxyKlassBytes(metaName, parentInterfaces.toArray(ObjectKlass.EMPTY_ARRAY), superKlass, getContext());
8989
}
9090
Klass proxyKlass = lookupOrDefineInBindingsLoader(proxyBytes, getContext());
9191

9292
if (!targetType.isAssignableFrom(proxyKlass)) {
93-
throw new ClassCastException("proxy object is not instance of expected type: " + targetType.getName());
93+
return null;
9494
}
9595
return proxyBytes.getProxyKlass((ObjectKlass) proxyKlass);
9696
}

espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/interop/ToEspressoNode.java

Lines changed: 25 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -184,18 +184,17 @@ public Object doMappedInterface(Object value, Klass targetType,
184184
@SuppressWarnings("unused") @CachedLibrary(limit = "LIMIT") InteropLibrary interop,
185185
@Cached InlinedBranchProfile error) throws UnsupportedTypeException {
186186
try {
187-
Object metaObject = getMetaObjectOrThrow(value, interop);
187+
Object metaObject = interop.getMetaObject(value);
188188
WrappedProxyKlass proxyKlass = lookupProxyKlassNode.execute(metaObject, getMetaName(metaObject, interop), targetType);
189189
if (proxyKlass != null) {
190190
targetType.safeInitialize();
191191
return proxyKlass.createProxyInstance(value, getLanguage(), interop);
192192
}
193-
error.enter(this);
194-
throw new ClassCastException();
195-
} catch (ClassCastException e) {
196-
error.enter(this);
197-
throw UnsupportedTypeException.create(new Object[]{value}, EspressoError.format("Could not cast foreign object to %s: ", targetType.getTypeAsString()));
193+
} catch (UnsupportedMessageException e) {
194+
// no meta object, fall through to throw unsupported type
198195
}
196+
error.enter(this);
197+
throw unsupportedType(value, targetType);
199198
}
200199

201200
@Specialization(guards = {
@@ -227,20 +226,19 @@ public Object doTypeConverter(Object value, Klass targetType,
227226
@SuppressWarnings("unused") @CachedLibrary(limit = "LIMIT") InteropLibrary interop,
228227
@Cached InlinedBranchProfile error) throws UnsupportedTypeException {
229228
try {
230-
Object metaObject = getMetaObjectOrThrow(value, interop);
229+
Object metaObject = interop.getMetaObject(value);
231230
String metaName = getMetaName(metaObject, interop);
232231

233232
// check if there's a specific type mapping available
234233
PolyglotTypeMappings.TypeConverter converter = lookupTypeConverter.execute(metaName);
235234
if (converter != null) {
236235
return converter.convert(StaticObject.createForeign(getLanguage(), targetType, value, interop));
237236
}
238-
error.enter(this);
239-
throw new ClassCastException();
240-
} catch (ClassCastException e) {
241-
error.enter(this);
242-
throw UnsupportedTypeException.create(new Object[]{value}, EspressoError.format("Could not cast foreign object to %s: ", targetType.getNameAsString(), e.getMessage()));
237+
} catch (UnsupportedMessageException e) {
238+
// no meta object, fall through to throw unsupported type
243239
}
240+
error.enter(this);
241+
throw unsupportedType(value, targetType);
244242
}
245243

246244
@Specialization(guards = {
@@ -252,22 +250,21 @@ public Object doInternalTypeConverter(Object value, Klass targetType,
252250
@Cached ToReference.DynamicToReference converterToEspresso,
253251
@Cached LookupInternalTypeConverterNode lookupInternalTypeConverter,
254252
@SuppressWarnings("unused") @CachedLibrary(limit = "LIMIT") InteropLibrary interop,
255-
@Cached InlinedBranchProfile error) throws UnsupportedTypeException {
253+
@Cached InlinedBranchProfile errorProfile) throws UnsupportedTypeException {
256254
try {
257-
Object metaObject = getMetaObjectOrThrow(value, interop);
255+
Object metaObject = interop.getMetaObject(value);
258256
String metaName = getMetaName(metaObject, interop);
259257

260258
// check if there's a specific type mapping available
261259
PolyglotTypeMappings.InternalTypeConverter converter = lookupInternalTypeConverter.execute(metaName);
262260
if (converter != null) {
263261
return converter.convertInternal(interop, value, getMeta(), converterToEspresso);
264262
}
265-
error.enter(this);
266-
throw new ClassCastException();
267-
} catch (ClassCastException e) {
268-
error.enter(this);
269-
throw UnsupportedTypeException.create(new Object[]{value}, EspressoError.format("Could not cast foreign object to %s: ", targetType.getNameAsString(), e.getMessage()));
263+
} catch (UnsupportedMessageException e) {
264+
// no meta object, fall through to throw unsupported type
270265
}
266+
errorProfile.enter(this);
267+
throw unsupportedType(value, targetType);
271268
}
272269

273270
@Specialization(guards = {
@@ -295,12 +292,8 @@ public Object doGeneric(Object value, Klass targetType,
295292
if (result != null) {
296293
return result;
297294
}
298-
try {
299-
checkHasAllFieldsOrThrow(value, (ObjectKlass) targetType, interop, getMeta());
300-
return StaticObject.createForeign(getLanguage(), targetType, value, interop);
301-
} catch (ClassCastException e) {
302-
throw UnsupportedTypeException.create(new Object[]{value}, targetType.getTypeAsString());
303-
}
295+
checkHasAllFieldsOrThrow(value, (ObjectKlass) targetType, interop, getMeta());
296+
return StaticObject.createForeign(getLanguage(), targetType, value, interop);
304297
}
305298
throw UnsupportedTypeException.create(new Object[]{value}, targetType.getTypeAsString());
306299
}
@@ -336,16 +329,8 @@ public static String getMetaName(Object metaObject, InteropLibrary interop) {
336329
}
337330
}
338331

339-
public static Object getMetaObjectOrThrow(Object value, InteropLibrary interop) throws ClassCastException {
340-
try {
341-
return interop.getMetaObject(value);
342-
} catch (UnsupportedMessageException e) {
343-
throw new ClassCastException("Could not lookup meta object");
344-
}
345-
}
346-
347332
@TruffleBoundary
348-
public static void checkHasAllFieldsOrThrow(Object value, ObjectKlass klass, InteropLibrary interopLibrary, Meta meta) {
333+
public static void checkHasAllFieldsOrThrow(Object value, ObjectKlass klass, InteropLibrary interopLibrary, Meta meta) throws UnsupportedTypeException {
349334
CompilerAsserts.partialEvaluationConstant(klass);
350335
/*
351336
* For boxed types a .value member is not required if there's a direct conversion via
@@ -371,11 +356,16 @@ public static void checkHasAllFieldsOrThrow(Object value, ObjectKlass klass, Int
371356

372357
for (Field f : klass.getDeclaredFields()) {
373358
if (!f.isStatic() && !interopLibrary.isMemberExisting(value, f.getNameAsString())) {
374-
throw new ClassCastException("Missing field: " + f.getNameAsString());
359+
throw UnsupportedTypeException.create(new Object[]{value}, klass.getTypeAsString() + " due to missing field: " + f.getNameAsString());
375360
}
376361
}
377362
if (klass.getSuperClass() != null) {
378363
checkHasAllFieldsOrThrow(value, klass.getSuperKlass(), interopLibrary, meta);
379364
}
380365
}
366+
367+
@TruffleBoundary
368+
static UnsupportedTypeException unsupportedType(Object value, Klass targetType) {
369+
return UnsupportedTypeException.create(new Object[]{value}, EspressoError.format("Could not cast foreign object to %s: ", targetType.getNameAsString()));
370+
}
381371
}

0 commit comments

Comments
 (0)