src/java.base/share/classes/java/lang/invoke/LambdaFormEditor.java
Index Unified diffs Context diffs Sdiffs Patch New Old Previous File Next File jdk Sdiff src/java.base/share/classes/java/lang/invoke

src/java.base/share/classes/java/lang/invoke/LambdaFormEditor.java

Print this page
rev 10607 : imported patch 19.8057042.editor.0
rev 10608 : 8057042: LambdaFormEditor: derive new LFs from a base LF
Reviewed-by: vlivanov, ?
Contributed-by: john.r.rose@oracle.com
rev 10609 : 8057922: Improve LambdaForm sharing by using LambdaFormEditor more extensively
Reviewed-by: vlivanov, ?
Contributed-by: john.r.rose@oracle.com


 427         BoundMethodHandle.SpeciesData newData = newSpeciesData(lambdaForm.parameterType(pos));
 428         Name oldBaseAddress = lambdaForm.parameter(0);  // BMH holding the values
 429         Name newBaseAddress;
 430         NamedFunction getter = newData.getterFunction(oldData.fieldCount());
 431 
 432         if (pos != 0) {
 433             // The newly created LF will run with a different BMH.
 434             // Switch over any pre-existing BMH field references to the new BMH class.
 435             buf.replaceFunctions(oldData.getterFunctions(), newData.getterFunctions(), oldBaseAddress);
 436             newBaseAddress = oldBaseAddress.withConstraint(newData);
 437             buf.renameParameter(0, newBaseAddress);
 438             buf.replaceParameterByNewExpression(pos, new Name(getter, newBaseAddress));
 439         } else {
 440             // cannot bind the MH arg itself, unless oldData is empty
 441             assert(oldData == BoundMethodHandle.SpeciesData.EMPTY);
 442             newBaseAddress = new Name(L_TYPE).withConstraint(newData);
 443             buf.replaceParameterByNewExpression(0, new Name(getter, newBaseAddress));
 444             buf.insertParameter(0, newBaseAddress);
 445         }
 446 
 447         buf.endEdit();
 448         form = buf.lambdaForm();
 449         return putInCache(key, form);
 450     }
























































































































































































































































































































































































 451 }


 427         BoundMethodHandle.SpeciesData newData = newSpeciesData(lambdaForm.parameterType(pos));
 428         Name oldBaseAddress = lambdaForm.parameter(0);  // BMH holding the values
 429         Name newBaseAddress;
 430         NamedFunction getter = newData.getterFunction(oldData.fieldCount());
 431 
 432         if (pos != 0) {
 433             // The newly created LF will run with a different BMH.
 434             // Switch over any pre-existing BMH field references to the new BMH class.
 435             buf.replaceFunctions(oldData.getterFunctions(), newData.getterFunctions(), oldBaseAddress);
 436             newBaseAddress = oldBaseAddress.withConstraint(newData);
 437             buf.renameParameter(0, newBaseAddress);
 438             buf.replaceParameterByNewExpression(pos, new Name(getter, newBaseAddress));
 439         } else {
 440             // cannot bind the MH arg itself, unless oldData is empty
 441             assert(oldData == BoundMethodHandle.SpeciesData.EMPTY);
 442             newBaseAddress = new Name(L_TYPE).withConstraint(newData);
 443             buf.replaceParameterByNewExpression(0, new Name(getter, newBaseAddress));
 444             buf.insertParameter(0, newBaseAddress);
 445         }
 446 
 447         form = buf.endEdit();

 448         return putInCache(key, form);
 449     }
 450 
 451     LambdaForm addArgumentForm(int pos, BasicType type) {
 452         Transform key = Transform.of(Transform.Kind.ADD_ARG, pos, type.ordinal());
 453         LambdaForm form = getInCache(key);
 454         if (form != null) {
 455             assert(form.arity == lambdaForm.arity+1);
 456             assert(form.parameterType(pos) == type);
 457             return form;
 458         }
 459         LambdaFormBuffer buf = buffer();
 460         buf.startEdit();
 461 
 462         buf.insertParameter(pos, new Name(type));
 463 
 464         form = buf.endEdit();
 465         return putInCache(key, form);
 466     }
 467 
 468     LambdaForm dupArgumentForm(int srcPos, int dstPos) {
 469         Transform key = Transform.of(Transform.Kind.DUP_ARG, srcPos, dstPos);
 470         LambdaForm form = getInCache(key);
 471         if (form != null) {
 472             assert(form.arity == lambdaForm.arity-1);
 473             return form;
 474         }
 475         LambdaFormBuffer buf = buffer();
 476         buf.startEdit();
 477 
 478         assert(lambdaForm.parameter(srcPos).constraint == null);
 479         assert(lambdaForm.parameter(dstPos).constraint == null);
 480         buf.replaceParameterByCopy(dstPos, srcPos);
 481 
 482         form = buf.endEdit();
 483         return putInCache(key, form);
 484     }
 485 
 486     LambdaForm spreadArgumentsForm(int pos, Class<?> arrayType, int arrayLength) {
 487         Class<?> elementType = arrayType.getComponentType();
 488         Class<?> erasedArrayType = arrayType;
 489         if (!elementType.isPrimitive())
 490             erasedArrayType = Object[].class;
 491         BasicType bt = basicType(elementType);
 492         int elementTypeKey = bt.ordinal();
 493         if (bt.basicTypeClass() != elementType) {
 494             if (elementType.isPrimitive()) {
 495                 elementTypeKey = TYPE_LIMIT + Wrapper.forPrimitiveType(elementType).ordinal();
 496             }
 497         }
 498         Transform key = Transform.of(Transform.Kind.SPREAD_ARGS, pos, elementTypeKey, arrayLength);
 499         LambdaForm form = getInCache(key);
 500         if (form != null) {
 501             assert(form.arity == lambdaForm.arity - arrayLength + 1);
 502             return form;
 503         }
 504         LambdaFormBuffer buf = buffer();
 505         buf.startEdit();
 506 
 507         assert(pos <= MethodType.MAX_JVM_ARITY);
 508         assert(pos + arrayLength <= lambdaForm.arity);
 509         assert(pos > 0);  // cannot spread the MH arg itself
 510 
 511         Name spreadParam = new Name(L_TYPE);
 512         Name checkSpread = new Name(MethodHandleImpl.Lazy.NF_checkSpreadArgument, spreadParam, arrayLength);
 513 
 514         // insert the new expressions
 515         int exprPos = lambdaForm.arity();
 516         buf.insertExpression(exprPos++, checkSpread);
 517         // adjust the arguments
 518         MethodHandle aload = MethodHandles.arrayElementGetter(erasedArrayType);
 519         for (int i = 0; i < arrayLength; i++) {
 520             Name loadArgument = new Name(aload, spreadParam, i);
 521             buf.insertExpression(exprPos + i, loadArgument);
 522             buf.replaceParameterByCopy(pos + i, exprPos + i);
 523         }
 524         buf.insertParameter(pos, spreadParam);
 525 
 526         form = buf.endEdit();
 527         return putInCache(key, form);
 528     }
 529 
 530     LambdaForm collectArgumentsForm(int pos, MethodType collectorType) {
 531         int collectorArity = collectorType.parameterCount();
 532         boolean dropResult = (collectorType.returnType() == void.class);
 533         if (collectorArity == 1 && !dropResult) {
 534             return filterArgumentForm(pos, basicType(collectorType.parameterType(0)));
 535         }
 536         BasicType[] newTypes = BasicType.basicTypes(collectorType.parameterList());
 537         Transform.Kind kind = (dropResult
 538                 ? Transform.Kind.COLLECT_ARGS_TO_VOID
 539                 : Transform.Kind.COLLECT_ARGS);
 540         if (dropResult && collectorArity == 0)  pos = 1;  // pure side effect
 541         Transform key = Transform.of(kind, pos, collectorArity, BasicType.basicTypesOrd(newTypes));
 542         LambdaForm form = getInCache(key);
 543         if (form != null) {
 544             assert(form.arity == lambdaForm.arity - (dropResult ? 0 : 1) + collectorArity);
 545             return form;
 546         }
 547         form = makeArgumentCombinationForm(pos, collectorType, false, dropResult);
 548         return putInCache(key, form);
 549     }
 550 
 551     LambdaForm collectArgumentArrayForm(int pos, MethodHandle arrayCollector) {
 552         MethodType collectorType = arrayCollector.type();
 553         int collectorArity = collectorType.parameterCount();
 554         assert(arrayCollector.intrinsicName() == Intrinsic.NEW_ARRAY);
 555         Class<?> arrayType = collectorType.returnType();
 556         Class<?> elementType = arrayType.getComponentType();
 557         BasicType argType = basicType(elementType);
 558         int argTypeKey = argType.ordinal();
 559         if (argType.basicTypeClass() != elementType) {
 560             // return null if it requires more metadata (like String[].class)
 561             if (!elementType.isPrimitive())
 562                 return null;
 563             argTypeKey = TYPE_LIMIT + Wrapper.forPrimitiveType(elementType).ordinal();
 564         }
 565         assert(collectorType.parameterList().equals(Collections.nCopies(collectorArity, elementType)));
 566         Transform.Kind kind = Transform.Kind.COLLECT_ARGS_TO_ARRAY;
 567         Transform key = Transform.of(kind, pos, collectorArity, argTypeKey);
 568         LambdaForm form = getInCache(key);
 569         if (form != null) {
 570             assert(form.arity == lambdaForm.arity - 1 + collectorArity);
 571             return form;
 572         }
 573         LambdaFormBuffer buf = buffer();
 574         buf.startEdit();
 575 
 576         assert(pos + 1 <= lambdaForm.arity);
 577         assert(pos > 0);  // cannot filter the MH arg itself
 578 
 579         Name[] newParams = new Name[collectorArity];
 580         for (int i = 0; i < collectorArity; i++) {
 581             newParams[i] = new Name(pos + i, argType);
 582         }
 583         Name callCombiner = new Name(arrayCollector, (Object[]) /*...*/ newParams);
 584 
 585         // insert the new expression
 586         int exprPos = lambdaForm.arity();
 587         buf.insertExpression(exprPos, callCombiner);
 588 
 589         // insert new arguments
 590         int argPos = pos + 1;  // skip result parameter
 591         for (Name newParam : newParams) {
 592             buf.insertParameter(argPos++, newParam);
 593         }
 594         assert(buf.lastIndexOf(callCombiner) == exprPos+newParams.length);
 595         buf.replaceParameterByCopy(pos, exprPos+newParams.length);
 596 
 597         form = buf.endEdit();
 598         return putInCache(key, form);
 599     }
 600 
 601     LambdaForm filterArgumentForm(int pos, BasicType newType) {
 602         Transform key = Transform.of(Transform.Kind.FILTER_ARG, pos, newType.ordinal());
 603         LambdaForm form = getInCache(key);
 604         if (form != null) {
 605             assert(form.arity == lambdaForm.arity);
 606             assert(form.parameterType(pos) == newType);
 607             return form;
 608         }
 609 
 610         BasicType oldType = lambdaForm.parameterType(pos);
 611         MethodType filterType = MethodType.methodType(oldType.basicTypeClass(),
 612                 newType.basicTypeClass());
 613         form = makeArgumentCombinationForm(pos, filterType, false, false);
 614         return putInCache(key, form);
 615     }
 616 
 617     private LambdaForm makeArgumentCombinationForm(int pos,
 618                                                    MethodType combinerType,
 619                                                    boolean keepArguments, boolean dropResult) {
 620         LambdaFormBuffer buf = buffer();
 621         buf.startEdit();
 622         int combinerArity = combinerType.parameterCount();
 623         int resultArity = (dropResult ? 0 : 1);
 624 
 625         assert(pos <= MethodType.MAX_JVM_ARITY);
 626         assert(pos + resultArity + (keepArguments ? combinerArity : 0) <= lambdaForm.arity);
 627         assert(pos > 0);  // cannot filter the MH arg itself
 628         assert(combinerType == combinerType.basicType());
 629         assert(combinerType.returnType() != void.class || dropResult);
 630 
 631         BoundMethodHandle.SpeciesData oldData = oldSpeciesData();
 632         BoundMethodHandle.SpeciesData newData = newSpeciesData(L_TYPE);
 633 
 634         // The newly created LF will run with a different BMH.
 635         // Switch over any pre-existing BMH field references to the new BMH class.
 636         Name oldBaseAddress = lambdaForm.parameter(0);  // BMH holding the values
 637         buf.replaceFunctions(oldData.getterFunctions(), newData.getterFunctions(), oldBaseAddress);
 638         Name newBaseAddress = oldBaseAddress.withConstraint(newData);
 639         buf.renameParameter(0, newBaseAddress);
 640 
 641         Name getCombiner = new Name(newData.getterFunction(oldData.fieldCount()), newBaseAddress);
 642         Object[] combinerArgs = new Object[1 + combinerArity];
 643         combinerArgs[0] = getCombiner;
 644         Name[] newParams;
 645         if (keepArguments) {
 646             newParams = new Name[0];
 647             System.arraycopy(lambdaForm.names, pos + resultArity,
 648                              combinerArgs, 1, combinerArity);
 649         } else {
 650             newParams = new Name[combinerArity];
 651             BasicType[] newTypes = basicTypes(combinerType.parameterList());
 652             for (int i = 0; i < newTypes.length; i++) {
 653                 newParams[i] = new Name(pos + i, newTypes[i]);
 654             }
 655             System.arraycopy(newParams, 0,
 656                              combinerArgs, 1, combinerArity);
 657         }
 658         Name callCombiner = new Name(combinerType, combinerArgs);
 659 
 660         // insert the two new expressions
 661         int exprPos = lambdaForm.arity();
 662         buf.insertExpression(exprPos+0, getCombiner);
 663         buf.insertExpression(exprPos+1, callCombiner);
 664 
 665         // insert new arguments, if needed
 666         int argPos = pos + resultArity;  // skip result parameter
 667         for (Name newParam : newParams) {
 668             buf.insertParameter(argPos++, newParam);
 669         }
 670         assert(buf.lastIndexOf(callCombiner) == exprPos+1+newParams.length);
 671         if (!dropResult) {
 672             buf.replaceParameterByCopy(pos, exprPos+1+newParams.length);
 673         }
 674 
 675         return buf.endEdit();
 676     }
 677 
 678     LambdaForm filterReturnForm(BasicType newType, boolean constantZero) {
 679         Transform.Kind kind = (constantZero ? Transform.Kind.FILTER_RETURN_TO_ZERO : Transform.Kind.FILTER_RETURN);
 680         Transform key = Transform.of(kind, newType.ordinal());
 681         LambdaForm form = getInCache(key);
 682         if (form != null) {
 683             assert(form.arity == lambdaForm.arity);
 684             assert(form.returnType() == newType);
 685             return form;
 686         }
 687         LambdaFormBuffer buf = buffer();
 688         buf.startEdit();
 689 
 690         int insPos = lambdaForm.names.length;
 691         Name callFilter;
 692         if (constantZero) {
 693             // Synthesize a constant zero value for the given type.
 694             if (newType == V_TYPE)
 695                 callFilter = null;
 696             else
 697                 callFilter = new Name(constantZero(newType));
 698         } else {
 699             BoundMethodHandle.SpeciesData oldData = oldSpeciesData();
 700             BoundMethodHandle.SpeciesData newData = newSpeciesData(L_TYPE);
 701 
 702             // The newly created LF will run with a different BMH.
 703             // Switch over any pre-existing BMH field references to the new BMH class.
 704             Name oldBaseAddress = lambdaForm.parameter(0);  // BMH holding the values
 705             buf.replaceFunctions(oldData.getterFunctions(), newData.getterFunctions(), oldBaseAddress);
 706             Name newBaseAddress = oldBaseAddress.withConstraint(newData);
 707             buf.renameParameter(0, newBaseAddress);
 708 
 709             Name getFilter = new Name(newData.getterFunction(oldData.fieldCount()), newBaseAddress);
 710             buf.insertExpression(insPos++, getFilter);
 711             BasicType oldType = lambdaForm.returnType();
 712             if (oldType == V_TYPE) {
 713                 MethodType filterType = MethodType.methodType(newType.basicTypeClass());
 714                 callFilter = new Name(filterType, getFilter);
 715             } else {
 716                 MethodType filterType = MethodType.methodType(newType.basicTypeClass(), oldType.basicTypeClass());
 717                 callFilter = new Name(filterType, getFilter, lambdaForm.names[lambdaForm.result]);
 718             }
 719         }
 720 
 721         if (callFilter != null)
 722             buf.insertExpression(insPos++, callFilter);
 723         buf.setResult(callFilter);
 724 
 725         form = buf.endEdit();
 726         return putInCache(key, form);
 727     }
 728 
 729     LambdaForm foldArgumentsForm(int foldPos, boolean dropResult, MethodType combinerType) {
 730         int combinerArity = combinerType.parameterCount();
 731         Transform.Kind kind = (dropResult ? Transform.Kind.FOLD_ARGS_TO_VOID : Transform.Kind.FOLD_ARGS);
 732         Transform key = Transform.of(kind, foldPos, combinerArity);
 733         LambdaForm form = getInCache(key);
 734         if (form != null) {
 735             assert(form.arity == lambdaForm.arity - (kind == Transform.Kind.FOLD_ARGS ? 1 : 0));
 736             return form;
 737         }
 738         form = makeArgumentCombinationForm(foldPos, combinerType, true, dropResult);
 739         return putInCache(key, form);
 740     }
 741 
 742     LambdaForm permuteArgumentsForm(int skip, int[] reorder) {
 743         assert(skip == 1);  // skip only the leading MH argument, names[0]
 744         int length = lambdaForm.names.length;
 745         int outArgs = reorder.length;
 746         int inTypes = 0;
 747         boolean nullPerm = true;
 748         for (int i = 0; i < reorder.length; i++) {
 749             int inArg = reorder[i];
 750             if (inArg != i)  nullPerm = false;
 751             inTypes = Math.max(inTypes, inArg+1);
 752         }
 753         assert(skip + reorder.length == lambdaForm.arity);
 754         if (nullPerm)  return lambdaForm;  // do not bother to cache
 755         Transform key = Transform.of(Transform.Kind.PERMUTE_ARGS, reorder);
 756         LambdaForm form = getInCache(key);
 757         if (form != null) {
 758             assert(form.arity == skip+inTypes) : form;
 759             return form;
 760         }
 761 
 762         BasicType[] types = new BasicType[inTypes];
 763         for (int i = 0; i < outArgs; i++) {
 764             int inArg = reorder[i];
 765             types[inArg] = lambdaForm.names[skip + i].type;
 766         }
 767         assert (skip + outArgs == lambdaForm.arity);
 768         assert (permutedTypesMatch(reorder, types, lambdaForm.names, skip));
 769         int pos = 0;
 770         while (pos < outArgs && reorder[pos] == pos) {
 771             pos += 1;
 772         }
 773         Name[] names2 = new Name[length - outArgs + inTypes];
 774         System.arraycopy(lambdaForm.names, 0, names2, 0, skip + pos);
 775         int bodyLength = length - lambdaForm.arity;
 776         System.arraycopy(lambdaForm.names, skip + outArgs, names2, skip + inTypes, bodyLength);
 777         int arity2 = names2.length - bodyLength;
 778         int result2 = lambdaForm.result;
 779         if (result2 >= 0) {
 780             if (result2 < skip + outArgs) {
 781                 result2 = reorder[result2 - skip];
 782             } else {
 783                 result2 = result2 - outArgs + inTypes;
 784             }
 785         }
 786         for (int j = pos; j < outArgs; j++) {
 787             Name n = lambdaForm.names[skip + j];
 788             int i = reorder[j];
 789             Name n2 = names2[skip + i];
 790             if (n2 == null) {
 791                 names2[skip + i] = n2 = new Name(types[i]);
 792             } else {
 793                 assert (n2.type == types[i]);
 794             }
 795             for (int k = arity2; k < names2.length; k++) {
 796                 names2[k] = names2[k].replaceName(n, n2);
 797             }
 798         }
 799         for (int i = skip + pos; i < arity2; i++) {
 800             if (names2[i] == null) {
 801                 names2[i] = argument(i, types[i - skip]);
 802             }
 803         }
 804         for (int j = lambdaForm.arity; j < lambdaForm.names.length; j++) {
 805             int i = j - lambdaForm.arity + arity2;
 806             Name n = lambdaForm.names[j];
 807             Name n2 = names2[i];
 808             if (n != n2) {
 809                 for (int k = i + 1; k < names2.length; k++) {
 810                     names2[k] = names2[k].replaceName(n, n2);
 811                 }
 812             }
 813         }
 814 
 815         form = new LambdaForm(lambdaForm.debugName, arity2, names2, result2);
 816         return putInCache(key, form);
 817     }
 818 
 819     static boolean permutedTypesMatch(int[] reorder, BasicType[] types, Name[] names, int skip) {
 820         for (int i = 0; i < reorder.length; i++) {
 821             assert (names[skip + i].isParam());
 822             assert (names[skip + i].type == types[reorder[i]]);
 823         }
 824         return true;
 825     }
 826 }
src/java.base/share/classes/java/lang/invoke/LambdaFormEditor.java
Index Unified diffs Context diffs Sdiffs Patch New Old Previous File Next File