Path: blob/master/test/jdk/java/lang/invoke/LoopCombinatorTest.java
41149 views
/*1* Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425/* @test26* @bug 813988527* @bug 815063528* @bug 815095629* @bug 815095730* @bug 815117931* @bug 815266732* @bug 815363733* @bug 815475134* @bug 815475435* @bug 816797436* @run testng/othervm -ea -esa test.java.lang.invoke.LoopCombinatorTest37*/3839package test.java.lang.invoke;4041import java.lang.invoke.MethodHandle;42import java.lang.invoke.MethodHandles;43import java.lang.invoke.MethodHandles.Lookup;44import java.lang.invoke.MethodType;45import java.util.*;4647import static java.lang.invoke.MethodType.methodType;4849import static org.testng.AssertJUnit.*;5051import org.testng.annotations.*;5253/**54* Tests for the loop combinators introduced in JEP 274.55*/56public class LoopCombinatorTest {5758static final Lookup LOOKUP = MethodHandles.lookup();5960@Test61public static void testLoopFac() throws Throwable {62MethodHandle[] counterClause = new MethodHandle[]{Fac.MH_zero, Fac.MH_inc};63MethodHandle[] accumulatorClause = new MethodHandle[]{Fac.MH_one, Fac.MH_mult, Fac.MH_pred, Fac.MH_fin};64MethodHandle loop = MethodHandles.loop(counterClause, accumulatorClause);65assertEquals(Fac.MT_fac, loop.type());66assertEquals(120, loop.invoke(5));67}6869@Test70public static void testLoopFacNullInit() throws Throwable {71// null initializer for counter, should initialize to 072MethodHandle[] counterClause = new MethodHandle[]{null, Fac.MH_inc};73MethodHandle[] accumulatorClause = new MethodHandle[]{Fac.MH_one, Fac.MH_mult, Fac.MH_pred, Fac.MH_fin};74MethodHandle loop = MethodHandles.loop(counterClause, accumulatorClause);75assertEquals(Fac.MT_fac, loop.type());76assertEquals(120, loop.invoke(5));77}7879@Test80public static void testLoopNullInit() throws Throwable {81// null initializer for counter, should initialize to 0, one-clause loop82MethodHandle[] counterClause = new MethodHandle[]{null, Loop.MH_inc, Loop.MH_pred, Loop.MH_fin};83MethodHandle loop = MethodHandles.loop(counterClause);84assertEquals(Loop.MT_loop, loop.type());85assertEquals(10, loop.invoke(10));86}8788@Test89public static void testLoopVoid1() throws Throwable {90// construct a post-checked loop that only does one iteration and has a void body and void local state91MethodHandle loop = MethodHandles.loop(new MethodHandle[]{Empty.MH_f, Empty.MH_f, Empty.MH_pred, null});92assertEquals(MethodType.methodType(void.class), loop.type());93loop.invoke();94}9596@Test97public static void testLoopVoid2() throws Throwable {98// construct a post-checked loop that only does one iteration and has a void body and void local state,99// initialized implicitly from the step type100MethodHandle loop = MethodHandles.loop(new MethodHandle[]{null, Empty.MH_f, Empty.MH_pred, null});101assertEquals(MethodType.methodType(void.class), loop.type());102loop.invoke();103}104105@Test106public static void testLoopVoid3() throws Throwable {107// construct a post-checked loop that only does one iteration and has a void body and void local state,108// and that has a void finalizer109MethodHandle loop = MethodHandles.loop(new MethodHandle[]{null, Empty.MH_f, Empty.MH_pred, Empty.MH_f});110assertEquals(MethodType.methodType(void.class), loop.type());111loop.invoke();112}113114@Test115public static void testLoopFacWithVoidState() throws Throwable {116// like testLoopFac, but with additional void state that outputs a dot117MethodHandle[] counterClause = new MethodHandle[]{Fac.MH_zero, Fac.MH_inc};118MethodHandle[] accumulatorClause = new MethodHandle[]{Fac.MH_one, Fac.MH_mult, Fac.MH_pred, Fac.MH_fin};119MethodHandle[] dotClause = new MethodHandle[]{null, Fac.MH_dot};120MethodHandle loop = MethodHandles.loop(counterClause, accumulatorClause, dotClause);121assertEquals(Fac.MT_fac, loop.type());122assertEquals(120, loop.invoke(5));123}124125@Test126public static void testLoopVoidInt() throws Throwable {127// construct a post-checked loop that only does one iteration and has a void body and void local state,128// and that returns a constant129MethodHandle loop = MethodHandles.loop(new MethodHandle[]{null, Empty.MH_f, Empty.MH_pred, Empty.MH_c});130assertEquals(MethodType.methodType(int.class), loop.type());131assertEquals(23, loop.invoke());132}133134@Test135public static void testLoopWithVirtuals() throws Throwable {136// construct a loop (to calculate factorial) that uses a mix of static and virtual methods137MethodHandle[] counterClause = new MethodHandle[]{null, LoopWithVirtuals.permute(LoopWithVirtuals.MH_inc)};138MethodHandle[] accumulatorClause = new MethodHandle[]{139// init function must indicate the loop arguments (there is no other means to determine them)140MethodHandles.dropArguments(LoopWithVirtuals.MH_one, 0, LoopWithVirtuals.class),141LoopWithVirtuals.permute(LoopWithVirtuals.MH_mult),142LoopWithVirtuals.permute(LoopWithVirtuals.MH_pred),143LoopWithVirtuals.permute(LoopWithVirtuals.MH_fin)144};145MethodHandle loop = MethodHandles.loop(counterClause, accumulatorClause);146assertEquals(LoopWithVirtuals.MT_loop, loop.type());147assertEquals(120, loop.invoke(new LoopWithVirtuals(), 5));148}149150@Test151public static void testLoopOmitPred() throws Throwable {152// construct a loop to calculate factorial that omits a predicate153MethodHandle[] counterClause = new MethodHandle[]{null, Fac.MH_inc, null, Fac.MH_fin};154MethodHandle[] accumulatorClause = new MethodHandle[]{Fac.MH_one, Fac.MH_mult, Fac.MH_pred, Fac.MH_fin};155MethodHandle loop = MethodHandles.loop(counterClause, accumulatorClause);156assertEquals(Fac.MT_fac, loop.type());157assertEquals(120, loop.invoke(5));158}159160@DataProvider161static Object[][] negativeTestData() {162MethodHandle i0 = MethodHandles.constant(int.class, 0);163MethodHandle ii = MethodHandles.dropArguments(i0, 0, int.class, int.class);164MethodHandle id = MethodHandles.dropArguments(i0, 0, int.class, double.class);165MethodHandle i3 = MethodHandles.dropArguments(i0, 0, int.class, int.class, int.class);166List<MethodHandle> inits = Arrays.asList(ii, id, i3);167List<Class<?>> ints3 = Arrays.asList(int.class, int.class, int.class);168List<Class<?>> ints4 = Arrays.asList(int.class, int.class, int.class, int.class);169List<MethodHandle> finis = Arrays.asList(Fac.MH_fin, Fac.MH_inc, Counted.MH_step);170List<MethodHandle> preds1 = Arrays.asList(null, null, null);171List<MethodHandle> preds2 = Arrays.asList(null, Fac.MH_fin, null);172MethodHandle eek = MethodHandles.dropArguments(i0, 0, int.class, int.class, double.class);173List<MethodHandle> nesteps = Arrays.asList(Fac.MH_inc, eek, Fac.MH_dot);174List<MethodHandle> nepreds = Arrays.asList(null, Fac.MH_pred, null);175List<MethodHandle> nefinis = Arrays.asList(null, Fac.MH_fin, null);176List<MethodHandle> lvsteps = Arrays.asList(LoopWithVirtuals.MH_inc, LoopWithVirtuals.MH_mult);177List<MethodHandle> lvpreds = Arrays.asList(null, LoopWithVirtuals.MH_pred);178List<MethodHandle> lvfinis = Arrays.asList(null, LoopWithVirtuals.MH_fin);179return new Object[][] {180{null, "null or no clauses passed"},181{new MethodHandle[][]{}, "null or no clauses passed"},182{new MethodHandle[][]{{null, Fac.MH_inc}, {Fac.MH_one, null, Fac.MH_mult, Fac.MH_pred, Fac.MH_fin}},183"All loop clauses must be represented as MethodHandle arrays with at most 4 elements."},184{new MethodHandle[][]{{null, Fac.MH_inc}, null}, "null clauses are not allowed"},185{new MethodHandle[][]{{Fac.MH_zero, Fac.MH_dot}},186"clause 0: init and step return types must match: int != void"},187{new MethodHandle[][]{{ii}, {id}, {i3}},188"found non-effectively identical init parameter type lists: " + inits +189" (common suffix: " + ints3 + ")"},190{new MethodHandle[][]{{null, Fac.MH_inc, null, Fac.MH_fin}, {null, Fac.MH_inc, null, Fac.MH_inc},191{null, Counted.MH_start, null, Counted.MH_step}},192"found non-identical finalizer return types: " + finis + " (return type: int)"},193{new MethodHandle[][]{{Fac.MH_zero, Fac.MH_inc}, {Fac.MH_one, Fac.MH_mult, null, Fac.MH_fin},194{null, Fac.MH_dot}}, "no predicate found: " + preds1},195{new MethodHandle[][]{{Fac.MH_zero, Fac.MH_inc}, {Fac.MH_one, Fac.MH_mult, Fac.MH_fin, Fac.MH_fin},196{null, Fac.MH_dot}}, "predicates must have boolean return type: " + preds2},197{new MethodHandle[][]{{Fac.MH_zero, Fac.MH_inc}, {Fac.MH_one, eek, Fac.MH_pred, Fac.MH_fin},198{null, Fac.MH_dot}},199"found non-effectively identical parameter type lists:\nstep: " + nesteps +200"\npred: " + nepreds + "\nfini: " + nefinis + " (common parameter sequence: " + ints3 + ")"},201{new MethodHandle[][]{{null, LoopWithVirtuals.MH_inc},202{LoopWithVirtuals.MH_one, LoopWithVirtuals.MH_mult, LoopWithVirtuals.MH_pred, LoopWithVirtuals.MH_fin}},203"found non-effectively identical parameter type lists:\nstep: " + lvsteps +204"\npred: " + lvpreds + "\nfini: " + lvfinis + " (common parameter sequence: " + ints4 + ")"}205};206}207208static final MethodHandle MH_loop;209210static {211try {212MH_loop = LOOKUP.findStatic(MethodHandles.class, "loop", methodType(MethodHandle.class, MethodHandle[][].class));213} catch (NoSuchMethodException | IllegalAccessException e) {214throw new ExceptionInInitializerError(e);215}216}217218@Test(dataProvider = "negativeTestData")219public static void testLoopNegative(MethodHandle[][] clauses, String expectedMessage) throws Throwable {220boolean caught = false;221try {222MH_loop.invokeWithArguments((Object[]) clauses);223} catch (IllegalArgumentException iae) {224assertEquals(expectedMessage, iae.getMessage());225caught = true;226}227assertTrue(caught);228}229230@Test(dataProvider = "whileLoopTestData")231public static void testWhileLoop(MethodHandle MH_zero,232MethodHandle MH_pred,233MethodHandle MH_step,234String messageOrNull) throws Throwable {235// int i = 0; while (i < limit) { ++i; } return i; => limit236try {237MethodHandle loop = MethodHandles.whileLoop(MH_zero, MH_pred, MH_step);238assert messageOrNull == null;239if (MH_step.type().equals(While.MH_step.type()))240assertEquals(While.MT_while, loop.type());241assertEquals(MH_step.type().dropParameterTypes(0, 1), loop.type());242while (loop.type().parameterCount() > 1) loop = snip(loop);243assertEquals(23, loop.invoke(23));244} catch (IllegalArgumentException iae) {245assert messageOrNull != null;246assertEqualsFIXME(messageOrNull, iae.getMessage());247}248}249250static void assertEqualsFIXME(String expect, String actual) {251if (!expect.equals(actual)) {252// just issue a warning253System.out.println("*** "+actual+"\n != "+expect);254}255}256257@DataProvider258static Object[][] whileLoopTestData() {259MethodHandle260zeroI = While.MH_zero,261zeroX = snip(zeroI),262zeroIB = slap(zeroI, byte.class),263predII = While.MH_pred,264predIX = snip(predII),265predIIB = slap(predII, byte.class),266stepII = While.MH_step,267stepIX = snip(stepII),268stepIIB = slap(stepII, byte.class)269;270return new Object[][] {271// normal while loop clauses, perhaps with effectively-identical reductions272{zeroI, predII, stepII, null},273{zeroX, predII, stepII, null},274{null, predII, stepII, null},275// expanded while loop clauses276{zeroIB, predIIB, stepIIB, null},277{zeroI, predIIB, stepIIB, null},278{null, predIIB, stepIIB, null},279{zeroIB, predII, stepIIB, null},280{zeroX, predII, stepIIB, null},281{null, predII, stepIIB, null},282// short step clauses cause errors283{zeroI, predII, stepIX, "loop predicate must match: (int,int)boolean != (int)boolean"},284{zeroIB, predIX, stepIX, "loop initializer must match: (int,byte)int != ()int"},285// bad body type286{zeroI, predII, tweak(stepII, -1, char.class), "body function must match: (int,int)char != (char,int,int)char"},287{zeroI, predII, tweak(stepII, 0, char.class), "body function must match: (char,int)int != (int,char,int)int"},288// bad pred type289{zeroI, tweak(predII, -1, char.class), stepII, "loop predicate must match: (int,int)char != (int,int)boolean"},290{zeroI, tweak(predII, 0, char.class), stepII, "loop predicate must match: (char,int)boolean != (int,int)boolean"},291// bad init type292{tweak(zeroI, -1, char.class), predII, stepII, "loop initializer must match: (int)char != (int)int"},293{tweak(zeroI, 0, char.class), predII, stepII, "loop initializer must match: (char)int != (int)int"},294};295}296297// tweak the type of an MH298static MethodHandle tweak(MethodHandle mh, int argPos, Class<?> type) {299MethodType mt = mh.type();300if (argPos == -1)301mt = mt.changeReturnType(type);302else303mt = mt.changeParameterType(argPos, type);304return MethodHandles.explicitCastArguments(mh, mt);305}306// snip off an MH argument, hard-wiring to zero307static MethodHandle snip(MethodHandle mh, int argPos) {308if (argPos < 0) return null; // special case for optional args309Class<?> argType = mh.type().parameterType(argPos);310Object zero;311try {312zero = MethodHandles.zero(argType).invoke();313} catch (Throwable ex) {314throw new AssertionError(ex);315}316return MethodHandles.insertArguments(mh, argPos, zero);317}318static MethodHandle snip(MethodHandle mh) {319return snip(mh, mh.type().parameterCount()-1);320}321// slap on an extra type on the end of the MH322static MethodHandle slap(MethodHandle mh, Class<?> addType) {323return MethodHandles.dropArguments(mh, mh.type().parameterCount(), addType);324}325326@Test327public static void testWhileLoopNoIteration() throws Throwable {328// a while loop that never executes its body because the predicate evaluates to false immediately329MethodHandle loop = MethodHandles.whileLoop(While.MH_initString, While.MH_predString, While.MH_stepString);330assertEquals(While.MT_string, loop.type());331assertEquals("a", loop.invoke());332}333334@Test(dataProvider = "whileLoopTestData")335public static void testDoWhileLoop(MethodHandle MH_zero,336MethodHandle MH_pred,337MethodHandle MH_step,338String messageOrNull) throws Throwable {339// int i = 0; do { ++i; } while (i < limit); return i; => limit340try {341MethodHandle loop = MethodHandles.doWhileLoop(MH_zero, MH_step, MH_pred);342assert messageOrNull == null;343if (MH_step.type().equals(While.MH_step.type()))344assertEquals(While.MT_while, loop.type());345assertEquals(MH_step.type().dropParameterTypes(0, 1), loop.type());346while (loop.type().parameterCount() > 1) loop = snip(loop);347assertEquals(23, loop.invoke(23));348} catch (IllegalArgumentException iae) {349assert messageOrNull != null;350if (!messageOrNull.equals(iae.getMessage())) {351// just issue a warning352System.out.println("*** "+messageOrNull+"\n != "+iae.getMessage());353}354}355}356357@Test358public static void testDoWhileBadInit() throws Throwable {359boolean caught = false;360try {361While w = new While();362MethodHandle loop = MethodHandles.doWhileLoop(MethodHandles.empty(methodType(char.class)),363While.MH_voidBody.bindTo(w),364While.MH_voidPred.bindTo(w));365} catch (IllegalArgumentException iae) {366assertEquals("loop initializer must match: ()char != (int)void", iae.getMessage());367caught = true;368}369assertTrue(caught);370}371372@Test373public static void testWhileZip() throws Throwable {374MethodHandle loop = MethodHandles.doWhileLoop(While.MH_zipInitZip, While.MH_zipStep, While.MH_zipPred);375assertEquals(While.MT_zip, loop.type());376List<String> a = Arrays.asList("a", "b", "c", "d");377List<String> b = Arrays.asList("e", "f", "g", "h");378List<String> zipped = Arrays.asList("a", "e", "b", "f", "c", "g", "d", "h");379assertEquals(zipped, (List<String>) loop.invoke(a.iterator(), b.iterator()));380}381382@Test383public static void testWhileBadInit() throws Throwable {384boolean caught = false;385try {386While w = new While();387MethodHandle loop = MethodHandles.whileLoop(MethodHandles.empty(methodType(void.class, char.class)),388While.MH_voidPred.bindTo(w),389While.MH_voidBody.bindTo(w));390} catch (IllegalArgumentException iae) {391assertEquals("loop initializer must match: (char)void != (int)void", iae.getMessage());392caught = true;393}394assertTrue(caught);395}396397@Test398public static void testWhileVoidInit() throws Throwable {399While w = new While();400int v = 5;401MethodHandle loop = MethodHandles.whileLoop(While.MH_voidInit.bindTo(w), While.MH_voidPred.bindTo(w),402While.MH_voidBody.bindTo(w));403assertEquals(While.MT_void, loop.type());404loop.invoke(v);405assertEquals(v, w.i);406}407408@Test409public static void testDoWhileVoidInit() throws Throwable {410While w = new While();411int v = 5;412MethodHandle loop = MethodHandles.doWhileLoop(While.MH_voidInit.bindTo(w), While.MH_voidBody.bindTo(w),413While.MH_voidPred.bindTo(w));414assertEquals(While.MT_void, loop.type());415loop.invoke(v);416assertEquals(v, w.i);417}418419@DataProvider420static Object[][] nullArgs() {421MethodHandle c = MethodHandles.constant(int.class, 1);422return new Object[][]{{null, c}, {c, null}};423}424425@Test(dataProvider = "nullArgs", expectedExceptions = NullPointerException.class)426public static void testWhileNullArgs(MethodHandle pred, MethodHandle body) {427MethodHandles.whileLoop(null, pred, body);428}429430@Test(dataProvider = "nullArgs", expectedExceptions = NullPointerException.class)431public static void testDoWhileNullArgs(MethodHandle body, MethodHandle pred) {432MethodHandles.whileLoop(null, body, pred);433}434435@Test436public static void testCountedLoop() throws Throwable {437// String s = "Lambdaman!"; for (int i = 0; i < 13; ++i) { s = "na " + s; } return s; => a variation on a well known theme438MethodHandle fit13 = MethodHandles.dropArguments(MethodHandles.constant(int.class, 13), 0, String.class);439MethodHandle loop = MethodHandles.countedLoop(fit13, Counted.MH_start, Counted.MH_step);440assertEquals(Counted.MT_counted, loop.type());441assertEquals("na na na na na na na na na na na na na Lambdaman!", loop.invoke("Lambdaman!"));442}443444@Test445public static void testCountedLoopVoidInit() throws Throwable {446MethodHandle fit5 = MethodHandles.constant(int.class, 5);447for (int i = 0; i < 8; i++) {448MethodHandle zero = MethodHandles.zero(void.class);449MethodHandle init = fit5;450MethodHandle body = Counted.MH_printHello;451boolean useNull = (i & 1) != 0, addInitArg = (i & 2) != 0, addBodyArg = (i & 4) != 0;452if (useNull) zero = null;453if (addInitArg) init = MethodHandles.dropArguments(init, 0, int.class);454if (addBodyArg) body = MethodHandles.dropArguments(body, 1, int.class);455System.out.println("testCountedLoopVoidInit i="+i+" : "+Arrays.asList(init, zero, body));456MethodHandle loop = MethodHandles.countedLoop(init, zero, body);457MethodType expectedType = Counted.MT_countedPrinting;458if (addInitArg || addBodyArg)459expectedType = expectedType.insertParameterTypes(0, int.class);460assertEquals(expectedType, loop.type());461if (addInitArg || addBodyArg)462loop.invoke(99);463else464loop.invoke();465}466}467468@Test469public static void testCountedArrayLoop() throws Throwable {470// int[] a = new int[]{0}; for (int i = 0; i < 13; ++i) { ++a[0]; } => a[0] == 13471MethodHandle fit13 = MethodHandles.dropArguments(MethodHandles.constant(int.class, 13), 0, int[].class);472MethodHandle loop = MethodHandles.countedLoop(fit13, null, Counted.MH_stepUpdateArray);473assertEquals(Counted.MT_arrayCounted, loop.type());474int[] a = new int[]{0};475loop.invoke(a);476assertEquals(13, a[0]);477}478479@Test480public static void testCountedPrintingLoop() throws Throwable {481MethodHandle fit5 = MethodHandles.constant(int.class, 5);482MethodHandle loop = MethodHandles.countedLoop(fit5, null, Counted.MH_printHello);483assertEquals(Counted.MT_countedPrinting, loop.type());484loop.invoke();485}486487@Test(expectedExceptions = NullPointerException.class)488public static void testCountedLoopNullBody() throws Throwable {489MethodHandle h5 = MethodHandles.constant(int.class, 5);490MethodHandle h13 = MethodHandles.constant(int.class, 13);491MethodHandle loop = MethodHandles.countedLoop(h5, h13, null);492assertEquals(methodType(int.class), loop.type());493assertEquals(13, loop.invoke());494}495496@Test(expectedExceptions = NullPointerException.class)497public static void testCountedLoopNullIterations() throws Throwable {498MethodHandle loop = MethodHandles.countedLoop(null, null, null);499assertEquals(methodType(void.class), loop.type());500loop.invoke();501}502503@Test(expectedExceptions = NullPointerException.class)504public static void testCountedLoopNullInitAndBody() throws Throwable {505MethodHandle loop = MethodHandles.countedLoop(MethodHandles.constant(int.class, 5), null, null);506assertEquals(methodType(void.class), loop.type());507loop.invoke();508}509510@DataProvider511static Object[][] countedLoopBodyParameters() {512Class<?> V = String.class, I = int.class, A = List.class;513// return types are of these forms:514// {count = int(A...), init = V(A...), body = V(V, I, A...)}515return new Object[][] {516// body leads determining A...517{methodType(I), methodType(V), methodType(V, V, I)},518{methodType(I), methodType(V), methodType(V, V, I, A)},519{methodType(I,A), methodType(V), methodType(V, V, I, A)},520{methodType(I), methodType(V,A), methodType(V, V, I, A)},521// body leads, with void V522{methodType(I), methodType(void.class), methodType(void.class, I)},523{methodType(I), methodType(void.class), methodType(void.class, I, A)},524{methodType(I,A), methodType(void.class), methodType(void.class, I, A)},525{methodType(I), methodType(void.class,A), methodType(void.class, I, A)},526// count leads determining A..., but only if body drops all A...527{methodType(I,A), methodType(V), methodType(V, V, I)},528{methodType(I,A), methodType(V,A), methodType(V, V, I)},529// count leads, with void V530{methodType(I,A), methodType(void.class), methodType(void.class, I)},531{methodType(I,A), methodType(void.class,A), methodType(void.class, I)},532};533}534535@Test(dataProvider = "countedLoopBodyParameters")536public static void testCountedLoopBodyParameters(MethodType countType, MethodType initType, MethodType bodyType) throws Throwable {537MethodHandle loop = MethodHandles.countedLoop(538MethodHandles.empty(countType),539initType == null ? null : MethodHandles.empty(initType),540MethodHandles.empty(bodyType));541// The rule: If body takes the minimum number of parameters, then take what countType offers.542// The initType has to just roll with whatever the other two agree on.543int innerParams = (bodyType.returnType() == void.class ? 1 : 2);544MethodType expectType = bodyType.dropParameterTypes(0, innerParams);545if (expectType.parameterCount() == 0)546expectType = expectType.insertParameterTypes(0, countType.parameterList());547assertEquals(expectType, loop.type());548}549550@Test(dataProvider = "countedLoopBodyParameters")551public static void testCountedLoopBodyParametersNullInit(MethodType countType, MethodType initType, MethodType bodyType) throws Throwable {552testCountedLoopBodyParameters(countType, null, bodyType);553}554555@Test556public static void testCountedLoopStateInitializedToNull() throws Throwable {557MethodHandle loop = MethodHandles.countedLoop(MethodHandles.constant(int.class, 5),558MethodHandles.empty(methodType(String.class)), Counted.MH_stateBody);559assertEquals(Counted.MT_bodyDeterminesState, loop.type());560assertEquals("sssssnull01234", loop.invoke());561}562563@Test564public static void testCountedLoopArgsDefinedByIterations() throws Throwable {565MethodHandle iterations =566MethodHandles.dropArguments(MethodHandles.constant(int.class, 3), 0, String.class);567MethodHandle loop = MethodHandles.countedLoop(iterations,568MethodHandles.empty(iterations.type().changeReturnType(String.class)), Counted.MH_append);569assertEquals(Counted.MT_iterationsDefineArgs, loop.type());570assertEquals("hello012", loop.invoke("hello"));571}572573@Test574public static void testCountedRangeLoop() throws Throwable {575// String s = "Lambdaman!"; for (int i = -5; i < 8; ++i) { s = "na " + s; } return s; => a well known theme576MethodHandle fitm5 = MethodHandles.dropArguments(Counted.MH_m5, 0, String.class);577MethodHandle fit8 = MethodHandles.dropArguments(Counted.MH_8, 0, String.class);578MethodHandle loop = MethodHandles.countedLoop(fitm5, fit8, Counted.MH_start, Counted.MH_step);579assertEquals(Counted.MT_counted, loop.type());580assertEquals("na na na na na na na na na na na na na Lambdaman!", loop.invoke("Lambdaman!"));581}582583@Test584public static void testCountedLoopCounterInit() throws Throwable {585// int x = 0; for (int i = 0; i < 5; ++i) { x += i; } return x; => 10586// (only if counter's first value in body is 0)587MethodHandle iter = MethodHandles.constant(int.class, 5);588MethodHandle init = MethodHandles.constant(int.class, 0);589MethodHandle body = Counted.MH_addCounter;590MethodHandle loop = MethodHandles.countedLoop(iter, init, body);591assertEquals(Counted.MT_counterInit, loop.type());592assertEquals(10, loop.invoke());593}594595@Test596public static void testCountedLoopEmpty() throws Throwable {597// for (int i = 0; i < 5; ++i) { /* empty */ }598MethodHandle loop = MethodHandles.countedLoop(MethodHandles.constant(int.class, 5), null,599MethodHandles.empty(methodType(void.class, int.class)));600assertEquals(methodType(void.class), loop.type());601loop.invoke();602}603604@Test605public static void testCountedRangeLoopEmpty() throws Throwable {606// for (int i = -5; i < 5; ++i) { /* empty */ }607MethodHandle loop = MethodHandles.countedLoop(MethodHandles.constant(int.class, -5),608MethodHandles.constant(int.class, 5), null, MethodHandles.empty(methodType(void.class, int.class)));609assertEquals(methodType(void.class), loop.type());610loop.invoke();611}612613@DataProvider614static Object[][] countedLoopNegativeData() {615MethodHandle dummy = MethodHandles.zero(void.class);616MethodHandle one = MethodHandles.constant(int.class, 1);617MethodHandle oneString = MethodHandles.dropArguments(one, 0, String.class);618MethodHandle oneDouble = MethodHandles.dropArguments(one, 0, double.class);619return new Object[][]{620{dummy, one, dummy, dummy, String.format("start/end must return int %s, %s", dummy, one)},621{one, dummy, dummy, dummy, String.format("start/end must return int %s, %s", one, dummy)},622{oneString, oneDouble, dummy, dummy,623String.format("start and end parameter types must match: %s != %s", oneString.type(),624oneDouble.type())},625{oneString, oneString, dummy, dummy,626String.format("start/end and init parameter types must match: %s != %s", oneString.type(),627dummy.type())},628{one, one, null, dummy, String.format("actual and expected body signatures must match: %s != %s",629dummy.type(), dummy.type().appendParameterTypes(int.class))}630};631}632633@Test(dataProvider = "countedLoopNegativeData")634public static void testCountedLoopNegative(MethodHandle start, MethodHandle end, MethodHandle init,635MethodHandle body, String msg) {636if (true) return; //%%%FIXME%%%%637boolean caught = false;638try {639MethodHandles.countedLoop(start, end, init, body);640} catch (IllegalArgumentException iae) {641assertEquals(msg, iae.getMessage());642caught = true;643}644assertTrue(caught);645}646647@Test648public static void testIterateSum() throws Throwable {649// Integer[] a = new Integer[]{1,2,3,4,5,6}; int sum = 0; for (int e : a) { sum += e; } return sum; => 21650MethodHandle loop = MethodHandles.iteratedLoop(Iterate.MH_sumIterator, Iterate.MH_sumInit, Iterate.MH_sumStep);651assertEquals(Iterate.MT_sum, loop.type());652assertEquals(21, loop.invoke(new Integer[]{1, 2, 3, 4, 5, 6}));653}654655@DataProvider656static Object[][] iteratorInits() {657return new Object[][]{{Iterate.MH_iteratorFromList}, {Iterate.MH_iteratorFromIterable}, {null}};658}659660@Test(dataProvider = "iteratorInits")661public static void testIterateReverse(MethodHandle iterator) throws Throwable {662// this test uses List as its loop state type; don't try to change that663if (iterator != null)664iterator = iterator.asType(iterator.type().changeParameterType(0, List.class));665for (int i = 0; i < 4; i++) {666MethodHandle init = Iterate.MH_reverseInit, body = Iterate.MH_reverseStep;667boolean snipInit = (i & 1) != 0, snipBody = (i & 2) != 0;668if (snipInit) init = snip(init);669if (snipBody) body = snip(body);670if (!snipInit && snipBody && iterator == null) {671// Body does not determine (A...), so the default guy just picks Iterable.672// If body insisted on (List), the default guy would adjust himself.673// Init has no authority to change the (A...), so must patch init.674// All according to plan!675init = slap(snip(init), Iterable.class);676}677System.out.println("testIterateReverse i="+i+" : "+Arrays.asList(iterator, init, body));678MethodHandle loop = MethodHandles.iteratedLoop(iterator, init, body);679MethodType expectedType = Iterate.MT_reverse;680if (iterator == null && i >= 2)681expectedType = expectedType.changeParameterType(0, Iterable.class);682assertEquals(expectedType, loop.type());683List<String> list = Arrays.asList("a", "b", "c", "d", "e");684List<String> reversedList = Arrays.asList("e", "d", "c", "b", "a");685assertEquals(reversedList, (List<String>) loop.invoke(list));686}687}688689@Test(dataProvider = "iteratorInits")690public static void testIterateLength(MethodHandle iterator) throws Throwable {691MethodHandle body = Iterate.MH_lengthStep;692MethodHandle init = Iterate.MH_lengthInit;693MethodType expectedType = Iterate.MT_length;694int barity = body.type().parameterCount();695Class<?> iteratorSource = iterator == null ? null : iterator.type().parameterType(0);696if (iterator != null && iteratorSource != body.type().parameterType(barity-1)) {697// adjust body to accept the other type698body = body.asType(body.type().changeParameterType(barity-1, iteratorSource));699init = init.asType(init.type().changeParameterType(0, iteratorSource));700expectedType = expectedType.changeParameterType(0, iteratorSource);701}702for (;; init = snip(init)) {703System.out.println("testIterateLength.init = "+init);704MethodHandle loop = MethodHandles.iteratedLoop(iterator, init, body);705assertEquals(expectedType, loop.type());706List<Double> list = Arrays.asList(23.0, 148.0, 42.0);707assertEquals(list.size(), (int) loop.invoke(list));708if (init == null) break;709}710}711712@Test(dataProvider = "iteratorInits")713public static void testIterateMap(MethodHandle iterator) throws Throwable {714MethodHandle body = Iterate.MH_mapStep;715MethodHandle init = Iterate.MH_mapInit;716MethodType expectedType = Iterate.MT_map;717int barity = body.type().parameterCount();718Class<?> iteratorSource = iterator == null ? null : iterator.type().parameterType(0);719if (iterator != null && iteratorSource != body.type().parameterType(barity-1)) {720// adjust body to accept the other type721body = body.asType(body.type().changeParameterType(barity-1, iteratorSource));722init = init.asType(init.type().changeParameterType(0, iteratorSource));723expectedType = expectedType.changeParameterType(0, iteratorSource);724}725for (; init != null; init = snip(init)) {726System.out.println("testIterateMap.init = "+init);727MethodHandle loop = MethodHandles.iteratedLoop(iterator, init, body);728assertEquals(expectedType, loop.type());729List<String> list = Arrays.asList("Hello", "world", "!");730List<String> upList = Arrays.asList("HELLO", "WORLD", "!");731assertEquals(upList, (List<String>) loop.invoke(list));732}733}734735@Test(dataProvider = "iteratorInits")736public static void testIteratePrint(MethodHandle iterator) throws Throwable {737MethodHandle body = Iterate.MH_printStep;738MethodType expectedType = Iterate.MT_print;739int barity = body.type().parameterCount();740Class<?> iteratorSource = iterator == null ? null : iterator.type().parameterType(0);741if (iterator != null && iteratorSource != body.type().parameterType(barity-1)) {742// adjust body to accept the other type743body = body.asType(body.type().changeParameterType(barity-1, iteratorSource));744expectedType = expectedType.changeParameterType(0, iteratorSource);745}746MethodHandle loop = MethodHandles.iteratedLoop(iterator, null, body);747assertEquals(expectedType, loop.type());748loop.invoke(Arrays.asList("hello", "world"));749}750751@Test(expectedExceptions = NullPointerException.class)752public static void testIterateNullBody() {753MethodHandles.iteratedLoop(MethodHandles.empty(methodType(Iterator.class, int.class)),754MethodHandles.identity(int.class), null);755}756757@DataProvider758static Object[][] wrongIteratorTypes() {759return new Object[][]{{void.class}, {Object.class}, {Iterable.class}};760}761762@Test(dataProvider = "wrongIteratorTypes")763public static void testIterateVoidIterator(Class<?> it) {764boolean caught = false;765MethodType v = methodType(it);766try {767MethodHandles.iteratedLoop(MethodHandles.empty(v), null, MethodHandles.empty(v));768} catch(IllegalArgumentException iae) {769assertEqualsFIXME("iteratedLoop first argument must have Iterator return type", iae.getMessage());770caught = true;771}772assertTrue(caught);773}774775@Test(dataProvider = "iteratorInits")776public static void testIterateVoidInit(MethodHandle iterator) throws Throwable {777// this test uses List as its loop state type; don't try to change that778if (iterator != null)779iterator = iterator.asType(iterator.type().changeParameterType(0, List.class));780MethodHandle loop = MethodHandles.iteratedLoop(iterator, Iterate.MH_voidInit, Iterate.MH_printStep);781assertEquals(Iterate.MT_print, loop.type());782loop.invoke(Arrays.asList("hello", "world"));783}784785@DataProvider786static Object[][] iterateParameters() {787MethodType i = methodType(int.class);788MethodType sil_v = methodType(void.class, String.class, int.class, List.class);789MethodType isl_i = methodType(int.class, int.class, String.class, List.class);790MethodType isli_i = methodType(int.class, int.class, String.class, List.class, int.class);791MethodType sl_v = methodType(void.class, String.class, List.class);792MethodType sli_v = methodType(void.class, String.class, List.class, int.class);793MethodType l_it = methodType(Iterator.class, List.class);794MethodType li_i = methodType(int.class, List.class, int.class);795MethodType li_it = methodType(Iterator.class, List.class, int.class);796MethodType il_it = methodType(Iterator.class, int.class, List.class);797MethodType l_i = methodType(int.class, List.class);798return new Object[][]{799{l_it, null, sl_v, ""},800{l_it, l_i, isl_i, ""},801{l_it, null, sl_v, ""},802{li_it, li_i, isli_i, ""},803{null, null, sil_v, "inferred first loop argument must inherit from Iterable: int"},804{il_it, null, sil_v, ""},805{li_it, null, sli_v, ""},806{sl_v, null, sl_v, "iteratedLoop first argument must have Iterator return type"},807{li_it, l_it, sl_v,808String.format("iterator and init parameter lists must match: %s != %s", li_it, l_it)},809{li_it, li_i, isl_i,810String.format("body types (regard parameter types after index 0, and result type) must match: %s != %s",811isl_i, isl_i.dropParameterTypes(0, 1).appendParameterTypes(int.class))}812};813}814815@Test(dataProvider = "iterateParameters")816public static void testIterateParameters(MethodType it, MethodType in, MethodType bo, String msg) {817boolean negative = !msg.isEmpty();818MethodHandle iterator = it == null ? null : MethodHandles.empty(it);819MethodHandle init = in == null ? null : MethodHandles.empty(in);820boolean caught = false;821MethodHandle loop = null;822try {823loop = MethodHandles.iteratedLoop(iterator, init, MethodHandles.empty(bo));824} catch (Throwable t) {825if (!negative) {826throw t;827}828assertEqualsFIXME(msg, t.getMessage());829caught = true;830}831if (negative) {832assertTrue(caught);833} else {834MethodType lt = loop.type();835if (it == null && in == null) {836assertEquals(bo.dropParameterTypes(0, 1), lt);837} else if (it == null) {838if (in.parameterCount() == 0) {839assertEquals(bo.dropParameterTypes(0, in.returnType() == void.class ? 1 : 2), lt);840} else {841assertEquals(methodType(bo.returnType(), in.parameterArray()), lt);842}843} else if (in == null) {844assertEquals(methodType(bo.returnType(), it.parameterArray()), lt);845} else if (it.parameterCount() > in.parameterCount()) {846assertEquals(methodType(bo.returnType(), it.parameterArray()), lt);847} else if (it.parameterCount() < in.parameterCount()) {848assertEquals(methodType(bo.returnType(), in.parameterArray()), lt);849} else {850// both it, in present; with equal parameter list lengths851assertEquals(it.parameterList(), lt.parameterList());852assertEquals(in.parameterList(), lt.parameterList());853assertEquals(bo.returnType(), lt.returnType());854}855}856}857858@Test859public static void testIteratorSubclass() throws Throwable {860MethodHandle loop = MethodHandles.iteratedLoop(MethodHandles.empty(methodType(BogusIterator.class, List.class)),861null, MethodHandles.empty(methodType(void.class, String.class, List.class)));862assertEquals(methodType(void.class, List.class), loop.type());863}864865static class BogusIterator implements Iterator {866@Override867public boolean hasNext() {868return false;869}870@Override871public Object next() {872return null;873}874}875876static class Empty {877878static void f() { }879880static boolean pred() {881return false;882}883884static int c() {885return 23;886}887888static final Class<Empty> EMPTY = Empty.class;889890static final MethodType MT_f = methodType(void.class);891static final MethodType MT_pred = methodType(boolean.class);892static final MethodType MT_c = methodType(int.class);893894static final MethodHandle MH_f;895static final MethodHandle MH_pred;896static final MethodHandle MH_c;897898static {899try {900MH_f = LOOKUP.findStatic(EMPTY, "f", MT_f);901MH_pred = LOOKUP.findStatic(EMPTY, "pred", MT_pred);902MH_c = LOOKUP.findStatic(EMPTY, "c", MT_c);903} catch (Exception e) {904throw new ExceptionInInitializerError(e);905}906}907}908909static class Fac {910911static int zero(int k) {912return 0;913}914915static int one(int k) {916return 1;917}918919static boolean pred(int i, int acc, int k) {920return i < k;921}922923static int inc(int i, int acc, int k) {924return i + 1;925}926927static int mult(int i, int acc, int k) {928return i * acc;929}930931static void dot(int i, int acc, int k) {932System.out.print('.');933}934935static int fin(int i, int acc, int k) {936return acc;937}938939static final Class<Fac> FAC = Fac.class;940941static final MethodType MT_init = methodType(int.class, int.class);942static final MethodType MT_fn = methodType(int.class, int.class, int.class, int.class);943static final MethodType MT_dot = methodType(void.class, int.class, int.class, int.class);944static final MethodType MT_pred = methodType(boolean.class, int.class, int.class, int.class);945946static final MethodHandle MH_zero;947static final MethodHandle MH_one;948static final MethodHandle MH_pred;949static final MethodHandle MH_inc;950static final MethodHandle MH_mult;951static final MethodHandle MH_dot;952static final MethodHandle MH_fin;953954static final MethodType MT_fac = methodType(int.class, int.class);955956static {957try {958MH_zero = LOOKUP.findStatic(FAC, "zero", MT_init);959MH_one = LOOKUP.findStatic(FAC, "one", MT_init);960MH_pred = LOOKUP.findStatic(FAC, "pred", MT_pred);961MH_inc = LOOKUP.findStatic(FAC, "inc", MT_fn);962MH_mult = LOOKUP.findStatic(FAC, "mult", MT_fn);963MH_dot = LOOKUP.findStatic(FAC, "dot", MT_dot);964MH_fin = LOOKUP.findStatic(FAC, "fin", MT_fn);965} catch (Exception e) {966throw new ExceptionInInitializerError(e);967}968}969970}971972static class Loop {973974static int inc(int i, int k) {975return i + 1;976}977978static boolean pred(int i, int k) {979return i < k;980}981982static int fin(int i, int k) {983return k;984}985986static final Class<Loop> LOOP = Loop.class;987988static final MethodType MT_inc = methodType(int.class, int.class, int.class);989static final MethodType MT_pred = methodType(boolean.class, int.class, int.class);990static final MethodType MT_fin = methodType(int.class, int.class, int.class);991992static final MethodHandle MH_inc;993static final MethodHandle MH_pred;994static final MethodHandle MH_fin;995996static final MethodType MT_loop = methodType(int.class, int.class);997998static {999try {1000MH_inc = LOOKUP.findStatic(LOOP, "inc", MT_inc);1001MH_pred = LOOKUP.findStatic(LOOP, "pred", MT_pred);1002MH_fin = LOOKUP.findStatic(LOOP, "fin", MT_fin);1003} catch (Exception e) {1004throw new ExceptionInInitializerError(e);1005}1006}10071008}10091010static class LoopWithVirtuals {10111012static int one(int k) {1013return 1;1014}10151016int inc(int i, int acc, int k) {1017return i + 1;1018}10191020int mult(int i, int acc, int k) {1021return i * acc;1022}10231024boolean pred(int i, int acc, int k) {1025return i < k;1026}10271028int fin(int i, int acc, int k) {1029return acc;1030}10311032static final Class<LoopWithVirtuals> LOOP_WITH_VIRTUALS = LoopWithVirtuals.class;10331034static final MethodType MT_one = methodType(int.class, int.class);1035static final MethodType MT_inc = methodType(int.class, int.class, int.class, int.class);1036static final MethodType MT_mult = methodType(int.class, int.class, int.class, int.class);1037static final MethodType MT_pred = methodType(boolean.class, int.class, int.class, int.class);1038static final MethodType MT_fin = methodType(int.class, int.class, int.class, int.class);10391040static final MethodHandle MH_one;1041static final MethodHandle MH_inc;1042static final MethodHandle MH_mult;1043static final MethodHandle MH_pred;1044static final MethodHandle MH_fin;10451046static final MethodType MT_loop = methodType(int.class, LOOP_WITH_VIRTUALS, int.class);10471048static {1049try {1050MH_one = LOOKUP.findStatic(LOOP_WITH_VIRTUALS, "one", MT_one);1051MH_inc = LOOKUP.findVirtual(LOOP_WITH_VIRTUALS, "inc", MT_inc);1052MH_mult = LOOKUP.findVirtual(LOOP_WITH_VIRTUALS, "mult", MT_mult);1053MH_pred = LOOKUP.findVirtual(LOOP_WITH_VIRTUALS, "pred", MT_pred);1054MH_fin = LOOKUP.findVirtual(LOOP_WITH_VIRTUALS, "fin", MT_fin);1055} catch (Exception e) {1056throw new ExceptionInInitializerError(e);1057}1058}10591060static MethodHandle permute(MethodHandle h) {1061// The handles representing virtual methods need to be rearranged to match the required order of arguments1062// (loop-local state comes first, then loop arguments). As the receiver comes first in the signature but is1063// a loop argument, it must be moved to the appropriate position in the signature.1064return MethodHandles.permuteArguments(h,1065methodType(h.type().returnType(), int.class, int.class, LOOP_WITH_VIRTUALS, int.class), 2, 0, 1, 3);1066}10671068}10691070static class While {10711072static int zero(int limit) {1073return 0;1074}10751076static boolean pred(int i, int limit) {1077return i < limit;1078}10791080static int step(int i, int limit) {1081return i + 1;1082}10831084static String initString() {1085return "a";1086}10871088static boolean predString(String s) {1089return s.length() != 1;1090}10911092static String stepString(String s) {1093return s + "a";1094}10951096static List<String> zipInitZip(Iterator<String> a, Iterator<String> b) {1097return new ArrayList<>();1098}10991100static boolean zipPred(List<String> zip, Iterator<String> a, Iterator<String> b) {1101return a.hasNext() && b.hasNext();1102}11031104static List<String> zipStep(List<String> zip, Iterator<String> a, Iterator<String> b) {1105zip.add(a.next());1106zip.add(b.next());1107return zip;1108}11091110private int i = 0;11111112void voidInit(int k) {1113// empty1114}11151116void voidBody(int k) {1117++i;1118}11191120boolean voidPred(int k) {1121return i < k;1122}11231124static final Class<While> WHILE = While.class;11251126static final MethodType MT_zero = methodType(int.class, int.class);1127static final MethodType MT_pred = methodType(boolean.class, int.class, int.class);1128static final MethodType MT_fn = methodType(int.class, int.class, int.class);1129static final MethodType MT_initString = methodType(String.class);1130static final MethodType MT_predString = methodType(boolean.class, String.class);1131static final MethodType MT_stepString = methodType(String.class, String.class);1132static final MethodType MT_zipInitZip = methodType(List.class, Iterator.class, Iterator.class);1133static final MethodType MT_zipPred = methodType(boolean.class, List.class, Iterator.class, Iterator.class);1134static final MethodType MT_zipStep = methodType(List.class, List.class, Iterator.class, Iterator.class);1135static final MethodType MT_voidInit = methodType(void.class, int.class);1136static final MethodType MT_voidBody = methodType(void.class, int.class);1137static final MethodType MT_voidPred = methodType(boolean.class, int.class);11381139static final MethodHandle MH_zero;1140static final MethodHandle MH_pred;1141static final MethodHandle MH_step;1142static final MethodHandle MH_initString;1143static final MethodHandle MH_predString;1144static final MethodHandle MH_stepString;1145static final MethodHandle MH_zipInitZip;1146static final MethodHandle MH_zipPred;1147static final MethodHandle MH_zipStep;1148static final MethodHandle MH_voidInit;1149static final MethodHandle MH_voidBody;1150static final MethodHandle MH_voidPred;11511152static final MethodType MT_while = methodType(int.class, int.class);1153static final MethodType MT_string = methodType(String.class);1154static final MethodType MT_zip = methodType(List.class, Iterator.class, Iterator.class);1155static final MethodType MT_void = methodType(void.class, int.class);11561157static {1158try {1159MH_zero = LOOKUP.findStatic(WHILE, "zero", MT_zero);1160MH_pred = LOOKUP.findStatic(WHILE, "pred", MT_pred);1161MH_step = LOOKUP.findStatic(WHILE, "step", MT_fn);1162MH_initString = LOOKUP.findStatic(WHILE, "initString", MT_initString);1163MH_predString = LOOKUP.findStatic(WHILE, "predString", MT_predString);1164MH_stepString = LOOKUP.findStatic(WHILE, "stepString", MT_stepString);1165MH_zipInitZip = LOOKUP.findStatic(WHILE, "zipInitZip", MT_zipInitZip);1166MH_zipPred = LOOKUP.findStatic(WHILE, "zipPred", MT_zipPred);1167MH_zipStep = LOOKUP.findStatic(WHILE, "zipStep", MT_zipStep);1168MH_voidInit = LOOKUP.findVirtual(WHILE, "voidInit", MT_voidInit);1169MH_voidBody = LOOKUP.findVirtual(WHILE, "voidBody", MT_voidBody);1170MH_voidPred = LOOKUP.findVirtual(WHILE, "voidPred", MT_voidPred);1171} catch (Exception e) {1172throw new ExceptionInInitializerError(e);1173}1174}11751176}11771178static class Counted {11791180static String start(String arg) {1181return arg;1182}11831184static String step(String v, int counter) {1185return "na " + v;1186}11871188static void stepUpdateArray(int counter, int[] a) {1189++a[0];1190}11911192static void printHello(int counter) {1193System.out.print("hello");1194}11951196static int addCounter(int x, int counter) {1197return x + counter;1198}11991200static String stateBody(String s, int counter) {1201return "s" + s + counter;1202}12031204static String append(String localState, int counter, String loopArg) {1205if (null == localState) {1206return loopArg + counter;1207}1208return localState + counter;1209}12101211static final Class<Counted> COUNTED = Counted.class;12121213static final MethodType MT_start = methodType(String.class, String.class);1214static final MethodType MT_step = methodType(String.class, String.class, int.class);1215static final MethodType MT_stepUpdateArray = methodType(void.class, int.class, int[].class);1216static final MethodType MT_printHello = methodType(void.class, int.class);1217static final MethodType MT_addCounter = methodType(int.class, int.class, int.class);1218static final MethodType MT_stateBody = methodType(String.class, String.class, int.class);1219static final MethodType MT_append = methodType(String.class, String.class, int.class, String.class);12201221static final MethodHandle MH_13;1222static final MethodHandle MH_m5;1223static final MethodHandle MH_8;1224static final MethodHandle MH_start;1225static final MethodHandle MH_step;1226static final MethodHandle MH_stepUpdateArray;1227static final MethodHandle MH_printHello;1228static final MethodHandle MH_addCounter;1229static final MethodHandle MH_stateBody;1230static final MethodHandle MH_append;12311232static final MethodType MT_counted = methodType(String.class, String.class);1233static final MethodType MT_arrayCounted = methodType(void.class, int[].class);1234static final MethodType MT_countedPrinting = methodType(void.class);1235static final MethodType MT_counterInit = methodType(int.class);1236static final MethodType MT_bodyDeterminesState = methodType(String.class);1237static final MethodType MT_iterationsDefineArgs = methodType(String.class, String.class);12381239static {1240try {1241MH_13 = MethodHandles.constant(int.class, 13);1242MH_m5 = MethodHandles.constant(int.class, -5);1243MH_8 = MethodHandles.constant(int.class, 8);1244MH_start = LOOKUP.findStatic(COUNTED, "start", MT_start);1245MH_step = LOOKUP.findStatic(COUNTED, "step", MT_step);1246MH_stepUpdateArray = LOOKUP.findStatic(COUNTED, "stepUpdateArray", MT_stepUpdateArray);1247MH_printHello = LOOKUP.findStatic(COUNTED, "printHello", MT_printHello);1248MH_addCounter = LOOKUP.findStatic(COUNTED, "addCounter", MT_addCounter);1249MH_stateBody = LOOKUP.findStatic(COUNTED, "stateBody", MT_stateBody);1250MH_append = LOOKUP.findStatic(COUNTED, "append", MT_append);1251} catch (Exception e) {1252throw new ExceptionInInitializerError(e);1253}1254}12551256}12571258static class Iterate {12591260static Iterator<Integer> sumIterator(Integer[] a) {1261return Arrays.asList(a).iterator();1262}12631264static int sumInit(Integer[] a) {1265return 0;1266}12671268static int sumStep(int s, int e, Integer[] a) {1269return s + e;1270}12711272static List<String> reverseInit(List<String> l) {1273return new ArrayList<>();1274}12751276static List<String> reverseStep(List<String> r, String e, List<String> l) {1277r.add(0, e);1278return r;1279}12801281static int lengthInit(List<Double> l) {1282return 0;1283}12841285static int lengthStep(int len, Object o, List<Double> l) {1286return len + 1;1287}12881289static List<String> mapInit(List<String> l) {1290return new ArrayList<>();1291}12921293static List<String> mapStep(List<String> r, String e, List<String> l) {1294r.add(e.toUpperCase());1295return r;1296}12971298static void printStep(String s, List<String> l) {1299System.out.print(s);1300}13011302static void voidInit(List<String> l) {1303// empty1304}13051306static ListIterator<?> iteratorFromList(List<?> l) {1307return l.listIterator();1308}13091310static Iterator<?> iteratorFromIterable(Iterable<?> l) {1311return l.iterator();1312}13131314static final Class<Iterate> ITERATE = Iterate.class;13151316static final MethodType MT_sumIterator = methodType(Iterator.class, Integer[].class);13171318static final MethodType MT_sumInit = methodType(int.class, Integer[].class);1319static final MethodType MT_reverseInit = methodType(List.class, List.class);1320static final MethodType MT_lenghInit = methodType(int.class, List.class);1321static final MethodType MT_mapInit = methodType(List.class, List.class);13221323static final MethodType MT_sumStep = methodType(int.class, int.class, int.class, Integer[].class);1324static final MethodType MT_reverseStep = methodType(List.class, List.class, String.class, List.class);1325static final MethodType MT_lengthStep = methodType(int.class, int.class, Object.class, List.class);1326static final MethodType MT_mapStep = methodType(List.class, List.class, String.class, List.class);1327static final MethodType MT_printStep = methodType(void.class, String.class, List.class);13281329static final MethodType MT_voidInit = methodType(void.class, List.class);13301331static final MethodType MT_iteratorFromList = methodType(ListIterator.class, List.class);1332static final MethodType MT_iteratorFromIterable = methodType(Iterator.class, Iterable.class);13331334static final MethodHandle MH_sumIterator;1335static final MethodHandle MH_sumInit;1336static final MethodHandle MH_sumStep;1337static final MethodHandle MH_printStep;13381339static final MethodHandle MH_reverseInit;1340static final MethodHandle MH_reverseStep;13411342static final MethodHandle MH_lengthInit;1343static final MethodHandle MH_lengthStep;13441345static final MethodHandle MH_mapInit;1346static final MethodHandle MH_mapStep;13471348static final MethodHandle MH_voidInit;13491350static final MethodHandle MH_iteratorFromList;1351static final MethodHandle MH_iteratorFromIterable;13521353static final MethodType MT_sum = methodType(int.class, Integer[].class);1354static final MethodType MT_reverse = methodType(List.class, List.class);1355static final MethodType MT_length = methodType(int.class, List.class);1356static final MethodType MT_map = methodType(List.class, List.class);1357static final MethodType MT_print = methodType(void.class, List.class);13581359static {1360try {1361MH_sumIterator = LOOKUP.findStatic(ITERATE, "sumIterator", MT_sumIterator);1362MH_sumInit = LOOKUP.findStatic(ITERATE, "sumInit", MT_sumInit);1363MH_sumStep = LOOKUP.findStatic(ITERATE, "sumStep", MT_sumStep);1364MH_reverseInit = LOOKUP.findStatic(ITERATE, "reverseInit", MT_reverseInit);1365MH_reverseStep = LOOKUP.findStatic(ITERATE, "reverseStep", MT_reverseStep);1366MH_lengthInit = LOOKUP.findStatic(ITERATE, "lengthInit", MT_lenghInit);1367MH_lengthStep = LOOKUP.findStatic(ITERATE, "lengthStep", MT_lengthStep);1368MH_mapInit = LOOKUP.findStatic(ITERATE, "mapInit", MT_mapInit);1369MH_mapStep = LOOKUP.findStatic(ITERATE, "mapStep", MT_mapStep);1370MH_printStep = LOOKUP.findStatic(ITERATE, "printStep", MT_printStep);1371MH_voidInit = LOOKUP.findStatic(ITERATE, "voidInit", MT_voidInit);1372MH_iteratorFromList = LOOKUP.findStatic(ITERATE, "iteratorFromList", MT_iteratorFromList);1373MH_iteratorFromIterable = LOOKUP.findStatic(ITERATE, "iteratorFromIterable", MT_iteratorFromIterable);1374} catch (Exception e) {1375throw new ExceptionInInitializerError(e);1376}1377}13781379}13801381}138213831384