Skip to content

Commit 60a4223

Browse files
authored
Merge pull request #102 from Snapchat/lf/wasm-async-exception
Translate C++ exceptions to async Errors in async functions
2 parents 7436cd6 + 31aaa17 commit 60a4223

39 files changed

+256
-324
lines changed

examples/generated-src/wasm/NativeSortItems.cpp

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,7 @@ void NativeSortItems::sort(const CppType& self, int32_t w_order,const em::val& w
2121
::djinni_generated::NativeItemList::toCpp(w_items));
2222
}
2323
catch(const std::exception& e) {
24-
djinni::djinni_throw_native_exception(e);
25-
throw;
24+
return djinni::ExceptionHandlingTraits<void>::handleNativeException(e);
2625
}
2726
}
2827
em::val NativeSortItems::create_with_listener(const em::val& w_listener) {
@@ -31,8 +30,7 @@ em::val NativeSortItems::create_with_listener(const em::val& w_listener) {
3130
return ::djinni_generated::NativeSortItems::fromCpp(r);
3231
}
3332
catch(const std::exception& e) {
34-
djinni::djinni_throw_native_exception(e);
35-
throw;
33+
return djinni::ExceptionHandlingTraits<::djinni_generated::NativeSortItems>::handleNativeException(e);
3634
}
3735
}
3836
em::val NativeSortItems::run_sort(const em::val& w_items) {
@@ -41,8 +39,7 @@ em::val NativeSortItems::run_sort(const em::val& w_items) {
4139
return ::djinni_generated::NativeItemList::fromCpp(r);
4240
}
4341
catch(const std::exception& e) {
44-
djinni::djinni_throw_native_exception(e);
45-
throw;
42+
return djinni::ExceptionHandlingTraits<::djinni_generated::NativeItemList>::handleNativeException(e);
4643
}
4744
}
4845

perftest/generated-src/wasm/NativeDjinniPerfBenchmark.cpp

Lines changed: 25 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,7 @@ em::val NativeDjinniPerfBenchmark::getInstance() {
4747
return ::djinni_generated::NativeDjinniPerfBenchmark::fromCpp(r);
4848
}
4949
catch(const std::exception& e) {
50-
djinni::djinni_throw_native_exception(e);
51-
throw;
50+
return djinni::ExceptionHandlingTraits<::djinni_generated::NativeDjinniPerfBenchmark>::handleNativeException(e);
5251
}
5352
}
5453
int64_t NativeDjinniPerfBenchmark::cppTests(const CppType& self) {
@@ -57,125 +56,111 @@ int64_t NativeDjinniPerfBenchmark::cppTests(const CppType& self) {
5756
return ::djinni::I64::fromCpp(r);
5857
}
5958
catch(const std::exception& e) {
60-
djinni::djinni_throw_native_exception(e);
61-
throw;
59+
return djinni::ExceptionHandlingTraits<::djinni::I64>::handleNativeException(e);
6260
}
6361
}
6462
void NativeDjinniPerfBenchmark::baseline(const CppType& self) {
6563
try {
6664
self->baseline();
6765
}
6866
catch(const std::exception& e) {
69-
djinni::djinni_throw_native_exception(e);
70-
throw;
67+
return djinni::ExceptionHandlingTraits<void>::handleNativeException(e);
7168
}
7269
}
7370
void NativeDjinniPerfBenchmark::argString(const CppType& self, const std::string& w_s) {
7471
try {
7572
self->argString(::djinni::String::toCpp(w_s));
7673
}
7774
catch(const std::exception& e) {
78-
djinni::djinni_throw_native_exception(e);
79-
throw;
75+
return djinni::ExceptionHandlingTraits<void>::handleNativeException(e);
8076
}
8177
}
8278
void NativeDjinniPerfBenchmark::argBinary(const CppType& self, const em::val& w_b) {
8379
try {
8480
self->argBinary(::djinni::Binary::toCpp(w_b));
8581
}
8682
catch(const std::exception& e) {
87-
djinni::djinni_throw_native_exception(e);
88-
throw;
83+
return djinni::ExceptionHandlingTraits<void>::handleNativeException(e);
8984
}
9085
}
9186
void NativeDjinniPerfBenchmark::argDataRef(const CppType& self, const em::val& w_r) {
9287
try {
9388
self->argDataRef(::djinni::NativeDataRef::toCpp(w_r));
9489
}
9590
catch(const std::exception& e) {
96-
djinni::djinni_throw_native_exception(e);
97-
throw;
91+
return djinni::ExceptionHandlingTraits<void>::handleNativeException(e);
9892
}
9993
}
10094
void NativeDjinniPerfBenchmark::argDataView(const CppType& self, const em::val& w_d) {
10195
try {
10296
self->argDataView(::djinni::NativeDataView::toCpp(w_d));
10397
}
10498
catch(const std::exception& e) {
105-
djinni::djinni_throw_native_exception(e);
106-
throw;
99+
return djinni::ExceptionHandlingTraits<void>::handleNativeException(e);
107100
}
108101
}
109102
void NativeDjinniPerfBenchmark::argEnumSixValue(const CppType& self, int32_t w_e) {
110103
try {
111104
self->argEnumSixValue(::djinni_generated::NativeEnumSixValue::toCpp(w_e));
112105
}
113106
catch(const std::exception& e) {
114-
djinni::djinni_throw_native_exception(e);
115-
throw;
107+
return djinni::ExceptionHandlingTraits<void>::handleNativeException(e);
116108
}
117109
}
118110
void NativeDjinniPerfBenchmark::argRecordSixInt(const CppType& self, const em::val& w_r) {
119111
try {
120112
self->argRecordSixInt(::djinni_generated::NativeRecordSixInt::toCpp(w_r));
121113
}
122114
catch(const std::exception& e) {
123-
djinni::djinni_throw_native_exception(e);
124-
throw;
115+
return djinni::ExceptionHandlingTraits<void>::handleNativeException(e);
125116
}
126117
}
127118
void NativeDjinniPerfBenchmark::argListInt(const CppType& self, const em::val& w_v) {
128119
try {
129120
self->argListInt(::djinni::List<::djinni::I64>::toCpp(w_v));
130121
}
131122
catch(const std::exception& e) {
132-
djinni::djinni_throw_native_exception(e);
133-
throw;
123+
return djinni::ExceptionHandlingTraits<void>::handleNativeException(e);
134124
}
135125
}
136126
void NativeDjinniPerfBenchmark::argArrayInt(const CppType& self, const em::val& w_v) {
137127
try {
138128
self->argArrayInt(::djinni::Array<::djinni::I64>::toCpp(w_v));
139129
}
140130
catch(const std::exception& e) {
141-
djinni::djinni_throw_native_exception(e);
142-
throw;
131+
return djinni::ExceptionHandlingTraits<void>::handleNativeException(e);
143132
}
144133
}
145134
void NativeDjinniPerfBenchmark::argObject(const CppType& self, const em::val& w_c) {
146135
try {
147136
self->argObject(::djinni_generated::NativeObjectPlatform::toCpp(w_c));
148137
}
149138
catch(const std::exception& e) {
150-
djinni::djinni_throw_native_exception(e);
151-
throw;
139+
return djinni::ExceptionHandlingTraits<void>::handleNativeException(e);
152140
}
153141
}
154142
void NativeDjinniPerfBenchmark::argListObject(const CppType& self, const em::val& w_l) {
155143
try {
156144
self->argListObject(::djinni::List<::djinni_generated::NativeObjectPlatform>::toCpp(w_l));
157145
}
158146
catch(const std::exception& e) {
159-
djinni::djinni_throw_native_exception(e);
160-
throw;
147+
return djinni::ExceptionHandlingTraits<void>::handleNativeException(e);
161148
}
162149
}
163150
void NativeDjinniPerfBenchmark::argListRecord(const CppType& self, const em::val& w_l) {
164151
try {
165152
self->argListRecord(::djinni::List<::djinni_generated::NativeRecordSixInt>::toCpp(w_l));
166153
}
167154
catch(const std::exception& e) {
168-
djinni::djinni_throw_native_exception(e);
169-
throw;
155+
return djinni::ExceptionHandlingTraits<void>::handleNativeException(e);
170156
}
171157
}
172158
void NativeDjinniPerfBenchmark::argArrayRecord(const CppType& self, const em::val& w_a) {
173159
try {
174160
self->argArrayRecord(::djinni::List<::djinni_generated::NativeRecordSixInt>::toCpp(w_a));
175161
}
176162
catch(const std::exception& e) {
177-
djinni::djinni_throw_native_exception(e);
178-
throw;
163+
return djinni::ExceptionHandlingTraits<void>::handleNativeException(e);
179164
}
180165
}
181166
int64_t NativeDjinniPerfBenchmark::returnInt(const CppType& self, int64_t w_i) {
@@ -184,8 +169,7 @@ int64_t NativeDjinniPerfBenchmark::returnInt(const CppType& self, int64_t w_i) {
184169
return ::djinni::I64::fromCpp(r);
185170
}
186171
catch(const std::exception& e) {
187-
djinni::djinni_throw_native_exception(e);
188-
throw;
172+
return djinni::ExceptionHandlingTraits<::djinni::I64>::handleNativeException(e);
189173
}
190174
}
191175
std::string NativeDjinniPerfBenchmark::returnString(const CppType& self, int32_t w_size) {
@@ -194,8 +178,7 @@ std::string NativeDjinniPerfBenchmark::returnString(const CppType& self, int32_t
194178
return ::djinni::String::fromCpp(r);
195179
}
196180
catch(const std::exception& e) {
197-
djinni::djinni_throw_native_exception(e);
198-
throw;
181+
return djinni::ExceptionHandlingTraits<::djinni::String>::handleNativeException(e);
199182
}
200183
}
201184
em::val NativeDjinniPerfBenchmark::returnBinary(const CppType& self, int32_t w_size) {
@@ -204,8 +187,7 @@ em::val NativeDjinniPerfBenchmark::returnBinary(const CppType& self, int32_t w_s
204187
return ::djinni::Binary::fromCpp(r);
205188
}
206189
catch(const std::exception& e) {
207-
djinni::djinni_throw_native_exception(e);
208-
throw;
190+
return djinni::ExceptionHandlingTraits<::djinni::Binary>::handleNativeException(e);
209191
}
210192
}
211193
em::val NativeDjinniPerfBenchmark::returnObject(const CppType& self) {
@@ -214,8 +196,7 @@ em::val NativeDjinniPerfBenchmark::returnObject(const CppType& self) {
214196
return ::djinni_generated::NativeObjectNative::fromCpp(r);
215197
}
216198
catch(const std::exception& e) {
217-
djinni::djinni_throw_native_exception(e);
218-
throw;
199+
return djinni::ExceptionHandlingTraits<::djinni_generated::NativeObjectNative>::handleNativeException(e);
219200
}
220201
}
221202
em::val NativeDjinniPerfBenchmark::returnListInt(const CppType& self, int32_t w_size) {
@@ -224,8 +205,7 @@ em::val NativeDjinniPerfBenchmark::returnListInt(const CppType& self, int32_t w_
224205
return ::djinni::List<::djinni::I64>::fromCpp(r);
225206
}
226207
catch(const std::exception& e) {
227-
djinni::djinni_throw_native_exception(e);
228-
throw;
208+
return djinni::ExceptionHandlingTraits<::djinni::List<::djinni::I64>>::handleNativeException(e);
229209
}
230210
}
231211
em::val NativeDjinniPerfBenchmark::returnArrayInt(const CppType& self, int32_t w_size) {
@@ -234,8 +214,7 @@ em::val NativeDjinniPerfBenchmark::returnArrayInt(const CppType& self, int32_t w
234214
return ::djinni::Array<::djinni::I64>::fromCpp(r);
235215
}
236216
catch(const std::exception& e) {
237-
djinni::djinni_throw_native_exception(e);
238-
throw;
217+
return djinni::ExceptionHandlingTraits<::djinni::Array<::djinni::I64>>::handleNativeException(e);
239218
}
240219
}
241220
em::val NativeDjinniPerfBenchmark::returnListObject(const CppType& self, int32_t w_size) {
@@ -244,8 +223,7 @@ em::val NativeDjinniPerfBenchmark::returnListObject(const CppType& self, int32_t
244223
return ::djinni::List<::djinni_generated::NativeObjectNative>::fromCpp(r);
245224
}
246225
catch(const std::exception& e) {
247-
djinni::djinni_throw_native_exception(e);
248-
throw;
226+
return djinni::ExceptionHandlingTraits<::djinni::List<::djinni_generated::NativeObjectNative>>::handleNativeException(e);
249227
}
250228
}
251229
em::val NativeDjinniPerfBenchmark::returnListRecord(const CppType& self, int32_t w_size) {
@@ -254,8 +232,7 @@ em::val NativeDjinniPerfBenchmark::returnListRecord(const CppType& self, int32_t
254232
return ::djinni::List<::djinni_generated::NativeRecordSixInt>::fromCpp(r);
255233
}
256234
catch(const std::exception& e) {
257-
djinni::djinni_throw_native_exception(e);
258-
throw;
235+
return djinni::ExceptionHandlingTraits<::djinni::List<::djinni_generated::NativeRecordSixInt>>::handleNativeException(e);
259236
}
260237
}
261238
em::val NativeDjinniPerfBenchmark::returnArrayRecord(const CppType& self, int32_t w_size) {
@@ -264,8 +241,7 @@ em::val NativeDjinniPerfBenchmark::returnArrayRecord(const CppType& self, int32_
264241
return ::djinni::List<::djinni_generated::NativeRecordSixInt>::fromCpp(r);
265242
}
266243
catch(const std::exception& e) {
267-
djinni::djinni_throw_native_exception(e);
268-
throw;
244+
return djinni::ExceptionHandlingTraits<::djinni::List<::djinni_generated::NativeRecordSixInt>>::handleNativeException(e);
269245
}
270246
}
271247
std::string NativeDjinniPerfBenchmark::roundTripString(const CppType& self, const std::string& w_s) {
@@ -274,8 +250,7 @@ std::string NativeDjinniPerfBenchmark::roundTripString(const CppType& self, cons
274250
return ::djinni::String::fromCpp(r);
275251
}
276252
catch(const std::exception& e) {
277-
djinni::djinni_throw_native_exception(e);
278-
throw;
253+
return djinni::ExceptionHandlingTraits<::djinni::String>::handleNativeException(e);
279254
}
280255
}
281256

perftest/generated-src/wasm/NativeObjectNative.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,7 @@ void NativeObjectNative::baseline(const CppType& self) {
1717
self->baseline();
1818
}
1919
catch(const std::exception& e) {
20-
djinni::djinni_throw_native_exception(e);
21-
throw;
20+
return djinni::ExceptionHandlingTraits<void>::handleNativeException(e);
2221
}
2322
}
2423

src/source/WasmGenerator.scala

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -375,11 +375,8 @@ class WasmGenerator(spec: Spec) extends Generator(spec) {
375375
m.ret.fold()(r => w.wl(s"return ${helperClass(r.resolved)}::fromCpp(${cppMarshal.maybeMove("r", r)});"))
376376
}
377377
w.w("catch(const std::exception& e)").braced {
378-
w.wl("djinni::djinni_throw_native_exception(e);");
379-
// The throw line is just to let the C++ compiler know that this
380-
// branch won't return a value. Execution will never reach this
381-
// line as the previous line already throws in JS code.
382-
w.wl("throw;");
378+
val helper = if (!m.ret.isEmpty) helperClass(m.ret.get.resolved) else "void"
379+
w.wl(s"return djinni::ExceptionHandlingTraits<${helper}>::handleNativeException(e);");
383380
}
384381
}
385382
}

support-lib/cpp/Future.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,7 @@ class PromiseBase {
179179
}
180180
private:
181181
detail::SharedStatePtr<T> _sharedState = std::make_shared<SharedState<T>>();
182+
detail::SharedStatePtr<T> _sharedStateReadOnly = _sharedState; // allow calling getFuture() after setValue()
182183

183184
template <typename UpdateFunc>
184185
void updateAndCallResultHandler(UpdateFunc&& updater) {
@@ -362,7 +363,7 @@ class Future {
362363

363364
template <typename T>
364365
Future<T> detail::PromiseBase<T>::getFuture() {
365-
return Future<T>(std::atomic_load(&_sharedState));
366+
return Future<T>(_sharedStateReadOnly);
366367
}
367368

368369
template <typename U>

support-lib/wasm/Future_wasm.hpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,4 +105,12 @@ class FutureAdaptor
105105
}
106106
};
107107

108+
template<typename U>
109+
struct ExceptionHandlingTraits<FutureAdaptor<U>> {
110+
static em::val handleNativeException(const std::exception& e) {
111+
auto r = FutureAdaptor<U>::NativePromiseType::reject(std::current_exception());
112+
return FutureAdaptor<U>::fromCpp(std::move(r));
113+
}
114+
};
115+
108116
} // namespace djinni

support-lib/wasm/djinni_wasm.hpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -602,6 +602,30 @@ class GenericBuffer: public DataObject {
602602
extern "C" void djinni_register_name_in_ns(const char* prefixedName, const char* namespacedName);
603603
extern "C" void djinni_throw_native_exception(const std::exception& e);
604604

605+
template<typename U>
606+
struct DefaultInit {
607+
static U get() { return U{}; }
608+
};
609+
template<>
610+
struct DefaultInit<em::val> {
611+
static em::val get() { return em::val::undefined(); }
612+
};
613+
614+
template<typename T>
615+
struct ExceptionHandlingTraits {
616+
using R = typename T::JsType;
617+
static R handleNativeException(const std::exception& e) {
618+
djinni_throw_native_exception(e);
619+
return DefaultInit<R>::get();
620+
}
621+
};
622+
template<>
623+
struct ExceptionHandlingTraits<void> {
624+
static void handleNativeException(const std::exception& e) {
625+
djinni_throw_native_exception(e);
626+
}
627+
};
628+
605629
template<typename ClassType>
606630
class DjinniClass_ : public em::class_<ClassType> {
607631
public:

test-suite/djinni/test.djinni

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ test_helpers = interface +c {
5050

5151
static get_async_result(): future<i32>;
5252
static future_roundtrip(f: future<i32>): future<string>;
53+
static async_early_throw(): future<i32>;
5354

5455
static check_async_interface(i: async_interface): future<string>;
5556
static check_async_composition(i: async_interface): future<string>;

test-suite/generated-src/cpp/test_helpers.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,8 @@ class TestHelpers {
9494

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

97+
static ::djinni::Future<int32_t> async_early_throw();
98+
9799
static ::djinni::Future<std::string> check_async_interface(const /*not-null*/ std::shared_ptr<AsyncInterface> & i);
98100

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

test-suite/generated-src/java/com/dropbox/djinni/test/TestHelpers.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,9 @@ public abstract class TestHelpers {
9191
@Nonnull
9292
public static native com.snapchat.djinni.Future<String> futureRoundtrip(@Nonnull com.snapchat.djinni.Future<Integer> f);
9393

94+
@Nonnull
95+
public static native com.snapchat.djinni.Future<Integer> asyncEarlyThrow();
96+
9497
@Nonnull
9598
public static native com.snapchat.djinni.Future<String> checkAsyncInterface(@CheckForNull AsyncInterface i);
9699

0 commit comments

Comments
 (0)