예제 #1
0
  public boolean mustCompile(Clazz clazz) {
    File oFile = config.getOFile(clazz);
    if (!oFile.exists() || oFile.lastModified() < clazz.lastModified()) {
      return true;
    }

    Set<Dependency> dependencies = clazz.getDependencies();
    for (Dependency dep : dependencies) {
      Clazz depClazz = config.getClazzes().load(dep.getClassName());
      if (depClazz == null) {
        if (dep.getPath() != null) {
          // depClazz was available the last time clazz was compiled but is now gone
          return true;
        }
      } else {
        if (dep.getPath() == null) {
          // depClazz was not available the last time clazz was compiled but is now available
          return true;
        }
        if (!dep.getPath().equals(depClazz.getPath().getFile().getAbsolutePath())) {
          // depClazz was located in another place the last time clazz was built
          return true;
        }
        if (depClazz.isInBootClasspath() != dep.isInBootClasspath()) {
          // depClazz has moved to/from the bootclasspath since the last time clazz was built
          return true;
        }
        if (depClazz.lastModified() > oFile.lastModified()) {
          // depClazz has been changed since the last time clazz was built
          return true;
        }
      }
    }

    // No class or interface has zero dependencies (we always add java.lang.Object as a dependency)
    // If dependencies is empty it probably means that an error occurred while reading the
    // serialized dependencies. By returning true here in that case the class will be recompiled
    // and the dependencies regenerated.
    return dependencies.isEmpty();
  }
예제 #2
0
  private StructureConstant createClassInfoErrorStruct() {
    /*
     * Check that clazz can be loaded, i.e. that the superclass
     * and interfaces of the class exist and are accessible to the
     * class. Also check that any exception the class uses in catch
     * clauses exist and is accessible to the class. If the class
     * cannot be loaded we override the ClassInfoHeader struct
     * produced by the ClassCompiler for the class with one which
     * tells the code in bc.c to throw an appropriate exception
     * whenever clazz is accessed.
     */

    int errorType = ClassCompiler.CI_ERROR_TYPE_NONE;
    String errorMessage = null;
    if (!sootClass.isInterface() && sootClass.hasSuperclass()) {
      // Check superclass
      SootClass superclazz = sootClass.getSuperclass();
      if (superclazz.isPhantom()) {
        errorType = ClassCompiler.CI_ERROR_TYPE_NO_CLASS_DEF_FOUND;
        errorMessage = superclazz.getName();
      } else if (!checkClassAccessible(superclazz, sootClass)) {
        errorType = ClassCompiler.CI_ERROR_TYPE_ILLEGAL_ACCESS;
        errorMessage = String.format(ILLEGAL_ACCESS_ERROR_CLASS, superclazz, sootClass);
      } else if (superclazz.isInterface()) {
        errorType = ClassCompiler.CI_ERROR_TYPE_INCOMPATIBLE_CLASS_CHANGE;
        errorMessage =
            String.format("class %s has interface %s as super class", sootClass, superclazz);
      }
      // No need to check for ClassCircularityError. Soot doesn't handle
      // such problems so the compilation will fail earlier.
    }

    if (errorType == ClassCompiler.CI_ERROR_TYPE_NONE) {
      // Check interfaces
      for (SootClass interfaze : sootClass.getInterfaces()) {
        if (interfaze.isPhantom()) {
          errorType = ClassCompiler.CI_ERROR_TYPE_NO_CLASS_DEF_FOUND;
          errorMessage = interfaze.getName();
          break;
        } else if (!checkClassAccessible(interfaze, sootClass)) {
          errorType = ClassCompiler.CI_ERROR_TYPE_ILLEGAL_ACCESS;
          errorMessage = String.format(ILLEGAL_ACCESS_ERROR_CLASS, interfaze, sootClass);
          break;
        } else if (!interfaze.isInterface()) {
          errorType = ClassCompiler.CI_ERROR_TYPE_INCOMPATIBLE_CLASS_CHANGE;
          errorMessage =
              String.format(
                  "class %s tries to implement class %s as interface", sootClass, interfaze);
          break;
        }
      }
    }

    if (errorType == ClassCompiler.CI_ERROR_TYPE_NONE) {
      // Check exceptions used in catch clauses. I cannot find any info in
      // the VM spec specifying that this has to be done when the class is loaded.
      // However, this is how it's done in other VMs so we do it too.
      for (String exName : catches) {
        Clazz ex = config.getClazzes().load(exName);
        if (ex == null || ex.getSootClass().isPhantom()) {
          errorType = ClassCompiler.CI_ERROR_TYPE_NO_CLASS_DEF_FOUND;
          errorMessage = exName;
          break;
        } else if (!checkClassAccessible(ex.getSootClass(), sootClass)) {
          errorType = ClassCompiler.CI_ERROR_TYPE_ILLEGAL_ACCESS;
          errorMessage = String.format(ILLEGAL_ACCESS_ERROR_CLASS, ex, sootClass);
          break;
        }
      }
    }

    if (errorType == ClassCompiler.CI_ERROR_TYPE_NONE) {
      return null;
    }

    // Create a ClassInfoError struct
    StructureConstantBuilder error = new StructureConstantBuilder();
    error.add(new NullConstant(I8_PTR)); // Points to the runtime Class struct
    error.add(new IntegerConstant(ClassCompiler.CI_ERROR));
    error.add(getString(getInternalName(sootClass)));
    error.add(new IntegerConstant(errorType));
    error.add(getString(errorMessage));
    return error.build();
  }