1 // REQUIRES: webassembly-registered-target 2 // RUN: %clang_cc1 %s -triple wasm32-unknown-unknown -fms-extensions -fexceptions -fcxx-exceptions -mllvm -wasm-enable-eh -exception-model=wasm -target-feature +exception-handling -emit-llvm -o - -std=c++11 | FileCheck %s 3 // RUN: %clang_cc1 %s -triple wasm64-unknown-unknown -fms-extensions -fexceptions -fcxx-exceptions -mllvm -wasm-enable-eh -exception-model=wasm -target-feature +exception-handling -emit-llvm -o - -std=c++11 | FileCheck %s 4 5 void may_throw(); 6 void dont_throw() noexcept; 7 8 struct Cleanup { 9 ~Cleanup() { dont_throw(); } 10 }; 11 12 // Multiple catch clauses w/o catch-all 13 void test0() { 14 try { 15 may_throw(); 16 } catch (int) { 17 dont_throw(); 18 } catch (double) { 19 dont_throw(); 20 } 21 } 22 23 // CHECK-LABEL: define void @_Z5test0v() {{.*}} personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) 24 25 // CHECK: %[[INT_ALLOCA:.*]] = alloca i32 26 // CHECK: invoke void @_Z9may_throwv() 27 // CHECK-NEXT: to label %[[NORMAL_BB:.*]] unwind label %[[CATCHDISPATCH_BB:.*]] 28 29 // CHECK: [[CATCHDISPATCH_BB]]: 30 // CHECK-NEXT: %[[CATCHSWITCH:.*]] = catchswitch within none [label %[[CATCHSTART_BB:.*]]] unwind to caller 31 32 // CHECK: [[CATCHSTART_BB]]: 33 // CHECK-NEXT: %[[CATCHPAD:.*]] = catchpad within %[[CATCHSWITCH]] [i8* bitcast (i8** @_ZTIi to i8*), i8* bitcast (i8** @_ZTId to i8*)] 34 // CHECK-NEXT: %[[EXN:.*]] = call i8* @llvm.wasm.get.exception(token %[[CATCHPAD]]) 35 // CHECK-NEXT: store i8* %[[EXN]], i8** %exn.slot 36 // CHECK-NEXT: %[[SELECTOR:.*]] = call i32 @llvm.wasm.get.ehselector(token %[[CATCHPAD]]) 37 // CHECK-NEXT: %[[TYPEID:.*]] = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*)) #2 38 // CHECK-NEXT: %[[MATCHES:.*]] = icmp eq i32 %[[SELECTOR]], %[[TYPEID]] 39 // CHECK-NEXT: br i1 %[[MATCHES]], label %[[CATCH_INT_BB:.*]], label %[[CATCH_FALLTHROUGH_BB:.*]] 40 41 // CHECK: [[CATCH_INT_BB]]: 42 // CHECK-NEXT: %[[EXN:.*]] = load i8*, i8** %exn.slot 43 // CHECK-NEXT: %[[ADDR:.*]] = call i8* @__cxa_begin_catch(i8* %[[EXN]]) {{.*}} [ "funclet"(token %[[CATCHPAD]]) ] 44 // CHECK-NEXT: %[[ADDR_CAST:.*]] = bitcast i8* %[[ADDR]] to i32* 45 // CHECK-NEXT: %[[INT_VAL:.*]] = load i32, i32* %[[ADDR_CAST]] 46 // CHECK-NEXT: store i32 %[[INT_VAL]], i32* %[[INT_ALLOCA]] 47 // CHECK-NEXT: call void @_Z10dont_throwv() {{.*}} [ "funclet"(token %[[CATCHPAD]]) ] 48 // CHECK-NEXT: call void @__cxa_end_catch() {{.*}} [ "funclet"(token %[[CATCHPAD]]) ] 49 // CHECK-NEXT: catchret from %[[CATCHPAD]] to label %[[CATCHRET_DEST_BB0:.*]] 50 51 // CHECK: [[CATCHRET_DEST_BB0]]: 52 // CHECK-NEXT: br label %[[TRY_CONT_BB:.*]] 53 54 // CHECK: [[CATCH_FALLTHROUGH_BB]] 55 // CHECK-NEXT: %[[TYPEID:.*]] = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTId to i8*)) #2 56 // CHECK-NEXT: %[[MATCHES:.*]] = icmp eq i32 %[[SELECTOR]], %[[TYPEID]] 57 // CHECK-NEXT: br i1 %[[MATCHES]], label %[[CATCH_FLOAT_BB:.*]], label %[[RETHROW_BB:.*]] 58 59 // CHECK: [[CATCH_FLOAT_BB]]: 60 // CHECK: catchret from %[[CATCHPAD]] to label %[[CATCHRET_DEST_BB1:.*]] 61 62 // CHECK: [[CATCHRET_DEST_BB1]]: 63 // CHECK-NEXT: br label %[[TRY_CONT_BB]] 64 65 // CHECK: [[RETHROW_BB]]: 66 // CHECK-NEXT: call void @llvm.wasm.rethrow() {{.*}} [ "funclet"(token %[[CATCHPAD]]) ] 67 // CHECK-NEXT: unreachable 68 69 // Single catch-all 70 void test1() { 71 try { 72 may_throw(); 73 } catch (...) { 74 dont_throw(); 75 } 76 } 77 78 // CATCH-LABEL: @_Z5test1v() 79 80 // CHECK: %[[CATCHSWITCH:.*]] = catchswitch within none [label %[[CATCHSTART_BB:.*]]] unwind to caller 81 82 // CHECK: [[CATCHSTART_BB]]: 83 // CHECK-NEXT: %[[CATCHPAD:.*]] = catchpad within %[[CATCHSWITCH]] [i8* null] 84 // CHECK: br label %[[CATCH_ALL_BB:.*]] 85 86 // CHECK: [[CATCH_ALL_BB]]: 87 // CHECK: catchret from %[[CATCHPAD]] to label 88 89 // Multiple catch clauses w/ catch-all 90 void test2() { 91 try { 92 may_throw(); 93 } catch (int) { 94 dont_throw(); 95 } catch (...) { 96 dont_throw(); 97 } 98 } 99 100 // CHECK-LABEL: @_Z5test2v() 101 102 // CHECK: %[[CATCHSWITCH:.*]] = catchswitch within none [label %[[CATCHSTART_BB:.*]]] unwind to caller 103 104 // CHECK: [[CATCHSTART_BB]]: 105 // CHECK-NEXT: %[[CATCHPAD:.*]] = catchpad within %[[CATCHSWITCH]] [i8* bitcast (i8** @_ZTIi to i8*), i8* null] 106 // CHECK: br i1 %{{.*}}, label %[[CATCH_INT_BB:.*]], label %[[CATCH_ALL_BB:.*]] 107 108 // CHECK: [[CATCH_INT_BB]]: 109 // CHECK: catchret from %[[CATCHPAD]] to label 110 111 // CHECK: [[CATCH_ALL_BB]]: 112 // CHECK: catchret from %[[CATCHPAD]] to label 113 114 // Cleanup 115 void test3() { 116 Cleanup c; 117 may_throw(); 118 } 119 120 // CHECK-LABEL: @_Z5test3v() 121 122 // CHECK: invoke void @_Z9may_throwv() 123 // CHECK-NEXT: to label {{.*}} unwind label %[[EHCLEANUP_BB:.*]] 124 125 // CHECK: [[EHCLEANUP_BB]]: 126 // CHECK-NEXT: %[[CLEANUPPAD:.*]] = cleanuppad within none [] 127 // CHECK-NEXT: call noundef %struct.Cleanup* @_ZN7CleanupD1Ev(%struct.Cleanup* {{[^,]*}} %{{.*}}) {{.*}} [ "funclet"(token %[[CLEANUPPAD]]) ] 128 // CHECK-NEXT: cleanupret from %[[CLEANUPPAD]] unwind to caller 129 130 // Possibly throwing function call within a catch 131 void test4() { 132 try { 133 may_throw(); 134 } catch (int) { 135 may_throw(); 136 } 137 } 138 139 // CHECK-LABEL: @_Z5test4v() 140 141 // CHECK: %[[CATCHSWITCH]] = catchswitch within none [label %[[CATCHSTART_BB]]] unwind to caller 142 143 // CHECK: [[CATCHSTART_BB]]: 144 // CHECK: %[[CATCHPAD:.*]] = catchpad within %[[CATCHSWITCH]] [i8* bitcast (i8** @_ZTIi to i8*)] 145 146 // CHECK: invoke void @_Z9may_throwv() [ "funclet"(token %[[CATCHPAD]]) ] 147 // CHECK-NEXT: to label %[[INVOKE_CONT_BB:.*]] unwind label %[[EHCLEANUP_BB:.*]] 148 149 // CHECK: [[INVOKE_CONT_BB]]: 150 // CHECK-NEXT: call void @__cxa_end_catch() {{.*}} [ "funclet"(token %[[CATCHPAD]]) ] 151 // CHECK-NEXT: catchret from %[[CATCHPAD]] to label 152 153 // CHECK: [[EHCLEANUP_BB]]: 154 // CHECK-NEXT: %[[CLEANUPPAD:.*]] = cleanuppad within %[[CATCHPAD]] [] 155 // CHECK-NEXT: call void @__cxa_end_catch() {{.*}} [ "funclet"(token %[[CLEANUPPAD]]) ] 156 // CHECK-NEXT: cleanupret from %[[CLEANUPPAD]] unwind to caller 157 158 // Possibly throwing function call within a catch-all 159 void test5() { 160 try { 161 may_throw(); 162 } catch (...) { 163 may_throw(); 164 } 165 } 166 167 // CHECK-LABEL: @_Z5test5v() 168 169 // CHECK: %[[CATCHSWITCH:.*]] = catchswitch within none [label %[[CATCHSTART_BB]]] unwind to caller 170 171 // CHECK: [[CATCHSTART_BB]]: 172 // CHECK: %[[CATCHPAD:.*]] = catchpad within %[[CATCHSWITCH]] [i8* null] 173 174 // CHECK: invoke void @_Z9may_throwv() [ "funclet"(token %[[CATCHPAD]]) ] 175 // CHECK-NEXT: to label %[[INVOKE_CONT_BB0:.*]] unwind label %[[EHCLEANUP_BB:.*]] 176 177 // CHECK: [[INVOKE_CONT_BB0]]: 178 // CHECK-NEXT: call void @__cxa_end_catch() [ "funclet"(token %[[CATCHPAD]]) ] 179 // CHECK-NEXT: catchret from %[[CATCHPAD]] to label 180 181 // CHECK: [[EHCLEANUP_BB]]: 182 // CHECK-NEXT: %[[CLEANUPPAD0:.*]] = cleanuppad within %[[CATCHPAD]] [] 183 // CHECK-NEXT: invoke void @__cxa_end_catch() [ "funclet"(token %[[CLEANUPPAD0]]) ] 184 // CHECK-NEXT: to label %[[INVOKE_CONT_BB1:.*]] unwind label %[[TERMINATE_BB:.*]] 185 186 // CHECK: [[INVOKE_CONT_BB1]]: 187 // CHECK-NEXT: cleanupret from %[[CLEANUPPAD0]] unwind to caller 188 189 // CHECK: [[TERMINATE_BB]]: 190 // CHECK-NEXT: %[[CLEANUPPAD1:.*]] = cleanuppad within %[[CLEANUPPAD0]] [] 191 // CHECK-NEXT: call void @_ZSt9terminatev() {{.*}} [ "funclet"(token %[[CLEANUPPAD1]]) ] 192 // CHECK-NEXT: unreachable 193 194 // Try-catch with cleanups 195 void test6() { 196 Cleanup c1; 197 try { 198 Cleanup c2; 199 may_throw(); 200 } catch (int) { 201 Cleanup c3; 202 may_throw(); 203 } 204 } 205 206 // CHECK-LABEL: @_Z5test6v() 207 // CHECK: invoke void @_Z9may_throwv() 208 // CHECK-NEXT: to label %{{.*}} unwind label %[[EHCLEANUP_BB0:.*]] 209 210 // CHECK: [[EHCLEANUP_BB0]]: 211 // CHECK-NEXT: %[[CLEANUPPAD0:.*]] = cleanuppad within none [] 212 // CHECK-NEXT: call noundef %struct.Cleanup* @_ZN7CleanupD1Ev(%struct.Cleanup* {{.*}}) {{.*}} [ "funclet"(token %[[CLEANUPPAD0]]) ] 213 // CHECK-NEXT: cleanupret from %[[CLEANUPPAD0]] unwind label %[[CATCH_DISPATCH_BB:.*]] 214 215 // CHECK: [[CATCH_DISPATCH_BB]]: 216 // CHECK-NEXT: %[[CATCHSWITCH:.*]] = catchswitch within none [label %[[CATCHSTART_BB:.*]]] unwind label %[[EHCLEANUP_BB1:.*]] 217 218 // CHECK: [[CATCHSTART_BB]]: 219 // CHECK-NEXT: %[[CATCHPAD:.*]] = catchpad within %[[CATCHSWITCH]] [i8* bitcast (i8** @_ZTIi to i8*)] 220 // CHECK: br i1 %{{.*}}, label %[[CATCH_INT_BB:.*]], label %[[RETHROW_BB:.*]] 221 222 // CHECK: [[CATCH_INT_BB]]: 223 // CHECK: invoke void @_Z9may_throwv() [ "funclet"(token %[[CATCHPAD]]) ] 224 // CHECK-NEXT: to label %[[INVOKE_CONT_BB:.*]] unwind label %[[EHCLEANUP_BB2:.*]] 225 226 // CHECK: [[INVOKE_CONT_BB]]: 227 // CHECK: catchret from %[[CATCHPAD]] to label %{{.*}} 228 229 // CHECK: [[RETHROW_BB]]: 230 // CHECK-NEXT: invoke void @llvm.wasm.rethrow() {{.*}} [ "funclet"(token %[[CATCHPAD]]) ] 231 // CHECK-NEXT: to label %[[UNREACHABLE_BB:.*]] unwind label %[[EHCLEANUP_BB1:.*]] 232 233 // CHECK: [[EHCLEANUP_BB2]]: 234 // CHECK-NEXT: %[[CLEANUPPAD2:.*]] = cleanuppad within %[[CATCHPAD]] [] 235 // CHECK-NEXT: call noundef %struct.Cleanup* @_ZN7CleanupD1Ev(%struct.Cleanup* {{[^,]*}} %{{.*}}) {{.*}} [ "funclet"(token %[[CLEANUPPAD2]]) ] 236 // CHECK-NEXT: cleanupret from %[[CLEANUPPAD2]] unwind label %[[EHCLEANUP_BB3:.*]] 237 238 // CHECK: [[EHCLEANUP_BB3]]: 239 // CHECK-NEXT: %[[CLEANUPPAD3:.*]] = cleanuppad within %[[CATCHPAD]] [] 240 // CHECK: cleanupret from %[[CLEANUPPAD3]] unwind label %[[EHCLEANUP_BB1:.*]] 241 242 // CHECK: [[EHCLEANUP_BB1]]: 243 // CHECK-NEXT: %[[CLEANUPPAD1:.*]] = cleanuppad within none [] 244 // CHECK-NEXT: call noundef %struct.Cleanup* @_ZN7CleanupD1Ev(%struct.Cleanup* {{[^,]*}} %{{.*}}) {{.*}} [ "funclet"(token %[[CLEANUPPAD1]]) ] 245 // CHECK-NEXT: cleanupret from %[[CLEANUPPAD1]] unwind to caller 246 247 // CHECK: [[UNREACHABLE_BB]]: 248 // CHECK-NEXT: unreachable 249 250 // Nested try-catches within a try with cleanups 251 void test7() { 252 Cleanup c1; 253 may_throw(); 254 try { 255 Cleanup c2; 256 may_throw(); 257 try { 258 Cleanup c3; 259 may_throw(); 260 } catch (int) { 261 may_throw(); 262 } catch (double) { 263 may_throw(); 264 } 265 } catch (int) { 266 may_throw(); 267 } catch (...) { 268 may_throw(); 269 } 270 } 271 272 // CHECK-LABEL: @_Z5test7v() 273 // CHECK: invoke void @_Z9may_throwv() 274 275 // CHECK: invoke void @_Z9may_throwv() 276 277 // CHECK: invoke void @_Z9may_throwv() 278 279 // CHECK: %[[CLEANUPPAD0:.*]] = cleanuppad within none [] 280 // CHECK: cleanupret from %[[CLEANUPPAD0]] unwind label 281 282 // CHECK: %[[CATCHSWITCH0:.*]] = catchswitch within none 283 284 // CHECK: %[[CATCHPAD0:.*]] = catchpad within %[[CATCHSWITCH0]] [i8* bitcast (i8** @_ZTIi to i8*), i8* bitcast (i8** @_ZTId to i8*)] 285 286 // CHECK: invoke void @_Z9may_throwv() [ "funclet"(token %[[CATCHPAD0]]) ] 287 288 // CHECK: catchret from %[[CATCHPAD0]] to label 289 290 // CHECK: invoke void @_Z9may_throwv() [ "funclet"(token %[[CATCHPAD0]]) ] 291 292 // CHECK: catchret from %[[CATCHPAD0]] to label 293 294 // CHECK: invoke void @llvm.wasm.rethrow() {{.*}} [ "funclet"(token %[[CATCHPAD0]]) ] 295 296 // CHECK: %[[CLEANUPPAD1:.*]] = cleanuppad within %[[CATCHPAD0]] [] 297 // CHECK: cleanupret from %[[CLEANUPPAD1]] unwind label 298 299 // CHECK: %[[CLEANUPPAD2:.*]] = cleanuppad within %[[CATCHPAD0]] [] 300 // CHECK: cleanupret from %[[CLEANUPPAD2]] unwind label 301 302 // CHECK: %[[CLEANUPPAD3:.*]] = cleanuppad within none [] 303 // CHECK: cleanupret from %[[CLEANUPPAD3]] unwind label 304 305 // CHECK: %[[CATCHSWITCH1:.*]] = catchswitch within none 306 307 // CHECK: %[[CATCHPAD1:.*]] = catchpad within %[[CATCHSWITCH1]] [i8* bitcast (i8** @_ZTIi to i8*), i8* null] 308 309 // CHECK: invoke void @_Z9may_throwv() [ "funclet"(token %[[CATCHPAD1]]) ] 310 311 // CHECK: catchret from %[[CATCHPAD1]] to label 312 313 // CHECK: invoke void @_Z9may_throwv() [ "funclet"(token %[[CATCHPAD1]]) ] 314 315 // CHECK: invoke void @__cxa_end_catch() [ "funclet"(token %[[CATCHPAD1]]) ] 316 317 // CHECK: catchret from %[[CATCHPAD1]] to label 318 319 // CHECK: %[[CLEANUPPAD4:.*]] = cleanuppad within %[[CATCHPAD1]] [] 320 // CHECK: invoke void @__cxa_end_catch() [ "funclet"(token %[[CLEANUPPAD4]]) ] 321 322 // CHECK: cleanupret from %[[CLEANUPPAD4]] unwind label 323 324 // CHECK: %[[CLEANUPPAD5:.*]] = cleanuppad within %[[CATCHPAD1]] [] 325 // CHECK: cleanupret from %[[CLEANUPPAD5]] unwind label 326 327 // CHECK: %[[CLEANUPPAD6:.*]] = cleanuppad within none [] 328 // CHECK: cleanupret from %[[CLEANUPPAD6]] unwind to caller 329 330 // CHECK: unreachable 331 332 // CHECK: %[[CLEANUPPAD7:.*]] = cleanuppad within %[[CLEANUPPAD4]] [] 333 // CHECK: call void @_ZSt9terminatev() {{.*}} [ "funclet"(token %[[CLEANUPPAD7]]) ] 334 // CHECK: unreachable 335 336 // Nested try-catches within a catch 337 void test8() { 338 try { 339 may_throw(); 340 } catch (int) { 341 try { 342 may_throw(); 343 } catch (int) { 344 may_throw(); 345 } 346 } 347 } 348 349 // CHECK-LABEL: @_Z5test8v() 350 // CHECK: invoke void @_Z9may_throwv() 351 352 // CHECK: %[[CATCHSWITCH0:.*]] = catchswitch within none 353 354 // CHECK: %[[CATCHPAD0:.*]] = catchpad within %[[CATCHSWITCH0]] [i8* bitcast (i8** @_ZTIi to i8*)] 355 356 // CHECK: invoke void @_Z9may_throwv() [ "funclet"(token %[[CATCHPAD0]]) ] 357 358 // CHECK: %[[CATCHSWITCH1:.*]] = catchswitch within %[[CATCHPAD0]] 359 360 // CHECK: %[[CATCHPAD1:.*]] = catchpad within %[[CATCHSWITCH1]] [i8* bitcast (i8** @_ZTIi to i8*)] 361 362 // CHECK: invoke void @_Z9may_throwv() [ "funclet"(token %[[CATCHPAD1]]) ] 363 364 // CHECK: catchret from %[[CATCHPAD1]] to label 365 366 // CHECK: invoke void @llvm.wasm.rethrow() {{.*}} [ "funclet"(token %[[CATCHPAD1]]) ] 367 368 // CHECK: catchret from %[[CATCHPAD0]] to label 369 370 // CHECK: call void @llvm.wasm.rethrow() {{.*}} [ "funclet"(token %[[CATCHPAD0]]) ] 371 // CHECK: unreachable 372 373 // CHECK: %[[CLEANUPPAD0:.*]] = cleanuppad within %[[CATCHPAD1]] [] 374 // CHECK: cleanupret from %[[CLEANUPPAD0]] unwind label 375 376 // CHECK: %[[CLEANUPPAD1:.*]] = cleanuppad within %[[CATCHPAD0]] [] 377 // CHECK: cleanupret from %[[CLEANUPPAD1]] unwind to caller 378 379 // CHECK: unreachable 380 381 // RUN: %clang_cc1 %s -triple wasm32-unknown-unknown -fms-extensions -fexceptions -fcxx-exceptions -exception-model=wasm -target-feature +exception-handling -emit-llvm -o - -std=c++11 2>&1 | FileCheck %s --check-prefix=WARNING-DEFAULT 382 // RUN: %clang_cc1 %s -triple wasm32-unknown-unknown -fms-extensions -fexceptions -fcxx-exceptions -exception-model=wasm -target-feature +exception-handling -Wwasm-exception-spec -emit-llvm -o - -std=c++11 2>&1 | FileCheck %s --check-prefix=WARNING-ON 383 // RUN: %clang_cc1 %s -triple wasm32-unknown-unknown -fms-extensions -fexceptions -fcxx-exceptions -exception-model=wasm -target-feature +exception-handling -Wno-wasm-exception-spec -emit-llvm -o - -std=c++11 2>&1 | FileCheck %s --check-prefix=WARNING-OFF 384 // RUN: %clang_cc1 %s -triple wasm32-unknown-unknown -fexceptions -fcxx-exceptions -emit-llvm -o - -std=c++11 2>&1 | FileCheck %s --check-prefix=EM-EH-WARNING 385 386 // Wasm EH ignores dynamic exception specifications with types at the moment. 387 // This is controlled by -Wwasm-exception-spec, which is on by default. This 388 // warning can be suppressed with -Wno-wasm-exception-spec. Checks if a warning 389 // message is correctly printed or not printed depending on the options. 390 void test9() throw(int) { 391 } 392 // WARNING-DEFAULT: warning: dynamic exception specifications with types are currently ignored in wasm 393 // WARNING-ON: warning: dynamic exception specifications with types are currently ignored in wasm 394 // WARNING-OFF-NOT: warning: dynamic exception specifications with types are currently ignored in wasm 395 // EM-EH-WARNING: warning: dynamic exception specifications with types are currently ignored in wasm 396 397 // Wasm curremtly treats 'throw()' in the same way as 'noexept'. Check if the 398 // same warning message is printed as if when a 'noexcept' function throws. 399 void test10() throw() { 400 throw 3; 401 } 402 // WARNING-DEFAULT: warning: 'test10' has a non-throwing exception specification but can still throw 403 // WARNING-DEFAULT: function declared non-throwing here 404 405 // Here we only check if the command enables wasm exception handling in the 406 // backend so that exception handling instructions can be generated in .s file. 407 408 // RUN: %clang_cc1 %s -triple wasm32-unknown-unknown -fms-extensions -fexceptions -fcxx-exceptions -mllvm -wasm-enable-eh -exception-model=wasm -target-feature +exception-handling -S -o - -std=c++11 | FileCheck %s --check-prefix=ASSEMBLY 409 410 // ASSEMBLY: try 411 // ASSEMBLY: catch 412 // ASSEMBLY: rethrow 413 // ASSEMBLY: end_try 414