@@ -681,6 +681,57 @@ size_t FileWriter::Write(const EnvSerializeInfo& data) {
681
681
return written_total;
682
682
}
683
683
684
+ // Layout of SnapshotMetadata
685
+ // [ 1 byte ] type of the snapshot
686
+ // [ 4/8 bytes ] length of the node version string
687
+ // [ ... ] |length| bytes of node version
688
+ // [ 4/8 bytes ] length of the node arch string
689
+ // [ ... ] |length| bytes of node arch
690
+ // [ 4/8 bytes ] length of the node platform string
691
+ // [ ... ] |length| bytes of node platform
692
+ // [ 4 bytes ] v8 cache version tag
693
+ template <>
694
+ SnapshotMetadata FileReader::Read () {
695
+ per_process::Debug (DebugCategory::MKSNAPSHOT, " Read<SnapshotMetadata>()\n " );
696
+
697
+ SnapshotMetadata result;
698
+ result.type = static_cast <SnapshotMetadata::Type>(Read<uint8_t >());
699
+ result.node_version = ReadString ();
700
+ result.node_arch = ReadString ();
701
+ result.node_platform = ReadString ();
702
+ result.v8_cache_version_tag = Read<uint32_t >();
703
+
704
+ if (is_debug) {
705
+ std::string str = ToStr (result);
706
+ Debug (" Read<SnapshotMetadata>() %s\n " , str.c_str ());
707
+ }
708
+ return result;
709
+ }
710
+
711
+ template <>
712
+ size_t FileWriter::Write (const SnapshotMetadata& data) {
713
+ if (is_debug) {
714
+ std::string str = ToStr (data);
715
+ Debug (" \n Write<SnapshotMetadata>() %s\n " , str.c_str ());
716
+ }
717
+ size_t written_total = 0 ;
718
+ // We need the Node.js version, platform and arch to match because
719
+ // Node.js may perform synchronizations that are platform-specific and they
720
+ // can be changed in semver-patches.
721
+ Debug (" Write snapshot type %" PRIu8 " \n " , static_cast <uint8_t >(data.type ));
722
+ written_total += Write<uint8_t >(static_cast <uint8_t >(data.type ));
723
+ Debug (" Write Node.js version %s\n " , data.node_version .c_str ());
724
+ written_total += WriteString (data.node_version );
725
+ Debug (" Write Node.js arch %s\n " , data.node_arch );
726
+ written_total += WriteString (data.node_arch );
727
+ Debug (" Write Node.js platform %s\n " , data.node_platform );
728
+ written_total += WriteString (data.node_platform );
729
+ Debug (" Write V8 cached data version tag %" PRIx32 " \n " ,
730
+ data.v8_cache_version_tag );
731
+ written_total += Write<uint32_t >(data.v8_cache_version_tag );
732
+ return written_total;
733
+ }
734
+
684
735
// Layout of the snapshot blob
685
736
// [ 4 bytes ] kMagic
686
737
// [ 4/8 bytes ] length of Node.js version string
@@ -697,13 +748,12 @@ void SnapshotData::ToBlob(FILE* out) const {
697
748
w.Debug (" SnapshotData::ToBlob()\n " );
698
749
699
750
size_t written_total = 0 ;
751
+
700
752
// Metadata
701
753
w.Debug (" Write magic %" PRIx32 " \n " , kMagic );
702
754
written_total += w.Write <uint32_t >(kMagic );
703
- w.Debug (" Write version %s\n " , NODE_VERSION);
704
- written_total += w.WriteString (NODE_VERSION);
705
- w.Debug (" Write arch %s\n " , NODE_ARCH);
706
- written_total += w.WriteString (NODE_ARCH);
755
+ w.Debug (" Write metadata\n " );
756
+ written_total += w.Write <SnapshotMetadata>(metadata);
707
757
708
758
written_total += w.Write <v8::StartupData>(v8_snapshot_blob_data);
709
759
w.Debug (" Write isolate_data_indices\n " );
@@ -714,22 +764,22 @@ void SnapshotData::ToBlob(FILE* out) const {
714
764
w.Debug (" SnapshotData::ToBlob() Wrote %d bytes\n " , written_total);
715
765
}
716
766
717
- void SnapshotData::FromBlob (SnapshotData* out, FILE* in) {
767
+ bool SnapshotData::FromBlob (SnapshotData* out, FILE* in) {
718
768
FileReader r (in);
719
769
r.Debug (" SnapshotData::FromBlob()\n " );
720
770
771
+ DCHECK_EQ (out->data_ownership , SnapshotData::DataOwnership::kOwned );
772
+
721
773
// Metadata
722
774
uint32_t magic = r.Read <uint32_t >();
723
- r.Debug (" Read magic %" PRIx64 " \n " , magic);
775
+ r.Debug (" Read magic %" PRIx32 " \n " , magic);
724
776
CHECK_EQ (magic, kMagic );
725
- std::string version = r.ReadString ();
726
- r.Debug (" Read version %s\n " , version.c_str ());
727
- CHECK_EQ (version, NODE_VERSION);
728
- std::string arch = r.ReadString ();
729
- r.Debug (" Read arch %s\n " , arch.c_str ());
730
- CHECK_EQ (arch, NODE_ARCH);
777
+ out->metadata = r.Read <SnapshotMetadata>();
778
+ r.Debug (" Read metadata\n " );
779
+ if (!out->Check ()) {
780
+ return false ;
781
+ }
731
782
732
- DCHECK_EQ (out->data_ownership , SnapshotData::DataOwnership::kOwned );
733
783
out->v8_snapshot_blob_data = r.Read <v8::StartupData>();
734
784
r.Debug (" Read isolate_data_info\n " );
735
785
out->isolate_data_info = r.Read <IsolateDataSerializeInfo>();
@@ -738,6 +788,54 @@ void SnapshotData::FromBlob(SnapshotData* out, FILE* in) {
738
788
out->code_cache = r.ReadVector <builtins::CodeCacheInfo>();
739
789
740
790
r.Debug (" SnapshotData::FromBlob() read %d bytes\n " , r.read_total );
791
+ return true ;
792
+ }
793
+
794
+ bool SnapshotData::Check () const {
795
+ if (metadata.node_version != per_process::metadata.versions .node ) {
796
+ fprintf (stderr,
797
+ " Failed to load the startup snapshot because it was built with"
798
+ " Node.js version %s and the current Node.js version is %s.\n " ,
799
+ metadata.node_version .c_str (),
800
+ NODE_VERSION);
801
+ return false ;
802
+ }
803
+
804
+ if (metadata.node_arch != per_process::metadata.arch ) {
805
+ fprintf (stderr,
806
+ " Failed to load the startup snapshot because it was built with"
807
+ " architecture %s and the architecture is %s.\n " ,
808
+ metadata.node_arch .c_str (),
809
+ NODE_ARCH);
810
+ return false ;
811
+ }
812
+
813
+ if (metadata.node_platform != per_process::metadata.platform ) {
814
+ fprintf (stderr,
815
+ " Failed to load the startup snapshot because it was built with"
816
+ " platform %s and the current platform is %s.\n " ,
817
+ metadata.node_platform .c_str (),
818
+ NODE_PLATFORM);
819
+ return false ;
820
+ }
821
+
822
+ uint32_t current_cache_version = v8::ScriptCompiler::CachedDataVersionTag ();
823
+ if (metadata.v8_cache_version_tag != current_cache_version &&
824
+ metadata.type == SnapshotMetadata::Type::kFullyCustomized ) {
825
+ // For now we only do this check for the customized snapshots - we know
826
+ // that the flags we use in the default snapshot are limited and safe
827
+ // enough so we can relax the constraints for it.
828
+ fprintf (stderr,
829
+ " Failed to load the startup snapshot because it was built with "
830
+ " a different version of V8 or with different V8 configurations.\n "
831
+ " Expected tag %" PRIx32 " , read %" PRIx32 " \n " ,
832
+ current_cache_version,
833
+ metadata.v8_cache_version_tag );
834
+ return false ;
835
+ }
836
+
837
+ // TODO(joyeecheung): check incompatible Node.js flags.
838
+ return true ;
741
839
}
742
840
743
841
SnapshotData::~SnapshotData () {
@@ -824,6 +922,10 @@ static const int v8_snapshot_blob_size = )"
824
922
// -- data_ownership begins --
825
923
SnapshotData::DataOwnership::kNotOwned,
826
924
// -- data_ownership ends --
925
+ // -- metadata begins --
926
+ )" << data->metadata
927
+ << R"( ,
928
+ // -- metadata ends --
827
929
// -- v8_snapshot_blob_data begins --
828
930
{ v8_snapshot_blob_data, v8_snapshot_blob_size },
829
931
// -- v8_snapshot_blob_data ends --
@@ -920,6 +1022,12 @@ int SnapshotBuilder::Generate(SnapshotData* out,
920
1022
per_process::v8_platform.Platform ()->UnregisterIsolate (isolate);
921
1023
});
922
1024
1025
+ // It's only possible to be kDefault in node_mksnapshot.
1026
+ SnapshotMetadata::Type snapshot_type =
1027
+ per_process::cli_options->build_snapshot
1028
+ ? SnapshotMetadata::Type::kFullyCustomized
1029
+ : SnapshotMetadata::Type::kDefault ;
1030
+
923
1031
{
924
1032
HandleScope scope (isolate);
925
1033
TryCatch bootstrapCatch (isolate);
@@ -982,7 +1090,7 @@ int SnapshotBuilder::Generate(SnapshotData* out,
982
1090
// point (we currently only support this kind of entry point, but we
983
1091
// could also explore snapshotting other kinds of execution modes
984
1092
// in the future).
985
- if (per_process::cli_options-> build_snapshot ) {
1093
+ if (snapshot_type == SnapshotMetadata::Type:: kFullyCustomized ) {
986
1094
#if HAVE_INSPECTOR
987
1095
// TODO(joyeecheung): move this before RunBootstrapping().
988
1096
env->InitializeInspector ({});
@@ -1050,6 +1158,12 @@ int SnapshotBuilder::Generate(SnapshotData* out,
1050
1158
return SNAPSHOT_ERROR;
1051
1159
}
1052
1160
1161
+ out->metadata = SnapshotMetadata{snapshot_type,
1162
+ per_process::metadata.versions .node ,
1163
+ per_process::metadata.arch ,
1164
+ per_process::metadata.platform ,
1165
+ v8::ScriptCompiler::CachedDataVersionTag ()};
1166
+
1053
1167
// We cannot resurrect the handles from the snapshot, so make sure that
1054
1168
// no handles are left open in the environment after the blob is created
1055
1169
// (which should trigger a GC and close all handles that can be closed).
0 commit comments