docs: public static double deepInstanceOf(JavaClass x, JavaClass y) throws ClassNotFoundException {
  
          if (x.equals(y)) {
              return 1.0;
          }
          if (Values.DOTTED_JAVA_LANG_OBJECT.equals(y.getClassName())) {
              return 1.0;
          }
          Subtypes2 subtypes2 = AnalysisContext.currentAnalysisContext().getSubtypes2();
          ClassDescriptor xDesc = DescriptorFactory.createClassDescriptor(x);
          ClassDescriptor yDesc = DescriptorFactory.createClassDescriptor(y);
  
          boolean xIsSubtypeOfY = Repository.instanceOf(x, y);
          if (xIsSubtypeOfY) {
              return 1.0;
          }
          boolean yIsSubtypeOfX = Repository.instanceOf(y, x);
          if (!yIsSubtypeOfX) {
              if (x.isFinal() || y.isFinal()) {
                  return 0.0;
              }
              if (!x.isInterface() && !y.isInterface()) {
                  return 0.0;
              }
          }
  
          Set<ClassDescriptor> transitiveCommonSubtypes = subtypes2.getTransitiveCommonSubtypes(xDesc, yDesc);
  
          if (transitiveCommonSubtypes.isEmpty()) {
              for (ClassDescriptor c : subtypes2.getSubtypes(xDesc)) {
                  XClass cx;
                  try {
                      cx = Global.getAnalysisCache().getClassAnalysis(XClass.class, c);
                  } catch (CheckedAnalysisException e) {
                      continue;
                  }
                  if (!cx.isAbstract() && !cx.isInterface()) {
                      if (x.isAbstract() || x.isInterface()) {
                          return 0.2;
                      }
                      return 0.1;
                  }
              }
              return 0.3;
          }
  
          // exist classes that are both X and Y
          Set<ClassDescriptor> xButNotY = new HashSet<>(subtypes2.getSubtypes(xDesc));
          xButNotY.removeAll(transitiveCommonSubtypes);
          for (ClassDescriptor c : xButNotY) {
  
              try {
                  XClass cx = Global.getAnalysisCache().getClassAnalysis(XClass.class, c);
                  if (!cx.isAbstract() && !cx.isInterface()) {
                      return 0.7;
                  }
              } catch (CheckedAnalysisException e) {
                  continue;
              }
  
          }
          return 0.99;
      }