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