blob: e49910a793838f2111e3f48cbd585a74c211629e [file] [log] [blame]
// Copyright (c) 2017, 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.
library vm.metadata.direct_call;
import 'package:kernel/ast.dart';
import 'package:kernel/src/printer.dart';
/// Metadata for annotating invocations converted to direct calls.
class DirectCallMetadata {
// Target of the direct call or enclosing member of a closure.
final Reference _memberReference;
final int _flags;
final int _closureId;
static const int flagCheckReceiverForNull = 1 << 0;
static const int flagClosure = 1 << 1;
DirectCallMetadata.targetMember(Member target, bool checkReceiverForNull)
: this._(getNonNullableMemberReferenceGetter(target),
checkReceiverForNull ? flagCheckReceiverForNull : 0, 0);
DirectCallMetadata.targetClosure(
Member closureMember, int closureId, bool checkReceiverForNull)
: this._(
getNonNullableMemberReferenceGetter(closureMember),
(checkReceiverForNull ? flagCheckReceiverForNull : 0) | flagClosure,
closureId);
DirectCallMetadata._(this._memberReference, this._flags, this._closureId)
: assert(_closureId >= 0);
// Target member or enclosing member of a closure.
Member get _member => _memberReference.asMember;
Member? get targetMember => isClosure ? null : _member;
bool get checkReceiverForNull => (_flags & flagCheckReceiverForNull) != 0;
bool get isClosure => (_flags & flagClosure) != 0;
@override
String toString() => isClosure
? 'closure ${_closureId} in ${_member.toText(astTextStrategyForTesting)}'
: '${_member.toText(astTextStrategyForTesting)}${checkReceiverForNull ? '??' : ''}';
}
/// Repository for [DirectCallMetadata].
class DirectCallMetadataRepository
extends MetadataRepository<DirectCallMetadata> {
static const repositoryTag = 'vm.direct-call.metadata';
@override
String get tag => repositoryTag;
@override
final Map<TreeNode, DirectCallMetadata> mapping =
<TreeNode, DirectCallMetadata>{};
@override
void writeToBinary(DirectCallMetadata metadata, Node node, BinarySink sink) {
sink.writeNullAllowedCanonicalNameReference(
getMemberReferenceGetter(metadata._member));
sink.writeByte(metadata._flags);
if (metadata.isClosure) {
sink.writeUInt30(metadata._closureId);
}
}
@override
DirectCallMetadata readFromBinary(Node node, BinarySource source) {
final memberReference =
source.readNullableCanonicalNameReference()?.reference;
if (memberReference == null) {
throw 'DirectCallMetadata should have a non-null member';
}
final flags = source.readByte();
final closureId =
(flags & DirectCallMetadata.flagClosure) != 0 ? source.readUInt30() : 0;
return DirectCallMetadata._(memberReference, flags, closureId);
}
}