private String getLambdaAccessMethodDesc(Handle implMethod) {
    if (implMethod.getTag() == H_INVOKESTATIC) {
      // static method call -> keep as-is
      return implMethod.getDesc();

    } else if (implMethod.getTag() == H_NEWINVOKESPECIAL) {
      // constructor call -> change to a a factory method
      return Types.changeReturnType(
          Type.getObjectType(implMethod.getOwner()), implMethod.getDesc());

    } else {
      // instance method call -> change to a static method
      return Types.prependArgumentType(Type.getObjectType(className), implMethod.getDesc());
    }
  }
 /**
  * Full constructor
  *
  * @param serializedLambda the fully {@link SerializedLambda} carrying all the required info.
  */
 public SerializedLambdaInfo(final SerializedLambda serializedLambda) {
   this(
       Type.getObjectType(serializedLambda.getImplClass()).getClassName(),
       serializedLambda.getImplMethodName(),
       serializedLambda.getImplMethodSignature(),
       getCapturedArguments(serializedLambda));
 }
  /* (non-Javadoc)
   * @see edu.umd.cs.findbugs.ba.INullnessAnnotationDatabase#addDefaultAnnotation(java.lang.String, java.lang.String, edu.umd.cs.findbugs.ba.NullnessAnnotation)
   */
  public void addDefaultAnnotation(Target target, String c, NullnessAnnotation n) {
    if (DEBUG) {
      System.out.println("addDefaultAnnotation: target=" + target + ", c=" + c + ", n=" + n);
    }

    ClassDescriptor classDesc =
        DescriptorFactory.instance().getClassDescriptorForDottedClassName(c);
    ClassInfo xclass;

    // Get the XClass (really a ClassInfo object)
    try {
      xclass = (ClassInfo) Global.getAnalysisCache().getClassAnalysis(XClass.class, classDesc);
    } catch (MissingClassException e) {
      //
      //	AnalysisContext.currentAnalysisContext().getLookupFailureCallback().reportMissingClass(e.getClassDescriptor());
      return;
    } catch (CheckedAnalysisException e) {
      //			AnalysisContext.logError("Error adding built-in nullness annotation", e);
      return;
    }
    if (n == NullnessAnnotation.NONNULL && target == AnnotationDatabase.Target.PARAMETER) {
      xclass.addAnnotation(new AnnotationValue(PARAMETERS_ARE_NONNULL_BY_DEFAULT));
      return;
    } else if (n == NullnessAnnotation.NONNULL && target == AnnotationDatabase.Target.METHOD) {
      xclass.addAnnotation(new AnnotationValue(RETURN_VALUES_ARE_NONNULL_BY_DEFAULT));
      return;
    }
    // Get the default annotation type
    ClassDescriptor defaultAnnotationType;
    if (target == AnnotationDatabase.Target.ANY) {
      defaultAnnotationType = FindBugsDefaultAnnotations.DEFAULT_ANNOTATION;
    } else if (target == AnnotationDatabase.Target.FIELD) {
      defaultAnnotationType = FindBugsDefaultAnnotations.DEFAULT_ANNOTATION_FOR_FIELDS;
    } else if (target == AnnotationDatabase.Target.METHOD) {
      defaultAnnotationType = FindBugsDefaultAnnotations.DEFAULT_ANNOTATION_FOR_METHODS;
    } else if (target == AnnotationDatabase.Target.PARAMETER) {
      defaultAnnotationType = FindBugsDefaultAnnotations.DEFAULT_ANNOTATION_FOR_PARAMETERS;
    } else {
      throw new IllegalArgumentException("Unknown target for default annotation: " + target);
    }

    // Get the JSR-305 nullness annotation type
    ClassDescriptor nullnessAnnotationType = getNullnessAnnotationClassDescriptor(n);

    // Construct an AnnotationValue containing the default annotation
    AnnotationValue annotationValue = new AnnotationValue(defaultAnnotationType);
    AnnotationVisitor v = annotationValue.getAnnotationVisitor();
    v.visit("value", Type.getObjectType(nullnessAnnotationType.getClassName()));
    v.visitEnd();

    if (DEBUG) {
      System.out.println("Adding AnnotationValue " + annotationValue + " to class " + xclass);
    }

    // Destructively add the annotation to the ClassInfo object
    xclass.addAnnotation(annotationValue);
  }
예제 #4
0
 private InsnList generateInvokeDynamicConstructor(String name, String owner, String desc) {
   InsnList insnList = new InsnList();
   Handle methodHandle =
       new Handle(
           Opcodes.H_INVOKESTATIC, BOOTSTRAP_CLASS, "dynvokeConstructor", BOOTSTRAP_SIGNATURE);
   String descReceiver =
       Type.getMethodDescriptor(Type.getObjectType(owner), Type.getArgumentTypes(desc));
   insnList.add(new InvokeDynamicInsnNode(owner + "." + name, descReceiver, methodHandle, ""));
   return insnList;
 }
 @Override
 public void visit(
     int version,
     int access,
     String name,
     String signature,
     String superName,
     String[] interfaces) {
   this.className = Type.getObjectType(name).getClassName();
   this.access = access;
 }
 @Override
 public BasicValue newOperation(AbstractInsnNode insn) throws AnalyzerException {
   switch (insn.getOpcode()) {
     case ACONST_NULL:
       return new TaggedValue(Type.getObjectType("null"), Tag.NULL);
     case NEW:
       analyzer.incrNewOperationCounters(topLevelMethod);
       // make new objects a tagged value to have possibility to tag an
       // input container later
       return new TaggedValue(Type.getObjectType(((TypeInsnNode) insn).desc));
       // tag "int"-like constants
     case BIPUSH:
     case SIPUSH:
       final IntInsnNode intInsn = (IntInsnNode) insn;
       return new TaggedValue(intInsn.operand);
     case LDC:
       final Object cst = ((LdcInsnNode) insn).cst;
       if (cst instanceof Integer) {
         return new TaggedValue((Integer) cst);
       }
       return super.newOperation(insn);
     case ICONST_M1:
       return new TaggedValue(-1);
     case ICONST_0:
       return new TaggedValue(0);
     case ICONST_1:
       return new TaggedValue(1);
     case ICONST_2:
       return new TaggedValue(2);
     case ICONST_3:
       return new TaggedValue(3);
     case ICONST_4:
       return new TaggedValue(4);
     case ICONST_5:
       return new TaggedValue(5);
     default:
       return super.newOperation(insn);
   }
 }
예제 #7
0
  public static ClassMetadata scan(ClassReader source) {
    ClassMetadata info = new ClassMetadata();
    source.accept(new MetaScanner(info), 0);
    info.type = Type.getObjectType(source.getClassName());

    for (FieldDescriptor fd : info.fields) {
      if ((fd.access & ACC_PUBLIC) == ACC_PUBLIC) {
        info.directFieldAccess = true;
      }
    }

    return info;
  }
예제 #8
0
 private InsnList generateInvokeDynamicVirtualInterfaceSpecial(
     String name, String owner, String desc, String bootstrapMethod) {
   InsnList insnList = new InsnList();
   Handle methodHandle =
       new Handle(Opcodes.H_INVOKESTATIC, BOOTSTRAP_CLASS, bootstrapMethod, BOOTSTRAP_SIGNATURE);
   List<Type> argsList =
       new ArrayList<Type>(Arrays.asList(new Type[] {Type.getObjectType(owner)}));
   argsList.addAll(Arrays.asList(Type.getArgumentTypes(desc)));
   String descReceiver =
       Type.getMethodDescriptor(
           Type.getReturnType(desc), argsList.toArray(new Type[argsList.size()]));
   insnList.add(new InvokeDynamicInsnNode(owner + "." + name, descReceiver, methodHandle, ""));
   return insnList;
 }
예제 #9
0
 @Override
 public void visitTypeInsn(int opcode, String type) {
   addType(Type.getObjectType(type));
 }
예제 #10
0
 private void addInternalName(String name) {
   addType(Type.getObjectType(name));
 }
/**
 * A {@link MethodVisitor} that renumbers local variables in their order of appearance. This adapter
 * allows one to easily addClass new local variables to a method. It may be used by inheriting from
 * this class, but the preferred way of using it is via delegation: the next visitor in the chain
 * can indeed addClass new locals when needed by calling {@link #newLocal} on this adapter (this
 * requires a reference back to this {@link LocalVariablesSorter}).
 *
 * @author Chris Nokleberg
 * @author Eugene Kuleshov
 * @author Eric Bruneton
 */
public class LocalVariablesSorter extends MethodVisitor {

  private static final Type OBJECT_TYPE = Type.getObjectType("java/lang/Object");

  /**
   * Mapping from old to new local variable indexes. A local variable at index i of size 1 is
   * remapped to 'mapping[2*i]', while a local variable at index i of size 2 is remapped to
   * 'mapping[2*i+1]'.
   */
  private int[] mapping = new int[40];

  /** Array used to store stack map local variable types after remapping. */
  private Object[] newLocals = new Object[20];

  /** Index of the first local variable, after formal parameters. */
  protected final int firstLocal;

  /** Index of the next local variable to be created by {@link #newLocal}. */
  protected int nextLocal;

  /** Indicates if at least one local variable has moved due to remapping. */
  private boolean changed;

  /**
   * Creates a new {@link LocalVariablesSorter}. <i>Subclasses must not use this constructor</i>.
   * Instead, they must use the {@link #LocalVariablesSorter(int, int, String, MethodVisitor)}
   * version.
   *
   * @param access access flags of the adapted method.
   * @param desc the method's descriptor (see {@link Type Type}).
   * @param mv the method visitor to which this adapter delegates calls.
   */
  public LocalVariablesSorter(final int access, final String desc, final MethodVisitor mv) {
    this(Opcodes.ASM4, access, desc, mv);
  }

  /**
   * Creates a new {@link LocalVariablesSorter}.
   *
   * @param api the ASM API version implemented by this visitor. Must be one of {@link
   *     Opcodes#ASM4}.
   * @param access access flags of the adapted method.
   * @param desc the method's descriptor (see {@link Type Type}).
   * @param mv the method visitor to which this adapter delegates calls.
   */
  protected LocalVariablesSorter(
      final int api, final int access, final String desc, final MethodVisitor mv) {
    super(api, mv);
    Type[] args = Type.getArgumentTypes(desc);
    nextLocal = (Opcodes.ACC_STATIC & access) == 0 ? 1 : 0;
    for (int i = 0; i < args.length; i++) {
      nextLocal += args[i].getSize();
    }
    firstLocal = nextLocal;
  }

  @Override
  public void visitVarInsn(final int opcode, final int var) {
    Type type;
    switch (opcode) {
      case Opcodes.LLOAD:
      case Opcodes.LSTORE:
        type = Type.LONG_TYPE;
        break;

      case Opcodes.DLOAD:
      case Opcodes.DSTORE:
        type = Type.DOUBLE_TYPE;
        break;

      case Opcodes.FLOAD:
      case Opcodes.FSTORE:
        type = Type.FLOAT_TYPE;
        break;

      case Opcodes.ILOAD:
      case Opcodes.ISTORE:
        type = Type.INT_TYPE;
        break;

      default:
        // case Opcodes.ALOAD:
        // case Opcodes.ASTORE:
        // case RET:
        type = OBJECT_TYPE;
        break;
    }
    mv.visitVarInsn(opcode, remap(var, type));
  }

  @Override
  public void visitIincInsn(final int var, final int increment) {
    mv.visitIincInsn(remap(var, Type.INT_TYPE), increment);
  }

  @Override
  public void visitMaxs(final int maxStack, final int maxLocals) {
    mv.visitMaxs(maxStack, nextLocal);
  }

  @Override
  public void visitLocalVariable(
      final String name,
      final String desc,
      final String signature,
      final Label start,
      final Label end,
      final int index) {
    int newIndex = remap(index, Type.getType(desc));
    mv.visitLocalVariable(name, desc, signature, start, end, newIndex);
  }

  @Override
  public void visitFrame(
      final int type,
      final int nLocal,
      final Object[] local,
      final int nStack,
      final Object[] stack) {
    if (type != Opcodes.F_NEW) { // uncompressed frame
      throw new IllegalStateException(
          "ClassReader.accept() should be called with EXPAND_FRAMES flag");
    }

    if (!changed) { // optimization for the case where mapping = identity
      mv.visitFrame(type, nLocal, local, nStack, stack);
      return;
    }

    // creates a copy of newLocals
    Object[] oldLocals = new Object[newLocals.length];
    System.arraycopy(newLocals, 0, oldLocals, 0, oldLocals.length);

    updateNewLocals(newLocals);

    // copies types from 'local' to 'newLocals'
    // 'newLocals' already contains the variables added with 'newLocal'

    int index = 0; // old local variable index
    int number = 0; // old local variable number
    for (; number < nLocal; ++number) {
      Object t = local[number];
      int size = t == Opcodes.LONG || t == Opcodes.DOUBLE ? 2 : 1;
      if (t != Opcodes.TOP) {
        Type typ = OBJECT_TYPE;
        if (t == Opcodes.INTEGER) {
          typ = Type.INT_TYPE;
        } else if (t == Opcodes.FLOAT) {
          typ = Type.FLOAT_TYPE;
        } else if (t == Opcodes.LONG) {
          typ = Type.LONG_TYPE;
        } else if (t == Opcodes.DOUBLE) {
          typ = Type.DOUBLE_TYPE;
        } else if (t instanceof String) {
          typ = Type.getObjectType((String) t);
        }
        setFrameLocal(remap(index, typ), t);
      }
      index += size;
    }

    // removes TOP after long and double types as well as trailing TOPs

    index = 0;
    number = 0;
    for (int i = 0; index < newLocals.length; ++i) {
      Object t = newLocals[index++];
      if (t != null && t != Opcodes.TOP) {
        newLocals[i] = t;
        number = i + 1;
        if (t == Opcodes.LONG || t == Opcodes.DOUBLE) {
          index += 1;
        }
      } else {
        newLocals[i] = Opcodes.TOP;
      }
    }

    // visits remapped frame
    mv.visitFrame(type, number, newLocals, nStack, stack);

    // restores original value of 'newLocals'
    newLocals = oldLocals;
  }

  // -------------

  /**
   * Creates a new local variable of the given type.
   *
   * @param type the type of the local variable to be created.
   * @return the identifier of the newly created local variable.
   */
  public int newLocal(final Type type) {
    Object t;
    switch (type.getSort()) {
      case Type.BOOLEAN:
      case Type.CHAR:
      case Type.BYTE:
      case Type.SHORT:
      case Type.INT:
        t = Opcodes.INTEGER;
        break;
      case Type.FLOAT:
        t = Opcodes.FLOAT;
        break;
      case Type.LONG:
        t = Opcodes.LONG;
        break;
      case Type.DOUBLE:
        t = Opcodes.DOUBLE;
        break;
      case Type.ARRAY:
        t = type.getDescriptor();
        break;
        // case Type.OBJECT:
      default:
        t = type.getInternalName();
        break;
    }
    int local = newLocalMapping(type);
    setLocalType(local, type);
    setFrameLocal(local, t);
    return local;
  }

  /**
   * Notifies subclasses that a new stack map frame is being visited. The array argument contains
   * the stack map frame types corresponding to the local variables added with {@link #newLocal}.
   * This method can update these types in place for the stack map frame being visited. The default
   * implementation of this method does nothing, i.e. a local variable added with {@link #newLocal}
   * will have the same type in all stack map frames. But this behavior is not always the desired
   * one, for instance if a local variable is added in the middle of a try/catch block: the frame
   * for the exception handler should have a TOP type for this new local.
   *
   * @param newLocals the stack map frame types corresponding to the local variables added with
   *     {@link #newLocal} (and null for the others). The format of this array is the same as in
   *     {@link MethodVisitor#visitFrame}, except that long and double types use two slots. The
   *     types for the current stack map frame must be updated in place in this array.
   */
  protected void updateNewLocals(Object[] newLocals) {}

  /**
   * Notifies subclasses that a local variable has been added or remapped. The default
   * implementation of this method does nothing.
   *
   * @param local a local variable identifier, as returned by {@link #newLocal newLocal()}.
   * @param type the type of the value being stored in the local variable.
   */
  protected void setLocalType(final int local, final Type type) {}

  private void setFrameLocal(final int local, final Object type) {
    int l = newLocals.length;
    if (local >= l) {
      Object[] a = new Object[Math.max(2 * l, local + 1)];
      System.arraycopy(newLocals, 0, a, 0, l);
      newLocals = a;
    }
    newLocals[local] = type;
  }

  private int remap(final int var, final Type type) {
    if (var + type.getSize() <= firstLocal) {
      return var;
    }
    int key = 2 * var + type.getSize() - 1;
    int size = mapping.length;
    if (key >= size) {
      int[] newMapping = new int[Math.max(2 * size, key + 1)];
      System.arraycopy(mapping, 0, newMapping, 0, size);
      mapping = newMapping;
    }
    int value = mapping[key];
    if (value == 0) {
      value = newLocalMapping(type);
      setLocalType(value, type);
      mapping[key] = value + 1;
    } else {
      value--;
    }
    if (value != var) {
      changed = true;
    }
    return value;
  }

  protected int newLocalMapping(final Type type) {
    int local = nextLocal;
    nextLocal += type.getSize();
    return local;
  }
}
  @Override
  public void visitFrame(
      final int type,
      final int nLocal,
      final Object[] local,
      final int nStack,
      final Object[] stack) {
    if (type != Opcodes.F_NEW) { // uncompressed frame
      throw new IllegalStateException(
          "ClassReader.accept() should be called with EXPAND_FRAMES flag");
    }

    if (!changed) { // optimization for the case where mapping = identity
      mv.visitFrame(type, nLocal, local, nStack, stack);
      return;
    }

    // creates a copy of newLocals
    Object[] oldLocals = new Object[newLocals.length];
    System.arraycopy(newLocals, 0, oldLocals, 0, oldLocals.length);

    updateNewLocals(newLocals);

    // copies types from 'local' to 'newLocals'
    // 'newLocals' already contains the variables added with 'newLocal'

    int index = 0; // old local variable index
    int number = 0; // old local variable number
    for (; number < nLocal; ++number) {
      Object t = local[number];
      int size = t == Opcodes.LONG || t == Opcodes.DOUBLE ? 2 : 1;
      if (t != Opcodes.TOP) {
        Type typ = OBJECT_TYPE;
        if (t == Opcodes.INTEGER) {
          typ = Type.INT_TYPE;
        } else if (t == Opcodes.FLOAT) {
          typ = Type.FLOAT_TYPE;
        } else if (t == Opcodes.LONG) {
          typ = Type.LONG_TYPE;
        } else if (t == Opcodes.DOUBLE) {
          typ = Type.DOUBLE_TYPE;
        } else if (t instanceof String) {
          typ = Type.getObjectType((String) t);
        }
        setFrameLocal(remap(index, typ), t);
      }
      index += size;
    }

    // removes TOP after long and double types as well as trailing TOPs

    index = 0;
    number = 0;
    for (int i = 0; index < newLocals.length; ++i) {
      Object t = newLocals[index++];
      if (t != null && t != Opcodes.TOP) {
        newLocals[i] = t;
        number = i + 1;
        if (t == Opcodes.LONG || t == Opcodes.DOUBLE) {
          index += 1;
        }
      } else {
        newLocals[i] = Opcodes.TOP;
      }
    }

    // visits remapped frame
    mv.visitFrame(type, number, newLocals, nStack, stack);

    // restores original value of 'newLocals'
    newLocals = oldLocals;
  }
 void addInternalName(final String name) {
   addType(Type.getObjectType(name));
 }
  @SuppressWarnings({"rawtypes", "unchecked"})
  @Override
  public BasicValue naryOperation(AbstractInsnNode insn, List rawValues) throws AnalyzerException {
    final List<BasicValue> values = (List<BasicValue>) rawValues;
    boolean isStatic = false;
    switch (insn.getOpcode()) {
      case INVOKESTATIC:
        isStatic = true;
      case INVOKESPECIAL:
      case INVOKEVIRTUAL:
      case INVOKEINTERFACE:
        final MethodInsnNode method = (MethodInsnNode) insn;
        String methodOwner = method.owner;

        // special case: in case that class is extending tuple we need to find the class
        // that contains the actual implementation to determine the tuple size
        if (method.name.equals("getField") || method.name.equals("setField")) {
          try {
            final String newMethodOwner =
                (String) findMethodNode(methodOwner, method.name, method.desc)[1];
            if (newMethodOwner.startsWith("org/apache/flink/api/java/tuple/Tuple")) {
              methodOwner = newMethodOwner;
            }
          } catch (IllegalStateException e) {
            // proceed with the known method owner
          }
        }

        // special case: collect method of Collector
        if (method.name.equals("collect")
            && methodOwner.equals("org/apache/flink/util/Collector")
            && isTagged(values.get(0))
            && tagged(values.get(0)).isCollector()) {
          // check for invalid return value
          if (isTagged(values.get(1)) && tagged(values.get(1)).isNull()) {
            analyzer.handleNullReturn();
          }
          // valid return value with input dependencies
          else if (hasImportantDependencies(values.get(1))) {
            // add a copy and a reference
            // to capture the current state and future changes in alternative paths
            analyzer.getCollectorValues().add(tagged(values.get(1)));
            analyzer.getCollectorValues().add(tagged(values.get(1)).copy());
          }
          // valid return value without input dependencies
          else {
            analyzer.getCollectorValues().add(null);
          }
        }
        // special case: iterator method of Iterable
        else if (method.name.equals("iterator")
            && methodOwner.equals("java/lang/Iterable")
            && isTagged(values.get(0))
            && tagged(values.get(0)).isInputIterable()) {
          return new TaggedValue(
              Type.getObjectType("java/util/Iterator"),
              (tagged(values.get(0)).isInput1Iterable())
                  ? Tag.INPUT_1_ITERATOR
                  : Tag.INPUT_2_ITERATOR);
        }
        // special case: hasNext method of Iterator
        else if (method.name.equals("hasNext")
            && methodOwner.equals("java/util/Iterator")
            && isTagged(values.get(0))
            && tagged(values.get(0)).isInputIterator()
            && !analyzer.isUdfBinary()
            && !analyzer.isIteratorTrueAssumptionApplied()) {
          return new TaggedValue(Type.BOOLEAN_TYPE, Tag.ITERATOR_TRUE_ASSUMPTION);
        }
        // special case: next method of Iterator
        else if (method.name.equals("next")
            && methodOwner.equals("java/util/Iterator")
            && isTagged(values.get(0))
            && tagged(values.get(0)).isInputIterator()) {
          // after this call it is not possible to assume "TRUE" of "hasNext()" again
          analyzer.applyIteratorTrueAssumption();
          if (tagged(values.get(0)).isInput1Iterator()) {
            return analyzer.getInput1AsTaggedValue();
          } else {
            return analyzer.getInput2AsTaggedValue();
          }
        }
        // if the UDF class contains instance variables that contain input,
        // we need to analyze also methods without input-dependent arguments
        // special case: do not follow the getRuntimeContext method of RichFunctions
        else if (!isStatic
            && isTagged(values.get(0))
            && tagged(values.get(0)).isThis()
            && hasImportantDependencies(values.get(0))
            && !isGetRuntimeContext(method)) {
          TaggedValue tv = invokeNestedMethod(values, method);
          if (tv != null) {
            return tv;
          }
        }
        // the arguments have input dependencies ("THIS" does not count to the arguments)
        // we can assume that method has at least one argument
        else if ((!isStatic
                && isTagged(values.get(0))
                && tagged(values.get(0)).isThis()
                && hasImportantDependencies(values, true))
            || (!isStatic
                && (!isTagged(values.get(0)) || !tagged(values.get(0)).isThis())
                && hasImportantDependencies(values, false))
            || (isStatic && hasImportantDependencies(values, false))) {
          // special case: Java unboxing/boxing methods on input
          Type newType;
          if (isTagged(values.get(0))
              && tagged(values.get(0)).isInput()
              && (!isStatic && (newType = checkForUnboxing(method.name, methodOwner)) != null
                  || (isStatic
                      && (newType = checkForBoxing(method.name, method.desc, methodOwner))
                          != null))) {
            return tagged(values.get(0)).copy(newType);
          }
          // special case: setField method of TupleXX
          else if (method.name.equals("setField")
              && methodOwner.startsWith("org/apache/flink/api/java/tuple/Tuple")
              && isTagged(values.get(0))) {
            final TaggedValue tuple = tagged(values.get(0));
            tuple.setTag(Tag.CONTAINER);

            // check if fieldPos is constant
            // if not, we can not determine a state for the tuple
            if (!isTagged(values.get(2)) || !tagged(values.get(2)).isIntConstant()) {
              tuple.makeRegular();
            } else {
              final int constant = tagged(values.get(2)).getIntConstant();

              if (constant < 0 || Integer.valueOf(methodOwner.split("Tuple")[1]) <= constant) {
                analyzer.handleInvalidTupleAccess();
              }

              // if it is at least tagged, add it anyways
              if (isTagged(values.get(1))) {
                tuple.addContainerMapping("f" + constant, tagged(values.get(1)), currentFrame);
              }
              // mark the field as it has an undefined state
              else {
                tuple.addContainerMapping("f" + constant, null, currentFrame);
              }
            }
          }
          // special case: getField method of TupleXX
          else if (method.name.equals("getField")
              && methodOwner.startsWith("org/apache/flink/api/java/tuple/Tuple")) {
            final TaggedValue tuple =
                tagged(values.get(0)); // we can assume that 0 is an input dependent tuple
            // constant field index
            if (isTagged(values.get(1)) // constant
                && tagged(values.get(1)).isIntConstant()) {
              final int constant = tagged(values.get(1)).getIntConstant();

              if (constant < 0 || Integer.valueOf(methodOwner.split("Tuple")[1]) <= constant) {
                analyzer.handleInvalidTupleAccess();
              }

              if (tuple.containerContains("f" + constant)) {
                final TaggedValue tupleField = tuple.getContainerMapping().get("f" + constant);
                if (tupleField != null) {
                  return tupleField;
                }
              }
            }
            // unknown field index
            else {
              // we need to make the tuple regular as we cannot track modifications of fields
              tuple.makeRegular();
              return new TaggedValue(Type.getObjectType("java/lang/Object"));
            }
          }
          // nested method invocation
          else {
            TaggedValue tv = invokeNestedMethod(values, method);
            if (tv != null) {
              return tv;
            }
          }
        }
        return super.naryOperation(insn, values);
      default:
        // TODO support for INVOKEDYNAMIC instructions
        return super.naryOperation(insn, values);
    }
  }
예제 #15
0
 private String getInternalName(String internalName) {
   return getDescriptor(Type.getObjectType(internalName));
 }