gt:         for (int i = 0; i < numLocals; i++) {
context: /*
   * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   *
   * This code is free software; you can redistribute it and/or modify it
   * under the terms of the GNU General Public License version 2 only, as
   * published by the Free Software Foundation.
   *
   * This code 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 Public License
   * version 2 for more details (a copy is included in the LICENSE file that
   * accompanied this code).
   *
   * You should have received a copy of the GNU General Public License version
   * 2 along with this work; if not, write to the Free Software Foundation,
   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   *
   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   * or visit www.oracle.com if you need additional information or have any
   * questions.
   */
  package org.graalvm.compiler.core.gen;
  
  import java.util.ArrayDeque;
  import java.util.Arrays;
  import java.util.Map;
  import java.util.Queue;
  
  import org.graalvm.compiler.debug.Debug;
  import org.graalvm.compiler.debug.DebugCounter;
  import org.graalvm.compiler.debug.GraalError;
  import org.graalvm.compiler.graph.Node;
  import org.graalvm.compiler.lir.ConstantValue;
  import org.graalvm.compiler.lir.LIRFrameState;
  import org.graalvm.compiler.lir.LabelRef;
  import org.graalvm.compiler.lir.Variable;
  import org.graalvm.compiler.nodes.ConstantNode;
  import org.graalvm.compiler.nodes.FrameState;
  import org.graalvm.compiler.nodes.ValueNode;
  import org.graalvm.compiler.nodes.spi.NodeValueMap;
  import org.graalvm.compiler.nodes.util.GraphUtil;
  import org.graalvm.compiler.nodes.virtual.EscapeObjectState;
  import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
  import org.graalvm.compiler.virtual.nodes.MaterializedObjectState;
  import org.graalvm.compiler.virtual.nodes.VirtualObjectState;
  
  import jdk.vm.ci.code.BytecodeFrame;
  import jdk.vm.ci.code.VirtualObject;
  import jdk.vm.ci.meta.JavaKind;
  import jdk.vm.ci.meta.JavaType;
  import jdk.vm.ci.meta.JavaValue;
  import jdk.vm.ci.meta.ResolvedJavaField;
  import jdk.vm.ci.meta.ResolvedJavaType;
  import jdk.vm.ci.meta.Value;
  
  /**
   * Builds {@link LIRFrameState}s from {@link FrameState}s.
   */
  public class DebugInfoBuilder {
  
      protected final NodeValueMap nodeValueMap;
  
      public DebugInfoBuilder(NodeValueMap nodeValueMap) {
          this.nodeValueMap = nodeValueMap;
      }
  
      private static final JavaValue[] NO_JAVA_VALUES = {};
      private static final JavaKind[] NO_JAVA_KINDS = {};
  
      protected final Map<VirtualObjectNode, VirtualObject> virtualObjects = Node.newMap();
      protected final Map<VirtualObjectNode, EscapeObjectState> objectStates = Node.newIdentityMap();
  
      protected final Queue<VirtualObjectNode> pendingVirtualObjects = new ArrayDeque<>();
  
      public LIRFrameState build(FrameState topState, LabelRef exceptionEdge) {
          assert virtualObjects.size() == 0;
          assert objectStates.size() == 0;
          assert pendingVirtualObjects.size() == 0;
  
          // collect all VirtualObjectField instances:
          FrameState current = topState;
          do {
              if (current.virtualObjectMappingCount() > 0) {
                  for (EscapeObjectState state : current.virtualObjectMappings()) {
                      if (!objectStates.containsKey(state.object())) {
                          if (!(state instanceof MaterializedObjectState) || ((MaterializedObjectState) state).materializedValue() != state.object()) {
                              objectStates.put(state.object(), state);
                          }
                      }
                  }
              }
              current = current.outerFrameState();
          } while (current != null);
  
          BytecodeFrame frame = computeFrameForState(topState);
  
          VirtualObject[] virtualObjectsArray = null;
          if (virtualObjects.size() != 0) {
              // fill in the VirtualObject values
              VirtualObjectNode vobjNode;
              while ((vobjNode = pendingVirtualObjects.poll()) != null) {
                  VirtualObject vobjValue = virtualObjects.get(vobjNode);
                  assert vobjValue.getValues() == null;
  
                  JavaValue[] values;
                  JavaKind[] slotKinds;
                  int entryCount = vobjNode.entryCount();
                  if (entryCount == 0) {
                      values = NO_JAVA_VALUES;
                      slotKinds = NO_JAVA_KINDS;
                  } else {
                      values = new JavaValue[entryCount];
                      slotKinds = new JavaKind[entryCount];
                  }
                  if (values.length > 0) {
                      VirtualObjectState currentField = (VirtualObjectState) objectStates.get(vobjNode);
                      assert currentField != null;
                      int pos = 0;
                      for (int i = 0; i < entryCount; i++) {
                          if (!currentField.values().get(i).isConstant() || currentField.values().get(i).asJavaConstant().getJavaKind() != JavaKind.Illegal) {
                              ValueNode value = currentField.values().get(i);
                              values[pos] = toJavaValue(value);
                              slotKinds[pos] = toSlotKind(value);
                              pos++;
                          } else {
                              assert currentField.values().get(i - 1).getStackKind() == JavaKind.Double || currentField.values().get(i - 1).getStackKind() == JavaKind.Long : vobjNode + " " + i + " " +
                                              currentField.values().get(i - 1);
                          }
                      }
                      if (pos != entryCount) {
                          values = Arrays.copyOf(values, pos);
                          slotKinds = Arrays.copyOf(slotKinds, pos);
                      }
                  }
                  assert checkValues(vobjValue.getType(), values, slotKinds);
                  vobjValue.setValues(values, slotKinds);
              }
  
              virtualObjectsArray = virtualObjects.values().toArray(new VirtualObject[virtualObjects.size()]);
              virtualObjects.clear();
          }
          objectStates.clear();
  
          return newLIRFrameState(exceptionEdge, frame, virtualObjectsArray);
      }
  
      private boolean checkValues(ResolvedJavaType type, JavaValue[] values, JavaKind[] slotKinds) {
          assert (values == null) == (slotKinds == null);
          if (values != null) {
              assert values.length == slotKinds.length;
              if (!type.isArray()) {
                  ResolvedJavaField[] fields = type.getInstanceFields(true);
                  int fieldIndex = 0;
                  for (int i = 0; i < values.length; i++) {
                      ResolvedJavaField field = fields[fieldIndex++];
                      JavaKind valKind = slotKinds[i].getStackKind();
                      JavaKind fieldKind = storageKind(field.getType());
                      if (fieldKind == JavaKind.Object) {
                          assert valKind.isObject() : field + ": " + valKind + " != " + fieldKind;
                      } else {
                          if ((valKind == JavaKind.Double || valKind == JavaKind.Long) && fieldKind == JavaKind.Int) {
                              assert storageKind(fields[fieldIndex].getType()) == JavaKind.Int;
                              fieldIndex++;
                          } else {
                              assert valKind == fieldKind.getStackKind() : field + ": " + valKind + " != " + fieldKind;
                          }
                      }
                  }
                  assert fields.length == fieldIndex : type + ": fields=" + Arrays.toString(fields) + ", field values=" + Arrays.toString(values);
              } else {
                  JavaKind componentKind = storageKind(type.getComponentType()).getStackKind();
                  if (componentKind == JavaKind.Object) {
                      for (int i = 0; i < values.length; i++) {
                          assert slotKinds[i].isObject() : slotKinds[i] + " != " + componentKind;
                      }
                  } else {
                      for (int i = 0; i < values.length; i++) {
                          assert slotKinds[i] == componentKind || componentKind.getBitCount() >= slotKinds[i].getBitCount() ||
                                          (componentKind == JavaKind.Int && slotKinds[i].getBitCount() >= JavaKind.Int.getBitCount()) : slotKinds[i] + " != " + componentKind;
                      }
                  }
              }
          }
          return true;
      }
  
      /*
       * Customization point for subclasses. For example, Word types have a kind Object, but are
       * internally stored as a primitive value. We do not know about Word types here, but subclasses
       * do know.
       */
      protected JavaKind storageKind(JavaType type) {
          return type.getJavaKind();
      }
  
      protected LIRFrameState newLIRFrameState(LabelRef exceptionEdge, BytecodeFrame frame, VirtualObject[] virtualObjectsArray) {
          return new LIRFrameState(frame, virtualObjectsArray, exceptionEdge);
      }
  
      protected BytecodeFrame computeFrameForState(FrameState state) {
          try {
              assert state.bci != BytecodeFrame.INVALID_FRAMESTATE_BCI;
              assert state.bci != BytecodeFrame.UNKNOWN_BCI;
              assert state.bci != BytecodeFrame.BEFORE_BCI || state.locksSize() == 0;
              assert state.bci != BytecodeFrame.AFTER_BCI || state.locksSize() == 0;
              assert state.bci != BytecodeFrame.AFTER_EXCEPTION_BCI || state.locksSize() == 0;
              assert !(state.getMethod().isSynchronized() && state.bci != BytecodeFrame.BEFORE_BCI && state.bci != BytecodeFrame.AFTER_BCI && state.bci != BytecodeFrame.AFTER_EXCEPTION_BCI) ||
                              state.locksSize() > 0;
              assert state.verify();
  
              int numLocals = state.localsSize();
              int numStack = state.stackSize();
              int numLocks = state.locksSize();
  
              int numValues = numLocals + numStack + numLocks;
              int numKinds = numLocals + numStack;
  
              JavaValue[] values = numValues == 0 ? NO_JAVA_VALUES : new JavaValue[numValues];
              JavaKind[] slotKinds = numKinds == 0 ? NO_JAVA_KINDS : new JavaKind[numKinds];
              computeLocals(state, numLocals, values, slotKinds);
              computeStack(state, numLocals, numStack, values, slotKinds);
              computeLocks(state, values);
  
              BytecodeFrame caller = null;
              if (state.outerFrameState() != null) {
                  caller = computeFrameForState(state.outerFrameState());
              }
  
              if (!state.canProduceBytecodeFrame()) {
                  // This typically means a snippet or intrinsic frame state made it to the backend
                  StackTraceElement ste = state.getCode().asStackTraceElement(state.bci);
                  throw new GraalError("Frame state for %s cannot be converted to a BytecodeFrame since the frame state's code is " +
                                  "not the same as the frame state method's code", ste);
              }
  
              return new BytecodeFrame(caller, state.getMethod(), state.bci, state.rethrowException(), state.duringCall(), values, slotKinds, numLocals, numStack, numLocks);
          } catch (GraalError e) {
              throw e.addContext("FrameState: ", state);
          }
      }
  
      protected void computeLocals(FrameState state, int numLocals, JavaValue[] values, JavaKind[] slotKinds) {
  