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

Print this page
rev 17771 : 8184777: species logic for BoundMethodHandle doesn't scale, needs refactor


 363                     for (Transform k : ta) {
 364                         m.put(k, k);
 365                     }
 366                     lambdaForm.transformCache = m;
 367                     // The second iteration will update for this query, concurrently.
 368                     continue;
 369                 }
 370                 int idx = (stale >= 0) ? stale : i;
 371                 ta[idx] = key;
 372                 return form;
 373             }
 374         }
 375     }
 376 
 377     private LambdaFormBuffer buffer() {
 378         return new LambdaFormBuffer(lambdaForm);
 379     }
 380 
 381     /// Editing methods for method handles.  These need to have fast paths.
 382 
 383     private BoundMethodHandle.SpeciesData oldSpeciesData() {
 384         return BoundMethodHandle.speciesData(lambdaForm);
 385     }
 386     private BoundMethodHandle.SpeciesData newSpeciesData(BasicType type) {
 387         return oldSpeciesData().extendWith(type);
 388     }
 389 
 390     BoundMethodHandle bindArgumentL(BoundMethodHandle mh, int pos, Object value) {
 391         assert(mh.speciesData() == oldSpeciesData());
 392         BasicType bt = L_TYPE;
 393         MethodType type2 = bindArgumentType(mh, pos, bt);
 394         LambdaForm form2 = bindArgumentForm(1+pos);
 395         return mh.copyWithExtendL(type2, form2, value);
 396     }
 397     BoundMethodHandle bindArgumentI(BoundMethodHandle mh, int pos, int value) {
 398         assert(mh.speciesData() == oldSpeciesData());
 399         BasicType bt = I_TYPE;
 400         MethodType type2 = bindArgumentType(mh, pos, bt);
 401         LambdaForm form2 = bindArgumentForm(1+pos);
 402         return mh.copyWithExtendI(type2, form2, value);
 403     }
 404 
 405     BoundMethodHandle bindArgumentJ(BoundMethodHandle mh, int pos, long value) {
 406         assert(mh.speciesData() == oldSpeciesData());
 407         BasicType bt = J_TYPE;


 429     private MethodType bindArgumentType(BoundMethodHandle mh, int pos, BasicType bt) {
 430         assert(mh.form.uncustomize() == lambdaForm);
 431         assert(mh.form.names[1+pos].type == bt);
 432         assert(BasicType.basicType(mh.type().parameterType(pos)) == bt);
 433         return mh.type().dropParameterTypes(pos, pos+1);
 434     }
 435 
 436     /// Editing methods for lambda forms.
 437     // Each editing method can (potentially) cache the edited LF so that it can be reused later.
 438 
 439     LambdaForm bindArgumentForm(int pos) {
 440         Transform key = Transform.of(Transform.BIND_ARG, pos);
 441         LambdaForm form = getInCache(key);
 442         if (form != null) {
 443             assert(form.parameterConstraint(0) == newSpeciesData(lambdaForm.parameterType(pos)));
 444             return form;
 445         }
 446         LambdaFormBuffer buf = buffer();
 447         buf.startEdit();
 448 
 449         BoundMethodHandle.SpeciesData oldData = oldSpeciesData();
 450         BoundMethodHandle.SpeciesData newData = newSpeciesData(lambdaForm.parameterType(pos));
 451         Name oldBaseAddress = lambdaForm.parameter(0);  // BMH holding the values
 452         Name newBaseAddress;
 453         NamedFunction getter = newData.getterFunction(oldData.fieldCount());
 454 
 455         if (pos != 0) {
 456             // The newly created LF will run with a different BMH.
 457             // Switch over any pre-existing BMH field references to the new BMH class.
 458             buf.replaceFunctions(oldData.getterFunctions(), newData.getterFunctions(), oldBaseAddress);
 459             newBaseAddress = oldBaseAddress.withConstraint(newData);
 460             buf.renameParameter(0, newBaseAddress);
 461             buf.replaceParameterByNewExpression(pos, new Name(getter, newBaseAddress));
 462         } else {
 463             // cannot bind the MH arg itself, unless oldData is empty
 464             assert(oldData == BoundMethodHandle.SpeciesData.EMPTY);
 465             newBaseAddress = new Name(L_TYPE).withConstraint(newData);
 466             buf.replaceParameterByNewExpression(0, new Name(getter, newBaseAddress));
 467             buf.insertParameter(0, newBaseAddress);
 468         }
 469 
 470         form = buf.endEdit();
 471         return putInCache(key, form);
 472     }
 473 
 474     LambdaForm addArgumentForm(int pos, BasicType type) {
 475         Transform key = Transform.of(Transform.ADD_ARG, pos, type.ordinal());
 476         LambdaForm form = getInCache(key);
 477         if (form != null) {
 478             assert(form.arity == lambdaForm.arity+1);
 479             assert(form.parameterType(pos) == type);
 480             return form;
 481         }
 482         LambdaFormBuffer buf = buffer();
 483         buf.startEdit();
 484 


 636         MethodType filterType = MethodType.methodType(oldType.basicTypeClass(),
 637                 newType.basicTypeClass());
 638         form = makeArgumentCombinationForm(pos, filterType, false, false);
 639         return putInCache(key, form);
 640     }
 641 
 642     private LambdaForm makeArgumentCombinationForm(int pos,
 643                                                    MethodType combinerType,
 644                                                    boolean keepArguments, boolean dropResult) {
 645         LambdaFormBuffer buf = buffer();
 646         buf.startEdit();
 647         int combinerArity = combinerType.parameterCount();
 648         int resultArity = (dropResult ? 0 : 1);
 649 
 650         assert(pos <= MethodType.MAX_JVM_ARITY);
 651         assert(pos + resultArity + (keepArguments ? combinerArity : 0) <= lambdaForm.arity);
 652         assert(pos > 0);  // cannot filter the MH arg itself
 653         assert(combinerType == combinerType.basicType());
 654         assert(combinerType.returnType() != void.class || dropResult);
 655 
 656         BoundMethodHandle.SpeciesData oldData = oldSpeciesData();
 657         BoundMethodHandle.SpeciesData newData = newSpeciesData(L_TYPE);
 658 
 659         // The newly created LF will run with a different BMH.
 660         // Switch over any pre-existing BMH field references to the new BMH class.
 661         Name oldBaseAddress = lambdaForm.parameter(0);  // BMH holding the values
 662         buf.replaceFunctions(oldData.getterFunctions(), newData.getterFunctions(), oldBaseAddress);
 663         Name newBaseAddress = oldBaseAddress.withConstraint(newData);
 664         buf.renameParameter(0, newBaseAddress);
 665 
 666         Name getCombiner = new Name(newData.getterFunction(oldData.fieldCount()), newBaseAddress);
 667         Object[] combinerArgs = new Object[1 + combinerArity];
 668         combinerArgs[0] = getCombiner;
 669         Name[] newParams;
 670         if (keepArguments) {
 671             newParams = new Name[0];
 672             System.arraycopy(lambdaForm.names, pos + resultArity,
 673                              combinerArgs, 1, combinerArity);
 674         } else {
 675             newParams = new Name[combinerArity];
 676             for (int i = 0; i < newParams.length; i++) {
 677                 newParams[i] = new Name(pos + i, basicType(combinerType.parameterType(i)));


 699         return buf.endEdit();
 700     }
 701 
 702     private LambdaForm makeArgumentCombinationForm(int pos,
 703                                                    MethodType combinerType,
 704                                                    int[] argPositions,
 705                                                    boolean keepArguments,
 706                                                    boolean dropResult) {
 707         LambdaFormBuffer buf = buffer();
 708         buf.startEdit();
 709         int combinerArity = combinerType.parameterCount();
 710         assert(combinerArity == argPositions.length);
 711 
 712         int resultArity = (dropResult ? 0 : 1);
 713 
 714         assert(pos <= lambdaForm.arity);
 715         assert(pos > 0);  // cannot filter the MH arg itself
 716         assert(combinerType == combinerType.basicType());
 717         assert(combinerType.returnType() != void.class || dropResult);
 718 
 719         BoundMethodHandle.SpeciesData oldData = oldSpeciesData();
 720         BoundMethodHandle.SpeciesData newData = newSpeciesData(L_TYPE);
 721 
 722         // The newly created LF will run with a different BMH.
 723         // Switch over any pre-existing BMH field references to the new BMH class.
 724         Name oldBaseAddress = lambdaForm.parameter(0);  // BMH holding the values
 725         buf.replaceFunctions(oldData.getterFunctions(), newData.getterFunctions(), oldBaseAddress);
 726         Name newBaseAddress = oldBaseAddress.withConstraint(newData);
 727         buf.renameParameter(0, newBaseAddress);
 728 
 729         Name getCombiner = new Name(newData.getterFunction(oldData.fieldCount()), newBaseAddress);
 730         Object[] combinerArgs = new Object[1 + combinerArity];
 731         combinerArgs[0] = getCombiner;
 732         Name[] newParams;
 733         if (keepArguments) {
 734             newParams = new Name[0];
 735             for (int i = 0; i < combinerArity; i++) {
 736                 combinerArgs[i + 1] = lambdaForm.parameter(1 + argPositions[i]);
 737                 assert (basicType(combinerType.parameterType(i)) == lambdaForm.parameterType(1 + argPositions[i]));
 738             }
 739         } else {
 740             newParams = new Name[combinerArity];


 769         byte kind = (constantZero ? Transform.FILTER_RETURN_TO_ZERO : Transform.FILTER_RETURN);
 770         Transform key = Transform.of(kind, newType.ordinal());
 771         LambdaForm form = getInCache(key);
 772         if (form != null) {
 773             assert(form.arity == lambdaForm.arity);
 774             assert(form.returnType() == newType);
 775             return form;
 776         }
 777         LambdaFormBuffer buf = buffer();
 778         buf.startEdit();
 779 
 780         int insPos = lambdaForm.names.length;
 781         Name callFilter;
 782         if (constantZero) {
 783             // Synthesize a constant zero value for the given type.
 784             if (newType == V_TYPE)
 785                 callFilter = null;
 786             else
 787                 callFilter = new Name(constantZero(newType));
 788         } else {
 789             BoundMethodHandle.SpeciesData oldData = oldSpeciesData();
 790             BoundMethodHandle.SpeciesData newData = newSpeciesData(L_TYPE);
 791 
 792             // The newly created LF will run with a different BMH.
 793             // Switch over any pre-existing BMH field references to the new BMH class.
 794             Name oldBaseAddress = lambdaForm.parameter(0);  // BMH holding the values
 795             buf.replaceFunctions(oldData.getterFunctions(), newData.getterFunctions(), oldBaseAddress);
 796             Name newBaseAddress = oldBaseAddress.withConstraint(newData);
 797             buf.renameParameter(0, newBaseAddress);
 798 
 799             Name getFilter = new Name(newData.getterFunction(oldData.fieldCount()), newBaseAddress);
 800             buf.insertExpression(insPos++, getFilter);
 801             BasicType oldType = lambdaForm.returnType();
 802             if (oldType == V_TYPE) {
 803                 MethodType filterType = MethodType.methodType(newType.basicTypeClass());
 804                 callFilter = new Name(filterType, getFilter);
 805             } else {
 806                 MethodType filterType = MethodType.methodType(newType.basicTypeClass(), oldType.basicTypeClass());
 807                 callFilter = new Name(filterType, getFilter, lambdaForm.names[lambdaForm.result]);
 808             }
 809         }
 810 




 363                     for (Transform k : ta) {
 364                         m.put(k, k);
 365                     }
 366                     lambdaForm.transformCache = m;
 367                     // The second iteration will update for this query, concurrently.
 368                     continue;
 369                 }
 370                 int idx = (stale >= 0) ? stale : i;
 371                 ta[idx] = key;
 372                 return form;
 373             }
 374         }
 375     }
 376 
 377     private LambdaFormBuffer buffer() {
 378         return new LambdaFormBuffer(lambdaForm);
 379     }
 380 
 381     /// Editing methods for method handles.  These need to have fast paths.
 382 
 383     private BoundMethodHandle.BMHSpecies oldSpeciesData() {
 384         return BoundMethodHandle.formSpeciesData(lambdaForm);
 385     }
 386     private BoundMethodHandle.BMHSpecies newSpeciesData(BasicType type) {
 387         return oldSpeciesData().extendWith((byte) type.ordinal());
 388     }
 389 
 390     BoundMethodHandle bindArgumentL(BoundMethodHandle mh, int pos, Object value) {
 391         assert(mh.speciesData() == oldSpeciesData());
 392         BasicType bt = L_TYPE;
 393         MethodType type2 = bindArgumentType(mh, pos, bt);
 394         LambdaForm form2 = bindArgumentForm(1+pos);
 395         return mh.copyWithExtendL(type2, form2, value);
 396     }
 397     BoundMethodHandle bindArgumentI(BoundMethodHandle mh, int pos, int value) {
 398         assert(mh.speciesData() == oldSpeciesData());
 399         BasicType bt = I_TYPE;
 400         MethodType type2 = bindArgumentType(mh, pos, bt);
 401         LambdaForm form2 = bindArgumentForm(1+pos);
 402         return mh.copyWithExtendI(type2, form2, value);
 403     }
 404 
 405     BoundMethodHandle bindArgumentJ(BoundMethodHandle mh, int pos, long value) {
 406         assert(mh.speciesData() == oldSpeciesData());
 407         BasicType bt = J_TYPE;


 429     private MethodType bindArgumentType(BoundMethodHandle mh, int pos, BasicType bt) {
 430         assert(mh.form.uncustomize() == lambdaForm);
 431         assert(mh.form.names[1+pos].type == bt);
 432         assert(BasicType.basicType(mh.type().parameterType(pos)) == bt);
 433         return mh.type().dropParameterTypes(pos, pos+1);
 434     }
 435 
 436     /// Editing methods for lambda forms.
 437     // Each editing method can (potentially) cache the edited LF so that it can be reused later.
 438 
 439     LambdaForm bindArgumentForm(int pos) {
 440         Transform key = Transform.of(Transform.BIND_ARG, pos);
 441         LambdaForm form = getInCache(key);
 442         if (form != null) {
 443             assert(form.parameterConstraint(0) == newSpeciesData(lambdaForm.parameterType(pos)));
 444             return form;
 445         }
 446         LambdaFormBuffer buf = buffer();
 447         buf.startEdit();
 448 
 449         BoundMethodHandle.BMHSpecies oldData = oldSpeciesData();
 450         BoundMethodHandle.BMHSpecies newData = newSpeciesData(lambdaForm.parameterType(pos));
 451         Name oldBaseAddress = lambdaForm.parameter(0);  // BMH holding the values
 452         Name newBaseAddress;
 453         NamedFunction getter = newData.getterFunction(oldData.fieldCount());
 454 
 455         if (pos != 0) {
 456             // The newly created LF will run with a different BMH.
 457             // Switch over any pre-existing BMH field references to the new BMH class.
 458             buf.replaceFunctions(oldData.getterFunctions(), newData.getterFunctions(), oldBaseAddress);
 459             newBaseAddress = oldBaseAddress.withConstraint(newData);
 460             buf.renameParameter(0, newBaseAddress);
 461             buf.replaceParameterByNewExpression(pos, new Name(getter, newBaseAddress));
 462         } else {
 463             // cannot bind the MH arg itself, unless oldData is empty
 464             assert(oldData == BoundMethodHandle.SPECIALIZER.topSpecies());
 465             newBaseAddress = new Name(L_TYPE).withConstraint(newData);
 466             buf.replaceParameterByNewExpression(0, new Name(getter, newBaseAddress));
 467             buf.insertParameter(0, newBaseAddress);
 468         }
 469 
 470         form = buf.endEdit();
 471         return putInCache(key, form);
 472     }
 473 
 474     LambdaForm addArgumentForm(int pos, BasicType type) {
 475         Transform key = Transform.of(Transform.ADD_ARG, pos, type.ordinal());
 476         LambdaForm form = getInCache(key);
 477         if (form != null) {
 478             assert(form.arity == lambdaForm.arity+1);
 479             assert(form.parameterType(pos) == type);
 480             return form;
 481         }
 482         LambdaFormBuffer buf = buffer();
 483         buf.startEdit();
 484 


 636         MethodType filterType = MethodType.methodType(oldType.basicTypeClass(),
 637                 newType.basicTypeClass());
 638         form = makeArgumentCombinationForm(pos, filterType, false, false);
 639         return putInCache(key, form);
 640     }
 641 
 642     private LambdaForm makeArgumentCombinationForm(int pos,
 643                                                    MethodType combinerType,
 644                                                    boolean keepArguments, boolean dropResult) {
 645         LambdaFormBuffer buf = buffer();
 646         buf.startEdit();
 647         int combinerArity = combinerType.parameterCount();
 648         int resultArity = (dropResult ? 0 : 1);
 649 
 650         assert(pos <= MethodType.MAX_JVM_ARITY);
 651         assert(pos + resultArity + (keepArguments ? combinerArity : 0) <= lambdaForm.arity);
 652         assert(pos > 0);  // cannot filter the MH arg itself
 653         assert(combinerType == combinerType.basicType());
 654         assert(combinerType.returnType() != void.class || dropResult);
 655 
 656         BoundMethodHandle.BMHSpecies oldData = oldSpeciesData();
 657         BoundMethodHandle.BMHSpecies newData = newSpeciesData(L_TYPE);
 658 
 659         // The newly created LF will run with a different BMH.
 660         // Switch over any pre-existing BMH field references to the new BMH class.
 661         Name oldBaseAddress = lambdaForm.parameter(0);  // BMH holding the values
 662         buf.replaceFunctions(oldData.getterFunctions(), newData.getterFunctions(), oldBaseAddress);
 663         Name newBaseAddress = oldBaseAddress.withConstraint(newData);
 664         buf.renameParameter(0, newBaseAddress);
 665 
 666         Name getCombiner = new Name(newData.getterFunction(oldData.fieldCount()), newBaseAddress);
 667         Object[] combinerArgs = new Object[1 + combinerArity];
 668         combinerArgs[0] = getCombiner;
 669         Name[] newParams;
 670         if (keepArguments) {
 671             newParams = new Name[0];
 672             System.arraycopy(lambdaForm.names, pos + resultArity,
 673                              combinerArgs, 1, combinerArity);
 674         } else {
 675             newParams = new Name[combinerArity];
 676             for (int i = 0; i < newParams.length; i++) {
 677                 newParams[i] = new Name(pos + i, basicType(combinerType.parameterType(i)));


 699         return buf.endEdit();
 700     }
 701 
 702     private LambdaForm makeArgumentCombinationForm(int pos,
 703                                                    MethodType combinerType,
 704                                                    int[] argPositions,
 705                                                    boolean keepArguments,
 706                                                    boolean dropResult) {
 707         LambdaFormBuffer buf = buffer();
 708         buf.startEdit();
 709         int combinerArity = combinerType.parameterCount();
 710         assert(combinerArity == argPositions.length);
 711 
 712         int resultArity = (dropResult ? 0 : 1);
 713 
 714         assert(pos <= lambdaForm.arity);
 715         assert(pos > 0);  // cannot filter the MH arg itself
 716         assert(combinerType == combinerType.basicType());
 717         assert(combinerType.returnType() != void.class || dropResult);
 718 
 719         BoundMethodHandle.BMHSpecies oldData = oldSpeciesData();
 720         BoundMethodHandle.BMHSpecies newData = newSpeciesData(L_TYPE);
 721 
 722         // The newly created LF will run with a different BMH.
 723         // Switch over any pre-existing BMH field references to the new BMH class.
 724         Name oldBaseAddress = lambdaForm.parameter(0);  // BMH holding the values
 725         buf.replaceFunctions(oldData.getterFunctions(), newData.getterFunctions(), oldBaseAddress);
 726         Name newBaseAddress = oldBaseAddress.withConstraint(newData);
 727         buf.renameParameter(0, newBaseAddress);
 728 
 729         Name getCombiner = new Name(newData.getterFunction(oldData.fieldCount()), newBaseAddress);
 730         Object[] combinerArgs = new Object[1 + combinerArity];
 731         combinerArgs[0] = getCombiner;
 732         Name[] newParams;
 733         if (keepArguments) {
 734             newParams = new Name[0];
 735             for (int i = 0; i < combinerArity; i++) {
 736                 combinerArgs[i + 1] = lambdaForm.parameter(1 + argPositions[i]);
 737                 assert (basicType(combinerType.parameterType(i)) == lambdaForm.parameterType(1 + argPositions[i]));
 738             }
 739         } else {
 740             newParams = new Name[combinerArity];


 769         byte kind = (constantZero ? Transform.FILTER_RETURN_TO_ZERO : Transform.FILTER_RETURN);
 770         Transform key = Transform.of(kind, newType.ordinal());
 771         LambdaForm form = getInCache(key);
 772         if (form != null) {
 773             assert(form.arity == lambdaForm.arity);
 774             assert(form.returnType() == newType);
 775             return form;
 776         }
 777         LambdaFormBuffer buf = buffer();
 778         buf.startEdit();
 779 
 780         int insPos = lambdaForm.names.length;
 781         Name callFilter;
 782         if (constantZero) {
 783             // Synthesize a constant zero value for the given type.
 784             if (newType == V_TYPE)
 785                 callFilter = null;
 786             else
 787                 callFilter = new Name(constantZero(newType));
 788         } else {
 789             BoundMethodHandle.BMHSpecies oldData = oldSpeciesData();
 790             BoundMethodHandle.BMHSpecies newData = newSpeciesData(L_TYPE);
 791 
 792             // The newly created LF will run with a different BMH.
 793             // Switch over any pre-existing BMH field references to the new BMH class.
 794             Name oldBaseAddress = lambdaForm.parameter(0);  // BMH holding the values
 795             buf.replaceFunctions(oldData.getterFunctions(), newData.getterFunctions(), oldBaseAddress);
 796             Name newBaseAddress = oldBaseAddress.withConstraint(newData);
 797             buf.renameParameter(0, newBaseAddress);
 798 
 799             Name getFilter = new Name(newData.getterFunction(oldData.fieldCount()), newBaseAddress);
 800             buf.insertExpression(insPos++, getFilter);
 801             BasicType oldType = lambdaForm.returnType();
 802             if (oldType == V_TYPE) {
 803                 MethodType filterType = MethodType.methodType(newType.basicTypeClass());
 804                 callFilter = new Name(filterType, getFilter);
 805             } else {
 806                 MethodType filterType = MethodType.methodType(newType.basicTypeClass(), oldType.basicTypeClass());
 807                 callFilter = new Name(filterType, getFilter, lambdaForm.names[lambdaForm.result]);
 808             }
 809         }
 810