system/src/sc/classfile/CFClass.java
private void initMethodAndFieldIndex() {
      CFMethod[] methods = classFile.methods;
      int tableSize = methods.length;

      CoalescedHashMap<String,Object[]> superMethods = null;
      CoalescedHashMap<String,Object[]>[] interfaceMethods = null;

      if (extendsType != null) {
         superMethods = ModelUtil.getMethodCache(extendsType);
         if (superMethods != null)
            tableSize += superMethods.size;
      }
      if (implementsTypes != null) {
         int numInterfaces = implementsTypes.size();
         interfaceMethods = new CoalescedHashMap[numInterfaces];
         for (int i = 0; i < numInterfaces; i++) {
            Object implType = implementsTypes.get(i);
            if (implType != null) {
               interfaceMethods[i] = ModelUtil.getMethodCache(implType);
               if (interfaceMethods[i] != null)
                  tableSize += interfaceMethods[i].size;
            }
         }
      }

      CoalescedHashMap<String,Object[]> cache = methodsByName = new CoalescedHashMap<String,Object[]>(tableSize);

      if (implementsTypes != null) {
         CoalescedHashMap<String,Object[]> implCache;
         for (int k = 0; k < implementsTypes.size(); k++) {
            Object implType = implementsTypes.get(k);
            if (implType != null) {
               implCache = ModelUtil.getMethodCache(implType);
               mergeSuperTypeMethods(implCache, implType);
            }
         }
      }
      if (superMethods != null) {
         mergeSuperTypeMethods(superMethods, extendsType);
      }

      for (CFMethod meth:methods) {
         String methodName = meth.name;
         Object method = meth;
         // Used to represent a method we inherit from the interface with a different signature (not that I could find this documented anyplace)
         if ((meth.accessFlags & AccessFlagInterfaceMethod) == AccessFlagInterfaceMethod)
            continue;
         // Is this actually set on methods anyplace by itself?
         if ((meth.accessFlags & Modifier.VOLATILE) != 0) {
            continue;
         }
         // Synthetic method - e.g. lambda code points and stuff like that
         if ((meth.accessFlags & SyntheticModifier) != 0) {
            continue;
         }
         Object[] methodList = cache.get(methodName);
         if (methodList == null) {
            methodList = new Object[1];
            methodList[0] = method;
            cache.put(methodName, methodList);
         }
         else {
            // Do not include super methods for the constructor - those are not inherited in Java
            Object[] superMethodList = methodName.equals("<init>") ? null : cache.get(methodName);
            boolean addToList = true;
            if (superMethodList != null) {
               for (int j = 0; j < superMethodList.length; j++) {
                  if (ModelUtil.overridesMethod(method, superMethodList[j])) {
                     addToList = false;
                     // Only override the method once for a given class.  Java has an annoying habit of returning
                     // interface methods that have different signatures from the class versions after the main
                     // methods in this list.  As long as we ignore those other methods, we get by ok.
                     if (j < methodList.length && superMethodList[j] == methodList[j]) {
                        // Used to use "pickMoreSpecificMethod" here but the isAssignableTo led to a recursive 'start' call which found an uninitialized method cache
                        // It looks like we really only need to choose between interface methods and real ones - since the default is that the sub-class overrides
                        // the base class for any implementation method.  That's true for 'abstract' methods as well here - e.g. an abstract class that overrides
                        // the Object.clone method and refines the type to
                        Object implMethod = ModelUtil.chooseImplMethod(superMethodList[j], method, false);
                        if (implMethod != null) {
                           method = implMethod;
                        }
                        // We start out with a CFMethod[] but may need to replace it with a Class if we override something
                        methodList = checkMethodList(cache, methodList, methodName, method);
                        methodList[j] = method;
                     }
                     // We'd like to break here and skip the rest of the loop but unfortunately Java returns methods with the same signature from
                     // getDeclared methods (e.g. AbstractStringBuilder.append(char)).   it also will not let you
                     // use those methods on an instance in this case.  So we need to replace all methods in the
                     // methodList that are overridden by this method.
                     //break;
                  }
               }
            }

            // New method - expand the list
            if (addToList) {
               Object[] newCachedList = new Object[methodList.length+1];
               System.arraycopy(methodList, 0, newCachedList, 0, methodList.length);
               newCachedList[methodList.length] = method;
               methodList = newCachedList;
               cache.put(methodName, methodList);
            }
            else {
               for (int j = 0; j < methodList.length; j++) {
                  Object otherMeth = methodList[j];
                  if (otherMeth != method && ModelUtil.overridesMethod(method, otherMeth)) {
                     Object newMethod = ModelUtil.pickMoreSpecificMethod(otherMeth, method, null, null, null);
                     if (newMethod == method) {
                        methodList = checkMethodList(cache, methodList, methodName, method);
                        methodList[j] = method;
                        break;
                     }
                  }
               }
            }
         }
      }

      // These do not include the super-type fields - instead, we aggregate on-the-fly in the various methods below.
      // The thinking is that it is pretty fast to do a property name lookup but more complex with methods given
      // the overriding rules.
      CFField[] fields = classFile.fields;
      fieldsByName = new CoalescedHashMap<String, CFField>(fields.length);
      for (CFField field:fields) {
         fieldsByName.put(field.name, field);
      }
   }
// put it into ModelUtil so it works generically pretty easily.
put it into ModelUtil so it works generically pretty easily.
put it into ModelUtil so it works generically pretty easily .
private void initMethodAndFieldIndex() {
      CFMethod[] methods = classFile.methods;
      int tableSize = methods.length;
      CoalescedHashMap<String,Object[]> superMethods = null;
      CoalescedHashMap<String,Object[]>[] interfaceMethods = null;
      if (extendsType != null) {
         superMethods = ModelUtil.getMethodCache(extendsType);
         if (superMethods != null)
            tableSize += superMethods.size;
      }
      if (implementsTypes != null) {
         int numInterfaces = implementsTypes.size();
         interfaceMethods = new CoalescedHashMap[numInterfaces];
         for (int i = 0; i < numInterfaces; i++) {
            Object implType = implementsTypes.get(i);
            if (implType != null) {
               interfaceMethods[i] = ModelUtil.getMethodCache(implType);
               if (interfaceMethods[i] != null)
                  tableSize += interfaceMethods[i].size;
            }
         }
      }
      CoalescedHashMap<String,Object[]> cache = methodsByName = new CoalescedHashMap<String,Object[]>(tableSize);
      if (implementsTypes != null) {
         CoalescedHashMap<String,Object[]> implCache;
         for (int k = 0; k < implementsTypes.size(); k++) {
            Object implType = implementsTypes.get(k);
            if (implType != null) {
               implCache = ModelUtil.getMethodCache(implType);
               mergeSuperTypeMethods(implCache, implType);
            }
         }
      }
      if (superMethods != null) {
         mergeSuperTypeMethods(superMethods, extendsType);
      }
      for (CFMethod meth:methods) {
         String methodName = meth.name;
         Object method = meth;
         if ((meth.accessFlags & AccessFlagInterfaceMethod) == AccessFlagInterfaceMethod)
            continue;
         if ((meth.accessFlags & Modifier.VOLATILE) != 0) {
            continue;
         }
         if ((meth.accessFlags & SyntheticModifier) != 0) {
            continue;
         }
         Object[] methodList = cache.get(methodName);
         if (methodList == null) {
            methodList = new Object[1];
            methodList[0] = method;
            cache.put(methodName, methodList);
         }
         else {
            Object[] superMethodList = methodName.equals("<init>") ? null : cache.get(methodName);
            boolean addToList = true;
            if (superMethodList != null) {
               for (int j = 0; j < superMethodList.length; j++) {
                  if (ModelUtil.overridesMethod(method, superMethodList[j])) {
                     addToList = false;
                     if (j < methodList.length && superMethodList[j] == methodList[j]) {
                        Object implMethod = ModelUtil.chooseImplMethod(superMethodList[j], method, false);
                        if (implMethod != null) {
                           method = implMethod;
                        }
                        methodList = checkMethodList(cache, methodList, methodName, method);
                        methodList[j] = method;
                     }
                  }
               }
            }
            if (addToList) {
               Object[] newCachedList = new Object[methodList.length+1];
               System.arraycopy(methodList, 0, newCachedList, 0, methodList.length);
               newCachedList[methodList.length] = method;
               methodList = newCachedList;
               cache.put(methodName, methodList);
            }
            else {
               for (int j = 0; j < methodList.length; j++) {
                  Object otherMeth = methodList[j];
                  if (otherMeth != method && ModelUtil.overridesMethod(method, otherMeth)) {
                     Object newMethod = ModelUtil.pickMoreSpecificMethod(otherMeth, method, null, null, null);
                     if (newMethod == method) {
                        methodList = checkMethodList(cache, methodList, methodName, method);
                        methodList[j] = method;
                        break;
                     }
                  }
               }
            }
         }
      }
      CFField[] fields = classFile.fields;
      fieldsByName = new CoalescedHashMap<String, CFField>(fields.length);
      for (CFField field:fields) {
         fieldsByName.put(field.name, field);
      }
   }
private void initMethodAndFieldIndex ( ) { CFMethod [ ] methods = classFile . methods ; int tableSize = methods . length ; CoalescedHashMap < String , Object [ ] > superMethods = null ; CoalescedHashMap < String , Object [ ] > [ ] interfaceMethods = null ; if ( extendsType != null ) { superMethods = ModelUtil . getMethodCache ( extendsType ) ; if ( superMethods != null ) tableSize += superMethods . size ; } if ( implementsTypes != null ) { int numInterfaces = implementsTypes . size ( ) ; interfaceMethods = new CoalescedHashMap [ numInterfaces ] ; for ( int i = 0 ; i < numInterfaces ; i ++ ) { Object implType = implementsTypes . get ( i ) ; if ( implType != null ) { interfaceMethods [ i ] = ModelUtil . getMethodCache ( implType ) ; if ( interfaceMethods [ i ] != null ) tableSize += interfaceMethods [ i ] . size ; } } } CoalescedHashMap < String , Object [ ] > cache = methodsByName = new CoalescedHashMap < String , Object [ ] > ( tableSize ) ; if ( implementsTypes != null ) { CoalescedHashMap < String , Object [ ] > implCache ; for ( int k = 0 ; k < implementsTypes . size ( ) ; k ++ ) { Object implType = implementsTypes . get ( k ) ; if ( implType != null ) { implCache = ModelUtil . getMethodCache ( implType ) ; mergeSuperTypeMethods ( implCache , implType ) ; } } } if ( superMethods != null ) { mergeSuperTypeMethods ( superMethods , extendsType ) ; } for ( CFMethod meth : methods ) { String methodName = meth . name ; Object method = meth ; if ( ( meth . accessFlags & AccessFlagInterfaceMethod ) == AccessFlagInterfaceMethod ) continue ; if ( ( meth . accessFlags & Modifier . VOLATILE ) != 0 ) { continue ; } if ( ( meth . accessFlags & SyntheticModifier ) != 0 ) { continue ; } Object [ ] methodList = cache . get ( methodName ) ; if ( methodList == null ) { methodList = new Object [ 1 ] ; methodList [ 0 ] = method ; cache . put ( methodName , methodList ) ; } else { Object [ ] superMethodList = methodName . equals ( "<init>" ) ? null : cache . get ( methodName ) ; boolean addToList = true ; if ( superMethodList != null ) { for ( int j = 0 ; j < superMethodList . length ; j ++ ) { if ( ModelUtil . overridesMethod ( method , superMethodList [ j ] ) ) { addToList = false ; if ( j < methodList . length && superMethodList [ j ] == methodList [ j ] ) { Object implMethod = ModelUtil . chooseImplMethod ( superMethodList [ j ] , method , false ) ; if ( implMethod != null ) { method = implMethod ; } methodList = checkMethodList ( cache , methodList , methodName , method ) ; methodList [ j ] = method ; } } } } if ( addToList ) { Object [ ] newCachedList = new Object [ methodList . length + 1 ] ; System . arraycopy ( methodList , 0 , newCachedList , 0 , methodList . length ) ; newCachedList [ methodList . length ] = method ; methodList = newCachedList ; cache . put ( methodName , methodList ) ; } else { for ( int j = 0 ; j < methodList . length ; j ++ ) { Object otherMeth = methodList [ j ] ; if ( otherMeth != method && ModelUtil . overridesMethod ( method , otherMeth ) ) { Object newMethod = ModelUtil . pickMoreSpecificMethod ( otherMeth , method , null , null , null ) ; if ( newMethod == method ) { methodList = checkMethodList ( cache , methodList , methodName , method ) ; methodList [ j ] = method ; break ; } } } } } } CFField [ ] fields = classFile . fields ; fieldsByName = new CoalescedHashMap < String , CFField > ( fields . length ) ; for ( CFField field : fields ) { fieldsByName . put ( field . name , field ) ; } }
put it into ModelUtil so it works generically pretty easily.
put it into ModelUtil so it works generically pretty easily .
// Used to represent a method we inherit from the interface with a different signature (not that I could find this documented anyplace) // Is this actually set on methods anyplace by itself? // Synthetic method - e.g. lambda code points and stuff like that // Do not include super methods for the constructor - those are not inherited in Java // Only override the method once for a given class.  Java has an annoying habit of returning // interface methods that have different signatures from the class versions after the main // methods in this list.  As long as we ignore those other methods, we get by ok. // Used to use "pickMoreSpecificMethod" here but the isAssignableTo led to a recursive 'start' call which found an uninitialized method cache // It looks like we really only need to choose between interface methods and real ones - since the default is that the sub-class overrides // the base class for any implementation method.  That's true for 'abstract' methods as well here - e.g. an abstract class that overrides // the Object.clone method and refines the type to // We start out with a CFMethod[] but may need to replace it with a Class if we override something // We'd like to break here and skip the rest of the loop but unfortunately Java returns methods with the same signature from // getDeclared methods (e.g. AbstractStringBuilder.append(char)).   it also will not let you // use those methods on an instance in this case.  So we need to replace all methods in the // methodList that are overridden by this method. //break; // New method - expand the list // These do not include the super-type fields - instead, we aggregate on-the-fly in the various methods below. // The thinking is that it is pretty fast to do a property name lookup but more complex with methods given // the overriding rules.