Ejemplo n.º 1
0
  /** Helper that updates the dex statistics. */
  private static void updateDexStatistics(
      CfOptions cfOptions,
      DexOptions dexOptions,
      RopMethod optRmeth,
      RopMethod nonOptRmeth,
      LocalVariableInfo locals,
      int paramSize,
      int originalByteCount) {
    /*
     * Run rop->dex again on optimized vs. non-optimized method to
     * collect statistics. We have to totally convert both ways,
     * since converting the "real" method getting added to the
     * file would corrupt it (by messing with its constant pool
     * indices).
     */

    DalvCode optCode =
        RopTranslator.translate(optRmeth, cfOptions.positionInfo, locals, paramSize, dexOptions);
    DalvCode nonOptCode =
        RopTranslator.translate(nonOptRmeth, cfOptions.positionInfo, locals, paramSize, dexOptions);

    /*
     * Fake out the indices, so code.getInsns() can work well enough
     * for the current purpose.
     */

    DalvCode.AssignIndicesCallback callback =
        new DalvCode.AssignIndicesCallback() {
          public int getIndex(Constant cst) {
            // Everything is at index 0!
            return 0;
          }
        };

    optCode.assignIndices(callback);
    nonOptCode.assignIndices(callback);

    CodeStatistics.updateDexStatistics(nonOptCode, optCode);
    CodeStatistics.updateOriginalByteCount(originalByteCount);
  }
Ejemplo n.º 2
0
  /**
   * Processes the methods of the given class.
   *
   * @param cf {@code non-null;} class being translated
   * @param cfOptions {@code non-null;} options for class translation
   * @param dexOptions {@code non-null;} options for dex output
   * @param out {@code non-null;} output class
   */
  private static void processMethods(
      DirectClassFile cf, CfOptions cfOptions, DexOptions dexOptions, ClassDefItem out) {
    CstType thisClass = cf.getThisClass();
    MethodList methods = cf.getMethods();
    int sz = methods.size();

    for (int i = 0; i < sz; i++) {
      Method one = methods.get(i);
      try {
        CstMethodRef meth = new CstMethodRef(thisClass, one.getNat());
        int accessFlags = one.getAccessFlags();
        boolean isStatic = AccessFlags.isStatic(accessFlags);
        boolean isPrivate = AccessFlags.isPrivate(accessFlags);
        boolean isNative = AccessFlags.isNative(accessFlags);
        boolean isAbstract = AccessFlags.isAbstract(accessFlags);
        boolean isConstructor = meth.isInstanceInit() || meth.isClassInit();
        DalvCode code;

        if (isNative || isAbstract) {
          // There's no code for native or abstract methods.
          code = null;
        } else {
          ConcreteMethod concrete =
              new ConcreteMethod(
                  one, cf, (cfOptions.positionInfo != PositionList.NONE), cfOptions.localInfo);

          TranslationAdvice advice;

          advice = DexTranslationAdvice.THE_ONE;

          RopMethod rmeth = Ropper.convert(concrete, advice);
          RopMethod nonOptRmeth = null;
          int paramSize;

          paramSize = meth.getParameterWordCount(isStatic);

          String canonicalName =
              thisClass.getClassType().getDescriptor() + "." + one.getName().getString();

          if (cfOptions.optimize && OptimizerOptions.shouldOptimize(canonicalName)) {
            if (DEBUG) {
              System.err.println("Optimizing " + canonicalName);
            }

            nonOptRmeth = rmeth;
            rmeth = Optimizer.optimize(rmeth, paramSize, isStatic, cfOptions.localInfo, advice);

            if (DEBUG) {
              OptimizerOptions.compareOptimizerStep(
                  nonOptRmeth, paramSize, isStatic, cfOptions, advice, rmeth);
            }

            if (cfOptions.statistics) {
              CodeStatistics.updateRopStatistics(nonOptRmeth, rmeth);
            }
          }

          LocalVariableInfo locals = null;

          if (cfOptions.localInfo) {
            locals = LocalVariableExtractor.extract(rmeth);
          }

          code =
              RopTranslator.translate(rmeth, cfOptions.positionInfo, locals, paramSize, dexOptions);

          if (cfOptions.statistics && nonOptRmeth != null) {
            updateDexStatistics(
                cfOptions,
                dexOptions,
                rmeth,
                nonOptRmeth,
                locals,
                paramSize,
                concrete.getCode().size());
          }
        }

        // Preserve the synchronized flag as its "declared" variant...
        if (AccessFlags.isSynchronized(accessFlags)) {
          accessFlags |= AccessFlags.ACC_DECLARED_SYNCHRONIZED;

          /*
           * ...but only native methods are actually allowed to be
           * synchronized.
           */
          if (!isNative) {
            accessFlags &= ~AccessFlags.ACC_SYNCHRONIZED;
          }
        }

        if (isConstructor) {
          accessFlags |= AccessFlags.ACC_CONSTRUCTOR;
        }

        TypeList exceptions = AttributeTranslator.getExceptions(one);
        EncodedMethod mi = new EncodedMethod(meth, accessFlags, code, exceptions);

        if (meth.isInstanceInit() || meth.isClassInit() || isStatic || isPrivate) {
          out.addDirectMethod(mi);
        } else {
          out.addVirtualMethod(mi);
        }

        Annotations annotations = AttributeTranslator.getMethodAnnotations(one);
        if (annotations.size() != 0) {
          out.addMethodAnnotations(meth, annotations);
        }

        AnnotationsList list = AttributeTranslator.getParameterAnnotations(one);
        if (list.size() != 0) {
          out.addParameterAnnotations(meth, list);
        }
      } catch (RuntimeException ex) {
        String msg =
            "...while processing " + one.getName().toHuman() + " " + one.getDescriptor().toHuman();
        throw ExceptionWithContext.withContext(ex, msg);
      }
    }
  }