Skip to content

Commit

Permalink
Merge commit 'd9309dda9673b5eda8feb3faf61ca953cb28e92a' into kenton/f…
Browse files Browse the repository at this point in the history
…ix-sql-cache
  • Loading branch information
kentonv committed Nov 14, 2024
2 parents cc4c191 + d9309dd commit 1b1de31
Show file tree
Hide file tree
Showing 42 changed files with 433 additions and 238 deletions.
8 changes: 8 additions & 0 deletions build/config/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
load("@bazel_skylib//rules:common_settings.bzl", "string_flag")

# Similar to --run_under flag to be able to run cross-compiled target binaries.
string_flag(
name = "target_run_under",
build_setting_default = "",
visibility = ["//visibility:public"],
)
114 changes: 101 additions & 13 deletions build/wd_js_bundle.bzl
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
load("@bazel_skylib//rules:common_settings.bzl", "BuildSettingInfo")
load("@bazel_skylib//rules:copy_file.bzl", "copy_file")
load("@capnp-cpp//src/capnp:cc_capnp_library.bzl", "cc_capnp_library")

Expand All @@ -13,8 +14,6 @@ const {const_name} :Modules.Bundle = (
]);
"""

MODULE_TEMPLATE = """ (name = "{name}", {src_type} = embed "{path}", type = {type}, {ts_declaration})"""

def _to_name(file_name):
return file_name.removesuffix(".js")

Expand All @@ -26,10 +25,85 @@ def _relative_path(file_path, dir_path):
fail("file_path need to start with dir_path: " + file_path + " vs " + dir_path)
return file_path.removeprefix(dir_path)

def _gen_compile_cache_impl(ctx):
file_list = ctx.actions.declare_file("in")

srcs = []
for src in ctx.attr.srcs:
srcs.extend(src.files.to_list())

outs = [ctx.actions.declare_file(src.basename + "_cache") for src in srcs]

content = []
for i in range(0, len(srcs)):
content.append("{} {}".format(srcs[i].path, outs[i].path))

ctx.actions.write(
output = file_list,
content = "\n".join(content) + "\n",
)

args = ctx.actions.args()
args.add(file_list)

run_under = ctx.attr._run_under[BuildSettingInfo].value

# use run_shell together with cfg = target instead of ctx.actions.run
# to prevent double-compilation of v8.
ctx.actions.run_shell(
outputs = outs,
inputs = [file_list] + srcs,
command = run_under + " " + ctx.executable._tool.path + " $@",
arguments = [args],
use_default_shell_env = True,
tools = [ctx.executable._tool],
)

return [
DefaultInfo(files = depset(direct = outs)),
]

_gen_compile_cache = rule(
implementation = _gen_compile_cache_impl,
attrs = {
"srcs": attr.label_list(mandatory = True, allow_files = True),
"_tool": attr.label(
executable = True,
allow_single_file = True,
cfg = "target",
default = "//src/rust/gen-compile-cache",
),
"_run_under": attr.label(default = "//build/config:target_run_under"),
},
)

def _get_compile_cache(compile_cache, m):
if not compile_cache:
return None
files = m.files.to_list()

if len(files) != 1:
fail("only single file expected")

return compile_cache.get(files[0].path)

MODULE_TEMPLATE = """ (name = "{name}", {src_type} = embed "{path}", type = {type}, {extras})"""

def _gen_api_bundle_capnpn_impl(ctx):
output_dir = ctx.outputs.out.dirname + "/"

def _render_module(name, label, src_type, type):
def _render_module(name, label, src_type, type, cache = None):
ts_declaration_extra = (
"tsDeclaration = embed \"" + _relative_path(
ctx.expand_location("$(location {})".format(ctx.attr.declarations[name]), ctx.attr.data),
output_dir,
) + "\", "
) if name in ctx.attr.declarations else ""
cache_extra = (
"compileCache = embed \"{}\", ".format(_relative_path(cache, output_dir))
) if cache else ""
extras = ts_declaration_extra + cache_extra

return MODULE_TEMPLATE.format(
name = name,
# capnp doesn't allow ".." dir escape, make paths relative.
Expand All @@ -40,20 +114,21 @@ def _gen_api_bundle_capnpn_impl(ctx):
output_dir,
),
type = type,
ts_declaration = (
"tsDeclaration = embed \"" + _relative_path(
ctx.expand_location("$(location {})".format(ctx.attr.declarations[name]), ctx.attr.data),
output_dir,
) + "\", "
) if name in ctx.attr.declarations else "",
extras = extras,
)

compile_cache = {}
if ctx.attr.compile_cache:
locations = ctx.expand_location("$(locations {})".format(ctx.attr.compile_cache.label)).split(" ")
for loc in locations:
compile_cache[loc.removesuffix("_cache")] = loc

modules = [
_render_module(ctx.attr.builtin_modules[m], m.label, "src", "builtin")
_render_module(ctx.attr.builtin_modules[m], m.label, "src", "builtin", _get_compile_cache(compile_cache, m))
for m in ctx.attr.builtin_modules
]
modules += [
_render_module(ctx.attr.internal_modules[m], m.label, "src", "internal")
_render_module(ctx.attr.internal_modules[m], m.label, "src", "internal", _get_compile_cache(compile_cache, m))
for m in ctx.attr.internal_modules
]
modules += [
Expand Down Expand Up @@ -90,6 +165,7 @@ gen_api_bundle_capnpn = rule(
"data": attr.label_list(allow_files = True),
"const_name": attr.string(mandatory = True),
"deps": attr.label_list(),
"compile_cache": attr.label(),
},
)

Expand Down Expand Up @@ -124,7 +200,8 @@ def wd_js_bundle(
internal_data_modules = [],
internal_json_modules = [],
declarations = [],
deps = []):
deps = [],
gen_compile_cache = False):
"""Generate cc capnp library with js api bundle.
NOTE: Due to capnpc embed limitation all modules must be in the same or sub directory of the
Expand All @@ -146,7 +223,7 @@ def wd_js_bundle(
internal_json_modules: list of json source files
declarations: d.ts label set
deps: dependency list
Returns: The set of data dependencies
gen_compile_cache: generate compilation cache of every file and include into the bundle
"""
builtin_modules_dict = {
m: "{}:{}".format(import_name, _to_name(m))
Expand Down Expand Up @@ -200,6 +277,16 @@ def wd_js_bundle(
list(internal_declarations.values())
)

compile_cache = None
if gen_compile_cache:
_gen_compile_cache(
name = name + "@compile_cache",
srcs = builtin_modules_dict.keys() + internal_modules_dict.keys(),
)
compile_cache = name + "@compile_cache"
deps = deps + [compile_cache]
data = data + [compile_cache]

gen_api_bundle_capnpn(
name = name + "@gen",
out = name + ".capnp",
Expand All @@ -213,6 +300,7 @@ def wd_js_bundle(
declarations = builtin_declarations | internal_declarations,
data = data,
deps = deps,
compile_cache = compile_cache,
)

cc_capnp_library(
Expand Down
7 changes: 6 additions & 1 deletion build/wd_ts_bundle.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ def wd_ts_bundle(
internal_json_modules = [],
lint = True,
deps = [],
js_deps = []):
js_deps = [],
gen_compile_cache = False):
"""Compiles typescript modules and generates api bundle with the result.
Args:
Expand All @@ -41,8 +42,11 @@ def wd_ts_bundle(
eslintrc_json: eslintrc.json label
internal_wasm_modules: list of wasm source files
internal_data_modules: list of data source files
internal_json_modules: list of json source files
lint: enables/disables source linting
deps: additional typescript dependencies
gen_compile_cache: generate compilation cache of every file and include into the bundle
js_deps: javascript dependencies
"""
ts_config(
name = name + "@tsconfig",
Expand Down Expand Up @@ -77,6 +81,7 @@ def wd_ts_bundle(
declarations = declarations,
schema_id = schema_id,
deps = deps + js_deps,
gen_compile_cache = gen_compile_cache,
)

if lint:
Expand Down
1 change: 1 addition & 0 deletions src/node/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ load("@workerd//:build/wd_ts_bundle.bzl", "wd_ts_bundle")
wd_ts_bundle(
name = "node",
eslintrc_json = "eslint.config.mjs",
gen_compile_cache = True,
import_name = "node",
internal_modules = glob([
"internal/*.ts",
Expand Down
16 changes: 8 additions & 8 deletions src/node/crypto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -285,14 +285,14 @@ export default {
// * [x] crypto.createHash(algorithm[, options])
// * [x] crypto.createHmac(algorithm, key[, options])
// * [x] crypto.getHashes()
// * Keys
// * [ ] crypto.createPrivateKey(key)
// * [ ] crypto.createPublicKey(key)
// * [x] crypto.createSecretKey(key[, encoding])
// * [x] crypto.generateKey(type, options, callback)
// * [x] crypto.generateKeyPair(type, options, callback)
// * [x] crypto.generateKeyPairSync(type, options)
// * [x] crypto.generateKeySync(type, options)
// * Keys, not implemented yet. Calling the following APIs will throw a ERR_METHOD_NOT_IMPLEMENTED
// * [.] crypto.createPrivateKey(key)
// * [.] crypto.createPublicKey(key)
// * [.] crypto.createSecretKey(key[, encoding])
// * [.] crypto.generateKey(type, options, callback)
// * [.] crypto.generateKeyPair(type, options, callback)
// * [.] crypto.generateKeyPairSync(type, options)
// * [.] crypto.generateKeySync(type, options)
// * Sign/Verify
// * [ ] crypto.createSign(algorithm[, options])
// * [ ] crypto.createVerify(algorithm[, options])
Expand Down
20 changes: 4 additions & 16 deletions src/node/internal/crypto_keys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -438,21 +438,15 @@ export function generateKey(
_options: GenerateKeyOptions,
callback: GenerateKeyCallback
) {
// We intentionally have not implemented key generation up to this point.
// The reason is that generation of cryptographically safe keys is a CPU
// intensive operation that can often exceed limits on the amount of CPU
// time a worker is allowed.
// This API is not implemented yet.
callback(new ERR_METHOD_NOT_IMPLEMENTED('crypto.generateKeySync'));
}

export function generateKeySync(
_type: SecretKeyType,
_options: GenerateKeyOptions
) {
// We intentionally have not implemented key generation up to this point.
// The reason is that generation of cryptographically safe keys is a CPU
// intensive operation that can often exceed limits on the amount of CPU
// time a worker is allowed.
// This API is not implemented yet.
throw new ERR_METHOD_NOT_IMPLEMENTED('crypto.generateKeySync');
}

Expand All @@ -461,20 +455,14 @@ export function generateKeyPair(
_options: GenerateKeyPairOptions,
callback: GenerateKeyPairCallback
) {
// We intentionally have not implemented key generation up to this point.
// The reason is that generation of cryptographically safe keys is a CPU
// intensive operation that can often exceed limits on the amount of CPU
// time a worker is allowed.
// This API is not implemented yet.
callback(new ERR_METHOD_NOT_IMPLEMENTED('crypto.generateKeyPair'));
}

export function generateKeyPairSync(
_type: AsymmetricKeyType,
_options: GenerateKeyPairOptions
): KeyObjectPair {
// We intentionally have not implemented key generation up to this point.
// The reason is that generation of cryptographically safe keys is a CPU
// intensive operation that can often exceed limits on the amount of CPU
// time a worker is allowed.
// This API is not implemented yet.
throw new ERR_METHOD_NOT_IMPLEMENTED('crypto.generateKeyPairSync');
}
8 changes: 5 additions & 3 deletions src/pyodide/internal/python.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,12 @@ async function prepareWasmLinearMemory(Module: Module): Promise<void> {
mountSitePackages(Module, SITE_PACKAGES.rootInfo);
entropyMountFiles(Module);
Module.noInitialRun = !SHOULD_RESTORE_SNAPSHOT;
preloadDynamicLibs(Module);
Module.removeRunDependency('dynlibs');
enterJaegerSpan('preload_dynamic_libs', () => preloadDynamicLibs(Module));
enterJaegerSpan('remove_run_dependency', () =>
Module.removeRunDependency('dynlibs')
);
if (SHOULD_RESTORE_SNAPSHOT) {
restoreSnapshot(Module);
enterJaegerSpan('restore_snapshot', () => restoreSnapshot(Module));
// Invalidate caches if we have a snapshot because the contents of site-packages
// may have changed.
simpleRunPython(
Expand Down
22 changes: 18 additions & 4 deletions src/workerd/api/blob.c++
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,11 @@ Blob::Blob(kj::Array<byte> data, kj::String type)
data(ownData.get<kj::Array<kj::byte>>()),
type(kj::mv(type)) {}

Blob::Blob(jsg::Lock& js, jsg::BufferSource data, kj::String type)
: ownData(kj::mv(data)),
data(getPtr(ownData.get<jsg::BufferSource>())),
type(kj::mv(type)) {}

Blob::Blob(jsg::Lock& js, kj::Array<byte> data, kj::String type)
: ownData(wrap(js, kj::mv(data))),
data(getPtr(ownData.get<jsg::BufferSource>())),
Expand Down Expand Up @@ -200,14 +205,23 @@ jsg::Ref<Blob> Blob::slice(
JSG_THIS, data.slice(start, end), normalizeType(kj::mv(type).orDefault(nullptr)));
}

jsg::Promise<kj::Array<kj::byte>> Blob::arrayBuffer(jsg::Lock& js) {
// TODO(perf): Find a way to avoid the copy.
jsg::Promise<jsg::BufferSource> Blob::arrayBuffer(jsg::Lock& js) {
FeatureObserver::maybeRecordUse(FeatureObserver::Feature::BLOB_AS_ARRAY_BUFFER);
return js.resolvedPromise(kj::heapArray<byte>(data));
// We use BufferSource here instead of kj::Array<kj::byte> to ensure that the
// resulting backing store is associated with the isolate, which is necessary
// for when we start making use of v8 sandboxing.
auto backing = jsg::BackingStore::alloc<v8::ArrayBuffer>(js, data.size());
backing.asArrayPtr().copyFrom(data);
return js.resolvedPromise(jsg::BufferSource(js, kj::mv(backing)));
}

jsg::Promise<jsg::BufferSource> Blob::bytes(jsg::Lock& js) {
return js.resolvedPromise(js.bytes(kj::heapArray<byte>(data)));
// We use BufferSource here instead of kj::Array<kj::byte> to ensure that the
// resulting backing store is associated with the isolate, which is necessary
// for when we start making use of v8 sandboxing.
auto backing = jsg::BackingStore::alloc<v8::Uint8Array>(js, data.size());
backing.asArrayPtr().copyFrom(data);
return js.resolvedPromise(jsg::BufferSource(js, kj::mv(backing)));
}

jsg::Promise<kj::String> Blob::text(jsg::Lock& js) {
Expand Down
3 changes: 2 additions & 1 deletion src/workerd/api/blob.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ class ReadableStream;
// An implementation of the Web Platform Standard Blob API
class Blob: public jsg::Object {
public:
Blob(jsg::Lock& js, jsg::BufferSource data, kj::String type);
Blob(jsg::Lock& js, kj::Array<byte> data, kj::String type);
Blob(jsg::Ref<Blob> parent, kj::ArrayPtr<const byte> data, kj::String type);

Expand Down Expand Up @@ -44,7 +45,7 @@ class Blob: public jsg::Object {
jsg::Ref<Blob> slice(
jsg::Optional<int> start, jsg::Optional<int> end, jsg::Optional<kj::String> type);

jsg::Promise<kj::Array<kj::byte>> arrayBuffer(jsg::Lock& js);
jsg::Promise<jsg::BufferSource> arrayBuffer(jsg::Lock& js);
jsg::Promise<jsg::BufferSource> bytes(jsg::Lock& js);
jsg::Promise<kj::String> text(jsg::Lock& js);
jsg::Ref<ReadableStream> stream();
Expand Down
9 changes: 1 addition & 8 deletions src/workerd/api/global-scope.c++
Original file line number Diff line number Diff line change
Expand Up @@ -849,15 +849,8 @@ jsg::JsValue resolveFromRegistry(jsg::Lock& js, kj::StringPtr specifier) {
auto& info = JSG_REQUIRE_NONNULL(
moduleRegistry->resolve(js, spec), Error, kj::str("No such module: ", specifier));
auto module = info.module.getHandle(js);
jsg::instantiateModule(js, module);

auto handle = jsg::check(module->Evaluate(js.v8Context()));
KJ_ASSERT(handle->IsPromise());
auto prom = handle.As<v8::Promise>();
KJ_ASSERT(prom->State() != v8::Promise::PromiseState::kPending);
if (module->GetStatus() == v8::Module::kErrored) {
jsg::throwTunneledException(js.v8Isolate, module->GetException());
}
jsg::instantiateModule(js, module);
return jsg::JsValue(js.v8Get(module->GetModuleNamespace().As<v8::Object>(), "default"_kj));
}
} // namespace
Expand Down
Loading

0 comments on commit 1b1de31

Please sign in to comment.