1
1
2
2
#include " node_snapshotable.h"
3
+ #include < fstream>
3
4
#include < iostream>
4
5
#include < sstream>
5
6
#include < vector>
@@ -711,13 +712,6 @@ SnapshotData::~SnapshotData() {
711
712
}
712
713
}
713
714
714
- template <typename T>
715
- void WriteVector (std::ostream* ss, const T* vec, size_t size) {
716
- for (size_t i = 0 ; i < size; i++) {
717
- *ss << std::to_string (vec[i]) << (i == size - 1 ? ' \n ' : ' ,' );
718
- }
719
- }
720
-
721
715
static std::string GetCodeCacheDefName (const std::string& id) {
722
716
char buf[64 ] = {0 };
723
717
size_t size = id.size ();
@@ -742,48 +736,71 @@ static std::string FormatSize(size_t size) {
742
736
return buf;
743
737
}
744
738
745
- #ifdef NODE_MKSNAPSHOT_USE_STRING_LITERALS
746
- static void WriteDataAsCharString (std::ostream* ss,
747
- const uint8_t * data,
748
- size_t length) {
749
- for (size_t i = 0 ; i < length; i++) {
750
- const uint8_t ch = data[i];
751
- // We can print most printable characters directly. The exceptions are '\'
752
- // (escape characters), " (would end the string), and ? (trigraphs). The
753
- // latter may be overly conservative: we compile with C++17 which doesn't
754
- // support trigraphs.
755
- if (ch >= ' ' && ch <= ' ~' && ch != ' \\ ' && ch != ' "' && ch != ' ?' ) {
756
- *ss << ch;
757
- } else {
758
- // All other characters are blindly output as octal.
759
- const char c0 = ' 0' + ((ch >> 6 ) & 7 );
760
- const char c1 = ' 0' + ((ch >> 3 ) & 7 );
761
- const char c2 = ' 0' + (ch & 7 );
762
- *ss << " \\ " << c0 << c1 << c2;
763
- }
764
- if (i % 64 == 63 ) {
765
- // Go to a newline every 64 bytes since many text editors have
766
- // problems with very long lines.
767
- *ss << " \"\n\" " ;
768
- }
739
+ std::string ToOctalString (const uint8_t ch) {
740
+ // We can print most printable characters directly. The exceptions are '\'
741
+ // (escape characters), " (would end the string), and ? (trigraphs). The
742
+ // latter may be overly conservative: we compile with C++17 which doesn't
743
+ // support trigraphs.
744
+ if (ch >= ' ' && ch <= ' ~' && ch != ' \\ ' && ch != ' "' && ch != ' ?' ) {
745
+ return std::string (1 , static_cast <char >(ch));
769
746
}
747
+ // All other characters are blindly output as octal.
748
+ const char c0 = ' 0' + ((ch >> 6 ) & 7 );
749
+ const char c1 = ' 0' + ((ch >> 3 ) & 7 );
750
+ const char c2 = ' 0' + (ch & 7 );
751
+ return std::string (" \\ " ) + c0 + c1 + c2;
770
752
}
771
753
772
- static void WriteStaticCodeCacheDataAsStringLiteral (
773
- std::ostream* ss, const builtins::CodeCacheInfo& info) {
774
- *ss << " static const uint8_t *" << GetCodeCacheDefName (info.id )
775
- << " = reinterpret_cast<const uint8_t *>(\" " ;
776
- WriteDataAsCharString (ss, info.data .data , info.data .length );
777
- *ss << " \" );\n " ;
754
+ std::vector<std::string> GetOctalTable () {
755
+ size_t size = 1 << 8 ;
756
+ std::vector<std::string> code_table (size);
757
+ for (size_t i = 0 ; i < size; ++i) {
758
+ code_table[i] = ToOctalString (static_cast <uint8_t >(i));
759
+ }
760
+ return code_table;
778
761
}
779
- #else
780
- static void WriteStaticCodeCacheDataAsArray (
781
- std::ostream* ss, const builtins::CodeCacheInfo& info) {
782
- *ss << " static const uint8_t " << GetCodeCacheDefName (info.id ) << " [] = {\n " ;
783
- WriteVector (ss, info.data .data , info.data .length );
784
- *ss << " };\n " ;
762
+
763
+ const std::string& GetOctalCode (uint8_t index) {
764
+ static std::vector<std::string> table = GetOctalTable ();
765
+ return table[index ];
766
+ }
767
+
768
+ template <typename T>
769
+ void WriteByteVectorLiteral (std::ostream* ss,
770
+ const T* vec,
771
+ size_t size,
772
+ const char * var_name,
773
+ bool use_string_literals) {
774
+ constexpr bool is_uint8_t = std::is_same_v<T, uint8_t >;
775
+ static_assert (is_uint8_t || std::is_same_v<T, char >);
776
+ constexpr const char * type_name = is_uint8_t ? " uint8_t" : " char" ;
777
+ if (use_string_literals) {
778
+ const uint8_t * data = reinterpret_cast <const uint8_t *>(vec);
779
+ *ss << " static const " << type_name << " *" << var_name << " = " ;
780
+ *ss << (is_uint8_t ? R"( reinterpret_cast<const uint8_t *>(")" : " \" " );
781
+ for (size_t i = 0 ; i < size; i++) {
782
+ const uint8_t ch = data[i];
783
+ *ss << GetOctalCode (ch);
784
+ if (i % 64 == 63 ) {
785
+ // Go to a newline every 64 bytes since many text editors have
786
+ // problems with very long lines.
787
+ *ss << " \"\n\" " ;
788
+ }
789
+ }
790
+ *ss << (is_uint8_t ? " \" );\n " : " \" ;\n " );
791
+ } else {
792
+ *ss << " static const " << type_name << " " << var_name << " [] = {" ;
793
+ for (size_t i = 0 ; i < size; i++) {
794
+ *ss << std::to_string (vec[i]) << (i == size - 1 ? ' \n ' : ' ,' );
795
+ if (i % 64 == 63 ) {
796
+ // Print a newline every 64 units and a offset to improve
797
+ // readability.
798
+ *ss << " // " << (i / 64 ) << " \n " ;
799
+ }
800
+ }
801
+ *ss << " };\n " ;
802
+ }
785
803
}
786
- #endif
787
804
788
805
static void WriteCodeCacheInitializer (std::ostream* ss,
789
806
const std::string& id,
@@ -796,7 +813,9 @@ static void WriteCodeCacheInitializer(std::ostream* ss,
796
813
*ss << " },\n " ;
797
814
}
798
815
799
- void FormatBlob (std::ostream& ss, const SnapshotData* data) {
816
+ void FormatBlob (std::ostream& ss,
817
+ const SnapshotData* data,
818
+ bool use_string_literals) {
800
819
ss << R"( #include <cstddef>
801
820
#include "env.h"
802
821
#include "node_snapshot_builder.h"
@@ -807,32 +826,24 @@ void FormatBlob(std::ostream& ss, const SnapshotData* data) {
807
826
namespace node {
808
827
)" ;
809
828
810
- #ifdef NODE_MKSNAPSHOT_USE_STRING_LITERALS
811
- ss << R"( static const char *v8_snapshot_blob_data = ")" ;
812
- WriteDataAsCharString (
813
- &ss,
814
- reinterpret_cast <const uint8_t *>(data->v8_snapshot_blob_data .data ),
815
- data->v8_snapshot_blob_data .raw_size );
816
- ss << R"( ";)" ;
817
- #else
818
- ss << R"( static const char v8_snapshot_blob_data[] = {)" ;
819
- WriteVector (&ss,
820
- data->v8_snapshot_blob_data .data ,
821
- data->v8_snapshot_blob_data .raw_size );
822
- ss << R"( };)" ;
823
- #endif
829
+ WriteByteVectorLiteral (&ss,
830
+ data->v8_snapshot_blob_data .data ,
831
+ data->v8_snapshot_blob_data .raw_size ,
832
+ " v8_snapshot_blob_data" ,
833
+ use_string_literals);
824
834
825
835
ss << R"( static const int v8_snapshot_blob_size = )"
826
- << data->v8_snapshot_blob_data .raw_size << " ;" ;
836
+ << data->v8_snapshot_blob_data .raw_size << " ;\n " ;
827
837
838
+ // Windows can't deal with too many large vector initializers.
839
+ // Store the data into static arrays first.
828
840
for (const auto & item : data->code_cache ) {
829
- #ifdef NODE_MKSNAPSHOT_USE_STRING_LITERALS
830
- WriteStaticCodeCacheDataAsStringLiteral (&ss, item);
831
- #else
832
- // Windows can't deal with too many large vector initializers.
833
- // Store the data into static arrays first.
834
- WriteStaticCodeCacheDataAsArray (&ss, item);
835
- #endif
841
+ std::string var_name = GetCodeCacheDefName (item.id );
842
+ WriteByteVectorLiteral (&ss,
843
+ item.data .data ,
844
+ item.data .length ,
845
+ var_name.c_str (),
846
+ use_string_literals);
836
847
}
837
848
838
849
ss << R"( const SnapshotData snapshot_data {
@@ -1069,17 +1080,45 @@ ExitCode SnapshotBuilder::CreateSnapshot(SnapshotData* out,
1069
1080
return ExitCode::kNoFailure ;
1070
1081
}
1071
1082
1072
- ExitCode SnapshotBuilder::Generate (
1073
- std::ostream& out ,
1083
+ ExitCode SnapshotBuilder::GenerateAsSource (
1084
+ const char * out_path ,
1074
1085
const std::vector<std::string>& args,
1075
1086
const std::vector<std::string>& exec_args,
1076
- std::optional<std::string_view> main_script) {
1087
+ std::optional<std::string_view> main_script_path,
1088
+ bool use_string_literals) {
1089
+ std::string main_script_content;
1090
+ std::optional<std::string_view> main_script_optional;
1091
+ if (main_script_path.has_value ()) {
1092
+ int r = ReadFileSync (&main_script_content, main_script_path.value ().data ());
1093
+ if (r != 0 ) {
1094
+ FPrintF (stderr,
1095
+ " Cannot read main script %s for building snapshot. %s: %s" ,
1096
+ main_script_path.value (),
1097
+ uv_err_name (r),
1098
+ uv_strerror (r));
1099
+ return ExitCode::kGenericUserError ;
1100
+ }
1101
+ main_script_optional = main_script_content;
1102
+ }
1103
+
1104
+ std::ofstream out (out_path, std::ios::out | std::ios::binary);
1105
+ if (!out) {
1106
+ FPrintF (stderr, " Cannot open %s for output.\n " , out_path);
1107
+ return ExitCode::kGenericUserError ;
1108
+ }
1109
+
1077
1110
SnapshotData data;
1078
- ExitCode exit_code = Generate (&data, args, exec_args, main_script );
1111
+ ExitCode exit_code = Generate (&data, args, exec_args, main_script_optional );
1079
1112
if (exit_code != ExitCode::kNoFailure ) {
1080
1113
return exit_code;
1081
1114
}
1082
- FormatBlob (out, &data);
1115
+ FormatBlob (out, &data, use_string_literals);
1116
+
1117
+ if (!out) {
1118
+ std::cerr << " Failed to write to " << out_path << " \n " ;
1119
+ exit_code = node::ExitCode::kGenericUserError ;
1120
+ }
1121
+
1083
1122
return exit_code;
1084
1123
}
1085
1124
0 commit comments