You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@uima.apache.org by sc...@apache.org on 2017/10/09 13:55:37 UTC

svn commit: r1811572 - in /uima/uv3/uimaj-v3/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl: FSClassRegistry.java TypeSystemImpl.java

Author: schor
Date: Mon Oct  9 13:55:37 2017
New Revision: 1811572

URL: http://svn.apache.org/viewvc?rev=1811572&view=rev
Log:
[UIMA-5607] change method of setup for constants in jcas classes to use reflection, rather than depending on static initializers running in the context of a type system commit.

Modified:
    uima/uv3/uimaj-v3/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSClassRegistry.java
    uima/uv3/uimaj-v3/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/TypeSystemImpl.java

Modified: uima/uv3/uimaj-v3/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSClassRegistry.java
URL: http://svn.apache.org/viewvc/uima/uv3/uimaj-v3/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSClassRegistry.java?rev=1811572&r1=1811571&r2=1811572&view=diff
==============================================================================
--- uima/uv3/uimaj-v3/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSClassRegistry.java (original)
+++ uima/uv3/uimaj-v3/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSClassRegistry.java Mon Oct  9 13:55:37 2017
@@ -140,10 +140,10 @@ public abstract class FSClassRegistry {
   // must precede first (static) use
   static private ThreadLocal<List<ErrorReport>> errorSet = new ThreadLocal<>();
  
-  /**
-   * Map (per class loader) from JCas Classes, to all callSites in that JCas class 
-   */
-  public static final Map<Class<? extends TOP>, ArrayList<Entry<String, MutableCallSite>>> callSites_all_JCasClasses = new HashMap<>();
+//  /**
+//   * Map (per class loader) from JCas Classes, to all callSites in that JCas class 
+//   */
+//  public static final Map<Class<? extends TOP>, ArrayList<Entry<String, MutableCallSite>>> callSites_all_JCasClasses = new HashMap<>();
 
   /**
    * One instance per UIMA Type per class loader
@@ -278,6 +278,8 @@ public abstract class FSClassRegistry {
       }
     }
     
+    callSites_toSync.clear();
+    
     /**
      * copy in built-ins
      *   update t2jcci (if not already loaded) with load info for type
@@ -294,6 +296,7 @@ public abstract class FSClassRegistry {
           type_to_jcasClassInfo.put(jcasClass.getCanonicalName(), jcas_class_info);
         }
         setTypeFromJCasIDforBuiltIns(jcas_class_info, ts, typecode);
+        updateAllCallSitesForJCasClass((Class<? extends TOP>) jcasClass, ts.getTypeForCode(typecode));
       }
     }  
     
@@ -327,7 +330,7 @@ public abstract class FSClassRegistry {
         throw new UIMARuntimeException(e, UIMARuntimeException.INTERNAL_ERROR);
       }
 
-      callSites_toSync.clear();
+
       maybeLoadJCasAndSubtypes(ts, ts.topType, type_to_jcasClassInfo.get(TOP.class.getCanonicalName()), cl, type_to_jcasClassInfo);
       
       MutableCallSite[] sync = callSites_toSync.toArray(new MutableCallSite[callSites_toSync.size()]);
@@ -472,48 +475,21 @@ public abstract class FSClassRegistry {
    * @return the loaded / resolved class
    */
   private static Class<?> maybeLoadJCas(TypeImpl ti, ClassLoader cl) {
-    Class<?> clazz = null;
+    Class<? extends TOP> clazz = null;
     String className = Misc.typeName2ClassName(ti.getName());
     
     try { 
-      TypeSystemImpl.typeBeingLoadedThreadLocal.set(ti);
-      clazz = Class.forName(className, true, cl);
-      ArrayList<Entry<String, MutableCallSite>> callsites = callSites_all_JCasClasses.get(clazz);
-      if (null != callsites) {
-        for (Entry<String, MutableCallSite> e : callsites) {
-          final int index = TypeSystemImpl.getAdjustedFeatureOffset(e.getKey());
-          if (index == -1) {
-            continue;  // a feature in the JCas class doesn't exist in the currently loaded type system
-                       // skip setting it.  If code uses this, a runtime error will happen.
-          }
-          final int prev = (int) e.getValue().getTarget().invokeExact();
-          
-          if (prev == -1) {
-            MethodHandle mh_constant = getConstantIntMethodHandle(index);
-
-            e.getValue().setTarget(mh_constant);
-            callSites_toSync.add(e.getValue());
-          } else if (prev != index) {
-            throw new UIMA_IllegalStateException(UIMA_IllegalStateException.JCAS_INCOMPATIBLE_TYPE_SYSTEMS,
-                new Object[] {ti.getName(), e.getKey()});
-          }
-
-        }
-      }
+      clazz = (Class<? extends TOP>) Class.forName(className, true, cl);
+      updateAllCallSitesForJCasClass(clazz, ti);
     } catch (ClassNotFoundException e) {
       // Class not found is normal, if there is no JCas for this class
-    } catch (Throwable e1) {
-      if (e1 instanceof UIMA_IllegalStateException) {
-        throw (UIMA_IllegalStateException) e1;
-      }
-      throw Misc.internalError();  // from invokeExact
     } finally {
       TypeSystemImpl.typeBeingLoadedThreadLocal.set(null);
     }
     return clazz;
   }
       
-  private static synchronized MethodHandle getConstantIntMethodHandle(int i) {
+  static synchronized MethodHandle getConstantIntMethodHandle(int i) {
     MethodHandle mh = Misc.getWithExpand(methodHandlesForInt, i);
     if (mh == null) {
       methodHandlesForInt.set(i, mh = MethodHandles.constant(int.class, i));
@@ -682,7 +658,7 @@ public abstract class FSClassRegistry {
   
 //  static boolean isFieldInClass(Feature feat, Class<?> clazz) {
 //    try {
-//      return null != clazz.getDeclaredField("_FI_" + feat.getShortName());
+//      return null != clazz.getDeclaredField("_FC_" + feat.getShortName());
 //    } catch (NoSuchFieldException e) {
 //      return false;
 //    }    
@@ -705,7 +681,7 @@ public abstract class FSClassRegistry {
    * Checks that a JCas class definition conforms to the current type in the current type system.
    * Checks that the superclass chain contains some match to the super type chain.
    * Checks that the return value for the getters for features matches the feature's range.
-   * Checks that static _FI_xxx values from the JCas class == the adjusted feature offsets in the type system
+   * Checks that static _FC_xxx values from the JCas class == the adjusted feature offsets in the type system
    * 
    * @param clazz - the JCas class to check
    * @param tsi -
@@ -797,32 +773,38 @@ public abstract class FSClassRegistry {
         }
       }
     }
-    
-    for (Field f : clazz.getDeclaredFields()) {
-      String fname = f.getName();
-      if (fname.length() <= 5 || !fname.startsWith("_FI_")) continue;
-      String featName = fname.substring(4);
-      FeatureImpl fi = ti.getFeatureByBaseName(featName);
-      if (fi == null) {
-        add2errors(errorSet, 
-                   new CASRuntimeException(CASRuntimeException.JCAS_FIELD_MISSING_IN_TYPE_SYSTEM, clazz.getName(), featName), 
-                   false);  // don't throw on this error, field is set to -1 and will throw if trying to use it   
-       } else {
-        int staticOffsetInClass = Misc.getPrivateStaticIntFieldNoInherit(clazz, fname);
-        if (fi.getAdjustedOffset() != staticOffsetInClass) {
-          /** In JCAS class "{0}", UIMA field "{1}" was set up when this class was previously loaded and initialized, to have
-           * an adjusted offset of "{2}" but now the feature has a different adjusted offset of "{3}"; this may be due to 
-           * something else other than type system commit actions loading and initializing the JCas class, or to
-           * having a different non-compatible type system for this class, trying to use a common JCas cover class, which is not supported. */
+    try {
+      for (Field f : clazz.getDeclaredFields()) {
+        String fname = f.getName();
+        if (fname.length() <= 5 || !fname.startsWith("_FC_")) continue;
+        String featName = fname.substring(4);
+        FeatureImpl fi = ti.getFeatureByBaseName(featName);
+        if (fi == null) {
           add2errors(errorSet, 
-                     new CASRuntimeException(CASRuntimeException.JCAS_FIELD_ADJ_OFFSET_CHANGED,
-                        clazz.getName(), 
-                        fi.getName(), 
-                        Integer.valueOf(staticOffsetInClass), 
-                        Integer.valueOf(fi.getAdjustedOffset())),
-                     staticOffsetInClass != -1);  // throw unless static offset is -1, in that case, a runtime error will occur if it is usedd
-        }
-      }
+                     new CASRuntimeException(CASRuntimeException.JCAS_FIELD_MISSING_IN_TYPE_SYSTEM, clazz.getName(), featName), 
+                     false);  // don't throw on this error, field is set to -1 and will throw if trying to use it   
+        } else {
+          Field mhf = clazz.getDeclaredField("_FH_" + featName);
+          mhf.setAccessible(true);
+          MethodHandle mh = (MethodHandle) mhf.get(null);
+          int staticOffsetInClass = (int) mh.invokeExact();
+          if (fi.getAdjustedOffset() != staticOffsetInClass) {
+             /** In JCAS class "{0}", UIMA field "{1}" was set up when this class was previously loaded and initialized, to have
+             * an adjusted offset of "{2}" but now the feature has a different adjusted offset of "{3}"; this may be due to 
+             * something else other than type system commit actions loading and initializing the JCas class, or to
+             * having a different non-compatible type system for this class, trying to use a common JCas cover class, which is not supported. */
+            add2errors(errorSet, 
+                       new CASRuntimeException(CASRuntimeException.JCAS_FIELD_ADJ_OFFSET_CHANGED,
+                          clazz.getName(), 
+                          fi.getName(), 
+                          Integer.valueOf(staticOffsetInClass), 
+                          Integer.valueOf(fi.getAdjustedOffset())),
+                       staticOffsetInClass != -1);  // throw unless static offset is -1, in that case, a runtime error will occur if it is usedd
+          }  // end of offset changed
+        }  // end of feature check
+      } // end of for loop
+    } catch (Throwable e) {
+      throw new RuntimeException(e);
     }
   }
   
@@ -918,5 +900,42 @@ public abstract class FSClassRegistry {
     return true;
   }
 
+  private static void updateAllCallSitesForJCasClass(Class<? extends TOP> clazz, TypeImpl type) {
+    try {
+      Field[] fields = clazz.getDeclaredFields();
+     
+      for (Field field : fields) {
+        String fieldName = field.getName();
+        if (fieldName.startsWith("_FC_")) {
+  
+          String featureName = fieldName.substring("_FC_".length());
+          final int index = TypeSystemImpl.getAdjustedFeatureOffset(type, featureName);
+          if (index == -1) {
+            continue;  // a feature defined in the JCas class doesn't exist in the currently loaded type
+          }             // skip setting it.  If code uses this, a runtime error will happen.
+          
+          MutableCallSite c;
+          field.setAccessible(true);
+          c = (MutableCallSite) field.get(null);
+          
+          if (c == null) { // happens when first load of TypeSystemImpl is from JCas class ref
+            continue;  // will be set later when type system is committed.
+          }
+          
+          int prev = (int) c.getTarget().invokeExact();
+          if (prev == -1) {
+            MethodHandle mh_constant = getConstantIntMethodHandle(index);
+            c.setTarget(mh_constant);
+            callSites_toSync.add(c);
+          } else if (prev != index) {
+            throw new UIMA_IllegalStateException(UIMA_IllegalStateException.JCAS_INCOMPATIBLE_TYPE_SYSTEMS,
+                new Object[] {type.getName(), featureName});
+          }
+        }
+      }
+    } catch (Throwable e) {
+      Misc.internalError(e); // never happen
+    }
+  }
 }
   
\ No newline at end of file

Modified: uima/uv3/uimaj-v3/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/TypeSystemImpl.java
URL: http://svn.apache.org/viewvc/uima/uv3/uimaj-v3/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/TypeSystemImpl.java?rev=1811572&r1=1811571&r2=1811572&view=diff
==============================================================================
--- uima/uv3/uimaj-v3/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/TypeSystemImpl.java (original)
+++ uima/uv3/uimaj-v3/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/TypeSystemImpl.java Mon Oct  9 13:55:37 2017
@@ -38,7 +38,6 @@ import java.lang.invoke.MethodHandles;
 import java.lang.invoke.MethodType;
 import java.lang.invoke.MutableCallSite;
 import java.lang.ref.WeakReference;
-import java.util.AbstractMap;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
@@ -48,7 +47,6 @@ import java.util.IdentityHashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
-import java.util.Map.Entry;
 import java.util.Set;
 import java.util.Vector;
 import java.util.WeakHashMap;
@@ -2589,8 +2587,7 @@ public class TypeSystemImpl implements T
 //  Class<?> getJCasClass(int typecode) {
 //    return jcasClassesInfo[typecode].jcasClass; 
 //  }
-  
-  /**
+    /**
    * This code is run when a JCas class is loaded and resolved, for the first time, as part of type system commit, or
    * as part of statically loading the FSClassRegister class (where this is done for all the built-ins, once).
    * It looks up the offset value in the type system (via a thread-local)
@@ -2613,8 +2610,14 @@ public class TypeSystemImpl implements T
        * Class.forName("myJCasClass", false, this.getClass().getClassLoader()).*/
       throw new CASRuntimeException(CASRuntimeException.JCAS_CLASS_INITIALIZED_BEFORE_TYPE_SYSTEM_COMMIT);
     }
+
     FeatureImpl fi = type.getFeatureByBaseName(featName);
-    return (fi == null) ? -1 : fi.getAdjustedOffset();
+    return (fi == null) ? -1 : fi.getAdjustedOffset();    
+  }
+  
+  static synchronized int getAdjustedFeatureOffset(TypeImpl type, String featName) {
+    FeatureImpl fi = type.getFeatureByBaseName(featName);
+    return (fi == null) ? -1 : fi.getAdjustedOffset();    
   }
     
   /**
@@ -2654,27 +2657,30 @@ public class TypeSystemImpl implements T
     
   /**
    * Creates and returns a new MutableCallSite, 
-   * recording it in list of all callsites for this type, in a map by typename
-   * 
-   * Done this way because 
-   *   - can't be a classloader-wide list of call sites - some might not be associated with this type system
-   *   - can't be a typesystem-wide list of call sites - the JCas class might be used by multiple type systems
-   *     and the first one to load it would set this value.
-   *   - has to be pairs of feature name, call-site, in order to get the value to set, later
-   *   --  doesn't need to be a hashmap, can be an arraylist of entry
-   *   Type being loaded may not be known at this point.
+//   * recording it in list of all callsites for this type, in a map by typename
+//   * 
+//   * Done this way because 
+//   *   - can't be a classloader-wide list of call sites - some might not be associated with this type system
+//   *   - can't be a typesystem-wide list of call sites - the JCas class might be used by multiple type systems
+//   *     and the first one to load it would set this value.
+//   *   - has to be pairs of feature name, call-site, in order to get the value to set, later
+//   *   --  doesn't need to be a hashmap, can be an arraylist of entry
+//   *   Type being loaded may not be known at this point.
    * @param clazz the JCas class
    * @param featName the short name of the feature
    * @return the created callsite
    */
-  public static MutableCallSite createCallSite(Class<? extends TOP> clazz, String featName) {
-    MutableCallSite callSite = new MutableCallSite(MethodType.methodType(int.class)); 
+  public final static MutableCallSite createCallSite(Class<? extends TOP> clazz, String featName) {
+    MutableCallSite callSite = new MutableCallSite(MethodType.methodType(int.class));
     callSite.setTarget(MHC_MINUS_1);  // for error checking
-    ArrayList<Entry<String, MutableCallSite>> callSitesForType = FSClassRegistry.callSites_all_JCasClasses.computeIfAbsent(clazz, k -> new ArrayList<>());
-    callSitesForType.add(new AbstractMap.SimpleEntry<String, MutableCallSite>(featName, callSite));
+//    ArrayList<Entry<String, MutableCallSite>> callSitesForType = FSClassRegistry.callSites_all_JCasClasses.computeIfAbsent(clazz, k -> new ArrayList<>());
+//    callSitesForType.add(new AbstractMap.SimpleEntry<String, MutableCallSite>(featName, callSite));
     return callSite;
   }
 
+//  private static boolean isBuiltIn(Class<? extends TOP> clazz) {
+//    return BuiltinTypeKinds.creatableBuiltinJCasClassNames.contains(clazz.getName());
+//  }
 //  /**
 //   * Get a list of types which have OID feature, filtered down to being just the top-most
 //   * (in the type hierarchy)