@Override
   public void generate(CompiledPredicateWriter g) {
      Term function = g.currentClause().getCurrentFunction();
      PredicateFactory ef = g.currentClause().getCurrentPredicateFactory();

      MultipleRulesWithMultipleImmutableArgumentsPredicate mrwmia = (MultipleRulesWithMultipleImmutableArgumentsPredicate) ef;
      String functionVariableName = g.classVariables().getPredicateFactoryVariableName(function, g.knowledgeBase());
      String ctrVarName = g.classVariables().getNewInlinedCtrVariableName();
      Runnable r = g.createOnBreakCallback(functionVariableName, function, ctrVarName);
      Set<Variable> termsThatAreNotYetAssignedButReusedLater = g.getTermArgumentsThatAreCurrentlyUnassignedAndNotReusedWithinTheTerm(function);
      if (termsThatAreNotYetAssignedButReusedLater.size() == function.getNumberOfArguments()) {
         g.logMultipleRulesWithImmutableArgumentsPredicateCall(functionVariableName, ctrVarName, function.getArgs());
         g.outputIfTrueThenBreak(ctrVarName + ">" + (mrwmia.data.length - 1), r);
         g.assign("final Term[] data" + ctrVarName, functionVariableName + ".data[" + ctrVarName + "++]");
         for (int i = 0; i < function.getNumberOfArguments(); i++) {
            Term arg = function.getArgument(i);
            String variableId = g.getVariableId(arg);
            g.classVariables().addAssignedVariable(variableId);
            g.assign(variableId, "data" + ctrVarName + "[" + i + "]");
         }
         g.logInlinedPredicatePredicate("Exit", functionVariableName, function);
      } else {
         Map<Term, String> tmpVars = g.getTermsThatRequireBacktrack(function);
         Map<String, String> variablesToKeepTempVersionOf = g.outputBacktrackTermArguments(tmpVars);
         g.logMultipleRulesWithImmutableArgumentsPredicateCall(functionVariableName, ctrVarName, function.getArgs());
         g.addLine("do {");
         g.outputIfTrueThenBreak(ctrVarName + ">" + (mrwmia.data.length - 1), r);
         g.assign("final Term[] data" + ctrVarName, functionVariableName + ".data[" + ctrVarName + "++]");
         // LinkedHashSet so predictable order (makes unit tests easier)
         Set<String> varsToBacktrack = new LinkedHashSet<>();
         for (int i = 0; i < function.getNumberOfArguments(); i++) {
            Term arg = function.getArgument(i);
            if (termsThatAreNotYetAssignedButReusedLater.contains(arg) == false) {
               String termId = tmpVars.get(arg);
               if (arg.isImmutable() == false) {
                  varsToBacktrack.add(termId);
               }
               g.beginIf(getUnifyStatement(termId, "data" + ctrVarName + "[" + i + "]") + "==false");
               for (String id : varsToBacktrack) {
                  g.outputBacktrack(id);
               }
               g.endBlock();
               g.addLine("else");
            }
         }
         g.addLine("{");
         for (Variable v : termsThatAreNotYetAssignedButReusedLater) {
            String variableId = g.getVariableId(v);
            g.classVariables().addAssignedVariable(variableId);
            int i = 0;
            for (; i < function.getNumberOfArguments(); i++) {
               if (v == function.getArgument(i)) {
                  break;
               }
            }
            g.assign(variableId, "data" + ctrVarName + "[" + i + "]");
         }
         g.logInlinedPredicatePredicate("Exit", functionVariableName, function);
         g.writeStatement("break");
         g.endBlock();
         g.addLine("} while (true);");
         g.assignTermToTempVariable(variablesToKeepTempVersionOf);
      }

      g.currentClause().clearVariablesToBackTrack();
   }