gt:                 for (int i1 = 0; i1 < length; i1++) {
context: /*
   * Copyright (c) 2013, 2017, 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 com.oracle.truffle.r.nodes.builtin.base;
  
  import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.toBoolean;
  import static com.oracle.truffle.r.nodes.unary.PrecedenceNode.COMPLEX_PRECEDENCE;
  import static com.oracle.truffle.r.nodes.unary.PrecedenceNode.DOUBLE_PRECEDENCE;
  import static com.oracle.truffle.r.nodes.unary.PrecedenceNode.EXPRESSION_PRECEDENCE;
  import static com.oracle.truffle.r.nodes.unary.PrecedenceNode.INT_PRECEDENCE;
  import static com.oracle.truffle.r.nodes.unary.PrecedenceNode.LIST_PRECEDENCE;
  import static com.oracle.truffle.r.nodes.unary.PrecedenceNode.LOGICAL_PRECEDENCE;
  import static com.oracle.truffle.r.nodes.unary.PrecedenceNode.NO_PRECEDENCE;
  import static com.oracle.truffle.r.nodes.unary.PrecedenceNode.RAW_PRECEDENCE;
  import static com.oracle.truffle.r.nodes.unary.PrecedenceNode.STRING_PRECEDENCE;
  import static com.oracle.truffle.r.runtime.RDispatch.INTERNAL_GENERIC;
  import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE;
  import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
  
  import com.oracle.truffle.api.CompilerAsserts;
  import com.oracle.truffle.api.CompilerDirectives;
  import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
  import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
  import com.oracle.truffle.api.dsl.Cached;
  import com.oracle.truffle.api.dsl.NodeChild;
  import com.oracle.truffle.api.dsl.Specialization;
  import com.oracle.truffle.api.nodes.ExplodeLoop;
  import com.oracle.truffle.api.profiles.BranchProfile;
  import com.oracle.truffle.api.profiles.ConditionProfile;
  import com.oracle.truffle.api.profiles.ValueProfile;
  import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimNamesAttributeNode;
  import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode;
  import com.oracle.truffle.r.nodes.builtin.CastBuilder;
  import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
  import com.oracle.truffle.r.nodes.builtin.base.CombineNodeGen.CombineInputCastNodeGen;
  import com.oracle.truffle.r.nodes.unary.CastComplexNodeGen;
  import com.oracle.truffle.r.nodes.unary.CastDoubleNodeGen;
  import com.oracle.truffle.r.nodes.unary.CastIntegerNodeGen;
  import com.oracle.truffle.r.nodes.unary.CastListNodeGen;
  import com.oracle.truffle.r.nodes.unary.CastLogicalNodeGen;
  import com.oracle.truffle.r.nodes.unary.CastNode;
  import com.oracle.truffle.r.nodes.unary.CastRawNodeGen;
  import com.oracle.truffle.r.nodes.unary.CastStringNodeGen;
  import com.oracle.truffle.r.nodes.unary.CastToVectorNode;
  import com.oracle.truffle.r.nodes.unary.PrecedenceNode;
  import com.oracle.truffle.r.nodes.unary.PrecedenceNodeGen;
  import com.oracle.truffle.r.runtime.ArgumentsSignature;
  import com.oracle.truffle.r.runtime.RError;
  import com.oracle.truffle.r.runtime.RRuntime;
  import com.oracle.truffle.r.runtime.builtins.RBuiltin;
  import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames;
  import com.oracle.truffle.r.runtime.data.RAttributesLayout;
  import com.oracle.truffle.r.runtime.data.RDataFactory;
  import com.oracle.truffle.r.runtime.data.RLanguage;
  import com.oracle.truffle.r.runtime.data.RList;
  import com.oracle.truffle.r.runtime.data.RNull;
  import com.oracle.truffle.r.runtime.data.RStringVector;
  import com.oracle.truffle.r.runtime.data.RVector;
  import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
  import com.oracle.truffle.r.runtime.nodes.RBaseNode;
  import com.oracle.truffle.r.runtime.nodes.RNode;
  import com.oracle.truffle.r.runtime.ops.na.NACheck;
  
  @RBuiltin(name = "c", kind = PRIMITIVE, parameterNames = {"...", "recursive"}, dispatch = INTERNAL_GENERIC, behavior = PURE)
  public abstract class Combine extends RBuiltinNode {
  
      public static Combine create() {
          return CombineNodeGen.create();
      }
  
      private static final ArgumentsSignature EMPTY_SIGNATURE = ArgumentsSignature.empty(1);
  
      protected static final int COMBINE_CACHED_LIMIT = PrecedenceNode.NUMBER_OF_PRECEDENCES;
  
      private static final int MAX_PROFILES = 4;
  
      @Child private PrecedenceNode precedenceNode = PrecedenceNodeGen.create();
      @Child private CombineInputCast inputCast = CombineInputCastNodeGen.create(null);
      @Child private CastToVectorNode castVector;
  
      private final BranchProfile naBranch = BranchProfile.create();
      private final NACheck naCheck = NACheck.create();
      private final ConditionProfile fastNamesMerge = ConditionProfile.createBinaryProfile();
      private final ConditionProfile isAbstractVectorProfile = ConditionProfile.createBinaryProfile();
      private final ConditionProfile hasNewNamesProfile = ConditionProfile.createBinaryProfile();
      @CompilationFinal private final ValueProfile[] argProfiles = new ValueProfile[MAX_PROFILES];
  
      @Override
      protected void createCasts(CastBuilder casts) {
          casts.arg("recursive").asLogicalVector().findFirst(RRuntime.LOGICAL_NA).map(toBoolean());
      }
  
      public abstract Object executeCombine(Object value, Object recursive);
  
      protected boolean isSimpleArguments(RArgsValuesAndNames args) {
          return !signatureHasNames(args.getSignature()) && args.getLength() == 1 && !(args.getArgument(0) instanceof RAbstractVector);
      }
  
      @Specialization(guards = {"isSimpleArguments(args)", "!recursive"})
      protected Object combineSimple(RArgsValuesAndNames args, @SuppressWarnings("unused") boolean recursive) {
          return args.getArgument(0);
      }
  
      @Specialization(contains = "combineSimple", limit = "1", guards = {"!recursive", "args.getSignature() == cachedSignature", "cachedPrecedence == precedence(args, cachedSignature.getLength())"})
      protected Object combineCached(RArgsValuesAndNames args, @SuppressWarnings("unused") boolean recursive,
                      @Cached("args.getSignature()") ArgumentsSignature cachedSignature,
                      @Cached("precedence( args, cachedSignature.getLength())") int cachedPrecedence,
                      @Cached("createCast(cachedPrecedence)") CastNode cast,
                      @Cached("create()") BranchProfile naNameBranch,
                      @Cached("create()") NACheck naNameCheck,
                      @Cached("createBinaryProfile()") ConditionProfile hasNamesProfile,
                      @Cached("create()") GetNamesAttributeNode getNamesNode) {
          CompilerAsserts.partialEvaluationConstant(cachedSignature);
          CompilerAsserts.partialEvaluationConstant(cachedPrecedence);
  
          if (cachedPrecedence == NO_PRECEDENCE) {
              return RNull.instance;
          }
  
          // perform all the casts
          Object[] elements = new Object[cachedSignature.getLength()];
          int size = prepareElements(args.getArguments(), cast, cachedPrecedence, elements);
  
          // prepare the names (if there are any)
          boolean signatureHasNames = signatureHasNames(cachedSignature);
          CompilerAsserts.partialEvaluationConstant(signatureHasNames);
          RStringVector namesVector = hasNamesProfile.profile(signatureHasNames || hasNames(elements, getNamesNode)) ? foldNames(naNameBranch, naNameCheck, elements, size, cachedSignature, getNamesNode)
                          : null;
  
          // get the actual contents of the result
          RVector<?> result = foldContents(cachedPrecedence, elements, size, namesVector);
  
          RBaseNode.reportWork(this, size);
  
          return result;
      }
  
      @TruffleBoundary
      @Specialization(limit = "COMBINE_CACHED_LIMIT", contains = "combineCached", guards = {"!recursive", "cachedPrecedence == precedence(args)"})
      protected Object combine(RArgsValuesAndNames args, @SuppressWarnings("unused") boolean recursive,
                      @Cached("precedence(args, args.getLength())") int cachedPrecedence,
                      @Cached("createCast(cachedPrecedence)") CastNode cast,
                      @Cached("create()") BranchProfile naNameBranch,
                      @Cached("create()") NACheck naNameCheck,
                      @Cached("createBinaryProfile()") ConditionProfile hasNamesProfile,
                      @Cached("create()") GetNamesAttributeNode getNamesNode) {
          return combineCached(args, false, args.getSignature(), cachedPrecedence, cast, naNameBranch, naNameCheck, hasNamesProfile, getNamesNode);
      }
  
      @Specialization(guards = "recursive")
      protected Object combineRecursive(RArgsValuesAndNames args, @SuppressWarnings("unused") boolean recursive,
                      @Cached("create()") Combine recursiveCombine,
                      @Cached("createBinaryProfile()") ConditionProfile useNewArgsProfile) {
          return combineRecursive(args, recursiveCombine, useNewArgsProfile);
      }
  
      @SuppressWarnings("static-method")
      @ExplodeLoop
      private Object combineRecursive(RArgsValuesAndNames args, Combine recursiveCombine, ConditionProfile useNewArgsProfile) {
          Object[] argsArray = args.getArguments();
          Object[] newArgsArray = new Object[argsArray.length];
          boolean useNewArgs = false;
          for (int i = 0; i < argsArray.length; i++) {
              Object arg = argsArray[i];
              if (arg instanceof RList) {
                  Object[] argsFromList = ((RList) arg).getDataWithoutCopying();
                  newArgsArray[i] = recursiveCombine.executeCombine(new RArgsValuesAndNames(argsFromList,
                                  ArgumentsSignature.empty(argsFromList.length)), true);
                  useNewArgs = true;
              } else {
                  newArgsArray[i] = arg;
              }
          }
  
          if (useNewArgsProfile.profile(useNewArgs)) {
              return recursiveCombine.executeCombine(new RArgsValuesAndNames(newArgsArray,
                              args.getSignature()), false);
          } else {
              return recursiveCombine.executeCombine(args, false);
          }
      }
  
      @ExplodeLoop
      private int prepareElements(Object[] args, CastNode cast, int precedence, Object[] elements) {
          int size = 0;
          for (int i = 0; i < elements.length; i++) {
              Object element = readAndCast(cast, args[i], precedence);
              if (i < argProfiles.length) {
                  if (argProfiles[i] == null) {
                      CompilerDirectives.transferToInterpreterAndInvalidate();
                      argProfiles[i] = ValueProfile.createClassProfile();
                  }
                  element = argProfiles[i].profile(element);
              }
              elements[i] = element;
              size += getElementSize(element);
          }
          return size;
      }
  
      private static int getElementSize(Object element) {
          if (element instanceof RAbstractVector) {
              return ((RAbstractVector) element).getLength();
          } else if (element instanceof RNull) {
              // nothing to do - NULL elements are skipped
              return 0;
          } else {
              return 1;
          }
      }
  
      @ExplodeLoop
      private boolean hasNames(Object[] elements, GetNamesAttributeNode getNamesNode) {
          for (int i = 0; i < elements.length; i++) {
              Object element = elements[i];
              if (i < argProfiles.length) {
                  element = argProfiles[i].profile(element);
              }
              if (element instanceof RAbstractVector) {
                  RAbstractVector vector = (RAbstractVector) element;
                  if (getNamesNode.getNames(vector) != null) {
                      return true;
                  }
              }
          }
          return false;
      }
  
      @ExplodeLoop
      private RStringVector foldNames(BranchProfile naNameBranch, NACheck naNameCheck, Object[] elements, int size, ArgumentsSignature signature, GetNamesAttributeNode getNamesNode) {
          RStringVector result = RDataFactory.createStringVector(new String[size], true);
          result.incRefCount();
          int pos = 0;
          for (int i = 0; i < elements.length; i++) {
              Object element = elements[i];
              if (i < argProfiles.length) {
                  element = argProfiles[i].profile(element);
              }
              pos += processNamesElement(naNameBranch, naNameCheck, result, pos, element, i, signature, getNamesNode);
          }
          return result;
      }
  
      private int processNamesElement(BranchProfile naNameBranch, NACheck naNameCheck, RStringVector result, int pos, Object element, int index, ArgumentsSignature signature,
                      GetNamesAttributeNode getNamesNode) {
          String signatureName = signature.getName(index);
          if (element instanceof RAbstractVector) {
              RAbstractVector v = (RAbstractVector) element;
              int length = v.getLength();
  
              RStringVector newNames = getNamesNode.getNames(v);
              if (signatureName != null && length > 0) {
                  if (fastNamesMerge.profile(length == 1 && newNames == null)) {
                      newNames = RDataFactory.createStringVector(new String[]{signatureName}, true);
                  } else {
                      newNames = RDataFactory.createStringVector(mergeNamesSlow(length, signatureName, newNames), true);
                  }
              }
              if (hasNewNamesProfile.profile(newNames != null)) {
  