diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/annotate/RecomputeFieldValue.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/annotate/RecomputeFieldValue.java index c12b3bdcaf60..7585756c7510 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/annotate/RecomputeFieldValue.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/annotate/RecomputeFieldValue.java @@ -109,8 +109,8 @@ enum Kind { */ Manual, /** - * Use a {@link CustomFieldValueComputer} or {@link CustomFieldValueTransformer}, which is - * specified as the target class. + * Use the {@link CustomFieldValueComputer} or {@link CustomFieldValueTransformer} specified + * by {@link RecomputeFieldValue#declClass} or {@link RecomputeFieldValue#declClassName}. */ Custom, } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JavaIOClassCacheAbsent.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JavaIOClassCacheAbsent.java new file mode 100644 index 000000000000..1290eaeba57d --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JavaIOClassCacheAbsent.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2022, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.core.jdk; + +import java.util.function.BooleanSupplier; + +/** + * A predicate that returns {@code true} iff {@code boolean java.io.ClassCache} does not exist. + */ +public class JavaIOClassCacheAbsent implements BooleanSupplier { + @Override + public boolean getAsBoolean() { + try { + Class.forName("java.io.ClassCache"); + return false; + } catch (ClassNotFoundException e) { + return true; + } + } +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JavaIOClassCachePresent.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JavaIOClassCachePresent.java new file mode 100644 index 000000000000..32151bc2a99d --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JavaIOClassCachePresent.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2022, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.core.jdk; + +import java.util.function.BooleanSupplier; + +/** + * A predicate that returns {@code true} iff {@code boolean java.io.ClassCache} exists. + */ +public class JavaIOClassCachePresent implements BooleanSupplier { + @Override + public boolean getAsBoolean() { + try { + Class.forName("java.io.ClassCache"); + return true; + } catch (ClassNotFoundException e) { + return false; + } + } +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JavaIOSubstitutions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JavaIOSubstitutions.java index 63c0c632739d..6b85e28bb543 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JavaIOSubstitutions.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JavaIOSubstitutions.java @@ -24,18 +24,32 @@ */ package com.oracle.svm.core.jdk; +import static com.oracle.svm.core.util.VMError.guarantee; + import java.io.Closeable; import java.lang.ref.ReferenceQueue; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; import java.util.List; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.nativeimage.ImageSingletons; + import com.oracle.svm.core.annotate.Alias; import com.oracle.svm.core.annotate.RecomputeFieldValue; import com.oracle.svm.core.annotate.RecomputeFieldValue.Kind; +import com.oracle.svm.core.annotate.RecomputeFieldValue.ValueAvailability; import com.oracle.svm.core.annotate.Substitute; import com.oracle.svm.core.annotate.TargetClass; +import com.oracle.svm.core.annotate.TargetElement; import com.oracle.svm.core.hub.DynamicHub; +import com.oracle.svm.core.meta.SharedField; + +import jdk.vm.ci.meta.MetaAccessProvider; +import jdk.vm.ci.meta.ResolvedJavaField; @TargetClass(java.io.FileDescriptor.class) final class Target_java_io_FileDescriptor { @@ -53,15 +67,51 @@ private static boolean hasStaticInitializer(Class cl) { } } +@TargetClass(className = "java.io.ClassCache", onlyWith = JavaIOClassCachePresent.class) +final class Target_java_io_ClassCache { +} + +/** + * Creates a new instance by calling the no-args constructor of the original value's class. + */ +class ConstructCopy implements RecomputeFieldValue.CustomFieldValueTransformer { + + @Override + public ValueAvailability valueAvailability() { + return ValueAvailability.BeforeAnalysis; + } + + @Override + public Object transform(MetaAccessProvider metaAccess, ResolvedJavaField original, ResolvedJavaField annotated, Object receiver, Object originalValue) { + try { + Constructor cons = originalValue.getClass().getDeclaredConstructor(); + cons.setAccessible(true); + return cons.newInstance(); + } catch (Exception e) { + throw new GraalError(e); + } + } +} + @TargetClass(value = java.io.ObjectStreamClass.class, innerClass = "Caches") final class Target_java_io_ObjectStreamClass_Caches { + @TargetElement(onlyWith = JavaIOClassCachePresent.class, name = "localDescs") // + @Alias @RecomputeFieldValue(kind = Kind.Custom, declClass = ConstructCopy.class) static Target_java_io_ClassCache localDescs0; + + @TargetElement(onlyWith = JavaIOClassCachePresent.class, name = "reflectors") // + @Alias @RecomputeFieldValue(kind = Kind.Custom, declClass = ConstructCopy.class) static Target_java_io_ClassCache reflectors0; + + @TargetElement(onlyWith = JavaIOClassCacheAbsent.class) // @Alias @RecomputeFieldValue(kind = Kind.NewInstance, declClass = ConcurrentHashMap.class) static ConcurrentMap localDescs; + @TargetElement(onlyWith = JavaIOClassCacheAbsent.class) // @Alias @RecomputeFieldValue(kind = Kind.NewInstance, declClass = ConcurrentHashMap.class) static ConcurrentMap reflectors; + @TargetElement(onlyWith = JavaIOClassCacheAbsent.class) // @Alias @RecomputeFieldValue(kind = Kind.NewInstance, declClass = ReferenceQueue.class) private static ReferenceQueue> localDescsQueue; + @TargetElement(onlyWith = JavaIOClassCacheAbsent.class) // @Alias @RecomputeFieldValue(kind = Kind.NewInstance, declClass = ReferenceQueue.class) private static ReferenceQueue> reflectorsQueue; }