[dart2js] Track, rather than compute, isCallOnInterceptor
By tracking `isCallOnInterceptor`, we avoid the need for class context information in the `sourceElement` to compute the value. `sourceElement` is now purely advisory to the choice of local names in codegen, and can't be the wrong kind of element as in issue #60793. Bug: #60793 Change-Id: I8bb68b6bf864a3a6f9f2beb40f68a6254431d49a Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/432003 Commit-Queue: Stephen Adams <sra@google.com> Reviewed-by: Mayank Patke <fishythefish@google.com>
This commit is contained in:
committed by
Commit Queue
parent
74f74d7157
commit
d49cd3c552
@@ -2480,7 +2480,7 @@ class SsaCodeGenerator implements HVisitor<void>, HBlockInformationVisitor {
|
||||
if (superElement is FieldEntity) {
|
||||
// TODO(sra): We can lower these in the simplifier.
|
||||
js.Name fieldName = _namer.instanceFieldPropertyName(superElement);
|
||||
use(node.getDartReceiver(_closedWorld));
|
||||
use(node.getDartReceiver());
|
||||
js.PropertyAccess access =
|
||||
js.PropertyAccess(
|
||||
pop(),
|
||||
|
||||
@@ -111,7 +111,7 @@ class SsaInstructionSelection extends HBaseVisitor<HInstruction?>
|
||||
// The instructionType of [nullCheck] is not nullable (since it is the
|
||||
// (not) null check!) This means that if we do need to check the type, we
|
||||
// should test against nullCheck.checkedInput, not the direct input.
|
||||
if (current!.getDartReceiver(_closedWorld) == nullCheck) {
|
||||
if (current!.getDartReceiver() == nullCheck) {
|
||||
if (current is HFieldGet) return current;
|
||||
if (current is HFieldSet) return current;
|
||||
if (current is HGetLength) return current;
|
||||
|
||||
@@ -62,8 +62,8 @@ class SsaFinalizeInterceptors extends HBaseVisitor<void>
|
||||
}
|
||||
|
||||
/// Returns `true` if [element] is an instance method that uses the
|
||||
/// interceptor calling convention but the instance and interceptor arguments
|
||||
/// will always be the same value.
|
||||
/// interceptor calling convention but the interceptor argument will always be
|
||||
/// the instance.
|
||||
bool usesSelfInterceptor(MemberEntity element) {
|
||||
if (!_interceptorData.isInterceptedMethod(element)) return false;
|
||||
ClassEntity cls = element.enclosingClass!;
|
||||
@@ -101,6 +101,12 @@ class SsaFinalizeInterceptors extends HBaseVisitor<void>
|
||||
thisParameter!.instructionType = receiverParameter!.instructionType;
|
||||
receiverParameter.block!.rewrite(receiverParameter, thisParameter);
|
||||
receiverParameter.sourceElement = const _RenameToUnderscore();
|
||||
|
||||
for (final instruction in thisParameter.usedBy) {
|
||||
if (instruction is HInvoke) {
|
||||
instruction.updateIsCallOnInterceptor();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -262,6 +268,7 @@ class SsaFinalizeInterceptors extends HBaseVisitor<void>
|
||||
}
|
||||
|
||||
void _replaceReceiverArgumentWithDummy(HInvoke node, int receiverIndex) {
|
||||
assert(!node.isCallOnInterceptor, 'node: $node');
|
||||
ConstantValue constant = DummyInterceptorConstantValue();
|
||||
HConstant dummy = _graph.addConstant(constant, _closedWorld);
|
||||
node.replaceInput(receiverIndex, dummy);
|
||||
|
||||
@@ -266,7 +266,7 @@ class SsaSimplifyInterceptors extends HBaseVisitor<bool>
|
||||
// If there is a call that dominates all other uses, we can use just the
|
||||
// selector of that instruction.
|
||||
if (dominator is HInvokeDynamic &&
|
||||
dominator.isCallOnInterceptor(_closedWorld) &&
|
||||
dominator.isCallOnInterceptor &&
|
||||
node == dominator.receiver &&
|
||||
useCount(dominator, node) == 1) {
|
||||
interceptedClasses = _interceptorData.getInterceptedClassesOn(
|
||||
@@ -303,7 +303,7 @@ class SsaSimplifyInterceptors extends HBaseVisitor<bool>
|
||||
interceptedClasses = {};
|
||||
for (HInstruction user in node.usedBy) {
|
||||
if (user is HInvokeDynamic &&
|
||||
user.isCallOnInterceptor(_closedWorld) &&
|
||||
user.isCallOnInterceptor &&
|
||||
node == user.receiver &&
|
||||
useCount(user, node) == 1) {
|
||||
interceptedClasses.addAll(
|
||||
@@ -313,7 +313,7 @@ class SsaSimplifyInterceptors extends HBaseVisitor<bool>
|
||||
),
|
||||
);
|
||||
} else if (user is HInvokeSuper &&
|
||||
user.isCallOnInterceptor(_closedWorld) &&
|
||||
user.isCallOnInterceptor &&
|
||||
node == user.receiver &&
|
||||
useCount(user, node) == 1) {
|
||||
interceptedClasses.addAll(
|
||||
@@ -402,7 +402,7 @@ class SsaSimplifyInterceptors extends HBaseVisitor<bool>
|
||||
// }
|
||||
|
||||
void finishInvoke(HInvoke invoke, Selector selector) {
|
||||
HInstruction callReceiver = invoke.getDartReceiver(_closedWorld)!;
|
||||
HInstruction callReceiver = invoke.getDartReceiver()!;
|
||||
if (receiver.nonCheck() == callReceiver.nonCheck()) {
|
||||
Set<ClassEntity> interceptedClasses = _interceptorData
|
||||
.getInterceptedClassesOn(selector.name, _closedWorld);
|
||||
@@ -412,19 +412,20 @@ class SsaSimplifyInterceptors extends HBaseVisitor<bool>
|
||||
interceptedClasses: interceptedClasses,
|
||||
)) {
|
||||
invoke.changeUse(node, callReceiver);
|
||||
invoke.updateIsCallOnInterceptor();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (HInstruction user in node.usedBy.toList()) {
|
||||
if (user is HInvokeDynamic) {
|
||||
if (user.isCallOnInterceptor(_closedWorld) &&
|
||||
if (user.isCallOnInterceptor &&
|
||||
node == user.inputs[0] &&
|
||||
useCount(user, node) == 1) {
|
||||
finishInvoke(user, user.selector);
|
||||
}
|
||||
} else if (user is HInvokeSuper) {
|
||||
if (user.isCallOnInterceptor(_closedWorld) &&
|
||||
if (user.isCallOnInterceptor &&
|
||||
node == user.inputs[0] &&
|
||||
useCount(user, node) == 1) {
|
||||
finishInvoke(user, user.selector);
|
||||
|
||||
@@ -361,7 +361,7 @@ class IndexSpecializer extends InvokeDynamicSpecializer {
|
||||
JClosedWorld closedWorld,
|
||||
OptimizationTestLog? log,
|
||||
) {
|
||||
HInstruction receiver = instruction.getDartReceiver(closedWorld);
|
||||
HInstruction receiver = instruction.getDartReceiver();
|
||||
var abstractValueDomain = closedWorld.abstractValueDomain;
|
||||
if (receiver.isIndexablePrimitive(abstractValueDomain).isPotentiallyFalse) {
|
||||
return null;
|
||||
@@ -419,7 +419,7 @@ class CodeUnitAtSpecializer extends InvokeDynamicSpecializer {
|
||||
OptimizationTestLog? log,
|
||||
) {
|
||||
final abstractValueDomain = closedWorld.abstractValueDomain;
|
||||
HInstruction receiver = instruction.getDartReceiver(closedWorld);
|
||||
HInstruction receiver = instruction.getDartReceiver();
|
||||
if (receiver.isStringOrNull(abstractValueDomain).isPotentiallyFalse) {
|
||||
return null;
|
||||
}
|
||||
@@ -460,7 +460,7 @@ class RemoveLastSpecializer extends InvokeDynamicSpecializer {
|
||||
JClosedWorld closedWorld,
|
||||
OptimizationTestLog? log,
|
||||
) {
|
||||
HInstruction receiver = instruction.getDartReceiver(closedWorld);
|
||||
HInstruction receiver = instruction.getDartReceiver();
|
||||
final abstractValueDomain = closedWorld.abstractValueDomain;
|
||||
if (receiver.isGrowableArray(abstractValueDomain).isPotentiallyFalse) {
|
||||
return null;
|
||||
@@ -876,7 +876,7 @@ class ModuloSpecializer extends BinaryArithmeticSpecializer {
|
||||
// track -0.0 precisely, we have to syntactically filter inputs that cannot
|
||||
// generate -0.0.
|
||||
|
||||
HInstruction receiver = instruction.getDartReceiver(closedWorld);
|
||||
HInstruction receiver = instruction.getDartReceiver();
|
||||
if (inputsArePositiveIntegers(instruction, closedWorld) &&
|
||||
!canBeNegativeZero(receiver)) {
|
||||
return HRemainder(
|
||||
@@ -1840,7 +1840,7 @@ class CompareToSpecializer extends InvokeDynamicSpecializer {
|
||||
JClosedWorld closedWorld,
|
||||
OptimizationTestLog? log,
|
||||
) {
|
||||
HInstruction receiver = instruction.getDartReceiver(closedWorld);
|
||||
HInstruction receiver = instruction.getDartReceiver();
|
||||
// `compareTo` has no side-effect (other than throwing) and can be GVN'ed
|
||||
// for some known types.
|
||||
if (receiver
|
||||
@@ -1890,7 +1890,7 @@ abstract class IdempotentStringOperationSpecializer
|
||||
JClosedWorld closedWorld,
|
||||
OptimizationTestLog? log,
|
||||
) {
|
||||
HInstruction receiver = instruction.getDartReceiver(closedWorld);
|
||||
HInstruction receiver = instruction.getDartReceiver();
|
||||
if (receiver
|
||||
.isStringOrNull(closedWorld.abstractValueDomain)
|
||||
.isDefinitelyTrue) {
|
||||
@@ -1937,7 +1937,7 @@ class PatternMatchSpecializer extends InvokeDynamicSpecializer {
|
||||
JClosedWorld closedWorld,
|
||||
OptimizationTestLog? log,
|
||||
) {
|
||||
HInstruction receiver = instruction.getDartReceiver(closedWorld);
|
||||
HInstruction receiver = instruction.getDartReceiver();
|
||||
HInstruction pattern = instruction.inputs[2];
|
||||
if (receiver
|
||||
.isStringOrNull(closedWorld.abstractValueDomain)
|
||||
@@ -1969,7 +1969,7 @@ class RoundSpecializer extends InvokeDynamicSpecializer {
|
||||
JClosedWorld closedWorld,
|
||||
OptimizationTestLog? log,
|
||||
) {
|
||||
HInstruction receiver = instruction.getDartReceiver(closedWorld);
|
||||
HInstruction receiver = instruction.getDartReceiver();
|
||||
if (receiver
|
||||
.isNumberOrNull(closedWorld.abstractValueDomain)
|
||||
.isDefinitelyTrue) {
|
||||
@@ -1997,7 +1997,7 @@ class ToIntSpecializer extends InvokeDynamicSpecializer {
|
||||
JClosedWorld closedWorld,
|
||||
OptimizationTestLog? log,
|
||||
) {
|
||||
HInstruction receiver = instruction.getDartReceiver(closedWorld);
|
||||
HInstruction receiver = instruction.getDartReceiver();
|
||||
|
||||
// We would like to reduce `x.toInt()` to `x`. The web platform considers
|
||||
// infinities to be `int` values, but it is too hard to tell if an input is
|
||||
|
||||
@@ -1334,7 +1334,7 @@ abstract class HInstruction implements SpannableWithEntity {
|
||||
AbstractBool isPrimitiveOrNull(AbstractValueDomain domain) =>
|
||||
domain.isPrimitiveOrNull(instructionType);
|
||||
|
||||
HInstruction? getDartReceiver(JClosedWorld closedWorld) => null;
|
||||
HInstruction? getDartReceiver() => null;
|
||||
bool onlyThrowsNSM() => false;
|
||||
|
||||
bool isInBasicBlock() => block != null;
|
||||
@@ -1481,8 +1481,6 @@ abstract class HInstruction implements SpannableWithEntity {
|
||||
bool isConstantFalse() => false;
|
||||
bool isConstantTrue() => false;
|
||||
|
||||
bool isInterceptor(JClosedWorld closedWorld) => false;
|
||||
|
||||
bool isValid() {
|
||||
HValidator validator = HValidator();
|
||||
validator.currentBlock = block;
|
||||
@@ -1914,6 +1912,12 @@ abstract class HInvoke extends HInstruction
|
||||
/// input is the Dart receiver.
|
||||
bool isInterceptedCall = false;
|
||||
|
||||
/// [_isCallOnInterceptor] is true if this invocation uses the interceptor
|
||||
/// calling convention *and* the interceptor input is an interceptor, and not
|
||||
/// the receiver. A call has `isInterceptedCall == true` and
|
||||
/// `_isCallOnInterceptor == false` after the 'self interceptor' optimization.
|
||||
bool _isCallOnInterceptor = false;
|
||||
|
||||
HInvoke(super.inputs, super.type) : super() {
|
||||
sideEffects.setAllSideEffects();
|
||||
sideEffects.setDependsOnSomething();
|
||||
@@ -1929,6 +1933,30 @@ abstract class HInvoke extends HInstruction
|
||||
void setAllocation(bool value) {
|
||||
_isAllocation = value;
|
||||
}
|
||||
|
||||
bool get isCallOnInterceptor => _isCallOnInterceptor;
|
||||
|
||||
/// Update 'isCallOnInterceptor'. An intercepted call can go through
|
||||
/// refinements that drop references to unneeded values or arguments:
|
||||
///
|
||||
/// interceptor.foo(receiver, ...); // isCallOnInterceptor = true
|
||||
/// -->
|
||||
/// receiver.foo(receiver, ...); // isCallOnInterceptor = false
|
||||
/// -->
|
||||
/// receiver.foo(dummy, ...); // isCallOnInterceptor = false
|
||||
void updateIsCallOnInterceptor() {
|
||||
if (isInterceptedCall && _isCallOnInterceptor) {
|
||||
final interceptor = inputs[0].nonCheck();
|
||||
final receiver = inputs[1].nonCheck();
|
||||
if (interceptor == receiver) {
|
||||
_isCallOnInterceptor = false;
|
||||
} else if (receiver case HConstant(
|
||||
constant: DummyInterceptorConstantValue(),
|
||||
)) {
|
||||
_isCallOnInterceptor = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
abstract class HInvokeDynamic extends HInvoke implements InstructionContext {
|
||||
@@ -1978,6 +2006,8 @@ abstract class HInvokeDynamic extends HInvoke implements InstructionContext {
|
||||
: const InvokeDynamicSpecializer(),
|
||||
super(inputs, resultType) {
|
||||
isInterceptedCall = isIntercepted;
|
||||
_isCallOnInterceptor = isIntercepted;
|
||||
updateIsCallOnInterceptor();
|
||||
}
|
||||
|
||||
Selector get selector => _selector;
|
||||
@@ -2047,18 +2077,13 @@ abstract class HInvokeDynamic extends HInvoke implements InstructionContext {
|
||||
HInstruction get receiver => inputs[0];
|
||||
|
||||
@override
|
||||
HInstruction getDartReceiver(JClosedWorld closedWorld) {
|
||||
return isCallOnInterceptor(closedWorld) ? inputs[1] : inputs[0];
|
||||
HInstruction getDartReceiver() {
|
||||
return _isCallOnInterceptor ? inputs[1] : inputs[0];
|
||||
}
|
||||
|
||||
/// The type arguments passed in this dynamic invocation.
|
||||
List<DartType> get typeArguments;
|
||||
|
||||
/// Returns whether this call is on an interceptor object.
|
||||
bool isCallOnInterceptor(JClosedWorld closedWorld) {
|
||||
return isInterceptedCall && receiver.isInterceptor(closedWorld);
|
||||
}
|
||||
|
||||
@override
|
||||
_GvnType get _gvnType => _GvnType.invokeDynamic;
|
||||
|
||||
@@ -2238,6 +2263,8 @@ class HInvokeStatic extends HInvoke {
|
||||
bool isIntercepted = false,
|
||||
}) : super(inputs, type) {
|
||||
isInterceptedCall = isIntercepted;
|
||||
_isCallOnInterceptor = isIntercepted;
|
||||
updateIsCallOnInterceptor();
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -2282,13 +2309,8 @@ class HInvokeSuper extends HInvokeStatic {
|
||||
|
||||
HInstruction get receiver => inputs[0];
|
||||
@override
|
||||
HInstruction getDartReceiver(JClosedWorld closedWorld) {
|
||||
return isCallOnInterceptor(closedWorld) ? inputs[1] : inputs[0];
|
||||
}
|
||||
|
||||
/// Returns whether this call is on an interceptor object.
|
||||
bool isCallOnInterceptor(JClosedWorld closedWorld) {
|
||||
return isInterceptedCall && receiver.isInterceptor(closedWorld);
|
||||
HInstruction getDartReceiver() {
|
||||
return isCallOnInterceptor ? inputs[1] : inputs[0];
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -2374,28 +2396,12 @@ class HFieldGet extends HFieldAccess {
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
bool isInterceptor(JClosedWorld closedWorld) {
|
||||
final entity = sourceElement;
|
||||
// In case of a closure inside an interceptor class, JavaScript `this`, the
|
||||
// interceptor, is stored in the generated closure class, and accessed
|
||||
// through a [HFieldGet].
|
||||
// TODO(sra): It would be better to track this as an explicit property
|
||||
// rather than recover it from `sourceElement`.
|
||||
if (entity is ThisLocal) {
|
||||
return closedWorld.interceptorData.isInterceptedClass(
|
||||
entity.enclosingClass,
|
||||
);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@override
|
||||
bool canThrow(AbstractValueDomain domain) =>
|
||||
receiver.isNull(domain).isPotentiallyTrue;
|
||||
|
||||
@override
|
||||
HInstruction getDartReceiver(JClosedWorld closedWorld) => receiver;
|
||||
HInstruction getDartReceiver() => receiver;
|
||||
@override
|
||||
bool onlyThrowsNSM() => true;
|
||||
|
||||
@@ -2425,7 +2431,7 @@ class HFieldSet extends HFieldAccess {
|
||||
receiver.isNull(domain).isPotentiallyTrue;
|
||||
|
||||
@override
|
||||
HInstruction getDartReceiver(JClosedWorld closedWorld) => receiver;
|
||||
HInstruction getDartReceiver() => receiver;
|
||||
@override
|
||||
bool onlyThrowsNSM() => true;
|
||||
|
||||
@@ -2478,7 +2484,7 @@ class HGetLength extends HInstruction {
|
||||
receiver.isNull(domain).isPotentiallyTrue;
|
||||
|
||||
@override
|
||||
HInstruction getDartReceiver(JClosedWorld closedWorld) => receiver;
|
||||
HInstruction getDartReceiver() => receiver;
|
||||
@override
|
||||
bool onlyThrowsNSM() => true;
|
||||
|
||||
@@ -2553,7 +2559,7 @@ class HReadModifyWrite extends HInstruction implements HLateInstruction {
|
||||
receiver.isNull(domain).isPotentiallyTrue;
|
||||
|
||||
@override
|
||||
HInstruction getDartReceiver(JClosedWorld closedWorld) => receiver;
|
||||
HInstruction getDartReceiver() => receiver;
|
||||
@override
|
||||
bool onlyThrowsNSM() => true;
|
||||
|
||||
@@ -3253,10 +3259,6 @@ class HConstant extends HInstruction {
|
||||
@override
|
||||
bool isConstantTrue() => constant is TrueConstantValue;
|
||||
|
||||
@override
|
||||
bool isInterceptor(JClosedWorld closedWorld) =>
|
||||
constant is InterceptorConstantValue;
|
||||
|
||||
// Maybe avoid this if the literal is big?
|
||||
@override
|
||||
bool isCodeMotionInvariant() => true;
|
||||
@@ -3337,27 +3339,12 @@ class HThis extends HParameterValue {
|
||||
// [element] can be null for some synthetic members, e.g. `$signature`.
|
||||
HThis(ThisLocal? element, AbstractValue type) : super(element, type);
|
||||
|
||||
@override
|
||||
ThisLocal? get sourceElement => super.sourceElement as ThisLocal?;
|
||||
|
||||
@override
|
||||
set sourceElement(covariant ThisLocal? local) {
|
||||
super.sourceElement = local;
|
||||
}
|
||||
|
||||
@override
|
||||
R accept<R>(HVisitor<R> visitor) => visitor.visitThis(this);
|
||||
|
||||
@override
|
||||
bool isCodeMotionInvariant() => true;
|
||||
|
||||
@override
|
||||
bool isInterceptor(JClosedWorld closedWorld) {
|
||||
return closedWorld.interceptorData.isInterceptedClass(
|
||||
sourceElement!.enclosingClass,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() => 'this';
|
||||
}
|
||||
@@ -3633,9 +3620,6 @@ class HInterceptor extends HInstruction {
|
||||
inputs.add(constant);
|
||||
}
|
||||
|
||||
@override
|
||||
bool isInterceptor(JClosedWorld closedWorld) => true;
|
||||
|
||||
@override
|
||||
_GvnType get _gvnType => _GvnType.interceptor;
|
||||
@override
|
||||
@@ -3670,9 +3654,8 @@ class HOneShotInterceptor extends HInvokeDynamic {
|
||||
) : super(selector, receiverType, null, inputs, true, resultType) {
|
||||
assert(inputs[0].isConstantNull());
|
||||
assert(selector.callStructure.typeArgumentCount == typeArguments.length);
|
||||
_isCallOnInterceptor = true;
|
||||
}
|
||||
@override
|
||||
bool isCallOnInterceptor(JClosedWorld closedWorld) => true;
|
||||
|
||||
@override
|
||||
String toString() =>
|
||||
@@ -3767,7 +3750,7 @@ class HIndex extends HInstruction {
|
||||
bool get isMovable => false;
|
||||
|
||||
@override
|
||||
HInstruction getDartReceiver(JClosedWorld closedWorld) => receiver;
|
||||
HInstruction getDartReceiver() => receiver;
|
||||
@override
|
||||
bool onlyThrowsNSM() => true;
|
||||
@override
|
||||
@@ -3806,7 +3789,7 @@ class HIndexAssign extends HInstruction {
|
||||
bool get isMovable => false;
|
||||
|
||||
@override
|
||||
HInstruction getDartReceiver(JClosedWorld closedWorld) => receiver;
|
||||
HInstruction getDartReceiver() => receiver;
|
||||
@override
|
||||
bool onlyThrowsNSM() => true;
|
||||
@override
|
||||
@@ -3832,7 +3815,7 @@ class HCharCodeAt extends HInstruction {
|
||||
bool get isMovable => false;
|
||||
|
||||
@override
|
||||
HInstruction getDartReceiver(JClosedWorld closedWorld) => receiver;
|
||||
HInstruction getDartReceiver() => receiver;
|
||||
@override
|
||||
bool onlyThrowsNSM() => true;
|
||||
@override
|
||||
|
||||
@@ -1042,7 +1042,7 @@ class SsaInstructionSimplifier extends HBaseVisitor<HInstruction>
|
||||
if (folded != node) return folded;
|
||||
}
|
||||
|
||||
HInstruction receiver = node.getDartReceiver(_closedWorld);
|
||||
HInstruction receiver = node.getDartReceiver();
|
||||
AbstractValue receiverType = receiver.instructionType;
|
||||
final element = _closedWorld.locateSingleMember(
|
||||
node.selector,
|
||||
@@ -1090,8 +1090,7 @@ class SsaInstructionSimplifier extends HBaseVisitor<HInstruction>
|
||||
|
||||
if (element is FieldEntity && element.name == node.selector.name) {
|
||||
FieldEntity field = element;
|
||||
if (!_nativeData.isNativeMember(field) &&
|
||||
!node.isCallOnInterceptor(_closedWorld)) {
|
||||
if (!_nativeData.isNativeMember(field) && !node.isCallOnInterceptor) {
|
||||
// Insertion point for the closure call.
|
||||
HInstruction insertionPoint = node;
|
||||
HInstruction load;
|
||||
@@ -1991,7 +1990,7 @@ class SsaInstructionSimplifier extends HBaseVisitor<HInstruction>
|
||||
HInstruction folded = handleInterceptedCall(node);
|
||||
if (folded != node) return folded;
|
||||
}
|
||||
HInstruction receiver = node.getDartReceiver(_closedWorld);
|
||||
HInstruction receiver = node.getDartReceiver();
|
||||
AbstractValue receiverType = receiver.instructionType;
|
||||
|
||||
Selector selector = node.selector;
|
||||
@@ -2102,7 +2101,7 @@ class SsaInstructionSimplifier extends HBaseVisitor<HInstruction>
|
||||
if (folded != node) return folded;
|
||||
}
|
||||
|
||||
HInstruction receiver = node.getDartReceiver(_closedWorld);
|
||||
HInstruction receiver = node.getDartReceiver();
|
||||
AbstractValue receiverType = receiver.instructionType;
|
||||
final member = node.element ??= _closedWorld.locateSingleMember(
|
||||
node.selector,
|
||||
@@ -2175,7 +2174,7 @@ class SsaInstructionSimplifier extends HBaseVisitor<HInstruction>
|
||||
|
||||
@override
|
||||
HInstruction visitInvokeClosure(HInvokeClosure node) {
|
||||
HInstruction closure = node.getDartReceiver(_closedWorld);
|
||||
HInstruction closure = node.getDartReceiver();
|
||||
|
||||
// Replace indirect call to static method tear-off closure with direct call
|
||||
// to static method.
|
||||
@@ -3169,10 +3168,10 @@ class SsaDeadCodeEliminator extends HGraphVisitor implements OptimizationPhase {
|
||||
|
||||
if (!instruction.onlyThrowsNSM()) return false;
|
||||
|
||||
final receiver = instruction.getDartReceiver(closedWorld);
|
||||
final receiver = instruction.getDartReceiver();
|
||||
HInstruction? current = instruction.next;
|
||||
do {
|
||||
if ((current!.getDartReceiver(closedWorld) == receiver) &&
|
||||
if ((current!.getDartReceiver() == receiver) &&
|
||||
current.canThrow(_abstractValueDomain)) {
|
||||
return true;
|
||||
}
|
||||
@@ -3218,9 +3217,9 @@ class SsaDeadCodeEliminator extends HGraphVisitor implements OptimizationPhase {
|
||||
if (use is HFieldSet) {
|
||||
// The use must be the receiver. Even if the use is also the argument,
|
||||
// i.e. a.x = a, the store is still dead if all other uses are dead.
|
||||
if (use.getDartReceiver(closedWorld) == instruction) return true;
|
||||
if (use.getDartReceiver() == instruction) return true;
|
||||
} else if (use is HFieldGet) {
|
||||
assert(use.getDartReceiver(closedWorld) == instruction);
|
||||
assert(use.getDartReceiver() == instruction);
|
||||
if (isDeadCode(use)) return true;
|
||||
}
|
||||
return false;
|
||||
@@ -3236,7 +3235,7 @@ class SsaDeadCodeEliminator extends HGraphVisitor implements OptimizationPhase {
|
||||
|
||||
bool isTrivialDeadStore(HInstruction instruction) {
|
||||
return instruction is HFieldSet &&
|
||||
isTrivialDeadStoreReceiver(instruction.getDartReceiver(closedWorld));
|
||||
isTrivialDeadStoreReceiver(instruction.getDartReceiver());
|
||||
}
|
||||
|
||||
bool isDeadCode(HInstruction instruction) {
|
||||
@@ -3335,11 +3334,7 @@ class SsaDeadCodeEliminator extends HGraphVisitor implements OptimizationPhase {
|
||||
final phiBlock = phi.block!;
|
||||
phiBlock.rewrite(phi, replacement);
|
||||
phiBlock.removePhi(phi);
|
||||
if (replacement.sourceElement == null &&
|
||||
phi.sourceElement != null &&
|
||||
replacement is! HThis) {
|
||||
replacement.sourceElement = phi.sourceElement;
|
||||
}
|
||||
replacement.sourceElement ??= phi.sourceElement;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -3714,11 +3709,7 @@ class SsaRedundantPhiEliminator implements OptimizationPhase {
|
||||
final phiBlock = phi.block!;
|
||||
phiBlock.rewrite(phi, candidate);
|
||||
phiBlock.removePhi(phi);
|
||||
if (candidate.sourceElement == null &&
|
||||
phi.sourceElement != null &&
|
||||
candidate is! HThis) {
|
||||
candidate.sourceElement = phi.sourceElement;
|
||||
}
|
||||
candidate.sourceElement ??= phi.sourceElement;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4508,7 +4499,7 @@ class SsaLoadElimination extends HBaseVisitor<void>
|
||||
@override
|
||||
void visitFieldGet(HFieldGet node) {
|
||||
FieldEntity element = node.element;
|
||||
HInstruction receiver = node.getDartReceiver(_closedWorld).nonCheck();
|
||||
HInstruction receiver = node.getDartReceiver().nonCheck();
|
||||
_visitFieldGet(element, receiver, node);
|
||||
}
|
||||
|
||||
@@ -4545,7 +4536,7 @@ class SsaLoadElimination extends HBaseVisitor<void>
|
||||
@override
|
||||
void visitFieldSet(HFieldSet node) {
|
||||
FieldEntity element = node.element;
|
||||
HInstruction receiver = node.getDartReceiver(_closedWorld).nonCheck();
|
||||
HInstruction receiver = node.getDartReceiver().nonCheck();
|
||||
if (memorySet.registerFieldValueUpdate(element, receiver, node.value)) {
|
||||
node.block!.remove(node);
|
||||
}
|
||||
|
||||
@@ -438,7 +438,7 @@ class SsaTypePropagator extends HBaseVisitor<AbstractValue>
|
||||
pendingOptimizations.putIfAbsent(node, () => checkInputs);
|
||||
}
|
||||
|
||||
HInstruction receiver = node.getDartReceiver(closedWorld);
|
||||
HInstruction receiver = node.getDartReceiver();
|
||||
AbstractValue receiverType = receiver.instructionType;
|
||||
node.updateReceiverType(abstractValueDomain, receiverType);
|
||||
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
void main() {
|
||||
void foo() {
|
||||
final f = switch (null) {
|
||||
_ => foo,
|
||||
};
|
||||
print(f);
|
||||
}
|
||||
|
||||
foo();
|
||||
}
|
||||
Reference in New Issue
Block a user