src/main/java/org/plumelib/bcelutil/StackMapUtils.java
protected final void fix_local_variable_table(MethodGen mgen) {
    InstructionList il = mgen.getInstructionList();
    if (il == null) {
      // no code so nothing to do
      first_local_index = 0;
      return;
    }

    // Get the current local variables (includes 'this' and parameters)
    LocalVariableGen[] locals = mgen.getLocalVariables();
    LocalVariableGen l;
    LocalVariableGen new_lvg;

    // We need a deep copy
    for (int ii = 0; ii < locals.length; ii++) {
      locals[ii] = (LocalVariableGen) (locals[ii].clone());
    }

    // The arg types are correct and include all parameters.
    Type[] arg_types = mgen.getArgumentTypes();

    // Initial offset into the stack frame
    int offset = 0;

    // Index into locals of the first parameter
    int loc_index = 0;

    // Rarely, the java compiler gets the max locals count wrong (too big).
    // This would cause problems for us later, so we need to recalculate
    // the highest local used based on looking at code offsets.
    mgen.setMaxLocals();
    int max_locals = mgen.getMaxLocals();
    // Remove the existing locals
    mgen.removeLocalVariables();
    // Reset MaxLocals to 0 and let code below rebuild it.
    mgen.setMaxLocals(0);

    // Determine the first 'true' local index into the local variables.
    // The object 'this' pointer and the parameters form the first n
    // entries in the list.
    first_local_index = arg_types.length;

    if (!mgen.isStatic()) {
      // Add the 'this' pointer back in.
      l = locals[0];
      new_lvg = mgen.addLocalVariable(l.getName(), l.getType(), l.getIndex(), null, null);
      debug_instrument.log(
          "Added <this> %s%n",
          new_lvg.getIndex() + ": " + new_lvg.getName() + ", " + new_lvg.getType());
      loc_index = 1;
      offset = 1;
      first_local_index++;
    }

    // Loop through each parameter
    for (int ii = 0; ii < arg_types.length; ii++) {

      // If this parameter doesn't have a matching local
      if ((loc_index >= locals.length) || (offset != locals[loc_index].getIndex())) {

        // Create a local variable to describe the missing parameter
        new_lvg = mgen.addLocalVariable("$hidden$" + offset, arg_types[ii], offset, null, null);
      } else {
        l = locals[loc_index];
        new_lvg = mgen.addLocalVariable(l.getName(), l.getType(), l.getIndex(), null, null);
        loc_index++;
      }
      debug_instrument.log(
          "Added param  %s%n",
          new_lvg.getIndex() + ": " + new_lvg.getName() + ", " + new_lvg.getType());
      offset += arg_types[ii].getSize();
    }

    // At this point the LocalVaraibles contain:
    //   the 'this' pointer (if present)
    //   the parameters to the method
    // This will be used to construct the initial state of the
    // StackMapTypes.
    LocalVariableGen[] initial_locals = mgen.getLocalVariables();
    initial_locals_count = initial_locals.length;
    initial_type_list = new StackMapType[initial_locals_count];
    for (int ii = 0; ii < initial_locals_count; ii++) {
      initial_type_list[ii] = generate_StackMapType_from_Type(initial_locals[ii].getType());
    }

    // Add back the true locals
    //
    // NOTE that the Java compiler uses unnamed local temps for:
    //   saving the exception in a finally clause
    //   the lock for a synchronized block
    //   iterators
    //   (others?)
    // We will create a 'fake' local for these cases.

    for (int ii = first_local_index; ii < locals.length; ii++) {
      l = locals[ii];
      if (l.getIndex() > offset) {
        // A gap in index values indicates a compiler allocated temp.
        // (if offset is 0, probably a lock object)
        // there is at least one hidden compiler temp before the next local
        offset = gen_temp_locals(mgen, offset);
        ii--; // need to revisit same local
      } else {
        new_lvg =
            mgen.addLocalVariable(l.getName(), l.getType(), l.getIndex(), l.getStart(), l.getEnd());
        debug_instrument.log(
            "Added local  %s%n",
            new_lvg.getIndex() + ": " + new_lvg.getName() + ", " + new_lvg.getType());
        offset = new_lvg.getIndex() + (new_lvg.getType()).getSize();
      }
    }

    // check for hidden temps after last declared local.
    while (offset < max_locals) {
      offset = gen_temp_locals(mgen, offset);
    }

    // Recalculate the highest local used based on looking at code offsets.
    mgen.setMaxLocals();
  }
protected final void fix_local_variable_table(MethodGen mgen) {
    InstructionList il = mgen.getInstructionList();
    if (il == null) {
      // no code so nothing to do
      first_local_index = 0;
      return;
    }

    // Get the current local variables (includes 'this' and parameters)
    LocalVariableGen[] locals = mgen.getLocalVariables();
    LocalVariableGen l;
    LocalVariableGen new_lvg;

    // We need a deep copy
    for (int ii = 0; ii < locals.length; ii++) {
      locals[ii] = (LocalVariableGen) (locals[ii].clone());
    }

    // The arg types are correct and include all parameters.
    Type[] arg_types = mgen.getArgumentTypes();

    // Initial offset into the stack frame
    int offset = 0;

    // Index into locals of the first parameter
    int loc_index = 0;

    // Rarely, the java compiler gets the max locals count wrong (too big).
    // This would cause problems for us later, so we need to recalculate
    // the highest local used based on looking at code offsets.
    mgen.setMaxLocals();
    int max_locals = mgen.getMaxLocals();
    // Remove the existing locals
    mgen.removeLocalVariables();
    // Reset MaxLocals to 0 and let code below rebuild it.
    mgen.setMaxLocals(0);

    // Determine the first 'true' local index into the local variables.
    // The object 'this' pointer and the parameters form the first n
    // entries in the list.
    first_local_index = arg_types.length;

    if (!mgen.isStatic()) {
      // Add the 'this' pointer back in.
      l = locals[0];
      new_lvg = mgen.addLocalVariable(l.getName(), l.getType(), l.getIndex(), null, null);
      debug_instrument.log(
          "Added <this> %s%n",
          new_lvg.getIndex() + ": " + new_lvg.getName() + ", " + new_lvg.getType());
      loc_index = 1;
      offset = 1;
      first_local_index++;
    }

    // Loop through each parameter
    for (int ii = 0; ii < arg_types.length; ii++) {

      // If this parameter doesn't have a matching local
      if ((loc_index >= locals.length) || (offset != locals[loc_index].getIndex())) {

        // Create a local variable to describe the missing parameter
        new_lvg = mgen.addLocalVariable("$hidden$" + offset, arg_types[ii], offset, null, null);
      } else {
        l = locals[loc_index];
        new_lvg = mgen.addLocalVariable(l.getName(), l.getType(), l.getIndex(), null, null);
        loc_index++;
      }
      debug_instrument.log(
          "Added param  %s%n",
          new_lvg.getIndex() + ": " + new_lvg.getName() + ", " + new_lvg.getType());
      offset += arg_types[ii].getSize();
    }

    // At this point the LocalVaraibles contain:
    //   the 'this' pointer (if present)
    //   the parameters to the method
    // This will be used to construct the initial state of the
    // StackMapTypes.
    LocalVariableGen[] initial_locals = mgen.getLocalVariables();
    initial_locals_count = initial_locals.length;
    initial_type_list = new StackMapType[initial_locals_count];
    for (int ii = 0; ii < initial_locals_count; ii++) {
      initial_type_list[ii] = generate_StackMapType_from_Type(initial_locals[ii].getType());
    }

    // Add back the true locals
    //
    // NOTE that the Java compiler uses unnamed local temps for:
    //   saving the exception in a finally clause
    //   the lock for a synchronized block
    //   iterators
    //   (others?)
    // We will create a 'fake' local for these cases.

    for (int ii = first_local_index; ii < locals.length; ii++) {
      l = locals[ii];
      if (l.getIndex() > offset) {
        // A gap in index values indicates a compiler allocated temp.
        // (if offset is 0, probably a lock object)
        // there is at least one hidden compiler temp before the next local
        offset = gen_temp_locals(mgen, offset);
        ii--; // need to revisit same local
      } else {
        new_lvg =
            mgen.addLocalVariable(l.getName(), l.getType(), l.getIndex(), l.getStart(), l.getEnd());
        debug_instrument.log(
            "Added local  %s%n",
            new_lvg.getIndex() + ": " + new_lvg.getName() + ", " + new_lvg.getType());
        offset = new_lvg.getIndex() + (new_lvg.getType()).getSize();
      }
    }

    // check for hidden temps after last declared local.
    while (offset < max_locals) {
      offset = gen_temp_locals(mgen, offset);
    }

    // Recalculate the highest local used based on looking at code offsets.
    mgen.setMaxLocals();
  }
Under some circumstances, there may be problems with the local variable table. These problems
occur when the Java compiler adds unnamed entries. There may be unnamed parameters and/or
unnamed local variables. These items appear as gaps in the LocalVariable table. This routine
creates LocalVariable entries for these missing items.

<ol>
<li>The java Compiler allocates a hidden parameter for the constructor of an inner class.
These items are given the name $hidden$ appended with their offset.
<li>The Java compiler allocates unnamed local temps for:
<ul>
<li>saving the exception in a finally clause
<li>the lock for a synchronized block
<li>interators
<li>(others?)
</ul>
These items are given the name DaIkOnTeMp appended with their offset.
</ol>

@param mgen MethodGen to be modified