Skip to content

Commit

Permalink
[GR-7033] Support for initialized ClassValue values.
Browse files Browse the repository at this point in the history
PullRequest: graal/1196
  • Loading branch information
Jaroslav Tulach committed Apr 10, 2018
2 parents 1ab86e7 + 6d1a7c3 commit 3b585c2
Show file tree
Hide file tree
Showing 2 changed files with 130 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
import com.oracle.svm.core.annotate.KeepOriginal;
import com.oracle.svm.core.annotate.NeverInline;
import com.oracle.svm.core.annotate.RecomputeFieldValue;
import com.oracle.svm.core.annotate.RecomputeFieldValue.CustomFieldValueComputer;
import com.oracle.svm.core.annotate.Substitute;
import com.oracle.svm.core.annotate.TargetClass;
import com.oracle.svm.core.annotate.TargetElement;
Expand All @@ -74,6 +75,10 @@
import com.oracle.svm.core.snippets.KnownIntrinsics;
import com.oracle.svm.core.stack.JavaStackWalker;
import com.oracle.svm.core.util.VMError;
import java.util.Map;
import jdk.vm.ci.meta.ResolvedJavaField;
import org.graalvm.nativeimage.Platform;
import org.graalvm.nativeimage.Platforms;

@TargetClass(java.lang.Object.class)
final class Target_java_lang_Object {
Expand Down Expand Up @@ -552,11 +557,9 @@ final class Target_java_lang_StrictMath {

/**
* We do not have dynamic class loading (and therefore no class unloading), so it is not necessary
* to keep the complicated code that the JDK uses. However, our simple substitutions have two
* drawbacks (but they are not a problem for now):
* to keep the complicated code that the JDK uses. However, our simple substitutions have a drawback
* (not a problem for now):
* <ul>
* <li>We do not persist values put into the ClassValue during image generation, i.e., we always
* start with an empty ClassValue at run time.
* <li>We do not implement the complicated state machine semantics for concurrent calls to
* {@link #get} and {@link #remove} that are explained in {@link ClassValue#remove}.
* </ul>
Expand All @@ -565,7 +568,7 @@ final class Target_java_lang_StrictMath {
@Substitute
final class Target_java_lang_ClassValue {

@RecomputeFieldValue(kind = RecomputeFieldValue.Kind.NewInstance, declClass = ConcurrentHashMap.class)//
@RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Custom, declClass = JavaLangSubstitutions.ClassValueInitializer.class)//
private final ConcurrentMap<Class<?>, Object> values;

@Substitute
Expand Down Expand Up @@ -692,4 +695,23 @@ static Package getPackage(Class<?> c) {

/** Dummy class to have a class with the file's name. */
public final class JavaLangSubstitutions {
@Platforms(Platform.HOSTED_ONLY.class)//
public static final class ClassValueSupport {
final Map<ClassValue<?>, Map<Class<?>, Object>> values;

public ClassValueSupport(Map<ClassValue<?>, Map<Class<?>, Object>> map) {
values = map;
}
}

static class ClassValueInitializer implements CustomFieldValueComputer {
@Override
public Object compute(ResolvedJavaField original, ResolvedJavaField annotated, Object receiver) {
ClassValueSupport support = ImageSingletons.lookup(ClassValueSupport.class);
ClassValue<?> v = (ClassValue<?>) receiver;
Map<Class<?>, Object> map = support.values.get(v);
assert map != null;
return map;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/*
* Copyright (c) 2015, 2017, 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.
*
* 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.hosted;

import com.oracle.graal.pointsto.meta.AnalysisType;
import com.oracle.svm.core.annotate.AutomaticFeature;
import com.oracle.svm.core.jdk.JavaLangSubstitutions.ClassValueSupport;
import com.oracle.svm.core.util.VMError;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.graalvm.nativeimage.Feature;
import org.graalvm.nativeimage.ImageSingletons;

@AutomaticFeature
public final class ClassValueFeature implements Feature {
private final Map<ClassValue<?>, Map<Class<?>, Object>> values = new ConcurrentHashMap<>();

@Override
public void afterRegistration(AfterRegistrationAccess access) {
ClassValueSupport support = new ClassValueSupport(values);
ImageSingletons.add(ClassValueSupport.class, support);
}

@Override
public void duringSetup(DuringSetupAccess access) {
access.registerObjectReplacer(this::processObject);
}

private Object processObject(Object obj) {
if (obj instanceof ClassValue) {
values.putIfAbsent((ClassValue<?>) obj, new ConcurrentHashMap<>());
}
return obj;
}

@Override
public void duringAnalysis(DuringAnalysisAccess access) {
FeatureImpl.DuringAnalysisAccessImpl impl = (FeatureImpl.DuringAnalysisAccessImpl) access;
List<AnalysisType> types = impl.getUniverse().getTypes();
for (AnalysisType t : types) {
if (!t.isInstantiated() && !t.isInTypeCheck()) {
continue;
}
Class<?> clazz = t.getJavaClass();
for (Map.Entry<ClassValue<?>, Map<Class<?>, Object>> e : values.entrySet()) {
ClassValue<?> v = e.getKey();
Map<Class<?>, Object> m = e.getValue();
if (!m.containsKey(clazz) && hasValue(v, clazz)) {
m.put(clazz, v.get(clazz));
access.requireAnalysisIteration();
}
}
}
}

private static final java.lang.reflect.Field IDENTITY;
private static final java.lang.reflect.Field CLASS_VALUE_MAP;
static {
try {
IDENTITY = ClassValue.class.getDeclaredField("identity");
IDENTITY.setAccessible(true);
CLASS_VALUE_MAP = Class.class.getDeclaredField("classValueMap");
CLASS_VALUE_MAP.setAccessible(true);
} catch (NoSuchFieldException ex) {
throw VMError.shouldNotReachHere(ex);
}
}

private static boolean hasValue(ClassValue<?> v, Class<?> c) {
try {
Map<?, ?> map = (Map<?, ?>) CLASS_VALUE_MAP.get(c);
final Object id = IDENTITY.get(v);
final boolean res = map.containsKey(id);
return res;
} catch (RuntimeException ex) {
throw ex;
} catch (Exception ex) {
throw new IllegalStateException(ex);
}
}

}

0 comments on commit 3b585c2

Please sign in to comment.