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

View file

@ -3817,6 +3817,8 @@ class BinaryBuilder {
return _readInvalidType(); return _readInvalidType();
case Tag.NeverType: case Tag.NeverType:
return _readNeverType(); return _readNeverType();
case Tag.NullType:
return _readNullType();
case Tag.InlineType: case Tag.InlineType:
return _readInlineType(); return _readInlineType();
case Tag.FunctionType: case Tag.FunctionType:
@ -3825,6 +3827,8 @@ class BinaryBuilder {
return _readIntersectionType(); return _readIntersectionType();
case Tag.RecordType: case Tag.RecordType:
return _readRecordType(); return _readRecordType();
case Tag.FutureOrType:
return _readFutureOrType();
default: default:
throw fail('unexpected dart type tag: $tag'); throw fail('unexpected dart type tag: $tag');
} }
@ -3853,19 +3857,14 @@ class BinaryBuilder {
return NeverType.fromNullability(Nullability.values[nullabilityIndex]); return NeverType.fromNullability(Nullability.values[nullabilityIndex]);
} }
DartType _readNullType() {
return const NullType();
}
DartType _readInterfaceType() { DartType _readInterfaceType() {
int nullabilityIndex = readByte(); int nullabilityIndex = readByte();
Reference reference = readNonNullClassReference(); Reference reference = readNonNullClassReference();
List<DartType> typeArguments = readDartTypeList(); 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( return new InterfaceType.byReference(
reference, Nullability.values[nullabilityIndex], typeArguments); reference, Nullability.values[nullabilityIndex], typeArguments);
} }
@ -3879,15 +3878,6 @@ class BinaryBuilder {
throw 'Expected a class reference to be valid but was `null`.'; 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. // Check cache.
final int cacheIndex = final int cacheIndex =
(classReferenceIndex - 1) * Nullability.values.length + (classReferenceIndex - 1) * Nullability.values.length +
@ -3905,6 +3895,12 @@ class BinaryBuilder {
return result; return result;
} }
DartType _readFutureOrType() {
int nullabilityIndex = readByte();
DartType typeArgument = readDartType();
return new FutureOrType(typeArgument, Nullability.values[nullabilityIndex]);
}
DartType _readInlineType() { DartType _readInlineType() {
int nullabilityIndex = readByte(); int nullabilityIndex = readByte();
Reference reference = readNonNullInlineClassReference(); Reference reference = readNonNullInlineClassReference();

View file

@ -2477,38 +2477,14 @@ class BinaryPrinter implements Visitor<void>, BinarySink {
@override @override
void visitFutureOrType(FutureOrType node) { void visitFutureOrType(FutureOrType node) {
// TODO(cstefantsova): Remove special treatment of FutureOr when the VM writeByte(Tag.FutureOrType);
// 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(node.declaredNullability.index); writeByte(node.declaredNullability.index);
checkCanonicalName(canonicalNameOfFutureOr);
writeUInt30(canonicalNameOfFutureOr.index + 1);
writeUInt30(1); // Type argument count.
writeNode(node.typeArgument); writeNode(node.typeArgument);
} }
@override @override
void visitNullType(NullType node) { void visitNullType(NullType node) {
// TODO(cstefantsova): Remove special treatment of Null when the VM writeByte(Tag.NullType);
// 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);
} }
@override @override

View file

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

View file

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

View file

@ -2244,6 +2244,7 @@ void KernelReaderHelper::SkipDartType() {
case kInvalidType: case kInvalidType:
case kDynamicType: case kDynamicType:
case kVoidType: case kVoidType:
case kNullType:
// those contain nothing. // those contain nothing.
return; return;
case kNeverType: case kNeverType:
@ -2292,6 +2293,10 @@ void KernelReaderHelper::SkipDartType() {
SkipDartType(); // read left. SkipDartType(); // read left.
SkipDartType(); // read right. SkipDartType(); // read right.
return; return;
case kFutureOrType:
ReadNullability();
SkipDartType(); // read type argument.
break;
default: default:
ReportUnexpectedTag("type", tag); ReportUnexpectedTag("type", tag);
UNREACHABLE(); UNREACHABLE();
@ -3205,6 +3210,9 @@ void TypeTranslator::BuildTypeInternal() {
.ToNullability(nullability, Heap::kOld); .ToNullability(nullability, Heap::kOld);
break; break;
} }
case kNullType:
result_ = IG->object_store()->null_type();
break;
case kInterfaceType: case kInterfaceType:
BuildInterfaceType(false); BuildInterfaceType(false);
break; break;
@ -3229,6 +3237,9 @@ void TypeTranslator::BuildTypeInternal() {
case kInlineType: case kInlineType:
BuildInlineType(); BuildInlineType();
break; break;
case kFutureOrType:
BuildFutureOrType();
break;
default: default:
helper_->ReportUnexpectedTag("type", tag); helper_->ReportUnexpectedTag("type", tag);
UNREACHABLE(); 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) { void TypeTranslator::BuildFunctionType(bool simple) {
const intptr_t num_enclosing_type_arguments = const intptr_t num_enclosing_type_arguments =
active_class_->enclosing != nullptr active_class_->enclosing != nullptr

View file

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

View file

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

View file

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

View file

@ -132,7 +132,7 @@ namespace dart {
0xc40903ac) \ 0xc40903ac) \
V(_SuspendState, _clone, SuspendState_clone, 0xae1a40a0) \ V(_SuspendState, _clone, SuspendState_clone, 0xae1a40a0) \
V(_SuspendState, _createAsyncCallbacks, SuspendState_createAsyncCallbacks, \ V(_SuspendState, _createAsyncCallbacks, SuspendState_createAsyncCallbacks, \
0x5e84c091) \ 0x86343257) \
V(_SuspendState, _createAsyncStarCallback, \ V(_SuspendState, _createAsyncStarCallback, \
SuspendState_createAsyncStarCallback, 0x98fb897c) \ SuspendState_createAsyncStarCallback, 0x98fb897c) \
V(_SuspendState, _resume, SuspendState_resume, 0x5d7a8489) \ V(_SuspendState, _resume, SuspendState_resume, 0x5d7a8489) \
@ -319,10 +319,10 @@ namespace dart {
V(::, _getNativeField, GetNativeField, 0xa0139b85) \ V(::, _getNativeField, GetNativeField, 0xa0139b85) \
V(::, reachabilityFence, ReachabilityFence, 0x730f2b7f) \ V(::, reachabilityFence, ReachabilityFence, 0x730f2b7f) \
V(_Utf8Decoder, _scan, Utf8DecoderScan, 0xb99d2ee1) \ V(_Utf8Decoder, _scan, Utf8DecoderScan, 0xb99d2ee1) \
V(_Future, timeout, FutureTimeout, 0xe21f0bf8) \ V(_Future, timeout, FutureTimeout, 0xa0f743d4) \
V(Future, wait, FutureWait, 0x22f98225) \ V(Future, wait, FutureWait, 0x295fe957) \
V(_RootZone, runUnary, RootZoneRunUnary, 0x64397ecb) \ V(_RootZone, runUnary, RootZoneRunUnary, 0x64397ecb) \
V(_FutureListener, handleValue, FutureListenerHandleValue, 0xbf5d3892) \ V(_FutureListener, handleValue, FutureListenerHandleValue, 0xec25d1b2) \
V(::, has63BitSmis, Has63BitSmis, 0xf61b56f1) \ V(::, has63BitSmis, Has63BitSmis, 0xf61b56f1) \
V(::, get:extensionStreamHasListener, ExtensionStreamHasListener, 0xfab46343)\ V(::, get:extensionStreamHasListener, ExtensionStreamHasListener, 0xfab46343)\
V(_Smi, get:hashCode, Smi_hashCode, 0x75e0ccd2) \ 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. // package:kernel/binary.md.
static const uint32_t kMagicProgramFile = 0x90ABCDEFu; 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 // Keep in sync with package:kernel/lib/binary/tag.dart
#define KERNEL_TAG_LIST(V) \ #define KERNEL_TAG_LIST(V) \
@ -136,6 +136,7 @@ static const uint32_t kSupportedKernelFormatVersion = 102;
V(RecordType, 100) \ V(RecordType, 100) \
V(InlineType, 103) \ V(InlineType, 103) \
V(ConstantExpression, 106) \ V(ConstantExpression, 106) \
V(FutureOrType, 107) \
V(InstanceGet, 118) \ V(InstanceGet, 118) \
V(InstanceSet, 119) \ V(InstanceSet, 119) \
V(InstanceInvocation, 120) \ V(InstanceInvocation, 120) \
@ -171,6 +172,7 @@ static const uint32_t kSupportedKernelFormatVersion = 102;
V(IfCaseStatement, 149) \ V(IfCaseStatement, 149) \
V(PatternAssignment, 150) \ V(PatternAssignment, 150) \
V(PatternVariableDeclaration, 151) \ V(PatternVariableDeclaration, 151) \
V(NullType, 152) \
V(SpecializedVariableGet, 224) \ V(SpecializedVariableGet, 224) \
V(SpecializedVariableSet, 232) \ V(SpecializedVariableSet, 232) \
V(SpecializedIntLiteral, 240) V(SpecializedIntLiteral, 240)

View file

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

View file

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