blob: 263bb15edf0f843e879563925a1e6794f294a2a7 [file] [log] [blame]
// 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 'package:vm/transformations/type_flow/types.dart' show RecordShape;
enum UnboxingKind {
boxed,
int,
double,
record,
unknown, // Not calculated yet.
}
class UnboxingType {
final UnboxingKind kind;
final RecordShape? recordShape;
const UnboxingType._(this.kind, this.recordShape);
UnboxingType.record(RecordShape shape) : this._(UnboxingKind.record, shape);
static const kUnknown = UnboxingType._(UnboxingKind.unknown, null);
static const kInt = UnboxingType._(UnboxingKind.int, null);
static const kDouble = UnboxingType._(UnboxingKind.double, null);
static const kBoxed = UnboxingType._(UnboxingKind.boxed, null);
UnboxingType intersect(UnboxingType other) {
if (kind == UnboxingKind.unknown) return other;
if (other.kind == UnboxingKind.unknown) return this;
if (this == other) return this;
return kBoxed;
}
@override
bool operator ==(other) =>
identical(this, other) ||
(other is UnboxingType &&
this.kind == other.kind &&
this.recordShape == other.recordShape);
@override
int get hashCode => (kind.index * 31) + recordShape.hashCode;
void writeToBinary(BinarySink sink) {
sink.writeUInt30(kind.index);
if (kind == UnboxingKind.record) {
recordShape!.writeToBinary(sink);
}
}
factory UnboxingType.readFromBinary(BinarySource source) {
final kind = UnboxingKind.values[source.readUInt30()];
final recordShape = (kind == UnboxingKind.record)
? RecordShape.readFromBinary(source)
: null;
return UnboxingType._(kind, recordShape);
}
@override
String toString() {
switch (kind) {
case UnboxingKind.boxed:
return 'b';
case UnboxingKind.int:
return 'i';
case UnboxingKind.double:
return 'd';
case UnboxingKind.record:
{
final sb = StringBuffer();
sb.write('r<');
sb.write(recordShape!.numPositionalFields.toString());
for (final named in recordShape!.namedFields) {
sb.write(',');
sb.write(named);
}
sb.write('>');
return sb.toString();
}
case UnboxingKind.unknown:
throw 'Unexpected UnboxingType.kUknown';
}
}
}
class UnboxingInfoMetadata {
final List<UnboxingType> argsInfo;
UnboxingType returnInfo;
UnboxingInfoMetadata(int argsLen)
: argsInfo = List<UnboxingType>.filled(argsLen, UnboxingType.kUnknown,
growable: true),
returnInfo = UnboxingType.kUnknown;
UnboxingInfoMetadata.readFromBinary(BinarySource source)
: argsInfo = List<UnboxingType>.generate(
source.readUInt30(), (_) => UnboxingType.readFromBinary(source),
growable: true),
returnInfo = UnboxingType.readFromBinary(source);
// Returns `true` if all arguments as well as the return value have to be
// boxed.
//
// We don't have to write out metadata for fully boxed methods, because this
// is the default.
bool get isFullyBoxed {
if (returnInfo != UnboxingType.kBoxed) return false;
for (final argInfo in argsInfo) {
if (argInfo != UnboxingType.kBoxed) return false;
}
return true;
}
void writeToBinary(BinarySink sink) {
sink.writeUInt30(argsInfo.length);
for (final argInfo in argsInfo) {
argInfo.writeToBinary(sink);
}
returnInfo.writeToBinary(sink);
}
@override
String toString() {
final sb = StringBuffer();
sb.write('(');
for (int i = 0; i < argsInfo.length; ++i) {
final argInfo = argsInfo[i];
sb.write(argInfo.toString());
if (i != (argsInfo.length - 1)) {
sb.write(',');
}
}
sb.write(')');
sb.write('->');
sb.write(returnInfo.toString());
return sb.toString();
}
}
class UnboxingInfoMetadataRepository
extends MetadataRepository<UnboxingInfoMetadata> {
static const repositoryTag = 'vm.unboxing-info.metadata';
@override
final String tag = repositoryTag;
@override
final Map<TreeNode, UnboxingInfoMetadata> mapping =
<TreeNode, UnboxingInfoMetadata>{};
@override
void writeToBinary(
UnboxingInfoMetadata metadata, Node node, BinarySink sink) {
metadata.writeToBinary(sink);
}
@override
UnboxingInfoMetadata readFromBinary(Node node, BinarySource source) {
return UnboxingInfoMetadata.readFromBinary(source);
}
}