Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions src/jsc/any_task_job.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ pub trait AnyTaskJobCtx: Sized {
#[repr(C)]
pub struct AnyTaskJob<C> {
run_from_js_erased: fn(*mut ()) -> JsResult<()>,
release_erased: fn(*mut ()),
vm: bun_ptr::BackRef<VirtualMachine>,
task: WorkPoolTask,
poll: KeepAlive,
Expand All @@ -56,7 +57,24 @@ pub unsafe fn dispatch_erased(ptr: *mut ()) -> JsResult<()> {
entry(ptr)
}

/// Free a queued job at VM shutdown without running its completion; the ctx
/// `Drop` needs the still-live VM to release its JSC handles and resources.
///
/// # Safety
/// `ptr` must be a live `*mut AnyTaskJob<C>` from [`AnyTaskJob::create`],
/// popped from the event-loop queue (so it held exclusive ownership); frees it.
Comment thread
robobun marked this conversation as resolved.
pub unsafe fn release_erased(ptr: *mut ()) {
// SAFETY: `AnyTaskJob<C>` is `#[repr(C)]` with `release_erased` second;
// caller contract that `ptr` is such an allocation.
let entry = unsafe { *ptr.cast::<fn(*mut ())>().add(1) };
entry(ptr)
}

const _: () = assert!(core::mem::offset_of!(AnyTaskJob<()>, run_from_js_erased) == 0);
const _: () = assert!(
core::mem::offset_of!(AnyTaskJob<()>, release_erased)
== core::mem::size_of::<fn(*mut ()) -> JsResult<()>>()
);

impl<C> bun_event_loop::Taskable for AnyTaskJob<C> {
const TAG: bun_event_loop::TaskTag = bun_event_loop::task_tag::AnyTaskJob;
Expand All @@ -82,6 +100,7 @@ impl<C: AnyTaskJobCtx> AnyTaskJob<C> {
let vm = bun_ptr::BackRef::new(global.bun_vm());
let job = bun_core::heap::into_raw(Box::new(Self {
run_from_js_erased: |p| Self::run_from_js(p.cast::<Self>()),
release_erased: |p| Self::release(p.cast::<Self>()),
vm,
task: WorkPoolTask {
node: Default::default(),
Expand Down Expand Up @@ -158,4 +177,11 @@ impl<C: AnyTaskJobCtx> AnyTaskJob<C> {
}
this.ctx.then(vm.global())
}

/// [`release_erased`]'s monomorphic body.
fn release(this: *mut Self) {
// SAFETY: `this` was produced by `heap::into_raw` in `create`; the
// caller (the popped queue entry) held exclusive ownership.
drop(unsafe { bun_core::heap::take(this) });
}
}
2 changes: 0 additions & 2 deletions src/jsc/bindings/headers-handwritten.h
Original file line number Diff line number Diff line change
Expand Up @@ -402,9 +402,7 @@ extern "C" size_t Bun__encoding__byteLengthUTF16AsUTF8(const char16_t* ptr, size
extern "C" JSC::EncodedJSValue Bun__encoding__constructFromLatin1(void*, const unsigned char* ptr, size_t len, Encoding encoding);
extern "C" JSC::EncodedJSValue Bun__encoding__constructFromUTF16(void*, const char16_t* ptr, size_t len, Encoding encoding);

extern "C" void Bun__EventLoop__runCallback1(JSC::JSGlobalObject* global, JSC::EncodedJSValue callback, JSC::EncodedJSValue thisValue, JSC::EncodedJSValue arg1);
extern "C" void Bun__EventLoop__runCallback2(JSC::JSGlobalObject* global, JSC::EncodedJSValue callback, JSC::EncodedJSValue thisValue, JSC::EncodedJSValue arg1, JSC::EncodedJSValue arg2);
extern "C" void Bun__EventLoop__runCallback3(JSC::JSGlobalObject* global, JSC::EncodedJSValue callback, JSC::EncodedJSValue thisValue, JSC::EncodedJSValue arg1, JSC::EncodedJSValue arg2, JSC::EncodedJSValue arg3);

/// @note throws a JS exception and returns false if a stack overflow occurs
template<bool isStrict, bool enableAsymmetricMatchers, bool skipPrototype = false>
Expand Down
19 changes: 7 additions & 12 deletions src/jsc/bindings/node/crypto/CryptoDhJob.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,30 +40,25 @@ void DhJobCtx::runTask(JSGlobalObject* globalObject)
m_result = ByteSource::allocated(dp.release());
}

extern "C" void Bun__DhJobCtx__runFromJS(DhJobCtx* ctx, JSGlobalObject* globalObject, EncodedJSValue callback)
extern "C" void Bun__DhJobCtx__runFromJS(DhJobCtx* ctx, JSGlobalObject* globalObject, JSCallbackArgs* out)
{
ctx->runFromJS(globalObject, JSValue::decode(callback));
*out = ctx->runFromJS(globalObject);
}
void DhJobCtx::runFromJS(JSGlobalObject* lexicalGlobalObject, JSValue callback)
JSCallbackArgs DhJobCtx::runFromJS(JSGlobalObject* lexicalGlobalObject)
{
VM& vm = lexicalGlobalObject->vm();
ThrowScope scope = DECLARE_THROW_SCOPE(vm);

if (!m_result) {
// Same message as the synchronous path so callers observe identical errors either way.
JSObject* err = createError(lexicalGlobalObject, ErrorCode::ERR_CRYPTO_OPERATION_FAILED, "diffieHellman operation failed"_s);
Bun__EventLoop__runCallback1(lexicalGlobalObject, JSValue::encode(callback), JSValue::encode(jsUndefined()), JSValue::encode(err));
return;
RETURN_IF_EXCEPTION(scope, {});
return { err };
}

JSValue result = WebCore::createBuffer(lexicalGlobalObject, m_result.span());

Bun__EventLoop__runCallback2(
lexicalGlobalObject,
JSValue::encode(callback),
JSValue::encode(jsUndefined()),
JSValue::encode(jsNull()),
JSValue::encode(result));
RETURN_IF_EXCEPTION(scope, {});
return { jsNull(), result };
}

extern "C" DhJob* Bun__DhJob__create(JSGlobalObject* globalObject, DhJobCtx* ctx, EncodedJSValue callback);
Expand Down
3 changes: 2 additions & 1 deletion src/jsc/bindings/node/crypto/CryptoDhJob.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include "root.h"
#include "JSCallbackArgs.h"
#include "KeyObject.h"
#include "CryptoUtil.h"

Expand Down Expand Up @@ -30,7 +31,7 @@ struct DhJobCtx {
static std::optional<DhJobCtx> fromJS(JSC::JSGlobalObject*, JSC::ThrowScope&, JSC::JSObject* options);

void runTask(JSC::JSGlobalObject*);
void runFromJS(JSC::JSGlobalObject*, JSC::JSValue callback);
JSCallbackArgs runFromJS(JSC::JSGlobalObject*);
void deinit();

RefPtr<KeyObjectData> m_privateKey;
Expand Down
4 changes: 2 additions & 2 deletions src/jsc/bindings/node/crypto/CryptoGenDhKeyPair.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ extern "C" void Bun__DhKeyPairJobCtx__runTask(DhKeyPairJobCtx* ctx, JSGlobalObje
ctx->runTask(globalObject, keyCtx);
}

extern "C" void Bun__DhKeyPairJobCtx__runFromJS(DhKeyPairJobCtx* ctx, JSGlobalObject* globalObject, EncodedJSValue callback)
extern "C" void Bun__DhKeyPairJobCtx__runFromJS(DhKeyPairJobCtx* ctx, JSGlobalObject* globalObject, JSCallbackArgs* out)
{
ctx->runFromJS(globalObject, JSValue::decode(callback));
*out = ctx->runFromJS(globalObject);
}

extern "C" DhKeyPairJob* Bun__DhKeyPairJob__create(JSGlobalObject* globalObject, DhKeyPairJobCtx* ctx, EncodedJSValue callback);
Expand Down
4 changes: 2 additions & 2 deletions src/jsc/bindings/node/crypto/CryptoGenDsaKeyPair.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ extern "C" void Bun__DsaKeyPairJobCtx__runTask(DsaKeyPairJobCtx* ctx, JSGlobalOb
ctx->runTask(globalObject, keyCtx);
}

extern "C" void Bun__DsaKeyPairJobCtx__runFromJS(DsaKeyPairJobCtx* ctx, JSGlobalObject* globalObject, EncodedJSValue callback)
extern "C" void Bun__DsaKeyPairJobCtx__runFromJS(DsaKeyPairJobCtx* ctx, JSGlobalObject* globalObject, JSCallbackArgs* out)
{
ctx->runFromJS(globalObject, JSValue::decode(callback));
*out = ctx->runFromJS(globalObject);
}

extern "C" DsaKeyPairJob* Bun__DsaKeyPairJob__create(JSGlobalObject* globalObject, DsaKeyPairJobCtx* ctx, EncodedJSValue callback);
Expand Down
4 changes: 2 additions & 2 deletions src/jsc/bindings/node/crypto/CryptoGenEcKeyPair.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ extern "C" void Bun__EcKeyPairJobCtx__runTask(EcKeyPairJobCtx* ctx, JSGlobalObje
ctx->runTask(globalObject, keyCtx);
}

extern "C" void Bun__EcKeyPairJobCtx__runFromJS(EcKeyPairJobCtx* ctx, JSGlobalObject* globalObject, EncodedJSValue callback)
extern "C" void Bun__EcKeyPairJobCtx__runFromJS(EcKeyPairJobCtx* ctx, JSGlobalObject* globalObject, JSCallbackArgs* out)
{
ctx->runFromJS(globalObject, JSValue::decode(callback));
*out = ctx->runFromJS(globalObject);
}

extern "C" EcKeyPairJob* Bun__EcKeyPairJob__create(JSGlobalObject* globalObject, EcKeyPairJobCtx* ctx, EncodedJSValue callback);
Expand Down
29 changes: 9 additions & 20 deletions src/jsc/bindings/node/crypto/CryptoGenKeyPair.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,44 +29,33 @@ void KeyPairJobCtx::runTask(JSGlobalObject* globalObject, ncrypto::EVPKeyCtxPoin
m_keyObj = KeyObject::create(CryptoKeyType::Private, WTF::move(key));
}

void KeyPairJobCtx::runFromJS(JSGlobalObject* lexicalGlobalObject, JSValue callback)
JSCallbackArgs KeyPairJobCtx::runFromJS(JSGlobalObject* lexicalGlobalObject)
{
VM& vm = lexicalGlobalObject->vm();
ThrowScope scope = DECLARE_THROW_SCOPE(vm);

auto exceptionCallback = [lexicalGlobalObject, callback](JSValue exceptionValue) {
Bun__EventLoop__runCallback1(lexicalGlobalObject, JSValue::encode(callback), JSValue::encode(jsUndefined()), JSValue::encode(exceptionValue));
};

if (!m_keyObj.data()) {
JSValue err = createCryptoError(lexicalGlobalObject, scope, m_opensslError, "key generation failed"_s);
Bun__EventLoop__runCallback1(lexicalGlobalObject, JSValue::encode(callback), JSValue::encode(jsUndefined()), JSValue::encode(err));
return;
RETURN_IF_EXCEPTION(scope, {});
return { err };
}

JSValue publicKeyValue = m_keyObj.exportPublic(lexicalGlobalObject, scope, m_publicKeyEncoding);
if (scope.exception()) [[unlikely]] {
JSValue exceptionValue = scope.exception();
// The thrown Error, not the Exception cell (node parity).
JSValue exceptionValue = scope.exception()->value();
(void)scope.tryClearException();
exceptionCallback(exceptionValue);
return;
return { exceptionValue };
}

JSValue privateKeyValue = m_keyObj.exportPrivate(lexicalGlobalObject, scope, m_privateKeyEncoding);
if (scope.exception()) [[unlikely]] {
JSValue exceptionValue = scope.exception();
JSValue exceptionValue = scope.exception()->value();
(void)scope.tryClearException();
exceptionCallback(exceptionValue);
return;
return { exceptionValue };
}

Bun__EventLoop__runCallback3(
lexicalGlobalObject,
JSValue::encode(callback),
JSValue::encode(jsUndefined()),
JSValue::encode(jsNull()),
JSValue::encode(publicKeyValue),
JSValue::encode(privateKeyValue));
return { jsNull(), publicKeyValue, privateKeyValue };
}

KeyEncodingConfig parseKeyEncodingConfig(JSGlobalObject* globalObject, ThrowScope& scope, JSValue keyTypeValue, JSValue optionsValue)
Expand Down
3 changes: 2 additions & 1 deletion src/jsc/bindings/node/crypto/CryptoGenKeyPair.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include "root.h"
#include "JSCallbackArgs.h"
#include "ncrypto.h"
#include "KeyObject.h"

Expand All @@ -23,7 +24,7 @@ struct KeyPairJobCtx {
}

void runTask(JSC::JSGlobalObject* globalObject, ncrypto::EVPKeyCtxPointer& ctx);
void runFromJS(JSC::JSGlobalObject* globalObject, JSC::JSValue callback);
JSCallbackArgs runFromJS(JSC::JSGlobalObject* globalObject);
void deinit();

int err() const { return m_opensslError; };
Expand Down
4 changes: 2 additions & 2 deletions src/jsc/bindings/node/crypto/CryptoGenNidKeyPair.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ extern "C" void Bun__NidKeyPairJobCtx__runTask(NidKeyPairJobCtx* ctx, JSGlobalOb
ctx->runTask(globalObject, keyCtx);
}

extern "C" void Bun__NidKeyPairJobCtx__runFromJS(NidKeyPairJobCtx* ctx, JSGlobalObject* globalObject, EncodedJSValue callback)
extern "C" void Bun__NidKeyPairJobCtx__runFromJS(NidKeyPairJobCtx* ctx, JSGlobalObject* globalObject, JSCallbackArgs* out)
{
ctx->runFromJS(globalObject, JSValue::decode(callback));
*out = ctx->runFromJS(globalObject);
}

extern "C" NidKeyPairJob* Bun__NidKeyPairJob__create(JSGlobalObject* globalObject, NidKeyPairJobCtx* ctx, EncodedJSValue callback);
Expand Down
4 changes: 2 additions & 2 deletions src/jsc/bindings/node/crypto/CryptoGenRsaKeyPair.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ extern "C" void Bun__RsaKeyPairJobCtx__runTask(RsaKeyPairJobCtx* ctx, JSGlobalOb
ctx->runTask(globalObject, keyCtx);
}

extern "C" void Bun__RsaKeyPairJobCtx__runFromJS(RsaKeyPairJobCtx* ctx, JSGlobalObject* globalObject, EncodedJSValue callback)
extern "C" void Bun__RsaKeyPairJobCtx__runFromJS(RsaKeyPairJobCtx* ctx, JSGlobalObject* globalObject, JSCallbackArgs* out)
{
ctx->runFromJS(globalObject, JSValue::decode(callback));
*out = ctx->runFromJS(globalObject);
}

extern "C" RsaKeyPairJob* Bun__RsaKeyPairJob__create(JSGlobalObject* globalObject, RsaKeyPairJobCtx* ctx, EncodedJSValue callback);
Expand Down
22 changes: 10 additions & 12 deletions src/jsc/bindings/node/crypto/CryptoHkdf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,19 +67,19 @@ void HkdfJobCtx::runTask(JSGlobalObject* lexicalGlobalObject)
m_result = ByteSource::allocated(dp.release());
}

extern "C" void Bun__HkdfJobCtx__runFromJS(HkdfJobCtx* ctx, JSGlobalObject* lexicalGlobalObject, EncodedJSValue callback)
extern "C" void Bun__HkdfJobCtx__runFromJS(HkdfJobCtx* ctx, JSGlobalObject* lexicalGlobalObject, JSCallbackArgs* out)
{
ctx->runFromJS(lexicalGlobalObject, JSValue::decode(callback));
*out = ctx->runFromJS(lexicalGlobalObject);
}
void HkdfJobCtx::runFromJS(JSGlobalObject* lexicalGlobalObject, JSValue callback)
JSCallbackArgs HkdfJobCtx::runFromJS(JSGlobalObject* lexicalGlobalObject)
{
auto& vm = lexicalGlobalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);

if (!m_result) {
JSObject* err = createError(lexicalGlobalObject, ErrorCode::ERR_CRYPTO_OPERATION_FAILED, "hkdf operation failed"_s);
Bun__EventLoop__runCallback1(lexicalGlobalObject, JSValue::encode(callback), JSValue::encode(jsUndefined()), JSValue::encode(err));
return;
RETURN_IF_EXCEPTION(scope, {});
return { err };
}

auto& result = m_result.value();
Expand All @@ -88,17 +88,15 @@ void HkdfJobCtx::runFromJS(JSGlobalObject* lexicalGlobalObject, JSValue callback
RefPtr<ArrayBuffer> buf = ArrayBuffer::tryCreateUninitialized(result.size(), 1);
if (!buf) {
JSObject* err = createOutOfMemoryError(lexicalGlobalObject);
Bun__EventLoop__runCallback1(lexicalGlobalObject, JSValue::encode(callback), JSValue::encode(jsUndefined()), JSValue::encode(err));
return;
RETURN_IF_EXCEPTION(scope, {});
return { err };
}

memcpy(buf->data(), result.data(), result.size());

Bun__EventLoop__runCallback2(lexicalGlobalObject,
JSValue::encode(callback),
JSValue::encode(jsUndefined()),
JSValue::encode(jsNull()),
JSValue::encode(JSArrayBuffer::create(vm, globalObject->arrayBufferStructure(), buf.releaseNonNull())));
JSValue resultBuffer = JSArrayBuffer::create(vm, globalObject->arrayBufferStructure(), buf.releaseNonNull());
RETURN_IF_EXCEPTION(scope, {});
return { jsNull(), resultBuffer };
}

extern "C" void Bun__HkdfJobCtx__deinit(HkdfJobCtx* ctx)
Expand Down
3 changes: 2 additions & 1 deletion src/jsc/bindings/node/crypto/CryptoHkdf.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include "root.h"
#include "JSCallbackArgs.h"
#include "helpers.h"
#include "ncrypto.h"
#include "CryptoUtil.h"
Expand All @@ -25,7 +26,7 @@ struct HkdfJobCtx {
static std::optional<HkdfJobCtx> fromJS(JSC::JSGlobalObject*, JSC::CallFrame*, JSC::ThrowScope&, Mode);

void runTask(JSC::JSGlobalObject*);
void runFromJS(JSC::JSGlobalObject*, JSC::JSValue callback);
JSCallbackArgs runFromJS(JSC::JSGlobalObject*);
void deinit();

ncrypto::Digest m_digest;
Expand Down
18 changes: 8 additions & 10 deletions src/jsc/bindings/node/crypto/CryptoKeygen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,32 +35,30 @@ void SecretKeyJobCtx::runTask(JSGlobalObject* lexicalGlobalObject)
m_result = WTF::move(key);
}

extern "C" void Bun__SecretKeyJobCtx__runFromJS(SecretKeyJobCtx* ctx, JSGlobalObject* lexicalGlobalObject, JSC::JSValue callback)
extern "C" void Bun__SecretKeyJobCtx__runFromJS(SecretKeyJobCtx* ctx, JSGlobalObject* lexicalGlobalObject, JSCallbackArgs* out)
{
ctx->runFromJS(lexicalGlobalObject, callback);
*out = ctx->runFromJS(lexicalGlobalObject);
}
void SecretKeyJobCtx::runFromJS(JSGlobalObject* lexicalGlobalObject, JSC::JSValue callback)
JSCallbackArgs SecretKeyJobCtx::runFromJS(JSGlobalObject* lexicalGlobalObject)
{
VM& vm = lexicalGlobalObject->vm();
ThrowScope scope = DECLARE_THROW_SCOPE(vm);
auto* globalObject = defaultGlobalObject(lexicalGlobalObject);

if (!m_result) {
JSObject* err = createError(lexicalGlobalObject, ErrorCode::ERR_CRYPTO_OPERATION_FAILED, "key generation failed"_s);
Bun__EventLoop__runCallback1(lexicalGlobalObject, JSValue::encode(callback), JSValue::encode(jsUndefined()), JSValue::encode(err));
return;
RETURN_IF_EXCEPTION(scope, {});
return { err };
}

KeyObject keyObject = KeyObject::create(WTF::move(*m_result));

Structure* structure = globalObject->m_JSSecretKeyObjectClassStructure.get(lexicalGlobalObject);
RETURN_IF_EXCEPTION(scope, {});
JSSecretKeyObject* secretKey = JSSecretKeyObject::create(vm, structure, lexicalGlobalObject, WTF::move(keyObject));
RETURN_IF_EXCEPTION(scope, {});

Bun__EventLoop__runCallback2(lexicalGlobalObject,
JSValue::encode(callback),
JSValue::encode(jsUndefined()),
JSValue::encode(jsNull()),
JSValue::encode(secretKey));
return { jsNull(), secretKey };
}

extern "C" void Bun__SecretKeyJobCtx__deinit(SecretKeyJobCtx* ctx)
Expand Down
3 changes: 2 additions & 1 deletion src/jsc/bindings/node/crypto/CryptoKeygen.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include "root.h"
#include "JSCallbackArgs.h"
#include "ncrypto.h"

namespace Bun {
Expand All @@ -11,7 +12,7 @@ struct SecretKeyJobCtx {
~SecretKeyJobCtx() = default;

void runTask(JSC::JSGlobalObject* lexicalGlobalObject);
void runFromJS(JSC::JSGlobalObject* lexicalGlobalObject, JSC::JSValue callback);
JSCallbackArgs runFromJS(JSC::JSGlobalObject* lexicalGlobalObject);
void deinit();

static std::optional<SecretKeyJobCtx> fromJS(JSC::JSGlobalObject*, JSC::ThrowScope&, JSC::JSValue typeValue, JSC::JSValue optionsValue);
Expand Down
Loading