|
|
|
@@ -47,7 +47,6 @@
|
|
|
|
|
#include <set>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <sys/uio.h>
|
|
|
|
|
#include <algorithm>
|
|
|
|
|
|
|
|
|
|
#include <typeinfo>
|
|
|
|
|
#include <typeindex>
|
|
|
|
@@ -195,7 +194,8 @@ private:
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void doRun(uv_timer_t* handle) {
|
|
|
|
|
UvEventPort* self = handle == nullptr ? nullptr : reinterpret_cast<UvEventPort*>(handle->data);
|
|
|
|
|
KJ_ASSERT(handle != nullptr);
|
|
|
|
|
UvEventPort* self = reinterpret_cast<UvEventPort*>(handle->data);
|
|
|
|
|
self->run();
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
@@ -237,7 +237,7 @@ static int applyFlags(int fd, uint flags) {
|
|
|
|
|
|
|
|
|
|
static constexpr uint NEW_FD_FLAGS =
|
|
|
|
|
#if __linux__
|
|
|
|
|
kj::LowLevelAsyncIoProvider::ALREADY_CLOEXEC || kj::LowLevelAsyncIoProvider::ALREADY_NONBLOCK ||
|
|
|
|
|
kj::LowLevelAsyncIoProvider::ALREADY_CLOEXEC | kj::LowLevelAsyncIoProvider::ALREADY_NONBLOCK |
|
|
|
|
|
#endif
|
|
|
|
|
kj::LowLevelAsyncIoProvider::TAKE_OWNERSHIP;
|
|
|
|
|
// We always try to open FDs with CLOEXEC and NONBLOCK already set on Linux, but on other platforms
|
|
|
|
@@ -410,6 +410,13 @@ public:
|
|
|
|
|
KJ_SYSCALL(shutdown(fd, SHUT_WR));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if CAPNP_VERSION >= 8000
|
|
|
|
|
kj::Promise<void> whenWriteDisconnected() override {
|
|
|
|
|
// TODO(someday): Implement using UV_DISCONNECT?
|
|
|
|
|
return kj::NEVER_DONE;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
kj::Promise<size_t> tryReadInternal(void* buffer, size_t minBytes, size_t maxBytes,
|
|
|
|
|
size_t alreadyRead) {
|
|
|
|
@@ -564,7 +571,7 @@ public:
|
|
|
|
|
struct sockaddr_in6 inet6;
|
|
|
|
|
} addr;
|
|
|
|
|
addrlen = sizeof(addr);
|
|
|
|
|
KJ_SYSCALL(getsockname(fd, &addr.generic, &addrlen));
|
|
|
|
|
KJ_SYSCALL(::getsockname(fd, &addr.generic, &addrlen));
|
|
|
|
|
switch (addr.generic.sa_family) {
|
|
|
|
|
case AF_INET: return ntohs(addr.inet4.sin_port);
|
|
|
|
|
case AF_INET6: return ntohs(addr.inet6.sin6_port);
|
|
|
|
@@ -690,12 +697,12 @@ class OwnHandle {
|
|
|
|
|
public:
|
|
|
|
|
OwnHandle() = default;
|
|
|
|
|
KJ_DISALLOW_COPY(OwnHandle);
|
|
|
|
|
inline OwnHandle(const v8::Handle<T>& other)
|
|
|
|
|
inline OwnHandle(const v8::Local<T>& other)
|
|
|
|
|
: handle(v8::Isolate::GetCurrent(), other) {}
|
|
|
|
|
inline OwnHandle(OwnHandle&& other) = default;
|
|
|
|
|
|
|
|
|
|
inline OwnHandle& operator=(OwnHandle&& other) = default;
|
|
|
|
|
inline OwnHandle& operator=(const v8::Handle<T>& other) {
|
|
|
|
|
inline OwnHandle& operator=(const v8::Local<T>& other) {
|
|
|
|
|
handle.Reset(v8::Isolate::GetCurrent(), other);
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
@@ -704,7 +711,7 @@ public:
|
|
|
|
|
inline bool operator!=(decltype(nullptr)) { return !handle.IsEmpty(); }
|
|
|
|
|
inline T* operator->() const { return get().operator->(); }
|
|
|
|
|
|
|
|
|
|
inline const v8::Handle<T> get() const {
|
|
|
|
|
inline const v8::Local<T> get() const {
|
|
|
|
|
return v8::Local<T>::New(v8::Isolate::GetCurrent(), handle);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -712,16 +719,16 @@ private:
|
|
|
|
|
v8::Global<T> handle;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
kj::String toKjString(v8::Handle<v8::String> handle) {
|
|
|
|
|
auto buf = kj::heapArray<char>(handle->Utf8Length() + 1);
|
|
|
|
|
handle->WriteUtf8(buf.begin(), buf.size());
|
|
|
|
|
kj::String toKjString(v8::Local<v8::String> handle) {
|
|
|
|
|
auto buf = kj::heapArray<char>(handle->Utf8Length(v8::Isolate::GetCurrent()) + 1);
|
|
|
|
|
handle->WriteUtf8(v8::Isolate::GetCurrent(), buf.begin(), buf.size());
|
|
|
|
|
buf[buf.size() - 1] = 0;
|
|
|
|
|
return kj::String(kj::mv(buf));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
kj::String toKjString(v8::Handle<v8::Value> handle) {
|
|
|
|
|
kj::String toKjString(v8::Local<v8::Value> handle) {
|
|
|
|
|
v8::HandleScope scope(v8::Isolate::GetCurrent());
|
|
|
|
|
return toKjString(handle->ToString());
|
|
|
|
|
return toKjString(handle->ToString(v8::Isolate::GetCurrent()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define KJV8_STACK_STR(name, handle, sizeHint) \
|
|
|
|
@@ -729,16 +736,16 @@ kj::String toKjString(v8::Handle<v8::Value> handle) {
|
|
|
|
|
kj::Array<char> name##_heap; \
|
|
|
|
|
kj::StringPtr name; \
|
|
|
|
|
{ \
|
|
|
|
|
v8::Handle<v8::String> v8str = handle->ToString(); \
|
|
|
|
|
v8::Local<v8::String> v8str = handle->ToString(v8::Isolate::GetCurrent()); \
|
|
|
|
|
char* ptr; \
|
|
|
|
|
size_t len = v8str->Utf8Length(); \
|
|
|
|
|
size_t len = v8str->Utf8Length(v8::Isolate::GetCurrent()); \
|
|
|
|
|
if (len < sizeHint) { \
|
|
|
|
|
ptr = name##_buf; \
|
|
|
|
|
} else { \
|
|
|
|
|
name##_heap = kj::heapArray<char>(len + 1); \
|
|
|
|
|
ptr = name##_heap.begin(); \
|
|
|
|
|
} \
|
|
|
|
|
v8str->WriteUtf8(ptr, len); \
|
|
|
|
|
v8str->WriteUtf8(v8::Isolate::GetCurrent(), ptr, len); \
|
|
|
|
|
ptr[len] = '\0'; \
|
|
|
|
|
name = kj::StringPtr(ptr, len); \
|
|
|
|
|
}
|
|
|
|
@@ -768,14 +775,14 @@ v8::Local<v8::Value> toJsException(kj::Exception&& exception) {
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
kj::Exception fromJsException(v8::Handle<v8::Value> exception) {
|
|
|
|
|
kj::Exception fromJsException(v8::Local<v8::Value> exception) {
|
|
|
|
|
kj::Exception::Type type = kj::Exception::Type::FAILED;
|
|
|
|
|
kj::String description;
|
|
|
|
|
|
|
|
|
|
if (exception->IsObject()) {
|
|
|
|
|
v8::HandleScope scope(v8::Isolate::GetCurrent());
|
|
|
|
|
v8::Object* obj = v8::Object::Cast(*exception);
|
|
|
|
|
v8::Handle<v8::Value> value = obj->Get(newSymbol("kjType"));
|
|
|
|
|
v8::Local<v8::Value> value = obj->Get(newSymbol("kjType"));
|
|
|
|
|
if (!value.IsEmpty() && !value->IsUndefined()) {
|
|
|
|
|
auto name = toKjString(value);
|
|
|
|
|
if (name == "overloaded") {
|
|
|
|
@@ -787,7 +794,7 @@ kj::Exception fromJsException(v8::Handle<v8::Value> exception) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
v8::Handle<v8::Value> stack = obj->Get(newSymbol("stack"));
|
|
|
|
|
v8::Local<v8::Value> stack = obj->Get(newSymbol("stack"));
|
|
|
|
|
if (!stack.IsEmpty() && !stack->IsUndefined()) {
|
|
|
|
|
description = toKjString(stack);
|
|
|
|
|
} else {
|
|
|
|
@@ -866,6 +873,17 @@ class Wrapper {
|
|
|
|
|
handle.SetWeak(this, &deleteCallback, v8::WeakCallbackType::kParameter);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
~WrappedObject() {
|
|
|
|
|
// Since destructors might perform non-trivial operations, including calling back into
|
|
|
|
|
// JavaScript, delay the destructor until the next turn of the event loop.
|
|
|
|
|
T* ptrCopy = ptr;
|
|
|
|
|
kj::evalLater([ptrCopy]() {
|
|
|
|
|
delete ptrCopy;
|
|
|
|
|
}).detach([](kj::Exception&& exception) {
|
|
|
|
|
KJ_LOG(ERROR, exception);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void deleteCallback(const v8::WeakCallbackInfo<WrappedObject>& data) {
|
|
|
|
|
delete reinterpret_cast<WrappedObject*>(data.GetParameter());
|
|
|
|
|
}
|
|
|
|
@@ -874,7 +892,9 @@ class Wrapper {
|
|
|
|
|
public:
|
|
|
|
|
template <typename T>
|
|
|
|
|
v8::Local<v8::Object> wrap(T* ptr) {
|
|
|
|
|
v8::Local<v8::Object> obj = getFunctionTemplate<T>()->GetFunction()->NewInstance();
|
|
|
|
|
v8::Local<v8::Object> obj = getFunctionTemplate<T>()
|
|
|
|
|
->GetFunction(v8::Isolate::GetCurrent()->GetCurrentContext()).ToLocalChecked()->NewInstance(v8::Isolate::GetCurrent()->GetCurrentContext())
|
|
|
|
|
.ToLocalChecked();
|
|
|
|
|
obj->SetAlignedPointerInInternalField(0, new WrappedObject<T>(obj, ptr));
|
|
|
|
|
return obj;
|
|
|
|
|
}
|
|
|
|
@@ -885,24 +905,27 @@ public:
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
|
static kj::Maybe<T&> tryUnwrap(v8::Handle<v8::Value> hdl) {
|
|
|
|
|
static kj::Maybe<T&> tryUnwrap(v8::Local<v8::Value> hdl) {
|
|
|
|
|
if (!hdl->IsObject()) return nullptr;
|
|
|
|
|
|
|
|
|
|
v8::Handle<v8::Object> obj(v8::Handle<v8::Object>::Cast(hdl));
|
|
|
|
|
v8::Local<v8::Object> obj(v8::Local<v8::Object>::Cast(hdl));
|
|
|
|
|
if (getFunctionTemplate<T>()->HasInstance(obj)) {
|
|
|
|
|
return *reinterpret_cast<WrappedObject<T>*>(obj->GetAlignedPointerFromInternalField(0))->ptr;
|
|
|
|
|
} else {
|
|
|
|
|
v8::Handle<v8::Value> native = obj->GetHiddenValue(newSymbol("capnp::native"));
|
|
|
|
|
if (native.IsEmpty() || native->IsUndefined()) {
|
|
|
|
|
return nullptr;
|
|
|
|
|
} else {
|
|
|
|
|
v8::Isolate* isolate = v8::Isolate::GetCurrent();
|
|
|
|
|
v8::Local<v8::Value> native;
|
|
|
|
|
if (obj->GetPrivate(isolate->GetCurrentContext(),
|
|
|
|
|
v8::Private::ForApi(isolate, newSymbol("capnp::native"))).ToLocal(&native) &&
|
|
|
|
|
!native->IsUndefined()) {
|
|
|
|
|
return tryUnwrap<T>(native);
|
|
|
|
|
} else {
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
|
static kj::Maybe<T&> unwrap(v8::Handle<v8::Value> hdl) {
|
|
|
|
|
static kj::Maybe<T&> unwrap(v8::Local<v8::Value> hdl) {
|
|
|
|
|
KJ_IF_MAYBE(result, tryUnwrap<T>(hdl)) {
|
|
|
|
|
return *result;
|
|
|
|
|
} else {
|
|
|
|
@@ -919,7 +942,7 @@ private:
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
|
static v8::Handle<v8::FunctionTemplate> getFunctionTemplate() {
|
|
|
|
|
static v8::Local<v8::FunctionTemplate> getFunctionTemplate() {
|
|
|
|
|
// Get the singleton FunctionTemplate for some wrapped type T.
|
|
|
|
|
|
|
|
|
|
// We allocate on the heap in order to prevent the destructor from running on shutdown, when
|
|
|
|
@@ -931,9 +954,9 @@ private:
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
|
static v8::Handle<v8::FunctionTemplate> newFunctionTemplate() {
|
|
|
|
|
static v8::Local<v8::FunctionTemplate> newFunctionTemplate() {
|
|
|
|
|
const std::type_info& type = typeid(T);
|
|
|
|
|
v8::Handle<v8::FunctionTemplate> result = v8::FunctionTemplate::New(v8::Isolate::GetCurrent());
|
|
|
|
|
v8::Local<v8::FunctionTemplate> result = v8::FunctionTemplate::New(v8::Isolate::GetCurrent());
|
|
|
|
|
result->InstanceTemplate()->SetInternalFieldCount(1);
|
|
|
|
|
|
|
|
|
|
// TODO(someday): Make stuff work with -fno-rtti? node itself is compiled without RTTI...
|
|
|
|
@@ -951,7 +974,7 @@ private:
|
|
|
|
|
if (name##_maybe == nullptr) KJV8_TYPE_ERROR(name, type); \
|
|
|
|
|
type& name KJ_UNUSED = KJ_ASSERT_NONNULL(name##_maybe)
|
|
|
|
|
|
|
|
|
|
kj::Maybe<kj::ArrayPtr<const byte>> unwrapBuffer(v8::Handle<v8::Value> value) {
|
|
|
|
|
kj::Maybe<kj::ArrayPtr<const byte>> unwrapBuffer(v8::Local<v8::Value> value) {
|
|
|
|
|
if (!node::Buffer::HasInstance(value)) {
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
@@ -971,7 +994,7 @@ void deleteArray(char*, void* hint) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
|
v8::Handle<v8::Value> wrapBuffer(kj::Array<T>&& array) {
|
|
|
|
|
v8::Local<v8::Value> wrapBuffer(kj::Array<T>&& array) {
|
|
|
|
|
char* data = reinterpret_cast<char*>(array.begin());
|
|
|
|
|
size_t size = array.size() * sizeof(T);
|
|
|
|
|
return node::Buffer::New(v8::Isolate::GetCurrent(), data, size, &deleteArray<T>,
|
|
|
|
@@ -1013,15 +1036,19 @@ void setNative(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
|
|
|
|
// passed to fromJs().
|
|
|
|
|
|
|
|
|
|
if (args[0]->IsObject()) {
|
|
|
|
|
v8::Object::Cast(*args[0])->SetHiddenValue(newSymbol("capnp::native"), args[1]);
|
|
|
|
|
v8::Isolate* isolate = v8::Isolate::GetCurrent();
|
|
|
|
|
v8::Object::Cast(*args[0])->SetPrivate(
|
|
|
|
|
isolate->GetCurrentContext(),
|
|
|
|
|
v8::Private::ForApi(isolate, newSymbol("capnp::native")),
|
|
|
|
|
args[1]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
v8::Handle<v8::Value> valueToJs(CapnpContext& context, capnp::DynamicValue::Reader value,
|
|
|
|
|
capnp::Type type, v8::Handle<v8::Value> capConstructor);
|
|
|
|
|
v8::Local<v8::Value> valueToJs(CapnpContext& context, capnp::DynamicValue::Reader value,
|
|
|
|
|
capnp::Type type, v8::Local<v8::Value> capConstructor);
|
|
|
|
|
|
|
|
|
|
v8::Handle<v8::Value> schemaToObject(capnp::ParsedSchema schema, CapnpContext& context,
|
|
|
|
|
v8::Handle<v8::Value> wrappedContext) {
|
|
|
|
|
v8::Local<v8::Value> schemaToObject(capnp::ParsedSchema schema, CapnpContext& context,
|
|
|
|
|
v8::Local<v8::Value> wrappedContext) {
|
|
|
|
|
auto proto = schema.getProto();
|
|
|
|
|
if (proto.isConst()) {
|
|
|
|
|
auto c = schema.asConst();
|
|
|
|
@@ -1060,7 +1087,7 @@ void import(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
liftKj(args, [&]() -> v8::Handle<v8::Value> {
|
|
|
|
|
liftKj(args, [&]() -> v8::Local<v8::Value> {
|
|
|
|
|
kj::Array<kj::String> searchPath;
|
|
|
|
|
kj::Array<kj::StringPtr> searchPathPtrs;
|
|
|
|
|
if (!args[2]->IsUndefined()) {
|
|
|
|
@@ -1068,7 +1095,7 @@ void import(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
|
|
|
|
searchPath = kj::heapArray<kj::String>(arr->Length());
|
|
|
|
|
searchPathPtrs = kj::heapArray<kj::StringPtr>(searchPath.size());
|
|
|
|
|
for (uint i: kj::indices(searchPath)) {
|
|
|
|
|
searchPath[i] = toKjString(arr->Get(i)->ToString());
|
|
|
|
|
searchPath[i] = toKjString(arr->Get(i)->ToString(v8::Isolate::GetCurrent()));
|
|
|
|
|
searchPathPtrs[i] = searchPath[i];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@@ -1087,7 +1114,7 @@ void import(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void enumerateMethods(capnp::InterfaceSchema schema, v8::Handle<v8::Object> methodMap,
|
|
|
|
|
void enumerateMethods(capnp::InterfaceSchema schema, v8::Local<v8::Object> methodMap,
|
|
|
|
|
CapnpContext& context, std::set<uint64_t>& seen) {
|
|
|
|
|
auto proto = schema.getProto();
|
|
|
|
|
if (seen.insert(proto.getId()).second) {
|
|
|
|
@@ -1111,7 +1138,7 @@ void methods(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
|
|
|
|
KJV8_UNWRAP(CapnpContext, context, args.Data());
|
|
|
|
|
KJV8_UNWRAP(capnp::Schema, schema, args[0]);
|
|
|
|
|
|
|
|
|
|
liftKj(args, [&]() -> v8::Handle<v8::Value> {
|
|
|
|
|
liftKj(args, [&]() -> v8::Local<v8::Value> {
|
|
|
|
|
auto proto = schema.getProto();
|
|
|
|
|
KJ_REQUIRE(proto.isInterface(), "not an interface type", proto.getDisplayName());
|
|
|
|
|
|
|
|
|
@@ -1149,7 +1176,7 @@ struct ServerResults: public kj::Refcounted {
|
|
|
|
|
// Becomes null when call returns.
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
kj::Maybe<capnp::DynamicStruct::Builder> unwrapBuilder(v8::Handle<v8::Value> handle) {
|
|
|
|
|
kj::Maybe<capnp::DynamicStruct::Builder> unwrapBuilder(v8::Local<v8::Value> handle) {
|
|
|
|
|
// We accept either StructBuilder or Request<DynamicStruct, DynamicStruct>.
|
|
|
|
|
capnp::DynamicStruct::Builder builder;
|
|
|
|
|
KJ_IF_MAYBE(request, Wrapper::tryUnwrap<ClientRequest>(handle)) {
|
|
|
|
@@ -1220,7 +1247,7 @@ struct ServerRequest {
|
|
|
|
|
// Becomes non-null when getResults() is first called. Subsequent calls return the same object.
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
kj::Maybe<capnp::DynamicStruct::Reader> unwrapReader(v8::Handle<v8::Value> handle) {
|
|
|
|
|
kj::Maybe<capnp::DynamicStruct::Reader> unwrapReader(v8::Local<v8::Value> handle) {
|
|
|
|
|
// We accept any builder as well as Response<DynamicStruct>.
|
|
|
|
|
KJ_IF_MAYBE(response, Wrapper::tryUnwrap<ClientResponse>(handle)) {
|
|
|
|
|
return response->response.map(
|
|
|
|
@@ -1256,7 +1283,7 @@ void newBuilder(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
|
|
|
|
KJV8_UNWRAP(CapnpContext, context, args.Data());
|
|
|
|
|
KJV8_UNWRAP(capnp::Schema, schema, args[0]);
|
|
|
|
|
|
|
|
|
|
liftKj(args, [&]() -> v8::Handle<v8::Value> {
|
|
|
|
|
liftKj(args, [&]() -> v8::Local<v8::Value> {
|
|
|
|
|
KJ_REQUIRE(schema.getProto().isStruct(),
|
|
|
|
|
"not a struct type", schema.getProto().getDisplayName());
|
|
|
|
|
|
|
|
|
@@ -1272,7 +1299,7 @@ void copyBuilder(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
|
|
|
|
KJV8_UNWRAP(CapnpContext, context, args.Data());
|
|
|
|
|
KJV8_UNWRAP_READER(reader, args[0]);
|
|
|
|
|
|
|
|
|
|
liftKj(args, [&]() -> v8::Handle<v8::Value> {
|
|
|
|
|
liftKj(args, [&]() -> v8::Local<v8::Value> {
|
|
|
|
|
return context.wrapper.wrap(new StructBuilder(reader));
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
@@ -1285,7 +1312,7 @@ void structToString(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
|
|
|
|
|
|
|
|
|
KJV8_UNWRAP_READER(reader, args[0]);
|
|
|
|
|
|
|
|
|
|
liftKj(args, [&]() -> v8::Handle<v8::Value> {
|
|
|
|
|
liftKj(args, [&]() -> v8::Local<v8::Value> {
|
|
|
|
|
return newString(kj::str(reader.getSchema().getProto().getDisplayName(), reader).cStr());
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
@@ -1294,36 +1321,36 @@ void structToString(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
|
|
|
|
|
|
|
|
|
struct FromJsConverter {
|
|
|
|
|
CapnpContext& context;
|
|
|
|
|
v8::Handle<v8::Value> contextHandle;
|
|
|
|
|
v8::Handle<v8::Function> localCapType;
|
|
|
|
|
v8::Local<v8::Value> contextHandle;
|
|
|
|
|
v8::Local<v8::Function> localCapType;
|
|
|
|
|
|
|
|
|
|
capnp::DynamicCapability::Client fromLocalCap(
|
|
|
|
|
capnp::InterfaceSchema schema, v8::Handle<v8::Object> object);
|
|
|
|
|
capnp::InterfaceSchema schema, v8::Local<v8::Object> object);
|
|
|
|
|
|
|
|
|
|
capnp::Orphan<capnp::DynamicValue> int64FromJs(v8::Handle<v8::Value> js) {
|
|
|
|
|
capnp::Orphan<capnp::DynamicValue> int64FromJs(v8::Local<v8::Value> js) {
|
|
|
|
|
if (js->IsNumber()) {
|
|
|
|
|
return js->IntegerValue();
|
|
|
|
|
return js->IntegerValue(v8::Isolate::GetCurrent()->GetCurrentContext()).ToChecked();
|
|
|
|
|
} else {
|
|
|
|
|
KJV8_STACK_STR(text, js, 32);
|
|
|
|
|
char* end;
|
|
|
|
|
int64_t result = strtoll(text.cStr(), &end, 0);
|
|
|
|
|
if (text.size() == 0 || *end != '\0') {
|
|
|
|
|
return js->IntegerValue();
|
|
|
|
|
return js->IntegerValue(v8::Isolate::GetCurrent()->GetCurrentContext()).ToChecked();
|
|
|
|
|
} else {
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
capnp::Orphan<capnp::DynamicValue> uint64FromJs(v8::Handle<v8::Value> js) {
|
|
|
|
|
capnp::Orphan<capnp::DynamicValue> uint64FromJs(v8::Local<v8::Value> js) {
|
|
|
|
|
if (js->IsNumber()) {
|
|
|
|
|
return js->IntegerValue();
|
|
|
|
|
return js->IntegerValue(v8::Isolate::GetCurrent()->GetCurrentContext()).ToChecked();
|
|
|
|
|
} else {
|
|
|
|
|
KJV8_STACK_STR(text, js, 32);
|
|
|
|
|
char* end;
|
|
|
|
|
uint64_t result = strtoull(text.cStr(), &end, 0);
|
|
|
|
|
if (text.size() == 0 || *end != '\0') {
|
|
|
|
|
return js->IntegerValue();
|
|
|
|
|
return js->IntegerValue(v8::Isolate::GetCurrent()->GetCurrentContext()).ToChecked();
|
|
|
|
|
} else {
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
@@ -1332,30 +1359,30 @@ struct FromJsConverter {
|
|
|
|
|
|
|
|
|
|
capnp::Orphan<capnp::DynamicValue> orphanFromJs(
|
|
|
|
|
capnp::StructSchema::Field field, capnp::Orphanage orphanage,
|
|
|
|
|
capnp::Type type, v8::Handle<v8::Value> js) {
|
|
|
|
|
capnp::Type type, v8::Local<v8::Value> js) {
|
|
|
|
|
switch (type.which()) {
|
|
|
|
|
case capnp::schema::Type::VOID:
|
|
|
|
|
// Accept any false-y value.
|
|
|
|
|
if (!js->BooleanValue()) {
|
|
|
|
|
if (!js->BooleanValue(v8::Isolate::GetCurrent())) {
|
|
|
|
|
return capnp::VOID;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case capnp::schema::Type::BOOL: return js->BooleanValue();
|
|
|
|
|
case capnp::schema::Type::INT8: return js->IntegerValue();
|
|
|
|
|
case capnp::schema::Type::INT16: return js->IntegerValue();
|
|
|
|
|
case capnp::schema::Type::INT32: return js->IntegerValue();
|
|
|
|
|
case capnp::schema::Type::BOOL: return js->BooleanValue(v8::Isolate::GetCurrent());
|
|
|
|
|
case capnp::schema::Type::INT8: return js->IntegerValue(v8::Isolate::GetCurrent()->GetCurrentContext()).ToChecked();
|
|
|
|
|
case capnp::schema::Type::INT16: return js->IntegerValue(v8::Isolate::GetCurrent()->GetCurrentContext()).ToChecked();
|
|
|
|
|
case capnp::schema::Type::INT32: return js->IntegerValue(v8::Isolate::GetCurrent()->GetCurrentContext()).ToChecked();
|
|
|
|
|
case capnp::schema::Type::INT64: return int64FromJs(js);
|
|
|
|
|
case capnp::schema::Type::UINT8: return js->IntegerValue();
|
|
|
|
|
case capnp::schema::Type::UINT16: return js->IntegerValue();
|
|
|
|
|
case capnp::schema::Type::UINT32: return js->IntegerValue();
|
|
|
|
|
case capnp::schema::Type::UINT8: return js->IntegerValue(v8::Isolate::GetCurrent()->GetCurrentContext()).ToChecked();
|
|
|
|
|
case capnp::schema::Type::UINT16: return js->IntegerValue(v8::Isolate::GetCurrent()->GetCurrentContext()).ToChecked();
|
|
|
|
|
case capnp::schema::Type::UINT32: return js->IntegerValue(v8::Isolate::GetCurrent()->GetCurrentContext()).ToChecked();
|
|
|
|
|
case capnp::schema::Type::UINT64: return uint64FromJs(js);
|
|
|
|
|
case capnp::schema::Type::FLOAT32: return js->NumberValue();
|
|
|
|
|
case capnp::schema::Type::FLOAT64: return js->NumberValue();
|
|
|
|
|
case capnp::schema::Type::FLOAT32: return js->NumberValue(v8::Isolate::GetCurrent()->GetCurrentContext()).ToChecked();
|
|
|
|
|
case capnp::schema::Type::FLOAT64: return js->NumberValue(v8::Isolate::GetCurrent()->GetCurrentContext()).ToChecked();
|
|
|
|
|
case capnp::schema::Type::TEXT: {
|
|
|
|
|
v8::HandleScope scope(v8::Isolate::GetCurrent());
|
|
|
|
|
auto str = js->ToString();
|
|
|
|
|
capnp::Orphan<capnp::Text> orphan = orphanage.newOrphan<capnp::Text>(str->Utf8Length());
|
|
|
|
|
str->WriteUtf8(orphan.get().begin());
|
|
|
|
|
auto str = js->ToString(v8::Isolate::GetCurrent());
|
|
|
|
|
capnp::Orphan<capnp::Text> orphan = orphanage.newOrphan<capnp::Text>(str->Utf8Length(v8::Isolate::GetCurrent()));
|
|
|
|
|
str->WriteUtf8(v8::Isolate::GetCurrent(), orphan.get().begin(), orphan.get().size());
|
|
|
|
|
return kj::mv(orphan);
|
|
|
|
|
}
|
|
|
|
|
case capnp::schema::Type::DATA:
|
|
|
|
@@ -1413,7 +1440,7 @@ struct FromJsConverter {
|
|
|
|
|
KJ_IF_MAYBE(enumerant, schema.findEnumerantByName(name)) {
|
|
|
|
|
return capnp::DynamicEnum(*enumerant);
|
|
|
|
|
} else if (js->IsUint32()) {
|
|
|
|
|
return capnp::DynamicEnum(schema, js->Uint32Value());
|
|
|
|
|
return capnp::DynamicEnum(schema, js->Uint32Value(v8::Isolate::GetCurrent()->GetCurrentContext()).ToChecked());
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
@@ -1439,8 +1466,10 @@ struct FromJsConverter {
|
|
|
|
|
} else KJ_IF_MAYBE(cap, Wrapper::tryUnwrap<capnp::DynamicCapability::Client>(js)) {
|
|
|
|
|
return orphanage.newOrphanCopy(*cap);
|
|
|
|
|
} else if (!localCapType.IsEmpty()) {
|
|
|
|
|
v8::Handle<v8::Value> arg = js;
|
|
|
|
|
auto wrapped = localCapType->NewInstance(1, &arg);
|
|
|
|
|
v8::Local<v8::Value> arg = js;
|
|
|
|
|
auto wrapped = localCapType->NewInstance(
|
|
|
|
|
v8::Isolate::GetCurrent()->GetCurrentContext(), 1, &arg)
|
|
|
|
|
.ToLocalChecked();
|
|
|
|
|
if (!wrapped.IsEmpty()) {
|
|
|
|
|
auto cap = fromLocalCap(schema, wrapped);
|
|
|
|
|
return orphanage.newOrphanCopy(cap);
|
|
|
|
@@ -1457,8 +1486,10 @@ struct FromJsConverter {
|
|
|
|
|
} else KJ_IF_MAYBE(cap, Wrapper::tryUnwrap<capnp::DynamicCapability::Client>(js)) {
|
|
|
|
|
return orphanage.newOrphanCopy(*cap);
|
|
|
|
|
} else if (!localCapType.IsEmpty()) {
|
|
|
|
|
v8::Handle<v8::Value> arg = js;
|
|
|
|
|
auto wrapped = localCapType->NewInstance(1, &arg);
|
|
|
|
|
v8::Local<v8::Value> arg = js;
|
|
|
|
|
auto wrapped = localCapType->NewInstance(
|
|
|
|
|
v8::Isolate::GetCurrent()->GetCurrentContext(), 1, &arg)
|
|
|
|
|
.ToLocalChecked();
|
|
|
|
|
if (!wrapped.IsEmpty()) {
|
|
|
|
|
auto cap = fromLocalCap(capnp::Schema::from<capnp::Capability>(), wrapped);
|
|
|
|
|
return orphanage.newOrphanCopy(cap);
|
|
|
|
@@ -1493,7 +1524,7 @@ struct FromJsConverter {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool fieldFromJs(capnp::DynamicStruct::Builder builder, capnp::StructSchema::Field field,
|
|
|
|
|
v8::Handle<v8::Value> js) {
|
|
|
|
|
v8::Local<v8::Value> js) {
|
|
|
|
|
if ((js->IsNull() || js->IsUndefined()) && !field.getType().isVoid()) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
@@ -1528,12 +1559,12 @@ struct FromJsConverter {
|
|
|
|
|
auto schema = builder.getSchema();
|
|
|
|
|
// for (auto field: schema.getFields()) {
|
|
|
|
|
// kj::StringPtr name = field.getProto().getName();
|
|
|
|
|
// v8::Handle<v8::Value> value = js->Get(newSymbol(name.begin(), name.size()));
|
|
|
|
|
// v8::Local<v8::Value> value = js->Get(newSymbol(name.begin(), name.size()));
|
|
|
|
|
// if (!value.IsEmpty() && !value->IsUndefined()) {
|
|
|
|
|
// fieldFromJs(builder, field, value);
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
v8::Local<v8::Array> fieldNames = js->GetPropertyNames();
|
|
|
|
|
v8::Local<v8::Array> fieldNames = js->GetPropertyNames(v8::Isolate::GetCurrent()->GetCurrentContext()).ToLocalChecked();
|
|
|
|
|
for (uint i: kj::range(0u, fieldNames->Length())) {
|
|
|
|
|
auto jsName = fieldNames->Get(i);
|
|
|
|
|
KJV8_STACK_STR(fieldName, jsName, 32);
|
|
|
|
@@ -1562,11 +1593,11 @@ void fromJs(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
|
|
|
|
|
|
|
|
|
KJV8_UNWRAP(CapnpContext, context, args.Data());
|
|
|
|
|
KJV8_UNWRAP_BUILDER(builder, args[0]);
|
|
|
|
|
v8::Handle<v8::Value> jsValue = args[1];
|
|
|
|
|
v8::Local<v8::Value> jsValue = args[1];
|
|
|
|
|
|
|
|
|
|
v8::Handle<v8::Function> localCapType = emptyHandle;
|
|
|
|
|
v8::Local<v8::Function> localCapType = emptyHandle;
|
|
|
|
|
if (args[2]->IsFunction()) {
|
|
|
|
|
localCapType = v8::Handle<v8::Function>::Cast(args[2]);
|
|
|
|
|
localCapType = v8::Local<v8::Function>::Cast(args[2]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
liftKj(args, [&]() -> void {
|
|
|
|
@@ -1595,12 +1626,12 @@ void fromJs(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
|
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
bool fieldToJs(CapnpContext& context, v8::Handle<v8::Object> object,
|
|
|
|
|
bool fieldToJs(CapnpContext& context, v8::Local<v8::Object> object,
|
|
|
|
|
capnp::DynamicStruct::Reader reader, capnp::StructSchema::Field field,
|
|
|
|
|
v8::Handle<v8::Value> capConstructor);
|
|
|
|
|
v8::Local<v8::Value> capConstructor);
|
|
|
|
|
|
|
|
|
|
v8::Handle<v8::Value> valueToJs(CapnpContext& context, capnp::DynamicValue::Reader value,
|
|
|
|
|
capnp::Type type, v8::Handle<v8::Value> capConstructor) {
|
|
|
|
|
v8::Local<v8::Value> valueToJs(CapnpContext& context, capnp::DynamicValue::Reader value,
|
|
|
|
|
capnp::Type type, v8::Local<v8::Value> capConstructor) {
|
|
|
|
|
switch (value.getType()) {
|
|
|
|
|
case capnp::DynamicValue::UNKNOWN:
|
|
|
|
|
return v8::Undefined(v8::Isolate::GetCurrent());
|
|
|
|
@@ -1683,11 +1714,13 @@ v8::Handle<v8::Value> valueToJs(CapnpContext& context, capnp::DynamicValue::Read
|
|
|
|
|
v8::EscapableHandleScope scope(v8::Isolate::GetCurrent());
|
|
|
|
|
auto cap = value.as<capnp::DynamicCapability>();
|
|
|
|
|
capnp::Schema schema = cap.getSchema();
|
|
|
|
|
v8::Handle<v8::Value> result = context.wrapper.wrapCopy(kj::mv(cap));
|
|
|
|
|
v8::Local<v8::Value> result = context.wrapper.wrapCopy(kj::mv(cap));
|
|
|
|
|
if (capConstructor->IsFunction()) {
|
|
|
|
|
v8::Function* func = v8::Function::Cast(*capConstructor);
|
|
|
|
|
v8::Handle<v8::Value> args[2] = { result, context.wrapper.wrapCopy(schema) };
|
|
|
|
|
result = func->NewInstance(kj::size(args), args);
|
|
|
|
|
v8::Local<v8::Value> args[2] = { result, context.wrapper.wrapCopy(schema) };
|
|
|
|
|
result = func->NewInstance(
|
|
|
|
|
v8::Isolate::GetCurrent()->GetCurrentContext(), kj::size(args), args)
|
|
|
|
|
.ToLocalChecked();
|
|
|
|
|
if (result.IsEmpty()) {
|
|
|
|
|
return emptyHandle;
|
|
|
|
|
}
|
|
|
|
@@ -1699,11 +1732,13 @@ v8::Handle<v8::Value> valueToJs(CapnpContext& context, capnp::DynamicValue::Read
|
|
|
|
|
v8::EscapableHandleScope scope(v8::Isolate::GetCurrent());
|
|
|
|
|
auto cap = value.as<capnp::AnyPointer>().getAs<capnp::Capability>();
|
|
|
|
|
capnp::DynamicCapability::Client dynamicCap(kj::mv(cap));
|
|
|
|
|
v8::Handle<v8::Value> result = context.wrapper.wrapCopy(kj::mv(dynamicCap));
|
|
|
|
|
v8::Local<v8::Value> result = context.wrapper.wrapCopy(kj::mv(dynamicCap));
|
|
|
|
|
if (capConstructor->IsFunction()) {
|
|
|
|
|
v8::Function* func = v8::Function::Cast(*capConstructor);
|
|
|
|
|
v8::Handle<v8::Value> args[1] = { result };
|
|
|
|
|
result = func->NewInstance(kj::size(args), args);
|
|
|
|
|
v8::Local<v8::Value> args[1] = { result };
|
|
|
|
|
result = func->NewInstance(
|
|
|
|
|
v8::Isolate::GetCurrent()->GetCurrentContext(), kj::size(args), args)
|
|
|
|
|
.ToLocalChecked();
|
|
|
|
|
if (result.IsEmpty()) {
|
|
|
|
|
return emptyHandle;
|
|
|
|
|
}
|
|
|
|
@@ -1720,11 +1755,11 @@ v8::Handle<v8::Value> valueToJs(CapnpContext& context, capnp::DynamicValue::Read
|
|
|
|
|
KJ_FAIL_ASSERT("Unimplemented DynamicValue type.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool fieldToJs(CapnpContext& context, v8::Handle<v8::Object> object,
|
|
|
|
|
bool fieldToJs(CapnpContext& context, v8::Local<v8::Object> object,
|
|
|
|
|
capnp::DynamicStruct::Reader reader, capnp::StructSchema::Field field,
|
|
|
|
|
v8::Handle<v8::Value> capConstructor) {
|
|
|
|
|
v8::Local<v8::Value> capConstructor) {
|
|
|
|
|
auto proto = field.getProto();
|
|
|
|
|
v8::Handle<v8::Value> fieldValue;
|
|
|
|
|
v8::Local<v8::Value> fieldValue;
|
|
|
|
|
switch (proto.which()) {
|
|
|
|
|
case capnp::schema::Field::SLOT:
|
|
|
|
|
fieldValue = valueToJs(context, reader.get(field), field.getType(), capConstructor);
|
|
|
|
@@ -1755,7 +1790,7 @@ void toJs(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
|
|
|
|
KJV8_UNWRAP(CapnpContext, context, args.Data());
|
|
|
|
|
KJV8_UNWRAP_READER(reader, args[0]);
|
|
|
|
|
|
|
|
|
|
liftKj(args, [&]() -> v8::Handle<v8::Value> {
|
|
|
|
|
liftKj(args, [&]() -> v8::Local<v8::Value> {
|
|
|
|
|
return valueToJs(context, reader, reader.getSchema(), args[1]);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
@@ -1769,7 +1804,7 @@ void toJsParams(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
|
|
|
|
KJV8_UNWRAP(CapnpContext, context, args.Data());
|
|
|
|
|
KJV8_UNWRAP_READER(reader, args[0]);
|
|
|
|
|
|
|
|
|
|
liftKj(args, [&]() -> v8::Handle<v8::Value> {
|
|
|
|
|
liftKj(args, [&]() -> v8::Local<v8::Value> {
|
|
|
|
|
auto schema = reader.getSchema();
|
|
|
|
|
if (schema.getProto().getScopeId() == 0) {
|
|
|
|
|
// This appears to be a parameter set.
|
|
|
|
@@ -1797,10 +1832,10 @@ void expectedSizeFromPrefix(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
|
|
|
|
|
|
|
|
|
KJV8_UNWRAP(CapnpContext, context, args.Data());
|
|
|
|
|
|
|
|
|
|
v8::Handle<v8::Value> bufferHandle = args[0];
|
|
|
|
|
v8::Local<v8::Value> bufferHandle = args[0];
|
|
|
|
|
KJV8_UNWRAP_BUFFER(buffer, bufferHandle);
|
|
|
|
|
|
|
|
|
|
liftKj(args, [&]() -> v8::Handle<v8::Value> {
|
|
|
|
|
liftKj(args, [&]() -> v8::Local<v8::Value> {
|
|
|
|
|
kj::ArrayPtr<const capnp::word> words;
|
|
|
|
|
kj::Array<capnp::word> copy;
|
|
|
|
|
if (reinterpret_cast<uintptr_t>(buffer.begin()) % sizeof(capnp::word) != 0) {
|
|
|
|
@@ -1823,7 +1858,7 @@ void fromBytes(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
|
|
|
|
|
|
|
|
|
KJV8_UNWRAP(CapnpContext, context, args.Data());
|
|
|
|
|
|
|
|
|
|
v8::Handle<v8::Value> bufferHandle = args[0];
|
|
|
|
|
v8::Local<v8::Value> bufferHandle = args[0];
|
|
|
|
|
KJV8_UNWRAP_BUFFER(buffer, bufferHandle);
|
|
|
|
|
|
|
|
|
|
KJV8_UNWRAP(capnp::Schema, schema, args[1]);
|
|
|
|
@@ -1835,10 +1870,10 @@ void fromBytes(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
|
|
|
|
KJV8_TYPE_ERROR(obj, v8::Object);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return liftKj(args, [&]() -> v8::Handle<v8::Value> {
|
|
|
|
|
return liftKj(args, [&]() -> v8::Local<v8::Value> {
|
|
|
|
|
auto options = args[2].As<v8::Object>();
|
|
|
|
|
bool packed = options->Get(newSymbol("packed"))->BooleanValue();
|
|
|
|
|
bool flat = options->Get(newSymbol("flat"))->BooleanValue();
|
|
|
|
|
bool packed = options->Get(newSymbol("packed"))->BooleanValue(v8::Isolate::GetCurrent());
|
|
|
|
|
bool flat = options->Get(newSymbol("flat"))->BooleanValue(v8::Isolate::GetCurrent());
|
|
|
|
|
|
|
|
|
|
v8::Local<v8::Object> wrapper;
|
|
|
|
|
|
|
|
|
@@ -1876,7 +1911,11 @@ void fromBytes(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
wrapper->SetHiddenValue(newSymbol("buffer"), bufferHandle);
|
|
|
|
|
v8::Isolate* isolate = v8::Isolate::GetCurrent();
|
|
|
|
|
wrapper->SetPrivate(
|
|
|
|
|
isolate->GetCurrentContext(),
|
|
|
|
|
v8::Private::ForApi(isolate, newSymbol("capnp::buffer")),
|
|
|
|
|
bufferHandle);
|
|
|
|
|
return wrapper;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
@@ -1889,10 +1928,10 @@ void toBytes(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
|
|
|
|
KJV8_TYPE_ERROR(obj, v8::Object);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return liftKj(args, [&]() -> v8::Handle<v8::Value> {
|
|
|
|
|
return liftKj(args, [&]() -> v8::Local<v8::Value> {
|
|
|
|
|
auto options = args[1].As<v8::Object>();
|
|
|
|
|
bool packed = options->Get(newSymbol("packed"))->BooleanValue();
|
|
|
|
|
bool flat = options->Get(newSymbol("flat"))->BooleanValue();
|
|
|
|
|
bool packed = options->Get(newSymbol("packed"))->BooleanValue(v8::Isolate::GetCurrent());
|
|
|
|
|
bool flat = options->Get(newSymbol("flat"))->BooleanValue(v8::Isolate::GetCurrent());
|
|
|
|
|
|
|
|
|
|
if (flat) {
|
|
|
|
|
// Write whole message to flat array.
|
|
|
|
@@ -1978,7 +2017,7 @@ void connect(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
|
|
|
|
KJV8_UNWRAP(CapnpContext, context, args.Data());
|
|
|
|
|
KJV8_STACK_STR(address, args[0], 64);
|
|
|
|
|
|
|
|
|
|
liftKj(args, [&]() -> v8::Handle<v8::Value> {
|
|
|
|
|
liftKj(args, [&]() -> v8::Local<v8::Value> {
|
|
|
|
|
kj::Maybe<capnp::Capability::Client> bootstrap =
|
|
|
|
|
Wrapper::tryUnwrap<capnp::DynamicCapability::Client>(args[1]);
|
|
|
|
|
|
|
|
|
@@ -2003,9 +2042,9 @@ void connectUnixFd(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
|
|
|
|
// the existing socket.
|
|
|
|
|
|
|
|
|
|
KJV8_UNWRAP(CapnpContext, context, args.Data());
|
|
|
|
|
int fd = args[0]->IntegerValue();
|
|
|
|
|
int fd = args[0]->IntegerValue(v8::Isolate::GetCurrent()->GetCurrentContext()).ToChecked();
|
|
|
|
|
|
|
|
|
|
liftKj(args, [&]() -> v8::Handle<v8::Value> {
|
|
|
|
|
liftKj(args, [&]() -> v8::Local<v8::Value> {
|
|
|
|
|
int fdPair[2];
|
|
|
|
|
KJ_SYSCALL(socketpair(AF_UNIX, SOCK_STREAM, 0, fdPair));
|
|
|
|
|
kj::AutoCloseFd clientEnd(fdPair[0]);
|
|
|
|
@@ -2080,7 +2119,7 @@ void restore(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
|
|
|
|
auto ref = toKjString(args[1]); // TODO(soon): Allow struct reader.
|
|
|
|
|
KJV8_UNWRAP(capnp::Schema, schema, args[2]);
|
|
|
|
|
|
|
|
|
|
liftKj(args, [&]() -> v8::Handle<v8::Value> {
|
|
|
|
|
liftKj(args, [&]() -> v8::Local<v8::Value> {
|
|
|
|
|
KJ_REQUIRE(schema.getProto().isInterface(),
|
|
|
|
|
"not an interface type", schema.getProto().getDisplayName());
|
|
|
|
|
|
|
|
|
@@ -2102,7 +2141,7 @@ void castAs(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
|
|
|
|
KJV8_UNWRAP(capnp::DynamicCapability::Client, cap, args[0]);
|
|
|
|
|
KJV8_UNWRAP(capnp::Schema, schema, args[1]);
|
|
|
|
|
|
|
|
|
|
liftKj(args, [&]() -> v8::Handle<v8::Value> {
|
|
|
|
|
liftKj(args, [&]() -> v8::Local<v8::Value> {
|
|
|
|
|
KJ_REQUIRE(schema.getProto().isInterface(),
|
|
|
|
|
"not an interface type", schema.getProto().getDisplayName());
|
|
|
|
|
return context.wrapper.wrapCopy(cap.castAs<capnp::DynamicCapability>(schema.asInterface()));
|
|
|
|
@@ -2118,7 +2157,7 @@ void schemaFor(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
|
|
|
|
KJV8_UNWRAP(CapnpContext, context, args.Data());
|
|
|
|
|
KJV8_UNWRAP(capnp::DynamicCapability::Client, cap, args[0]);
|
|
|
|
|
|
|
|
|
|
liftKj(args, [&]() -> v8::Handle<v8::Value> {
|
|
|
|
|
liftKj(args, [&]() -> v8::Local<v8::Value> {
|
|
|
|
|
return context.wrapper.wrapCopy(capnp::Schema(cap.getSchema()));
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
@@ -2161,7 +2200,7 @@ void dupCap(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
|
|
|
|
KJV8_UNWRAP(CapnpContext, context, args.Data());
|
|
|
|
|
KJV8_UNWRAP(capnp::DynamicCapability::Client, cap, args[0]);
|
|
|
|
|
|
|
|
|
|
liftKj(args, [&]() -> v8::Handle<v8::Value> {
|
|
|
|
|
liftKj(args, [&]() -> v8::Local<v8::Value> {
|
|
|
|
|
return context.wrapper.wrapCopy(cap);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
@@ -2191,48 +2230,57 @@ void request(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
|
|
|
|
KJV8_UNWRAP(capnp::DynamicCapability::Client, cap, args[0]);
|
|
|
|
|
KJV8_UNWRAP(capnp::InterfaceSchema::Method, method, args[1]);
|
|
|
|
|
|
|
|
|
|
liftKj(args, [&]() -> v8::Handle<v8::Value> {
|
|
|
|
|
liftKj(args, [&]() -> v8::Local<v8::Value> {
|
|
|
|
|
return context.wrapper.wrapCopy(ClientRequest { cap.newRequest(method) });
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void pipelineToJs(CapnpContext& context, capnp::DynamicStruct::Pipeline&& pipeline,
|
|
|
|
|
v8::Handle<v8::Object> js, v8::Handle<v8::Value> capConstructor);
|
|
|
|
|
v8::Local<v8::Object> js, v8::Local<v8::Value> capConstructor);
|
|
|
|
|
|
|
|
|
|
v8::Handle<v8::Object> pipelineStructFieldToJs(CapnpContext& context,
|
|
|
|
|
v8::Local<v8::Object> pipelineStructFieldToJs(CapnpContext& context,
|
|
|
|
|
capnp::DynamicStruct::Pipeline& pipeline,
|
|
|
|
|
capnp::StructSchema::Field field,
|
|
|
|
|
v8::Handle<v8::Value> capConstructor) {
|
|
|
|
|
v8::Handle<v8::Object> fieldValue = v8::Object::New(v8::Isolate::GetCurrent());
|
|
|
|
|
v8::Local<v8::Value> capConstructor) {
|
|
|
|
|
v8::Local<v8::Object> fieldValue = v8::Object::New(v8::Isolate::GetCurrent());
|
|
|
|
|
pipelineToJs(context, pipeline.get(field).releaseAs<capnp::DynamicStruct>(),
|
|
|
|
|
fieldValue, capConstructor);
|
|
|
|
|
return fieldValue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void pipelineToJs(CapnpContext& context, capnp::DynamicStruct::Pipeline&& pipeline,
|
|
|
|
|
v8::Handle<v8::Object> js, v8::Handle<v8::Value> capConstructor) {
|
|
|
|
|
v8::Local<v8::Object> js, v8::Local<v8::Value> capConstructor) {
|
|
|
|
|
v8::HandleScope scope(v8::Isolate::GetCurrent());
|
|
|
|
|
capnp::StructSchema schema = pipeline.getSchema();
|
|
|
|
|
|
|
|
|
|
for (capnp::StructSchema::Field field: schema.getNonUnionFields()) {
|
|
|
|
|
auto proto = field.getProto();
|
|
|
|
|
v8::Handle<v8::Object> fieldValue;
|
|
|
|
|
v8::Local<v8::Object> fieldValue;
|
|
|
|
|
|
|
|
|
|
switch (proto.which()) {
|
|
|
|
|
case capnp::schema::Field::SLOT:
|
|
|
|
|
switch (proto.getSlot().getType().which()) {
|
|
|
|
|
case capnp::schema::Field::SLOT: {
|
|
|
|
|
auto type = field.getType();
|
|
|
|
|
switch (type.which()) {
|
|
|
|
|
case capnp::schema::Type::STRUCT:
|
|
|
|
|
fieldValue = pipelineStructFieldToJs(context, pipeline, field, capConstructor);
|
|
|
|
|
break;
|
|
|
|
|
case capnp::schema::Type::ANY_POINTER:
|
|
|
|
|
if (type.whichAnyPointerKind() !=
|
|
|
|
|
capnp::schema::Type::AnyPointer::Unconstrained::CAPABILITY) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
// fallthrough
|
|
|
|
|
case capnp::schema::Type::INTERFACE: {
|
|
|
|
|
auto cap = pipeline.get(field).releaseAs<capnp::DynamicCapability>();
|
|
|
|
|
capnp::Schema capSchema = cap.getSchema();
|
|
|
|
|
fieldValue = context.wrapper.wrapCopy(kj::mv(cap));
|
|
|
|
|
if (!capConstructor->IsUndefined() && capConstructor->IsFunction()) {
|
|
|
|
|
v8::Function* func = v8::Function::Cast(*capConstructor);
|
|
|
|
|
v8::Handle<v8::Value> args[2] = { fieldValue,
|
|
|
|
|
v8::Local<v8::Value> args[2] = { fieldValue,
|
|
|
|
|
context.wrapper.wrapCopy(kj::mv(capSchema)) };
|
|
|
|
|
fieldValue = func->NewInstance(kj::size(args), args);
|
|
|
|
|
fieldValue = func->NewInstance(
|
|
|
|
|
v8::Isolate::GetCurrent()->GetCurrentContext(), kj::size(args), args)
|
|
|
|
|
.ToLocalChecked();
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
@@ -2240,6 +2288,7 @@ void pipelineToJs(CapnpContext& context, capnp::DynamicStruct::Pipeline&& pipeli
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case capnp::schema::Field::GROUP:
|
|
|
|
|
fieldValue = pipelineStructFieldToJs(context, pipeline, field, capConstructor);
|
|
|
|
@@ -2279,9 +2328,9 @@ void send(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
liftKj(args, [&]() -> v8::Handle<v8::Value> {
|
|
|
|
|
OwnHandle<v8::Function> callback = v8::Handle<v8::Function>::Cast(args[1]);
|
|
|
|
|
OwnHandle<v8::Function> errorCallback = v8::Handle<v8::Function>::Cast(args[2]);
|
|
|
|
|
liftKj(args, [&]() -> v8::Local<v8::Value> {
|
|
|
|
|
OwnHandle<v8::Function> callback = v8::Local<v8::Function>::Cast(args[1]);
|
|
|
|
|
OwnHandle<v8::Function> errorCallback = v8::Local<v8::Function>::Cast(args[2]);
|
|
|
|
|
|
|
|
|
|
auto promise = KJ_REQUIRE_NONNULL(request.request, "Request already sent.").send();
|
|
|
|
|
request.request = nullptr;
|
|
|
|
@@ -2291,7 +2340,7 @@ void send(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
|
|
|
|
auto canceler = kj::refcounted<Canceler>();
|
|
|
|
|
canceler->fulfiller = kj::mv(cancelerPaf.fulfiller);
|
|
|
|
|
|
|
|
|
|
v8::Handle<v8::Object> result = context.wrapper.wrapCopy(kj::addRef(*canceler));
|
|
|
|
|
v8::Local<v8::Object> result = context.wrapper.wrapCopy(kj::addRef(*canceler));
|
|
|
|
|
|
|
|
|
|
// Wait for results and call the callback. Note that we can safely capture `context` by
|
|
|
|
|
// reference because if the context is destroyed, the event loop will stop running.
|
|
|
|
@@ -2301,7 +2350,7 @@ void send(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
|
|
|
|
[&context](OwnHandle<v8::Function>&& callback,
|
|
|
|
|
capnp::Response<capnp::DynamicStruct>&& response) {
|
|
|
|
|
v8::HandleScope scope(v8::Isolate::GetCurrent());
|
|
|
|
|
v8::Handle<v8::Value> args[1] = {
|
|
|
|
|
v8::Local<v8::Value> args[1] = {
|
|
|
|
|
context.wrapper.wrapCopy(ClientResponse { kj::mv(response) })
|
|
|
|
|
};
|
|
|
|
|
// TODO(cleanup): Call() demands an Object parameter but `undefined` is not an object. So
|
|
|
|
@@ -2312,7 +2361,7 @@ void send(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
|
|
|
|
[&context](OwnHandle<v8::Function>&& errorCallback,
|
|
|
|
|
kj::Exception&& exception) {
|
|
|
|
|
v8::HandleScope scope(v8::Isolate::GetCurrent());
|
|
|
|
|
v8::Handle<v8::Value> args[1] = { toJsException(kj::mv(exception)) };
|
|
|
|
|
v8::Local<v8::Value> args[1] = { toJsException(kj::mv(exception)) };
|
|
|
|
|
node::MakeCallback(scope.GetIsolate(), v8::Object::New(scope.GetIsolate()),
|
|
|
|
|
errorCallback.get(), 1, args);
|
|
|
|
|
}));
|
|
|
|
@@ -2339,56 +2388,22 @@ void cancel(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
|
// Local caps
|
|
|
|
|
|
|
|
|
|
struct TypeHash {
|
|
|
|
|
inline size_t operator()(const capnp::Type& t) const {
|
|
|
|
|
return t.hashCode();
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
std::unordered_map<capnp::Type, uint, TypeHash> localCapTypeCounts;
|
|
|
|
|
|
|
|
|
|
void dumpLocalCapTypeCounts(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
|
|
|
|
liftKj(args, [&]() -> void {
|
|
|
|
|
typedef std::pair<capnp::Type, uint> E;
|
|
|
|
|
kj::Array<E> array = KJ_MAP(e, localCapTypeCounts) { return E(e); };
|
|
|
|
|
|
|
|
|
|
std::sort(array.begin(), array.end(),
|
|
|
|
|
[](const E& a, const E& b) { return a.second > b.second; });
|
|
|
|
|
|
|
|
|
|
auto lines = KJ_MAP(e, array) {
|
|
|
|
|
return kj::str('\n', e.second, " ", e.first.asInterface().getProto().getDisplayName());
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
auto typeStats = kj::strArray(lines, "");
|
|
|
|
|
KJ_LOG(WARNING, "dumping types of local capabilities", typeStats);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class LocalCap final: public capnp::DynamicCapability::Server {
|
|
|
|
|
public:
|
|
|
|
|
LocalCap(capnp::InterfaceSchema schema, v8::Handle<v8::Object> object,
|
|
|
|
|
CapnpContext& capnpContext, v8::Handle<v8::Value> capnpContextHandle)
|
|
|
|
|
LocalCap(capnp::InterfaceSchema schema, v8::Local<v8::Object> object,
|
|
|
|
|
CapnpContext& capnpContext, v8::Local<v8::Value> capnpContextHandle)
|
|
|
|
|
: capnp::DynamicCapability::Server(schema),
|
|
|
|
|
object(object), capnpContext(capnpContext), capnpContextHandle(capnpContextHandle) {
|
|
|
|
|
localCapTypeCounts[schema]++;
|
|
|
|
|
}
|
|
|
|
|
object(object), capnpContext(capnpContext), capnpContextHandle(capnpContextHandle) {}
|
|
|
|
|
|
|
|
|
|
~LocalCap() {
|
|
|
|
|
// Call the object's close() method if it has one, so that it can react to the handle being
|
|
|
|
|
// dropped.
|
|
|
|
|
|
|
|
|
|
auto iter = localCapTypeCounts.find(getSchema());
|
|
|
|
|
if (iter == localCapTypeCounts.end()) {
|
|
|
|
|
KJ_LOG(ERROR, "inconsistent type counts");
|
|
|
|
|
} else if (--iter->second == 0) {
|
|
|
|
|
localCapTypeCounts.erase(iter);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
v8::HandleScope scope(v8::Isolate::GetCurrent());
|
|
|
|
|
|
|
|
|
|
auto jsMethod = object->Get(newSymbol("close"));
|
|
|
|
|
if (jsMethod->IsFunction()) {
|
|
|
|
|
auto func = v8::Handle<v8::Function>::Cast(jsMethod);
|
|
|
|
|
auto func = v8::Local<v8::Function>::Cast(jsMethod);
|
|
|
|
|
node::MakeCallback(scope.GetIsolate(), object.get(), func, 0, nullptr);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@@ -2404,7 +2419,7 @@ public:
|
|
|
|
|
KJ_FAIL_ASSERT("Method not implemented.", name) { break; }
|
|
|
|
|
return kj::READY_NOW;
|
|
|
|
|
}
|
|
|
|
|
auto func = v8::Handle<v8::Function>::Cast(jsMethod);
|
|
|
|
|
auto func = v8::Local<v8::Function>::Cast(jsMethod);
|
|
|
|
|
|
|
|
|
|
auto paf = kj::newPromiseAndFulfiller<void>();
|
|
|
|
|
|
|
|
|
@@ -2413,7 +2428,7 @@ public:
|
|
|
|
|
request.context = context;
|
|
|
|
|
request.params = context.getParams();
|
|
|
|
|
|
|
|
|
|
v8::Handle<v8::Value> arg = capnpContext.wrapper.wrapCopy(kj::mv(request));
|
|
|
|
|
v8::Local<v8::Value> arg = capnpContext.wrapper.wrapCopy(kj::mv(request));
|
|
|
|
|
node::MakeCallback(scope.GetIsolate(), object.get(), func, 1, &arg);
|
|
|
|
|
return kj::mv(paf.promise);
|
|
|
|
|
}
|
|
|
|
@@ -2425,7 +2440,7 @@ private:
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
capnp::DynamicCapability::Client FromJsConverter::fromLocalCap(
|
|
|
|
|
capnp::InterfaceSchema schema, v8::Handle<v8::Object> object) {
|
|
|
|
|
capnp::InterfaceSchema schema, v8::Local<v8::Object> object) {
|
|
|
|
|
return kj::heap<LocalCap>(schema, object, context, contextHandle);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -2447,10 +2462,10 @@ void newCap(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
|
|
|
|
KJV8_TYPE_ERROR(obj, v8::Object);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
liftKj(args, [&]() -> v8::Handle<v8::Value> {
|
|
|
|
|
liftKj(args, [&]() -> v8::Local<v8::Value> {
|
|
|
|
|
return context.wrapper.wrapCopy(capnp::DynamicCapability::Client(
|
|
|
|
|
kj::heap<LocalCap>(schema.asInterface(),
|
|
|
|
|
v8::Handle<v8::Object>::Cast(args[1]),
|
|
|
|
|
v8::Local<v8::Object>::Cast(args[1]),
|
|
|
|
|
context, args.Data())));
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
@@ -2467,7 +2482,7 @@ void newPromisedCap(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
|
|
|
|
KJV8_TYPE_ERROR(schema, capnp::InterfaceSchema);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
liftKj(args, [&]() -> v8::Handle<v8::Value> {
|
|
|
|
|
liftKj(args, [&]() -> v8::Local<v8::Value> {
|
|
|
|
|
auto paf = kj::newPromiseAndFulfiller<capnp::Capability::Client>();
|
|
|
|
|
|
|
|
|
|
v8::Local<v8::Object> result = v8::Object::New(v8::Isolate::GetCurrent());
|
|
|
|
@@ -2521,7 +2536,7 @@ void isCap(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
|
|
|
|
//
|
|
|
|
|
// If `value` is a capability, return true.
|
|
|
|
|
|
|
|
|
|
liftKj(args, [&]() -> v8::Handle<v8::Value> {
|
|
|
|
|
liftKj(args, [&]() -> v8::Local<v8::Value> {
|
|
|
|
|
return v8::Boolean::New(v8::Isolate::GetCurrent(),
|
|
|
|
|
Wrapper::tryUnwrap<capnp::DynamicCapability::Client>(args[0]) != nullptr);
|
|
|
|
|
});
|
|
|
|
@@ -2551,7 +2566,7 @@ void getResults(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
|
|
|
|
KJV8_UNWRAP(CapnpContext, context, args.Data());
|
|
|
|
|
KJV8_UNWRAP(ServerRequest, request, args[0]);
|
|
|
|
|
|
|
|
|
|
liftKj(args, [&]() -> v8::Handle<v8::Value> {
|
|
|
|
|
liftKj(args, [&]() -> v8::Local<v8::Value> {
|
|
|
|
|
kj::Own<ServerResults> results;
|
|
|
|
|
KJ_IF_MAYBE(existing, request.results) {
|
|
|
|
|
results = kj::addRef(**existing);
|
|
|
|
@@ -2756,7 +2771,7 @@ void matchPowerboxQuery(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
|
|
|
|
KJV8_UNWRAP_BUFFER(queryBuffer, args[0]);
|
|
|
|
|
KJV8_UNWRAP_BUFFER(candidateBuffer, args[1]);
|
|
|
|
|
|
|
|
|
|
liftKj(args, [&]() -> v8::Handle<v8::Value> {
|
|
|
|
|
liftKj(args, [&]() -> v8::Local<v8::Value> {
|
|
|
|
|
AlignedWords queryWords(queryBuffer);
|
|
|
|
|
AlignedWords candidateWords(candidateBuffer);
|
|
|
|
|
|
|
|
|
@@ -2777,7 +2792,7 @@ void chacha20(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
|
|
|
|
KJV8_UNWRAP_BUFFER(nonce, args[1]);
|
|
|
|
|
KJV8_UNWRAP_BUFFER(key, args[2]);
|
|
|
|
|
|
|
|
|
|
liftKj(args, [&]() -> v8::Handle<v8::Value> {
|
|
|
|
|
liftKj(args, [&]() -> v8::Local<v8::Value> {
|
|
|
|
|
KJ_REQUIRE(key.size() == crypto_stream_chacha20_KEYBYTES);
|
|
|
|
|
KJ_REQUIRE(nonce.size() == crypto_stream_chacha20_NONCEBYTES);
|
|
|
|
|
|
|
|
|
@@ -2796,18 +2811,43 @@ void chacha20(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
|
|
void crashHandler(int signo, siginfo_t* info, void* context) {
|
|
|
|
|
void* traceSpace[32];
|
|
|
|
|
|
|
|
|
|
// ignoreCount = 2 to ignore crashHandler() and signal trampoline.
|
|
|
|
|
auto trace = kj::getStackTrace(traceSpace, 2);
|
|
|
|
|
|
|
|
|
|
auto message = kj::str("*** Received signal #", signo, ": ", strsignal(signo),
|
|
|
|
|
"\nstack: ", stringifyStackTraceAddresses(trace), '\n');
|
|
|
|
|
|
|
|
|
|
kj::FdOutputStream(STDERR_FILENO).write(message.begin(), message.size());
|
|
|
|
|
_exit(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
|
|
void catchSegfaults() {
|
|
|
|
|
struct sigaction action;
|
|
|
|
|
memset(&action, 0, sizeof(action));
|
|
|
|
|
action.sa_flags = SA_SIGINFO | SA_ONSTACK | SA_NODEFER | SA_RESETHAND;
|
|
|
|
|
action.sa_sigaction = &crashHandler;
|
|
|
|
|
KJ_SYSCALL(sigaction(SIGSEGV, &action, nullptr));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endif // SANDSTORM_BUILD
|
|
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
void init(v8::Handle<v8::Object> exports) {
|
|
|
|
|
void init(v8::Local<v8::Object> exports) {
|
|
|
|
|
CapnpContext* context = new CapnpContext;
|
|
|
|
|
auto wrappedContext = context->wrapper.wrap(context);
|
|
|
|
|
|
|
|
|
|
auto mapFunction = [&](const char* name, v8::FunctionCallback callback) {
|
|
|
|
|
exports->Set(newSymbol(name),
|
|
|
|
|
v8::FunctionTemplate::New(v8::Isolate::GetCurrent(), callback, wrappedContext)
|
|
|
|
|
->GetFunction());
|
|
|
|
|
->GetFunction(v8::Isolate::GetCurrent()->GetCurrentContext()).ToLocalChecked());
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
mapFunction("setNative", setNative);
|
|
|
|
@@ -2848,9 +2888,8 @@ void init(v8::Handle<v8::Object> exports) {
|
|
|
|
|
#ifdef SANDSTORM_BUILD
|
|
|
|
|
mapFunction("matchPowerboxQuery", matchPowerboxQuery);
|
|
|
|
|
mapFunction("chacha20", chacha20);
|
|
|
|
|
catchSegfaults();
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
mapFunction("dumpLocalCapTypeCounts", dumpLocalCapTypeCounts);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|