@@ -16,6 +16,7 @@ use llvm::{SequentiallyConsistent, Acquire, Release, AtomicXchg, ValueRef, TypeK
16
16
use middle:: subst;
17
17
use middle:: subst:: FnSpace ;
18
18
use trans:: adt;
19
+ use trans:: attributes;
19
20
use trans:: base:: * ;
20
21
use trans:: build:: * ;
21
22
use trans:: callee;
@@ -1159,26 +1160,14 @@ fn trans_msvc_try<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
1159
1160
// of exceptions (e.g. the normal semantics of LLVM's landingpad and invoke
1160
1161
// instructions).
1161
1162
//
1162
- // This translation is a little surprising for two reasons:
1163
+ // This translation is a little surprising because
1164
+ // we always call a shim function instead of inlining the call to `invoke`
1165
+ // manually here. This is done because in LLVM we're only allowed to have one
1166
+ // personality per function definition. The call to the `try` intrinsic is
1167
+ // being inlined into the function calling it, and that function may already
1168
+ // have other personality functions in play. By calling a shim we're
1169
+ // guaranteed that our shim will have the right personality function.
1163
1170
//
1164
- // 1. We always call a shim function instead of inlining the call to `invoke`
1165
- // manually here. This is done because in LLVM we're only allowed to have one
1166
- // personality per function definition. The call to the `try` intrinsic is
1167
- // being inlined into the function calling it, and that function may already
1168
- // have other personality functions in play. By calling a shim we're
1169
- // guaranteed that our shim will have the right personality function.
1170
- //
1171
- // 2. Instead of making one shim (explained above), we make two shims! The
1172
- // reason for this has to do with the technical details about the
1173
- // implementation of unwinding in the runtime, but the tl;dr; is that the
1174
- // outer shim's personality function says "catch rust exceptions" and the
1175
- // inner shim's landing pad will not `resume` the exception being thrown.
1176
- // This means that the outer shim's landing pad is never run and the inner
1177
- // shim's return value is the return value of the whole call.
1178
- //
1179
- // The double-shim aspect is currently done for implementation ease on the
1180
- // runtime side of things, and more info can be found in
1181
- // src/libstd/rt/unwind/gcc.rs.
1182
1171
fn trans_gnu_try < ' blk , ' tcx > ( bcx : Block < ' blk , ' tcx > ,
1183
1172
func : ValueRef ,
1184
1173
data : ValueRef ,
@@ -1188,108 +1177,63 @@ fn trans_gnu_try<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
1188
1177
let ccx = bcx. ccx ( ) ;
1189
1178
let dloc = DebugLoc :: None ;
1190
1179
1191
- // Type indicator for the exception being thrown, not entirely sure
1192
- // what's going on here but it's what all the examples in LLVM use.
1193
- let lpad_ty = Type :: struct_ ( ccx, & [ Type :: i8p ( ccx) , Type :: i32 ( ccx) ] ,
1194
- false ) ;
1180
+ // Translates the shims described above:
1181
+ //
1182
+ // bcx:
1183
+ // invoke %func(%args...) normal %normal unwind %catch
1184
+ //
1185
+ // normal:
1186
+ // ret null
1187
+ //
1188
+ // catch:
1189
+ // (ptr, _) = landingpad
1190
+ // ret ptr
1195
1191
1196
- // Define the "inner try" shim
1197
- let rust_try_inner = declare:: define_internal_rust_fn ( ccx,
1198
- "__rust_try_inner" ,
1199
- try_fn_ty) ;
1200
- trans_rust_try ( ccx, rust_try_inner, lpad_ty, bcx. fcx . eh_personality ( ) ,
1201
- output, dloc, & mut |bcx, then, catch| {
1202
- let func = llvm:: get_param ( rust_try_inner, 0 ) ;
1203
- let data = llvm:: get_param ( rust_try_inner, 1 ) ;
1204
- Invoke ( bcx, func, & [ data] , then. llbb , catch. llbb , None , dloc) ;
1205
- C_null ( Type :: i8p ( ccx) )
1206
- } ) ;
1207
-
1208
- // Define the "outer try" shim.
1209
- let rust_try = declare:: define_internal_rust_fn ( ccx, "__rust_try" ,
1210
- try_fn_ty) ;
1192
+ let rust_try = declare:: define_internal_rust_fn ( ccx, "__rust_try" , try_fn_ty) ;
1193
+ attributes:: emit_uwtable ( rust_try, true ) ;
1211
1194
let catch_pers = match bcx. tcx ( ) . lang_items . eh_personality_catch ( ) {
1212
1195
Some ( did) => callee:: trans_fn_ref ( ccx, did, ExprId ( 0 ) ,
1213
1196
bcx. fcx . param_substs ) . val ,
1214
1197
None => bcx. tcx ( ) . sess . bug ( "eh_personality_catch not defined" ) ,
1215
1198
} ;
1216
- trans_rust_try ( ccx, rust_try, lpad_ty, catch_pers, output, dloc,
1217
- & mut |bcx, then, catch| {
1218
- let func = llvm:: get_param ( rust_try, 0 ) ;
1219
- let data = llvm:: get_param ( rust_try, 1 ) ;
1220
- Invoke ( bcx, rust_try_inner, & [ func, data] , then. llbb , catch. llbb ,
1221
- None , dloc)
1222
- } ) ;
1223
- return rust_try
1224
- } ) ;
1225
1199
1226
- // Note that no invoke is used here because by definition this function
1227
- // can't panic (that's what it's catching).
1228
- let ret = Call ( bcx, llfn, & [ func, data] , None , dloc) ;
1229
- Store ( bcx, ret, dest) ;
1230
- return bcx;
1231
-
1232
- // Translates both the inner and outer shims described above. The only
1233
- // difference between these two is the function invoked and the personality
1234
- // involved, so a common routine is shared.
1235
- //
1236
- // bcx:
1237
- // invoke %func(%args...) normal %normal unwind %unwind
1238
- //
1239
- // normal:
1240
- // ret null
1241
- //
1242
- // unwind:
1243
- // (ptr, _) = landingpad
1244
- // br (ptr != null), done, reraise
1245
- //
1246
- // done:
1247
- // ret ptr
1248
- //
1249
- // reraise:
1250
- // resume
1251
- //
1252
- // Note that the branch checking for `null` here isn't actually necessary,
1253
- // it's just an unfortunate hack to make sure that LLVM doesn't optimize too
1254
- // much. If this were not present, then LLVM would correctly deduce that our
1255
- // inner shim should be tagged with `nounwind` (as it catches all
1256
- // exceptions) and then the outer shim's `invoke` will be translated to just
1257
- // a simple call, destroying that entry for the personality function.
1258
- //
1259
- // To ensure that both shims always have an `invoke` this check against null
1260
- // confuses LLVM enough to the point that it won't infer `nounwind` and
1261
- // we'll proceed as normal.
1262
- fn trans_rust_try < ' a , ' tcx > ( ccx : & CrateContext < ' a , ' tcx > ,
1263
- llfn : ValueRef ,
1264
- lpad_ty : Type ,
1265
- personality : ValueRef ,
1266
- output : ty:: FnOutput < ' tcx > ,
1267
- dloc : DebugLoc ,
1268
- invoke : & mut FnMut ( Block , Block , Block ) -> ValueRef ) {
1269
1200
let ( fcx, block_arena) ;
1270
1201
block_arena = TypedArena :: new ( ) ;
1271
- fcx = new_fn_ctxt ( ccx, llfn , ast:: DUMMY_NODE_ID , false ,
1202
+ fcx = new_fn_ctxt ( ccx, rust_try , ast:: DUMMY_NODE_ID , false ,
1272
1203
output, ccx. tcx ( ) . mk_substs ( Substs :: trans_empty ( ) ) ,
1273
1204
None , & block_arena) ;
1274
1205
let bcx = init_function ( & fcx, true , output) ;
1275
1206
let then = bcx. fcx . new_temp_block ( "then" ) ;
1276
1207
let catch = bcx. fcx . new_temp_block ( "catch" ) ;
1277
- let reraise = bcx. fcx . new_temp_block ( "reraise" ) ;
1278
- let catch_return = bcx. fcx . new_temp_block ( "catch-return" ) ;
1279
1208
1280
- let invoke_ret = invoke ( bcx, then, catch) ;
1281
- Ret ( then, invoke_ret, dloc) ;
1282
- let vals = LandingPad ( catch, lpad_ty, personality, 1 ) ;
1209
+ let func = llvm:: get_param ( rust_try, 0 ) ;
1210
+ let data = llvm:: get_param ( rust_try, 1 ) ;
1211
+ Invoke ( bcx, func, & [ data] , then. llbb , catch. llbb , None , dloc) ;
1212
+ Ret ( then, C_null ( Type :: i8p ( ccx) ) , dloc) ;
1213
+
1214
+ // Type indicator for the exception being thrown.
1215
+ // The first value in this tuple is a pointer to the exception object being thrown.
1216
+ // The second value is a "selector" indicating which of the landing pad clauses
1217
+ // the exception's type had been matched to. rust_try ignores the selector.
1218
+ let lpad_ty = Type :: struct_ ( ccx, & [ Type :: i8p ( ccx) , Type :: i32 ( ccx) ] ,
1219
+ false ) ;
1220
+ let vals = LandingPad ( catch, lpad_ty, catch_pers, 1 ) ;
1283
1221
AddClause ( catch, vals, C_null ( Type :: i8p ( ccx) ) ) ;
1284
1222
let ptr = ExtractValue ( catch, vals, 0 ) ;
1285
- let valid = ICmp ( catch, llvm:: IntNE , ptr, C_null ( Type :: i8p ( ccx) ) , dloc) ;
1286
- CondBr ( catch, valid, catch_return. llbb , reraise. llbb , dloc) ;
1287
- Ret ( catch_return, ptr, dloc) ;
1288
- Resume ( reraise, vals) ;
1289
- }
1223
+ Ret ( catch, ptr, dloc) ;
1224
+ fcx. cleanup ( ) ;
1225
+
1226
+ return rust_try
1227
+ } ) ;
1228
+
1229
+ // Note that no invoke is used here because by definition this function
1230
+ // can't panic (that's what it's catching).
1231
+ let ret = Call ( bcx, llfn, & [ func, data] , None , dloc) ;
1232
+ Store ( bcx, ret, dest) ;
1233
+ return bcx;
1290
1234
}
1291
1235
1292
- // Helper to generate the `Ty` associated with `rust_Try `
1236
+ // Helper to generate the `Ty` associated with `rust_try `
1293
1237
fn get_rust_try_fn < ' a , ' tcx > ( fcx : & FunctionContext < ' a , ' tcx > ,
1294
1238
f : & mut FnMut ( Ty < ' tcx > ,
1295
1239
ty:: FnOutput < ' tcx > ) -> ValueRef )
@@ -1299,8 +1243,7 @@ fn get_rust_try_fn<'a, 'tcx>(fcx: &FunctionContext<'a, 'tcx>,
1299
1243
return llfn
1300
1244
}
1301
1245
1302
- // Define the types up front for the signatures of the rust_try and
1303
- // rust_try_inner functions.
1246
+ // Define the type up front for the signature of the rust_try function.
1304
1247
let tcx = ccx. tcx ( ) ;
1305
1248
let i8p = tcx. mk_mut_ptr ( tcx. types . i8 ) ;
1306
1249
let fn_ty = tcx. mk_bare_fn ( ty:: BareFnTy {
0 commit comments