@@ -725,7 +725,7 @@ public Object apply(Object object) {
725725 }
726726 }
727727
728- private static final class StaticObjectSupport {
728+ static final class StaticObjectSupport {
729729 private static final Method VALIDATE_CLASSES = ReflectionUtil .lookupMethod (StaticShape .Builder .class , "validateClasses" , Class .class , Class .class );
730730
731731 static void duringSetup (DuringSetupAccess access ) {
@@ -777,23 +777,26 @@ private static boolean validateClasses(Class<?> storageSuperClass, Class<?> fact
777777 }
778778 }
779779
780- private static final class StaticObjectArrayBasedSupport {
780+ static final class StaticObjectArrayBasedSupport {
781781 private static final Method STORAGE_CLASS_NAME = ReflectionUtil .lookupMethod (StaticShape .Builder .class , "storageClassName" );
782782
783- private static final Class <?> GENERATOR_CLASS_LOADER_CLASS = loadClass ("com.oracle.truffle.api.staticobject.GeneratorClassLoader " );
784- private static final Constructor <?> GENERATOR_CLASS_LOADER_CONSTRUCTOR = ReflectionUtil .lookupConstructor (GENERATOR_CLASS_LOADER_CLASS , Class .class );
783+ private static final Class <?> GENERATOR_CLASS_LOADERS_CLASS = loadClass ("com.oracle.truffle.api.staticobject.GeneratorClassLoaders " );
784+ private static final Constructor <?> GENERATOR_CLASS_LOADERS_CONSTRUCTOR = ReflectionUtil .lookupConstructor (GENERATOR_CLASS_LOADERS_CLASS , Class .class );
785785
786- private static final Class <?> ARRAY_BASED_FACTORY = loadClass ("com.oracle.truffle.api.staticobject.ArrayBasedStaticShape$ArrayBasedFactory " );
786+ private static final Class <?> ARRAY_BASED_STATIC_SHAPE = loadClass ("com.oracle.truffle.api.staticobject.ArrayBasedStaticShape" );
787787 private static final Class <?> ARRAY_BASED_SHAPE_GENERATOR = loadClass ("com.oracle.truffle.api.staticobject.ArrayBasedShapeGenerator" );
788788 private static final Method GET_ARRAY_BASED_SHAPE_GENERATOR = ReflectionUtil .lookupMethod (ARRAY_BASED_SHAPE_GENERATOR , "getShapeGenerator" , TruffleLanguage .class ,
789- GENERATOR_CLASS_LOADER_CLASS , Class .class , Class .class , String .class );
789+ GENERATOR_CLASS_LOADERS_CLASS , Class .class , Class .class , String .class );
790790
791- private static final Map <Class <?>, ClassLoader > CLASS_LOADERS = new ConcurrentHashMap <>();
791+ private static final Map <Class <?>, Object > GENERATOR_CLASS_LOADERS_MAP = new ConcurrentHashMap <>();
792792 private static final int ALIGNMENT_CORRECTION ;
793793 private static BeforeAnalysisAccess beforeAnalysisAccess ;
794794
795795 private static final IdentityHashMap <Object , Object > registeredShapeGenerators = new IdentityHashMap <>();
796796
797+ static volatile ConcurrentHashMap <Object , Object > replacements ;
798+ private static final Class <?> FACTORY_CLASS_LOADER ;
799+
797800 static {
798801 // ArrayBasedShapeGenerator$ArrayBasedPropertyLayout makes sure that primitives are
799802 // stored in a byte[] at offsets that are long-aligned. When using the Static Object
@@ -804,19 +807,30 @@ private static final class StaticObjectArrayBasedSupport {
804807 int longIndexScale = ConfigurationValues .getObjectLayout ().getArrayIndexScale (JavaKind .Long );
805808 int misalignment = ConfigurationValues .getObjectLayout ().getArrayBaseOffset (JavaKind .Byte ) % longIndexScale ;
806809 ALIGNMENT_CORRECTION = misalignment == 0 ? 0 : longIndexScale - misalignment ;
810+
811+ if (ALIGNMENT_CORRECTION != 0 ) {
812+ // Can be an equality-based map because factory classes do not override
813+ // `hashCode()` and `equals()`.
814+ replacements = new ConcurrentHashMap <>();
815+ // `ArrayBasedStaticShape.replacements` must be initialized only when there is
816+ // an alignment correction, else some factories will not be replaced and will
817+ // continue to register replacement candidates.
818+ ReflectionUtil .writeStaticField (ARRAY_BASED_STATIC_SHAPE , "replacements" , replacements );
819+ FACTORY_CLASS_LOADER = loadClass ("com.oracle.truffle.api.staticobject.GeneratorClassLoaders$FactoryClassLoader" );
820+ } else {
821+ replacements = null ;
822+ FACTORY_CLASS_LOADER = null ;
823+ }
807824 }
808825
809826 static void duringSetup (DuringSetupAccess access ) {
810827 if (ALIGNMENT_CORRECTION != 0 ) {
811- ConcurrentHashMap <Object , Object > replacements = ReflectionUtil .readField (ARRAY_BASED_FACTORY , "replacements" , null );
812828 access .registerObjectReplacer (obj -> {
813829 if (!replacements .isEmpty ()) {
814830 boolean isByteArray = obj instanceof byte [];
815- if (isByteArray || ARRAY_BASED_FACTORY .isInstance (obj )) {
816-
831+ if (isByteArray || FACTORY_CLASS_LOADER .isInstance (obj .getClass ().getClassLoader ())) {
817832 Object replacement = replacements .get (obj );
818833 if (replacement != null ) {
819-
820834 // The `replacements` map is populated by the generated
821835 // factories. The keys of this map are the primitive byte arrays
822836 // and the factory instances that must be replaced, and the
@@ -890,8 +904,8 @@ static void onBuildInvocation(Class<?> storageSuperClass, Class<?> factoryInterf
890904 * ArrayBasedShapeGenerator caches generated classes, there won't be code
891905 * generation at run time.
892906 */
893- ClassLoader generatorCL = getGeneratorClassLoader (factoryInterface );
894- getGetShapeGenerator (generatorCL , storageSuperClass , factoryInterface );
907+ Object gcls = getGeneratorClassLoaders (factoryInterface );
908+ getGetShapeGenerator (gcls , storageSuperClass , factoryInterface );
895909 } catch (ReflectiveOperationException e ) {
896910 throw VMError .shouldNotReachHere (e );
897911 }
@@ -929,21 +943,21 @@ static void duringAnalysis(DuringAnalysisAccess access) {
929943 }
930944 }
931945
932- private static ClassLoader getGeneratorClassLoader (Class <?> factoryInterface ) throws ReflectiveOperationException {
933- ClassLoader cl = CLASS_LOADERS .get (factoryInterface );
934- if (cl == null ) {
935- ClassLoader newCL = ( ClassLoader ) GENERATOR_CLASS_LOADER_CONSTRUCTOR .newInstance (factoryInterface );
936- cl = CLASS_LOADERS .putIfAbsent (factoryInterface , newCL );
937- if (cl == null ) {
938- cl = newCL ;
946+ private static Object getGeneratorClassLoaders (Class <?> factoryInterface ) throws ReflectiveOperationException {
947+ Object gcls = GENERATOR_CLASS_LOADERS_MAP .get (factoryInterface );
948+ if (gcls == null ) {
949+ Object newGCLs = GENERATOR_CLASS_LOADERS_CONSTRUCTOR .newInstance (factoryInterface );
950+ gcls = GENERATOR_CLASS_LOADERS_MAP .putIfAbsent (factoryInterface , newGCLs );
951+ if (gcls == null ) {
952+ gcls = newGCLs ;
939953 }
940954 }
941- return cl ;
955+ return gcls ;
942956 }
943957
944- private static void getGetShapeGenerator (ClassLoader generatorCL , Class <?> storageSuperClass , Class <?> factoryInterface ) throws ReflectiveOperationException {
958+ private static void getGetShapeGenerator (Object gcls , Class <?> storageSuperClass , Class <?> factoryInterface ) throws ReflectiveOperationException {
945959 String storageClassName = (String ) STORAGE_CLASS_NAME .invoke (null );
946- GET_ARRAY_BASED_SHAPE_GENERATOR .invoke (null , null , generatorCL , storageSuperClass , factoryInterface , storageClassName );
960+ GET_ARRAY_BASED_SHAPE_GENERATOR .invoke (null , null , gcls , storageSuperClass , factoryInterface , storageClassName );
947961 }
948962
949963 private static Class <?> loadClass (String name ) {
@@ -1090,10 +1104,34 @@ final class Target_com_oracle_truffle_api_staticobject_PodBasedStaticShape<T> {
10901104 static native <T > Target_com_oracle_truffle_api_staticobject_PodBasedStaticShape <T > create (Class <?> generatedStorageClass , T factory , boolean safetyChecks , Object pod );
10911105}
10921106
1093- @ TargetClass (className = "com.oracle.truffle.api.staticobject.ArrayBasedStaticShape$ArrayBasedFactory " , onlyWith = TruffleBaseFeature .IsEnabled .class )
1094- final class Target_com_oracle_truffle_api_staticobject_ArrayBasedStaticShape_ArrayBasedFactory {
1095- @ Alias @ RecomputeFieldValue (kind = Kind .Reset ) //
1107+ @ TargetClass (className = "com.oracle.truffle.api.staticobject.ArrayBasedStaticShape" , onlyWith = TruffleBaseFeature .IsEnabled .class )
1108+ final class Target_com_oracle_truffle_api_staticobject_ArrayBasedStaticShape {
1109+ @ Alias @ RecomputeFieldValue (kind = Kind .Custom , declClass = MapCleaner . class , isFinal = true ) //
10961110 static ConcurrentHashMap <Object , Object > replacements ;
1111+
1112+ private static class MapCleaner implements FieldValueTransformerWithAvailability {
1113+ @ Override
1114+ public ValueAvailability valueAvailability () {
1115+ return ValueAvailability .AfterCompilation ;
1116+ }
1117+
1118+ @ Override
1119+ @ SuppressWarnings ("unchecked" )
1120+ public Object transform (Object receiver , Object originalValue ) {
1121+ if (originalValue != null ) {
1122+ ConcurrentHashMap <Object , Object > originalMap = (ConcurrentHashMap <Object , Object >) originalValue ;
1123+ // Copied so that the object replacer can continue replacing references, even after
1124+ // compilation.
1125+ TruffleBaseFeature .StaticObjectSupport .StaticObjectArrayBasedSupport .replacements = new ConcurrentHashMap <>(originalMap );
1126+ // Cleared so that factory instances that hold a reference to it do not leak
1127+ // objects.
1128+ originalMap .clear ();
1129+ // Return null so that new factory instances do not register replacements. See
1130+ // `ArrayBasedStaticShape.create()`.
1131+ }
1132+ return null ;
1133+ }
1134+ }
10971135}
10981136
10991137@ TargetClass (className = "com.oracle.truffle.api.staticobject.StaticProperty" , onlyWith = TruffleBaseFeature .IsEnabled .class )
0 commit comments