All Downloads are FREE. Search and download functionalities are using the official Maven repository.

soot.AbstractASMBackend Maven / Gradle / Ivy

package soot;

/*-
 * #%L
 * Soot - a J*va Optimization Framework
 * %%
 * Copyright (C) 1997 - 2018 Raja Vallée-Rai and others
 * %%
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation, either version 2.1 of the
 * License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Lesser Public License for more details.
 * 
 * You should have received a copy of the GNU General Lesser Public
 * License along with this program.  If not, see
 * .
 * #L%
 */

import static soot.util.backend.ASMBackendUtils.createASMAttribute;
import static soot.util.backend.ASMBackendUtils.getDefaultValue;
import static soot.util.backend.ASMBackendUtils.slashify;
import static soot.util.backend.ASMBackendUtils.toTypeDesc;
import static soot.util.backend.ASMBackendUtils.translateJavaVersion;

import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.util.TraceClassVisitor;

import soot.baf.BafBody;
import soot.jimple.JimpleBody;
import soot.options.Options;
import soot.tagkit.AnnotationAnnotationElem;
import soot.tagkit.AnnotationArrayElem;
import soot.tagkit.AnnotationBooleanElem;
import soot.tagkit.AnnotationClassElem;
import soot.tagkit.AnnotationConstants;
import soot.tagkit.AnnotationDefaultTag;
import soot.tagkit.AnnotationDoubleElem;
import soot.tagkit.AnnotationElem;
import soot.tagkit.AnnotationEnumElem;
import soot.tagkit.AnnotationFloatElem;
import soot.tagkit.AnnotationIntElem;
import soot.tagkit.AnnotationLongElem;
import soot.tagkit.AnnotationStringElem;
import soot.tagkit.AnnotationTag;
import soot.tagkit.Attribute;
import soot.tagkit.EnclosingMethodTag;
import soot.tagkit.Host;
import soot.tagkit.InnerClassAttribute;
import soot.tagkit.InnerClassTag;
import soot.tagkit.OuterClassTag;
import soot.tagkit.SignatureTag;
import soot.tagkit.SourceFileTag;
import soot.tagkit.Tag;
import soot.tagkit.VisibilityAnnotationTag;
import soot.tagkit.VisibilityParameterAnnotationTag;
import soot.util.backend.SootASMClassWriter;

/**
 * Abstract super-class for ASM-based back-ends. Generates byte-code for everything except the method bodies, as they are
 * dependent on the IR.
 *
 * @author Tobias Hamann, Florian Kuebler, Dominik Helm, Lukas Sommer
 *
 */
public abstract class AbstractASMBackend {

  // An ASM ClassVisitor that is used to emit the bytecode to
  protected ClassVisitor cv;
  // The SootClass that is to be converted into bytecode
  protected SootClass sc;
  // The Java version to be used for generating this class
  protected int javaVersion;

  private final Map bafBodyCache = new HashMap();

  /**
   * Creates a new ASM backend
   *
   * @param sc
   *          The SootClass that is to be converted into bytecode
   * @param javaVersion
   *          A particular Java version enforced by the user, may be 0 for automatic detection, must not be lower than
   *          necessary for all features used
   */
  public AbstractASMBackend(SootClass sc, int javaVersion) {
    this.sc = sc;

    int minVersion = getMinJavaVersion(sc);

    if (javaVersion == 0) {
      javaVersion = Options.java_version_default;
    }

    if (javaVersion != Options.java_version_default && javaVersion < minVersion) {
      throw new IllegalArgumentException("Enforced Java version " + translateJavaVersion(javaVersion)
          + " too low to support required features (" + translateJavaVersion(minVersion) + " required)");
    }

    javaVersion = Math.max(javaVersion, minVersion);

    switch (javaVersion) {
      case Options.java_version_1_1:
        this.javaVersion = Opcodes.V1_1;
        break;
      case Options.java_version_1_2:
        this.javaVersion = Opcodes.V1_2;
        break;
      case Options.java_version_1_3:
        this.javaVersion = Opcodes.V1_3;
        break;
      case Options.java_version_1_4:
        this.javaVersion = Opcodes.V1_4;
        break;
      case Options.java_version_1_5:
        this.javaVersion = Opcodes.V1_5;
        break;
      case Options.java_version_1_6:
        this.javaVersion = Opcodes.V1_6;
        break;
      case Options.java_version_1_7:
        this.javaVersion = Opcodes.V1_7;
        break;
      case Options.java_version_1_8:
        this.javaVersion = Opcodes.V1_8;
        break;
    }
  }

  /**
   * Gets the baf body for the given SootMethod. This method will first check whether the method already has a baf body. If
   * not, it will query the local cache. If this fails as well, it will construct a new baf body.
   *
   * @param method
   *          The method for which to obtain a baf body
   * @return The baf body for the given method
   */
  protected BafBody getBafBody(SootMethod method) {
    final Body activeBody = method.getActiveBody();
    if (activeBody instanceof BafBody) {
      return (BafBody) activeBody;
    }

    BafBody body = bafBodyCache.get(method);
    if (body != null) {
      return body;
    }

    if (activeBody instanceof JimpleBody) {
      body = PackManager.v().convertJimpleBodyToBaf(method);
    } else {
      throw new RuntimeException("ASM-backend can only translate Baf- and JimpleBodies!");
    }

    bafBodyCache.put(method, body);
    return body;
  }

  /**
   * Determines the minimum Java version required for the bytecode of the given SootClass
   *
   * @param sc
   *          The SootClass the minimum Java version is to be determined for
   * @return The minimum Java version required for the given SootClass
   */
  private int getMinJavaVersion(SootClass sc) {
    int minVersion = Options.java_version_1_1;

    if (sc.hasTag("SignatureTag")) {
      if (((SignatureTag) sc.getTag("SignatureTag")).getSignature().contains("<")) {
        minVersion = Options.java_version_1_5;
      }
    }
    if (sc.hasTag("VisibilityAnnotationTag")) {
      minVersion = Options.java_version_1_5;
    }
    if (Modifier.isAnnotation(sc.getModifiers())) {
      // Class is defining an annotation
      minVersion = Options.java_version_1_5;
    }

    for (SootField sf : sc.getFields()) {
      if (minVersion >= Options.java_version_1_5) {
        break;
      }
      if (sf.hasTag("SignatureTag")) {
        if (((SignatureTag) sf.getTag("SignatureTag")).getSignature().contains("<")) {
          minVersion = Options.java_version_1_5;
        }
      }
      if (sf.hasTag("VisibilityAnnotationTag")) {
        minVersion = Options.java_version_1_5;
      }
    }

    // We need to clone the method list, because it may happen during writeout
    // that we need to split methods, which are longer than the JVM spec allows.
    // This feature is work in progress.
    List clonedList = new ArrayList<>(sc.getMethods());
    for (SootMethod sm : clonedList) {
      if (minVersion >= Options.java_version_1_8) {
        break;
      }
      if (sm.hasTag("SignatureTag")) {
        if (((SignatureTag) sm.getTag("SignatureTag")).getSignature().contains("<")) {
          minVersion = Math.max(minVersion, Options.java_version_1_5);
        }
      }
      if (sm.hasTag("VisibilityAnnotationTag") || sm.hasTag("VisibilityParameterAnnotationTag")) {
        minVersion = Math.max(minVersion, Options.java_version_1_5);
      }
      if (sm.hasActiveBody()) {
        minVersion = Math.max(minVersion, getMinJavaVersion(sm));
      }
    }
    return minVersion;
  }

  /**
   * Determines the minimum Java version required for the bytecode of the given SootMethod Subclasses should override this
   * method to suit their needs, otherwise Java 1.7 is assumed for compatibility with invokeDynamic
   *
   * @param sm
   *          The SootMethod the minimum Java version is to be determined for
   * @return The minimum Java version required for the given SootMethod
   */
  protected int getMinJavaVersion(SootMethod sm) {
    return Options.java_version_1_7;
  }

  /**
   * Outputs the bytecode generated as a class file
   *
   * @param os
   *          The OutputStream the class file is written to
   */
  public void generateClassFile(OutputStream os) {
    ClassWriter cw = new SootASMClassWriter(ClassWriter.COMPUTE_FRAMES);
    cv = cw;
    generateByteCode();
    try {
      os.write(cw.toByteArray());
    } catch (IOException e) {
      throw new RuntimeException("Could not write class file in the ASM-backend!", e);
    }
  }

  /**
   * Outputs the bytecode generated as a textual representation
   *
   * @param pw
   *          The PrintWriter the textual representation is written to
   */
  public void generateTextualRepresentation(PrintWriter pw) {
    cv = new TraceClassVisitor(pw);
    generateByteCode();
  }

  /**
   * Emits the bytecode for the complete class
   */
  protected void generateByteCode() {
    generateClassHeader();

    // Retrieve information about the source of the class
    if (sc.hasTag("SourceFileTag") && !Options.v().no_output_source_file_attribute()) {
      String srcName = ((SourceFileTag) sc.getTag("SourceFileTag")).getSourceFile();
      cv.visitSource(srcName, null); // TODO Correct value for the debug
      // argument
    }

    // Retrieve information about outer class if present
    if (sc.hasOuterClass() || sc.hasTag("EnclosingMethodTag") || sc.hasTag("OuterClassTag")) {
      generateOuterClassReference();
    }

    // Retrieve information about annotations
    generateAnnotations(cv, sc);

    // Retrieve information about attributes
    generateAttributes();

    // Retrieve information about inner classes
    generateInnerClassReferences();

    // Generate fields
    generateFields();

    // Generate methods
    generateMethods();

    cv.visitEnd();
  }

  /**
   * Comparatator that is used to sort the methods before they are written out. This is mainly used to enforce a
   * deterministic output between runs which we need for testing.
   *
   * @author Steven Arzt
   *
   */
  private class SootMethodComparator implements Comparator {

    @Override
    public int compare(SootMethod o1, SootMethod o2) {
      return o1.getName().compareTo(o2.getName());
    }

  }

  /**
   * Emits the bytecode for all methods of the class
   */
  protected void generateMethods() {
    List sortedMethods = new ArrayList(sc.getMethods());
    Collections.sort(sortedMethods, new SootMethodComparator());
    for (SootMethod sm : sortedMethods) {
      if (sm.isPhantom()) {
        continue;
      }

      int access = getModifiers(sm.getModifiers(), sm);
      String name = sm.getName();
      StringBuilder descBuilder = new StringBuilder(5);
      descBuilder.append('(');
      for (Type t : sm.getParameterTypes()) {
        descBuilder.append(toTypeDesc(t));
      }
      descBuilder.append(')');
      descBuilder.append(toTypeDesc(sm.getReturnType()));

      String sig = null;
      if (sm.hasTag("SignatureTag")) {
        SignatureTag genericSignature = (SignatureTag) sm.getTag("SignatureTag");
        sig = genericSignature.getSignature();
      }

      List exceptionList = sm.getExceptionsUnsafe();
      String[] exceptions;
      if (exceptionList != null) {
        exceptions = new String[exceptionList.size()];
        int i = 0;
        for (SootClass exc : sm.getExceptions()) {
          exceptions[i] = slashify(exc.getName());
          ++i;
        }
      } else {
        exceptions = new String[0];
      }
      MethodVisitor mv = cv.visitMethod(access, name, descBuilder.toString(), sig, exceptions);
      if (mv != null) {
        // Visit parameter annotations
        for (Tag t : sm.getTags()) {
          if (t instanceof VisibilityParameterAnnotationTag) {
            VisibilityParameterAnnotationTag vpt = (VisibilityParameterAnnotationTag) t;
            ArrayList tags = vpt.getVisibilityAnnotations();
            if (tags != null) {
              for (int j = 0; j < tags.size(); ++j) {
                VisibilityAnnotationTag va = tags.get(j);
                if (va == null) {
                  continue;
                }
                for (AnnotationTag at : va.getAnnotations()) {
                  AnnotationVisitor av = mv.visitParameterAnnotation(j, at.getType(),
                      (va.getVisibility() == AnnotationConstants.RUNTIME_VISIBLE));
                  generateAnnotationElems(av, at.getElems(), true);
                }
              }
            }
          }
        }

        generateAnnotations(mv, sm);

        generateAttributes(mv, sm);
        if (sm.hasActiveBody()) {
          mv.visitCode();
          generateMethodBody(mv, sm);
          /*
           * Correct values are computed automatically by ASM, but we need the call anyways.
           */
          mv.visitMaxs(0, 0);
        }
        mv.visitEnd();
      }
    }
  }

  /**
   * Emits the bytecode for all fields of the class
   */
  protected void generateFields() {
    for (SootField f : sc.getFields()) {
      if (f.isPhantom()) {
        continue;
      }
      String name = f.getName();
      String desc = toTypeDesc(f.getType());
      String sig = null;
      if (f.hasTag("SignatureTag")) {
        SignatureTag genericSignature = (SignatureTag) f.getTag("SignatureTag");
        sig = genericSignature.getSignature();
      }
      Object value = getDefaultValue(f);
      int access = getModifiers(f.getModifiers(), f);
      FieldVisitor fv = cv.visitField(access, name, desc, sig, value);
      if (fv != null) {
        generateAnnotations(fv, f);
        generateAttributes(fv, f);
        fv.visitEnd();
      }
    }
  }

  /**
   * Comparatator that is used to sort the inner class references before they are written out. This is mainly used to enforce
   * a deterministic output between runs which we need for testing.
   *
   * @author Steven Arzt
   *
   */
  private class SootInnerClassComparator implements Comparator {

    @Override
    public int compare(InnerClassTag o1, InnerClassTag o2) {
      return o1.getInnerClass() == null ? 0 : o1.getInnerClass().compareTo(o2.getInnerClass());
    }

  }

  /**
   * Emits the bytecode for all references to inner classes if present
   */
  protected void generateInnerClassReferences() {
    if (sc.hasTag("InnerClassAttribute") && !Options.v().no_output_inner_classes_attribute()) {
      InnerClassAttribute ica = (InnerClassAttribute) sc.getTag("InnerClassAttribute");
      List sortedTags = new ArrayList(ica.getSpecs());
      Collections.sort(sortedTags, new SootInnerClassComparator());
      for (InnerClassTag ict : sortedTags) {
        String name = slashify(ict.getInnerClass());
        String outerClassName = slashify(ict.getOuterClass());
        String innerName = slashify(ict.getShortName());
        int access = ict.getAccessFlags();
        cv.visitInnerClass(name, outerClassName, innerName, access);
      }
    }
  }

  /**
   * Emits the bytecode for all attributes of the class
   */
  protected void generateAttributes() {
    for (Tag t : sc.getTags()) {
      if (t instanceof Attribute) {
        cv.visitAttribute(createASMAttribute((Attribute) t));
      }
    }
  }

  /**
   * Emits the bytecode for all attributes of a field
   *
   * @param fv
   *          The FieldVisitor to emit the bytecode to
   * @param f
   *          The SootField the bytecode is to be emitted for
   */
  protected void generateAttributes(FieldVisitor fv, SootField f) {
    for (Tag t : f.getTags()) {
      if (t instanceof Attribute) {
        org.objectweb.asm.Attribute a = createASMAttribute((Attribute) t);
        fv.visitAttribute(a);
      }
    }
  }

  /**
   * Emits the bytecode for all attributes of a method
   *
   * @param fv
   *          The MethodVisitor to emit the bytecode to
   * @param f
   *          The SootMethod the bytecode is to be emitted for
   */
  protected void generateAttributes(MethodVisitor mv, SootMethod m) {
    for (Tag t : m.getTags()) {
      if (t instanceof Attribute) {
        org.objectweb.asm.Attribute a = createASMAttribute((Attribute) t);
        mv.visitAttribute(a);
      }
    }
  }

  /**
   * Emits the bytecode for all annotations of a class, field or method
   *
   * @param visitor
   *          A ClassVisitor, FieldVisitor or MethodVisitor to emit the bytecode to
   * @param host
   *          A Host (SootClass, SootField or SootMethod) the bytecode is to be emitted for, has to match the visitor
   */
  protected void generateAnnotations(Object visitor, Host host) {
    for (Tag t : host.getTags()) {
      // Find all VisibilityAnnotationTags
      if (t instanceof VisibilityAnnotationTag) {
        VisibilityAnnotationTag vat = (VisibilityAnnotationTag) t;
        boolean runTimeVisible = (vat.getVisibility() == AnnotationConstants.RUNTIME_VISIBLE);
        for (AnnotationTag at : vat.getAnnotations()) {
          AnnotationVisitor av = null;
          if (visitor instanceof ClassVisitor) {
            av = ((ClassVisitor) visitor).visitAnnotation(at.getType(), runTimeVisible);
          } else if (visitor instanceof FieldVisitor) {
            av = ((FieldVisitor) visitor).visitAnnotation(at.getType(), runTimeVisible);
          } else if (visitor instanceof MethodVisitor) {
            av = ((MethodVisitor) visitor).visitAnnotation(at.getType(), runTimeVisible);
          }

          generateAnnotationElems(av, at.getElems(), true);
        }
      }
      /*
       * Here TypeAnnotations could be visited potentially. Currently (2015/02/03) they are not supported by the
       * ASM-front-end and their information is not accessible.
       */

      // Visit AnnotationDefault on methods
      else if (host instanceof SootMethod && t instanceof AnnotationDefaultTag) {
        AnnotationDefaultTag adt = (AnnotationDefaultTag) t;
        AnnotationVisitor av = ((MethodVisitor) visitor).visitAnnotationDefault();
        generateAnnotationElems(av, Collections.singleton(adt.getDefaultVal()), true);
      }

    }
  }

  /**
   * Emits the bytecode for the values of an annotation
   *
   * @param av
   *          The AnnotationVisitor to emit the bytecode to
   * @param elements
   *          A collection of AnnatiotionElem that are the values of the annotation
   * @param addName
   *          True, if the name of the annotation has to be added, false otherwise (should be false only in recursive calls!)
   */
  protected void generateAnnotationElems(AnnotationVisitor av, Collection elements, boolean addName) {
    if (av != null) {
      Iterator it = elements.iterator();
      while (it.hasNext()) {
        AnnotationElem elem = it.next();
        if (elem instanceof AnnotationEnumElem) {
          AnnotationEnumElem enumElem = (AnnotationEnumElem) elem;
          av.visitEnum(enumElem.getName(), enumElem.getTypeName(), enumElem.getConstantName());
        } else if (elem instanceof AnnotationArrayElem) {
          AnnotationArrayElem arrayElem = (AnnotationArrayElem) elem;
          AnnotationVisitor arrayVisitor = av.visitArray(arrayElem.getName());
          generateAnnotationElems(arrayVisitor, arrayElem.getValues(), false);
        } else if (elem instanceof AnnotationAnnotationElem) {
          AnnotationAnnotationElem aElem = (AnnotationAnnotationElem) elem;
          AnnotationVisitor aVisitor = av.visitAnnotation(aElem.getName(), aElem.getValue().getType());
          generateAnnotationElems(aVisitor, aElem.getValue().getElems(), true);
        } else {
          Object val = null;
          if (elem instanceof AnnotationIntElem) {
            AnnotationIntElem intElem = (AnnotationIntElem) elem;
            int value = intElem.getValue();
            switch (intElem.getKind()) {
              case 'B':
                val = (byte) value;
                break;
              case 'Z':
                val = (value == 1);
                break;
              case 'I':
                val = value;
                break;
              case 'S':
                val = (short) value;
                break;
            }
          } else if (elem instanceof AnnotationBooleanElem) {
            AnnotationBooleanElem booleanElem = (AnnotationBooleanElem) elem;
            val = booleanElem.getValue();
          } else if (elem instanceof AnnotationFloatElem) {
            AnnotationFloatElem floatElem = (AnnotationFloatElem) elem;
            val = floatElem.getValue();
          } else if (elem instanceof AnnotationLongElem) {
            AnnotationLongElem longElem = (AnnotationLongElem) elem;
            val = longElem.getValue();
          } else if (elem instanceof AnnotationDoubleElem) {
            AnnotationDoubleElem doubleElem = (AnnotationDoubleElem) elem;
            val = doubleElem.getValue();
          } else if (elem instanceof AnnotationStringElem) {
            AnnotationStringElem stringElem = (AnnotationStringElem) elem;
            val = stringElem.getValue();
          } else if (elem instanceof AnnotationClassElem) {
            AnnotationClassElem classElem = (AnnotationClassElem) elem;
            val = org.objectweb.asm.Type.getType(classElem.getDesc());
          }
          if (addName) {
            av.visit(elem.getName(), val);
          } else {
            av.visit(null, val);
          }

        }
      }
      av.visitEnd();
    }
  }

  /**
   * Emits the bytecode for a reference to an outer class if necessary
   */
  protected void generateOuterClassReference() {
    SootClass outerClass = sc.getOuterClass();
    String outerClassName = slashify(outerClass.getName());
    String enclosingMethod = null;
    String enclosingMethodSig = null;
    if (sc.hasTag("EnclosingMethodTag")) {
      EnclosingMethodTag emTag = (EnclosingMethodTag) sc.getTag("EnclosingMethodTag");
      if (!sc.hasOuterClass()) {
        outerClassName = slashify(emTag.getEnclosingClass());
      }
      enclosingMethod = emTag.getEnclosingMethod();
      enclosingMethodSig = emTag.getEnclosingMethodSig();
    }
    if (!sc.hasOuterClass() && sc.hasTag("OuterClassTag")) {
      outerClassName = slashify(((OuterClassTag) sc.getTag("OuterClassTag")).getName());
    }
    cv.visitOuterClass(outerClassName, enclosingMethod, enclosingMethodSig);
  }

  /**
   * Emits the bytecode for the class itself, including its signature
   */
  protected void generateClassHeader() {
    /*
     * Retrieve all modifiers
     */
    int classModifiers = sc.getModifiers();
    int modifier = getModifiers(classModifiers, sc);

    // Retrieve class-name
    String className = slashify(sc.getName());
    // Retrieve generics
    String signature = null;
    if (sc.hasTag("SignatureTag")) {
      signature = ((SignatureTag) sc.getTag("SignatureTag")).getSignature();
    }
    /*
     * Retrieve super-class If no super-class is explicitly given, the default is java.lang.Object.
     */
    String superClass = "java/lang/Object";
    SootClass csuperClass = sc.getSuperclassUnsafe();
    if (csuperClass != null) {
      superClass = slashify(csuperClass.getName());
    }

    // Retrieve directly implemented interfaces
    String[] interfaces = new String[sc.getInterfaceCount()];
    Iterator implementedInterfaces = sc.getInterfaces().iterator();
    int i = 0;
    while (implementedInterfaces.hasNext()) {
      SootClass interf = implementedInterfaces.next();
      interfaces[i] = slashify(interf.getName());
      ++i;
    }

    cv.visit(javaVersion, modifier, className, signature, superClass, interfaces);
  }

  /**
   * Utility method to get the access modifiers of a Host
   *
   * @param modVal
   *          The bitset representation of the Host's modifiers
   * @param host
   *          The Host (SootClass, SootField or SootMethod) the modifiers are to be retrieved from
   * @return A bitset representation of the Host's modifiers in ASM's internal representation
   */
  protected static int getModifiers(int modVal, Host host) {
    int modifier = 0;
    // Retrieve visibility-modifier
    if (Modifier.isPublic(modVal)) {
      modifier |= Opcodes.ACC_PUBLIC;
    } else if (Modifier.isPrivate(modVal)) {
      modifier |= Opcodes.ACC_PRIVATE;
    } else if (Modifier.isProtected(modVal)) {
      modifier |= Opcodes.ACC_PROTECTED;
    }
    // Retrieve static-modifier
    if (Modifier.isStatic(modVal) && ((host instanceof SootField) || (host instanceof SootMethod))) {
      modifier |= Opcodes.ACC_STATIC;
    }
    // Retrieve final-modifier
    if (Modifier.isFinal(modVal)) {
      modifier |= Opcodes.ACC_FINAL;
    }
    // Retrieve synchronized-modifier
    if (Modifier.isSynchronized(modVal) && host instanceof SootMethod) {
      modifier |= Opcodes.ACC_SYNCHRONIZED;
    }
    // Retrieve volatile/bridge-modifier
    if (Modifier.isVolatile(modVal) && !(host instanceof SootClass)) {
      modifier |= Opcodes.ACC_VOLATILE;
    }
    // Retrieve transient/varargs-modifier
    if (Modifier.isTransient(modVal) && !(host instanceof SootClass)) {
      modifier |= Opcodes.ACC_TRANSIENT;
    }
    // Retrieve native-modifier
    if (Modifier.isNative(modVal) && host instanceof SootMethod) {
      modifier |= Opcodes.ACC_NATIVE;
    }
    // Retrieve interface-modifier
    if (Modifier.isInterface(modVal) && host instanceof SootClass) {
      modifier |= Opcodes.ACC_INTERFACE;
    } else if (host instanceof SootClass) {
      /*
       * For all classes except for interfaces the super-flag should be set. See JVM 8-Specification section 4.1, page 72.
       */
      modifier |= Opcodes.ACC_SUPER;
    }
    // Retrieve abstract-modifier
    if (Modifier.isAbstract(modVal) && !(host instanceof SootField)) {
      modifier |= Opcodes.ACC_ABSTRACT;
    }
    // Retrieve strictFP-modifier
    if (Modifier.isStrictFP(modVal) && host instanceof SootMethod) {
      modifier |= Opcodes.ACC_STRICT;
    }
    /*
     * Retrieve synthetic-modifier. Class not present in source-code but generated by e.g. compiler TODO Do we need both
     * checks?
     */
    if (Modifier.isSynthetic(modVal) || host.hasTag("SyntheticTag")) {
      modifier |= Opcodes.ACC_SYNTHETIC;
    }
    // Retrieve annotation-modifier
    if (Modifier.isAnnotation(modVal) && host instanceof SootClass) {
      modifier |= Opcodes.ACC_ANNOTATION;
    }
    // Retrieve enum-modifier
    if (Modifier.isEnum(modVal) && !(host instanceof SootMethod)) {
      modifier |= Opcodes.ACC_ENUM;
    }
    return modifier;
  }

  /**
   * Emits the bytecode for the body of a single method Has to be implemented by subclasses to suit their needs
   *
   * @param mv
   *          The MethodVisitor to emit the bytecode to
   * @param method
   *          The SootMethod the bytecode is to be emitted for
   */
  abstract protected void generateMethodBody(MethodVisitor mv, SootMethod method);

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy