mirror of
https://github.com/dart-lang/sdk
synced 2024-10-14 17:56:11 +00:00
[vm/nnbd] Add separate Snapshot::Kind for core snapshots
Core snapshots should be agnostic to the sound null safety mode (so they can be used both in weak and strong modes), and snapshot writer verifies that. Snapshot::kFull was previously used both for core snapshots and app snapshots on ia32. However, app snapshots are not guaranteed to be agnostic, which appeared as failures on a few test on ia32. Also, VM should be able to detect null safety mode from app snapshots, even if they do not contain code, but null safety mode was not written into features string of kFull snapshots. In order to disambiguate core snapshots, a new Snapshot::Kind is added. Snapshot::kFullCore works exactly as Snapshot::kFull, except for verification of agnostic null safety and snapshot features string omitting null safety mode. All snapshots except kFullCore now have null safety mode included into their features string. Fixes https://github.com/dart-lang/sdk/issues/43626 Issue https://github.com/dart-lang/sdk/issues/43613 Change-Id: I8cd3b049ef4e428dd5e1ce666d4c7aa3b596d70c Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/166308 Reviewed-by: Régis Crelier <regis@google.com> Commit-Queue: Alexander Markov <alexmarkov@google.com>
This commit is contained in:
parent
c21b906182
commit
d77fff7307
|
@ -446,7 +446,8 @@ static void CreateAndWriteCoreSnapshot() {
|
|||
// First create a snapshot.
|
||||
result = Dart_CreateSnapshot(&vm_snapshot_data_buffer, &vm_snapshot_data_size,
|
||||
&isolate_snapshot_data_buffer,
|
||||
&isolate_snapshot_data_size);
|
||||
&isolate_snapshot_data_size,
|
||||
/*is_core=*/true);
|
||||
CHECK_RESULT(result);
|
||||
|
||||
// Now write the vm isolate and isolate snapshots out to the
|
||||
|
@ -539,7 +540,7 @@ static void CreateAndWriteAppSnapshot() {
|
|||
intptr_t isolate_snapshot_data_size = 0;
|
||||
|
||||
result = Dart_CreateSnapshot(NULL, NULL, &isolate_snapshot_data_buffer,
|
||||
&isolate_snapshot_data_size);
|
||||
&isolate_snapshot_data_size, /*is_core=*/false);
|
||||
CHECK_RESULT(result);
|
||||
|
||||
WriteFile(isolate_snapshot_data_filename, isolate_snapshot_data_buffer,
|
||||
|
|
|
@ -489,8 +489,8 @@ void Snapshot::GenerateAppJIT(const char* snapshot_filename) {
|
|||
uint8_t* isolate_buffer = NULL;
|
||||
intptr_t isolate_size = 0;
|
||||
|
||||
Dart_Handle result =
|
||||
Dart_CreateSnapshot(NULL, NULL, &isolate_buffer, &isolate_size);
|
||||
Dart_Handle result = Dart_CreateSnapshot(NULL, NULL, &isolate_buffer,
|
||||
&isolate_size, /*is_core=*/false);
|
||||
if (Dart_IsError(result)) {
|
||||
ErrorExit(kErrorExitCode, "%s\n", Dart_GetError(result));
|
||||
}
|
||||
|
|
|
@ -1242,6 +1242,8 @@ DART_EXPORT void Dart_ExitIsolate();
|
|||
* snapshot. This buffer is scope allocated and is only valid
|
||||
* until the next call to Dart_ExitScope.
|
||||
* \param size Returns the size of the buffer.
|
||||
* \param is_core Create a snapshot containing core libraries.
|
||||
* Such snapshot should be agnostic to null safety mode.
|
||||
*
|
||||
* \return A valid handle if no error occurs during the operation.
|
||||
*/
|
||||
|
@ -1249,7 +1251,8 @@ DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle
|
|||
Dart_CreateSnapshot(uint8_t** vm_snapshot_data_buffer,
|
||||
intptr_t* vm_snapshot_data_size,
|
||||
uint8_t** isolate_snapshot_data_buffer,
|
||||
intptr_t* isolate_snapshot_data_size);
|
||||
intptr_t* isolate_snapshot_data_size,
|
||||
bool is_core);
|
||||
|
||||
/**
|
||||
* Returns whether the buffer contains a kernel file.
|
||||
|
|
|
@ -528,12 +528,12 @@ BENCHMARK_SIZE(CoreSnapshotSize) {
|
|||
MallocWriteStream vm_snapshot_data(FullSnapshotWriter::kInitialSize);
|
||||
MallocWriteStream isolate_snapshot_data(FullSnapshotWriter::kInitialSize);
|
||||
FullSnapshotWriter writer(
|
||||
Snapshot::kFull, &vm_snapshot_data, &isolate_snapshot_data,
|
||||
Snapshot::kFullCore, &vm_snapshot_data, &isolate_snapshot_data,
|
||||
/*vm_image_writer=*/nullptr, /*iso_image_writer=*/nullptr);
|
||||
writer.WriteFullSnapshot();
|
||||
const Snapshot* snapshot =
|
||||
Snapshot::SetupFromBuffer(isolate_snapshot_data.buffer());
|
||||
ASSERT(snapshot->kind() == Snapshot::kFull);
|
||||
ASSERT(snapshot->kind() == Snapshot::kFullCore);
|
||||
benchmark->set_score(snapshot->length());
|
||||
}
|
||||
|
||||
|
@ -566,12 +566,12 @@ BENCHMARK_SIZE(StandaloneSnapshotSize) {
|
|||
MallocWriteStream vm_snapshot_data(FullSnapshotWriter::kInitialSize);
|
||||
MallocWriteStream isolate_snapshot_data(FullSnapshotWriter::kInitialSize);
|
||||
FullSnapshotWriter writer(
|
||||
Snapshot::kFull, &vm_snapshot_data, &isolate_snapshot_data,
|
||||
Snapshot::kFullCore, &vm_snapshot_data, &isolate_snapshot_data,
|
||||
/*vm_image_writer=*/nullptr, /*iso_image_writer=*/nullptr);
|
||||
writer.WriteFullSnapshot();
|
||||
const Snapshot* snapshot =
|
||||
Snapshot::SetupFromBuffer(isolate_snapshot_data.buffer());
|
||||
ASSERT(snapshot->kind() == Snapshot::kFull);
|
||||
ASSERT(snapshot->kind() == Snapshot::kFullCore);
|
||||
benchmark->set_score(snapshot->length());
|
||||
}
|
||||
|
||||
|
|
|
@ -245,7 +245,8 @@ class ClassSerializationCluster : public SerializationCluster {
|
|||
s->UnexpectedObject(cls, "Class with illegal cid");
|
||||
}
|
||||
s->WriteCid(class_id);
|
||||
if (s->kind() == Snapshot::kFull && RequireLegacyErasureOfConstants(cls)) {
|
||||
if (s->kind() == Snapshot::kFullCore &&
|
||||
RequireLegacyErasureOfConstants(cls)) {
|
||||
s->UnexpectedObject(cls, "Class with non mode agnostic constants");
|
||||
}
|
||||
if (s->kind() != Snapshot::kFullAOT) {
|
||||
|
@ -596,7 +597,7 @@ class FunctionSerializationCluster : public SerializationCluster {
|
|||
objects_.Add(func);
|
||||
|
||||
PushFromTo(func);
|
||||
if (kind == Snapshot::kFull) {
|
||||
if ((kind == Snapshot::kFull) || (kind == Snapshot::kFullCore)) {
|
||||
NOT_IN_PRECOMPILED(s->Push(func->ptr()->bytecode_));
|
||||
} else if (kind == Snapshot::kFullAOT) {
|
||||
s->Push(func->ptr()->code_);
|
||||
|
@ -625,7 +626,7 @@ class FunctionSerializationCluster : public SerializationCluster {
|
|||
FunctionPtr func = objects_[i];
|
||||
AutoTraceObjectName(func, MakeDisambiguatedFunctionName(s, func));
|
||||
WriteFromTo(func);
|
||||
if (kind == Snapshot::kFull) {
|
||||
if ((kind == Snapshot::kFull) || (kind == Snapshot::kFullCore)) {
|
||||
NOT_IN_PRECOMPILED(WriteField(func, bytecode_));
|
||||
} else if (kind == Snapshot::kFullAOT) {
|
||||
WriteField(func, code_);
|
||||
|
@ -692,7 +693,7 @@ class FunctionDeserializationCluster : public DeserializationCluster {
|
|||
Function::InstanceSize());
|
||||
ReadFromTo(func);
|
||||
|
||||
if (kind == Snapshot::kFull) {
|
||||
if ((kind == Snapshot::kFull) || (kind == Snapshot::kFullCore)) {
|
||||
NOT_IN_PRECOMPILED(func->ptr()->bytecode_ =
|
||||
static_cast<BytecodePtr>(d->ReadRef()));
|
||||
} else if (kind == Snapshot::kFullAOT) {
|
||||
|
|
|
@ -782,12 +782,12 @@ bool Dart::DetectNullSafety(const char* script_uri,
|
|||
// when generating the snapshot.
|
||||
ASSERT(FLAG_sound_null_safety == kNullSafetyOptionUnspecified);
|
||||
|
||||
// If snapshot is an appJIT/AOT snapshot we will figure out the mode by
|
||||
// If snapshot is not a core snapshot we will figure out the mode by
|
||||
// sniffing the feature string in the snapshot.
|
||||
if (snapshot_data != nullptr) {
|
||||
// Read the snapshot and check for null safety option.
|
||||
const Snapshot* snapshot = Snapshot::SetupFromBuffer(snapshot_data);
|
||||
if (Snapshot::IncludesCode(snapshot->kind())) {
|
||||
if (!Snapshot::IsAgnosticToNullSafety(snapshot->kind())) {
|
||||
return SnapshotHeaderReader::NullSafetyFromSnapshot(snapshot);
|
||||
}
|
||||
}
|
||||
|
@ -1034,7 +1034,9 @@ const char* Dart::FeaturesString(Isolate* isolate,
|
|||
#else
|
||||
#error What architecture?
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!Snapshot::IsAgnosticToNullSafety(kind)) {
|
||||
if (isolate != NULL) {
|
||||
if (isolate->null_safety()) {
|
||||
buffer.AddString(" null-safety");
|
||||
|
|
|
@ -1934,7 +1934,8 @@ DART_EXPORT Dart_Handle
|
|||
Dart_CreateSnapshot(uint8_t** vm_snapshot_data_buffer,
|
||||
intptr_t* vm_snapshot_data_size,
|
||||
uint8_t** isolate_snapshot_data_buffer,
|
||||
intptr_t* isolate_snapshot_data_size) {
|
||||
intptr_t* isolate_snapshot_data_size,
|
||||
bool is_core) {
|
||||
#if defined(DART_PRECOMPILED_RUNTIME)
|
||||
return Api::NewError("Cannot create snapshots on an AOT runtime.");
|
||||
#else
|
||||
|
@ -1966,8 +1967,10 @@ Dart_CreateSnapshot(uint8_t** vm_snapshot_data_buffer,
|
|||
FullSnapshotWriter::kInitialSize);
|
||||
ZoneWriteStream isolate_snapshot_data(Api::TopScope(T)->zone(),
|
||||
FullSnapshotWriter::kInitialSize);
|
||||
const Snapshot::Kind snapshot_kind =
|
||||
is_core ? Snapshot::kFullCore : Snapshot::kFull;
|
||||
FullSnapshotWriter writer(
|
||||
Snapshot::kFull, &vm_snapshot_data, &isolate_snapshot_data,
|
||||
snapshot_kind, &vm_snapshot_data, &isolate_snapshot_data,
|
||||
nullptr /* vm_image_writer */, nullptr /* isolate_image_writer */);
|
||||
writer.WriteFullSnapshot();
|
||||
if (vm_snapshot_data_buffer != nullptr) {
|
||||
|
|
|
@ -479,6 +479,7 @@ class ObjectStore {
|
|||
ObjectPtr* to_snapshot(Snapshot::Kind kind) {
|
||||
switch (kind) {
|
||||
case Snapshot::kFull:
|
||||
case Snapshot::kFullCore:
|
||||
return reinterpret_cast<ObjectPtr*>(&global_object_pool_);
|
||||
case Snapshot::kFullJIT:
|
||||
case Snapshot::kFullAOT:
|
||||
|
|
|
@ -762,6 +762,7 @@ class ClassLayout : public ObjectLayout {
|
|||
case Snapshot::kFullAOT:
|
||||
return reinterpret_cast<ObjectPtr*>(&allocation_stub_);
|
||||
case Snapshot::kFull:
|
||||
case Snapshot::kFullCore:
|
||||
return reinterpret_cast<ObjectPtr*>(&direct_subclasses_);
|
||||
case Snapshot::kFullJIT:
|
||||
return reinterpret_cast<ObjectPtr*>(&dependent_code_);
|
||||
|
@ -836,6 +837,7 @@ class PatchClassLayout : public ObjectLayout {
|
|||
case Snapshot::kFullAOT:
|
||||
return reinterpret_cast<ObjectPtr*>(&script_);
|
||||
case Snapshot::kFull:
|
||||
case Snapshot::kFullCore:
|
||||
case Snapshot::kFullJIT:
|
||||
return reinterpret_cast<ObjectPtr*>(&library_kernel_data_);
|
||||
case Snapshot::kMessage:
|
||||
|
@ -1026,6 +1028,7 @@ class FunctionLayout : public ObjectLayout {
|
|||
switch (kind) {
|
||||
case Snapshot::kFullAOT:
|
||||
case Snapshot::kFull:
|
||||
case Snapshot::kFullCore:
|
||||
case Snapshot::kFullJIT:
|
||||
return reinterpret_cast<ObjectPtr*>(&data_);
|
||||
case Snapshot::kMessage:
|
||||
|
@ -1194,6 +1197,7 @@ class FieldLayout : public ObjectLayout {
|
|||
ObjectPtr* to_snapshot(Snapshot::Kind kind) {
|
||||
switch (kind) {
|
||||
case Snapshot::kFull:
|
||||
case Snapshot::kFullCore:
|
||||
case Snapshot::kFullJIT:
|
||||
case Snapshot::kFullAOT:
|
||||
return reinterpret_cast<ObjectPtr*>(&initializer_function_);
|
||||
|
@ -1270,6 +1274,7 @@ class ScriptLayout : public ObjectLayout {
|
|||
case Snapshot::kFullAOT:
|
||||
return reinterpret_cast<ObjectPtr*>(&url_);
|
||||
case Snapshot::kFull:
|
||||
case Snapshot::kFullCore:
|
||||
case Snapshot::kFullJIT:
|
||||
return reinterpret_cast<ObjectPtr*>(&kernel_program_info_);
|
||||
case Snapshot::kMessage:
|
||||
|
@ -1343,6 +1348,7 @@ class LibraryLayout : public ObjectLayout {
|
|||
case Snapshot::kFullAOT:
|
||||
return reinterpret_cast<ObjectPtr*>(&exports_);
|
||||
case Snapshot::kFull:
|
||||
case Snapshot::kFullCore:
|
||||
case Snapshot::kFullJIT:
|
||||
return reinterpret_cast<ObjectPtr*>(&kernel_data_);
|
||||
case Snapshot::kMessage:
|
||||
|
@ -2067,6 +2073,7 @@ class ICDataLayout : public CallSiteDataLayout {
|
|||
case Snapshot::kFullAOT:
|
||||
return reinterpret_cast<ObjectPtr*>(&entries_);
|
||||
case Snapshot::kFull:
|
||||
case Snapshot::kFullCore:
|
||||
case Snapshot::kFullJIT:
|
||||
return to();
|
||||
case Snapshot::kMessage:
|
||||
|
@ -2174,6 +2181,7 @@ class LibraryPrefixLayout : public InstanceLayout {
|
|||
case Snapshot::kFullAOT:
|
||||
return reinterpret_cast<ObjectPtr*>(&imports_);
|
||||
case Snapshot::kFull:
|
||||
case Snapshot::kFullCore:
|
||||
case Snapshot::kFullJIT:
|
||||
return reinterpret_cast<ObjectPtr*>(&importer_);
|
||||
case Snapshot::kMessage:
|
||||
|
|
|
@ -229,6 +229,8 @@ const char* Snapshot::KindToCString(Kind kind) {
|
|||
switch (kind) {
|
||||
case kFull:
|
||||
return "full";
|
||||
case kFullCore:
|
||||
return "full-core";
|
||||
case kFullJIT:
|
||||
return "full-jit";
|
||||
case kFullAOT:
|
||||
|
|
|
@ -91,11 +91,12 @@ enum SerializeState {
|
|||
class Snapshot {
|
||||
public:
|
||||
enum Kind {
|
||||
kFull, // Full snapshot of core libraries or an application.
|
||||
kFullJIT, // Full + JIT code
|
||||
kFullAOT, // Full + AOT code
|
||||
kMessage, // A partial snapshot used only for isolate messaging.
|
||||
kNone, // gen_snapshot
|
||||
kFull, // Full snapshot of an application.
|
||||
kFullCore, // Full snapshot of core libraries. Agnostic to null safety.
|
||||
kFullJIT, // Full + JIT code
|
||||
kFullAOT, // Full + AOT code
|
||||
kMessage, // A partial snapshot used only for isolate messaging.
|
||||
kNone, // gen_snapshot
|
||||
kInvalid
|
||||
};
|
||||
static const char* KindToCString(Kind kind);
|
||||
|
@ -130,13 +131,15 @@ class Snapshot {
|
|||
void set_kind(Kind value) { return Write<int64_t>(kKindOffset, value); }
|
||||
|
||||
static bool IsFull(Kind kind) {
|
||||
return (kind == kFull) || (kind == kFullJIT) || (kind == kFullAOT);
|
||||
return (kind == kFull) || (kind == kFullCore) || (kind == kFullJIT) ||
|
||||
(kind == kFullAOT);
|
||||
}
|
||||
static bool IsAgnosticToNullSafety(Kind kind) { return (kind == kFullCore); }
|
||||
static bool IncludesCode(Kind kind) {
|
||||
return (kind == kFullJIT) || (kind == kFullAOT);
|
||||
}
|
||||
static bool IncludesBytecode(Kind kind) {
|
||||
return (kind == kFull) || (kind == kFullJIT);
|
||||
return (kind == kFull) || (kind == kFullCore) || (kind == kFullJIT);
|
||||
}
|
||||
|
||||
const uint8_t* Addr() const { return reinterpret_cast<const uint8_t*>(this); }
|
||||
|
@ -171,7 +174,8 @@ class Snapshot {
|
|||
inline static bool IsSnapshotCompatible(Snapshot::Kind vm_kind,
|
||||
Snapshot::Kind isolate_kind) {
|
||||
if (vm_kind == isolate_kind) return true;
|
||||
if (vm_kind == Snapshot::kFull && isolate_kind == Snapshot::kFullJIT)
|
||||
if (((vm_kind == Snapshot::kFull) || (vm_kind == Snapshot::kFullCore)) &&
|
||||
isolate_kind == Snapshot::kFullJIT)
|
||||
return true;
|
||||
return Snapshot::IsFull(isolate_kind);
|
||||
}
|
||||
|
|
|
@ -2073,7 +2073,8 @@ VM_UNIT_TEST_CASE(LegacyErasureDetectionInFullSnapshot) {
|
|||
// Write snapshot with object content.
|
||||
MallocWriteStream isolate_snapshot_data(FullSnapshotWriter::kInitialSize);
|
||||
FullSnapshotWriter writer(
|
||||
Snapshot::kFull, /*vm_snapshot_data=*/nullptr, &isolate_snapshot_data,
|
||||
Snapshot::kFullCore, /*vm_snapshot_data=*/nullptr,
|
||||
&isolate_snapshot_data,
|
||||
/*vm_image_writer=*/nullptr, /*iso_image_writer=*/nullptr);
|
||||
writer.WriteFullSnapshot();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue