44#include " debug_utils-inl.h"
55#include " env-inl.h"
66#include " json_parser.h"
7+ #include " node_contextify.h"
8+ #include " node_errors.h"
79#include " node_external_reference.h"
810#include " node_internals.h"
911#include " node_union_bytes.h"
12+ #include " node_v8_platform-inl.h"
13+ #include " util-inl.h"
1014
1115// The POSTJECT_SENTINEL_FUSE macro is a string of random characters selected by
1216// the Node.js project that is present only once in the entire binary. It is
2630
2731using node::ExitCode;
2832using v8::Context;
33+ using v8::Function;
2934using v8::FunctionCallbackInfo;
35+ using v8::HandleScope;
36+ using v8::Isolate;
3037using v8::Local;
3138using v8::Object;
39+ using v8::ScriptCompiler;
40+ using v8::String;
3241using v8::Value;
3342
3443namespace node {
@@ -78,6 +87,11 @@ size_t SeaSerializer::Write(const SeaResource& sea) {
7887 sea.code .data (),
7988 sea.code .size ());
8089 written_total += WriteStringView (sea.code , StringLogMode::kAddressAndContent );
90+
91+ Debug (" Write SEA resource code cache %p, size=%zu\n " ,
92+ sea.code_cache .data (),
93+ sea.code_cache .size ());
94+ written_total += WriteStringView (sea.code_cache , StringLogMode::kAddressOnly );
8195 return written_total;
8296}
8397
@@ -105,7 +119,12 @@ SeaResource SeaDeserializer::Read() {
105119
106120 std::string_view code = ReadStringView (StringLogMode::kAddressAndContent );
107121 Debug (" Read SEA resource code %p, size=%zu\n " , code.data (), code.size ());
108- return {flags, code};
122+
123+ std::string_view code_cache = ReadStringView (StringLogMode::kAddressOnly );
124+ Debug (" Read SEA resource code cache %p, size=%zu\n " ,
125+ code_cache.data (),
126+ code_cache.size ());
127+ return {flags, code, code_cache};
109128}
110129
111130std::string_view FindSingleExecutableBlob () {
@@ -161,6 +180,27 @@ void IsExperimentalSeaWarningNeeded(const FunctionCallbackInfo<Value>& args) {
161180 sea_resource.flags & SeaFlags::kDisableExperimentalSeaWarning ));
162181}
163182
183+ void GetCodeCache (const FunctionCallbackInfo<Value>& args) {
184+ if (!IsSingleExecutable ()) {
185+ return ;
186+ }
187+
188+ Environment* env = Environment::GetCurrent (args);
189+ Isolate* isolate = env->isolate ();
190+ HandleScope scope (isolate);
191+
192+ SeaResource sea_resource = FindSingleExecutableResource ();
193+
194+ Local<Object> buf =
195+ Buffer::Copy (
196+ env,
197+ reinterpret_cast <const char *>(sea_resource.code_cache .data ()),
198+ sea_resource.code_cache .length ())
199+ .ToLocalChecked ();
200+
201+ args.GetReturnValue ().Set (buf);
202+ }
203+
164204std::tuple<int , char **> FixupArgsForSEA (int argc, char ** argv) {
165205 // Repeats argv[0] at position 1 on argv as a replacement for the missing
166206 // entry point file path.
@@ -238,6 +278,49 @@ std::optional<SeaConfig> ParseSingleExecutableConfig(
238278 return result;
239279}
240280
281+ std::optional<std::string> GenerateCodeCache (std::string_view main_path,
282+ std::string_view main_script) {
283+ RAIIIsolate raii_isolate;
284+ Isolate* isolate = raii_isolate.get ();
285+
286+ HandleScope handle_scope (isolate);
287+ Local<Context> context = Context::New (isolate);
288+ Context::Scope context_scope (context);
289+
290+ errors::PrinterTryCatch bootstrapCatch (
291+ isolate, errors::PrinterTryCatch::kPrintSourceLine );
292+
293+ Local<String> filename;
294+ if (!String::NewFromUtf8 (isolate, main_path.data ()).ToLocal (&filename)) {
295+ return {};
296+ }
297+
298+ Local<String> content;
299+ if (!String::NewFromUtf8 (isolate, main_script.data ()).ToLocal (&content)) {
300+ return {};
301+ }
302+
303+ std::vector<Local<String>> parameters = {
304+ FIXED_ONE_BYTE_STRING (isolate, " exports" ),
305+ FIXED_ONE_BYTE_STRING (isolate, " require" ),
306+ FIXED_ONE_BYTE_STRING (isolate, " module" ),
307+ FIXED_ONE_BYTE_STRING (isolate, " __filename" ),
308+ FIXED_ONE_BYTE_STRING (isolate, " __dirname" ),
309+ };
310+
311+ Local<Function> fn;
312+ if (!contextify::CompileFunction (
313+ isolate, context, filename, content, std::move (parameters))
314+ .ToLocal (&fn)) {
315+ return {};
316+ }
317+
318+ std::unique_ptr<ScriptCompiler::CachedData> cache{
319+ ScriptCompiler::CreateCodeCacheForFunction (fn)};
320+ std::string code_cache (cache->data , cache->data + cache->length );
321+ return code_cache;
322+ }
323+
241324ExitCode GenerateSingleExecutableBlob (const SeaConfig& config) {
242325 std::string main_script;
243326 // TODO(joyeecheung): unify the file utils.
@@ -248,7 +331,15 @@ ExitCode GenerateSingleExecutableBlob(const SeaConfig& config) {
248331 return ExitCode::kGenericUserError ;
249332 }
250333
251- SeaResource sea{config.flags , main_script};
334+ std::optional<std::string> optional_code_cache =
335+ GenerateCodeCache (config.main_path , main_script);
336+ if (!optional_code_cache.has_value ()) {
337+ FPrintF (stderr, " Cannot generate V8 code cache\n " );
338+ return ExitCode::kGenericUserError ;
339+ }
340+ std::string code_cache = optional_code_cache.value ();
341+
342+ SeaResource sea{config.flags , main_script, code_cache};
252343
253344 SeaSerializer serializer;
254345 serializer.Write (sea);
@@ -288,10 +379,12 @@ void Initialize(Local<Object> target,
288379 target,
289380 " isExperimentalSeaWarningNeeded" ,
290381 IsExperimentalSeaWarningNeeded);
382+ SetMethod (context, target, " getCodeCache" , GetCodeCache);
291383}
292384
293385void RegisterExternalReferences (ExternalReferenceRegistry* registry) {
294386 registry->Register (IsExperimentalSeaWarningNeeded);
387+ registry->Register (GetCodeCache);
295388}
296389
297390} // namespace sea
0 commit comments