diff --git a/src/workerd/jsg/compile-cache.c++ b/src/workerd/jsg/compile-cache.c++ index b6b9be5c797..fc5879925ad 100644 --- a/src/workerd/jsg/compile-cache.c++ +++ b/src/workerd/jsg/compile-cache.c++ @@ -14,8 +14,9 @@ std::unique_ptr CompileCache::Data::AsCachedData // CompileCache -void CompileCache::add( - kj::StringPtr key, std::shared_ptr cached) const { +void CompileCache::add(kj::StringPtr key, v8::Local script) const { + auto cached = + std::shared_ptr(v8::ScriptCompiler::CreateCodeCache(script)); cache.lockExclusive()->upsert(kj::str(key), Data(kj::mv(cached)), [](auto&, auto&&) {}); } diff --git a/src/workerd/jsg/compile-cache.h b/src/workerd/jsg/compile-cache.h index c8e208d44d4..a65d63e3a89 100644 --- a/src/workerd/jsg/compile-cache.h +++ b/src/workerd/jsg/compile-cache.h @@ -42,7 +42,7 @@ class CompileCache { std::shared_ptr owningPtr; }; - void add(kj::StringPtr key, std::shared_ptr cached) const; + void add(kj::StringPtr key, v8::Local script) const; kj::Maybe find(kj::StringPtr key) const; static const CompileCache& get() { diff --git a/src/workerd/jsg/modules.c++ b/src/workerd/jsg/modules.c++ index 4107313bb88..6b842a2ede1 100644 --- a/src/workerd/jsg/modules.c++ +++ b/src/workerd/jsg/modules.c++ @@ -417,9 +417,7 @@ v8::Local compileEsmModule(jsg::Lock& js, jsg::check(v8::ScriptCompiler::CompileModule(js.v8Isolate, &source, compileOptions)); if (existingCacheData == nullptr) { - auto cachedData = std::shared_ptr( - v8::ScriptCompiler::CreateCodeCache(module->GetUnboundModuleScript())); - compileCache.add(name, kj::mv(cachedData)); + compileCache.add(name, module->GetUnboundModuleScript()); } return module; diff --git a/src/workerd/server/BUILD.bazel b/src/workerd/server/BUILD.bazel index 1c3c46c7db4..9caa8431ba7 100644 --- a/src/workerd/server/BUILD.bazel +++ b/src/workerd/server/BUILD.bazel @@ -140,6 +140,7 @@ wd_cc_library( hdrs = [ "v8-platform-impl.h", ], + visibility = ["//visibility:public"], deps = [ "//src/workerd/jsg", "@capnp-cpp//src/kj", diff --git a/src/workerd/tools/BUILD.bazel b/src/workerd/tools/BUILD.bazel index 2331e0eeee9..20f4ca818d9 100644 --- a/src/workerd/tools/BUILD.bazel +++ b/src/workerd/tools/BUILD.bazel @@ -71,3 +71,20 @@ run_binary( tool = "param_extractor_bin", visibility = ["//visibility:public"], ) + +# This binary is used to generate compile cache for workerd. +# This will later be used by workerd to access compile caches of JS internals. +# NOTE: We only enable compile cache for linux at the moment. +cc_binary( + name = "create_compile_cache_bin", + srcs = ["create-compile-cache.c++"], + target_compatible_with = select({ + "@platforms//os:linux": [], + "//conditions:default": ["@platforms//:incompatible"], + }), + deps = [ + "//src/workerd/jsg", + "@capnp-cpp//src/kj", + "@workerd-v8//:v8", + ], +) diff --git a/src/workerd/tools/create-compile-cache.c++ b/src/workerd/tools/create-compile-cache.c++ new file mode 100644 index 00000000000..82b2a3c0ce5 --- /dev/null +++ b/src/workerd/tools/create-compile-cache.c++ @@ -0,0 +1,113 @@ +#include "fcntl.h" + +#include +#include + +#include +#include + +namespace workerd::api { +namespace { +JSG_DECLARE_ISOLATE_TYPE(CompileCacheIsolate); + +constexpr int resourceLineOffset = 0; +constexpr int resourceColumnOffset = 0; +constexpr bool resourceIsSharedCrossOrigin = false; +constexpr int scriptId = -1; +constexpr bool resourceIsOpaque = false; +constexpr bool isWasm = false; +constexpr bool isModule = true; + +// CompileCacheCreator receives an argument of a text file where each line +// represents the path of the file to create compile caches for. +class CompileCacheCreator { +public: + explicit CompileCacheCreator(kj::ProcessContext& context) + : context(context), + ccIsolate(system, kj::heap(), params) {}; + + kj::MainFunc getMain() { + return kj::MainBuilder( + context, "Process a file list", "This binary processes the specified file list.") + .expectArg("", KJ_BIND_METHOD(*this, setFilePath)) + .callAfterParsing(KJ_BIND_METHOD(*this, run)) + .build(); + } + + void readFiles() { + auto fileListFd = open(filePath.begin(), O_RDONLY); + auto fileList = kj::newDiskReadableFile(kj::AutoCloseFd(fileListFd)); + auto fileListContent = fileList->mmap(0, fileList->stat().size); + + size_t start = 0; + size_t end = 0; + + while (end < fileListContent.size()) { + while (end < fileListContent.size() && fileListContent[end] != '\n') { + end++; + } + + auto path = fileListContent.slice(start, end); + + if (path.size() > 0) { + auto fd = open(path.asChars().begin(), O_RDONLY); + auto file = kj::newDiskReadableFile(kj::AutoCloseFd(fd)); + auto content = file->mmap(0, file->stat().size); + + auto heap = kj::heapArray(content.size()); + std::memcpy(heap.begin(), content.begin(), content.size()); + file_contents.add(kj::tuple(kj::heapString(path.asChars()), kj::mv(heap))); + } + + end++; + start = end; + } + } + + kj::MainBuilder::Validity run() { + readFiles(); + + const auto& compileCache = jsg::CompileCache::get(); + auto options = v8::ScriptCompiler::kNoCompileOptions; + + ccIsolate.runInLockScope([&](CompileCacheIsolate::Lock& js) { + for (auto& entry: file_contents) { + kj::StringPtr name = kj::get<0>(entry); + kj::ArrayPtr content = kj::get<1>(entry); + + v8::ScriptOrigin origin(jsg::v8StrIntern(js.v8Isolate, name), resourceLineOffset, + resourceColumnOffset, resourceIsSharedCrossOrigin, scriptId, {}, resourceIsOpaque, + isWasm, isModule); + + auto contentStr = jsg::newExternalOneByteString(js, content.asChars()); + auto source = v8::ScriptCompiler::Source(contentStr, origin, nullptr); + auto module = jsg::check(v8::ScriptCompiler::CompileModule(js.v8Isolate, &source, options)); + + compileCache.add(name, module->GetUnboundModuleScript()); + } + }); + + return true; + } + +private: + kj::ProcessContext& context; + kj::StringPtr filePath{}; + + jsg::V8System system{}; + v8::Isolate::CreateParams params{}; + CompileCacheIsolate ccIsolate; + + kj::MainBuilder::Validity setFilePath(kj::StringPtr path) { + filePath = path; + return true; + } + + // Key is the path of the file, and value is the content. + kj::Vector>> file_contents{}; +}; + +} // namespace +} // namespace workerd::api + +KJ_MAIN(workerd::api::CompileCacheCreator)