3939import graphql .schema .GraphQLCodeRegistry ;
4040import graphql .schema .GraphQLEnumType ;
4141import graphql .schema .GraphQLFieldDefinition ;
42+ import graphql .schema .GraphQLList ;
4243import graphql .schema .GraphQLObjectType ;
44+ import graphql .schema .GraphQLOutputType ;
4345import graphql .schema .GraphQLScalarType ;
4446import graphql .schema .GraphQLSchema ;
4547import graphql .schema .GraphQLType ;
@@ -489,7 +491,7 @@ protected Object resolveFieldWithInfo(ExecutionContext executionContext, Executi
489491 if (!executionContext .isNoOpDataLoaderDispatch ()) {
490492 executionContext .getDataLoaderDispatcherStrategy ().startComplete (parameters );
491493 }
492- FieldValueInfo completeFieldResult = completeField (fieldDef , executionContext , parameters , fetchedValue );
494+ FieldValueInfo completeFieldResult = completeField (fieldDef , parentType , executionContext , parameters , fetchedValue );
493495 if (!executionContext .isNoOpDataLoaderDispatch ()) {
494496 executionContext .getDataLoaderDispatcherStrategy ().stopComplete (parameters );
495497 }
@@ -503,7 +505,7 @@ protected Object resolveFieldWithInfo(ExecutionContext executionContext, Executi
503505 return result ;
504506 } else {
505507 try {
506- FieldValueInfo fieldValueInfo = completeField (fieldDef , executionContext , parameters , fetchedValueObj );
508+ FieldValueInfo fieldValueInfo = completeField (fieldDef , parentType , executionContext , parameters , fetchedValueObj );
507509 if (fieldCtx != null ) {
508510 fieldCtx .onDispatched ();
509511 fieldCtx .onCompleted (FetchedValue .getFetchedValue (fetchedValueObj ), null );
@@ -791,11 +793,10 @@ protected FieldValueInfo completeField(ExecutionContext executionContext,
791793 Field field = parameters .getField ().getSingleField ();
792794 GraphQLObjectType parentType = parameters .getExecutionStepInfo ().getUnwrappedNonNullTypeAs ();
793795 GraphQLFieldDefinition fieldDef = getFieldDef (executionContext .getGraphQLSchema (), parentType , field );
794- return completeField (fieldDef , executionContext , parameters , fetchedValue );
796+ return completeField (fieldDef , parentType , executionContext , parameters , fetchedValue );
795797 }
796798
797- private FieldValueInfo completeField (GraphQLFieldDefinition fieldDef , ExecutionContext executionContext , ExecutionStrategyParameters parameters , Object fetchedValue ) {
798- GraphQLObjectType parentType = parameters .getExecutionStepInfo ().getUnwrappedNonNullTypeAs ();
799+ private FieldValueInfo completeField (GraphQLFieldDefinition fieldDef , GraphQLObjectType parentType , ExecutionContext executionContext , ExecutionStrategyParameters parameters , Object fetchedValue ) {
799800 ExecutionStepInfo executionStepInfo = createExecutionStepInfo (executionContext , parameters , fieldDef , parentType );
800801
801802 boolean noOpFieldInstr = executionContext .isNoOpFieldInstrumentation ();
@@ -966,22 +967,29 @@ protected FieldValueInfo completeValueForList(ExecutionContext executionContext,
966967 }
967968
968969 List <FieldValueInfo > fieldValueInfos = new ArrayList <>(size .orElse (1 ));
970+ // Hoist loop-invariant computations: the parent path and local context don't change per element,
971+ // and the list element type (unwrapped from the list type) is the same for all elements
972+ ResultPath parentPath = parameters .getPath ();
973+ Object parentLocalContext = parameters .getLocalContext ();
974+ GraphQLList listFieldType = executionStepInfo .getUnwrappedNonNullTypeAs ();
975+ GraphQLOutputType typeInList = (GraphQLOutputType ) listFieldType .getWrappedType ();
969976 int index = 0 ;
970977 for (Object item : iterableValues ) {
971978 if (incrementAndCheckMaxNodesExceeded (executionContext )) {
972979 return new FieldValueInfo (NULL , null , fieldValueInfos );
973980 }
974981
975- ResultPath indexedPath = parameters . getPath () .segment (index );
982+ ResultPath indexedPath = parentPath .segment (index );
976983
977- ExecutionStepInfo stepInfoForListElement = executionStepInfoFactory .newExecutionStepInfoForListElement (executionStepInfo , indexedPath );
984+ // Inline newExecutionStepInfoForListElement to avoid per-element getUnwrappedNonNullTypeAs + getWrappedType
985+ ExecutionStepInfo stepInfoForListElement = executionStepInfo .transform (typeInList , executionStepInfo , indexedPath );
978986
979987 Object fetchedValue = unboxPossibleDataFetcherResult (executionContext , parameters , item );
980988
981989 ExecutionStrategyParameters newParameters = parameters .transform (
982990 stepInfoForListElement ,
983991 indexedPath ,
984- FetchedValue .getLocalContext (fetchedValue , parameters . getLocalContext () ),
992+ FetchedValue .getLocalContext (fetchedValue , parentLocalContext ),
985993 FetchedValue .getFetchedValue (fetchedValue )
986994 );
987995
0 commit comments