[kernel,vm] First-class kernel serialization of FutureOrType and NullType

TEST=ci
Fixes https://github.com/dart-lang/sdk/issues/52565

Change-Id: I9906f2d10c7ed51d11a0c402b51c8189ac3b6298
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/306901
Commit-Queue: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Chloe Stefantsova <cstefantsova@google.com>
Reviewed-by: Ryan Macnak <rmacnak@google.com>
This commit is contained in:
Alexander Markov 2023-06-05 21:24:35 +00:00 committed by Commit Queue
parent 8d29829271
commit 5ff0821b27
14 changed files with 509 additions and 471 deletions

View file

@ -147,7 +147,7 @@ type CanonicalName {
type ComponentFile {
UInt32 magic = 0x90ABCDEF;
UInt32 formatVersion = 102;
UInt32 formatVersion = 103;
Byte[10] shortSdkHash;
List<String> problemsAsJson; // Described in problems.md.
Library[] libraries;
@ -1540,6 +1540,10 @@ type VoidType extends DartType {
Byte tag = 92;
}
type NullType extends DartType {
Byte tag = 152;
}
type InterfaceType extends DartType {
Byte tag = 93;
Byte nullability; // Index into the Nullability enum above.
@ -1633,6 +1637,12 @@ type TypedefType {
List<DartType> typeArguments;
}
type FutureOrType extends DartType {
Byte tag = 107;
Byte nullability; // Index into the Nullability enum above.
DartType typeArgument;
}
type TypeParameter {
// Note: there is no tag on TypeParameter
Byte flags (isCovariantByClass);

View file

@ -3817,6 +3817,8 @@ class BinaryBuilder {
return _readInvalidType();
case Tag.NeverType:
return _readNeverType();
case Tag.NullType:
return _readNullType();
case Tag.InlineType:
return _readInlineType();
case Tag.FunctionType:
@ -3825,6 +3827,8 @@ class BinaryBuilder {
return _readIntersectionType();
case Tag.RecordType:
return _readRecordType();
case Tag.FutureOrType:
return _readFutureOrType();
default:
throw fail('unexpected dart type tag: $tag');
}
@ -3853,19 +3857,14 @@ class BinaryBuilder {
return NeverType.fromNullability(Nullability.values[nullabilityIndex]);
}
DartType _readNullType() {
return const NullType();
}
DartType _readInterfaceType() {
int nullabilityIndex = readByte();
Reference reference = readNonNullClassReference();
List<DartType> typeArguments = readDartTypeList();
CanonicalName? canonicalName = reference.canonicalName;
if (canonicalName != null &&
canonicalName.name == "FutureOr" &&
canonicalName.parent!.name == "dart:async" &&
canonicalName.parent!.parent != null &&
canonicalName.parent!.parent!.isRoot) {
return new FutureOrType(
typeArguments.single, Nullability.values[nullabilityIndex]);
}
return new InterfaceType.byReference(
reference, Nullability.values[nullabilityIndex], typeArguments);
}
@ -3879,15 +3878,6 @@ class BinaryBuilder {
throw 'Expected a class reference to be valid but was `null`.';
}
// We check this before the cache to not return a wrong cached value for
// this special case.
if (!forSupertype &&
canonicalName.name == "Null" &&
canonicalName.parent!.name == "dart:core" &&
canonicalName.parent!.parent!.isRoot) {
return const NullType();
}
// Check cache.
final int cacheIndex =
(classReferenceIndex - 1) * Nullability.values.length +
@ -3905,6 +3895,12 @@ class BinaryBuilder {
return result;
}
DartType _readFutureOrType() {
int nullabilityIndex = readByte();
DartType typeArgument = readDartType();
return new FutureOrType(typeArgument, Nullability.values[nullabilityIndex]);
}
DartType _readInlineType() {
int nullabilityIndex = readByte();
Reference reference = readNonNullInlineClassReference();

View file

@ -2477,38 +2477,14 @@ class BinaryPrinter implements Visitor<void>, BinarySink {
@override
void visitFutureOrType(FutureOrType node) {
// TODO(cstefantsova): Remove special treatment of FutureOr when the VM
// supports the new encoding: just write the tag.
assert(_knownCanonicalNameNonRootTops.isNotEmpty);
CanonicalName root = _knownCanonicalNameNonRootTops.first;
while (!root.isRoot) {
root = root.parent!;
}
CanonicalName canonicalNameOfFutureOr =
root.getChild("dart:async").getChild("FutureOr");
writeByte(Tag.InterfaceType);
writeByte(Tag.FutureOrType);
writeByte(node.declaredNullability.index);
checkCanonicalName(canonicalNameOfFutureOr);
writeUInt30(canonicalNameOfFutureOr.index + 1);
writeUInt30(1); // Type argument count.
writeNode(node.typeArgument);
}
@override
void visitNullType(NullType node) {
// TODO(cstefantsova): Remove special treatment of Null when the VM
// supports the new encoding: just write the tag.
assert(_knownCanonicalNameNonRootTops.isNotEmpty);
CanonicalName root = _knownCanonicalNameNonRootTops.first;
while (!root.isRoot) {
root = root.parent!;
}
CanonicalName canonicalNameOfNull =
root.getChild("dart:core").getChild("Null");
writeByte(Tag.SimpleInterfaceType);
writeByte(node.declaredNullability.index);
checkCanonicalName(canonicalNameOfNull);
writeUInt30(canonicalNameOfNull.index + 1);
writeByte(Tag.NullType);
}
@override

View file

@ -158,6 +158,7 @@ class Tag {
// 104 is occupied by [RecordLiteral] (expression).
// 105 is occupied by [ConstRecordLiteral] (expression).
// 106 is occupied by [ConstantExpression].
static const int FutureOrType = 107;
// 108 is occupied by [RedirectingFactory] (member).
// 109 is occupied by [SetLiteral] (expression).
@ -206,6 +207,8 @@ class Tag {
static const int PatternAssignment = 150;
static const int PatternVariableDeclaration = 151;
static const int NullType = 152;
static const int SpecializedTagHighBits = 0xE0; // 0b11100000
static const int SpecializedTagMask = 0xF8; // 0b11111000
static const int SpecializedPayloadMask = 0x7; // 0b00000111
@ -222,7 +225,7 @@ class Tag {
/// Internal version of kernel binary format.
/// Bump it when making incompatible changes in kernel binaries.
/// Keep in sync with runtime/vm/kernel_binary.h, pkg/kernel/binary.md.
static const int BinaryFormatVersion = 102;
static const int BinaryFormatVersion = 103;
}
abstract class ConstantTag {

View file

@ -233,6 +233,7 @@ void KernelFingerprintHelper::CalculateDartTypeFingerprint() {
case kInvalidType:
case kDynamicType:
case kVoidType:
case kNullType:
// those contain nothing.
break;
case kNeverType:
@ -280,6 +281,10 @@ void KernelFingerprintHelper::CalculateDartTypeFingerprint() {
CalculateDartTypeFingerprint(); // read instantiated representation type.
break;
}
case kFutureOrType:
BuildHash(static_cast<uint32_t>(ReadNullability()));
CalculateDartTypeFingerprint(); // read type argument.
break;
default:
ReportUnexpectedTag("type", tag);
UNREACHABLE();

View file

@ -2244,6 +2244,7 @@ void KernelReaderHelper::SkipDartType() {
case kInvalidType:
case kDynamicType:
case kVoidType:
case kNullType:
// those contain nothing.
return;
case kNeverType:
@ -2292,6 +2293,10 @@ void KernelReaderHelper::SkipDartType() {
SkipDartType(); // read left.
SkipDartType(); // read right.
return;
case kFutureOrType:
ReadNullability();
SkipDartType(); // read type argument.
break;
default:
ReportUnexpectedTag("type", tag);
UNREACHABLE();
@ -3205,6 +3210,9 @@ void TypeTranslator::BuildTypeInternal() {
.ToNullability(nullability, Heap::kOld);
break;
}
case kNullType:
result_ = IG->object_store()->null_type();
break;
case kInterfaceType:
BuildInterfaceType(false);
break;
@ -3229,6 +3237,9 @@ void TypeTranslator::BuildTypeInternal() {
case kInlineType:
BuildInlineType();
break;
case kFutureOrType:
BuildFutureOrType();
break;
default:
helper_->ReportUnexpectedTag("type", tag);
UNREACHABLE();
@ -3275,6 +3286,27 @@ void TypeTranslator::BuildInterfaceType(bool simple) {
}
}
void TypeTranslator::BuildFutureOrType() {
Nullability nullability = helper_->ReadNullability();
if (apply_canonical_type_erasure_ && nullability != Nullability::kNullable) {
nullability = Nullability::kLegacy;
}
const TypeArguments& type_arguments =
TypeArguments::Handle(Z, TypeArguments::New(1));
BuildTypeInternal(); // read type argument.
type_arguments.SetTypeAt(0, result_);
const Class& klass = Class::Handle(Z, IG->object_store()->future_or_class());
ASSERT(!klass.IsNull());
result_ = Type::New(klass, type_arguments, nullability);
result_ = result_.NormalizeFutureOrType(Heap::kOld);
if (finalize_) {
result_ = ClassFinalizer::FinalizeType(result_);
}
}
void TypeTranslator::BuildFunctionType(bool simple) {
const intptr_t num_enclosing_type_arguments =
active_class_->enclosing != nullptr

View file

@ -1576,6 +1576,7 @@ class TypeTranslator {
void BuildTypeParameterType();
void BuildIntersectionType();
void BuildInlineType();
void BuildFutureOrType();
class TypeParameterScope {
public:

View file

@ -1375,6 +1375,7 @@ void ScopeBuilder::VisitDartType() {
case kInvalidType:
case kDynamicType:
case kVoidType:
case kNullType:
// those contain nothing.
return;
case kNeverType:
@ -1404,6 +1405,9 @@ void ScopeBuilder::VisitDartType() {
case kInlineType:
VisitInlineType();
return;
case kFutureOrType:
VisitFutureOrType();
return;
default:
ReportUnexpectedTag("type", tag);
UNREACHABLE();
@ -1525,6 +1529,11 @@ void ScopeBuilder::VisitInlineType() {
VisitDartType(); // read instantiated representation type.
}
void ScopeBuilder::VisitFutureOrType() {
helper_.ReadNullability();
VisitDartType(); // read type argument.
}
void ScopeBuilder::HandleLocalFunction(intptr_t parent_kernel_offset) {
// "Peek" ahead into the function node
const intptr_t offset = helper_.ReaderOffset();

View file

@ -52,6 +52,7 @@ class ScopeBuilder {
void VisitTypeParameterType();
void VisitIntersectionType();
void VisitInlineType();
void VisitFutureOrType();
void HandleLocalFunction(intptr_t parent_kernel_offset);
AbstractType& BuildAndVisitVariableType();

View file

@ -132,7 +132,7 @@ namespace dart {
0xc40903ac) \
V(_SuspendState, _clone, SuspendState_clone, 0xae1a40a0) \
V(_SuspendState, _createAsyncCallbacks, SuspendState_createAsyncCallbacks, \
0x5e84c091) \
0x86343257) \
V(_SuspendState, _createAsyncStarCallback, \
SuspendState_createAsyncStarCallback, 0x98fb897c) \
V(_SuspendState, _resume, SuspendState_resume, 0x5d7a8489) \
@ -319,10 +319,10 @@ namespace dart {
V(::, _getNativeField, GetNativeField, 0xa0139b85) \
V(::, reachabilityFence, ReachabilityFence, 0x730f2b7f) \
V(_Utf8Decoder, _scan, Utf8DecoderScan, 0xb99d2ee1) \
V(_Future, timeout, FutureTimeout, 0xe21f0bf8) \
V(Future, wait, FutureWait, 0x22f98225) \
V(_Future, timeout, FutureTimeout, 0xa0f743d4) \
V(Future, wait, FutureWait, 0x295fe957) \
V(_RootZone, runUnary, RootZoneRunUnary, 0x64397ecb) \
V(_FutureListener, handleValue, FutureListenerHandleValue, 0xbf5d3892) \
V(_FutureListener, handleValue, FutureListenerHandleValue, 0xec25d1b2) \
V(::, has63BitSmis, Has63BitSmis, 0xf61b56f1) \
V(::, get:extensionStreamHasListener, ExtensionStreamHasListener, 0xfab46343)\
V(_Smi, get:hashCode, Smi_hashCode, 0x75e0ccd2) \

File diff suppressed because it is too large Load diff

View file

@ -18,7 +18,7 @@ namespace kernel {
// package:kernel/binary.md.
static const uint32_t kMagicProgramFile = 0x90ABCDEFu;
static const uint32_t kSupportedKernelFormatVersion = 102;
static const uint32_t kSupportedKernelFormatVersion = 103;
// Keep in sync with package:kernel/lib/binary/tag.dart
#define KERNEL_TAG_LIST(V) \
@ -136,6 +136,7 @@ static const uint32_t kSupportedKernelFormatVersion = 102;
V(RecordType, 100) \
V(InlineType, 103) \
V(ConstantExpression, 106) \
V(FutureOrType, 107) \
V(InstanceGet, 118) \
V(InstanceSet, 119) \
V(InstanceInvocation, 120) \
@ -171,6 +172,7 @@ static const uint32_t kSupportedKernelFormatVersion = 102;
V(IfCaseStatement, 149) \
V(PatternAssignment, 150) \
V(PatternVariableDeclaration, 151) \
V(NullType, 152) \
V(SpecializedVariableGet, 224) \
V(SpecializedVariableSet, 232) \
V(SpecializedIntLiteral, 240)

View file

@ -2123,6 +2123,7 @@ ErrorPtr Object::Init(IsolateGroup* isolate_group,
cls.set_num_type_arguments_unsafe(1);
RegisterClass(cls, Symbols::FutureOr(), lib);
pending_classes.Add(cls);
object_store->set_future_or_class(cls);
cls = Class::New<SuspendState, RTN::SuspendState>(isolate_group);
RegisterPrivateClass(cls, Symbols::_SuspendState(), lib);
@ -2674,6 +2675,7 @@ ErrorPtr Object::Init(IsolateGroup* isolate_group,
cls = Class::New<MirrorReference, RTN::MirrorReference>(isolate_group);
cls = Class::New<UserTag, RTN::UserTag>(isolate_group);
cls = Class::New<FutureOr, RTN::FutureOr>(isolate_group);
object_store->set_future_or_class(cls);
cls = Class::New<TransferableTypedData, RTN::TransferableTypedData>(
isolate_group);
}

View file

@ -114,6 +114,7 @@ class ObjectPointerVisitor;
RW(Field, pragma_name) \
RW(Field, pragma_options) \
RW(Class, future_class) \
RW(Class, future_or_class) \
RW(Class, completer_class) \
RW(Class, one_byte_string_class) \
RW(Class, two_byte_string_class) \