[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<R, S>` 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<R>` from function type parameters `R`:
Now:
`R[_eval]("B<0>")`
Previously:
`dart_rti.instanceType(this)[_bind](R)[_eval]("B<N+1>")`
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 <natebiggs@google.com>
Commit-Queue: Nicholas Shahan <nshahan@google.com>
This commit is contained in:
committed by
Commit Queue
parent
7e4fca78a8
commit
14bb2be360
@@ -3786,20 +3786,18 @@ class ProgramCompiler extends ComputeOnceConstantVisitor<js_ast.Expression>
|
||||
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():
|
||||
|
||||
@@ -4357,20 +4357,18 @@ class LibraryCompiler extends ComputeOnceConstantVisitor<js_ast.Expression>
|
||||
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():
|
||||
|
||||
@@ -244,24 +244,24 @@ class ExtendedTypeEnvironment<T extends ExtendableTypeEnvironment>
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user