From 14bb2be360d2354d996444592ea6776f3265f686 Mon Sep 17 00:00:00 2001 From: Nicholas Shahan Date: Thu, 10 Jul 2025 13:08:45 -0700 Subject: [PATCH] [ddc] Optimize building type environments at runtime * Avoids retrieving the instance type in more cases. In static class methods (including constructor tear offs) `dart_rti.instanceType(this)` was being used as the base of the environment binding. In these cases the result was the reified type of the JavaScript function. This worked as long as the base type of the binding is ignored, but it was not intuitive and had to fall through all the other cases before settling on that result. * Avoids parsing a recipe for the `dynamic` every time when we already can have it available in our type table. Compiled code examples: Building the type `A` from function type parameters `R` and `S`: Now: `T.dynamic()[_bind](R)[_bind](S)[_eval]("A<1,2>")` Previously: `dart_rti.instanceType(this)[_bind](R)[_bind](S)[_eval]("A<1,2>")` Building the type `B` from function type parameters `R`: Now: `R[_eval]("B<0>")` Previously: `dart_rti.instanceType(this)[_bind](R)[_eval]("B")` where N is the number of type arguments of the enclosing class. `` Change-Id: I213666edd7c6427f0d42d958541e53a798e8877c Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/439460 Reviewed-by: Nate Biggs Commit-Queue: Nicholas Shahan --- pkg/dev_compiler/lib/src/kernel/compiler.dart | 18 ++++++------- .../lib/src/kernel/compiler_new.dart | 18 ++++++------- .../lib/src/kernel/type_environment.dart | 26 +++++++++---------- 3 files changed, 29 insertions(+), 33 deletions(-) diff --git a/pkg/dev_compiler/lib/src/kernel/compiler.dart b/pkg/dev_compiler/lib/src/kernel/compiler.dart index 33358d898cc..aeddbc9439d 100644 --- a/pkg/dev_compiler/lib/src/kernel/compiler.dart +++ b/pkg/dev_compiler/lib/src/kernel/compiler.dart @@ -3786,20 +3786,18 @@ class ProgramCompiler extends ComputeOnceConstantVisitor if (recipe == '0') return env; } else { var environmentTypes = environment.functionTypeParameters; - // Create a dummy interface type to "hold" type arguments. - env = emitRtiEval( - _emitTypeParameter(environmentTypes.first), - '@<0>', - ); - // Bind remaining type arguments. - for (var i = 1; i < environmentTypes.length; i++) { - env = emitRtiBind(env, environmentTypes[i]); + // By convention we create a binding environment with "dynamic" as + // the base. + env = _emitType(const DynamicType()); + // Bind all type arguments to it. + for (var typeParameter in environmentTypes) { + env = emitRtiBind(env, typeParameter); } } return emitRtiEval(env, recipe); case RtiTypeEnvironment(): - // RTI type environments are already constructed and attached to the - // provided RTI. + // RTI type environments take the form of a preconstructed RTI that + // is accessible via a known parameter name. var env = _rtiParam; return emitRtiEval(env, recipe); case ClassTypeEnvironment(): diff --git a/pkg/dev_compiler/lib/src/kernel/compiler_new.dart b/pkg/dev_compiler/lib/src/kernel/compiler_new.dart index 7c7d24a509d..9303f38e8b2 100644 --- a/pkg/dev_compiler/lib/src/kernel/compiler_new.dart +++ b/pkg/dev_compiler/lib/src/kernel/compiler_new.dart @@ -4357,20 +4357,18 @@ class LibraryCompiler extends ComputeOnceConstantVisitor if (recipe == '0') return env; } else { var environmentTypes = environment.functionTypeParameters; - // Create a dummy interface type to "hold" type arguments. - env = emitRtiEval( - _emitTypeParameter(environmentTypes.first), - '@<0>', - ); - // Bind remaining type arguments. - for (var i = 1; i < environmentTypes.length; i++) { - env = emitRtiBind(env, environmentTypes[i]); + // By convention we create a binding environment with "dynamic" as + // the base. + env = _emitType(const DynamicType()); + // Bind all type arguments to it. + for (var typeParameter in environmentTypes) { + env = emitRtiBind(env, typeParameter); } } return emitRtiEval(env, recipe); case RtiTypeEnvironment(): - // RTI type environments are already constructed and attached to the - // provided RTI. + // RTI type environments take the form of a preconstructed RTI that + // is accessible via a known parameter name. var env = _rtiParam; return emitRtiEval(env, recipe); case ClassTypeEnvironment(): diff --git a/pkg/dev_compiler/lib/src/kernel/type_environment.dart b/pkg/dev_compiler/lib/src/kernel/type_environment.dart index 2cc3aa76cf8..1525de3b216 100644 --- a/pkg/dev_compiler/lib/src/kernel/type_environment.dart +++ b/pkg/dev_compiler/lib/src/kernel/type_environment.dart @@ -244,24 +244,24 @@ class ExtendedTypeEnvironment var baseEnvironmentNeeded = requiredParameters.any( _baseTypeEnvironment._typeParameters.contains, ); - var additionalParameters = requiredParameters.where( - _typeParameters.contains, - ); - if (additionalParameters.isEmpty) { - return baseEnvironmentNeeded - // Simply using the base environment has a compact representation - // and is already constructed. - ? _baseTypeEnvironment + var additionalParameters = requiredParameters + .where(_typeParameters.contains) + .toList(); + if (!baseEnvironmentNeeded) { + return additionalParameters.isEmpty // No type parameters are needed from this environment. - : const EmptyTypeEnvironment(); + ? const EmptyTypeEnvironment() + // A binding environment with a single parameter will be reduced to + // just the parameter. + : BindingTypeEnvironment(additionalParameters); } + // Simply using the base environment has a compact representation and at + // runtime it has already been constructed. + if (additionalParameters.isEmpty) return _baseTypeEnvironment; // This is already the exact environment needed. if (additionalParameters.length == _typeParameters.length) return this; // An extended environment with fewer additional parameters is needed. - return ExtendedTypeEnvironment( - _baseTypeEnvironment, - additionalParameters.toList(), - ); + return ExtendedTypeEnvironment(_baseTypeEnvironment, additionalParameters); } @override