blob: d6441dffd7c74a92762cc050bc8ca1ab4cf97828 [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.inferred_type;
import 'package:kernel/ast.dart';
import 'package:kernel/src/printer.dart';
/// Metadata for annotating nodes with an inferred type information.
class InferredType {
final Reference _concreteClassReference;
final Constant _constantValue;
final int _flags;
static const int flagNullable = 1 << 0;
static const int flagInt = 1 << 1;
// For invocations: whether to use the unchecked entry-point.
static const int flagSkipCheck = 1 << 2;
static const int flagConstant = 1 << 3;
static const int flagReceiverNotInt = 1 << 4;
// Entire list may be null if no type arguments were inferred.
// Will always be null if `concreteClass` is null.
//
// Each component may be null if that particular type argument was not
// inferred.
//
// Otherwise, a non-null type argument indicates that that particular type
// argument (in the runtime type) is always exactly a particular `DartType`.
final List<DartType> exactTypeArguments;
InferredType(
Class concreteClass, bool nullable, bool isInt, Constant constantValue,
{List<DartType> exactTypeArguments,
bool skipCheck: false,
bool receiverNotInt: false})
: this._byReference(
getClassReference(concreteClass),
constantValue,
(nullable ? flagNullable : 0) |
(isInt ? flagInt : 0) |
(skipCheck ? flagSkipCheck : 0) |
(constantValue != null ? flagConstant : 0) |
(receiverNotInt ? flagReceiverNotInt : 0),
exactTypeArguments);
InferredType._byReference(this._concreteClassReference, this._constantValue,
this._flags, this.exactTypeArguments) {
assert(exactTypeArguments == null || _concreteClassReference != null);
assert(_constantValue == null || _concreteClassReference != null);
}
Class get concreteClass => _concreteClassReference?.asClass;
Constant get constantValue => _constantValue;
bool get nullable => (_flags & flagNullable) != 0;
bool get isInt => (_flags & flagInt) != 0;
bool get skipCheck => (_flags & flagSkipCheck) != 0;
bool get receiverNotInt => (_flags & flagReceiverNotInt) != 0;
int get flags => _flags;
@override
String toString() {
final StringBuffer buf = new StringBuffer();
if (concreteClass != null) {
buf.write(concreteClass.toText(astTextStrategyForTesting));
} else if (isInt) {
buf.write('int');
} else {
buf.write('!');
}
if (nullable) {
buf.write('?');
}
if (exactTypeArguments != null) {
buf.write('<');
buf.write(exactTypeArguments
.map(
(t) => t != null ? "${t.toText(astTextStrategyForTesting)}" : "?")
.join(", "));
buf.write('>');
}
if (skipCheck) {
buf.write(' (skip check)');
}
if (_constantValue != null) {
buf.write(
' (value: ${_constantValue.toText(astTextStrategyForTesting)})');
}
if (receiverNotInt) {
buf.write(' (receiver not int)');
}
return buf.toString();
}
}
/// Repository for [InferredType].
class InferredTypeMetadataRepository extends MetadataRepository<InferredType> {
static const String repositoryTag = 'vm.inferred-type.metadata';
@override
String get tag => repositoryTag;
@override
final Map<TreeNode, InferredType> mapping = <TreeNode, InferredType>{};
@override
void writeToBinary(InferredType metadata, Node node, BinarySink sink) {
// TODO(sjindel/tfa): Implement serialization of type arguments when can use
// them for optimizations.
sink.writeNullAllowedCanonicalNameReference(
getCanonicalNameOfClass(metadata.concreteClass));
sink.writeByte(metadata._flags);
if (metadata.constantValue != null) {
sink.writeConstantReference(metadata.constantValue);
}
}
@override
InferredType readFromBinary(Node node, BinarySource source) {
// TODO(sjindel/tfa): Implement serialization of type arguments when can use
// them for optimizations.
final concreteClassReference =
source.readCanonicalNameReference()?.getReference();
final flags = source.readByte();
final constantValue = (flags & InferredType.flagConstant) != 0
? source.readConstantReference()
: null;
return new InferredType._byReference(
concreteClassReference, constantValue, flags, null);
}
}