Port to Node 14.
This commit is contained in:
1 parent
a2ed298d34
commit
ca17e686f2
1 file changed
+192
-117
+192
-117
@@ -655,13 +655,36 @@ private:
|
||||
// =======================================================================================
|
||||
// KJ <-> v8 glue
|
||||
|
||||
class JsExceptionThrown {};
|
||||
|
||||
template <typename T>
|
||||
v8::Local<T> check(v8::MaybeLocal<T> ml) {
|
||||
v8::Local<T> result;
|
||||
if (ml.ToLocal(&result)) {
|
||||
return result;
|
||||
} else {
|
||||
throw JsExceptionThrown();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T check(v8::Maybe<T> m) {
|
||||
T result;
|
||||
if (m.To(&result)) {
|
||||
return result;
|
||||
} else {
|
||||
throw JsExceptionThrown();
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(cleanup): V8 added this requirement that everything pass an Isolate. We should probably be
|
||||
// stringing it through rather than using v8::Isolate::GetCurrent() everywhere.
|
||||
v8::Local<v8::String> newString(const char* str) {
|
||||
return v8::String::NewFromUtf8(v8::Isolate::GetCurrent(), str);
|
||||
return check(v8::String::NewFromUtf8(v8::Isolate::GetCurrent(), str));
|
||||
}
|
||||
v8::Local<v8::String> newSymbol(const char* str) {
|
||||
return v8::String::NewFromUtf8(v8::Isolate::GetCurrent(), str, v8::String::kInternalizedString);
|
||||
return check(v8::String::NewFromUtf8(
|
||||
v8::Isolate::GetCurrent(), str, v8::NewStringType::kInternalized));
|
||||
}
|
||||
v8::Local<v8::Integer> newInt32(int i) {
|
||||
return v8::Int32::New(v8::Isolate::GetCurrent(), i);
|
||||
@@ -728,7 +751,7 @@ kj::String toKjString(v8::Local<v8::String> handle) {
|
||||
|
||||
kj::String toKjString(v8::Local<v8::Value> handle) {
|
||||
v8::HandleScope scope(v8::Isolate::GetCurrent());
|
||||
return toKjString(handle->ToString(v8::Isolate::GetCurrent()));
|
||||
return toKjString(check(handle->ToString(v8::Isolate::GetCurrent()->GetCurrentContext())));
|
||||
}
|
||||
|
||||
#define KJV8_STACK_STR(name, handle, sizeHint) \
|
||||
@@ -736,16 +759,18 @@ kj::String toKjString(v8::Local<v8::Value> handle) {
|
||||
kj::Array<char> name##_heap; \
|
||||
kj::StringPtr name; \
|
||||
{ \
|
||||
v8::Local<v8::String> v8str = handle->ToString(v8::Isolate::GetCurrent()); \
|
||||
auto isolate = v8::Isolate::GetCurrent(); \
|
||||
auto jsContext = isolate->GetCurrentContext(); \
|
||||
v8::Local<v8::String> v8str = check(handle->ToString(jsContext)); \
|
||||
char* ptr; \
|
||||
size_t len = v8str->Utf8Length(v8::Isolate::GetCurrent()); \
|
||||
size_t len = v8str->Utf8Length(isolate); \
|
||||
if (len < sizeHint) { \
|
||||
ptr = name##_buf; \
|
||||
} else { \
|
||||
name##_heap = kj::heapArray<char>(len + 1); \
|
||||
ptr = name##_heap.begin(); \
|
||||
} \
|
||||
v8str->WriteUtf8(v8::Isolate::GetCurrent(), ptr, len); \
|
||||
v8str->WriteUtf8(isolate, ptr, len); \
|
||||
ptr[len] = '\0'; \
|
||||
name = kj::StringPtr(ptr, len); \
|
||||
}
|
||||
@@ -756,9 +781,10 @@ v8::Local<v8::Value> toJsException(kj::Exception&& exception) {
|
||||
|
||||
if (result->IsObject()) {
|
||||
v8::Object* obj = v8::Object::Cast(*result);
|
||||
auto context = v8::Isolate::GetCurrent()->GetCurrentContext();
|
||||
|
||||
obj->Set(newSymbol("cppFile"), newString(exception.getFile()));
|
||||
obj->Set(newSymbol("line"), newInt32(exception.getLine()));
|
||||
check(obj->Set(context, newSymbol("cppFile"), newString(exception.getFile())));
|
||||
check(obj->Set(context, newSymbol("line"), newInt32(exception.getLine())));
|
||||
|
||||
const char* type = "unknown";
|
||||
switch (exception.getType()) {
|
||||
@@ -767,7 +793,7 @@ v8::Local<v8::Value> toJsException(kj::Exception&& exception) {
|
||||
case kj::Exception::Type::DISCONNECTED : type = "disconnected" ; break;
|
||||
case kj::Exception::Type::UNIMPLEMENTED : type = "unimplemented"; break;
|
||||
}
|
||||
obj->Set(newSymbol("kjType"), newSymbol(type));
|
||||
check(obj->Set(context, newSymbol("kjType"), newSymbol(type)));
|
||||
} else {
|
||||
KJ_LOG(WARNING, "v8 exception is not an object?");
|
||||
}
|
||||
@@ -781,8 +807,9 @@ kj::Exception fromJsException(v8::Local<v8::Value> exception) {
|
||||
|
||||
if (exception->IsObject()) {
|
||||
v8::HandleScope scope(v8::Isolate::GetCurrent());
|
||||
auto context = scope.GetIsolate()->GetCurrentContext();
|
||||
v8::Object* obj = v8::Object::Cast(*exception);
|
||||
v8::Local<v8::Value> value = obj->Get(newSymbol("kjType"));
|
||||
v8::Local<v8::Value> value = check(obj->Get(context, newSymbol("kjType")));
|
||||
if (!value.IsEmpty() && !value->IsUndefined()) {
|
||||
auto name = toKjString(value);
|
||||
if (name == "overloaded") {
|
||||
@@ -794,7 +821,7 @@ kj::Exception fromJsException(v8::Local<v8::Value> exception) {
|
||||
}
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> stack = obj->Get(newSymbol("stack"));
|
||||
v8::Local<v8::Value> stack = check(obj->Get(context, newSymbol("stack")));
|
||||
if (!stack.IsEmpty() && !stack->IsUndefined()) {
|
||||
description = toKjString(stack);
|
||||
} else {
|
||||
@@ -821,8 +848,12 @@ struct LiftKj_<v8::Local<T>> {
|
||||
template <typename Func>
|
||||
static void apply(const v8::FunctionCallbackInfo<v8::Value>& info, Func&& func) {
|
||||
KJ_IF_MAYBE(exception, kj::runCatchingExceptions([&]() {
|
||||
v8::HandleScope scope(v8::Isolate::GetCurrent());
|
||||
info.GetReturnValue().Set(func());
|
||||
try {
|
||||
v8::HandleScope scope(v8::Isolate::GetCurrent());
|
||||
info.GetReturnValue().Set(func());
|
||||
} catch (const JsExceptionThrown&) {
|
||||
// an exception is already scheduled on the isolate, leave return value empty
|
||||
}
|
||||
})) {
|
||||
info.GetIsolate()->ThrowException(toJsException(kj::mv(*exception)));
|
||||
}
|
||||
@@ -834,9 +865,13 @@ struct LiftKj_<void> {
|
||||
template <typename Func>
|
||||
static void apply(const v8::FunctionCallbackInfo<v8::Value>& info, Func&& func) {
|
||||
KJ_IF_MAYBE(exception, kj::runCatchingExceptions([&]() {
|
||||
v8::HandleScope scope(v8::Isolate::GetCurrent());
|
||||
func();
|
||||
info.GetReturnValue().SetUndefined();
|
||||
try {
|
||||
v8::HandleScope scope(v8::Isolate::GetCurrent());
|
||||
func();
|
||||
info.GetReturnValue().SetUndefined();
|
||||
} catch (const JsExceptionThrown&) {
|
||||
// an exception is already scheduled on the isolate, leave return value empty
|
||||
}
|
||||
})) {
|
||||
info.GetIsolate()->ThrowException(toJsException(kj::mv(*exception)));
|
||||
}
|
||||
@@ -869,7 +904,6 @@ class Wrapper {
|
||||
WrappedObject(v8::Local<v8::Object> obj, T* ptr)
|
||||
: handle(v8::Isolate::GetCurrent(), obj),
|
||||
ptr(ptr) {
|
||||
handle.MarkIndependent();
|
||||
handle.SetWeak(this, &deleteCallback, v8::WeakCallbackType::kParameter);
|
||||
}
|
||||
|
||||
@@ -892,9 +926,9 @@ class Wrapper {
|
||||
public:
|
||||
template <typename T>
|
||||
v8::Local<v8::Object> wrap(T* ptr) {
|
||||
v8::Local<v8::Object> obj = getFunctionTemplate<T>()
|
||||
->GetFunction(v8::Isolate::GetCurrent()->GetCurrentContext()).ToLocalChecked()->NewInstance(v8::Isolate::GetCurrent()->GetCurrentContext())
|
||||
.ToLocalChecked();
|
||||
v8::Local<v8::Object> obj = check(check(getFunctionTemplate<T>()
|
||||
->GetFunction(v8::Isolate::GetCurrent()->GetCurrentContext()))
|
||||
->NewInstance(v8::Isolate::GetCurrent()->GetCurrentContext()));
|
||||
obj->SetAlignedPointerInInternalField(0, new WrappedObject<T>(obj, ptr));
|
||||
return obj;
|
||||
}
|
||||
@@ -997,8 +1031,8 @@ template <typename T>
|
||||
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>,
|
||||
new kj::Array<T>(kj::mv(array))).ToLocalChecked();
|
||||
return check(node::Buffer::New(v8::Isolate::GetCurrent(), data, size, &deleteArray<T>,
|
||||
new kj::Array<T>(kj::mv(array))));
|
||||
}
|
||||
|
||||
// =======================================================================================
|
||||
@@ -1056,14 +1090,16 @@ v8::Local<v8::Value> schemaToObject(capnp::ParsedSchema schema, CapnpContext& co
|
||||
} else {
|
||||
auto result = context.wrapper.wrap(new capnp::Schema(schema));
|
||||
|
||||
result->Set(newSymbol("typeId"),
|
||||
// 64-bit values must be stringified to avoid losing precision.
|
||||
newString(kj::str(proto.getId()).cStr()));
|
||||
auto jsContext = v8::Isolate::GetCurrent()->GetCurrentContext();
|
||||
|
||||
check(result->Set(jsContext, newSymbol("typeId"),
|
||||
// 64-bit values must be stringified to avoid losing precision.
|
||||
newString(kj::str(proto.getId()).cStr())));
|
||||
|
||||
for (auto nested: proto.getNestedNodes()) {
|
||||
kj::StringPtr name = nested.getName();
|
||||
result->Set(newSymbol(name.cStr()),
|
||||
schemaToObject(schema.getNested(name), context, wrappedContext));
|
||||
check(result->Set(jsContext, newSymbol(name.cStr()),
|
||||
schemaToObject(schema.getNested(name), context, wrappedContext)));
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -1091,11 +1127,13 @@ void import(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
kj::Array<kj::String> searchPath;
|
||||
kj::Array<kj::StringPtr> searchPathPtrs;
|
||||
if (!args[2]->IsUndefined()) {
|
||||
auto isolate = v8::Isolate::GetCurrent();
|
||||
auto context = isolate->GetCurrentContext();
|
||||
v8::Array* arr = v8::Array::Cast(*args[2]);
|
||||
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(v8::Isolate::GetCurrent()));
|
||||
searchPath[i] = toKjString(check(check(arr->Get(context, i))->ToString(context)));
|
||||
searchPathPtrs[i] = searchPath[i];
|
||||
}
|
||||
}
|
||||
@@ -1117,6 +1155,7 @@ void import(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
void enumerateMethods(capnp::InterfaceSchema schema, v8::Local<v8::Object> methodMap,
|
||||
CapnpContext& context, std::set<uint64_t>& seen) {
|
||||
auto proto = schema.getProto();
|
||||
auto jsContext = v8::Isolate::GetCurrent()->GetCurrentContext();
|
||||
if (seen.insert(proto.getId()).second) {
|
||||
for (auto superclass: schema.getSuperclasses()) {
|
||||
enumerateMethods(superclass, methodMap, context, seen);
|
||||
@@ -1124,8 +1163,8 @@ void enumerateMethods(capnp::InterfaceSchema schema, v8::Local<v8::Object> metho
|
||||
|
||||
auto methods = schema.getMethods();
|
||||
for (auto method: methods) {
|
||||
methodMap->Set(newSymbol(method.getProto().getName().cStr()),
|
||||
context.wrapper.wrapCopy(method));
|
||||
check(methodMap->Set(jsContext, newSymbol(method.getProto().getName().cStr()),
|
||||
context.wrapper.wrapCopy(method)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1329,13 +1368,13 @@ struct FromJsConverter {
|
||||
|
||||
capnp::Orphan<capnp::DynamicValue> int64FromJs(v8::Local<v8::Value> js) {
|
||||
if (js->IsNumber()) {
|
||||
return js->IntegerValue(v8::Isolate::GetCurrent()->GetCurrentContext()).ToChecked();
|
||||
return check(js->IntegerValue(v8::Isolate::GetCurrent()->GetCurrentContext()));
|
||||
} 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(v8::Isolate::GetCurrent()->GetCurrentContext()).ToChecked();
|
||||
return check(js->IntegerValue(v8::Isolate::GetCurrent()->GetCurrentContext()));
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
@@ -1344,13 +1383,13 @@ struct FromJsConverter {
|
||||
|
||||
capnp::Orphan<capnp::DynamicValue> uint64FromJs(v8::Local<v8::Value> js) {
|
||||
if (js->IsNumber()) {
|
||||
return js->IntegerValue(v8::Isolate::GetCurrent()->GetCurrentContext()).ToChecked();
|
||||
return check(js->IntegerValue(v8::Isolate::GetCurrent()->GetCurrentContext()));
|
||||
} 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(v8::Isolate::GetCurrent()->GetCurrentContext()).ToChecked();
|
||||
return check(js->IntegerValue(v8::Isolate::GetCurrent()->GetCurrentContext()));
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
@@ -1360,29 +1399,33 @@ struct FromJsConverter {
|
||||
capnp::Orphan<capnp::DynamicValue> orphanFromJs(
|
||||
capnp::StructSchema::Field field, capnp::Orphanage orphanage,
|
||||
capnp::Type type, v8::Local<v8::Value> js) {
|
||||
auto isolate = v8::Isolate::GetCurrent();
|
||||
v8::HandleScope scope(isolate);
|
||||
auto jsContext = isolate->GetCurrentContext();
|
||||
|
||||
switch (type.which()) {
|
||||
case capnp::schema::Type::VOID:
|
||||
// Accept any false-y value.
|
||||
if (!js->BooleanValue(v8::Isolate::GetCurrent())) {
|
||||
if (!js->BooleanValue(isolate)) {
|
||||
return capnp::VOID;
|
||||
}
|
||||
break;
|
||||
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::BOOL: return js->BooleanValue(isolate);
|
||||
case capnp::schema::Type::INT8: return check(js->IntegerValue(jsContext));
|
||||
case capnp::schema::Type::INT16: return check(js->IntegerValue(jsContext));
|
||||
case capnp::schema::Type::INT32: return check(js->IntegerValue(jsContext));
|
||||
case capnp::schema::Type::INT64: return int64FromJs(js);
|
||||
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::UINT8: return check(js->IntegerValue(jsContext));
|
||||
case capnp::schema::Type::UINT16: return check(js->IntegerValue(jsContext));
|
||||
case capnp::schema::Type::UINT32: return check(js->IntegerValue(jsContext));
|
||||
case capnp::schema::Type::UINT64: return uint64FromJs(js);
|
||||
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::FLOAT32: return check(js->NumberValue(jsContext));
|
||||
case capnp::schema::Type::FLOAT64: return check(js->NumberValue(jsContext));
|
||||
case capnp::schema::Type::TEXT: {
|
||||
v8::HandleScope scope(v8::Isolate::GetCurrent());
|
||||
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());
|
||||
auto str = check(js->ToString(jsContext));
|
||||
capnp::Orphan<capnp::Text> orphan = orphanage.newOrphan<capnp::Text>(
|
||||
str->Utf8Length(isolate));
|
||||
str->WriteUtf8(isolate, orphan.get().begin(), orphan.get().size());
|
||||
return kj::mv(orphan);
|
||||
}
|
||||
case capnp::schema::Type::DATA:
|
||||
@@ -1401,7 +1444,7 @@ struct FromJsConverter {
|
||||
// Struct lists can't adopt.
|
||||
bool error = false;
|
||||
for (uint i: kj::indices(builder)) {
|
||||
auto element = jsArray->Get(i);
|
||||
auto element = check(jsArray->Get(jsContext, i));
|
||||
if (element->IsObject()) {
|
||||
if (!structFromJs(builder[i].as<capnp::DynamicStruct>(),
|
||||
v8::Object::Cast(*element))) {
|
||||
@@ -1417,7 +1460,7 @@ struct FromJsConverter {
|
||||
bool isPointerList = builder.as<capnp::AnyList>().getElementSize() ==
|
||||
capnp::ElementSize::POINTER;
|
||||
for (uint i: kj::indices(builder)) {
|
||||
auto jsElement = jsArray->Get(i);
|
||||
auto jsElement = check(jsArray->Get(jsContext, i));
|
||||
if (isPointerList && (jsElement->IsNull() || jsElement->IsUndefined())) {
|
||||
// Skip null element.
|
||||
} else {
|
||||
@@ -1434,13 +1477,12 @@ struct FromJsConverter {
|
||||
break;
|
||||
}
|
||||
case capnp::schema::Type::ENUM: {
|
||||
v8::HandleScope scope(v8::Isolate::GetCurrent()); // for string conversion
|
||||
KJV8_STACK_STR(name, js, 32);
|
||||
auto schema = type.asEnum();
|
||||
KJ_IF_MAYBE(enumerant, schema.findEnumerantByName(name)) {
|
||||
return capnp::DynamicEnum(*enumerant);
|
||||
} else if (js->IsUint32()) {
|
||||
return capnp::DynamicEnum(schema, js->Uint32Value(v8::Isolate::GetCurrent()->GetCurrentContext()).ToChecked());
|
||||
return capnp::DynamicEnum(schema, check(js->Uint32Value(jsContext)));
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -1467,9 +1509,7 @@ struct FromJsConverter {
|
||||
return orphanage.newOrphanCopy(*cap);
|
||||
} else if (!localCapType.IsEmpty()) {
|
||||
v8::Local<v8::Value> arg = js;
|
||||
auto wrapped = localCapType->NewInstance(
|
||||
v8::Isolate::GetCurrent()->GetCurrentContext(), 1, &arg)
|
||||
.ToLocalChecked();
|
||||
auto wrapped = check(localCapType->NewInstance(jsContext, 1, &arg));
|
||||
if (!wrapped.IsEmpty()) {
|
||||
auto cap = fromLocalCap(schema, wrapped);
|
||||
return orphanage.newOrphanCopy(cap);
|
||||
@@ -1487,9 +1527,7 @@ struct FromJsConverter {
|
||||
return orphanage.newOrphanCopy(*cap);
|
||||
} else if (!localCapType.IsEmpty()) {
|
||||
v8::Local<v8::Value> arg = js;
|
||||
auto wrapped = localCapType->NewInstance(
|
||||
v8::Isolate::GetCurrent()->GetCurrentContext(), 1, &arg)
|
||||
.ToLocalChecked();
|
||||
auto wrapped = check(localCapType->NewInstance(jsContext, 1, &arg));
|
||||
if (!wrapped.IsEmpty()) {
|
||||
auto cap = fromLocalCap(capnp::Schema::from<capnp::Capability>(), wrapped);
|
||||
return orphanage.newOrphanCopy(cap);
|
||||
@@ -1555,7 +1593,10 @@ struct FromJsConverter {
|
||||
}
|
||||
|
||||
bool structFromJs(capnp::DynamicStruct::Builder builder, v8::Object* js) {
|
||||
v8::HandleScope scope(v8::Isolate::GetCurrent());
|
||||
auto isolate = v8::Isolate::GetCurrent();
|
||||
v8::HandleScope scope(isolate);
|
||||
auto jsContext = isolate->GetCurrentContext();
|
||||
|
||||
auto schema = builder.getSchema();
|
||||
// for (auto field: schema.getFields()) {
|
||||
// kj::StringPtr name = field.getProto().getName();
|
||||
@@ -1564,12 +1605,12 @@ struct FromJsConverter {
|
||||
// fieldFromJs(builder, field, value);
|
||||
// }
|
||||
// }
|
||||
v8::Local<v8::Array> fieldNames = js->GetPropertyNames(v8::Isolate::GetCurrent()->GetCurrentContext()).ToLocalChecked();
|
||||
v8::Local<v8::Array> fieldNames = check(js->GetPropertyNames(jsContext));
|
||||
for (uint i: kj::range(0u, fieldNames->Length())) {
|
||||
auto jsName = fieldNames->Get(i);
|
||||
auto jsName = check(fieldNames->Get(jsContext, i));
|
||||
KJV8_STACK_STR(fieldName, jsName, 32);
|
||||
KJ_IF_MAYBE(field, schema.findFieldByName(fieldName)) {
|
||||
fieldFromJs(builder, *field, js->Get(jsName));
|
||||
fieldFromJs(builder, *field, check(js->Get(jsContext, jsName)));
|
||||
} else {
|
||||
throwException(v8::Exception::TypeError(newString(
|
||||
kj::str("No field named: ", fieldName).cStr())));
|
||||
@@ -1600,6 +1641,10 @@ void fromJs(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
localCapType = v8::Local<v8::Function>::Cast(args[2]);
|
||||
}
|
||||
|
||||
auto isolate = args.GetIsolate();
|
||||
v8::HandleScope scope(isolate);
|
||||
auto jsContext = isolate->GetCurrentContext();
|
||||
|
||||
liftKj(args, [&]() -> void {
|
||||
auto schema = builder.getSchema();
|
||||
|
||||
@@ -1611,7 +1656,7 @@ void fromJs(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
uint length = kj::min(array->Length(), fields.size());
|
||||
|
||||
for (uint i = 0; i < length; i++) {
|
||||
if (!converter.fieldFromJs(builder, fields[i], array->Get(i))) {
|
||||
if (!converter.fieldFromJs(builder, fields[i], check(array->Get(jsContext, i)))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1632,69 +1677,71 @@ bool fieldToJs(CapnpContext& context, v8::Local<v8::Object> object,
|
||||
|
||||
v8::Local<v8::Value> valueToJs(CapnpContext& context, capnp::DynamicValue::Reader value,
|
||||
capnp::Type type, v8::Local<v8::Value> capConstructor) {
|
||||
auto isolate = v8::Isolate::GetCurrent();
|
||||
v8::EscapableHandleScope scope(isolate);
|
||||
auto jsContext = isolate->GetCurrentContext();
|
||||
|
||||
switch (value.getType()) {
|
||||
case capnp::DynamicValue::UNKNOWN:
|
||||
return v8::Undefined(v8::Isolate::GetCurrent());
|
||||
return scope.Escape(v8::Undefined(isolate));
|
||||
case capnp::DynamicValue::VOID:
|
||||
return v8::Null(v8::Isolate::GetCurrent());
|
||||
return scope.Escape(v8::Null(isolate));
|
||||
case capnp::DynamicValue::BOOL:
|
||||
return v8::Boolean::New(v8::Isolate::GetCurrent(), value.as<bool>());
|
||||
return scope.Escape(v8::Boolean::New(isolate, value.as<bool>()));
|
||||
case capnp::DynamicValue::INT: {
|
||||
if (type.which() == capnp::schema::Type::INT64 ||
|
||||
type.which() == capnp::schema::Type::UINT64) {
|
||||
// 64-bit values must be stringified to avoid losing precision.
|
||||
return newString(kj::str(value.as<int64_t>()).cStr());
|
||||
return scope.Escape(newString(kj::str(value.as<int64_t>()).cStr()));
|
||||
} else {
|
||||
return v8::Integer::New(v8::Isolate::GetCurrent(), value.as<int32_t>());
|
||||
return scope.Escape(v8::Integer::New(isolate, value.as<int32_t>()));
|
||||
}
|
||||
}
|
||||
case capnp::DynamicValue::UINT: {
|
||||
if (type.which() == capnp::schema::Type::INT64 ||
|
||||
type.which() == capnp::schema::Type::UINT64) {
|
||||
// 64-bit values must be stringified to avoid losing precision.
|
||||
return newString(kj::str(value.as<uint64_t>()).cStr());
|
||||
return scope.Escape(newString(kj::str(value.as<uint64_t>()).cStr()));
|
||||
} else {
|
||||
return v8::Integer::NewFromUnsigned(v8::Isolate::GetCurrent(), value.as<uint32_t>());
|
||||
return scope.Escape(v8::Integer::NewFromUnsigned(isolate, value.as<uint32_t>()));
|
||||
}
|
||||
}
|
||||
case capnp::DynamicValue::FLOAT:
|
||||
return v8::Number::New(v8::Isolate::GetCurrent(), value.as<double>());
|
||||
return scope.Escape(v8::Number::New(isolate, value.as<double>()));
|
||||
case capnp::DynamicValue::TEXT: {
|
||||
capnp::Text::Reader text = value.as<capnp::Text>();
|
||||
return v8::String::NewFromUtf8(v8::Isolate::GetCurrent(), text.begin(),
|
||||
v8::String::kNormalString, text.size());
|
||||
return scope.Escape(check(v8::String::NewFromUtf8(
|
||||
isolate, text.begin(), v8::NewStringType::kNormal, text.size())));
|
||||
}
|
||||
case capnp::DynamicValue::DATA: {
|
||||
capnp::Data::Reader data = value.as<capnp::Data>();
|
||||
return node::Buffer::Copy(v8::Isolate::GetCurrent(),
|
||||
reinterpret_cast<const char*>(data.begin()), data.size()).ToLocalChecked();
|
||||
return scope.Escape(check(node::Buffer::Copy(isolate,
|
||||
reinterpret_cast<const char*>(data.begin()), data.size())));
|
||||
}
|
||||
case capnp::DynamicValue::LIST: {
|
||||
v8::EscapableHandleScope scope(v8::Isolate::GetCurrent());
|
||||
capnp::DynamicList::Reader list = value.as<capnp::DynamicList>();
|
||||
auto elementType = list.getSchema().getElementType();
|
||||
auto array = v8::Array::New(v8::Isolate::GetCurrent(), list.size());
|
||||
auto array = v8::Array::New(isolate, list.size());
|
||||
for (uint i: kj::indices(list)) {
|
||||
auto subValue = valueToJs(context, list[i], elementType, capConstructor);
|
||||
if (subValue.IsEmpty()) {
|
||||
return emptyHandle;
|
||||
}
|
||||
array->Set(i, subValue);
|
||||
check(array->Set(jsContext, i, subValue));
|
||||
}
|
||||
return scope.Escape(array);
|
||||
}
|
||||
case capnp::DynamicValue::ENUM: {
|
||||
auto enumValue = value.as<capnp::DynamicEnum>();
|
||||
KJ_IF_MAYBE(enumerant, enumValue.getEnumerant()) {
|
||||
return newSymbol(enumerant->getProto().getName().cStr());
|
||||
return scope.Escape(newSymbol(enumerant->getProto().getName().cStr()));
|
||||
} else {
|
||||
return v8::Integer::NewFromUnsigned(v8::Isolate::GetCurrent(), enumValue.getRaw());
|
||||
return scope.Escape(v8::Integer::NewFromUnsigned(isolate, enumValue.getRaw()));
|
||||
}
|
||||
}
|
||||
case capnp::DynamicValue::STRUCT: {
|
||||
v8::EscapableHandleScope scope(v8::Isolate::GetCurrent());
|
||||
capnp::DynamicStruct::Reader reader = value.as<capnp::DynamicStruct>();
|
||||
auto object = v8::Object::New(v8::Isolate::GetCurrent());
|
||||
auto object = v8::Object::New(isolate);
|
||||
KJ_IF_MAYBE(field, reader.which()) {
|
||||
if (!fieldToJs(context, object, reader, *field, capConstructor)) {
|
||||
return emptyHandle;
|
||||
@@ -1711,16 +1758,13 @@ v8::Local<v8::Value> valueToJs(CapnpContext& context, capnp::DynamicValue::Reade
|
||||
return scope.Escape(object);
|
||||
}
|
||||
case capnp::DynamicValue::CAPABILITY: {
|
||||
v8::EscapableHandleScope scope(v8::Isolate::GetCurrent());
|
||||
auto cap = value.as<capnp::DynamicCapability>();
|
||||
capnp::Schema schema = cap.getSchema();
|
||||
v8::Local<v8::Value> result = context.wrapper.wrapCopy(kj::mv(cap));
|
||||
if (capConstructor->IsFunction()) {
|
||||
v8::Function* func = v8::Function::Cast(*capConstructor);
|
||||
v8::Local<v8::Value> args[2] = { result, context.wrapper.wrapCopy(schema) };
|
||||
result = func->NewInstance(
|
||||
v8::Isolate::GetCurrent()->GetCurrentContext(), kj::size(args), args)
|
||||
.ToLocalChecked();
|
||||
result = check(func->NewInstance(jsContext, kj::size(args), args));
|
||||
if (result.IsEmpty()) {
|
||||
return emptyHandle;
|
||||
}
|
||||
@@ -1729,16 +1773,13 @@ v8::Local<v8::Value> valueToJs(CapnpContext& context, capnp::DynamicValue::Reade
|
||||
}
|
||||
case capnp::DynamicValue::ANY_POINTER: {
|
||||
if (type.whichAnyPointerKind() == capnp::schema::Type::AnyPointer::Unconstrained::CAPABILITY) {
|
||||
v8::EscapableHandleScope scope(v8::Isolate::GetCurrent());
|
||||
auto cap = value.as<capnp::AnyPointer>().getAs<capnp::Capability>();
|
||||
capnp::DynamicCapability::Client dynamicCap(kj::mv(cap));
|
||||
v8::Local<v8::Value> result = context.wrapper.wrapCopy(kj::mv(dynamicCap));
|
||||
if (capConstructor->IsFunction()) {
|
||||
v8::Function* func = v8::Function::Cast(*capConstructor);
|
||||
v8::Local<v8::Value> args[1] = { result };
|
||||
result = func->NewInstance(
|
||||
v8::Isolate::GetCurrent()->GetCurrentContext(), kj::size(args), args)
|
||||
.ToLocalChecked();
|
||||
result = check(func->NewInstance(jsContext, kj::size(args), args));
|
||||
if (result.IsEmpty()) {
|
||||
return emptyHandle;
|
||||
}
|
||||
@@ -1747,7 +1788,7 @@ v8::Local<v8::Value> valueToJs(CapnpContext& context, capnp::DynamicValue::Reade
|
||||
} else {
|
||||
capnp::MallocMessageBuilder message;
|
||||
message.setRoot(value.as<capnp::AnyPointer>());
|
||||
return wrapBuffer(capnp::messageToFlatArray(message));
|
||||
return scope.Escape(wrapBuffer(capnp::messageToFlatArray(message)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1758,6 +1799,10 @@ v8::Local<v8::Value> valueToJs(CapnpContext& context, capnp::DynamicValue::Reade
|
||||
bool fieldToJs(CapnpContext& context, v8::Local<v8::Object> object,
|
||||
capnp::DynamicStruct::Reader reader, capnp::StructSchema::Field field,
|
||||
v8::Local<v8::Value> capConstructor) {
|
||||
auto isolate = v8::Isolate::GetCurrent();
|
||||
v8::HandleScope scope(isolate);
|
||||
auto jsContext = isolate->GetCurrentContext();
|
||||
|
||||
auto proto = field.getProto();
|
||||
v8::Local<v8::Value> fieldValue;
|
||||
switch (proto.which()) {
|
||||
@@ -1775,7 +1820,7 @@ setField:
|
||||
if (fieldValue.IsEmpty()) {
|
||||
return false;
|
||||
} else {
|
||||
object->Set(newSymbol(proto.getName().cStr()), fieldValue);
|
||||
check(object->Set(jsContext, newSymbol(proto.getName().cStr()), fieldValue));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1804,6 +1849,10 @@ void toJsParams(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
KJV8_UNWRAP(CapnpContext, context, args.Data());
|
||||
KJV8_UNWRAP_READER(reader, args[0]);
|
||||
|
||||
auto isolate = args.GetIsolate();
|
||||
v8::HandleScope scope(isolate);
|
||||
auto jsContext = isolate->GetCurrentContext();
|
||||
|
||||
liftKj(args, [&]() -> v8::Local<v8::Value> {
|
||||
auto schema = reader.getSchema();
|
||||
if (schema.getProto().getScopeId() == 0) {
|
||||
@@ -1814,12 +1863,13 @@ void toJsParams(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
auto fields = schema.getFields();
|
||||
auto result = v8::Array::New(v8::Isolate::GetCurrent(), fields.size());
|
||||
for (uint i: kj::indices(fields)) {
|
||||
result->Set(i, valueToJs(context, reader.get(fields[i]), fields[i].getType(), args[1]));
|
||||
check(result->Set(jsContext, i, valueToJs(
|
||||
context, reader.get(fields[i]), fields[i].getType(), args[1])));
|
||||
}
|
||||
return result;
|
||||
} else {
|
||||
auto result = v8::Array::New(v8::Isolate::GetCurrent(), 1);
|
||||
result->Set(0, valueToJs(context, reader, reader.getSchema(), args[1]));
|
||||
check(result->Set(jsContext, 0, valueToJs(context, reader, reader.getSchema(), args[1])));
|
||||
return result;
|
||||
}
|
||||
});
|
||||
@@ -1870,10 +1920,16 @@ void fromBytes(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
KJV8_TYPE_ERROR(obj, v8::Object);
|
||||
}
|
||||
|
||||
auto isolate = args.GetIsolate();
|
||||
v8::HandleScope scope(isolate);
|
||||
auto jsContext = isolate->GetCurrentContext();
|
||||
|
||||
return liftKj(args, [&]() -> v8::Local<v8::Value> {
|
||||
auto options = args[2].As<v8::Object>();
|
||||
bool packed = options->Get(newSymbol("packed"))->BooleanValue(v8::Isolate::GetCurrent());
|
||||
bool flat = options->Get(newSymbol("flat"))->BooleanValue(v8::Isolate::GetCurrent());
|
||||
bool packed = check(options->Get(jsContext, newSymbol("packed")))
|
||||
->BooleanValue(v8::Isolate::GetCurrent());
|
||||
bool flat = check(options->Get(jsContext, newSymbol("flat")))
|
||||
->BooleanValue(v8::Isolate::GetCurrent());
|
||||
|
||||
v8::Local<v8::Object> wrapper;
|
||||
|
||||
@@ -1928,10 +1984,16 @@ void toBytes(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
KJV8_TYPE_ERROR(obj, v8::Object);
|
||||
}
|
||||
|
||||
auto isolate = args.GetIsolate();
|
||||
v8::HandleScope scope(isolate);
|
||||
auto jsContext = isolate->GetCurrentContext();
|
||||
|
||||
return liftKj(args, [&]() -> v8::Local<v8::Value> {
|
||||
auto options = args[1].As<v8::Object>();
|
||||
bool packed = options->Get(newSymbol("packed"))->BooleanValue(v8::Isolate::GetCurrent());
|
||||
bool flat = options->Get(newSymbol("flat"))->BooleanValue(v8::Isolate::GetCurrent());
|
||||
bool packed = check(options->Get(jsContext, newSymbol("packed")))
|
||||
->BooleanValue(v8::Isolate::GetCurrent());
|
||||
bool flat = check(options->Get(jsContext, newSymbol("flat")))
|
||||
->BooleanValue(v8::Isolate::GetCurrent());
|
||||
|
||||
if (flat) {
|
||||
// Write whole message to flat array.
|
||||
@@ -2042,7 +2104,7 @@ void connectUnixFd(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
// the existing socket.
|
||||
|
||||
KJV8_UNWRAP(CapnpContext, context, args.Data());
|
||||
int fd = args[0]->IntegerValue(v8::Isolate::GetCurrent()->GetCurrentContext()).ToChecked();
|
||||
int fd = check(args[0]->IntegerValue(v8::Isolate::GetCurrent()->GetCurrentContext()));
|
||||
|
||||
liftKj(args, [&]() -> v8::Local<v8::Value> {
|
||||
int fdPair[2];
|
||||
@@ -2250,7 +2312,10 @@ v8::Local<v8::Object> pipelineStructFieldToJs(CapnpContext& context,
|
||||
|
||||
void pipelineToJs(CapnpContext& context, capnp::DynamicStruct::Pipeline&& pipeline,
|
||||
v8::Local<v8::Object> js, v8::Local<v8::Value> capConstructor) {
|
||||
v8::HandleScope scope(v8::Isolate::GetCurrent());
|
||||
auto isolate = v8::Isolate::GetCurrent();
|
||||
v8::HandleScope scope(isolate);
|
||||
auto jsContext = isolate->GetCurrentContext();
|
||||
|
||||
capnp::StructSchema schema = pipeline.getSchema();
|
||||
|
||||
for (capnp::StructSchema::Field field: schema.getNonUnionFields()) {
|
||||
@@ -2278,9 +2343,8 @@ void pipelineToJs(CapnpContext& context, capnp::DynamicStruct::Pipeline&& pipeli
|
||||
v8::Function* func = v8::Function::Cast(*capConstructor);
|
||||
v8::Local<v8::Value> args[2] = { fieldValue,
|
||||
context.wrapper.wrapCopy(kj::mv(capSchema)) };
|
||||
fieldValue = func->NewInstance(
|
||||
v8::Isolate::GetCurrent()->GetCurrentContext(), kj::size(args), args)
|
||||
.ToLocalChecked();
|
||||
fieldValue = check(func->NewInstance(
|
||||
v8::Isolate::GetCurrent()->GetCurrentContext(), kj::size(args), args));
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -2299,7 +2363,7 @@ void pipelineToJs(CapnpContext& context, capnp::DynamicStruct::Pipeline&& pipeli
|
||||
}
|
||||
|
||||
KJ_ASSERT(!fieldValue.IsEmpty());
|
||||
js->Set(newSymbol(proto.getName().cStr()), fieldValue);
|
||||
check(js->Set(jsContext, newSymbol(proto.getName().cStr()), fieldValue));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2358,8 +2422,7 @@ void send(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
node::MakeCallback(scope.GetIsolate(), v8::Object::New(scope.GetIsolate()),
|
||||
callback.get(), 1, args);
|
||||
})).detach(kj::mvCapture(errorCallback,
|
||||
[&context](OwnHandle<v8::Function>&& errorCallback,
|
||||
kj::Exception&& exception) {
|
||||
[](OwnHandle<v8::Function>&& errorCallback, kj::Exception&& exception) {
|
||||
v8::HandleScope scope(v8::Isolate::GetCurrent());
|
||||
v8::Local<v8::Value> args[1] = { toJsException(kj::mv(exception)) };
|
||||
node::MakeCallback(scope.GetIsolate(), v8::Object::New(scope.GetIsolate()),
|
||||
@@ -2399,9 +2462,11 @@ public:
|
||||
// Call the object's close() method if it has one, so that it can react to the handle being
|
||||
// dropped.
|
||||
|
||||
v8::HandleScope scope(v8::Isolate::GetCurrent());
|
||||
auto isolate = v8::Isolate::GetCurrent();
|
||||
v8::HandleScope scope(isolate);
|
||||
auto jsContext = isolate->GetCurrentContext();
|
||||
|
||||
auto jsMethod = object->Get(newSymbol("close"));
|
||||
auto jsMethod = check(object->Get(jsContext, newSymbol("close")));
|
||||
if (jsMethod->IsFunction()) {
|
||||
auto func = v8::Local<v8::Function>::Cast(jsMethod);
|
||||
node::MakeCallback(scope.GetIsolate(), object.get(), func, 0, nullptr);
|
||||
@@ -2410,9 +2475,11 @@ public:
|
||||
|
||||
kj::Promise<void> call(capnp::InterfaceSchema::Method method,
|
||||
capnp::CallContext<capnp::DynamicStruct, capnp::DynamicStruct> context) override {
|
||||
v8::HandleScope scope(v8::Isolate::GetCurrent());
|
||||
auto isolate = v8::Isolate::GetCurrent();
|
||||
v8::HandleScope scope(isolate);
|
||||
auto jsContext = isolate->GetCurrentContext();
|
||||
|
||||
auto jsMethod = object->Get(newSymbol(method.getProto().getName().cStr()));
|
||||
auto jsMethod = check(object->Get(jsContext, newSymbol(method.getProto().getName().cStr())));
|
||||
|
||||
if (!jsMethod->IsFunction()) {
|
||||
auto name = method.getProto().getName();
|
||||
@@ -2482,16 +2549,20 @@ void newPromisedCap(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
KJV8_TYPE_ERROR(schema, capnp::InterfaceSchema);
|
||||
}
|
||||
|
||||
auto isolate = args.GetIsolate();
|
||||
v8::HandleScope scope(isolate);
|
||||
auto jsContext = isolate->GetCurrentContext();
|
||||
|
||||
liftKj(args, [&]() -> v8::Local<v8::Value> {
|
||||
auto paf = kj::newPromiseAndFulfiller<capnp::Capability::Client>();
|
||||
|
||||
v8::Local<v8::Object> result = v8::Object::New(v8::Isolate::GetCurrent());
|
||||
result->Set(newSymbol("cap"),
|
||||
check(result->Set(jsContext, newSymbol("cap"),
|
||||
context.wrapper.wrapCopy(
|
||||
capnp::Capability::Client(kj::mv(paf.promise))
|
||||
.castAs<capnp::DynamicCapability>(schema.asInterface())));
|
||||
result->Set(newSymbol("fulfiller"),
|
||||
context.wrapper.wrapCopy(kj::mv(paf.fulfiller)));
|
||||
.castAs<capnp::DynamicCapability>(schema.asInterface()))));
|
||||
check(result->Set(jsContext, newSymbol("fulfiller"),
|
||||
context.wrapper.wrapCopy(kj::mv(paf.fulfiller))));
|
||||
return result;
|
||||
});
|
||||
}
|
||||
@@ -2844,10 +2915,14 @@ void init(v8::Local<v8::Object> exports) {
|
||||
CapnpContext* context = new CapnpContext;
|
||||
auto wrappedContext = context->wrapper.wrap(context);
|
||||
|
||||
auto isolate = v8::Isolate::GetCurrent();
|
||||
v8::HandleScope scope(isolate);
|
||||
auto jsContext = isolate->GetCurrentContext();
|
||||
|
||||
auto mapFunction = [&](const char* name, v8::FunctionCallback callback) {
|
||||
exports->Set(newSymbol(name),
|
||||
v8::FunctionTemplate::New(v8::Isolate::GetCurrent(), callback, wrappedContext)
|
||||
->GetFunction(v8::Isolate::GetCurrent()->GetCurrentContext()).ToLocalChecked());
|
||||
check(exports->Set(jsContext, newSymbol(name),
|
||||
check(v8::FunctionTemplate::New(isolate, callback, wrappedContext)
|
||||
->GetFunction(jsContext))));
|
||||
};
|
||||
|
||||
mapFunction("setNative", setNative);
|
||||
|
||||
Reference in new issue
Block a user