Skip to content

Commit

Permalink
create compile caches on compile step
Browse files Browse the repository at this point in the history
  • Loading branch information
anonrig committed Oct 28, 2024
1 parent aefa9f8 commit ac911a3
Show file tree
Hide file tree
Showing 6 changed files with 136 additions and 6 deletions.
5 changes: 3 additions & 2 deletions src/workerd/jsg/compile-cache.c++
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ std::unique_ptr<v8::ScriptCompiler::CachedData> CompileCache::Data::AsCachedData

// CompileCache

void CompileCache::add(
kj::StringPtr key, std::shared_ptr<v8::ScriptCompiler::CachedData> cached) const {
void CompileCache::add(kj::StringPtr key, v8::Local<v8::UnboundModuleScript> script) const {
auto cached =
std::shared_ptr<v8::ScriptCompiler::CachedData>(v8::ScriptCompiler::CreateCodeCache(script));
cache.lockExclusive()->upsert(kj::str(key), Data(kj::mv(cached)), [](auto&, auto&&) {});
}

Expand Down
2 changes: 1 addition & 1 deletion src/workerd/jsg/compile-cache.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ class CompileCache {
std::shared_ptr<void> owningPtr;
};

void add(kj::StringPtr key, std::shared_ptr<v8::ScriptCompiler::CachedData> cached) const;
void add(kj::StringPtr key, v8::Local<v8::UnboundModuleScript> script) const;
kj::Maybe<Data&> find(kj::StringPtr key) const;

static const CompileCache& get() {
Expand Down
4 changes: 1 addition & 3 deletions src/workerd/jsg/modules.c++
Original file line number Diff line number Diff line change
Expand Up @@ -417,9 +417,7 @@ v8::Local<v8::Module> compileEsmModule(jsg::Lock& js,
jsg::check(v8::ScriptCompiler::CompileModule(js.v8Isolate, &source, compileOptions));

if (existingCacheData == nullptr) {
auto cachedData = std::shared_ptr<v8::ScriptCompiler::CachedData>(
v8::ScriptCompiler::CreateCodeCache(module->GetUnboundModuleScript()));
compileCache.add(name, kj::mv(cachedData));
compileCache.add(name, module->GetUnboundModuleScript());
}

return module;
Expand Down
1 change: 1 addition & 0 deletions src/workerd/server/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ wd_cc_library(
hdrs = [
"v8-platform-impl.h",
],
visibility = ["//visibility:public"],
deps = [
"//src/workerd/jsg",
"@capnp-cpp//src/kj",
Expand Down
17 changes: 17 additions & 0 deletions src/workerd/tools/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -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",
],
)
113 changes: 113 additions & 0 deletions src/workerd/tools/create-compile-cache.c++
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
#include "fcntl.h"

#include <workerd/jsg/compile-cache.h>
#include <workerd/jsg/setup.h>

#include <kj/filesystem.h>
#include <kj/main.h>

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<jsg::IsolateObserver>(), params) {};

kj::MainFunc getMain() {
return kj::MainBuilder(
context, "Process a file list", "This binary processes the specified file list.")
.expectArg("<file_path>", 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<kj::byte>(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<kj::byte> 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<kj::Tuple<kj::String, kj::Array<kj::byte>>> file_contents{};
};

} // namespace
} // namespace workerd::api

KJ_MAIN(workerd::api::CompileCacheCreator)

0 comments on commit ac911a3

Please sign in to comment.