Beispiel #1
0
  /**
   * Reset the state of the operand stack based on the stack state recorded for a given target.
   *
   * @param target the target whose recorded state will be used to reset the state of this frame's
   *     operand stack
   * @param isForCatch specifies if target corresponds to an exception handler entry
   */
  public void resetStack(Target target, boolean isForCatch) {
    Klass[] recordedTypes = target.getStack();
    if (!isForCatch) {
      sp = 0;
      if (recordedTypes.length != 0) {
        StackProducer[] derivedStack = target.getDerivedStack();
        boolean isBackwardBranchTarget = (derivedStack[0] == null);
        if (isBackwardBranchTarget) {
          for (int i = 0; i < recordedTypes.length; i++) {
            Klass recordedType = recordedTypes[i];
            if (recordedType != Klass.LONG2 && recordedType != Klass.DOUBLE2) {

              StackMerge merge = new StackMerge(recordedType);
              // Sometimes we end up with old derivedStack[0] == a StackMerge with no producers.
              Assert.that(derivedStack[0] == null || !derivedStack[0].isOnStack());
              derivedStack[0] = merge;
              push(merge);
            }
          }
        } else {
          while (sp != derivedStack.length) {
            StackProducer producer = derivedStack[sp];
            stack[sp++] = producer;
          }
        }
      }
    } else {
      // Assert.that(sp == 0);
      sp = 0;
    }
  }
Beispiel #2
0
  /**
   * Reset the state of the local variable array based on the local variable state recorded for a
   * given target.
   *
   * @param target the target whose recorded state will be used to reset the state of this frame's
   *     local variable array
   */
  public void resetLocals(Target target) {
    Klass[] recordedTypes = target.getLocals();
    int i;
    for (i = 0; i < recordedTypes.length; i++) {
      localTypes[i] = recordedTypes[i];
    }
    while (i < localTypes.length) {
      localTypes[i++] = Klass.TOP;
    }

    // There is at least one TCK test that has a stack map in a synchronized method
    // at the entry to some unreachable code:
    // javasoft.sqe.tests.vm.instr.athrow.athrow013.athrow01301m1.athrow01301m1_wrapper
    // In this case, the stack map will be invalid with respect to the synthesized
    // stack map at the entry to the exception handler wrapping the whole method
    // to implement the correct semantics for method synchronization. To make such
    // code pass the translator, the reset state of the locals includes the extra state
    // derived from the synthesized stack map.
    if (finallyTargetForSynchronizedMethod != null) {
      Klass[] types = finallyTargetForSynchronizedMethod.getLocals();
      if (types.length > recordedTypes.length) {
        for (i = recordedTypes.length; i != types.length; ++i) {
          localTypes[i] = types[i];
        }
      }
    }
  }
Beispiel #3
0
  /**
   * Verifies that the current state of the local variables array matches the state specified by a
   * stack map entry.
   *
   * @param target the target encapsulating a stack map entry specifying what the current state of
   *     the local variables array should be
   * @param replaceWithTarget if true, then the current state of the local variable array is updated
   *     to reflect the state recorded in the stack map entry
   */
  public void mergeLocals(Target target, boolean replaceWithTarget) {
    Klass[] recordedTypes = target.getLocals();
    if (recordedTypes.length > localTypes.length) {
      throw codeParser.verifyError("size of recorded and derived local variable array differs");
    }

    /*
     * Check the locals
     */
    for (int i = 0; i < recordedTypes.length; i++) {
      Klass recordedType = recordedTypes[i];
      Klass derivedType = localTypes[i];
      if (!recordedType.isAssignableFrom(derivedType)) {
        /*
         * For some reason, the preverifier occasionally generates
         * stack map entries for local variables even though the
         * local variable is dead. What's more, in these cases,
         * it determines that the type resulting from merging an
         * object type and an interface type is the interface
         * type. This makes no sense to me, but the case must be
         * allowed.
         */
        if (!recordedType.isInterface() || derivedType.isPrimitive()) {
          throw codeParser.verifyError("invalid type in local variable");
        }
      }
      if (replaceWithTarget) {
        localTypes[i] = recordedType;
      }
    }
  }
Beispiel #4
0
  /**
   * Merges the current state of the operand stack into the saved state at a control flow target.
   * This method also verifies that the current state of the operand stack matches the expected
   * state of the operand stack at the target as pecified by a stack map entry.
   *
   * @param target the target encapsulting the merged state of the operand stack at a distinct
   *     address
   * @param replaceWithTarget if true, then the current state of the operand stack is updated to
   *     reflect the state recorded in the stack map entry
   */
  public void mergeStack(Target target, boolean replaceWithTarget) {
    Klass[] recordedTypes = target.getStack();

    /*
     * Fail if the map sp is different
     */
    if (recordedTypes.length != getStackSize()) {
      throw codeParser.verifyError("size of recorded and derived stack differs");
    }

    /*
     * Check the stack items
     */
    for (int r = 0, d = 0; r < recordedTypes.length; ++r, ++d) {
      Klass recordedType = recordedTypes[r];
      Klass derivedType = getStackTypeAt(d);
      if (!recordedType.isAssignableFrom(derivedType)) {

        // Interfaces are treated like java.lang.Object in the verifier according to the CLDC spec.
        if (!recordedType.isInterface() || !Klass.OBJECT.isAssignableFrom(derivedType)) {
          throw codeParser.verifyError(
              "invalid type on operand stack @ "
                  + d
                  + ": expected "
                  + recordedType
                  + ", received "
                  + derivedType);
        }
      }
    }

    /*
     * Merge the instructions on the stack
     */
    target.merge(this);

    if (replaceWithTarget) {
      resetStack(target, false);
    }
  }
Beispiel #5
0
 /**
  * Traces the state of the local variables at the current verification address.
  *
  * @param target the stack map (if any) at the current verification address
  */
 private void traceLocals(Target target) {
   if (Translator.TRACING_ENABLED) {
     Klass[] map = (target == null) ? Klass.NO_CLASSES : target.getLocals();
     int i = 0;
     int l = 0;
     while (i < map.length || l < localTypes.length) {
       Klass derived = (l < localTypes.length) ? localTypes[l] : null;
       Klass recorded = (i < map.length) ? map[i] : null;
       String prefix = "  local[" + l + "]: ";
       traceType(derived, prefix, true);
       if (recorded != null) {
         traceType(recorded, prefix, false);
       }
       i++;
       l++;
     }
   }
 }
Beispiel #6
0
 /**
  * Traces the state of the operand stack at the current verification address.
  *
  * @param target the stack map (if any) at the current verification address
  */
 private void traceStack(Target target) {
   if (Translator.TRACING_ENABLED) {
     Klass[] map = target == null ? Klass.NO_CLASSES : target.getStack();
     int r = 0; // index into recorded stack (i.e. from stack map)
     int d = 0; // index into derived stack
     while (r < map.length || d < sp) {
       Klass derived = (d < sp) ? getStackTypeAt(d) : null;
       Klass recorded = (r < map.length) ? map[r] : null;
       String prefix = "  stack[" + r + "]: ";
       traceType(derived, prefix, true);
       if (recorded != null) {
         traceType(recorded, prefix, false);
       }
       ++r;
       ++d;
     }
   }
 }