[vm] Add more checks when packing nullability during serialization.

Also only shift as many bits as needed to fit nullability into the
serialized value in case additional type states or flags are added in
the future.

Change-Id: Ic821070971f77040e05d5aeb53a5a0ed85cc8d09
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/158180
Commit-Queue: Tess Strickland <sstrickl@google.com>
Reviewed-by: Ryan Macnak <rmacnak@google.com>
This commit is contained in:
Tess Strickland
2020-08-12 14:56:44 +00:00
committed by commit-bot@chromium.org
parent d5def62c9c
commit 41458ba4b1
3 changed files with 56 additions and 51 deletions
+45 -40
View File
@@ -3366,6 +3366,10 @@ class LibraryPrefixDeserializationCluster : public DeserializationCluster {
}
};
// Used to pack nullability into other serialized values.
static constexpr intptr_t kNullabilityBitSize = 2;
static constexpr intptr_t kNullabilityBitMask = (1 << kNullabilityBitSize) - 1;
#if !defined(DART_PRECOMPILED_RUNTIME)
class TypeSerializationCluster : public SerializationCluster {
public:
@@ -3412,31 +3416,31 @@ class TypeSerializationCluster : public SerializationCluster {
void WriteFill(Serializer* s) {
intptr_t count = canonical_objects_.length();
for (intptr_t i = 0; i < count; i++) {
TypePtr type = canonical_objects_[i];
AutoTraceObject(type);
WriteFromTo(type);
s->WriteTokenPosition(type->ptr()->token_pos_);
const uint8_t combined =
(type->ptr()->type_state_ << 4) | type->ptr()->nullability_;
ASSERT(type->ptr()->type_state_ == (combined >> 4));
ASSERT(type->ptr()->nullability_ == (combined & 0xf));
s->Write<uint8_t>(combined);
WriteType(s, canonical_objects_[i]);
}
count = objects_.length();
for (intptr_t i = 0; i < count; i++) {
TypePtr type = objects_[i];
AutoTraceObject(type);
WriteFromTo(type);
s->WriteTokenPosition(type->ptr()->token_pos_);
const uint8_t combined =
(type->ptr()->type_state_ << 4) | type->ptr()->nullability_;
ASSERT(type->ptr()->type_state_ == (combined >> 4));
ASSERT(type->ptr()->nullability_ == (combined & 0xf));
s->Write<uint8_t>(combined);
WriteType(s, objects_[i]);
}
}
private:
void WriteType(Serializer* s, TypePtr type) {
AutoTraceObject(type);
WriteFromTo(type);
s->WriteTokenPosition(type->ptr()->token_pos_);
ASSERT(type->ptr()->type_state_ < (1 << TypeLayout::kTypeStateBitSize));
ASSERT(type->ptr()->nullability_ < (1 << kNullabilityBitSize));
static_assert(TypeLayout::kTypeStateBitSize + kNullabilityBitSize <=
kBitsPerByte * sizeof(uint8_t),
"Cannot pack type_state_ and nullability_ into a uint8_t");
const uint8_t combined = (type->ptr()->type_state_ << kNullabilityBitSize) |
type->ptr()->nullability_;
ASSERT_EQUAL(type->ptr()->type_state_, combined >> kNullabilityBitSize);
ASSERT_EQUAL(type->ptr()->nullability_, combined & kNullabilityBitMask);
s->Write<uint8_t>(combined);
}
GrowableArray<TypePtr> canonical_objects_;
GrowableArray<TypePtr> objects_;
};
@@ -3468,26 +3472,12 @@ class TypeDeserializationCluster : public DeserializationCluster {
for (intptr_t id = canonical_start_index_; id < canonical_stop_index_;
id++) {
TypePtr type = static_cast<TypePtr>(d->Ref(id));
bool is_canonical = true;
Deserializer::InitializeHeader(type, kTypeCid, Type::InstanceSize(),
is_canonical);
ReadFromTo(type);
type->ptr()->token_pos_ = d->ReadTokenPosition();
const uint8_t combined = d->Read<uint8_t>();
type->ptr()->type_state_ = combined >> 4;
type->ptr()->nullability_ = combined & 0xf;
ReadType(d, type, /*is_canonical=*/true);
}
for (intptr_t id = start_index_; id < stop_index_; id++) {
TypePtr type = static_cast<TypePtr>(d->Ref(id));
bool is_canonical = false;
Deserializer::InitializeHeader(type, kTypeCid, Type::InstanceSize(),
is_canonical);
ReadFromTo(type);
type->ptr()->token_pos_ = d->ReadTokenPosition();
const uint8_t combined = d->Read<uint8_t>();
type->ptr()->type_state_ = combined >> 4;
type->ptr()->nullability_ = combined & 0xf;
ReadType(d, type, /*is_canonical=*/false);
}
}
@@ -3523,6 +3513,16 @@ class TypeDeserializationCluster : public DeserializationCluster {
}
private:
void ReadType(Deserializer* d, TypePtr type, bool is_canonical) {
Deserializer::InitializeHeader(type, kTypeCid, Type::InstanceSize(),
is_canonical);
ReadFromTo(type);
type->ptr()->token_pos_ = d->ReadTokenPosition();
const uint8_t combined = d->Read<uint8_t>();
type->ptr()->type_state_ = combined >> kNullabilityBitSize;
type->ptr()->nullability_ = combined & kNullabilityBitMask;
}
intptr_t canonical_start_index_;
intptr_t canonical_stop_index_;
};
@@ -3659,10 +3659,15 @@ class TypeParameterSerializationCluster : public SerializationCluster {
s->Write<int32_t>(type->ptr()->parameterized_class_id_);
s->WriteTokenPosition(type->ptr()->token_pos_);
s->Write<int16_t>(type->ptr()->index_);
const uint8_t combined =
(type->ptr()->flags_ << 4) | type->ptr()->nullability_;
ASSERT(type->ptr()->flags_ == (combined >> 4));
ASSERT(type->ptr()->nullability_ == (combined & 0xf));
ASSERT(type->ptr()->flags_ < (1 << TypeParameterLayout::kFlagsBitSize));
ASSERT(type->ptr()->nullability_ < (1 << kNullabilityBitSize));
static_assert(TypeParameterLayout::kFlagsBitSize + kNullabilityBitSize <=
kBitsPerByte * sizeof(uint8_t),
"Cannot pack flags_ and nullability_ into a uint8_t");
const uint8_t combined = (type->ptr()->flags_ << kNullabilityBitSize) |
type->ptr()->nullability_;
ASSERT_EQUAL(type->ptr()->flags_, combined >> kNullabilityBitSize);
ASSERT_EQUAL(type->ptr()->nullability_, combined & kNullabilityBitMask);
s->Write<uint8_t>(combined);
}
@@ -3752,8 +3757,8 @@ class TypeParameterDeserializationCluster : public DeserializationCluster {
type->ptr()->token_pos_ = d->ReadTokenPosition();
type->ptr()->index_ = d->Read<int16_t>();
const uint8_t combined = d->Read<uint8_t>();
type->ptr()->flags_ = combined >> 4;
type->ptr()->nullability_ = combined & 0xf;
type->ptr()->flags_ = combined >> kNullabilityBitSize;
type->ptr()->nullability_ = combined & kNullabilityBitMask;
}
intptr_t canonical_start_index_;
+1
View File
@@ -900,6 +900,7 @@ enum class Nullability : int8_t {
kNullable = 0,
kNonNullable = 1,
kLegacy = 2,
// Adjust kNullabilityBitSize in clustered_snapshot.cc if adding new values.
};
// Equality kind between types.
+10 -11
View File
@@ -2190,9 +2190,12 @@ class AbstractTypeLayout : public InstanceLayout {
kBeingFinalized, // In the process of being finalized.
kFinalizedInstantiated, // Instantiated type ready for use.
kFinalizedUninstantiated, // Uninstantiated type ready for use.
// Adjust kTypeStateBitSize if more are added.
};
protected:
static constexpr intptr_t kTypeStateBitSize = 2;
uword type_test_stub_entry_point_; // Accessed from generated code.
CodePtr type_test_stub_; // Must be the last field, since subclasses use it
// in their VISIT_FROM.
@@ -2237,17 +2240,6 @@ class TypeRefLayout : public AbstractTypeLayout {
};
class TypeParameterLayout : public AbstractTypeLayout {
public:
enum {
kFinalizedBit = 0,
kGenericCovariantImplBit,
kDeclarationBit,
};
class FinalizedBit : public BitField<uint8_t, bool, kFinalizedBit, 1> {};
class GenericCovariantImplBit
: public BitField<uint8_t, bool, kGenericCovariantImplBit, 1> {};
class DeclarationBit : public BitField<uint8_t, bool, kDeclarationBit, 1> {};
private:
RAW_HEAP_OBJECT_IMPLEMENTATION(TypeParameter);
@@ -2263,6 +2255,13 @@ class TypeParameterLayout : public AbstractTypeLayout {
uint8_t flags_;
int8_t nullability_;
using FinalizedBit = BitField<decltype(flags_), bool, 0, 1>;
using GenericCovariantImplBit =
BitField<decltype(flags_), bool, FinalizedBit::kNextBit, 1>;
using DeclarationBit =
BitField<decltype(flags_), bool, GenericCovariantImplBit::kNextBit, 1>;
static constexpr intptr_t kFlagsBitSize = DeclarationBit::kNextBit;
ObjectPtr* to_snapshot(Snapshot::Kind kind) { return to(); }
friend class CidRewriteVisitor;