diff --git a/cpp/platform_support/dom_connector.hpp b/cpp/platform_support/dom_connector.hpp index 3daf3b6..6268f35 100644 --- a/cpp/platform_support/dom_connector.hpp +++ b/cpp/platform_support/dom_connector.hpp @@ -11,6 +11,7 @@ #include struct JsStub; +struct JsFuncStub; class JsObjectTempRef; using JsObjectRef = std::shared_ptr; @@ -18,19 +19,21 @@ extern "C" { /** * @brief Increments the refcount of an opaque JavaScript object ID. */ -extern void _js_ref(unsigned int obj); +extern void _js_ref(unsigned int obj_id); /** * @brief Decrements the refcount of an opaque JavaScript object ID. * * When the refcount reaches zero the object ID must not be used anymore. */ -extern void _js_unref(unsigned int obj); +extern void _js_unref(unsigned int obj_id); -extern void _js_call_sync(unsigned int obj, const char* func, JsStub* args, size_t n_args); -extern void _js_call_async(unsigned int obj, const char* func, JsStub* args, size_t n_args, void(*callback)(void*, const JsStub&), void* ctx, unsigned int dict_depth); -extern void _js_get_property(unsigned int obj, const char* property, void(*callback)(void*, const JsStub&), void* ctx, unsigned int dict_depth); -extern void _js_set_property(unsigned int obj, const char* property, JsStub* arg); +extern void* _js_get_property(unsigned int obj_id, const char* property, unsigned int dict_depth, JsStub* p_out); +extern void _js_set_property(unsigned int obj_id, const char* property, JsStub* arg); +extern void* _js_call_sync(unsigned int obj_id, const char* func, JsStub* args, size_t n_args, unsigned int dict_depth, JsStub* p_out); +extern void _js_call_async(unsigned int obj_id, const char* func, JsStub* args, size_t n_args, void(*callback)(void*, const JsStub&, const JsStub&), void* ctx, unsigned int dict_depth); + +extern void _js_release(void*); } @@ -53,10 +56,11 @@ struct JsStub { struct JsFuncStub { uintptr_t callback; uintptr_t ctx; + unsigned int dict_depth; }; struct JsArrayStub { - uintptr_t start; + uintptr_t begin; uintptr_t end; }; @@ -75,7 +79,10 @@ class JsTransferStorage { delete [] ptr; } for (auto ptr: funcs) { - delete [] ptr; + delete ptr; + } + for (auto ptr: arrays) { + delete ptr; } } @@ -115,7 +122,7 @@ class JsTransferStorage { } JsStub to_js(fibre::Callback val) { - JsFuncStub* func = new JsFuncStub{(uintptr_t)val.get_ptr(), (uintptr_t)val.get_ctx()}; + JsFuncStub* func = new JsFuncStub{(uintptr_t)val.get_ptr(), (uintptr_t)val.get_ctx(), 0}; funcs.push_back(func); return {JsType::kFunc, (uintptr_t)func}; } @@ -146,14 +153,10 @@ class JsObjectTempRef { } template fibre::RichStatus get_property(std::string property, TVal* result, unsigned int dict_depth = 0) { - fibre::RichStatus status; - fibre::Callback callback{ - [&](const JsStub& stub) { - status = from_js(stub, result); - } - }; - _js_get_property(id_, property.data(), callback.get_ptr(), - callback.get_ctx(), dict_depth); + JsStub out; + void* storage = _js_get_property(id_, property.data(), dict_depth, &out); + fibre::RichStatus status = from_js(out, result); + _js_release(storage); return status; } @@ -172,7 +175,7 @@ class JsObjectTempRef { template void call_async(std::string func, - fibre::Callback callback, + fibre::Callback callback, unsigned int dict_depth, TArgs... args) { JsTransferStorage storage; @@ -266,7 +269,7 @@ static inline fibre::RichStatus from_js(const JsStub& stub, fibre::cbufptr_t* ou // time allocated buffer. Maybe we can optimize this? F_RET_IF(stub.type != JsType::kArray, "expected array type but got " << (int)stub.type); JsArrayStub* array_stub = (JsArrayStub*)stub.val; - *output = {(const unsigned char*)array_stub->start, (const unsigned char*)array_stub->end}; + *output = {(const unsigned char*)array_stub->begin, (const unsigned char*)array_stub->end}; return fibre::RichStatus::success(); } diff --git a/cpp/platform_support/dom_connector.js b/cpp/platform_support/dom_connector.js index fc538a2..387a688 100644 --- a/cpp/platform_support/dom_connector.js +++ b/cpp/platform_support/dom_connector.js @@ -170,7 +170,7 @@ mergeInto(LibraryManager.library, { const cb = Module.asm.__indirect_function_table.get(callback); const storage = makeStorage(); try { - const ptr = Module._malloc(8 + args.length); + const ptr = Module._malloc(8 * args.length); try { for (let i = 0; i < args.length; ++i) { toWasm(storage, args[i], ptr + 8 * i); @@ -215,19 +215,22 @@ mergeInto(LibraryManager.library, { __js_ref = _js_ref; __js_unref = _js_unref; - __js_call_async = _js_call_async; __js_get_property = _js_get_property; __js_set_property = _js_set_property; + __js_call_async = _js_call_async; + __js_release = _js_release; }, _js_ref: function() {}, _js_ref__deps: ['$method_support'], _js_unref: function() {}, _js_unref__deps: ['$method_support'], - _js_call_async: function() {}, - _js_call_async__deps: ['$method_support'], _js_get_property: function() {}, _js_get_property__deps: ['$method_support'], _js_set_property: function() {}, _js_set_property__deps: ['$method_support'], + _js_call_async: function() {}, + _js_call_async__deps: ['$method_support'], + _js_release: function() {}, + _js_release__deps: ['$method_support'], }); diff --git a/cpp/platform_support/webusb_backend.cpp b/cpp/platform_support/webusb_backend.cpp index 964d3c8..60ef9ca 100644 --- a/cpp/platform_support/webusb_backend.cpp +++ b/cpp/platform_support/webusb_backend.cpp @@ -30,7 +30,7 @@ class WebUsb final : public UsbHostController { on_lost_device_t on_lost) final; RichStatus stop() final; - void on_get_devices_finished(const JsStub& stub); + void on_get_devices_finished(const JsStub& result_stub, const JsStub& error_stub); void on_connect(const JsStub* args, size_t n_args); void on_disconnect(const JsStub* args, size_t n_args); @@ -51,10 +51,10 @@ struct WebUsbDevice final : UsbDevice { RichStatus bulk_in_transfer(uint8_t ep_num, bufptr_t buffer, Callback callback) final; RichStatus bulk_out_transfer(uint8_t ep_num, cbufptr_t buffer, Callback callback) final; - void on_open_finished(const JsStub& stub); - void on_claim_interface_finished(const JsStub& stub); - void on_bulk_in_transfer_finished(const JsStub& stub); - void on_bulk_out_transfer_finished(const JsStub& stub); + void on_open_finished(const JsStub& result_stub, const JsStub& error_stub); + void on_claim_interface_finished(const JsStub& result_stub, const JsStub& error_stub); + void on_bulk_in_transfer_finished(const JsStub& result_stub, const JsStub& error_stub); + void on_bulk_out_transfer_finished(const JsStub& result_stub, const JsStub& error_stub); WebUsb* webusb_; JsObjectRef ref_; @@ -101,11 +101,11 @@ RichStatus WebUsb::stop() { return RichStatus::success(); } -void WebUsb::on_get_devices_finished(const JsStub& stub) { +void WebUsb::on_get_devices_finished(const JsStub& result_stub, const JsStub& error_stub) { F_LOG_D(logger_, "got devices"); std::vector devices; - if (F_LOG_IF_ERR(logger_, from_js(stub, &devices), "in device list")) { + if (F_LOG_IF_ERR(logger_, from_js(result_stub, &devices), "in device list")) { return; } @@ -243,21 +243,26 @@ RichStatus WebUsbDevice::bulk_out_transfer(uint8_t ep_num, cbufptr_t buffer, Cal return RichStatus::success(); } -void WebUsbDevice::on_open_finished(const JsStub& stub) { - F_LOG_D(webusb_->logger_, "open finished"); - open_cb_.invoke_and_clear(this); +void WebUsbDevice::on_open_finished(const JsStub& result_stub, const JsStub& error_stub) { + if (error_stub.type != JsType::kUndefined) { + F_LOG_D(webusb_->logger_, "open failed with type " << (int)error_stub.type); + // TODO: error handling + } else { + F_LOG_D(webusb_->logger_, "open finished"); + open_cb_.invoke_and_clear(this); + } } -void WebUsbDevice::on_claim_interface_finished(const JsStub& stub) { +void WebUsbDevice::on_claim_interface_finished(const JsStub& result_stub, const JsStub& error_stub) { F_LOG_D(webusb_->logger_, "claim_interface finished"); claim_interface_cb_.invoke_and_clear(this); } -void WebUsbDevice::on_bulk_in_transfer_finished(const JsStub& stub) { +void WebUsbDevice::on_bulk_in_transfer_finished(const JsStub& result_stub, const JsStub& error_stub) { F_LOG_T(webusb_->logger_, "bulk_in_transfer finished"); std::unordered_map result; - if (F_LOG_IF_ERR(webusb_->logger_, from_js(stub, &result), "can't parse transfer result")) { + if (F_LOG_IF_ERR(webusb_->logger_, from_js(result_stub, &result), "can't parse transfer result")) { return; // TODO: propagate error to callback } @@ -296,11 +301,11 @@ void WebUsbDevice::on_bulk_in_transfer_finished(const JsStub& stub) { bulk_in_transfer_cb_.invoke_and_clear(RichStatus::success(), end); } -void WebUsbDevice::on_bulk_out_transfer_finished(const JsStub& stub) { +void WebUsbDevice::on_bulk_out_transfer_finished(const JsStub& result_stub, const JsStub& error_stub) { F_LOG_T(webusb_->logger_, "bulk_out_transfer finished"); std::unordered_map result; - if (F_LOG_IF_ERR(webusb_->logger_, from_js(stub, &result), "can't parse transfer result")) { + if (F_LOG_IF_ERR(webusb_->logger_, from_js(result_stub, &result), "can't parse transfer result")) { return; // TODO: propagate error to callback }