From d53f197f6f4ff8c43066a1efe65b3beba5dc8854 Mon Sep 17 00:00:00 2001 From: Allan Gregersen Date: Fri, 27 Oct 2023 14:26:12 +0200 Subject: [PATCH 01/11] declare internal built-in type converters for host primitive array types. --- .../nodes/interop/PolyglotTypeMappings.java | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/interop/PolyglotTypeMappings.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/interop/PolyglotTypeMappings.java index b5493e043e44..3da2bdb8d9a9 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/interop/PolyglotTypeMappings.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/interop/PolyglotTypeMappings.java @@ -27,6 +27,8 @@ import java.util.Map; import java.util.Set; +import com.oracle.truffle.espresso.impl.ArrayKlass; +import com.oracle.truffle.espresso.impl.PrimitiveKlass; import org.graalvm.collections.EconomicMap; import org.graalvm.collections.UnmodifiableEconomicMap; import org.graalvm.options.OptionMap; @@ -141,6 +143,14 @@ private void addInternalConverters(Meta meta) { } else { warn(current, meta.getContext()); } + converters.put("byte[]", new PrimitiveArrayConverter(meta._byte_array)); + converters.put("boolean[]", new PrimitiveArrayConverter(meta._boolean_array)); + converters.put("char[]", new PrimitiveArrayConverter(meta._char_array)); + converters.put("short[]", new PrimitiveArrayConverter(meta._short_array)); + converters.put("int[]", new PrimitiveArrayConverter(meta._int_array)); + converters.put("long[]", new PrimitiveArrayConverter(meta._long_array)); + converters.put("float[]", new PrimitiveArrayConverter(meta._float_array)); + converters.put("double[]", new PrimitiveArrayConverter(meta._double_array)); internalTypeConverterFunctions = EconomicMap.create(converters); } @@ -331,4 +341,18 @@ private StaticObject toByteArray(BigInteger bigInteger, Meta meta) { return StaticObject.wrap(bigInteger.toByteArray(), meta); } } + + public final class PrimitiveArrayConverter implements InternalTypeConverter { + + private final ArrayKlass klass; + + public PrimitiveArrayConverter(ArrayKlass klass) { + this.klass = klass; + } + + @Override + public StaticObject convertInternal(InteropLibrary interop, Object value, Meta meta, ToReference.DynamicToReference toEspresso) { + return StaticObject.createForeign(toEspresso.getLanguage(), klass, value, interop); + } + } } From b290701487078dc95d64caa881924ae2d96b22b9 Mon Sep 17 00:00:00 2001 From: Allan Gregersen Date: Fri, 27 Oct 2023 14:29:29 +0200 Subject: [PATCH 02/11] remove unused import --- .../truffle/espresso/nodes/interop/PolyglotTypeMappings.java | 1 - 1 file changed, 1 deletion(-) diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/interop/PolyglotTypeMappings.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/interop/PolyglotTypeMappings.java index 3da2bdb8d9a9..cb8ff4ab7163 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/interop/PolyglotTypeMappings.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/interop/PolyglotTypeMappings.java @@ -28,7 +28,6 @@ import java.util.Set; import com.oracle.truffle.espresso.impl.ArrayKlass; -import com.oracle.truffle.espresso.impl.PrimitiveKlass; import org.graalvm.collections.EconomicMap; import org.graalvm.collections.UnmodifiableEconomicMap; import org.graalvm.options.OptionMap; From dc2ccd832ff4b958d96fcd6559092db6a1965a42 Mon Sep 17 00:00:00 2001 From: Allan Gregersen Date: Tue, 31 Oct 2023 13:46:11 +0100 Subject: [PATCH 03/11] check array trait for interop object before converting to espresso guest object --- .../truffle/espresso/nodes/interop/PolyglotTypeMappings.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/interop/PolyglotTypeMappings.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/interop/PolyglotTypeMappings.java index cb8ff4ab7163..07a4843cd2a1 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/interop/PolyglotTypeMappings.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/interop/PolyglotTypeMappings.java @@ -351,6 +351,9 @@ public PrimitiveArrayConverter(ArrayKlass klass) { @Override public StaticObject convertInternal(InteropLibrary interop, Object value, Meta meta, ToReference.DynamicToReference toEspresso) { + if (!interop.hasArrayElements(value)) { + throw new ClassCastException(); + } return StaticObject.createForeign(toEspresso.getLanguage(), klass, value, interop); } } From 4f4aceafa5c11c2c3e9c685a3b565d1e5d3aca8d Mon Sep 17 00:00:00 2001 From: Allan Gregersen Date: Tue, 31 Oct 2023 13:47:04 +0100 Subject: [PATCH 04/11] handle foreign object arrays in Array substitutions --- .../Target_java_lang_reflect_Array.java | 228 ++++++++++++++++-- .../truffle/espresso/vm/InterpreterToVM.java | 2 +- .../com/oracle/truffle/espresso/vm/VM.java | 34 ++- 3 files changed, 229 insertions(+), 35 deletions(-) diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_reflect_Array.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_reflect_Array.java index 3493d043cf5c..1829ef90ced3 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_reflect_Array.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_reflect_Array.java @@ -27,6 +27,10 @@ import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.interop.InteropLibrary; +import com.oracle.truffle.api.interop.InvalidArrayIndexException; +import com.oracle.truffle.api.interop.UnsupportedMessageException; +import com.oracle.truffle.api.interop.UnsupportedTypeException; import com.oracle.truffle.espresso.EspressoLanguage; import com.oracle.truffle.espresso.descriptors.Types; import com.oracle.truffle.espresso.impl.ArrayKlass; @@ -445,23 +449,91 @@ public static void set(@JavaType(Object.class) StaticObject array, int index, @J throw meta.throwNullPointerException(); } if (array.isArray()) { - // @formatter:off + try { Object widenValue = Target_sun_reflect_NativeMethodAccessorImpl.checkAndWiden(meta, value, ((ArrayKlass) array.getKlass()).getComponentType()); switch (((ArrayKlass) array.getKlass()).getComponentType().getJavaKind()) { - case Boolean : vm.setArrayByte(language, ((boolean) widenValue) ? (byte) 1 : (byte) 0, index, array); break; - case Byte : vm.setArrayByte(language, ((byte) widenValue), index, array); break; - case Short : vm.setArrayShort(language, ((short) widenValue), index, array); break; - case Char : vm.setArrayChar(language, ((char) widenValue), index, array); break; - case Int : vm.setArrayInt(language, ((int) widenValue), index, array); break; - case Float : vm.setArrayFloat(language, ((float) widenValue), index, array); break; - case Long : vm.setArrayLong(language, ((long) widenValue), index, array); break; - case Double : vm.setArrayDouble(language, ((double) widenValue), index, array); break; + case Boolean: { + if (array.isForeignObject()) { + InteropLibrary library = InteropLibrary.getUncached(); + library.writeArrayElement(array.rawForeignObject(language), index, widenValue); + } else { + vm.setArrayByte(language, ((boolean) widenValue) ? (byte) 1 : (byte) 0, index, array); + } + break; + } + case Byte: { + if (array.isForeignObject()) { + InteropLibrary library = InteropLibrary.getUncached(); + library.writeArrayElement(array.rawForeignObject(language), index, widenValue); + } else { + vm.setArrayByte(language, ((byte) widenValue), index, array); + } + break; + } + case Short: { + if (array.isForeignObject()) { + InteropLibrary library = InteropLibrary.getUncached(); + library.writeArrayElement(array.rawForeignObject(language), index, widenValue); + } else { + vm.setArrayShort(language, ((short) widenValue), index, array); + } + break; + } + case Char: { + if (array.isForeignObject()) { + InteropLibrary library = InteropLibrary.getUncached(); + library.writeArrayElement(array.rawForeignObject(language), index, widenValue); + } else { + vm.setArrayChar(language, ((char) widenValue), index, array); + } + break; + } + case Int: { + if (array.isForeignObject()) { + InteropLibrary library = InteropLibrary.getUncached(); + library.writeArrayElement(array.rawForeignObject(language), index, widenValue); + } else { + vm.setArrayInt(language, ((int) widenValue), index, array); + } + break; + } + case Float: { + if (array.isForeignObject()) { + InteropLibrary library = InteropLibrary.getUncached(); + library.writeArrayElement(array.rawForeignObject(language), index, widenValue); + } else { + vm.setArrayFloat(language, ((float) widenValue), index, array); + } + break; + } + case Long: { + if (array.isForeignObject()) { + InteropLibrary library = InteropLibrary.getUncached(); + library.writeArrayElement(array.rawForeignObject(language), index, widenValue); + } else { + vm.setArrayLong(language, ((long) widenValue), index, array); + } + break; + } + case Double: { + if (array.isForeignObject()) { + InteropLibrary library = InteropLibrary.getUncached(); + library.writeArrayElement(array.rawForeignObject(language), index, widenValue); + } else { + vm.setArrayDouble(language, ((double) widenValue), index, array); + } + break; + } case Object : vm.setArrayObject(language, value, index, array); break; default : CompilerDirectives.transferToInterpreter(); throw EspressoError.shouldNotReachHere("invalid array type: " + array); } - // @formatter:on + } catch (UnsupportedMessageException | UnsupportedTypeException e) { + throw meta.throwException(meta.java_lang_IllegalArgumentException); + } catch (InvalidArrayIndexException e) { + throw meta.throwException(meta.java_lang_ArrayIndexOutOfBoundsException); + } } else { throw meta.throwException(meta.java_lang_IllegalArgumentException); } @@ -489,25 +561,131 @@ public static void set(@JavaType(Object.class) StaticObject array, int index, @J throw meta.throwNullPointerException(); } if (array.isArray()) { - // @formatter:off - switch (((ArrayKlass) array.getKlass()).getComponentType().getJavaKind()) { - case Boolean : return meta.boxBoolean(vm.getArrayByte(language, index, array) != 0); - case Byte : return meta.boxByte(vm.getArrayByte(language, index, array)); - case Short : return meta.boxShort(vm.getArrayShort(language, index, array)); - case Char : return meta.boxCharacter(vm.getArrayChar(language, index, array)); - case Int : return meta.boxInteger(vm.getArrayInt(language, index, array)); - case Float : return meta.boxFloat(vm.getArrayFloat(language, index, array)); - case Long : return meta.boxLong(vm.getArrayLong(language, index, array)); - case Double : return meta.boxDouble(vm.getArrayDouble(language, index, array)); - case Object : return vm.getArrayObject(language, index, array); - default : - CompilerDirectives.transferToInterpreter(); - throw EspressoError.shouldNotReachHere("invalid array type: " + array); + try { + switch (((ArrayKlass) array.getKlass()).getComponentType().getJavaKind()) { + case Boolean: { + boolean result; + if (array.isForeignObject()) { + InteropLibrary library = InteropLibrary.getUncached(); + result = library.asBoolean(library.readArrayElement(array.rawForeignObject(language), index)); + } else { + result = vm.getArrayByte(language, index, array) != 0; + } + return meta.boxBoolean(result); + } + case Byte: { + byte result; + if (array.isForeignObject()) { + InteropLibrary library = InteropLibrary.getUncached(); + result = library.asByte(library.readArrayElement(array.rawForeignObject(language), index)); + } else { + result = vm.getArrayByte(language, index, array); + } + return meta.boxByte(result); + } + case Short: { + short result; + if (array.isForeignObject()) { + InteropLibrary library = InteropLibrary.getUncached(); + result = library.asShort(library.readArrayElement(array.rawForeignObject(language), index)); + } else { + result = vm.getArrayShort(language, index, array); + } + return meta.boxShort(result); + } + case Char: { + char result; + if (array.isForeignObject()) { + InteropLibrary library = InteropLibrary.getUncached(); + String str = library.asString(library.readArrayElement(array.rawForeignObject(language), index)); + if (str.isEmpty()) { + result = ' '; + } else if (str.length() > 1) { + throw meta.throwException(meta.java_lang_IllegalArgumentException); + } else { + result = str.charAt(0); + } + } else { + result = vm.getArrayChar(language, index, array); + } + return meta.boxCharacter(result); + } + case Int: { + int result; + if (array.isForeignObject()) { + InteropLibrary library = InteropLibrary.getUncached(); + result = library.asInt(library.readArrayElement(array.rawForeignObject(language), index)); + } else { + result = vm.getArrayInt(language, index, array); + } + return meta.boxInteger(result); + } + case Float: { + float result; + if (array.isForeignObject()) { + InteropLibrary library = InteropLibrary.getUncached(); + result = library.asFloat(library.readArrayElement(array.rawForeignObject(language), index)); + } else { + result = vm.getArrayFloat(language, index, array); + } + return meta.boxFloat(result); + } + case Long: { + long result; + if (array.isForeignObject()) { + InteropLibrary library = InteropLibrary.getUncached(); + result = library.asLong(library.readArrayElement(array.rawForeignObject(language), index)); + } else { + result = vm.getArrayLong(language, index, array); + } + return meta.boxLong(result); + } + case Double: { + double result; + if (array.isForeignObject()) { + InteropLibrary library = InteropLibrary.getUncached(); + result = library.asDouble(library.readArrayElement(array.rawForeignObject(language), index)); + } else { + result = vm.getArrayDouble(language, index, array); + } + return meta.boxDouble(result); + } + case Object: { + if (array.isForeignObject()) { + InteropLibrary library = InteropLibrary.getUncached(); + Object result = library.readArrayElement(array.rawForeignObject(language), index); + return StaticObject.createForeign(language, meta.java_lang_Object, result, InteropLibrary.getUncached(result)); + } else { + return vm.getArrayObject(language, index, array); + } + } + default: + CompilerDirectives.transferToInterpreter(); + throw EspressoError.shouldNotReachHere("invalid array type: " + array); + } + } catch (UnsupportedMessageException e) { + throw meta.throwException(meta.java_lang_IllegalArgumentException); + } catch (InvalidArrayIndexException e) { + int length = getForeignArrayLength(array, language, meta); + throw meta.throwExceptionWithMessage(meta.java_lang_ArrayIndexOutOfBoundsException, InterpreterToVM.outOfBoundsMessage(index, length)); } - // @formatter:on } else { throw meta.throwException(meta.java_lang_IllegalArgumentException); } } + private static int getForeignArrayLength(StaticObject array, EspressoLanguage language, Meta meta) { + assert array.isForeignObject(); + try { + Object foreignObject = array.rawForeignObject(language); + InteropLibrary library = InteropLibrary.getUncached(foreignObject); + long arrayLength = library.getArraySize(foreignObject); + if (arrayLength > Integer.MAX_VALUE) { + return Integer.MAX_VALUE; + } + return (int) arrayLength; + } catch (UnsupportedMessageException e) { + throw meta.throwExceptionWithMessage(meta.java_lang_IllegalArgumentException, "can't get array length because foreign object is not an array"); + } + } } diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/InterpreterToVM.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/InterpreterToVM.java index 58b69a62307d..d72c981239bf 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/InterpreterToVM.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/InterpreterToVM.java @@ -114,7 +114,7 @@ public int getArrayInt(EspressoLanguage language, int index, @JavaType(int[].cla } @TruffleBoundary - private static String outOfBoundsMessage(int index, int length) { + public static String outOfBoundsMessage(int index, int length) { return "Index " + index + " out of bounds for length " + length; } diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/VM.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/VM.java index c438e8a40c3c..0c6168c361d0 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/VM.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/VM.java @@ -2531,15 +2531,31 @@ private Map buildPropertiesMap() { @VmImpl(isJni = true) public int JVM_GetArrayLength(@JavaType(Object.class) StaticObject array, @Inject EspressoLanguage language, @Inject SubstitutionProfiler profiler) { - try { - return Array.getLength(MetaUtil.unwrapArrayOrNull(language, array)); - } catch (IllegalArgumentException e) { - profiler.profile(0); - Meta meta = getMeta(); - throw meta.throwExceptionWithMessage(meta.java_lang_IllegalArgumentException, e.getMessage()); - } catch (NullPointerException e) { - profiler.profile(1); - throw getMeta().throwNullPointerException(); + if (array.isForeignObject()) { + try { + Object foreignObject = array.rawForeignObject(language); + InteropLibrary library = InteropLibrary.getUncached(foreignObject); + long arrayLength = library.getArraySize(foreignObject); + if (arrayLength > Integer.MAX_VALUE) { + return Integer.MAX_VALUE; + } + return (int) arrayLength; + } catch (UnsupportedMessageException e) { + profiler.profile(0); + Meta meta = getMeta(); + throw meta.throwExceptionWithMessage(meta.java_lang_IllegalArgumentException, "can't get array length because foreign object is not an array"); + } + } else { + try { + return Array.getLength(MetaUtil.unwrapArrayOrNull(language, array)); + } catch (IllegalArgumentException e) { + profiler.profile(1); + Meta meta = getMeta(); + throw meta.throwExceptionWithMessage(meta.java_lang_IllegalArgumentException, e.getMessage()); + } catch (NullPointerException e) { + profiler.profile(2); + throw getMeta().throwNullPointerException(); + } } } From 88cccd014a5e362945de0fa9f4f54d09feda835f Mon Sep 17 00:00:00 2001 From: Codrut Stancu Date: Wed, 25 Oct 2023 01:09:31 +0200 Subject: [PATCH 05/11] Install hosted values readers in ImageHeapConstant lazily. --- .../pointsto/heap/HeapSnapshotVerifier.java | 60 +++++++----- .../pointsto/heap/ImageHeapConstant.java | 44 +++++++-- .../pointsto/heap/ImageHeapInstance.java | 49 +++++++--- .../pointsto/heap/ImageHeapObjectArray.java | 57 +++++++---- .../graal/pointsto/heap/ImageHeapScanner.java | 98 ++++++++++++------- .../graal/pointsto/util/AnalysisFuture.java | 4 + .../hosted/GraalGraphObjectReplacer.java | 1 + .../AnalysisConstantReflectionProvider.java | 30 +++++- .../svm/hosted/c/CGlobalDataFeature.java | 2 +- .../svm/hosted/heap/SVMImageHeapVerifier.java | 6 +- 10 files changed, 249 insertions(+), 102 deletions(-) diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/HeapSnapshotVerifier.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/HeapSnapshotVerifier.java index d72d31940e9c..66865b2e440d 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/HeapSnapshotVerifier.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/HeapSnapshotVerifier.java @@ -187,31 +187,37 @@ private boolean verifyFieldValue(JavaConstant receiver, AnalysisField field, Jav if (field.isStatic()) { TypeData typeData = field.getDeclaringClass().getOrComputeData(); JavaConstant fieldSnapshot = typeData.readFieldValue(field); - verifyStaticFieldValue(typeData, field, maybeUnwrapSnapshot(fieldSnapshot, fieldValue instanceof ImageHeapConstant), fieldValue, reason); + verifyStaticFieldValue(typeData, field, fieldSnapshot, fieldValue, reason); } else { - ImageHeapInstance receiverObject = (ImageHeapInstance) getReceiverObject(receiver, reason); + ImageHeapInstance receiverObject = (ImageHeapInstance) getSnapshot(receiver, reason); JavaConstant fieldSnapshot = receiverObject.readFieldValue(field); - verifyInstanceFieldValue(field, receiver, receiverObject, maybeUnwrapSnapshot(fieldSnapshot, fieldValue instanceof ImageHeapConstant), fieldValue, reason); + verifyInstanceFieldValue(field, receiver, receiverObject, fieldSnapshot, fieldValue, reason); } return false; } private void verifyStaticFieldValue(TypeData typeData, AnalysisField field, JavaConstant fieldSnapshot, JavaConstant fieldValue, ScanReason reason) { - if (!Objects.equals(fieldSnapshot, fieldValue)) { + JavaConstant result = fieldSnapshot; + JavaConstant unwrappedSnapshot = maybeUnwrapSnapshot(fieldSnapshot, fieldValue instanceof ImageHeapConstant); + if (!Objects.equals(unwrappedSnapshot, fieldValue)) { String format = "Value mismatch for static field %s %n snapshot: %s %n new value: %s %n"; - Consumer onAnalysisModified = analysisModified(reason, format, field, fieldSnapshot, fieldValue); - scanner.patchStaticField(typeData, field, fieldValue, reason, onAnalysisModified).ensureDone(); + Consumer onAnalysisModified = analysisModified(reason, format, field, unwrappedSnapshot, fieldValue); + result = scanner.patchStaticField(typeData, field, fieldValue, reason, onAnalysisModified).ensureDone(); heapPatched = true; } + ImageHeapScanner.ensureReaderInstalled(result); } private void verifyInstanceFieldValue(AnalysisField field, JavaConstant receiver, ImageHeapInstance receiverObject, JavaConstant fieldSnapshot, JavaConstant fieldValue, ScanReason reason) { - if (!Objects.equals(fieldSnapshot, fieldValue)) { + JavaConstant result = fieldSnapshot; + JavaConstant unwrappedSnapshot = maybeUnwrapSnapshot(fieldSnapshot, fieldValue instanceof ImageHeapConstant); + if (!Objects.equals(unwrappedSnapshot, fieldValue)) { String format = "Value mismatch for instance field %s of %s %n snapshot: %s %n new value: %s %n"; - Consumer onAnalysisModified = analysisModified(reason, format, field, asString(receiver), fieldSnapshot, fieldValue); - scanner.patchInstanceField(receiverObject, field, fieldValue, reason, onAnalysisModified).ensureDone(); + Consumer onAnalysisModified = analysisModified(reason, format, field, asString(receiver), unwrappedSnapshot, fieldValue); + result = scanner.patchInstanceField(receiverObject, field, fieldValue, reason, onAnalysisModified).ensureDone(); heapPatched = true; } + ImageHeapScanner.ensureReaderInstalled(result); } private Consumer analysisModified(ScanReason reason, String format, Object... args) { @@ -249,40 +255,48 @@ public boolean forNonNullArrayElement(JavaConstant array, AnalysisType arrayType * fields that become available but may have not yet been consumed. We simply execute * the future, then compare the produced value. */ - ImageHeapObjectArray arrayObject = (ImageHeapObjectArray) getReceiverObject(array, reason); + ImageHeapObjectArray arrayObject = (ImageHeapObjectArray) getSnapshot(array, reason); JavaConstant elementSnapshot = arrayObject.readElementValue(index); verifyArrayElementValue(elementValue, index, reason, array, arrayObject, elementSnapshot); return false; } private void verifyArrayElementValue(JavaConstant elementValue, int index, ScanReason reason, JavaConstant array, ImageHeapObjectArray arrayObject, JavaConstant elementSnapshot) { + JavaConstant result = elementSnapshot; if (!Objects.equals(maybeUnwrapSnapshot(elementSnapshot, elementValue instanceof ImageHeapConstant), elementValue)) { String format = "Value mismatch for array element at index %s of %s %n snapshot: %s %n new value: %s %n"; Consumer onAnalysisModified = analysisModified(reason, format, index, asString(array), elementSnapshot, elementValue); - scanner.patchArrayElement(arrayObject, index, elementValue, reason, onAnalysisModified).ensureDone(); + result = scanner.patchArrayElement(arrayObject, index, elementValue, reason, onAnalysisModified).ensureDone(); heapPatched = true; } + ImageHeapScanner.ensureReaderInstalled(result); } @SuppressWarnings({"unchecked", "rawtypes"}) - private ImageHeapConstant getReceiverObject(JavaConstant constant, ScanReason reason) { + private ImageHeapConstant getSnapshot(JavaConstant constant, ScanReason reason) { + ImageHeapConstant result; if (constant instanceof ImageHeapConstant) { /* This is a simulated constant. */ - return (ImageHeapConstant) constant; - } - Object task = imageHeap.getSnapshot(constant); - if (task == null) { - throw error(reason, "Task is null for constant %s.", constant); - } else if (task instanceof ImageHeapConstant) { - return (ImageHeapConstant) task; + result = (ImageHeapConstant) constant; } else { - AnalysisFuture future = ((AnalysisFuture) task); - if (future.isDone()) { - return future.guardedGet(); + Object task = imageHeap.getSnapshot(constant); + if (task == null) { + throw error(reason, "Task is null for constant %s.", constant); + } else if (task instanceof ImageHeapConstant) { + result = (ImageHeapConstant) task; } else { - throw error(reason, "Task not yet executed for constant %s.", constant); + AnalysisFuture future = ((AnalysisFuture) task); + if (future.isDone()) { + result = future.guardedGet(); + } else { + throw error(reason, "Task not yet executed for constant %s.", constant); + } } } + if (!result.isReaderInstalled()) { + throw error(reason, "Reader not yet installed for constant %s.", constant); + } + return result; } @Override diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapConstant.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapConstant.java index 81c3c741dcfe..d23fdb08dcce 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapConstant.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapConstant.java @@ -27,14 +27,15 @@ import java.util.Objects; import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; -import jdk.graal.compiler.core.common.type.CompressibleConstant; -import jdk.graal.compiler.core.common.type.TypedConstant; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; import com.oracle.graal.pointsto.ObjectScanner; +import com.oracle.graal.pointsto.util.AnalysisFuture; import com.oracle.graal.pointsto.util.AtomicUtils; +import jdk.graal.compiler.core.common.type.CompressibleConstant; +import jdk.graal.compiler.core.common.type.TypedConstant; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.MetaAccessProvider; @@ -50,7 +51,7 @@ @Platforms(Platform.HOSTED_ONLY.class) public abstract class ImageHeapConstant implements JavaConstant, TypedConstant, CompressibleConstant, VMConstant { /** Stores the type of this object. */ - protected ResolvedJavaType type; + protected final ResolvedJavaType type; /** * Stores the hosted object, already processed by the object transformers. It is null for * instances of partially evaluated classes. @@ -62,17 +63,45 @@ public abstract class ImageHeapConstant implements JavaConstant, TypedConstant, @SuppressWarnings("unused") private volatile Object isReachable; + /** + * A future that reads the hosted field or array elements values lazily only when the receiver + * object is used. This way the shadow heap can contain hosted only objects, i.e., objects that + * cannot be reachable at run time but are processed ahead-of-time. + */ + protected AnalysisFuture hostedValuesReader; + private static final AtomicReferenceFieldUpdater isReachableUpdater = AtomicReferenceFieldUpdater .newUpdater(ImageHeapConstant.class, Object.class, "isReachable"); ImageHeapConstant(ResolvedJavaType type, JavaConstant object, int identityHashCode, boolean compressed) { + Objects.requireNonNull(type); this.type = type; this.hostedObject = object; this.identityHashCode = identityHashCode; this.compressed = compressed; } + public void ensureReaderInstalled() { + if (hostedValuesReader != null) { + hostedValuesReader.ensureDone(); + } + } + + /** + * A regular image heap constant starts off without any fields or array elements installed. It + * instead contains a future task, the hostedValuesReader, which creates the tasks that read the + * hosted values. It must be executed before any values can be accessed. This ensures that the + * hosted values are only read when the constant is indeed used, i.e., it was not eliminated by + * constant folding. + * + * Simulated constants are fully initialized when they are created. + */ + protected boolean isReaderInstalled() { + return hostedValuesReader == null || hostedValuesReader.isDone(); + } + public boolean markReachable(ObjectScanner.ScanReason reason) { + ensureReaderInstalled(); return AtomicUtils.atomicSet(this, reason, isReachableUpdater); } @@ -145,10 +174,6 @@ public ResolvedJavaType getType(MetaAccessProvider provider) { return type; } - public void setType(ResolvedJavaType type) { - this.type = type; - } - @Override public Object asBoxedPrimitive() { return null; @@ -212,4 +237,9 @@ public boolean equals(Object o) { public int hashCode() { return hostedObject != null ? hostedObject.hashCode() : 0; } + + @Override + public String toString() { + return "ImageHeapConstant< " + type.toJavaName() + ", reachable: " + isReachable() + ", reader installed: " + isReaderInstalled() + ">"; + } } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapInstance.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapInstance.java index 4b28cd3feae3..e2e88cde1bb7 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapInstance.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapInstance.java @@ -27,10 +27,12 @@ import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import java.util.Arrays; +import java.util.concurrent.atomic.AtomicReference; import com.oracle.graal.pointsto.ObjectScanner; import com.oracle.graal.pointsto.heap.value.ValueSupplier; import com.oracle.graal.pointsto.meta.AnalysisField; +import com.oracle.graal.pointsto.util.AnalysisError; import com.oracle.graal.pointsto.util.AnalysisFuture; import jdk.vm.ci.meta.JavaConstant; @@ -52,34 +54,53 @@ public final class ImageHeapInstance extends ImageHeapConstant { private static final VarHandle arrayHandle = MethodHandles.arrayElementVarHandle(Object[].class); /** - * Stores either an {@link AnalysisFuture} of {@link JavaConstant} or its result, a + * A reference to the field values array. It is only set when the constant is actually used and + * the hosted values of its fields/elements may be read. + * + * Each value is either an {@link AnalysisFuture} of {@link JavaConstant} or its result, a * {@link JavaConstant}, indexed by {@link AnalysisField#getPosition()}. *

* Evaluating the {@link AnalysisFuture} runs * {@link ImageHeapScanner#createFieldValue(AnalysisField, ImageHeapInstance, ValueSupplier, ObjectScanner.ScanReason)} * which adds the result to the image heap. */ - private final Object[] fieldValues; + private final AtomicReference fieldValuesRef; + + ImageHeapInstance(ResolvedJavaType type, JavaConstant object) { + super(type, object, createIdentityHashCode(object), false); + this.fieldValuesRef = new AtomicReference<>(); + } public ImageHeapInstance(ResolvedJavaType type) { this(type, null, type.getInstanceFields(true).length); } - ImageHeapInstance(ResolvedJavaType type, JavaConstant object, int length) { + private ImageHeapInstance(ResolvedJavaType type, JavaConstant object, int length) { this(type, object, new Object[length], createIdentityHashCode(object), false); } private ImageHeapInstance(ResolvedJavaType type, JavaConstant object, Object[] fieldValues, int identityHashCode, boolean compressed) { super(type, object, identityHashCode, compressed); - this.fieldValues = fieldValues; + this.fieldValuesRef = new AtomicReference<>(fieldValues); + } + + private ImageHeapInstance(ResolvedJavaType type, JavaConstant object, AtomicReference fieldValuesRef, int identityHashCode, boolean compressed) { + super(type, object, identityHashCode, compressed); + this.fieldValuesRef = fieldValuesRef; + } + + void setFieldValues(Object[] fieldValues) { + boolean success = this.fieldValuesRef.compareAndSet(null, fieldValues); + AnalysisError.guarantee(success, "Unexpected field values reference for constant %s", this); } /** * Record the task computing the field value. It will be retrieved and executed when the field * is marked as read. */ - public void setFieldTask(AnalysisField field, AnalysisFuture task) { - arrayHandle.setVolatile(this.fieldValues, field.getPosition(), task); + void setFieldTask(AnalysisField field, AnalysisFuture task) { + AnalysisError.guarantee(isReaderInstalled()); + arrayHandle.setVolatile(this.fieldValuesRef.get(), field.getPosition(), task); } /** @@ -88,7 +109,8 @@ public void setFieldTask(AnalysisField field, AnalysisFuture task) * and replaced. */ public void setFieldValue(AnalysisField field, JavaConstant value) { - arrayHandle.setVolatile(this.fieldValues, field.getPosition(), value); + AnalysisError.guarantee(isReaderInstalled()); + arrayHandle.setVolatile(this.fieldValuesRef.get(), field.getPosition(), value); } /** @@ -97,7 +119,8 @@ public void setFieldValue(AnalysisField field, JavaConstant value) { * or the result of executing the task, i.e., a {@link JavaConstant}. */ public Object getFieldValue(AnalysisField field) { - return arrayHandle.getVolatile(this.fieldValues, field.getPosition()); + AnalysisError.guarantee(isReaderInstalled()); + return arrayHandle.getVolatile(this.fieldValuesRef.get(), field.getPosition()); } /** @@ -113,13 +136,13 @@ public JavaConstant readFieldValue(AnalysisField field) { @Override public JavaConstant compress() { assert !compressed : this; - return new ImageHeapInstance(type, hostedObject, fieldValues, identityHashCode, true); + return new ImageHeapInstance(type, hostedObject, fieldValuesRef, identityHashCode, true); } @Override public JavaConstant uncompress() { assert compressed : this; - return new ImageHeapInstance(type, hostedObject, fieldValues, identityHashCode, false); + return new ImageHeapInstance(type, hostedObject, fieldValuesRef, identityHashCode, false); } @Override @@ -128,7 +151,7 @@ public ImageHeapConstant forObjectClone() { return null; } - Object[] newFieldValues = Arrays.copyOf(fieldValues, fieldValues.length); + Object[] newFieldValues = Arrays.copyOf(fieldValuesRef.get(), fieldValuesRef.get().length); /* The new constant is never backed by a hosted object, regardless of the input object. */ JavaConstant newObject = null; return new ImageHeapInstance(type, newObject, newFieldValues, createIdentityHashCode(newObject), compressed); @@ -137,7 +160,7 @@ public ImageHeapConstant forObjectClone() { @Override public boolean equals(Object o) { if (o instanceof ImageHeapInstance) { - return super.equals(o) && this.fieldValues == ((ImageHeapInstance) o).fieldValues; + return super.equals(o) && this.fieldValuesRef == ((ImageHeapInstance) o).fieldValuesRef; } return false; } @@ -146,7 +169,7 @@ public boolean equals(Object o) { public int hashCode() { final int prime = 31; int result = super.hashCode(); - result = prime * result + System.identityHashCode(fieldValues); + result = prime * result + System.identityHashCode(fieldValuesRef); return result; } } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapObjectArray.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapObjectArray.java index 859a9c71cc3d..9dcdd5c0f0ae 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapObjectArray.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapObjectArray.java @@ -27,10 +27,12 @@ import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import java.util.Arrays; +import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; import com.oracle.graal.pointsto.ObjectScanner; import com.oracle.graal.pointsto.meta.AnalysisType; +import com.oracle.graal.pointsto.util.AnalysisError; import com.oracle.graal.pointsto.util.AnalysisFuture; import jdk.vm.ci.meta.JavaConstant; @@ -40,28 +42,42 @@ public final class ImageHeapObjectArray extends ImageHeapArray { private static final VarHandle arrayHandle = MethodHandles.arrayElementVarHandle(Object[].class); + final int length; /** - * Stores either an {@link AnalysisFuture} of {@link JavaConstant} or its result, a + * A reference to the element values array. It is only set when the constant is initialized. + * Each value is either an {@link AnalysisFuture} of {@link JavaConstant} or its result, a * {@link JavaConstant}, indexed by array index. */ - private final Object[] arrayElementValues; + private final AtomicReference arrayElementValuesRef; ImageHeapObjectArray(ResolvedJavaType type, int length) { - this(type, null, new Object[length]); + this(type, null, new Object[length], length); } ImageHeapObjectArray(ResolvedJavaType type, JavaConstant object, int length) { - this(type, object, new Object[length]); + this(type, object, null, length); } - ImageHeapObjectArray(ResolvedJavaType type, JavaConstant object, Object[] arrayElementValues) { - this(type, object, arrayElementValues, createIdentityHashCode(object), false); + ImageHeapObjectArray(ResolvedJavaType type, JavaConstant object, Object[] arrayElementValues, int length) { + this(type, object, arrayElementValues, length, createIdentityHashCode(object), false); } - private ImageHeapObjectArray(ResolvedJavaType type, JavaConstant object, Object[] arrayElementValues, int identityHashCode, boolean compressed) { + private ImageHeapObjectArray(ResolvedJavaType type, JavaConstant object, Object[] arrayElementValues, int length, int identityHashCode, boolean compressed) { + super(type, object, identityHashCode, compressed); + this.arrayElementValuesRef = new AtomicReference<>(arrayElementValues); + this.length = length; + } + + private ImageHeapObjectArray(ResolvedJavaType type, JavaConstant object, AtomicReference arrayElementValuesRef, int length, int identityHashCode, boolean compressed) { super(type, object, identityHashCode, compressed); assert type.isArray() : type; - this.arrayElementValues = arrayElementValues; + this.arrayElementValuesRef = arrayElementValuesRef; + this.length = length; + } + + void setElementValues(Object[] elementValues) { + boolean success = this.arrayElementValuesRef.compareAndSet(null, elementValues); + AnalysisError.guarantee(success, "Unexpected field values reference for constant %s", this); } /** @@ -70,7 +86,8 @@ private ImageHeapObjectArray(ResolvedJavaType type, JavaConstant object, Object[ */ @Override public Object getElement(int idx) { - return arrayHandle.getVolatile(this.arrayElementValues, idx); + AnalysisError.guarantee(isReaderInstalled()); + return arrayHandle.getVolatile(this.arrayElementValuesRef.get(), idx); } /** @@ -86,44 +103,46 @@ public JavaConstant readElementValue(int index) { @Override public void setElement(int idx, JavaConstant value) { - arrayHandle.setVolatile(this.arrayElementValues, idx, value); + AnalysisError.guarantee(isReaderInstalled()); + arrayHandle.setVolatile(this.arrayElementValuesRef.get(), idx, value); } - public void setElementTask(int idx, AnalysisFuture task) { - arrayHandle.setVolatile(this.arrayElementValues, idx, task); + void setElementTask(int idx, AnalysisFuture task) { + AnalysisError.guarantee(isReaderInstalled()); + arrayHandle.setVolatile(this.arrayElementValuesRef.get(), idx, task); } @Override public int getLength() { - return arrayElementValues.length; + return length; } @Override public JavaConstant compress() { assert !compressed : this; - return new ImageHeapObjectArray(type, hostedObject, arrayElementValues, identityHashCode, true); + return new ImageHeapObjectArray(type, hostedObject, arrayElementValuesRef, length, identityHashCode, true); } @Override public JavaConstant uncompress() { assert compressed : this; - return new ImageHeapObjectArray(type, hostedObject, arrayElementValues, identityHashCode, false); + return new ImageHeapObjectArray(type, hostedObject, arrayElementValuesRef, length, identityHashCode, false); } @Override public ImageHeapConstant forObjectClone() { assert type.isCloneableWithAllocation() : "all arrays implement Cloneable"; - Object[] newArrayElementValues = Arrays.copyOf(arrayElementValues, arrayElementValues.length); + Object[] newArrayElementValues = Arrays.copyOf(arrayElementValuesRef.get(), arrayElementValuesRef.get().length); /* The new constant is never backed by a hosted object, regardless of the input object. */ JavaConstant newObject = null; - return new ImageHeapObjectArray(type, newObject, newArrayElementValues, createIdentityHashCode(newObject), compressed); + return new ImageHeapObjectArray(type, newObject, newArrayElementValues, length, createIdentityHashCode(newObject), compressed); } @Override public boolean equals(Object o) { if (o instanceof ImageHeapObjectArray) { - return super.equals(o) && this.arrayElementValues == ((ImageHeapObjectArray) o).arrayElementValues; + return super.equals(o) && this.arrayElementValuesRef == ((ImageHeapObjectArray) o).arrayElementValuesRef; } return false; } @@ -132,7 +151,7 @@ public boolean equals(Object o) { public int hashCode() { final int prime = 31; int result = super.hashCode(); - result = prime * result + System.identityHashCode(arrayElementValues); + result = prime * result + System.identityHashCode(arrayElementValuesRef); return result; } } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java index e602a70397e6..aa9a8432bdfe 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java @@ -33,10 +33,6 @@ import org.graalvm.collections.EconomicMap; import org.graalvm.collections.MapCursor; -import jdk.graal.compiler.api.replacements.SnippetReflectionProvider; -import jdk.graal.compiler.core.common.SuppressFBWarnings; -import jdk.graal.compiler.core.common.type.TypedConstant; -import jdk.graal.compiler.debug.GraalError; import com.oracle.graal.pointsto.BigBang; import com.oracle.graal.pointsto.ObjectScanner; @@ -59,6 +55,10 @@ import com.oracle.graal.pointsto.util.GraalAccess; import com.oracle.svm.util.ReflectionUtil; +import jdk.graal.compiler.api.replacements.SnippetReflectionProvider; +import jdk.graal.compiler.core.common.SuppressFBWarnings; +import jdk.graal.compiler.core.common.type.TypedConstant; +import jdk.graal.compiler.debug.GraalError; import jdk.vm.ci.code.BytecodePosition; import jdk.vm.ci.meta.ConstantReflectionProvider; import jdk.vm.ci.meta.JavaConstant; @@ -252,40 +252,53 @@ protected ImageHeapConstant createImageHeapObject(JavaConstant constant, ScanRea private ImageHeapArray createImageHeapObjectArray(JavaConstant constant, AnalysisType type, int length, ScanReason reason) { ImageHeapObjectArray array = new ImageHeapObjectArray(type, constant, length); - ScanReason arrayReason = new ArrayScan(type, constant, reason); - for (int idx = 0; idx < length; idx++) { - final JavaConstant rawElementValue = constantReflection.readArrayElement(constant, idx); - int finalIdx = idx; - array.setElementTask(idx, new AnalysisFuture<>(() -> { - JavaConstant arrayElement = createImageHeapConstant(rawElementValue, arrayReason); - array.setElement(finalIdx, arrayElement); - return arrayElement; - })); - } + /* Read hosted array element values only when the array is initialized. */ + AnalysisFuture hostedElementsReader = new AnalysisFuture<>(() -> { + type.registerAsReachable(reason); + ScanReason arrayReason = new ArrayScan(type, constant, reason); + Object[] elementValues = new Object[length]; + for (int idx = 0; idx < length; idx++) { + final JavaConstant rawElementValue = constantReflection.readArrayElement(constant, idx); + int finalIdx = idx; + elementValues[idx] = new AnalysisFuture<>(() -> { + JavaConstant arrayElement = createImageHeapConstant(rawElementValue, arrayReason); + array.setElement(finalIdx, arrayElement); + return arrayElement; + }); + } + array.setElementValues(elementValues); + }); + array.hostedValuesReader = hostedElementsReader; return array; } private ImageHeapInstance createImageHeapInstance(JavaConstant constant, AnalysisType type, ScanReason reason) { - /* We are about to query the type's fields, the type must be marked as reachable. */ - type.registerAsReachable(reason); - ResolvedJavaField[] instanceFields = type.getInstanceFields(true); - ImageHeapInstance instance = new ImageHeapInstance(type, constant, instanceFields.length); - for (ResolvedJavaField javaField : instanceFields) { - AnalysisField field = (AnalysisField) javaField; - ValueSupplier rawFieldValue; - try { - rawFieldValue = readHostedFieldValue(field, universe.toHosted(constant)); - } catch (InternalError | TypeNotPresentException | LinkageError e) { - /* Ignore missing type errors. */ - continue; + ImageHeapInstance instance = new ImageHeapInstance(type, constant); + /* Read hosted field values only when the receiver is initialized. */ + AnalysisFuture hostedFieldReader = new AnalysisFuture<>(() -> { + /* We are about to query the type's fields, the type must be marked as reachable. */ + type.registerAsReachable(reason); + ResolvedJavaField[] instanceFields = type.getInstanceFields(true); + Object[] hostedFieldValues = new Object[instanceFields.length]; + for (ResolvedJavaField javaField : instanceFields) { + AnalysisField field = (AnalysisField) javaField; + ValueSupplier rawFieldValue; + try { + rawFieldValue = readHostedFieldValue(field, universe.toHosted(constant)); + } catch (InternalError | TypeNotPresentException | LinkageError e) { + /* Ignore missing type errors. */ + continue; + } + hostedFieldValues[field.getPosition()] = new AnalysisFuture<>(() -> { + ScanReason fieldReason = new FieldScan(field, constant, reason); + JavaConstant value = createFieldValue(field, instance, rawFieldValue, fieldReason); + instance.setFieldValue(field, value); + return value; + }); } - instance.setFieldTask(field, new AnalysisFuture<>(() -> { - ScanReason fieldReason = new FieldScan(field, constant, reason); - JavaConstant value = createFieldValue(field, instance, rawFieldValue, fieldReason); - instance.setFieldValue(field, value); - return value; - })); - } + instance.setFieldValues(hostedFieldValues); + }); + instance.hostedValuesReader = hostedFieldReader; return instance; } @@ -349,7 +362,8 @@ JavaConstant onFieldValueReachable(AnalysisField field, ImageHeapInstance receiv } JavaConstant onFieldValueReachable(AnalysisField field, ImageHeapInstance receiver, ValueSupplier rawValue, ScanReason reason, Consumer onAnalysisModified) { - AnalysisError.guarantee(field.isReachable(), "Field value is only reachable when field is reachable: %s", field); + // Static field can be read for constant folding before being marked as reachable. + AnalysisError.guarantee(field.isStatic() || field.isReachable(), "Field value is only reachable when field is reachable: %s", field); JavaConstant fieldValue = createFieldValue(field, receiver, rawValue, reason); markReachable(fieldValue, reason, onAnalysisModified); notifyAnalysis(field, receiver, fieldValue, reason, onAnalysisModified); @@ -550,13 +564,27 @@ public void rescanField(Object receiver, Field reflectionField) { ImageHeapInstance receiverObject = (ImageHeapInstance) toImageHeapObject(receiverConstant, OtherReason.RESCAN); AnalysisFuture fieldTask = patchInstanceField(receiverObject, field, fieldValue, OtherReason.RESCAN, null); if (field.isRead() || field.isFolded()) { - rescanCollectionElements(fieldTask.ensureDone()); + JavaConstant constant = fieldTask.ensureDone(); + ensureReaderInstalled(constant); + rescanCollectionElements(constant); } } } }); } + /** + * For image heap constants created during verification, i.e., either correct values set lazily + * but for which the {@link ImageHeapConstant} was not yet created or values created by patching + * a wrong snapshot, we need to manually ensure that the readers are installed since the + * verification will continue expanding them. + */ + static void ensureReaderInstalled(JavaConstant constant) { + if (constant.getJavaKind() == JavaKind.Object && constant.isNonNull()) { + ((ImageHeapConstant) constant).ensureReaderInstalled(); + } + } + protected AnalysisFuture patchStaticField(TypeData typeData, AnalysisField field, JavaConstant fieldValue, ScanReason reason, Consumer onAnalysisModified) { AnalysisFuture task = new AnalysisFuture<>(() -> { JavaConstant value = onFieldValueReachable(field, fieldValue, reason, onAnalysisModified); diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/util/AnalysisFuture.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/util/AnalysisFuture.java index 9188cf9493fc..10221ac4ab8d 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/util/AnalysisFuture.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/util/AnalysisFuture.java @@ -37,6 +37,10 @@ public AnalysisFuture(Callable callable) { super(callable); } + public AnalysisFuture(Runnable runnable) { + super(runnable, null); + } + public AnalysisFuture(Runnable runnable, V result) { super(runnable, result); } diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/GraalGraphObjectReplacer.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/GraalGraphObjectReplacer.java index 662fbc7b8590..4d92ce3d8986 100644 --- a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/GraalGraphObjectReplacer.java +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/GraalGraphObjectReplacer.java @@ -462,6 +462,7 @@ public void updateSubstrateDataAfterCompilation(HostedUniverse hUniverse, Provid JavaConstant constantValue = hField.isStatic() && ((HostedConstantFieldProvider) providers.getConstantFieldProvider()).isFinalField(hField, null) ? providers.getConstantReflection().readFieldValue(hField, null) : null; + constantValue = providers.getSnippetReflection().unwrapConstant(constantValue); sField.setSubstrateData(hField.getLocation(), hField.isAccessed(), hField.isWritten() || !hField.isValueAvailable(), constantValue); } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantReflectionProvider.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantReflectionProvider.java index 906840657422..e77179f45a5b 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantReflectionProvider.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantReflectionProvider.java @@ -123,6 +123,7 @@ public JavaConstant unboxPrimitive(JavaConstant source) { */ AnalysisType type = (AnalysisType) imageHeapConstant.getType(metaAccess); if (BOXING_CLASSES.contains(type.getJavaClass())) { + imageHeapConstant.ensureReaderInstalled(); ResolvedJavaField[] fields = type.getInstanceFields(true); assert fields.length == 1 && fields[0].getName().equals("value"); return ((ImageHeapInstance) imageHeapConstant).readFieldValue((AnalysisField) fields[0]); @@ -144,8 +145,8 @@ public Integer readArrayLength(JavaConstant array) { return null; } if (array instanceof ImageHeapConstant) { - if (array instanceof ImageHeapArray) { - return ((ImageHeapArray) array).getLength(); + if (array instanceof ImageHeapArray heapArray) { + return heapArray.getLength(); } return null; } @@ -162,6 +163,7 @@ public JavaConstant readArrayElement(JavaConstant array, int index) { if (index < 0 || index >= heapArray.getLength()) { return null; } + heapArray.ensureReaderInstalled(); return replaceObject(heapArray.readElementValue(index)); } return null; @@ -174,6 +176,7 @@ public JavaConstant readArrayElement(JavaConstant array, int index) { public void forEachArrayElement(JavaConstant array, ObjIntConsumer consumer) { if (array instanceof ImageHeapConstant) { if (array instanceof ImageHeapArray heapArray) { + heapArray.ensureReaderInstalled(); for (int index = 0; index < heapArray.getLength(); index++) { JavaConstant element = heapArray.readElementValue(index); consumer.accept(replaceObject(element), index); @@ -191,6 +194,10 @@ public JavaConstant readFieldValue(ResolvedJavaField field, JavaConstant receive } public JavaConstant readValue(UniverseMetaAccess suppliedMetaAccess, AnalysisField field, JavaConstant receiver, boolean returnSimulatedValues) { + return readValue(suppliedMetaAccess, field, receiver, returnSimulatedValues, true); + } + + public JavaConstant readValue(UniverseMetaAccess suppliedMetaAccess, AnalysisField field, JavaConstant receiver, boolean returnSimulatedValues, boolean readFromShadowHeap) { if (!field.isStatic()) { if (receiver.isNull() || !field.getDeclaringClass().isAssignableFrom(((TypedConstant) receiver).getType(metaAccess))) { /* @@ -210,7 +217,24 @@ public JavaConstant readValue(UniverseMetaAccess suppliedMetaAccess, AnalysisFie if (returnSimulatedValues) { value = readSimulatedValue(field); } - if (value == null && receiver instanceof ImageHeapConstant) { + if (value == null && field.isStatic() && returnSimulatedValues && readFromShadowHeap) { + /* + * The shadow heap uses simulated values for static fields by default. So, only when + * simulated values are explicitly requested we can read via the shadow heap. Otherwise, + * this will lead to recursive parsing request errors. + */ + if (SimulateClassInitializerSupport.singleton().isEnabled()) { + /* + * The "late initialization" doesn't work with heap snapshots because the wrong + * value will be snapshot for classes proven late, so we only read via the shadow + * heap if simulation of class initializers is enabled. The check and this comment + * will be removed when the old initialization strategy is removed. + */ + value = field.getDeclaringClass().getOrComputeData().readFieldValue(field); + } + } + if (value == null && receiver instanceof ImageHeapConstant heapConstant) { + heapConstant.ensureReaderInstalled(); AnalysisError.guarantee(ReadableJavaField.isValueAvailable(field), "Value not yet available for %s", field); ImageHeapInstance heapObject = (ImageHeapInstance) receiver; value = heapObject.readFieldValue(field); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/CGlobalDataFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/CGlobalDataFeature.java index 05e57d0f36fc..741315a0a6dd 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/CGlobalDataFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/CGlobalDataFeature.java @@ -130,7 +130,7 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec JavaConstant nonConstantRegistryJavaConstant = snippetReflection.forObject(nonConstantRegistry); ValueNode cGlobalDataNode = receiver.get(); if (cGlobalDataNode.isConstant()) { - CGlobalDataImpl data = providers.getSnippetReflection().asObject(CGlobalDataImpl.class, cGlobalDataNode.asJavaConstant()); + CGlobalDataImpl data = snippetReflection.asObject(CGlobalDataImpl.class, cGlobalDataNode.asJavaConstant()); CGlobalDataInfo info = CGlobalDataFeature.this.map.get(data); b.addPush(targetMethod.getSignature().getReturnKind(), new CGlobalDataLoadAddressNode(info)); } else { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageHeapVerifier.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageHeapVerifier.java index a2409d35d082..e0de60c7d63a 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageHeapVerifier.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageHeapVerifier.java @@ -95,7 +95,11 @@ private static final class VerifierObjectScanner extends ObjectScanner { @Override protected JavaConstant readFieldValue(AnalysisField field, JavaConstant receiver) { AnalysisConstantReflectionProvider constantReflectionProvider = (AnalysisConstantReflectionProvider) bb.getConstantReflectionProvider(); - return constantReflectionProvider.readValue(metaAccess, field, receiver, true); + /* + * The verifier compares the hosted values with the ones from the shadow heap, so the + * constant reflection must not return shadow heap values. + */ + return constantReflectionProvider.readValue(metaAccess, field, receiver, true, false); } } From fc9affa656214685f295ab06e22fb81ea646e6f4 Mon Sep 17 00:00:00 2001 From: Codrut Stancu Date: Tue, 31 Oct 2023 14:10:30 +0100 Subject: [PATCH 06/11] Refactor ImageHeapConstant. --- .../graal/pointsto/heap/ImageHeapArray.java | 7 +- .../pointsto/heap/ImageHeapConstant.java | 111 +++++++++++------- .../pointsto/heap/ImageHeapInstance.java | 97 +++++++-------- .../pointsto/heap/ImageHeapObjectArray.java | 97 +++++++-------- .../heap/ImageHeapPrimitiveArray.java | 65 +++++----- .../graal/pointsto/heap/ImageHeapScanner.java | 6 +- .../com/oracle/svm/util/ReflectionUtil.java | 12 ++ 7 files changed, 218 insertions(+), 177 deletions(-) diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapArray.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapArray.java index 815c03e12ea2..0bc8f603b24a 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapArray.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapArray.java @@ -27,7 +27,6 @@ import com.oracle.graal.pointsto.meta.AnalysisType; import jdk.vm.ci.meta.JavaConstant; -import jdk.vm.ci.meta.ResolvedJavaType; public abstract class ImageHeapArray extends ImageHeapConstant { @@ -36,9 +35,9 @@ public static ImageHeapArray create(AnalysisType type, int length) { return type.getComponentType().getStorageKind().isPrimitive() ? new ImageHeapPrimitiveArray(type, length) : new ImageHeapObjectArray(type, length); } - protected ImageHeapArray(ResolvedJavaType type, JavaConstant object, int identityHashCode, boolean compressed) { - super(type, object, identityHashCode, compressed); - assert type.isArray() : type; + protected ImageHeapArray(ConstantData constantData, boolean compressed) { + super(constantData, compressed); + assert constantData.type.isArray() : constantData.type; } public abstract Object getElement(int idx); diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapConstant.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapConstant.java index d23fdb08dcce..5bef16d477ff 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapConstant.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapConstant.java @@ -24,15 +24,16 @@ */ package com.oracle.graal.pointsto.heap; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.VarHandle; import java.util.Objects; -import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; import com.oracle.graal.pointsto.ObjectScanner; import com.oracle.graal.pointsto.util.AnalysisFuture; -import com.oracle.graal.pointsto.util.AtomicUtils; +import com.oracle.svm.util.ReflectionUtil; import jdk.graal.compiler.core.common.type.CompressibleConstant; import jdk.graal.compiler.core.common.type.TypedConstant; @@ -50,40 +51,64 @@ */ @Platforms(Platform.HOSTED_ONLY.class) public abstract class ImageHeapConstant implements JavaConstant, TypedConstant, CompressibleConstant, VMConstant { - /** Stores the type of this object. */ - protected final ResolvedJavaType type; - /** - * Stores the hosted object, already processed by the object transformers. It is null for - * instances of partially evaluated classes. - */ - protected final JavaConstant hostedObject; - protected final int identityHashCode; - - protected final boolean compressed; - @SuppressWarnings("unused") private volatile Object isReachable; + public static final VarHandle isReachableHandle = ReflectionUtil.unreflectField(ConstantData.class, "isReachable", MethodHandles.lookup()); + + public abstract static class ConstantData { + /** + * Stores the type of this object. + */ + protected final ResolvedJavaType type; + /** + * Stores the hosted object, already processed by the object transformers. It is null for + * instances of partially evaluated classes. + */ + protected final JavaConstant hostedObject; + /** + * See {@link #createIdentityHashCode(JavaConstant)}. + */ + protected final int identityHashCode; + /** + * A future that reads the hosted field or array elements values lazily only when the + * receiver object is used. This way the shadow heap can contain hosted only objects, i.e., + * objects that cannot be reachable at run time but are processed ahead-of-time. + */ + protected AnalysisFuture hostedValuesReader; + /** + * A constant is marked as reachable only when it is decided that it can be used at run-time + * and its field values/array elements need to be processed. The value of the field is + * initially null, then it stores the reason why this constant became reachable. + */ + @SuppressWarnings("unused") private volatile Object isReachable; + + ConstantData(ResolvedJavaType type, JavaConstant object, int identityHashCode) { + Objects.requireNonNull(type); + this.type = type; + this.hostedObject = object; + this.identityHashCode = identityHashCode; + } - /** - * A future that reads the hosted field or array elements values lazily only when the receiver - * object is used. This way the shadow heap can contain hosted only objects, i.e., objects that - * cannot be reachable at run time but are processed ahead-of-time. - */ - protected AnalysisFuture hostedValuesReader; + @Override + public int hashCode() { + return hostedObject != null ? hostedObject.hashCode() : super.hashCode(); + } + } - private static final AtomicReferenceFieldUpdater isReachableUpdater = AtomicReferenceFieldUpdater - .newUpdater(ImageHeapConstant.class, Object.class, "isReachable"); + protected final ConstantData constantData; + protected final boolean compressed; - ImageHeapConstant(ResolvedJavaType type, JavaConstant object, int identityHashCode, boolean compressed) { - Objects.requireNonNull(type); - this.type = type; - this.hostedObject = object; - this.identityHashCode = identityHashCode; + ImageHeapConstant(ConstantData constantData, boolean compressed) { + this.constantData = constantData; this.compressed = compressed; } + public ConstantData getConstantData() { + return constantData; + } + public void ensureReaderInstalled() { - if (hostedValuesReader != null) { - hostedValuesReader.ensureDone(); + if (constantData.hostedValuesReader != null) { + constantData.hostedValuesReader.ensureDone(); } } @@ -97,16 +122,16 @@ public void ensureReaderInstalled() { * Simulated constants are fully initialized when they are created. */ protected boolean isReaderInstalled() { - return hostedValuesReader == null || hostedValuesReader.isDone(); + return constantData.hostedValuesReader == null || constantData.hostedValuesReader.isDone(); } public boolean markReachable(ObjectScanner.ScanReason reason) { ensureReaderInstalled(); - return AtomicUtils.atomicSet(this, reason, isReachableUpdater); + return isReachableHandle.compareAndSet(constantData, null, reason); } public boolean isReachable() { - return AtomicUtils.isSet(this, isReachableUpdater); + return isReachableHandle.get(constantData) != null; } static int createIdentityHashCode(JavaConstant object) { @@ -125,15 +150,15 @@ static int createIdentityHashCode(JavaConstant object) { @Override public int getIdentityHashCode() { - if (hostedObject != null) { - if (hostedObject.isNull()) { + if (constantData.hostedObject != null) { + if (constantData.hostedObject.isNull()) { /* * According to the JavaDoc of System.identityHashCode, the identity hash code of * null is 0. */ return 0; } else { - return ((TypedConstant) hostedObject).getIdentityHashCode(); + return ((TypedConstant) constantData.hostedObject).getIdentityHashCode(); } } else { /* @@ -141,17 +166,17 @@ public int getIdentityHashCode() { * hash code that has the same properties as the image builder VM, so we use the * identity hash code of a new and otherwise unused object in the image builder VM. */ - assert identityHashCode > 0 : "The Java HotSpot VM only returns positive numbers for the identity hash code, so we want to have the same restriction on Substrate VM in order to not surprise users"; - return identityHashCode; + assert constantData.identityHashCode > 0 : "The Java HotSpot VM only returns positive numbers for the identity hash code, so we want to have the same restriction on Substrate VM in order to not surprise users"; + return constantData.identityHashCode; } } public JavaConstant getHostedObject() { - return hostedObject; + return constantData.hostedObject; } public boolean isBackedByHostedObject() { - return hostedObject != null; + return constantData.hostedObject != null; } @Override @@ -171,7 +196,7 @@ public boolean isDefaultForKind() { @Override public ResolvedJavaType getType(MetaAccessProvider provider) { - return type; + return constantData.type; } @Override @@ -211,7 +236,7 @@ public boolean isCompressed() { @Override public String toValueString() { - return type.getName(); + return constantData.type.getName(); } /** @@ -228,18 +253,18 @@ public boolean equals(Object o) { * the previous behavior where the raw object was extracted and used as a key when * constructing the image heap map. */ - return Objects.equals(this.type, other.type) && Objects.equals(this.hostedObject, other.hostedObject); + return this.constantData == other.constantData; } return false; } @Override public int hashCode() { - return hostedObject != null ? hostedObject.hashCode() : 0; + return constantData.hashCode(); } @Override public String toString() { - return "ImageHeapConstant< " + type.toJavaName() + ", reachable: " + isReachable() + ", reader installed: " + isReaderInstalled() + ">"; + return "ImageHeapConstant< " + constantData.type.toJavaName() + ", reachable: " + isReachable() + ", reader installed: " + isReaderInstalled() + ">"; } } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapInstance.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapInstance.java index e2e88cde1bb7..00236dfd42a5 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapInstance.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapInstance.java @@ -27,13 +27,14 @@ import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import java.util.Arrays; -import java.util.concurrent.atomic.AtomicReference; +import java.util.Objects; import com.oracle.graal.pointsto.ObjectScanner; import com.oracle.graal.pointsto.heap.value.ValueSupplier; import com.oracle.graal.pointsto.meta.AnalysisField; import com.oracle.graal.pointsto.util.AnalysisError; import com.oracle.graal.pointsto.util.AnalysisFuture; +import com.oracle.svm.util.ReflectionUtil; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.ResolvedJavaType; @@ -52,23 +53,36 @@ public final class ImageHeapInstance extends ImageHeapConstant { private static final VarHandle arrayHandle = MethodHandles.arrayElementVarHandle(Object[].class); + public static final VarHandle valuesHandle = ReflectionUtil.unreflectField(InstanceData.class, "fieldValues", MethodHandles.lookup()); + + public static class InstanceData extends ConstantData { + + /** + * The field values array. It is only set when the constant is actually used and the hosted + * values of its fields/elements may be read. + * + * Each value is either an {@link AnalysisFuture} of {@link JavaConstant} or its result, a + * {@link JavaConstant}, indexed by {@link AnalysisField#getPosition()}. + *

+ * Evaluating the {@link AnalysisFuture} runs + * {@link ImageHeapScanner#createFieldValue(AnalysisField, ImageHeapInstance, ValueSupplier, ObjectScanner.ScanReason)} + * which adds the result to the image heap. + */ + private Object[] fieldValues; + + InstanceData(ResolvedJavaType type, JavaConstant object, int identityHashCode) { + super(type, object, identityHashCode); + } - /** - * A reference to the field values array. It is only set when the constant is actually used and - * the hosted values of its fields/elements may be read. - * - * Each value is either an {@link AnalysisFuture} of {@link JavaConstant} or its result, a - * {@link JavaConstant}, indexed by {@link AnalysisField#getPosition()}. - *

- * Evaluating the {@link AnalysisFuture} runs - * {@link ImageHeapScanner#createFieldValue(AnalysisField, ImageHeapInstance, ValueSupplier, ObjectScanner.ScanReason)} - * which adds the result to the image heap. - */ - private final AtomicReference fieldValuesRef; + InstanceData(ResolvedJavaType type, JavaConstant object, int identityHashCode, Object[] fieldValues) { + super(type, object, identityHashCode); + this.fieldValues = fieldValues; + } + + } ImageHeapInstance(ResolvedJavaType type, JavaConstant object) { - super(type, object, createIdentityHashCode(object), false); - this.fieldValuesRef = new AtomicReference<>(); + super(new InstanceData(type, object, createIdentityHashCode(object)), false); } public ImageHeapInstance(ResolvedJavaType type) { @@ -76,21 +90,24 @@ public ImageHeapInstance(ResolvedJavaType type) { } private ImageHeapInstance(ResolvedJavaType type, JavaConstant object, int length) { - this(type, object, new Object[length], createIdentityHashCode(object), false); + this(type, object, createIdentityHashCode(object), new Object[length], false); + } + + private ImageHeapInstance(ResolvedJavaType type, JavaConstant object, int identityHashCode, Object[] fieldValues, boolean compressed) { + super(new InstanceData(type, object, identityHashCode, fieldValues), compressed); } - private ImageHeapInstance(ResolvedJavaType type, JavaConstant object, Object[] fieldValues, int identityHashCode, boolean compressed) { - super(type, object, identityHashCode, compressed); - this.fieldValuesRef = new AtomicReference<>(fieldValues); + ImageHeapInstance(ConstantData data, boolean compressed) { + super(data, compressed); } - private ImageHeapInstance(ResolvedJavaType type, JavaConstant object, AtomicReference fieldValuesRef, int identityHashCode, boolean compressed) { - super(type, object, identityHashCode, compressed); - this.fieldValuesRef = fieldValuesRef; + @Override + public InstanceData getConstantData() { + return (InstanceData) super.getConstantData(); } void setFieldValues(Object[] fieldValues) { - boolean success = this.fieldValuesRef.compareAndSet(null, fieldValues); + boolean success = valuesHandle.compareAndSet(constantData, null, fieldValues); AnalysisError.guarantee(success, "Unexpected field values reference for constant %s", this); } @@ -100,7 +117,7 @@ void setFieldValues(Object[] fieldValues) { */ void setFieldTask(AnalysisField field, AnalysisFuture task) { AnalysisError.guarantee(isReaderInstalled()); - arrayHandle.setVolatile(this.fieldValuesRef.get(), field.getPosition(), task); + arrayHandle.setVolatile(valuesHandle.get(constantData), field.getPosition(), task); } /** @@ -110,7 +127,7 @@ void setFieldTask(AnalysisField field, AnalysisFuture task) { */ public void setFieldValue(AnalysisField field, JavaConstant value) { AnalysisError.guarantee(isReaderInstalled()); - arrayHandle.setVolatile(this.fieldValuesRef.get(), field.getPosition(), value); + arrayHandle.setVolatile(valuesHandle.get(constantData), field.getPosition(), value); } /** @@ -120,7 +137,7 @@ public void setFieldValue(AnalysisField field, JavaConstant value) { */ public Object getFieldValue(AnalysisField field) { AnalysisError.guarantee(isReaderInstalled()); - return arrayHandle.getVolatile(this.fieldValuesRef.get(), field.getPosition()); + return arrayHandle.getVolatile(valuesHandle.get(constantData), field.getPosition()); } /** @@ -136,40 +153,26 @@ public JavaConstant readFieldValue(AnalysisField field) { @Override public JavaConstant compress() { assert !compressed : this; - return new ImageHeapInstance(type, hostedObject, fieldValuesRef, identityHashCode, true); + return new ImageHeapInstance(constantData, true); } @Override public JavaConstant uncompress() { assert compressed : this; - return new ImageHeapInstance(type, hostedObject, fieldValuesRef, identityHashCode, false); + return new ImageHeapInstance(constantData, false); } @Override public ImageHeapConstant forObjectClone() { - if (!type.isCloneableWithAllocation()) { + if (!constantData.type.isCloneableWithAllocation()) { return null; } - Object[] newFieldValues = Arrays.copyOf(fieldValuesRef.get(), fieldValuesRef.get().length); + Object[] fieldValues = getConstantData().fieldValues; + Objects.requireNonNull(fieldValues, "Cannot clone an instance before the field values are set."); + Object[] newFieldValues = Arrays.copyOf(fieldValues, fieldValues.length); /* The new constant is never backed by a hosted object, regardless of the input object. */ JavaConstant newObject = null; - return new ImageHeapInstance(type, newObject, newFieldValues, createIdentityHashCode(newObject), compressed); - } - - @Override - public boolean equals(Object o) { - if (o instanceof ImageHeapInstance) { - return super.equals(o) && this.fieldValuesRef == ((ImageHeapInstance) o).fieldValuesRef; - } - return false; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = super.hashCode(); - result = prime * result + System.identityHashCode(fieldValuesRef); - return result; + return new ImageHeapInstance(constantData.type, newObject, createIdentityHashCode(newObject), newFieldValues, compressed); } } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapObjectArray.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapObjectArray.java index 9dcdd5c0f0ae..d4f08dff1fdf 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapObjectArray.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapObjectArray.java @@ -27,13 +27,14 @@ import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import java.util.Arrays; -import java.util.concurrent.atomic.AtomicReference; +import java.util.Objects; import java.util.function.Consumer; import com.oracle.graal.pointsto.ObjectScanner; import com.oracle.graal.pointsto.meta.AnalysisType; import com.oracle.graal.pointsto.util.AnalysisError; import com.oracle.graal.pointsto.util.AnalysisFuture; +import com.oracle.svm.util.ReflectionUtil; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.ResolvedJavaType; @@ -41,42 +42,58 @@ public final class ImageHeapObjectArray extends ImageHeapArray { private static final VarHandle arrayHandle = MethodHandles.arrayElementVarHandle(Object[].class); + private static final VarHandle elementsHandle = ReflectionUtil.unreflectField(ArrayData.class, "arrayElementValues", MethodHandles.lookup()); - final int length; - /** - * A reference to the element values array. It is only set when the constant is initialized. - * Each value is either an {@link AnalysisFuture} of {@link JavaConstant} or its result, a - * {@link JavaConstant}, indexed by array index. - */ - private final AtomicReference arrayElementValuesRef; + public static class ArrayData extends ConstantData { - ImageHeapObjectArray(ResolvedJavaType type, int length) { - this(type, null, new Object[length], length); + /** + * The element values array. It is only set when the constant is initialized. Each value is + * either an {@link AnalysisFuture} of {@link JavaConstant} or its result, a + * {@link JavaConstant}, indexed by array index. + */ + private Object[] arrayElementValues; + + final int length; + + public ArrayData(ResolvedJavaType type, JavaConstant object, int identityHashCode, int length) { + super(type, object, identityHashCode); + this.length = length; + } + + public ArrayData(ResolvedJavaType type, JavaConstant object, int identityHashCode, Object[] arrayElementValues, int length) { + super(type, object, identityHashCode); + this.arrayElementValues = arrayElementValues; + this.length = length; + } } ImageHeapObjectArray(ResolvedJavaType type, JavaConstant object, int length) { - this(type, object, null, length); + super(new ArrayData(type, object, createIdentityHashCode(object), length), false); + } + + ImageHeapObjectArray(ResolvedJavaType type, int length) { + this(type, null, new Object[length], length); } ImageHeapObjectArray(ResolvedJavaType type, JavaConstant object, Object[] arrayElementValues, int length) { - this(type, object, arrayElementValues, length, createIdentityHashCode(object), false); + this(type, object, createIdentityHashCode(object), arrayElementValues, length, false); + } + + private ImageHeapObjectArray(ResolvedJavaType type, JavaConstant object, int identityHashCode, Object[] arrayElementValues, int length, boolean compressed) { + super(new ArrayData(type, object, identityHashCode, arrayElementValues, length), compressed); } - private ImageHeapObjectArray(ResolvedJavaType type, JavaConstant object, Object[] arrayElementValues, int length, int identityHashCode, boolean compressed) { - super(type, object, identityHashCode, compressed); - this.arrayElementValuesRef = new AtomicReference<>(arrayElementValues); - this.length = length; + ImageHeapObjectArray(ConstantData data, boolean compressed) { + super(data, compressed); } - private ImageHeapObjectArray(ResolvedJavaType type, JavaConstant object, AtomicReference arrayElementValuesRef, int length, int identityHashCode, boolean compressed) { - super(type, object, identityHashCode, compressed); - assert type.isArray() : type; - this.arrayElementValuesRef = arrayElementValuesRef; - this.length = length; + @Override + public ArrayData getConstantData() { + return (ArrayData) super.getConstantData(); } void setElementValues(Object[] elementValues) { - boolean success = this.arrayElementValuesRef.compareAndSet(null, elementValues); + boolean success = elementsHandle.compareAndSet(constantData, null, elementValues); AnalysisError.guarantee(success, "Unexpected field values reference for constant %s", this); } @@ -87,7 +104,7 @@ void setElementValues(Object[] elementValues) { @Override public Object getElement(int idx) { AnalysisError.guarantee(isReaderInstalled()); - return arrayHandle.getVolatile(this.arrayElementValuesRef.get(), idx); + return arrayHandle.getVolatile(elementsHandle.get(constantData), idx); } /** @@ -104,54 +121,40 @@ public JavaConstant readElementValue(int index) { @Override public void setElement(int idx, JavaConstant value) { AnalysisError.guarantee(isReaderInstalled()); - arrayHandle.setVolatile(this.arrayElementValuesRef.get(), idx, value); + arrayHandle.setVolatile(elementsHandle.get(constantData), idx, value); } void setElementTask(int idx, AnalysisFuture task) { AnalysisError.guarantee(isReaderInstalled()); - arrayHandle.setVolatile(this.arrayElementValuesRef.get(), idx, task); + arrayHandle.setVolatile(elementsHandle.get(constantData), idx, task); } @Override public int getLength() { - return length; + return getConstantData().length; } @Override public JavaConstant compress() { assert !compressed : this; - return new ImageHeapObjectArray(type, hostedObject, arrayElementValuesRef, length, identityHashCode, true); + return new ImageHeapObjectArray(constantData, true); } @Override public JavaConstant uncompress() { assert compressed : this; - return new ImageHeapObjectArray(type, hostedObject, arrayElementValuesRef, length, identityHashCode, false); + return new ImageHeapObjectArray(constantData, false); } @Override public ImageHeapConstant forObjectClone() { - assert type.isCloneableWithAllocation() : "all arrays implement Cloneable"; + assert constantData.type.isCloneableWithAllocation() : "all arrays implement Cloneable"; - Object[] newArrayElementValues = Arrays.copyOf(arrayElementValuesRef.get(), arrayElementValuesRef.get().length); + ArrayData arrayData = getConstantData(); + Objects.requireNonNull(arrayData.arrayElementValues, "Cannot clone an array before the element values are set."); + Object[] newArrayElementValues = Arrays.copyOf(arrayData.arrayElementValues, arrayData.arrayElementValues.length); /* The new constant is never backed by a hosted object, regardless of the input object. */ JavaConstant newObject = null; - return new ImageHeapObjectArray(type, newObject, newArrayElementValues, length, createIdentityHashCode(newObject), compressed); - } - - @Override - public boolean equals(Object o) { - if (o instanceof ImageHeapObjectArray) { - return super.equals(o) && this.arrayElementValuesRef == ((ImageHeapObjectArray) o).arrayElementValuesRef; - } - return false; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = super.hashCode(); - result = prime * result + System.identityHashCode(arrayElementValuesRef); - return result; + return new ImageHeapObjectArray(constantData.type, newObject, createIdentityHashCode(newObject), newArrayElementValues, arrayData.length, compressed); } } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapPrimitiveArray.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapPrimitiveArray.java index 9b4c17d61193..7480fee57b3e 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapPrimitiveArray.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapPrimitiveArray.java @@ -37,8 +37,21 @@ public final class ImageHeapPrimitiveArray extends ImageHeapArray { - private final Object array; - private final int length; + public ImageHeapPrimitiveArray(ConstantData constantData, boolean compressed) { + super(constantData, compressed); + } + + public static class PrimitiveArrayData extends ConstantData { + + private final Object array; + private final int length; + + public PrimitiveArrayData(ResolvedJavaType type, JavaConstant object, int identityHashCode, Object array, int length) { + super(type, object, identityHashCode); + this.array = array; + this.length = length; + } + } ImageHeapPrimitiveArray(AnalysisType type, int length) { this(type, null, @@ -55,10 +68,13 @@ public final class ImageHeapPrimitiveArray extends ImageHeapArray { } private ImageHeapPrimitiveArray(ResolvedJavaType type, JavaConstant hostedObject, Object array, int identityHashCode, boolean compressed, int length) { - super(type, hostedObject, identityHashCode, compressed); + super(new PrimitiveArrayData(type, hostedObject, identityHashCode, array, length), compressed); assert type.isArray() && type.getComponentType().isPrimitive() : type; - this.array = array; - this.length = length; + } + + @Override + public PrimitiveArrayData getConstantData() { + return (PrimitiveArrayData) super.getConstantData(); } private static Object getClone(JavaKind kind, Object arrayObject) { @@ -76,7 +92,7 @@ private static Object getClone(JavaKind kind, Object arrayObject) { } public Object getArray() { - return array; + return getConstantData().array; } /** @@ -90,57 +106,42 @@ public Object getElement(int idx) { @Override public JavaConstant readElementValue(int idx) { - return JavaConstant.forBoxedPrimitive(Array.get(array, idx)); + return JavaConstant.forBoxedPrimitive(Array.get(getArray(), idx)); } @Override public void setElement(int idx, JavaConstant value) { - if (value.getJavaKind() != type.getComponentType().getJavaKind()) { - throw AnalysisError.shouldNotReachHere("Cannot store value of kind " + value.getJavaKind() + " into primitive array of type " + type); + if (value.getJavaKind() != constantData.type.getComponentType().getJavaKind()) { + throw AnalysisError.shouldNotReachHere("Cannot store value of kind " + value.getJavaKind() + " into primitive array of type " + getConstantData().type); } - Array.set(array, idx, value.asBoxedPrimitive()); + Array.set(getArray(), idx, value.asBoxedPrimitive()); } @Override public int getLength() { - return length; + return getConstantData().length; } @Override public JavaConstant compress() { assert !compressed : this; - return new ImageHeapPrimitiveArray(type, hostedObject, array, identityHashCode, true, length); + return new ImageHeapPrimitiveArray(constantData, true); } @Override public JavaConstant uncompress() { assert compressed : this; - return new ImageHeapPrimitiveArray(type, hostedObject, array, identityHashCode, false, length); + return new ImageHeapPrimitiveArray(constantData, false); } @Override public ImageHeapConstant forObjectClone() { - assert type.isCloneableWithAllocation() : "all arrays implement Cloneable"; + assert constantData.type.isCloneableWithAllocation() : "all arrays implement Cloneable"; - Object newArray = getClone(type.getComponentType().getJavaKind(), array); + PrimitiveArrayData data = getConstantData(); + Object newArray = getClone(data.type.getComponentType().getJavaKind(), data.array); /* The new constant is never backed by a hosted object, regardless of the input object. */ JavaConstant newHostedObject = null; - return new ImageHeapPrimitiveArray(type, newHostedObject, newArray, createIdentityHashCode(newHostedObject), compressed, length); - } - - @Override - public boolean equals(Object o) { - if (o instanceof ImageHeapPrimitiveArray) { - return super.equals(o) && this.array == ((ImageHeapPrimitiveArray) o).array; - } - return false; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = super.hashCode(); - result = prime * result + System.identityHashCode(array); - return result; + return new ImageHeapPrimitiveArray(data.type, newHostedObject, newArray, createIdentityHashCode(newHostedObject), compressed, data.length); } } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java index aa9a8432bdfe..a8ffa92d2b3d 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java @@ -253,7 +253,7 @@ protected ImageHeapConstant createImageHeapObject(JavaConstant constant, ScanRea private ImageHeapArray createImageHeapObjectArray(JavaConstant constant, AnalysisType type, int length, ScanReason reason) { ImageHeapObjectArray array = new ImageHeapObjectArray(type, constant, length); /* Read hosted array element values only when the array is initialized. */ - AnalysisFuture hostedElementsReader = new AnalysisFuture<>(() -> { + array.constantData.hostedValuesReader = new AnalysisFuture<>(() -> { type.registerAsReachable(reason); ScanReason arrayReason = new ArrayScan(type, constant, reason); Object[] elementValues = new Object[length]; @@ -268,14 +268,13 @@ private ImageHeapArray createImageHeapObjectArray(JavaConstant constant, Analysi } array.setElementValues(elementValues); }); - array.hostedValuesReader = hostedElementsReader; return array; } private ImageHeapInstance createImageHeapInstance(JavaConstant constant, AnalysisType type, ScanReason reason) { ImageHeapInstance instance = new ImageHeapInstance(type, constant); /* Read hosted field values only when the receiver is initialized. */ - AnalysisFuture hostedFieldReader = new AnalysisFuture<>(() -> { + instance.constantData.hostedValuesReader = new AnalysisFuture<>(() -> { /* We are about to query the type's fields, the type must be marked as reachable. */ type.registerAsReachable(reason); ResolvedJavaField[] instanceFields = type.getInstanceFields(true); @@ -298,7 +297,6 @@ private ImageHeapInstance createImageHeapInstance(JavaConstant constant, Analysi } instance.setFieldValues(hostedFieldValues); }); - instance.hostedValuesReader = hostedFieldReader; return instance; } diff --git a/substratevm/src/com.oracle.svm.util/src/com/oracle/svm/util/ReflectionUtil.java b/substratevm/src/com.oracle.svm.util/src/com/oracle/svm/util/ReflectionUtil.java index ad5087d8add8..8cc0e06e3899 100644 --- a/substratevm/src/com.oracle.svm.util/src/com/oracle/svm/util/ReflectionUtil.java +++ b/substratevm/src/com.oracle.svm.util/src/com/oracle/svm/util/ReflectionUtil.java @@ -24,6 +24,8 @@ */ package com.oracle.svm.util; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.VarHandle; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; @@ -117,6 +119,16 @@ public static T newInstance(Constructor constructor, Object... initArgs) } } + public static VarHandle unreflectField(Class declaringClass, String fieldName, MethodHandles.Lookup lookup) { + try { + Field field = ReflectionUtil.lookupField(declaringClass, fieldName); + MethodHandles.Lookup privateLookup = MethodHandles.privateLookupIn(declaringClass, lookup); + return privateLookup.unreflectVarHandle(field); + } catch (IllegalAccessException ex) { + throw new ReflectionUtilError(ex); + } + } + public static Field lookupField(Class declaringClass, String fieldName) { return lookupField(false, declaringClass, fieldName); } From 2953910ed25323b84902c0a5c223fab646561714 Mon Sep 17 00:00:00 2001 From: Allan Gregersen Date: Wed, 1 Nov 2023 08:15:00 +0100 Subject: [PATCH 07/11] cover all get/set specific typed methods with foreign object handling --- .../Target_java_lang_reflect_Array.java | 397 +++++++++++------- 1 file changed, 239 insertions(+), 158 deletions(-) diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_reflect_Array.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_reflect_Array.java index 1829ef90ced3..8437785a30ab 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_reflect_Array.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_reflect_Array.java @@ -162,11 +162,22 @@ public static boolean getBoolean(@JavaType(Object.class) StaticObject array, int profiler.profile(1); throw meta.throwException(meta.java_lang_IllegalArgumentException); } - try { - return Array.getByte(array.unwrap(language), index) != 0; - } catch (ArrayIndexOutOfBoundsException e) { - profiler.profile(5); - throw rethrowAsGuestException(e, meta, profiler); + if (array.isForeignObject()) { + try { + InteropLibrary library = InteropLibrary.getUncached(); + return library.asBoolean(library.readArrayElement(array.rawForeignObject(language), index)); + } catch (UnsupportedMessageException e) { + throw meta.throwException(meta.java_lang_IllegalArgumentException); + } catch (InvalidArrayIndexException e) { + throw meta.throwException(meta.java_lang_ArrayIndexOutOfBoundsException); + } + } else { + try { + return Array.getByte(array.unwrap(language), index) != 0; + } catch (ArrayIndexOutOfBoundsException e) { + profiler.profile(5); + throw rethrowAsGuestException(e, meta, profiler); + } } } @@ -176,11 +187,22 @@ public static byte getByte(@JavaType(Object.class) StaticObject array, int index @Inject Meta meta, @Inject SubstitutionProfiler profiler) { checkNonNullArray(array, meta, profiler); - try { - return Array.getByte(array.unwrap(language), index); - } catch (NullPointerException | ArrayIndexOutOfBoundsException | IllegalArgumentException e) { - profiler.profile(5); - throw rethrowAsGuestException(e, meta, profiler); + if (array.isForeignObject()) { + try { + InteropLibrary library = InteropLibrary.getUncached(); + return library.asByte(library.readArrayElement(array.rawForeignObject(language), index)); + } catch (UnsupportedMessageException e) { + throw meta.throwException(meta.java_lang_IllegalArgumentException); + } catch (InvalidArrayIndexException e) { + throw meta.throwException(meta.java_lang_ArrayIndexOutOfBoundsException); + } + } else { + try { + return Array.getByte(array.unwrap(language), index); + } catch (NullPointerException | ArrayIndexOutOfBoundsException | IllegalArgumentException e) { + profiler.profile(5); + throw rethrowAsGuestException(e, meta, profiler); + } } } @@ -190,11 +212,29 @@ public static char getChar(@JavaType(Object.class) StaticObject array, int index @Inject Meta meta, @Inject SubstitutionProfiler profiler) { checkNonNullArray(array, meta, profiler); - try { - return Array.getChar(array.unwrap(language), index); - } catch (NullPointerException | ArrayIndexOutOfBoundsException | IllegalArgumentException e) { - profiler.profile(5); - throw rethrowAsGuestException(e, meta, profiler); + if (array.isForeignObject()) { + try { + InteropLibrary library = InteropLibrary.getUncached(); + String str = library.asString(library.readArrayElement(array.rawForeignObject(language), index)); + if (str.isEmpty()) { + return '\u0000'; + } else if (str.length() > 1) { + throw meta.throwException(meta.java_lang_IllegalArgumentException); + } else { + return str.charAt(0); + } + } catch (UnsupportedMessageException e) { + throw meta.throwException(meta.java_lang_IllegalArgumentException); + } catch (InvalidArrayIndexException e) { + throw meta.throwException(meta.java_lang_ArrayIndexOutOfBoundsException); + } + } else { + try { + return Array.getChar(array.unwrap(language), index); + } catch (NullPointerException | ArrayIndexOutOfBoundsException | IllegalArgumentException e) { + profiler.profile(5); + throw rethrowAsGuestException(e, meta, profiler); + } } } @@ -204,11 +244,22 @@ public static short getShort(@JavaType(Object.class) StaticObject array, int ind @Inject Meta meta, @Inject SubstitutionProfiler profiler) { checkNonNullArray(array, meta, profiler); - try { - return Array.getShort(array.unwrap(language), index); - } catch (NullPointerException | ArrayIndexOutOfBoundsException | IllegalArgumentException e) { - profiler.profile(5); - throw rethrowAsGuestException(e, meta, profiler); + if (array.isForeignObject()) { + try { + InteropLibrary library = InteropLibrary.getUncached(); + return library.asShort(library.readArrayElement(array.rawForeignObject(language), index)); + } catch (UnsupportedMessageException e) { + throw meta.throwException(meta.java_lang_IllegalArgumentException); + } catch (InvalidArrayIndexException e) { + throw meta.throwException(meta.java_lang_ArrayIndexOutOfBoundsException); + } + } else { + try { + return Array.getShort(array.unwrap(language), index); + } catch (NullPointerException | ArrayIndexOutOfBoundsException | IllegalArgumentException e) { + profiler.profile(5); + throw rethrowAsGuestException(e, meta, profiler); + } } } @@ -218,11 +269,22 @@ public static int getInt(@JavaType(Object.class) StaticObject array, int index, @Inject Meta meta, @Inject SubstitutionProfiler profiler) { checkNonNullArray(array, meta, profiler); - try { - return Array.getInt(array.unwrap(language), index); - } catch (NullPointerException | ArrayIndexOutOfBoundsException | IllegalArgumentException e) { - profiler.profile(5); - throw rethrowAsGuestException(e, meta, profiler); + if (array.isForeignObject()) { + try { + InteropLibrary library = InteropLibrary.getUncached(); + return library.asInt(library.readArrayElement(array.rawForeignObject(language), index)); + } catch (UnsupportedMessageException e) { + throw meta.throwException(meta.java_lang_IllegalArgumentException); + } catch (InvalidArrayIndexException e) { + throw meta.throwException(meta.java_lang_ArrayIndexOutOfBoundsException); + } + } else { + try { + return Array.getInt(array.unwrap(language), index); + } catch (NullPointerException | ArrayIndexOutOfBoundsException | IllegalArgumentException e) { + profiler.profile(5); + throw rethrowAsGuestException(e, meta, profiler); + } } } @@ -232,11 +294,22 @@ public static float getFloat(@JavaType(Object.class) StaticObject array, int ind @Inject Meta meta, @Inject SubstitutionProfiler profiler) { checkNonNullArray(array, meta, profiler); - try { - return Array.getFloat(array.unwrap(language), index); - } catch (NullPointerException | ArrayIndexOutOfBoundsException | IllegalArgumentException e) { - profiler.profile(5); - throw rethrowAsGuestException(e, meta, profiler); + if (array.isForeignObject()) { + try { + InteropLibrary library = InteropLibrary.getUncached(); + return library.asFloat(library.readArrayElement(array.rawForeignObject(language), index)); + } catch (UnsupportedMessageException e) { + throw meta.throwException(meta.java_lang_IllegalArgumentException); + } catch (InvalidArrayIndexException e) { + throw meta.throwException(meta.java_lang_ArrayIndexOutOfBoundsException); + } + } else { + try { + return Array.getFloat(array.unwrap(language), index); + } catch (NullPointerException | ArrayIndexOutOfBoundsException | IllegalArgumentException e) { + profiler.profile(5); + throw rethrowAsGuestException(e, meta, profiler); + } } } @@ -246,11 +319,22 @@ public static double getDouble(@JavaType(Object.class) StaticObject array, int i @Inject Meta meta, @Inject SubstitutionProfiler profiler) { checkNonNullArray(array, meta, profiler); - try { - return Array.getDouble(array.unwrap(language), index); - } catch (NullPointerException | ArrayIndexOutOfBoundsException | IllegalArgumentException e) { - profiler.profile(5); - throw rethrowAsGuestException(e, meta, profiler); + if (array.isForeignObject()) { + try { + InteropLibrary library = InteropLibrary.getUncached(); + return library.asDouble(library.readArrayElement(array.rawForeignObject(language), index)); + } catch (UnsupportedMessageException e) { + throw meta.throwException(meta.java_lang_IllegalArgumentException); + } catch (InvalidArrayIndexException e) { + throw meta.throwException(meta.java_lang_ArrayIndexOutOfBoundsException); + } + } else { + try { + return Array.getDouble(array.unwrap(language), index); + } catch (NullPointerException | ArrayIndexOutOfBoundsException | IllegalArgumentException e) { + profiler.profile(5); + throw rethrowAsGuestException(e, meta, profiler); + } } } @@ -260,11 +344,22 @@ public static long getLong(@JavaType(Object.class) StaticObject array, int index @Inject Meta meta, @Inject SubstitutionProfiler profiler) { checkNonNullArray(array, meta, profiler); - try { - return Array.getLong(array.unwrap(language), index); - } catch (NullPointerException | ArrayIndexOutOfBoundsException | IllegalArgumentException e) { - profiler.profile(5); - throw rethrowAsGuestException(e, meta, profiler); + if (array.isForeignObject()) { + try { + InteropLibrary library = InteropLibrary.getUncached(); + return library.asLong(library.readArrayElement(array.rawForeignObject(language), index)); + } catch (UnsupportedMessageException e) { + throw meta.throwException(meta.java_lang_IllegalArgumentException); + } catch (InvalidArrayIndexException e) { + throw meta.throwException(meta.java_lang_ArrayIndexOutOfBoundsException); + } + } else { + try { + return Array.getLong(array.unwrap(language), index); + } catch (NullPointerException | ArrayIndexOutOfBoundsException | IllegalArgumentException e) { + profiler.profile(5); + throw rethrowAsGuestException(e, meta, profiler); + } } } @@ -319,11 +414,15 @@ public static void setBoolean(@JavaType(Object.class) StaticObject array, int in profiler.profile(1); throw meta.throwException(meta.java_lang_IllegalArgumentException); } - try { - Array.setByte(array.unwrap(language), index, value ? (byte) 1 : (byte) 0); - } catch (ArrayIndexOutOfBoundsException e) { - profiler.profile(5); - throw rethrowAsGuestException(e, meta, profiler); + if (array.isForeignObject()) { + writeForeignArrayElement(array, language, index, value, meta); + } else { + try { + Array.setByte(array.unwrap(language), index, value ? (byte) 1 : (byte) 0); + } catch (ArrayIndexOutOfBoundsException e) { + profiler.profile(5); + throw rethrowAsGuestException(e, meta, profiler); + } } } @@ -333,11 +432,15 @@ public static void setByte(@JavaType(Object.class) StaticObject array, int index @Inject Meta meta, @Inject SubstitutionProfiler profiler) { checkNonNullArray(array, meta, profiler); - try { - Array.setByte(array.unwrap(language), index, value); - } catch (NullPointerException | ArrayIndexOutOfBoundsException | IllegalArgumentException e) { - profiler.profile(5); - throw rethrowAsGuestException(e, meta, profiler); + if (array.isForeignObject()) { + writeForeignArrayElement(array, language, index, value, meta); + } else { + try { + Array.setByte(array.unwrap(language), index, value); + } catch (NullPointerException | ArrayIndexOutOfBoundsException | IllegalArgumentException e) { + profiler.profile(5); + throw rethrowAsGuestException(e, meta, profiler); + } } } @@ -347,11 +450,15 @@ public static void setChar(@JavaType(Object.class) StaticObject array, int index @Inject Meta meta, @Inject SubstitutionProfiler profiler) { checkNonNullArray(array, meta, profiler); - try { - Array.setChar(array.unwrap(language), index, value); - } catch (NullPointerException | ArrayIndexOutOfBoundsException | IllegalArgumentException e) { - profiler.profile(5); - throw rethrowAsGuestException(e, meta, profiler); + if (array.isForeignObject()) { + writeForeignArrayElement(array, language, index, value, meta); + } else { + try { + Array.setChar(array.unwrap(language), index, value); + } catch (NullPointerException | ArrayIndexOutOfBoundsException | IllegalArgumentException e) { + profiler.profile(5); + throw rethrowAsGuestException(e, meta, profiler); + } } } @@ -361,11 +468,15 @@ public static void setShort(@JavaType(Object.class) StaticObject array, int inde @Inject Meta meta, @Inject SubstitutionProfiler profiler) { checkNonNullArray(array, meta, profiler); - try { - Array.setShort(array.unwrap(language), index, value); - } catch (NullPointerException | ArrayIndexOutOfBoundsException | IllegalArgumentException e) { - profiler.profile(5); - throw rethrowAsGuestException(e, meta, profiler); + if (array.isForeignObject()) { + writeForeignArrayElement(array, language, index, value, meta); + } else { + try { + Array.setShort(array.unwrap(language), index, value); + } catch (NullPointerException | ArrayIndexOutOfBoundsException | IllegalArgumentException e) { + profiler.profile(5); + throw rethrowAsGuestException(e, meta, profiler); + } } } @@ -375,11 +486,15 @@ public static void setInt(@JavaType(Object.class) StaticObject array, int index, @Inject Meta meta, @Inject SubstitutionProfiler profiler) { checkNonNullArray(array, meta, profiler); - try { - Array.setInt(array.unwrap(language), index, value); - } catch (NullPointerException | ArrayIndexOutOfBoundsException | IllegalArgumentException e) { - profiler.profile(5); - throw rethrowAsGuestException(e, meta, profiler); + if (array.isForeignObject()) { + writeForeignArrayElement(array, language, index, value, meta); + } else { + try { + Array.setInt(array.unwrap(language), index, value); + } catch (NullPointerException | ArrayIndexOutOfBoundsException | IllegalArgumentException e) { + profiler.profile(5); + throw rethrowAsGuestException(e, meta, profiler); + } } } @@ -389,11 +504,15 @@ public static void setFloat(@JavaType(Object.class) StaticObject array, int inde @Inject Meta meta, @Inject SubstitutionProfiler profiler) { checkNonNullArray(array, meta, profiler); - try { - Array.setFloat(array.unwrap(language), index, value); - } catch (NullPointerException | ArrayIndexOutOfBoundsException | IllegalArgumentException e) { - profiler.profile(5); - throw rethrowAsGuestException(e, meta, profiler); + if (array.isForeignObject()) { + writeForeignArrayElement(array, language, index, value, meta); + } else { + try { + Array.setFloat(array.unwrap(language), index, value); + } catch (NullPointerException | ArrayIndexOutOfBoundsException | IllegalArgumentException e) { + profiler.profile(5); + throw rethrowAsGuestException(e, meta, profiler); + } } } @@ -403,11 +522,15 @@ public static void setDouble(@JavaType(Object.class) StaticObject array, int ind @Inject Meta meta, @Inject SubstitutionProfiler profiler) { checkNonNullArray(array, meta, profiler); - try { - Array.setDouble(array.unwrap(language), index, value); - } catch (NullPointerException | ArrayIndexOutOfBoundsException | IllegalArgumentException e) { - profiler.profile(5); - throw rethrowAsGuestException(e, meta, profiler); + if (array.isForeignObject()) { + writeForeignArrayElement(array, language, index, value, meta); + } else { + try { + Array.setDouble(array.unwrap(language), index, value); + } catch (NullPointerException | ArrayIndexOutOfBoundsException | IllegalArgumentException e) { + profiler.profile(5); + throw rethrowAsGuestException(e, meta, profiler); + } } } @@ -417,11 +540,26 @@ public static void setLong(@JavaType(Object.class) StaticObject array, int index @Inject Meta meta, @Inject SubstitutionProfiler profiler) { checkNonNullArray(array, meta, profiler); + if (array.isForeignObject()) { + writeForeignArrayElement(array, language, index, value, meta); + } else { + try { + Array.setLong(array.unwrap(language), index, value); + } catch (NullPointerException | ArrayIndexOutOfBoundsException | IllegalArgumentException e) { + profiler.profile(5); + throw rethrowAsGuestException(e, meta, profiler); + } + } + } + + private static void writeForeignArrayElement(StaticObject array, EspressoLanguage language, int index, Object value, Meta meta) { try { - Array.setLong(array.unwrap(language), index, value); - } catch (NullPointerException | ArrayIndexOutOfBoundsException | IllegalArgumentException e) { - profiler.profile(5); - throw rethrowAsGuestException(e, meta, profiler); + InteropLibrary library = InteropLibrary.getUncached(); + library.writeArrayElement(array.rawForeignObject(language), index, value); + } catch (UnsupportedMessageException | UnsupportedTypeException e) { + throw meta.throwException(meta.java_lang_IllegalArgumentException); + } catch (InvalidArrayIndexException e) { + throw meta.throwException(meta.java_lang_ArrayIndexOutOfBoundsException); } } @@ -449,91 +587,34 @@ public static void set(@JavaType(Object.class) StaticObject array, int index, @J throw meta.throwNullPointerException(); } if (array.isArray()) { - try { Object widenValue = Target_sun_reflect_NativeMethodAccessorImpl.checkAndWiden(meta, value, ((ArrayKlass) array.getKlass()).getComponentType()); - switch (((ArrayKlass) array.getKlass()).getComponentType().getJavaKind()) { - case Boolean: { - if (array.isForeignObject()) { - InteropLibrary library = InteropLibrary.getUncached(); - library.writeArrayElement(array.rawForeignObject(language), index, widenValue); - } else { - vm.setArrayByte(language, ((boolean) widenValue) ? (byte) 1 : (byte) 0, index, array); - } - break; - } - case Byte: { - if (array.isForeignObject()) { - InteropLibrary library = InteropLibrary.getUncached(); - library.writeArrayElement(array.rawForeignObject(language), index, widenValue); - } else { - vm.setArrayByte(language, ((byte) widenValue), index, array); - } - break; - } - case Short: { - if (array.isForeignObject()) { - InteropLibrary library = InteropLibrary.getUncached(); - library.writeArrayElement(array.rawForeignObject(language), index, widenValue); - } else { - vm.setArrayShort(language, ((short) widenValue), index, array); - } - break; - } - case Char: { - if (array.isForeignObject()) { - InteropLibrary library = InteropLibrary.getUncached(); - library.writeArrayElement(array.rawForeignObject(language), index, widenValue); - } else { - vm.setArrayChar(language, ((char) widenValue), index, array); - } - break; - } - case Int: { - if (array.isForeignObject()) { - InteropLibrary library = InteropLibrary.getUncached(); - library.writeArrayElement(array.rawForeignObject(language), index, widenValue); - } else { - vm.setArrayInt(language, ((int) widenValue), index, array); - } - break; - } - case Float: { - if (array.isForeignObject()) { - InteropLibrary library = InteropLibrary.getUncached(); - library.writeArrayElement(array.rawForeignObject(language), index, widenValue); - } else { - vm.setArrayFloat(language, ((float) widenValue), index, array); - } - break; - } - case Long: { - if (array.isForeignObject()) { - InteropLibrary library = InteropLibrary.getUncached(); - library.writeArrayElement(array.rawForeignObject(language), index, widenValue); - } else { - vm.setArrayLong(language, ((long) widenValue), index, array); - } - break; - } - case Double: { - if (array.isForeignObject()) { - InteropLibrary library = InteropLibrary.getUncached(); - library.writeArrayElement(array.rawForeignObject(language), index, widenValue); - } else { - vm.setArrayDouble(language, ((double) widenValue), index, array); - } - break; + if (array.isForeignObject()) { + try { + InteropLibrary library = InteropLibrary.getUncached(); + library.writeArrayElement(array.rawForeignObject(language), index, widenValue); + return; + } catch (UnsupportedMessageException | UnsupportedTypeException e) { + throw meta.throwException(meta.java_lang_IllegalArgumentException); + } catch (InvalidArrayIndexException e) { + throw meta.throwException(meta.java_lang_ArrayIndexOutOfBoundsException); } + } + // @formatter:off + switch (((ArrayKlass) array.getKlass()).getComponentType().getJavaKind()) { + case Boolean : vm.setArrayByte(language, ((boolean) widenValue) ? (byte) 1 : (byte) 0, index, array); break; + case Byte : vm.setArrayByte(language, ((byte) widenValue), index, array); break; + case Short : vm.setArrayShort(language, ((short) widenValue), index, array); break; + case Char : vm.setArrayChar(language, ((char) widenValue), index, array); break; + case Int : vm.setArrayInt(language, ((int) widenValue), index, array); break; + case Float : vm.setArrayFloat(language, ((float) widenValue), index, array); break; + case Long : vm.setArrayLong(language, ((long) widenValue), index, array); break; + case Double : vm.setArrayDouble(language, ((double) widenValue), index, array); break; case Object : vm.setArrayObject(language, value, index, array); break; default : CompilerDirectives.transferToInterpreter(); throw EspressoError.shouldNotReachHere("invalid array type: " + array); } - } catch (UnsupportedMessageException | UnsupportedTypeException e) { - throw meta.throwException(meta.java_lang_IllegalArgumentException); - } catch (InvalidArrayIndexException e) { - throw meta.throwException(meta.java_lang_ArrayIndexOutOfBoundsException); - } + // @formatter:on } else { throw meta.throwException(meta.java_lang_IllegalArgumentException); } @@ -599,7 +680,7 @@ public static void set(@JavaType(Object.class) StaticObject array, int index, @J InteropLibrary library = InteropLibrary.getUncached(); String str = library.asString(library.readArrayElement(array.rawForeignObject(language), index)); if (str.isEmpty()) { - result = ' '; + result = '\u0000'; } else if (str.length() > 1) { throw meta.throwException(meta.java_lang_IllegalArgumentException); } else { From 2876bfedeab4960dff6675fbb57c6ee5cd6b7b6e Mon Sep 17 00:00:00 2001 From: jovanstevanovic Date: Wed, 1 Nov 2023 08:23:55 +0100 Subject: [PATCH 08/11] Transient failure with malformed adopted profiles. --- .../src/jdk/graal/compiler/util/json/JSONParser.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/util/json/JSONParser.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/util/json/JSONParser.java index ce060c4d6263..18f795263f12 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/util/json/JSONParser.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/util/json/JSONParser.java @@ -547,7 +547,7 @@ private static String readFully(final Reader reader) throws IOException { try { int numChars; - while ((numChars = reader.read(arr, 0, arr.length)) > 0) { + while ((numChars = reader.read(arr, 0, arr.length)) >= 0) { sb.append(arr, 0, numChars); } } finally { From 2913b321d2de5c777c94d23d726b806e0e05f3b7 Mon Sep 17 00:00:00 2001 From: Martin Entlicher Date: Tue, 24 Oct 2023 09:48:13 +0200 Subject: [PATCH 09/11] Correct the thrown exceptions in Javadoc of getTruffleFile. (GR-49636) --- .../truffle/tools/chromeinspector/ScriptsHandler.java | 2 +- .../truffle/tools/dap/server/LoadedSourcesHandler.java | 6 +++--- .../truffle/api/instrumentation/TruffleInstrument.java | 8 ++++++++ .../src/com/oracle/truffle/api/TruffleLanguage.java | 6 ++++++ 4 files changed, 18 insertions(+), 4 deletions(-) diff --git a/tools/src/com.oracle.truffle.tools.chromeinspector/src/com/oracle/truffle/tools/chromeinspector/ScriptsHandler.java b/tools/src/com.oracle.truffle.tools.chromeinspector/src/com/oracle/truffle/tools/chromeinspector/ScriptsHandler.java index a3fc385b22cb..e7c49b4cd8b7 100644 --- a/tools/src/com.oracle.truffle.tools.chromeinspector/src/com/oracle/truffle/tools/chromeinspector/ScriptsHandler.java +++ b/tools/src/com.oracle.truffle.tools.chromeinspector/src/com/oracle/truffle/tools/chromeinspector/ScriptsHandler.java @@ -185,7 +185,7 @@ private String getSourceURL(Source source, TruffleContext truffleContext) { } else { try { return env.getTruffleFile(truffleContext, path).getAbsoluteFile().toUri().toString(); - } catch (SecurityException ex) { + } catch (UnsupportedOperationException | IllegalArgumentException | SecurityException ex) { if (File.separatorChar == '/') { return path; } else { diff --git a/tools/src/com.oracle.truffle.tools.dap/src/com/oracle/truffle/tools/dap/server/LoadedSourcesHandler.java b/tools/src/com.oracle.truffle.tools.dap/src/com/oracle/truffle/tools/dap/server/LoadedSourcesHandler.java index 1ad2e853f645..60e89b7be1f6 100644 --- a/tools/src/com.oracle.truffle.tools.dap/src/com/oracle/truffle/tools/dap/server/LoadedSourcesHandler.java +++ b/tools/src/com.oracle.truffle.tools.dap/src/com/oracle/truffle/tools/dap/server/LoadedSourcesHandler.java @@ -34,7 +34,7 @@ import com.oracle.truffle.tools.dap.types.LoadedSourceEvent; import java.net.URI; -import java.nio.file.InvalidPathException; +import java.nio.file.FileSystemNotFoundException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -205,7 +205,7 @@ private Pair getPath(Source source, TruffleContext truffleConte tFile = context.getEnv().getTruffleFile(truffleContext, path); } } - } catch (UnsupportedOperationException | InvalidPathException ex) { + } catch (UnsupportedOperationException | IllegalArgumentException | FileSystemNotFoundException ex) { // Unsupported URI/path } if (tFile != null) { @@ -218,7 +218,7 @@ private Pair getPath(Source source, TruffleContext truffleConte } else if (path != null) { try { srcRef = !context.getEnv().getTruffleFile(truffleContext, path).isReadable(); - } catch (SecurityException | InvalidPathException ex) { + } catch (UnsupportedOperationException | SecurityException | IllegalArgumentException ex) { // Can not verify readability srcRef = true; } diff --git a/truffle/src/com.oracle.truffle.api.instrumentation/src/com/oracle/truffle/api/instrumentation/TruffleInstrument.java b/truffle/src/com.oracle.truffle.api.instrumentation/src/com/oracle/truffle/api/instrumentation/TruffleInstrument.java index 5dd1a0121266..30010fd87548 100644 --- a/truffle/src/com.oracle.truffle.api.instrumentation/src/com/oracle/truffle/api/instrumentation/TruffleInstrument.java +++ b/truffle/src/com.oracle.truffle.api.instrumentation/src/com/oracle/truffle/api/instrumentation/TruffleInstrument.java @@ -855,6 +855,10 @@ public TruffleFile getTruffleFile(URI uri) { * context. * @param path the absolute or relative path to create {@link TruffleFile} for * @return {@link TruffleFile} + * @throws UnsupportedOperationException when the {@link FileSystem} supports only + * {@link URI} + * @throws IllegalArgumentException if the {@code path} string cannot be converted to a + * {@link Path} * @since 23.0 */ public TruffleFile getTruffleFile(TruffleContext context, String path) { @@ -872,6 +876,10 @@ public TruffleFile getTruffleFile(TruffleContext context, String path) { * context. * @param uri the {@link URI} to create {@link TruffleFile} for * @return {@link TruffleFile} + * @throws UnsupportedOperationException when {@link URI} scheme is not supported + * @throws IllegalArgumentException if preconditions on the {@code uri} do not hold. + * @throws FileSystemNotFoundException is the file system, identified by the {@code uri}, + * does not exist and cannot be created automatically * @since 23.0 */ public TruffleFile getTruffleFile(TruffleContext context, URI uri) { diff --git a/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleLanguage.java b/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleLanguage.java index 46f197a74b74..4b1ccbf56358 100644 --- a/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleLanguage.java +++ b/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleLanguage.java @@ -2899,6 +2899,8 @@ public TruffleFile getPublicTruffleFile(String path) { * @return {@link TruffleFile} * @throws UnsupportedOperationException when {@link URI} scheme is not supported * @throws IllegalArgumentException if preconditions on the {@code uri} do not hold. + * @throws FileSystemNotFoundException is the file system, identified by the {@code uri}, + * does not exist and cannot be created automatically * @since 19.3.0 */ @TruffleBoundary @@ -2960,6 +2962,8 @@ public TruffleFile getInternalTruffleFile(String path) { * @since 19.3.0 * @throws UnsupportedOperationException when {@link URI} scheme is not supported * @throws IllegalArgumentException if preconditions on the {@code uri} do not hold. + * @throws FileSystemNotFoundException is the file system, identified by the {@code uri}, + * does not exist and cannot be created automatically * @see #getTruffleFileInternal(URI, Predicate) * @see #getPublicTruffleFile(java.net.URI) */ @@ -3039,6 +3043,8 @@ public TruffleFile getTruffleFileInternal(String path, Predicate fi * @throws UnsupportedOperationException when the {@link FileSystem} supports only * {@link URI} * @throws IllegalArgumentException if preconditions on the {@code uri} do not hold. + * @throws FileSystemNotFoundException is the file system, identified by the {@code uri}, + * does not exist and cannot be created automatically * @since 21.1.0 * @see #getTruffleFileInternal(String, Predicate) * @see #getPublicTruffleFile(URI) From f2cab514753367988ac7cb8dcd0841028efabc9b Mon Sep 17 00:00:00 2001 From: Codrut Stancu Date: Wed, 1 Nov 2023 11:10:07 +0100 Subject: [PATCH 10/11] Cleanup. --- .../pointsto/heap/ImageHeapConstant.java | 6 +-- .../pointsto/heap/ImageHeapInstance.java | 37 ++++++++++------- .../pointsto/heap/ImageHeapObjectArray.java | 41 +++++++++++++------ 3 files changed, 54 insertions(+), 30 deletions(-) diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapConstant.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapConstant.java index 5bef16d477ff..366a3002b4ff 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapConstant.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapConstant.java @@ -63,17 +63,17 @@ public abstract static class ConstantData { * Stores the hosted object, already processed by the object transformers. It is null for * instances of partially evaluated classes. */ - protected final JavaConstant hostedObject; + private final JavaConstant hostedObject; /** * See {@link #createIdentityHashCode(JavaConstant)}. */ - protected final int identityHashCode; + private final int identityHashCode; /** * A future that reads the hosted field or array elements values lazily only when the * receiver object is used. This way the shadow heap can contain hosted only objects, i.e., * objects that cannot be reachable at run time but are processed ahead-of-time. */ - protected AnalysisFuture hostedValuesReader; + AnalysisFuture hostedValuesReader; /** * A constant is marked as reachable only when it is decided that it can be used at run-time * and its field values/array elements need to be processed. The value of the field is diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapInstance.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapInstance.java index 00236dfd42a5..88b328542642 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapInstance.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapInstance.java @@ -58,13 +58,13 @@ public final class ImageHeapInstance extends ImageHeapConstant { public static class InstanceData extends ConstantData { /** - * The field values array. It is only set when the constant is actually used and the hosted - * values of its fields/elements may be read. - * - * Each value is either an {@link AnalysisFuture} of {@link JavaConstant} or its result, a - * {@link JavaConstant}, indexed by {@link AnalysisField#getPosition()}. + * Stores the field values, indexed by {@link AnalysisField#getPosition()}. For normal + * constants it is set via {@link #setFieldValues(Object[])} only when the constant is + * actually used and the hosted values of its fields may be read. For simulated constants it + * is set on creation. *

- * Evaluating the {@link AnalysisFuture} runs + * Each value is either an {@link AnalysisFuture} of {@link JavaConstant} or its result, a + * {@link JavaConstant}. Evaluating the {@link AnalysisFuture} runs * {@link ImageHeapScanner#createFieldValue(AnalysisField, ImageHeapInstance, ValueSupplier, ObjectScanner.ScanReason)} * which adds the result to the image heap. */ @@ -78,7 +78,6 @@ public static class InstanceData extends ConstantData { super(type, object, identityHashCode); this.fieldValues = fieldValues; } - } ImageHeapInstance(ResolvedJavaType type, JavaConstant object) { @@ -111,13 +110,25 @@ void setFieldValues(Object[] fieldValues) { AnalysisError.guarantee(success, "Unexpected field values reference for constant %s", this); } + /** + * {@link InstanceData#fieldValues} are only set once, in {@link #setFieldValues(Object[])} and + * shouldn't be accessed before set, i.e., read access is guarded by + * {@link #isReaderInstalled()} which ensures that the future setting the field values was + * executed, therefore we can read the field directly. + */ + private Object[] getFieldValues() { + AnalysisError.guarantee(isReaderInstalled()); + Object[] fieldValues = getConstantData().fieldValues; + AnalysisError.guarantee(fieldValues != null); + return fieldValues; + } + /** * Record the task computing the field value. It will be retrieved and executed when the field * is marked as read. */ void setFieldTask(AnalysisField field, AnalysisFuture task) { - AnalysisError.guarantee(isReaderInstalled()); - arrayHandle.setVolatile(valuesHandle.get(constantData), field.getPosition(), task); + arrayHandle.setVolatile(getFieldValues(), field.getPosition(), task); } /** @@ -126,8 +137,7 @@ void setFieldTask(AnalysisField field, AnalysisFuture task) { * and replaced. */ public void setFieldValue(AnalysisField field, JavaConstant value) { - AnalysisError.guarantee(isReaderInstalled()); - arrayHandle.setVolatile(valuesHandle.get(constantData), field.getPosition(), value); + arrayHandle.setVolatile(getFieldValues(), field.getPosition(), value); } /** @@ -136,8 +146,7 @@ public void setFieldValue(AnalysisField field, JavaConstant value) { * or the result of executing the task, i.e., a {@link JavaConstant}. */ public Object getFieldValue(AnalysisField field) { - AnalysisError.guarantee(isReaderInstalled()); - return arrayHandle.getVolatile(valuesHandle.get(constantData), field.getPosition()); + return arrayHandle.getVolatile(getFieldValues(), field.getPosition()); } /** @@ -168,7 +177,7 @@ public ImageHeapConstant forObjectClone() { return null; } - Object[] fieldValues = getConstantData().fieldValues; + Object[] fieldValues = getFieldValues(); Objects.requireNonNull(fieldValues, "Cannot clone an instance before the field values are set."); Object[] newFieldValues = Arrays.copyOf(fieldValues, fieldValues.length); /* The new constant is never backed by a hosted object, regardless of the input object. */ diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapObjectArray.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapObjectArray.java index d4f08dff1fdf..a7f28491de82 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapObjectArray.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapObjectArray.java @@ -47,9 +47,14 @@ public final class ImageHeapObjectArray extends ImageHeapArray { public static class ArrayData extends ConstantData { /** - * The element values array. It is only set when the constant is initialized. Each value is - * either an {@link AnalysisFuture} of {@link JavaConstant} or its result, a - * {@link JavaConstant}, indexed by array index. + * Stores the array element values, indexed by array index. For normal constants it is set + * via {@link #setElementValues(Object[])} only when the constant is actually used and the + * hosted values of its elements may be read. For simulated constants it is set on creation. + *

+ * Each value is either an {@link AnalysisFuture} of {@link JavaConstant} or its result, a + * {@link JavaConstant}. Evaluating the {@link AnalysisFuture} runs + * {@link ImageHeapScanner#createImageHeapConstant(JavaConstant, ObjectScanner.ScanReason)} + * which adds the result to the image heap. */ private Object[] arrayElementValues; @@ -97,14 +102,26 @@ void setElementValues(Object[] elementValues) { AnalysisError.guarantee(success, "Unexpected field values reference for constant %s", this); } + /** + * {@link ArrayData#arrayElementValues} are only set once, in + * {@link #setElementValues(Object[])} and shouldn't be accessed before set, i.e., read access + * is guarded by {@link #isReaderInstalled()} which ensures that the future setting the field + * values was executed, therefore we can read the field directly. + */ + private Object[] getElementValues() { + AnalysisError.guarantee(isReaderInstalled()); + Object[] arrayElements = getConstantData().arrayElementValues; + AnalysisError.guarantee(arrayElements != null); + return arrayElements; + } + /** * Return the value of the element at the specified index as computed by * {@link ImageHeapScanner#onArrayElementReachable(ImageHeapArray, AnalysisType, JavaConstant, int, ObjectScanner.ScanReason, Consumer)}. */ @Override public Object getElement(int idx) { - AnalysisError.guarantee(isReaderInstalled()); - return arrayHandle.getVolatile(elementsHandle.get(constantData), idx); + return arrayHandle.getVolatile(getElementValues(), idx); } /** @@ -120,13 +137,11 @@ public JavaConstant readElementValue(int index) { @Override public void setElement(int idx, JavaConstant value) { - AnalysisError.guarantee(isReaderInstalled()); - arrayHandle.setVolatile(elementsHandle.get(constantData), idx, value); + arrayHandle.setVolatile(getElementValues(), idx, value); } void setElementTask(int idx, AnalysisFuture task) { - AnalysisError.guarantee(isReaderInstalled()); - arrayHandle.setVolatile(elementsHandle.get(constantData), idx, task); + arrayHandle.setVolatile(getElementValues(), idx, task); } @Override @@ -150,11 +165,11 @@ public JavaConstant uncompress() { public ImageHeapConstant forObjectClone() { assert constantData.type.isCloneableWithAllocation() : "all arrays implement Cloneable"; - ArrayData arrayData = getConstantData(); - Objects.requireNonNull(arrayData.arrayElementValues, "Cannot clone an array before the element values are set."); - Object[] newArrayElementValues = Arrays.copyOf(arrayData.arrayElementValues, arrayData.arrayElementValues.length); + Object[] arrayElements = getElementValues(); + Objects.requireNonNull(arrayElements, "Cannot clone an array before the element values are set."); + Object[] newArrayElementValues = Arrays.copyOf(arrayElements, arrayElements.length); /* The new constant is never backed by a hosted object, regardless of the input object. */ JavaConstant newObject = null; - return new ImageHeapObjectArray(constantData.type, newObject, createIdentityHashCode(newObject), newArrayElementValues, arrayData.length, compressed); + return new ImageHeapObjectArray(constantData.type, newObject, createIdentityHashCode(newObject), newArrayElementValues, arrayElements.length, compressed); } } From 563a0d724827884bcca13c4f9c156f5d43d05b26 Mon Sep 17 00:00:00 2001 From: Codrut Stancu Date: Wed, 1 Nov 2023 11:23:34 +0100 Subject: [PATCH 11/11] Use AnalysisType in ImageHeapConstant. --- .../pointsto/heap/ImageHeapConstant.java | 8 ++-- .../pointsto/heap/ImageHeapInstance.java | 14 +++--- .../pointsto/heap/ImageHeapObjectArray.java | 13 +++--- .../heap/ImageHeapPrimitiveArray.java | 5 +-- .../graal/pointsto/heap/ImageHeapScanner.java | 4 +- .../AnalysisConstantReflectionProvider.java | 6 +-- .../SimulateClassInitializerGraphDecoder.java | 44 +++++++++---------- .../svm/hosted/meta/HostedMetaAccess.java | 5 +-- 8 files changed, 47 insertions(+), 52 deletions(-) diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapConstant.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapConstant.java index 366a3002b4ff..76f167f363db 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapConstant.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapConstant.java @@ -32,6 +32,7 @@ import org.graalvm.nativeimage.Platforms; import com.oracle.graal.pointsto.ObjectScanner; +import com.oracle.graal.pointsto.meta.AnalysisType; import com.oracle.graal.pointsto.util.AnalysisFuture; import com.oracle.svm.util.ReflectionUtil; @@ -40,7 +41,6 @@ import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.MetaAccessProvider; -import jdk.vm.ci.meta.ResolvedJavaType; import jdk.vm.ci.meta.VMConstant; /** @@ -58,7 +58,7 @@ public abstract static class ConstantData { /** * Stores the type of this object. */ - protected final ResolvedJavaType type; + protected final AnalysisType type; /** * Stores the hosted object, already processed by the object transformers. It is null for * instances of partially evaluated classes. @@ -81,7 +81,7 @@ public abstract static class ConstantData { */ @SuppressWarnings("unused") private volatile Object isReachable; - ConstantData(ResolvedJavaType type, JavaConstant object, int identityHashCode) { + ConstantData(AnalysisType type, JavaConstant object, int identityHashCode) { Objects.requireNonNull(type); this.type = type; this.hostedObject = object; @@ -195,7 +195,7 @@ public boolean isDefaultForKind() { } @Override - public ResolvedJavaType getType(MetaAccessProvider provider) { + public AnalysisType getType(MetaAccessProvider provider) { return constantData.type; } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapInstance.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapInstance.java index 88b328542642..f9844938095c 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapInstance.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapInstance.java @@ -32,12 +32,12 @@ import com.oracle.graal.pointsto.ObjectScanner; import com.oracle.graal.pointsto.heap.value.ValueSupplier; import com.oracle.graal.pointsto.meta.AnalysisField; +import com.oracle.graal.pointsto.meta.AnalysisType; import com.oracle.graal.pointsto.util.AnalysisError; import com.oracle.graal.pointsto.util.AnalysisFuture; import com.oracle.svm.util.ReflectionUtil; import jdk.vm.ci.meta.JavaConstant; -import jdk.vm.ci.meta.ResolvedJavaType; /** * This class implements an instance object snapshot. It stores the field values in an Object[], @@ -70,29 +70,29 @@ public static class InstanceData extends ConstantData { */ private Object[] fieldValues; - InstanceData(ResolvedJavaType type, JavaConstant object, int identityHashCode) { + InstanceData(AnalysisType type, JavaConstant object, int identityHashCode) { super(type, object, identityHashCode); } - InstanceData(ResolvedJavaType type, JavaConstant object, int identityHashCode, Object[] fieldValues) { + InstanceData(AnalysisType type, JavaConstant object, int identityHashCode, Object[] fieldValues) { super(type, object, identityHashCode); this.fieldValues = fieldValues; } } - ImageHeapInstance(ResolvedJavaType type, JavaConstant object) { + ImageHeapInstance(AnalysisType type, JavaConstant object) { super(new InstanceData(type, object, createIdentityHashCode(object)), false); } - public ImageHeapInstance(ResolvedJavaType type) { + public ImageHeapInstance(AnalysisType type) { this(type, null, type.getInstanceFields(true).length); } - private ImageHeapInstance(ResolvedJavaType type, JavaConstant object, int length) { + private ImageHeapInstance(AnalysisType type, JavaConstant object, int length) { this(type, object, createIdentityHashCode(object), new Object[length], false); } - private ImageHeapInstance(ResolvedJavaType type, JavaConstant object, int identityHashCode, Object[] fieldValues, boolean compressed) { + private ImageHeapInstance(AnalysisType type, JavaConstant object, int identityHashCode, Object[] fieldValues, boolean compressed) { super(new InstanceData(type, object, identityHashCode, fieldValues), compressed); } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapObjectArray.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapObjectArray.java index a7f28491de82..a222b3fd3ee8 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapObjectArray.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapObjectArray.java @@ -37,7 +37,6 @@ import com.oracle.svm.util.ReflectionUtil; import jdk.vm.ci.meta.JavaConstant; -import jdk.vm.ci.meta.ResolvedJavaType; public final class ImageHeapObjectArray extends ImageHeapArray { @@ -60,31 +59,31 @@ public static class ArrayData extends ConstantData { final int length; - public ArrayData(ResolvedJavaType type, JavaConstant object, int identityHashCode, int length) { + public ArrayData(AnalysisType type, JavaConstant object, int identityHashCode, int length) { super(type, object, identityHashCode); this.length = length; } - public ArrayData(ResolvedJavaType type, JavaConstant object, int identityHashCode, Object[] arrayElementValues, int length) { + public ArrayData(AnalysisType type, JavaConstant object, int identityHashCode, Object[] arrayElementValues, int length) { super(type, object, identityHashCode); this.arrayElementValues = arrayElementValues; this.length = length; } } - ImageHeapObjectArray(ResolvedJavaType type, JavaConstant object, int length) { + ImageHeapObjectArray(AnalysisType type, JavaConstant object, int length) { super(new ArrayData(type, object, createIdentityHashCode(object), length), false); } - ImageHeapObjectArray(ResolvedJavaType type, int length) { + ImageHeapObjectArray(AnalysisType type, int length) { this(type, null, new Object[length], length); } - ImageHeapObjectArray(ResolvedJavaType type, JavaConstant object, Object[] arrayElementValues, int length) { + ImageHeapObjectArray(AnalysisType type, JavaConstant object, Object[] arrayElementValues, int length) { this(type, object, createIdentityHashCode(object), arrayElementValues, length, false); } - private ImageHeapObjectArray(ResolvedJavaType type, JavaConstant object, int identityHashCode, Object[] arrayElementValues, int length, boolean compressed) { + private ImageHeapObjectArray(AnalysisType type, JavaConstant object, int identityHashCode, Object[] arrayElementValues, int length, boolean compressed) { super(new ArrayData(type, object, identityHashCode, arrayElementValues, length), compressed); } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapPrimitiveArray.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapPrimitiveArray.java index 7480fee57b3e..931cdd2b26d0 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapPrimitiveArray.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapPrimitiveArray.java @@ -33,7 +33,6 @@ import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; -import jdk.vm.ci.meta.ResolvedJavaType; public final class ImageHeapPrimitiveArray extends ImageHeapArray { @@ -46,7 +45,7 @@ public static class PrimitiveArrayData extends ConstantData { private final Object array; private final int length; - public PrimitiveArrayData(ResolvedJavaType type, JavaConstant object, int identityHashCode, Object array, int length) { + public PrimitiveArrayData(AnalysisType type, JavaConstant object, int identityHashCode, Object array, int length) { super(type, object, identityHashCode); this.array = array; this.length = length; @@ -67,7 +66,7 @@ public PrimitiveArrayData(ResolvedJavaType type, JavaConstant object, int identi createIdentityHashCode(hostedObject), false, length); } - private ImageHeapPrimitiveArray(ResolvedJavaType type, JavaConstant hostedObject, Object array, int identityHashCode, boolean compressed, int length) { + private ImageHeapPrimitiveArray(AnalysisType type, JavaConstant hostedObject, Object array, int identityHashCode, boolean compressed, int length) { super(new PrimitiveArrayData(type, hostedObject, identityHashCode, array, length), compressed); assert type.isArray() && type.getComponentType().isPrimitive() : type; } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java index a8ffa92d2b3d..0adbc47b1abe 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java @@ -486,7 +486,7 @@ protected void onObjectReachable(ImageHeapConstant imageHeapConstant, ScanReason markTypeInstantiated(objectType, reason); if (imageHeapConstant instanceof ImageHeapObjectArray imageHeapArray) { - AnalysisType arrayType = (AnalysisType) imageHeapArray.getType(metaAccess); + AnalysisType arrayType = imageHeapArray.getType(metaAccess); for (int idx = 0; idx < imageHeapArray.getLength(); idx++) { JavaConstant elementValue = imageHeapArray.readElementValue(idx); ArrayScan arrayScanReason = new ArrayScan(arrayType, imageHeapArray, reason, idx); @@ -607,7 +607,7 @@ protected AnalysisFuture patchInstanceField(ImageHeapInstance rece protected AnalysisFuture patchArrayElement(ImageHeapObjectArray arrayObject, int index, JavaConstant elementValue, ScanReason reason, Consumer onAnalysisModified) { AnalysisFuture task = new AnalysisFuture<>(() -> { - JavaConstant value = onArrayElementReachable(arrayObject, (AnalysisType) arrayObject.getType(metaAccess), elementValue, index, reason, onAnalysisModified); + JavaConstant value = onArrayElementReachable(arrayObject, arrayObject.getType(metaAccess), elementValue, index, reason, onAnalysisModified); arrayObject.setElement(index, value); return value; }); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantReflectionProvider.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantReflectionProvider.java index e77179f45a5b..a0ef920660b0 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantReflectionProvider.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantReflectionProvider.java @@ -28,8 +28,6 @@ import java.util.Set; import java.util.function.ObjIntConsumer; -import jdk.graal.compiler.core.common.type.TypedConstant; -import jdk.graal.compiler.word.Word; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; import org.graalvm.word.WordBase; @@ -60,6 +58,8 @@ import com.oracle.svm.hosted.meta.HostedMetaAccess; import com.oracle.svm.hosted.meta.RelocatableConstant; +import jdk.graal.compiler.core.common.type.TypedConstant; +import jdk.graal.compiler.word.Word; import jdk.vm.ci.meta.Constant; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; @@ -121,7 +121,7 @@ public JavaConstant unboxPrimitive(JavaConstant source) { * Unbox by reading the known single field "value", which is a primitive field of the * correct unboxed type. */ - AnalysisType type = (AnalysisType) imageHeapConstant.getType(metaAccess); + AnalysisType type = imageHeapConstant.getType(metaAccess); if (BOXING_CLASSES.contains(type.getJavaClass())) { imageHeapConstant.ensureReaderInstalled(); ResolvedJavaField[] fields = type.getInstanceFields(true); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/SimulateClassInitializerGraphDecoder.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/SimulateClassInitializerGraphDecoder.java index 2bbee446a63e..bce10d710a84 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/SimulateClassInitializerGraphDecoder.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/SimulateClassInitializerGraphDecoder.java @@ -52,6 +52,24 @@ import org.graalvm.collections.EconomicMap; import org.graalvm.collections.EconomicSet; +import org.graalvm.nativeimage.ImageSingletons; + +import com.oracle.graal.pointsto.BigBang; +import com.oracle.graal.pointsto.ObjectScanner; +import com.oracle.graal.pointsto.heap.ImageHeapArray; +import com.oracle.graal.pointsto.heap.ImageHeapConstant; +import com.oracle.graal.pointsto.heap.ImageHeapInstance; +import com.oracle.graal.pointsto.meta.AnalysisField; +import com.oracle.graal.pointsto.meta.AnalysisType; +import com.oracle.graal.pointsto.phases.InlineBeforeAnalysisGraphDecoder; +import com.oracle.svm.core.classinitialization.EnsureClassInitializedNode; +import com.oracle.svm.core.config.ObjectLayout; +import com.oracle.svm.core.meta.SubstrateObjectConstant; +import com.oracle.svm.core.util.VMError; +import com.oracle.svm.hosted.classinitialization.SimulateClassInitializerPolicy.SimulateClassInitializerInlineScope; +import com.oracle.svm.hosted.fieldfolding.IsStaticFinalFieldInitializedNode; +import com.oracle.svm.hosted.fieldfolding.MarkStaticFinalFieldInitializedNode; + import jdk.graal.compiler.core.common.type.TypedConstant; import jdk.graal.compiler.debug.DebugContext; import jdk.graal.compiler.graph.Node; @@ -78,24 +96,6 @@ import jdk.graal.compiler.nodes.virtual.VirtualObjectNode; import jdk.graal.compiler.replacements.arraycopy.ArrayCopyNode; import jdk.graal.compiler.replacements.nodes.ObjectClone; -import org.graalvm.nativeimage.ImageSingletons; - -import com.oracle.graal.pointsto.BigBang; -import com.oracle.graal.pointsto.ObjectScanner; -import com.oracle.graal.pointsto.heap.ImageHeapArray; -import com.oracle.graal.pointsto.heap.ImageHeapConstant; -import com.oracle.graal.pointsto.heap.ImageHeapInstance; -import com.oracle.graal.pointsto.meta.AnalysisField; -import com.oracle.graal.pointsto.meta.AnalysisType; -import com.oracle.graal.pointsto.phases.InlineBeforeAnalysisGraphDecoder; -import com.oracle.svm.core.classinitialization.EnsureClassInitializedNode; -import com.oracle.svm.core.config.ObjectLayout; -import com.oracle.svm.core.meta.SubstrateObjectConstant; -import com.oracle.svm.core.util.VMError; -import com.oracle.svm.hosted.classinitialization.SimulateClassInitializerPolicy.SimulateClassInitializerInlineScope; -import com.oracle.svm.hosted.fieldfolding.IsStaticFinalFieldInitializedNode; -import com.oracle.svm.hosted.fieldfolding.MarkStaticFinalFieldInitializedNode; - import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.MetaAccessProvider; @@ -306,7 +306,7 @@ private Node handleStoreIndexedNode(StoreIndexedNode node) { int idx = asIntegerOrMinusOne(node.index()); if (array != null && value != null && idx >= 0 && idx < array.getLength()) { - var componentType = (AnalysisType) array.getType(metaAccess).getComponentType(); + var componentType = array.getType(metaAccess).getComponentType(); if (node.elementKind().isPrimitive() || value.isNull() || componentType.isAssignableFrom(((TypedConstant) value).getType(metaAccess))) { array.setElement(idx, adaptForImageHeap(value, componentType.getStorageKind())); return null; @@ -341,8 +341,8 @@ protected boolean handleArrayCopy(ImageHeapArray source, int sourcePos, ImageHea return false; } - var sourceComponentType = (AnalysisType) source.getType(metaAccess).getComponentType(); - var destComponentType = (AnalysisType) dest.getType(metaAccess).getComponentType(); + var sourceComponentType = source.getType(metaAccess).getComponentType(); + var destComponentType = dest.getType(metaAccess).getComponentType(); if (sourceComponentType.getJavaKind() != destComponentType.getJavaKind()) { return false; } @@ -534,7 +534,7 @@ private ValueNode handleBoxNode(BoxNode node) { private ValueNode handleObjectClone(SimulateClassInitializerInlineScope countersScope, ObjectClone node) { var originalImageHeapConstant = asActiveImageHeapConstant(node.getObject()); if (originalImageHeapConstant != null) { - var type = (AnalysisType) originalImageHeapConstant.getType(metaAccess); + var type = originalImageHeapConstant.getType(metaAccess); if ((originalImageHeapConstant instanceof ImageHeapArray originalArray && accumulateNewArraySize(countersScope, type, originalArray.getLength(), node.asNode())) || (type.isCloneableWithAllocation() && accumulateNewInstanceSize(countersScope, type, node.asNode()))) { var cloned = originalImageHeapConstant.forObjectClone(); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedMetaAccess.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedMetaAccess.java index b91752e7a556..70040834ee8e 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedMetaAccess.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedMetaAccess.java @@ -33,14 +33,12 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -import jdk.graal.compiler.core.common.type.TypedConstant; - import com.oracle.graal.pointsto.heap.ImageHeapConstant; import com.oracle.graal.pointsto.infrastructure.UniverseMetaAccess; import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; -import com.oracle.graal.pointsto.meta.AnalysisType; import com.oracle.svm.core.deopt.Deoptimizer; +import jdk.graal.compiler.core.common.type.TypedConstant; import jdk.vm.ci.meta.DeoptimizationAction; import jdk.vm.ci.meta.DeoptimizationReason; import jdk.vm.ci.meta.JavaConstant; @@ -62,7 +60,6 @@ public HostedType lookupJavaType(Class clazz) { public HostedType lookupJavaType(JavaConstant constant) { if (constant instanceof ImageHeapConstant) { ResolvedJavaType type = ((TypedConstant) constant).getType(this); - assert type == null || type instanceof AnalysisType : type; return (HostedType) universe.lookup(type); } return (HostedType) super.lookupJavaType(constant);