Skip to content

Commit

Permalink
Merge pull request #102 from Snapchat/lf/wasm-async-exception
Browse files Browse the repository at this point in the history
Translate C++ exceptions to async Errors in async functions
  • Loading branch information
li-feng-sc authored Aug 24, 2022
2 parents 7436cd6 + 31aaa17 commit 60a4223
Show file tree
Hide file tree
Showing 39 changed files with 256 additions and 324 deletions.
9 changes: 3 additions & 6 deletions examples/generated-src/wasm/NativeSortItems.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,7 @@ void NativeSortItems::sort(const CppType& self, int32_t w_order,const em::val& w
::djinni_generated::NativeItemList::toCpp(w_items));
}
catch(const std::exception& e) {
djinni::djinni_throw_native_exception(e);
throw;
return djinni::ExceptionHandlingTraits<void>::handleNativeException(e);
}
}
em::val NativeSortItems::create_with_listener(const em::val& w_listener) {
Expand All @@ -31,8 +30,7 @@ em::val NativeSortItems::create_with_listener(const em::val& w_listener) {
return ::djinni_generated::NativeSortItems::fromCpp(r);
}
catch(const std::exception& e) {
djinni::djinni_throw_native_exception(e);
throw;
return djinni::ExceptionHandlingTraits<::djinni_generated::NativeSortItems>::handleNativeException(e);
}
}
em::val NativeSortItems::run_sort(const em::val& w_items) {
Expand All @@ -41,8 +39,7 @@ em::val NativeSortItems::run_sort(const em::val& w_items) {
return ::djinni_generated::NativeItemList::fromCpp(r);
}
catch(const std::exception& e) {
djinni::djinni_throw_native_exception(e);
throw;
return djinni::ExceptionHandlingTraits<::djinni_generated::NativeItemList>::handleNativeException(e);
}
}

Expand Down
75 changes: 25 additions & 50 deletions perftest/generated-src/wasm/NativeDjinniPerfBenchmark.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,7 @@ em::val NativeDjinniPerfBenchmark::getInstance() {
return ::djinni_generated::NativeDjinniPerfBenchmark::fromCpp(r);
}
catch(const std::exception& e) {
djinni::djinni_throw_native_exception(e);
throw;
return djinni::ExceptionHandlingTraits<::djinni_generated::NativeDjinniPerfBenchmark>::handleNativeException(e);
}
}
int64_t NativeDjinniPerfBenchmark::cppTests(const CppType& self) {
Expand All @@ -57,125 +56,111 @@ int64_t NativeDjinniPerfBenchmark::cppTests(const CppType& self) {
return ::djinni::I64::fromCpp(r);
}
catch(const std::exception& e) {
djinni::djinni_throw_native_exception(e);
throw;
return djinni::ExceptionHandlingTraits<::djinni::I64>::handleNativeException(e);
}
}
void NativeDjinniPerfBenchmark::baseline(const CppType& self) {
try {
self->baseline();
}
catch(const std::exception& e) {
djinni::djinni_throw_native_exception(e);
throw;
return djinni::ExceptionHandlingTraits<void>::handleNativeException(e);
}
}
void NativeDjinniPerfBenchmark::argString(const CppType& self, const std::string& w_s) {
try {
self->argString(::djinni::String::toCpp(w_s));
}
catch(const std::exception& e) {
djinni::djinni_throw_native_exception(e);
throw;
return djinni::ExceptionHandlingTraits<void>::handleNativeException(e);
}
}
void NativeDjinniPerfBenchmark::argBinary(const CppType& self, const em::val& w_b) {
try {
self->argBinary(::djinni::Binary::toCpp(w_b));
}
catch(const std::exception& e) {
djinni::djinni_throw_native_exception(e);
throw;
return djinni::ExceptionHandlingTraits<void>::handleNativeException(e);
}
}
void NativeDjinniPerfBenchmark::argDataRef(const CppType& self, const em::val& w_r) {
try {
self->argDataRef(::djinni::NativeDataRef::toCpp(w_r));
}
catch(const std::exception& e) {
djinni::djinni_throw_native_exception(e);
throw;
return djinni::ExceptionHandlingTraits<void>::handleNativeException(e);
}
}
void NativeDjinniPerfBenchmark::argDataView(const CppType& self, const em::val& w_d) {
try {
self->argDataView(::djinni::NativeDataView::toCpp(w_d));
}
catch(const std::exception& e) {
djinni::djinni_throw_native_exception(e);
throw;
return djinni::ExceptionHandlingTraits<void>::handleNativeException(e);
}
}
void NativeDjinniPerfBenchmark::argEnumSixValue(const CppType& self, int32_t w_e) {
try {
self->argEnumSixValue(::djinni_generated::NativeEnumSixValue::toCpp(w_e));
}
catch(const std::exception& e) {
djinni::djinni_throw_native_exception(e);
throw;
return djinni::ExceptionHandlingTraits<void>::handleNativeException(e);
}
}
void NativeDjinniPerfBenchmark::argRecordSixInt(const CppType& self, const em::val& w_r) {
try {
self->argRecordSixInt(::djinni_generated::NativeRecordSixInt::toCpp(w_r));
}
catch(const std::exception& e) {
djinni::djinni_throw_native_exception(e);
throw;
return djinni::ExceptionHandlingTraits<void>::handleNativeException(e);
}
}
void NativeDjinniPerfBenchmark::argListInt(const CppType& self, const em::val& w_v) {
try {
self->argListInt(::djinni::List<::djinni::I64>::toCpp(w_v));
}
catch(const std::exception& e) {
djinni::djinni_throw_native_exception(e);
throw;
return djinni::ExceptionHandlingTraits<void>::handleNativeException(e);
}
}
void NativeDjinniPerfBenchmark::argArrayInt(const CppType& self, const em::val& w_v) {
try {
self->argArrayInt(::djinni::Array<::djinni::I64>::toCpp(w_v));
}
catch(const std::exception& e) {
djinni::djinni_throw_native_exception(e);
throw;
return djinni::ExceptionHandlingTraits<void>::handleNativeException(e);
}
}
void NativeDjinniPerfBenchmark::argObject(const CppType& self, const em::val& w_c) {
try {
self->argObject(::djinni_generated::NativeObjectPlatform::toCpp(w_c));
}
catch(const std::exception& e) {
djinni::djinni_throw_native_exception(e);
throw;
return djinni::ExceptionHandlingTraits<void>::handleNativeException(e);
}
}
void NativeDjinniPerfBenchmark::argListObject(const CppType& self, const em::val& w_l) {
try {
self->argListObject(::djinni::List<::djinni_generated::NativeObjectPlatform>::toCpp(w_l));
}
catch(const std::exception& e) {
djinni::djinni_throw_native_exception(e);
throw;
return djinni::ExceptionHandlingTraits<void>::handleNativeException(e);
}
}
void NativeDjinniPerfBenchmark::argListRecord(const CppType& self, const em::val& w_l) {
try {
self->argListRecord(::djinni::List<::djinni_generated::NativeRecordSixInt>::toCpp(w_l));
}
catch(const std::exception& e) {
djinni::djinni_throw_native_exception(e);
throw;
return djinni::ExceptionHandlingTraits<void>::handleNativeException(e);
}
}
void NativeDjinniPerfBenchmark::argArrayRecord(const CppType& self, const em::val& w_a) {
try {
self->argArrayRecord(::djinni::List<::djinni_generated::NativeRecordSixInt>::toCpp(w_a));
}
catch(const std::exception& e) {
djinni::djinni_throw_native_exception(e);
throw;
return djinni::ExceptionHandlingTraits<void>::handleNativeException(e);
}
}
int64_t NativeDjinniPerfBenchmark::returnInt(const CppType& self, int64_t w_i) {
Expand All @@ -184,8 +169,7 @@ int64_t NativeDjinniPerfBenchmark::returnInt(const CppType& self, int64_t w_i) {
return ::djinni::I64::fromCpp(r);
}
catch(const std::exception& e) {
djinni::djinni_throw_native_exception(e);
throw;
return djinni::ExceptionHandlingTraits<::djinni::I64>::handleNativeException(e);
}
}
std::string NativeDjinniPerfBenchmark::returnString(const CppType& self, int32_t w_size) {
Expand All @@ -194,8 +178,7 @@ std::string NativeDjinniPerfBenchmark::returnString(const CppType& self, int32_t
return ::djinni::String::fromCpp(r);
}
catch(const std::exception& e) {
djinni::djinni_throw_native_exception(e);
throw;
return djinni::ExceptionHandlingTraits<::djinni::String>::handleNativeException(e);
}
}
em::val NativeDjinniPerfBenchmark::returnBinary(const CppType& self, int32_t w_size) {
Expand All @@ -204,8 +187,7 @@ em::val NativeDjinniPerfBenchmark::returnBinary(const CppType& self, int32_t w_s
return ::djinni::Binary::fromCpp(r);
}
catch(const std::exception& e) {
djinni::djinni_throw_native_exception(e);
throw;
return djinni::ExceptionHandlingTraits<::djinni::Binary>::handleNativeException(e);
}
}
em::val NativeDjinniPerfBenchmark::returnObject(const CppType& self) {
Expand All @@ -214,8 +196,7 @@ em::val NativeDjinniPerfBenchmark::returnObject(const CppType& self) {
return ::djinni_generated::NativeObjectNative::fromCpp(r);
}
catch(const std::exception& e) {
djinni::djinni_throw_native_exception(e);
throw;
return djinni::ExceptionHandlingTraits<::djinni_generated::NativeObjectNative>::handleNativeException(e);
}
}
em::val NativeDjinniPerfBenchmark::returnListInt(const CppType& self, int32_t w_size) {
Expand All @@ -224,8 +205,7 @@ em::val NativeDjinniPerfBenchmark::returnListInt(const CppType& self, int32_t w_
return ::djinni::List<::djinni::I64>::fromCpp(r);
}
catch(const std::exception& e) {
djinni::djinni_throw_native_exception(e);
throw;
return djinni::ExceptionHandlingTraits<::djinni::List<::djinni::I64>>::handleNativeException(e);
}
}
em::val NativeDjinniPerfBenchmark::returnArrayInt(const CppType& self, int32_t w_size) {
Expand All @@ -234,8 +214,7 @@ em::val NativeDjinniPerfBenchmark::returnArrayInt(const CppType& self, int32_t w
return ::djinni::Array<::djinni::I64>::fromCpp(r);
}
catch(const std::exception& e) {
djinni::djinni_throw_native_exception(e);
throw;
return djinni::ExceptionHandlingTraits<::djinni::Array<::djinni::I64>>::handleNativeException(e);
}
}
em::val NativeDjinniPerfBenchmark::returnListObject(const CppType& self, int32_t w_size) {
Expand All @@ -244,8 +223,7 @@ em::val NativeDjinniPerfBenchmark::returnListObject(const CppType& self, int32_t
return ::djinni::List<::djinni_generated::NativeObjectNative>::fromCpp(r);
}
catch(const std::exception& e) {
djinni::djinni_throw_native_exception(e);
throw;
return djinni::ExceptionHandlingTraits<::djinni::List<::djinni_generated::NativeObjectNative>>::handleNativeException(e);
}
}
em::val NativeDjinniPerfBenchmark::returnListRecord(const CppType& self, int32_t w_size) {
Expand All @@ -254,8 +232,7 @@ em::val NativeDjinniPerfBenchmark::returnListRecord(const CppType& self, int32_t
return ::djinni::List<::djinni_generated::NativeRecordSixInt>::fromCpp(r);
}
catch(const std::exception& e) {
djinni::djinni_throw_native_exception(e);
throw;
return djinni::ExceptionHandlingTraits<::djinni::List<::djinni_generated::NativeRecordSixInt>>::handleNativeException(e);
}
}
em::val NativeDjinniPerfBenchmark::returnArrayRecord(const CppType& self, int32_t w_size) {
Expand All @@ -264,8 +241,7 @@ em::val NativeDjinniPerfBenchmark::returnArrayRecord(const CppType& self, int32_
return ::djinni::List<::djinni_generated::NativeRecordSixInt>::fromCpp(r);
}
catch(const std::exception& e) {
djinni::djinni_throw_native_exception(e);
throw;
return djinni::ExceptionHandlingTraits<::djinni::List<::djinni_generated::NativeRecordSixInt>>::handleNativeException(e);
}
}
std::string NativeDjinniPerfBenchmark::roundTripString(const CppType& self, const std::string& w_s) {
Expand All @@ -274,8 +250,7 @@ std::string NativeDjinniPerfBenchmark::roundTripString(const CppType& self, cons
return ::djinni::String::fromCpp(r);
}
catch(const std::exception& e) {
djinni::djinni_throw_native_exception(e);
throw;
return djinni::ExceptionHandlingTraits<::djinni::String>::handleNativeException(e);
}
}

Expand Down
3 changes: 1 addition & 2 deletions perftest/generated-src/wasm/NativeObjectNative.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@ void NativeObjectNative::baseline(const CppType& self) {
self->baseline();
}
catch(const std::exception& e) {
djinni::djinni_throw_native_exception(e);
throw;
return djinni::ExceptionHandlingTraits<void>::handleNativeException(e);
}
}

Expand Down
7 changes: 2 additions & 5 deletions src/source/WasmGenerator.scala
Original file line number Diff line number Diff line change
Expand Up @@ -375,11 +375,8 @@ class WasmGenerator(spec: Spec) extends Generator(spec) {
m.ret.fold()(r => w.wl(s"return ${helperClass(r.resolved)}::fromCpp(${cppMarshal.maybeMove("r", r)});"))
}
w.w("catch(const std::exception& e)").braced {
w.wl("djinni::djinni_throw_native_exception(e);");
// The throw line is just to let the C++ compiler know that this
// branch won't return a value. Execution will never reach this
// line as the previous line already throws in JS code.
w.wl("throw;");
val helper = if (!m.ret.isEmpty) helperClass(m.ret.get.resolved) else "void"
w.wl(s"return djinni::ExceptionHandlingTraits<${helper}>::handleNativeException(e);");
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion support-lib/cpp/Future.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ class PromiseBase {
}
private:
detail::SharedStatePtr<T> _sharedState = std::make_shared<SharedState<T>>();
detail::SharedStatePtr<T> _sharedStateReadOnly = _sharedState; // allow calling getFuture() after setValue()

template <typename UpdateFunc>
void updateAndCallResultHandler(UpdateFunc&& updater) {
Expand Down Expand Up @@ -362,7 +363,7 @@ class Future {

template <typename T>
Future<T> detail::PromiseBase<T>::getFuture() {
return Future<T>(std::atomic_load(&_sharedState));
return Future<T>(_sharedStateReadOnly);
}

template <typename U>
Expand Down
8 changes: 8 additions & 0 deletions support-lib/wasm/Future_wasm.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,4 +105,12 @@ class FutureAdaptor
}
};

template<typename U>
struct ExceptionHandlingTraits<FutureAdaptor<U>> {
static em::val handleNativeException(const std::exception& e) {
auto r = FutureAdaptor<U>::NativePromiseType::reject(std::current_exception());
return FutureAdaptor<U>::fromCpp(std::move(r));
}
};

} // namespace djinni
24 changes: 24 additions & 0 deletions support-lib/wasm/djinni_wasm.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -602,6 +602,30 @@ class GenericBuffer: public DataObject {
extern "C" void djinni_register_name_in_ns(const char* prefixedName, const char* namespacedName);
extern "C" void djinni_throw_native_exception(const std::exception& e);

template<typename U>
struct DefaultInit {
static U get() { return U{}; }
};
template<>
struct DefaultInit<em::val> {
static em::val get() { return em::val::undefined(); }
};

template<typename T>
struct ExceptionHandlingTraits {
using R = typename T::JsType;
static R handleNativeException(const std::exception& e) {
djinni_throw_native_exception(e);
return DefaultInit<R>::get();
}
};
template<>
struct ExceptionHandlingTraits<void> {
static void handleNativeException(const std::exception& e) {
djinni_throw_native_exception(e);
}
};

template<typename ClassType>
class DjinniClass_ : public em::class_<ClassType> {
public:
Expand Down
1 change: 1 addition & 0 deletions test-suite/djinni/test.djinni
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ test_helpers = interface +c {

static get_async_result(): future<i32>;
static future_roundtrip(f: future<i32>): future<string>;
static async_early_throw(): future<i32>;

static check_async_interface(i: async_interface): future<string>;
static check_async_composition(i: async_interface): future<string>;
Expand Down
2 changes: 2 additions & 0 deletions test-suite/generated-src/cpp/test_helpers.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@ class TestHelpers {

static ::djinni::Future<std::string> future_roundtrip(::djinni::Future<int32_t> f);

static ::djinni::Future<int32_t> async_early_throw();

static ::djinni::Future<std::string> check_async_interface(const /*not-null*/ std::shared_ptr<AsyncInterface> & i);

static ::djinni::Future<std::string> check_async_composition(const /*not-null*/ std::shared_ptr<AsyncInterface> & i);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,9 @@ public abstract class TestHelpers {
@Nonnull
public static native com.snapchat.djinni.Future<String> futureRoundtrip(@Nonnull com.snapchat.djinni.Future<Integer> f);

@Nonnull
public static native com.snapchat.djinni.Future<Integer> asyncEarlyThrow();

@Nonnull
public static native com.snapchat.djinni.Future<String> checkAsyncInterface(@CheckForNull AsyncInterface i);

Expand Down
Loading

0 comments on commit 60a4223

Please sign in to comment.