[vm, kernel] Cleanup support for old invocation nodes from the VM

This change concludes switching to the new invocation nodes in the VM.
Support for the old invocation nodes (MethodInvocation, PropertyGet
and PropertySet) is removed from the VM and VM-specific kernel
transformations.

TEST=ci

Closes https://github.com/dart-lang/sdk/issues/45340

Change-Id: I0717732feb1b9c6ebdf0f6079ed42a90d00970a5
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/204741
Reviewed-by: Johnni Winther <johnniwinther@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Alexander Markov <alexmarkov@google.com>
This commit is contained in:
Alexander Markov 2021-06-24 16:17:50 +00:00 committed by commit-bot@chromium.org
parent 960cc715ee
commit a9757d177a
16 changed files with 34 additions and 724 deletions

View file

@ -215,8 +215,6 @@ class ExpressionLifter extends Transformer {
@override
TreeNode visitVariableSet(VariableSet expr) => unary(expr);
@override
TreeNode visitPropertyGet(PropertyGet expr) => unary(expr);
@override
TreeNode visitInstanceGet(InstanceGet expr) => unary(expr);
@override
TreeNode visitDynamicGet(DynamicGet expr) => unary(expr);
@ -237,14 +235,6 @@ class ExpressionLifter extends Transformer {
@override
TreeNode visitThrow(Throw expr) => unary(expr);
@override
TreeNode visitPropertySet(PropertySet expr) {
return transformTreeNode(expr, () {
expr.value = transform(expr.value)..parent = expr;
expr.receiver = transform(expr.receiver)..parent = expr;
});
}
@override
TreeNode visitInstanceSet(InstanceSet expr) {
return transformTreeNode(expr, () {
@ -274,14 +264,6 @@ class ExpressionLifter extends Transformer {
return args;
}
@override
TreeNode visitMethodInvocation(MethodInvocation expr) {
return transformTreeNode(expr, () {
visitArguments(expr.arguments);
expr.receiver = transform(expr.receiver)..parent = expr;
});
}
@override
TreeNode visitInstanceInvocation(InstanceInvocation expr) {
return transformTreeNode(expr, () {

View file

@ -60,13 +60,16 @@ class AnnotateWithStaticTypes extends RecursiveVisitor {
}
@override
visitPropertySet(PropertySet node) {
super.visitPropertySet(node);
visitPropertyGet(PropertyGet node) =>
throw 'Unexpected node ${node.runtimeType}: $node at ${node.location}';
if (hasGenericCovariantParameters(node.interfaceTarget)) {
annotateWithReceiver(node, node.receiver);
}
}
@override
visitPropertySet(PropertySet node) =>
throw 'Unexpected node ${node.runtimeType}: $node at ${node.location}';
@override
visitMethodInvocation(MethodInvocation node) =>
throw 'Unexpected node ${node.runtimeType}: $node at ${node.location}';
@override
visitInstanceSet(InstanceSet node) {
@ -77,18 +80,6 @@ class AnnotateWithStaticTypes extends RecursiveVisitor {
}
}
@override
visitMethodInvocation(MethodInvocation node) {
super.visitMethodInvocation(node);
// TODO(34162): We don't need to save the type here for calls, just whether
// or not it's a statically-checked call.
if (node.name.text == 'call' ||
hasGenericCovariantParameters(node.interfaceTarget)) {
annotateWithReceiver(node, node.receiver);
}
}
@override
visitInstanceInvocation(InstanceInvocation node) {
super.visitInstanceInvocation(node);

View file

@ -119,12 +119,6 @@ abstract class Devirtualization extends RecursiveVisitor {
}
}
@override
visitMethodInvocation(MethodInvocation node) {
super.visitMethodInvocation(node);
_handleMethodInvocation(node, node.interfaceTarget, node.arguments);
}
@override
visitInstanceInvocation(InstanceInvocation node) {
super.visitInstanceInvocation(node);
@ -162,12 +156,6 @@ abstract class Devirtualization extends RecursiveVisitor {
}
}
@override
visitPropertyGet(PropertyGet node) {
super.visitPropertyGet(node);
_handlePropertyGet(node, node.interfaceTarget);
}
@override
visitInstanceGet(InstanceGet node) {
super.visitInstanceGet(node);
@ -188,12 +176,6 @@ abstract class Devirtualization extends RecursiveVisitor {
}
}
@override
visitPropertySet(PropertySet node) {
super.visitPropertySet(node);
_handlePropertySet(node, node.interfaceTarget);
}
@override
visitInstanceSet(InstanceSet node) {
super.visitInstanceSet(node);

View file

@ -674,44 +674,6 @@ class _FfiUseSiteTransformer extends FfiTransformer {
..fileOffset = node.fileOffset);
}
@override
visitMethodInvocation(MethodInvocation node) {
super.visitMethodInvocation(node);
final Member target = node.interfaceTarget;
try {
if (target == elementAtMethod) {
final DartType pointerType =
node.receiver.getStaticType(_staticTypeContext);
final DartType nativeType = _pointerTypeGetTypeArg(pointerType);
_ensureNativeTypeValid(nativeType, node, allowCompounds: true);
Expression inlineSizeOf = _inlineSizeOf(nativeType);
if (inlineSizeOf != null) {
// Generates `receiver.offsetBy(inlineSizeOfExpression)`.
return InstanceInvocation(
InstanceAccessKind.Instance,
node.receiver,
offsetByMethod.name,
Arguments(
[multiply(node.arguments.positional.single, inlineSizeOf)]),
interfaceTarget: offsetByMethod,
functionType:
Substitution.fromInterfaceType(pointerType as InterfaceType)
.substituteType(offsetByMethod.getterType)
as FunctionType);
}
}
} on _FfiStaticTypeError {
// It's OK to swallow the exception because the diagnostics issued will
// cause compilation to fail. By continuing, we can report more
// diagnostics before compilation ends.
}
return node;
}
@override
visitInstanceInvocation(InstanceInvocation node) {
super.visitInstanceInvocation(node);

View file

@ -165,12 +165,6 @@ class ReferenceUpdater extends RecursiveVisitor {
node.stubTarget = _resolveNewInterfaceTarget(node.stubTarget);
}
@override
visitPropertyGet(PropertyGet node) {
node.interfaceTarget = _resolveNewInterfaceTarget(node.interfaceTarget);
super.visitPropertyGet(node);
}
@override
visitInstanceGet(InstanceGet node) {
node.interfaceTarget = _resolveNewInterfaceTarget(node.interfaceTarget)!;
@ -184,24 +178,12 @@ class ReferenceUpdater extends RecursiveVisitor {
super.visitInstanceTearOff(node);
}
@override
visitPropertySet(PropertySet node) {
node.interfaceTarget = _resolveNewInterfaceTarget(node.interfaceTarget);
super.visitPropertySet(node);
}
@override
visitInstanceSet(InstanceSet node) {
node.interfaceTarget = _resolveNewInterfaceTarget(node.interfaceTarget)!;
super.visitInstanceSet(node);
}
@override
visitMethodInvocation(MethodInvocation node) {
node.interfaceTarget = _resolveNewInterfaceTarget(node.interfaceTarget);
super.visitMethodInvocation(node);
}
@override
visitInstanceInvocation(InstanceInvocation node) {
node.interfaceTarget =

View file

@ -175,20 +175,6 @@ class DynamicSelectorsCollector extends RecursiveVisitor {
return v;
}
@override
visitMethodInvocation(MethodInvocation node) {
super.visitMethodInvocation(node);
Selector selector;
if (node.interfaceTarget == null) {
dynamicSelectors.add(new Selector.doInvoke(node.name));
} else {
if (node.receiver is! ThisExpression) {
nonThisSelectors.add(selector ??= new Selector.doInvoke(node.name));
}
}
}
@override
visitInstanceInvocation(InstanceInvocation node) {
super.visitInstanceInvocation(node);
@ -211,25 +197,6 @@ class DynamicSelectorsCollector extends RecursiveVisitor {
}
}
@override
visitPropertyGet(PropertyGet node) {
super.visitPropertyGet(node);
Selector selector;
if (node.interfaceTarget == null) {
dynamicSelectors.add(selector = new Selector.doGet(node.name));
} else {
if (node.receiver is! ThisExpression) {
nonThisSelectors.add(selector ??= new Selector.doGet(node.name));
}
final target = node.interfaceTarget;
if (target is Procedure && target.kind == ProcedureKind.Method) {
tearOffSelectors.add(new Selector.doInvoke(node.name));
}
}
}
@override
visitInstanceGet(InstanceGet node) {
super.visitInstanceGet(node);
@ -253,20 +220,6 @@ class DynamicSelectorsCollector extends RecursiveVisitor {
tearOffSelectors.add(new Selector.doInvoke(node.name));
}
@override
visitPropertySet(PropertySet node) {
super.visitPropertySet(node);
Selector selector;
if (node.interfaceTarget == null) {
dynamicSelectors.add(selector = new Selector.doSet(node.name));
} else {
if (node.receiver is! ThisExpression) {
nonThisSelectors.add(selector ??= new Selector.doSet(node.name));
}
}
}
@override
visitInstanceSet(InstanceSet node) {
super.visitInstanceSet(node);

View file

@ -155,17 +155,6 @@ class ProtobufHandler {
Statistics.protobufMetadataFieldsPruned += cls.numberOfFieldsPruned;
}
bool _isUnusedMetadataMethodInvocation(
_MessageClass cls, MethodInvocation node) {
if (node.interfaceTarget != null &&
node.interfaceTarget.enclosingClass == _builderInfoClass &&
fieldAddingMethods.contains(node.name.text)) {
final tagNumber = (node.arguments.positional[0] as IntLiteral).value;
return !cls._usedTags.contains(tagNumber);
}
return false;
}
bool _isUnusedMetadata(_MessageClass cls, InstanceInvocation node) {
if (node.interfaceTarget.enclosingClass == _builderInfoClass &&
fieldAddingMethods.contains(node.name.text)) {
@ -190,38 +179,6 @@ class _MetadataTransformer extends Transformer {
_MetadataTransformer(this.ph, this.cls);
@override
TreeNode visitMethodInvocation(MethodInvocation node) {
if (!ph._isUnusedMetadataMethodInvocation(cls, node)) {
super.visitMethodInvocation(node);
return node;
}
// Replace the field metadata method with a dummy call to
// `BuilderInfo.add`. This is to preserve the index calculations when
// removing a field.
// Change the tag-number to 0. Otherwise the decoder will get confused.
++numberOfFieldsPruned;
return InstanceInvocation(
InstanceAccessKind.Instance,
node.receiver,
ph._builderInfoAddMethod.name,
Arguments(
<Expression>[
IntLiteral(0), // tagNumber
NullLiteral(), // name
NullLiteral(), // fieldType
NullLiteral(), // defaultOrMaker
NullLiteral(), // subBuilder
NullLiteral(), // valueOf
NullLiteral(), // enumValues
],
types: const <DartType>[NullType()],
),
interfaceTarget: ph._builderInfoAddMethod,
functionType: ph._typeOfBuilderInfoAddOfNull)
..fileOffset = node.fileOffset;
}
@override
TreeNode visitInstanceInvocation(InstanceInvocation node) {
if (!ph._isUnusedMetadata(cls, node)) {

View file

@ -296,12 +296,6 @@ class _Collect extends RecursiveVisitor {
info.callCount++;
}
@override
void visitMethodInvocation(MethodInvocation node) {
collectCall(node.interfaceTarget, node.arguments);
super.visitMethodInvocation(node);
}
@override
void visitInstanceInvocation(InstanceInvocation node) {
collectCall(node.interfaceTarget, node.arguments);
@ -639,12 +633,6 @@ class _Transform extends RecursiveVisitor {
args.replaceWith(Arguments(positional, named: named, types: args.types));
}
@override
void visitMethodInvocation(MethodInvocation node) {
super.visitMethodInvocation(node);
transformCall(node.interfaceTarget, node, node.receiver, node.arguments);
}
@override
void visitInstanceInvocation(InstanceInvocation node) {
super.visitInstanceInvocation(node);

View file

@ -1134,9 +1134,7 @@ class SummaryCollector extends RecursiveResultVisitor<TypeExpr> {
}
TypeExpr _makeNarrowNotNull(TreeNode node, TypeExpr arg) {
assert(node is NullCheck ||
node is MethodInvocation && isComparisonWithNull(node) ||
node is EqualsNull);
assert(node is NullCheck || node is EqualsNull);
if (arg is NarrowNotNull) {
nullTests[node] = arg;
return arg;
@ -1355,44 +1353,6 @@ class SummaryCollector extends RecursiveResultVisitor<TypeExpr> {
}
_variableValues = null;
return;
} else if (node is MethodInvocation &&
node.receiver is VariableGet &&
node.name.text == '==') {
assert(node.arguments.positional.length == 1 &&
node.arguments.types.isEmpty &&
node.arguments.named.isEmpty);
final lhs = node.receiver as VariableGet;
final rhs = node.arguments.positional.single;
if (isNullLiteral(rhs)) {
// 'x == null', where x is a variable.
final expr = _visit(lhs);
_makeCall(node, DirectSelector(_environment.coreTypes.objectEquals),
Args<TypeExpr>([expr, _nullType]));
final narrowedNotNull = _makeNarrowNotNull(node, expr);
final int varIndex = _variablesInfo.varIndex[lhs.variable];
if (_variableCells[varIndex] == null) {
trueState[varIndex] = _nullType;
falseState[varIndex] = narrowedNotNull;
}
_variableValues = null;
return;
} else if ((rhs is IntLiteral &&
_isSubtype(lhs.variable.type,
_environment.coreTypes.intLegacyRawType)) ||
(rhs is StringLiteral &&
_isSubtype(lhs.variable.type,
_environment.coreTypes.stringLegacyRawType)) ||
(rhs is ConstantExpression &&
!_hasOverriddenEquals(lhs.variable.type))) {
// 'x == c', where x is a variable and c is a constant.
_addUse(_visit(node));
final int varIndex = _variablesInfo.varIndex[lhs.variable];
if (_variableCells[varIndex] == null) {
trueState[varIndex] = _visit(rhs);
}
_variableValues = null;
return;
}
} else if (node is EqualsCall && node.left is VariableGet) {
final lhs = node.left as VariableGet;
final rhs = node.right;
@ -1620,55 +1580,6 @@ class SummaryCollector extends RecursiveResultVisitor<TypeExpr> {
return _staticType(node);
}
@override
TypeExpr visitMethodInvocation(MethodInvocation node) {
if (isComparisonWithNull(node)) {
final arg = _visit(getArgumentOfComparisonWithNull(node));
_makeNarrowNotNull(node, arg);
_makeCall(node, DirectSelector(_environment.coreTypes.objectEquals),
Args<TypeExpr>([arg, _nullType]));
return _boolType;
}
final receiverNode = node.receiver;
final receiver = _visit(receiverNode);
final args = _visitArguments(receiver, node.arguments);
final target = node.interfaceTarget;
if (receiverNode is ConstantExpression && node.name.text == '[]') {
Constant constant = receiverNode.constant;
if (constant is ListConstant) {
return _handleIndexingIntoListConstant(constant);
}
}
TypeExpr result;
if (target == null) {
if (node.name.text == '==') {
_makeCall(node, new DynamicSelector(CallKind.Method, node.name), args);
return new Type.nullable(_boolType);
}
if (node.name.text == 'call') {
final recvType = _staticDartType(node.receiver);
if ((recvType is FunctionType) ||
(recvType == _environment.functionLegacyRawType)) {
// Call to a Function.
return _staticType(node);
}
}
result = _makeCall(
node, new DynamicSelector(CallKind.Method, node.name), args);
} else {
assert(target is Procedure && !target.isGetter);
// TODO(alexmarkov): overloaded arithmetic operators
result = _makeCall(
node,
(node.receiver is ThisExpression)
? new VirtualSelector(target)
: new InterfaceSelector(target),
args);
}
_updateReceiverAfterCall(receiverNode, receiver, node.name);
return result;
}
@override
TypeExpr visitInstanceInvocation(InstanceInvocation node) {
final receiverNode = node.receiver;
@ -1780,12 +1691,6 @@ class SummaryCollector extends RecursiveResultVisitor<TypeExpr> {
return result;
}
@override
TypeExpr visitPropertyGet(PropertyGet node) {
return _handlePropertyGet(
node, node.receiver, node.interfaceTarget, node.name);
}
@override
TypeExpr visitInstanceGet(InstanceGet node) {
return _handlePropertyGet(
@ -1808,29 +1713,6 @@ class SummaryCollector extends RecursiveResultVisitor<TypeExpr> {
return _handlePropertyGet(node, node.receiver, null, node.name);
}
@override
TypeExpr visitPropertySet(PropertySet node) {
var receiver = _visit(node.receiver);
var value = _visit(node.value);
var args = new Args<TypeExpr>([receiver, value]);
final target = node.interfaceTarget;
if (target == null) {
_makeCall(
node, new DynamicSelector(CallKind.PropertySet, node.name), args);
} else {
assert((target is Field) || ((target is Procedure) && target.isSetter));
_makeCall(
node,
(node.receiver is ThisExpression)
? new VirtualSelector(target, callKind: CallKind.PropertySet)
: new InterfaceSelector(target, callKind: CallKind.PropertySet),
args);
}
_updateReceiverAfterCall(node.receiver, receiver, node.name,
isSetter: true);
return value;
}
@override
TypeExpr visitInstanceSet(InstanceSet node) {
var receiver = _visit(node.receiver);

View file

@ -306,11 +306,9 @@ class AnnotateKernel extends RecursiveVisitor {
}
final bool markSkipCheck = !callSite.useCheckedEntry &&
(node is MethodInvocation ||
node is InstanceInvocation ||
(node is InstanceInvocation ||
node is DynamicInvocation ||
node is EqualsCall ||
node is PropertySet ||
node is InstanceSet ||
node is DynamicSet);
@ -355,16 +353,12 @@ class AnnotateKernel extends RecursiveVisitor {
// Tell the table selector assigner about the callsite.
final Selector selector = callSite.selector;
if (selector is InterfaceSelector && !_callSiteUsesDirectCall(node)) {
if (node is PropertyGet ||
node is InstanceGet ||
node is InstanceTearOff) {
if (node is InstanceGet || node is InstanceTearOff) {
_tableSelectorAssigner.registerGetterCall(
selector.member, callSite.isNullableReceiver);
} else {
assert(node is MethodInvocation ||
node is InstanceInvocation ||
assert(node is InstanceInvocation ||
node is EqualsCall ||
node is PropertySet ||
node is InstanceSet);
_tableSelectorAssigner.registerMethodOrSetterCall(
selector.member, callSite.isNullableReceiver);
@ -484,12 +478,6 @@ class AnnotateKernel extends RecursiveVisitor {
super.visitField(node);
}
@override
visitMethodInvocation(MethodInvocation node) {
_annotateCallSite(node, node.interfaceTarget);
super.visitMethodInvocation(node);
}
@override
visitInstanceInvocation(InstanceInvocation node) {
_annotateCallSite(node, node.interfaceTarget);
@ -520,12 +508,6 @@ class AnnotateKernel extends RecursiveVisitor {
super.visitEqualsCall(node);
}
@override
visitPropertyGet(PropertyGet node) {
_annotateCallSite(node, node.interfaceTarget);
super.visitPropertyGet(node);
}
@override
visitInstanceGet(InstanceGet node) {
_annotateCallSite(node, node.interfaceTarget);
@ -550,12 +532,6 @@ class AnnotateKernel extends RecursiveVisitor {
super.visitDynamicGet(node);
}
@override
visitPropertySet(PropertySet node) {
_annotateCallSite(node, node.interfaceTarget);
super.visitPropertySet(node);
}
@override
visitInstanceSet(InstanceSet node) {
_annotateCallSite(node, node.interfaceTarget);
@ -1104,30 +1080,6 @@ class _TreeShakerPass1 extends RemovingTransformer {
return node;
}
@override
TreeNode visitMethodInvocation(
MethodInvocation node, TreeNode removalSentinel) {
node.transformOrRemoveChildren(this);
if (_isUnreachable(node)) {
return _makeUnreachableCall(
_flattenArguments(node.arguments, receiver: node.receiver));
}
if (isComparisonWithNull(node)) {
final nullTest = _getNullTest(node);
if (nullTest.isAlwaysNull || nullTest.isAlwaysNotNull) {
return _evaluateArguments(
_flattenArguments(node.arguments, receiver: node.receiver),
BoolLiteral(nullTest.isAlwaysNull));
}
}
node.interfaceTarget =
fieldMorpher.adjustInstanceCallTarget(node.interfaceTarget);
if (node.interfaceTarget != null) {
shaker.addUsedMember(node.interfaceTarget);
}
return node;
}
@override
TreeNode visitInstanceInvocation(
InstanceInvocation node, TreeNode removalSentinel) {
@ -1200,21 +1152,6 @@ class _TreeShakerPass1 extends RemovingTransformer {
return node;
}
@override
TreeNode visitPropertyGet(PropertyGet node, TreeNode removalSentinel) {
node.transformOrRemoveChildren(this);
if (_isUnreachable(node)) {
return _makeUnreachableCall([node.receiver]);
} else {
node.interfaceTarget =
fieldMorpher.adjustInstanceCallTarget(node.interfaceTarget);
if (node.interfaceTarget != null) {
shaker.addUsedMember(node.interfaceTarget);
}
return node;
}
}
@override
TreeNode visitInstanceGet(InstanceGet node, TreeNode removalSentinel) {
node.transformOrRemoveChildren(this);
@ -1263,21 +1200,6 @@ class _TreeShakerPass1 extends RemovingTransformer {
}
}
@override
TreeNode visitPropertySet(PropertySet node, TreeNode removalSentinel) {
node.transformOrRemoveChildren(this);
if (_isUnreachable(node)) {
return _makeUnreachableCall([node.receiver, node.value]);
} else {
node.interfaceTarget = fieldMorpher
.adjustInstanceCallTarget(node.interfaceTarget, isSetter: true);
if (node.interfaceTarget != null) {
shaker.addUsedMember(node.interfaceTarget);
}
return node;
}
}
@override
TreeNode visitInstanceSet(InstanceSet node, TreeNode removalSentinel) {
node.transformOrRemoveChildren(this);

View file

@ -377,26 +377,6 @@ extension NullabilitySuffix on Nullability {
String get suffix => nullabilitySuffix[this];
}
bool isNullLiteral(Expression expr) =>
expr is NullLiteral ||
(expr is ConstantExpression && expr.constant is NullConstant);
Expression getArgumentOfComparisonWithNull(MethodInvocation node) {
if (node.name.text == '==') {
final lhs = node.receiver;
final rhs = node.arguments.positional.single;
if (isNullLiteral(lhs)) {
return rhs;
} else if (isNullLiteral(rhs)) {
return lhs;
}
}
return null;
}
bool isComparisonWithNull(MethodInvocation node) =>
getArgumentOfComparisonWithNull(node) != null;
bool mayHaveSideEffects(Expression node) {
// Keep this function in sync with mayHaveOrSeeSideEffects:
// If new false cases are added here, add the corresponding visibility cases

View file

@ -1115,8 +1115,6 @@ Fragment StreamingFlowGraphBuilder::BuildExpression(TokenPosition* position) {
return BuildVariableSet(position);
case kSpecializedVariableSet:
return BuildVariableSet(payload, position);
case kPropertyGet:
return BuildPropertyGet(position);
case kInstanceGet:
return BuildInstanceGet(position);
case kDynamicGet:
@ -1125,8 +1123,6 @@ Fragment StreamingFlowGraphBuilder::BuildExpression(TokenPosition* position) {
return BuildInstanceTearOff(position);
case kFunctionTearOff:
return BuildFunctionTearOff(position);
case kPropertySet:
return BuildPropertySet(position);
case kInstanceSet:
return BuildInstanceSet(position);
case kDynamicSet:
@ -1139,10 +1135,10 @@ Fragment StreamingFlowGraphBuilder::BuildExpression(TokenPosition* position) {
return BuildStaticGet(position);
case kStaticSet:
return BuildStaticSet(position);
case kMethodInvocation:
case kInstanceInvocation:
return BuildMethodInvocation(position, /*is_dynamic=*/false);
case kDynamicInvocation:
return BuildMethodInvocation(position, tag);
return BuildMethodInvocation(position, /*is_dynamic=*/true);
case kLocalFunctionInvocation:
return BuildLocalFunctionInvocation(position);
case kFunctionInvocation:
@ -2173,78 +2169,6 @@ Fragment StreamingFlowGraphBuilder::BuildVariableSetImpl(
return instructions;
}
Fragment StreamingFlowGraphBuilder::BuildPropertyGet(TokenPosition* p) {
const intptr_t offset = ReaderOffset() - 1; // Include the tag.
const TokenPosition position = ReadPosition(); // read position.
if (p != NULL) *p = position;
const DirectCallMetadata direct_call =
direct_call_metadata_helper_.GetDirectTargetForPropertyGet(offset);
const InferredTypeMetadata result_type =
inferred_type_metadata_helper_.GetInferredType(offset);
Fragment instructions = BuildExpression(); // read receiver.
LocalVariable* receiver = NULL;
if (direct_call.check_receiver_for_null_) {
// Duplicate receiver for CheckNull before it is consumed by PushArgument.
receiver = MakeTemporary();
instructions += LoadLocal(receiver);
}
const String& getter_name = ReadNameAsGetterName(); // read name.
const Function* interface_target = &Function::null_function();
const Function* tearoff_interface_target = &Function::null_function();
const NameIndex itarget_name =
ReadInterfaceMemberNameReference(); // read interface_target_reference.
if (!H.IsRoot(itarget_name) && H.IsGetter(itarget_name)) {
interface_target = &Function::ZoneHandle(
Z,
H.LookupMethodByMember(itarget_name, H.DartGetterName(itarget_name)));
ASSERT(getter_name.ptr() == interface_target->name());
} else if (!H.IsRoot(itarget_name) && H.IsMethod(itarget_name)) {
tearoff_interface_target = &Function::ZoneHandle(
Z,
H.LookupMethodByMember(itarget_name, H.DartMethodName(itarget_name)));
}
if (direct_call.check_receiver_for_null_) {
instructions += CheckNull(position, receiver, getter_name);
}
const String* mangled_name = &getter_name;
const Function* direct_call_target = &direct_call.target_;
if (H.IsRoot(itarget_name)) {
mangled_name = &String::ZoneHandle(
Z, Function::CreateDynamicInvocationForwarderName(getter_name));
if (!direct_call_target->IsNull()) {
direct_call_target = &Function::ZoneHandle(
direct_call.target_.GetDynamicInvocationForwarder(*mangled_name));
}
}
if (!direct_call_target->IsNull()) {
ASSERT(CompilerState::Current().is_aot());
instructions +=
StaticCall(position, *direct_call_target, 1, Array::null_array(),
ICData::kNoRebind, &result_type);
} else {
const intptr_t kTypeArgsLen = 0;
const intptr_t kNumArgsChecked = 1;
instructions +=
InstanceCall(position, *mangled_name, Token::kGET, kTypeArgsLen, 1,
Array::null_array(), kNumArgsChecked, *interface_target,
*tearoff_interface_target, &result_type);
}
if (direct_call.check_receiver_for_null_) {
instructions += DropTempsPreserveTop(1); // Drop receiver, preserve result.
}
return instructions;
}
Fragment StreamingFlowGraphBuilder::BuildInstanceGet(TokenPosition* p) {
const intptr_t offset = ReaderOffset() - 1; // Include the tag.
ReadByte(); // read kind.
@ -2451,101 +2375,6 @@ Fragment StreamingFlowGraphBuilder::BuildFunctionTearOff(TokenPosition* p) {
return instructions;
}
Fragment StreamingFlowGraphBuilder::BuildPropertySet(TokenPosition* p) {
const intptr_t offset = ReaderOffset() - 1; // Include the tag.
const DirectCallMetadata direct_call =
direct_call_metadata_helper_.GetDirectTargetForPropertySet(offset);
const CallSiteAttributesMetadata call_site_attributes =
call_site_attributes_metadata_helper_.GetCallSiteAttributes(offset);
const InferredTypeMetadata inferred_type =
inferred_type_metadata_helper_.GetInferredType(offset);
// True if callee can skip argument type checks.
bool is_unchecked_call = inferred_type.IsSkipCheck();
if (call_site_attributes.receiver_type != nullptr &&
call_site_attributes.receiver_type->HasTypeClass() &&
!Class::Handle(call_site_attributes.receiver_type->type_class())
.IsGeneric()) {
is_unchecked_call = true;
}
Fragment instructions(MakeTemp());
LocalVariable* variable = MakeTemporary();
const TokenPosition position = ReadPosition(); // read position.
if (p != nullptr) *p = position;
if (PeekTag() == kThisExpression) {
is_unchecked_call = true;
}
instructions += BuildExpression(); // read receiver.
LocalVariable* receiver = nullptr;
if (direct_call.check_receiver_for_null_) {
// Duplicate receiver for CheckNull before it is consumed by PushArgument.
receiver = MakeTemporary();
instructions += LoadLocal(receiver);
}
const String& setter_name = ReadNameAsSetterName(); // read name.
instructions += BuildExpression(); // read value.
instructions += StoreLocal(TokenPosition::kNoSource, variable);
const Function* interface_target = &Function::null_function();
const NameIndex itarget_name =
ReadInterfaceMemberNameReference(); // read interface_target_reference.
if (!H.IsRoot(itarget_name)) {
interface_target = &Function::ZoneHandle(
Z,
H.LookupMethodByMember(itarget_name, H.DartSetterName(itarget_name)));
ASSERT(setter_name.ptr() == interface_target->name());
}
if (direct_call.check_receiver_for_null_) {
instructions += CheckNull(position, receiver, setter_name);
}
const String* mangled_name = &setter_name;
const Function* direct_call_target = &direct_call.target_;
if (H.IsRoot(itarget_name)) {
mangled_name = &String::ZoneHandle(
Z, Function::CreateDynamicInvocationForwarderName(setter_name));
if (!direct_call_target->IsNull()) {
direct_call_target = &Function::ZoneHandle(
direct_call.target_.GetDynamicInvocationForwarder(*mangled_name));
}
}
if (!direct_call_target->IsNull()) {
ASSERT(CompilerState::Current().is_aot());
instructions +=
StaticCall(position, *direct_call_target, 2, Array::null_array(),
ICData::kNoRebind, /*result_type=*/nullptr,
/*type_args_count=*/0,
/*use_unchecked_entry=*/is_unchecked_call);
} else {
const intptr_t kTypeArgsLen = 0;
const intptr_t kNumArgsChecked = 1;
instructions += InstanceCall(
position, *mangled_name, Token::kSET, kTypeArgsLen, 2,
Array::null_array(), kNumArgsChecked, *interface_target,
Function::null_function(),
/*result_type=*/nullptr,
/*use_unchecked_entry=*/is_unchecked_call, &call_site_attributes);
}
instructions += Drop(); // Drop result of the setter invocation.
if (direct_call.check_receiver_for_null_) {
instructions += Drop(); // Drop receiver.
}
return instructions;
}
Fragment StreamingFlowGraphBuilder::BuildInstanceSet(TokenPosition* p) {
const intptr_t offset = ReaderOffset() - 1; // Include the tag.
ReadByte(); // read kind.
@ -3020,19 +2849,12 @@ Fragment StreamingFlowGraphBuilder::BuildStaticSet(TokenPosition* p) {
}
Fragment StreamingFlowGraphBuilder::BuildMethodInvocation(TokenPosition* p,
Tag tag) {
ASSERT((tag == kMethodInvocation) || (tag == kInstanceInvocation) ||
(tag == kDynamicInvocation));
bool is_dynamic) {
const intptr_t offset = ReaderOffset() - 1; // Include the tag.
if ((tag == kInstanceInvocation) || (tag == kDynamicInvocation)) {
ReadByte(); // read kind.
}
ReadByte(); // read kind.
// read flags.
const uint8_t flags =
((tag == kMethodInvocation) || (tag == kInstanceInvocation)) ? ReadFlags()
: 0;
const uint8_t flags = is_dynamic ? 0 : ReadFlags();
const bool is_invariant = (flags & kMethodInvocationFlagInvariant) != 0;
const TokenPosition position = ReadPosition(); // read position.
@ -3047,22 +2869,13 @@ Fragment StreamingFlowGraphBuilder::BuildMethodInvocation(TokenPosition* p,
const Tag receiver_tag = PeekTag(); // peek tag for receiver.
bool is_unchecked_closure_call = false;
bool is_unchecked_call = is_invariant || result_type.IsSkipCheck();
if (call_site_attributes.receiver_type != nullptr) {
if ((tag == kMethodInvocation) &&
call_site_attributes.receiver_type->IsFunctionType()) {
AlternativeReadingScope alt(&reader_);
SkipExpression(); // skip receiver
is_unchecked_closure_call =
ReadNameAsMethodName().Equals(Symbols::Call());
} else if ((tag != kDynamicInvocation) &&
call_site_attributes.receiver_type->HasTypeClass() &&
!call_site_attributes.receiver_type->IsDynamicType() &&
!Class::Handle(call_site_attributes.receiver_type->type_class())
.IsGeneric()) {
is_unchecked_call = true;
}
if (!is_dynamic && (call_site_attributes.receiver_type != nullptr) &&
call_site_attributes.receiver_type->HasTypeClass() &&
!call_site_attributes.receiver_type->IsDynamicType() &&
!Class::Handle(call_site_attributes.receiver_type->type_class())
.IsGeneric()) {
is_unchecked_call = true;
}
Fragment instructions;
@ -3079,7 +2892,7 @@ Fragment StreamingFlowGraphBuilder::BuildMethodInvocation(TokenPosition* p,
const TypeArguments& type_arguments =
T.BuildTypeArguments(list_length); // read types.
instructions += TranslateInstantiatedTypeArguments(type_arguments);
if (direct_call.check_receiver_for_null_ || is_unchecked_closure_call) {
if (direct_call.check_receiver_for_null_) {
// Don't yet push type arguments if we need to check receiver for null.
// In this case receiver will be duplicated so instead of pushing
// type arguments here we need to push it between receiver_temp
@ -3092,7 +2905,7 @@ Fragment StreamingFlowGraphBuilder::BuildMethodInvocation(TokenPosition* p,
// Take note of whether the invocation is against the receiver of the current
// function: in this case, we may skip some type checks in the callee.
if ((PeekTag() == kThisExpression) && (tag != kDynamicInvocation)) {
if ((PeekTag() == kThisExpression) && !is_dynamic) {
is_unchecked_call = true;
}
instructions += BuildExpression(); // read receiver.
@ -3119,7 +2932,7 @@ Fragment StreamingFlowGraphBuilder::BuildMethodInvocation(TokenPosition* p,
}
LocalVariable* receiver_temp = NULL;
if (direct_call.check_receiver_for_null_ || is_unchecked_closure_call) {
if (direct_call.check_receiver_for_null_) {
// Duplicate receiver for CheckNull before it is consumed by PushArgument.
receiver_temp = MakeTemporary();
if (type_arguments_temp != NULL) {
@ -3149,15 +2962,14 @@ Fragment StreamingFlowGraphBuilder::BuildMethodInvocation(TokenPosition* p,
checked_argument_count = argument_count;
}
if (tag == kInstanceInvocation) {
if (!is_dynamic) {
SkipDartType(); // read function_type.
}
const Function* interface_target = &Function::null_function();
// read interface_target_reference.
const NameIndex itarget_name =
((tag == kMethodInvocation) || (tag == kInstanceInvocation))
? ReadInterfaceMemberNameReference()
: NameIndex(); // read interface_target_reference.
is_dynamic ? NameIndex() : ReadInterfaceMemberNameReference();
// TODO(dartbug.com/34497): Once front-end desugars calls via
// fields/getters, filtering of field and getter interface targets here
// can be turned into assertions.
@ -3169,12 +2981,9 @@ Fragment StreamingFlowGraphBuilder::BuildMethodInvocation(TokenPosition* p,
ASSERT(!interface_target->IsGetterFunction());
}
// TODO(sjindel): Avoid the check for null on unchecked closure calls if TFA
// allows.
if (direct_call.check_receiver_for_null_ || is_unchecked_closure_call) {
// Receiver temp is needed to load the function to call from the closure.
if (direct_call.check_receiver_for_null_) {
instructions += CheckNull(position, receiver_temp, name,
/*clear_temp=*/!is_unchecked_closure_call);
/*clear_temp=*/true);
}
const String* mangled_name = &name;
@ -3193,19 +3002,7 @@ Fragment StreamingFlowGraphBuilder::BuildMethodInvocation(TokenPosition* p,
}
}
if (is_unchecked_closure_call) {
// Lookup the function in the closure.
instructions += LoadLocal(receiver_temp);
if (!FLAG_precompiled_mode || !FLAG_use_bare_instructions) {
instructions += LoadNativeField(Slot::Closure_function());
}
if (parsed_function()->function().is_debuggable()) {
ASSERT(!parsed_function()->function().is_native());
instructions += DebugStepCheck(position);
}
instructions +=
B->ClosureCall(position, type_args_len, argument_count, argument_names);
} else if (!direct_call_target->IsNull()) {
if (!direct_call_target->IsNull()) {
// Even if TFA infers a concrete receiver type, the static type of the
// call-site may still be dynamic and we need to call the dynamic invocation
// forwarder to ensure type-checks are performed.

View file

@ -274,12 +274,10 @@ class StreamingFlowGraphBuilder : public KernelReaderHelper {
Fragment BuildVariableSet(uint8_t payload, TokenPosition* position);
Fragment BuildVariableSetImpl(TokenPosition position,
intptr_t variable_kernel_position);
Fragment BuildPropertyGet(TokenPosition* position);
Fragment BuildInstanceGet(TokenPosition* position);
Fragment BuildDynamicGet(TokenPosition* position);
Fragment BuildInstanceTearOff(TokenPosition* position);
Fragment BuildFunctionTearOff(TokenPosition* position);
Fragment BuildPropertySet(TokenPosition* position);
Fragment BuildInstanceSet(TokenPosition* position);
Fragment BuildDynamicSet(TokenPosition* position);
Fragment BuildAllocateInvocationMirrorCall(TokenPosition position,
@ -293,7 +291,7 @@ class StreamingFlowGraphBuilder : public KernelReaderHelper {
Fragment BuildSuperPropertySet(TokenPosition* position);
Fragment BuildStaticGet(TokenPosition* position);
Fragment BuildStaticSet(TokenPosition* position);
Fragment BuildMethodInvocation(TokenPosition* position, Tag tag);
Fragment BuildMethodInvocation(TokenPosition* position, bool is_dynamic);
Fragment BuildLocalFunctionInvocation(TokenPosition* position);
Fragment BuildFunctionInvocation(TokenPosition* position);
Fragment BuildEqualsCall(TokenPosition* position);

View file

@ -373,12 +373,6 @@ void KernelFingerprintHelper::CalculateExpressionFingerprint() {
ReadUInt(); // read kernel position.
CalculateExpressionFingerprint(); // read expression.
return;
case kPropertyGet:
ReadPosition(); // read position.
CalculateExpressionFingerprint(); // read receiver.
BuildHash(ReadNameAsGetterName().Hash()); // read name.
CalculateGetterNameFingerprint(); // read interface_target_reference.
return;
case kInstanceGet:
ReadByte(); // read kind.
ReadPosition(); // read position.
@ -405,13 +399,6 @@ void KernelFingerprintHelper::CalculateExpressionFingerprint() {
ReadPosition(); // read position.
CalculateExpressionFingerprint(); // read receiver.
return;
case kPropertySet:
ReadPosition(); // read position.
CalculateExpressionFingerprint(); // read receiver.
BuildHash(ReadNameAsSetterName().Hash()); // read name.
CalculateExpressionFingerprint(); // read value.
CalculateSetterNameFingerprint(); // read interface_target_reference.
return;
case kInstanceSet:
ReadByte(); // read kind.
ReadPosition(); // read position.
@ -447,14 +434,6 @@ void KernelFingerprintHelper::CalculateExpressionFingerprint() {
CalculateCanonicalNameFingerprint(); // read target_reference.
CalculateExpressionFingerprint(); // read expression.
return;
case kMethodInvocation:
ReadFlags(); // read flags.
ReadPosition(); // read position.
CalculateExpressionFingerprint(); // read receiver.
BuildHash(ReadNameAsMethodName().Hash()); // read name.
CalculateArgumentsFingerprint(); // read arguments.
CalculateMethodNameFingerprint(); // read interface_target_reference.
return;
case kInstanceInvocation:
ReadByte(); // read kind.
ReadFlags(); // read flags.

View file

@ -2320,12 +2320,6 @@ void KernelReaderHelper::SkipExpression() {
ReadUInt(); // read kernel position.
SkipExpression(); // read expression.
return;
case kPropertyGet:
ReadPosition(); // read position.
SkipExpression(); // read receiver.
SkipName(); // read name.
SkipInterfaceMemberNameReference(); // read interface_target_reference.
return;
case kInstanceGet:
ReadByte(); // read kind.
ReadPosition(); // read position.
@ -2352,13 +2346,6 @@ void KernelReaderHelper::SkipExpression() {
ReadPosition(); // read position.
SkipExpression(); // read receiver.
return;
case kPropertySet:
ReadPosition(); // read position.
SkipExpression(); // read receiver.
SkipName(); // read name.
SkipExpression(); // read value.
SkipInterfaceMemberNameReference(); // read interface_target_reference.
return;
case kInstanceSet:
ReadByte(); // read kind.
ReadPosition(); // read position.
@ -2394,14 +2381,6 @@ void KernelReaderHelper::SkipExpression() {
SkipCanonicalNameReference(); // read target_reference.
SkipExpression(); // read expression.
return;
case kMethodInvocation:
ReadFlags(); // read flags.
ReadPosition(); // read position.
SkipExpression(); // read receiver.
SkipName(); // read name.
SkipArguments(); // read arguments.
SkipInterfaceMemberNameReference(); // read interface_target_reference.
return;
case kInstanceInvocation:
ReadByte(); // read kind.
ReadFlags(); // read flags.

View file

@ -686,13 +686,6 @@ void ScopeBuilder::VisitExpression() {
VisitExpression(); // read expression.
return;
}
case kPropertyGet:
helper_.ReadPosition(); // read position.
VisitExpression(); // read receiver.
helper_.SkipName(); // read name.
// read interface_target_reference.
helper_.SkipInterfaceMemberNameReference();
return;
case kInstanceGet:
helper_.ReadByte(); // read kind.
helper_.ReadPosition(); // read position.
@ -721,14 +714,6 @@ void ScopeBuilder::VisitExpression() {
helper_.ReadPosition(); // read position.
VisitExpression(); // read receiver.
return;
case kPropertySet:
helper_.ReadPosition(); // read position.
VisitExpression(); // read receiver.
helper_.SkipName(); // read name.
VisitExpression(); // read value.
// read interface_target_reference.
helper_.SkipInterfaceMemberNameReference();
return;
case kInstanceSet:
helper_.ReadByte(); // read kind.
helper_.ReadPosition(); // read position.
@ -767,15 +752,6 @@ void ScopeBuilder::VisitExpression() {
helper_.SkipCanonicalNameReference(); // read target_reference.
VisitExpression(); // read expression.
return;
case kMethodInvocation:
helper_.ReadFlags(); // read flags.
helper_.ReadPosition(); // read position.
VisitExpression(); // read receiver.
helper_.SkipName(); // read name.
VisitArguments(); // read arguments.
// read interface_target_reference.
helper_.SkipInterfaceMemberNameReference();
return;
case kInstanceInvocation:
helper_.ReadByte(); // read kind.
helper_.ReadFlags(); // read flags.