docs: private static ClassMetadata getClassMetadata(final Class cls, final Map /* <Class,ClassMetadata> */metadataMap,
                                                    final ClassAccessPrivilegedAction caAction,
                                                    final FieldAccessPrivilegedAction faAction) {
          if (null == cls) {
              return null;
          }
  
          ClassMetadata result;
          synchronized (metadataMap) {
              result = (ClassMetadata) metadataMap.get(cls);
          }
          if (result != null) {
              return result;
          }
  
          int primitiveFieldCount = 0;
          int shellSize = OBJECT_SHELL_SIZE; // java.lang.Object shell
          final List /* Field */refFields = new LinkedList();
  
          final Field[] declaredFields;
          try {
              caAction.setContext(cls);
              declaredFields = (Field[]) AccessController.doPrivileged(caAction);
          } catch (PrivilegedActionException pae) {
              throw new RuntimeException("could not access declared fields of class " + cls.getName() + ": "
                                         + pae.getException());
          }
  
          for (int f = 0; f < declaredFields.length; ++f) {
              final Field field = declaredFields[f];
              if (Modifier.isStatic(field.getModifiers())) {
                  continue;
              }
              /*
               * Can't do that: HashMap data is transient, for example... if (Modifier.isTransient(field.getModifiers()))
               * { shellSize += OBJREF_SIZE; continue; }
               */
  
              final Class fieldType = field.getType();
              if (fieldType.isPrimitive()) {
                  // memory alignment ignored:
                  shellSize += sizeofPrimitiveType(fieldType);
                  ++primitiveFieldCount;
              } else {
                  // prepare for graph traversal later:
                  if (!field.isAccessible()) {
                      try {
                          faAction.setContext(field);
                          AccessController.doPrivileged(faAction);
                      } catch (PrivilegedActionException pae) {
                          throw new RuntimeException("could not make field " + field + " accessible: "
                                                     + pae.getException());
                      }
                  }
  
                  // memory alignment ignored:
                  shellSize += OBJREF_SIZE;
                  refFields.add(field);
              }
          }
  
          // recurse into superclass:
          final ClassMetadata superMetadata = getClassMetadata(cls.getSuperclass(), metadataMap, caAction, faAction);
          if (superMetadata != null) {
              primitiveFieldCount += superMetadata.m_primitiveFieldCount;
              shellSize += superMetadata.m_shellSize - OBJECT_SHELL_SIZE;
              refFields.addAll(Arrays.asList(superMetadata.m_refFields));
          }
  
          final Field[] _refFields = new Field[refFields.size()];
          refFields.toArray(_refFields);
  
          result = new ClassMetadata(primitiveFieldCount, shellSize, _refFields);
          synchronized (metadataMap) {
              metadataMap.put(cls, result);
          }
  
          return result;
      }