| // Copyright (c) 2020, 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. |
| |
| import 'package:kernel/ast.dart'; |
| |
| import '../../metadata/procedure_attributes.dart'; |
| import '../../metadata/table_selector.dart'; |
| |
| // Assigns dispatch table selector IDs to interface targets. |
| // TODO(dartbug.com/40188): Implement a more fine-grained assignment based on |
| // hierarchy connectedness. |
| class TableSelectorAssigner { |
| final TableSelectorMetadata metadata = TableSelectorMetadata(); |
| |
| final Map<Name, int> _methodSelectorId = {}; |
| final Map<Name, int> _getterSelectorId = {}; |
| final Map<Name, int> _setterSelectorId = {}; |
| |
| int _selectorIdForMap(Map<Name, int> map, Member member) { |
| return map.putIfAbsent(member.name, () => metadata.addSelector()); |
| } |
| |
| int methodOrSetterSelectorId(Member member) { |
| if (member is Procedure) { |
| switch (member.kind) { |
| case ProcedureKind.Method: |
| case ProcedureKind.Operator: |
| return _selectorIdForMap(_methodSelectorId, member); |
| case ProcedureKind.Setter: |
| return _selectorIdForMap(_setterSelectorId, member); |
| case ProcedureKind.Getter: |
| return ProcedureAttributesMetadata.kInvalidSelectorId; |
| default: |
| throw "Unexpected procedure kind '${member.kind}'"; |
| } |
| } |
| if (member is Field) { |
| return _selectorIdForMap(_setterSelectorId, member); |
| } |
| throw "Unexpected member kind '${member.runtimeType}'"; |
| } |
| |
| int getterSelectorId(Member member) { |
| if (member is Procedure) { |
| switch (member.kind) { |
| case ProcedureKind.Getter: |
| case ProcedureKind.Method: |
| return _selectorIdForMap(_getterSelectorId, member); |
| case ProcedureKind.Operator: |
| case ProcedureKind.Setter: |
| return ProcedureAttributesMetadata.kInvalidSelectorId; |
| default: |
| throw "Unexpected procedure kind '${member.kind}'"; |
| } |
| } |
| if (member is Field) { |
| return _selectorIdForMap(_getterSelectorId, member); |
| } |
| throw "Unexpected member kind '${member.runtimeType}'"; |
| } |
| |
| void registerMethodOrSetterCall(Member member, bool calledOnNull) { |
| final TableSelectorInfo selector = |
| metadata.selectors[methodOrSetterSelectorId(member)]; |
| selector.callCount++; |
| selector.calledOnNull |= calledOnNull; |
| } |
| |
| void registerGetterCall(Member member, bool calledOnNull) { |
| final TableSelectorInfo selector = |
| metadata.selectors[getterSelectorId(member)]; |
| selector.callCount++; |
| selector.calledOnNull |= calledOnNull; |
| if (member is Procedure && member.kind == ProcedureKind.Method) { |
| final TableSelectorInfo methodSelector = |
| metadata.selectors[methodOrSetterSelectorId(member)]; |
| methodSelector.tornOff = true; |
| } |
| } |
| } |