@@ -51,7 +51,7 @@ This file consists of three conceptual sections:
51
51
52
52
use driver:: session;
53
53
use lib:: llvm:: llvm;
54
- use lib:: llvm:: { ModuleRef , ContextRef } ;
54
+ use lib:: llvm:: { ModuleRef , ContextRef , ValueRef } ;
55
55
use lib:: llvm:: debuginfo:: * ;
56
56
use middle:: trans:: common:: * ;
57
57
use middle:: trans:: machine;
@@ -97,7 +97,7 @@ pub struct DebugContext {
97
97
priv builder : DIBuilderRef ,
98
98
priv curr_loc : ( uint , uint ) ,
99
99
priv created_files : HashMap < ~str , DIFile > ,
100
- priv created_functions : HashMap < ast :: NodeId , DISubprogram > ,
100
+ priv created_functions : HashMap < FunctionCacheKey , DISubprogram > ,
101
101
priv created_blocks : HashMap < ast:: NodeId , DILexicalBlock > ,
102
102
priv created_types : HashMap < uint , DIType >
103
103
}
@@ -121,6 +121,19 @@ impl DebugContext {
121
121
}
122
122
}
123
123
124
+ #[ deriving( Eq , IterBytes ) ]
125
+ struct FunctionCacheKey {
126
+ // Use the address of the llvm function (FunctionContext::llfn) as key for the cache. This
127
+ // nicely takes care of monomorphization, where two specializations will have the same
128
+ // ast::NodeId but different llvm functions (each needing its own debug description).
129
+ priv llfn : ValueRef
130
+ }
131
+
132
+ impl FunctionCacheKey {
133
+ fn for_function_context ( fcx : & FunctionContext ) -> FunctionCacheKey {
134
+ FunctionCacheKey { llfn : fcx. llfn }
135
+ }
136
+ }
124
137
125
138
pub struct FunctionDebugContext {
126
139
priv scope_map : HashMap < ast:: NodeId , DIScope > ,
@@ -269,13 +282,22 @@ pub fn update_source_pos(fcx: &FunctionContext,
269
282
/// The return value should be ignored if called from outside of the debuginfo module.
270
283
pub fn create_function_metadata ( fcx : & mut FunctionContext ) -> DISubprogram {
271
284
let cx = fcx. ccx ;
285
+ let cache_key = FunctionCacheKey :: for_function_context ( fcx) ;
286
+
287
+ match dbg_cx ( cx) . created_functions . find_copy ( & cache_key) {
288
+ Some ( fn_metadata) => {
289
+ assert ! ( fcx. debug_context. is_some( ) ) ;
290
+ return fn_metadata;
291
+ }
292
+ None => { /* fallthrough */ }
293
+ }
272
294
273
295
let fnitem = cx. tcx . items . get_copy ( & fcx. id ) ;
274
- let ( ident, fn_decl, id , generics ) = match fnitem {
296
+ let ( ident, fn_decl, generics , span ) = match fnitem {
275
297
ast_map:: node_item( ref item, _) => {
276
298
match item. node {
277
299
ast:: item_fn( ref fn_decl, _, _, ref generics, _) => {
278
- ( item. ident , ty , item . id , Some ( generics) )
300
+ ( item. ident , fn_decl , Some ( generics) , item . span )
279
301
}
280
302
_ => fcx. ccx . sess . span_bug ( item. span ,
281
303
"create_function_metadata: item bound to non-function" )
@@ -284,23 +306,24 @@ pub fn create_function_metadata(fcx: &mut FunctionContext) -> DISubprogram {
284
306
ast_map:: node_method(
285
307
@ast:: method {
286
308
decl : ref fn_decl,
287
- id : id,
288
309
ident : ident,
289
310
generics : ref generics,
311
+ span : span,
290
312
_
291
313
} ,
292
314
_,
293
315
_) => {
294
- ( ident, fn_decl, id , Some ( generics) )
316
+ ( ident, fn_decl, Some ( generics) , span )
295
317
}
296
318
ast_map:: node_expr( ref expr) => {
297
319
match expr. node {
298
320
ast:: expr_fn_block( ref fn_decl, _) => {
299
321
let name = gensym_name ( "fn" ) ;
300
- ( name, fn_decl, expr . id ,
322
+ ( name, fn_decl,
301
323
// This is not quite right. It should actually inherit the generics of the
302
324
// enclosing function.
303
- None )
325
+ None ,
326
+ expr. span )
304
327
}
305
328
_ => fcx. ccx . sess . span_bug ( expr. span ,
306
329
"create_function_metadata: expected an expr_fn_block here" )
@@ -310,126 +333,148 @@ pub fn create_function_metadata(fcx: &mut FunctionContext) -> DISubprogram {
310
333
@ast:: provided(
311
334
@ast:: method {
312
335
decl : ref fn_decl,
313
- id : id,
314
336
ident : ident,
315
337
generics : ref generics,
338
+ span : span,
316
339
_
317
340
} ) ,
318
341
_,
319
342
_) => {
320
- ( ident, fn_decl, id , Some ( generics) )
343
+ ( ident, fn_decl, Some ( generics) , span )
321
344
}
322
345
_ => fcx. ccx . sess . bug ( fmt ! ( "create_function_metadata: unexpected sort of node: %?" , fnitem) )
323
346
} ;
324
347
325
- match dbg_cx ( cx) . created_functions . find_copy ( & id) {
326
- Some ( fn_metadata) => return fn_metadata,
327
- None => ( )
328
- }
329
-
330
- let span = match fcx. span {
331
- Some ( value) => value,
332
- None => codemap:: dummy_sp ( )
333
- } ;
334
-
335
348
debug ! ( "create_function_metadata: %s, %s" ,
336
349
cx. sess. str_of( ident) ,
337
350
cx. sess. codemap. span_to_str( span) ) ;
338
351
339
352
let loc = span_start ( cx, span) ;
340
353
let file_metadata = file_metadata ( cx, loc. file . name ) ;
341
354
342
- let return_type_metadata = if cx. sess . opts . extra_debuginfo {
355
+ let function_type_metadata = unsafe {
356
+ let fn_signature = get_function_signature ( fcx, fn_decl) ;
357
+ llvm:: LLVMDIBuilderCreateSubroutineType ( DIB ( cx) , file_metadata, fn_signature)
358
+ } ;
359
+
360
+ let mut function_name = cx. sess . str_of ( ident) . to_owned ( ) ;
361
+ let template_parameters = get_template_parameters ( fcx,
362
+ generics,
363
+ file_metadata,
364
+ span,
365
+ & mut function_name) ;
366
+
367
+ let fn_metadata = do function_name. to_c_str ( ) . with_ref |function_name| {
368
+ unsafe {
369
+ llvm:: LLVMDIBuilderCreateFunction (
370
+ DIB ( cx) ,
371
+ file_metadata,
372
+ function_name,
373
+ function_name,
374
+ file_metadata,
375
+ loc. line as c_uint ,
376
+ function_type_metadata,
377
+ false ,
378
+ true ,
379
+ loc. line as c_uint ,
380
+ FlagPrototyped as c_uint ,
381
+ cx. sess . opts . optimize != session:: No ,
382
+ fcx. llfn ,
383
+ template_parameters,
384
+ ptr:: null ( ) )
385
+ }
386
+ } ;
387
+
388
+ dbg_cx ( cx) . created_functions . insert ( cache_key, fn_metadata) ;
389
+
390
+ // Initialize fn debug context (including scope map)
391
+ {
392
+ assert ! ( fcx. debug_context. is_none( ) ) ;
393
+
394
+ let mut fn_debug_context = ~FunctionDebugContext :: new ( ) ;
395
+ let entry_block_id = fcx. entry_bcx . get_ref ( ) . node_info . get_ref ( ) . id ;
396
+ let entry_block = cx. tcx . items . get ( & entry_block_id) ;
397
+
398
+ match * entry_block {
399
+ ast_map:: node_block( ref block) => {
400
+ let scope_map = & mut fn_debug_context. scope_map ;
401
+ let arg_pats = do fn_decl. inputs . map |arg_ref| { arg_ref. pat } ;
402
+
403
+ populate_scope_map ( cx, arg_pats, block, fn_metadata, scope_map) ;
404
+ }
405
+ _ => cx. sess . span_bug ( span,
406
+ fmt ! ( "debuginfo::create_function_metadata() - \
407
+ FunctionContext::entry_bcx::node_info points to wrong type of ast_map entry. \
408
+ Expected: ast_map::node_block, actual: %?", * entry_block) )
409
+ }
410
+
411
+ fcx. debug_context = Some ( fn_debug_context) ;
412
+ }
413
+
414
+ return fn_metadata;
415
+
416
+ fn get_function_signature ( fcx : & FunctionContext , fn_decl : & ast:: fn_decl ) -> DIArray {
417
+ let cx = fcx. ccx ;
418
+
419
+ if !cx. sess . opts . extra_debuginfo {
420
+ return create_DIArray ( DIB ( cx) , [ ] ) ;
421
+ }
422
+
423
+ let mut signature = vec:: with_capacity ( fn_decl. inputs . len ( ) + 1 ) ;
424
+
425
+ // Return type -- llvm::DIBuilder wants this at index 0
343
426
match fn_decl. output . node {
344
- ast:: ty_nil => ptr:: null ( ) ,
427
+ ast:: ty_nil => {
428
+ signature. push ( ptr:: null ( ) ) ;
429
+ }
345
430
_ => {
346
- let return_type = ty:: node_id_to_type ( cx. tcx , id) ;
431
+ let return_type = ty:: node_id_to_type ( cx. tcx , fcx . id ) ;
347
432
let return_type = match fcx. param_substs {
348
433
None => return_type,
349
434
Some ( substs) => {
350
435
ty:: subst_tps ( cx. tcx , substs. tys , substs. self_ty , return_type)
351
436
}
352
437
} ;
353
438
354
- type_metadata ( cx, return_type, ret_ty . span )
439
+ signature . push ( type_metadata ( cx, return_type, codemap :: dummy_sp ( ) ) ) ;
355
440
}
356
441
}
357
- } else {
358
- ptr:: null ( )
359
- } ;
360
442
361
- let fn_ty = unsafe {
362
- llvm:: LLVMDIBuilderCreateSubroutineType (
363
- DIB ( cx) ,
364
- file_metadata,
365
- create_DIArray ( DIB ( cx) , [ return_type_metadata] ) )
366
- } ;
367
-
368
- let template_parameters: DIArray = get_template_parameters ( cx, fcx, generics, file_metadata, span) ;
369
-
370
- let fn_metadata =
371
- do cx. sess . str_of ( ident) . with_c_str |name| {
372
- do cx. sess . str_of ( ident) . with_c_str |linkage| {
373
- unsafe {
374
- llvm:: LLVMDIBuilderCreateFunction (
375
- DIB ( cx) ,
376
- file_metadata,
377
- name,
378
- linkage,
379
- file_metadata,
380
- loc. line as c_uint ,
381
- fn_ty,
382
- false ,
383
- true ,
384
- loc. line as c_uint ,
385
- FlagPrototyped as c_uint ,
386
- cx. sess . opts . optimize != session:: No ,
387
- fcx. llfn ,
388
- template_parameters,
389
- ptr:: null ( ) )
390
- }
391
- } } ;
392
-
393
- assert ! ( fcx. debug_context. is_none( ) ) ;
394
-
395
- let mut fn_debug_context = ~FunctionDebugContext :: new ( ) ;
396
- let entry_block_id = fcx. entry_bcx . get_ref ( ) . node_info . get_ref ( ) . id ;
397
- let entry_block = cx. tcx . items . get ( & entry_block_id) ;
398
-
399
- match * entry_block {
400
- ast_map:: node_block( ref block) => {
401
- let scope_map = & mut fn_debug_context. scope_map ;
402
- let arg_pats = do fn_decl. inputs . map |arg_ref| { arg_ref. pat } ;
443
+ // arguments types
444
+ for arg in fn_decl. inputs . iter ( ) {
445
+ let arg_type = ty:: node_id_to_type ( cx. tcx , arg. pat . id ) ;
446
+ let arg_type = match fcx. param_substs {
447
+ None => arg_type,
448
+ Some ( substs) => {
449
+ ty:: subst_tps ( cx. tcx , substs. tys , substs. self_ty , arg_type)
450
+ }
451
+ } ;
403
452
404
- populate_scope_map ( cx, arg_pats , block , fn_metadata , scope_map ) ;
453
+ signature . push ( type_metadata ( cx, arg_type , codemap :: dummy_sp ( ) ) ) ;
405
454
}
406
- _ => cx. sess . span_bug ( span,
407
- fmt ! ( "debuginfo::create_function_metadata() - \
408
- FunctionContext::entry_bcx::node_info points to wrong type of ast_map entry. \
409
- Expected: ast_map::node_block, actual: %?", * entry_block) )
410
- }
411
-
412
- fcx. debug_context = Some ( fn_debug_context) ;
413
455
414
- dbg_cx ( cx) . created_functions . insert ( id , fn_metadata ) ;
415
- return fn_metadata ;
456
+ return create_DIArray ( DIB ( cx) , signature ) ;
457
+ }
416
458
417
- fn get_template_parameters ( cx : & mut CrateContext ,
418
- fcx : & FunctionContext ,
459
+ fn get_template_parameters ( fcx : & FunctionContext ,
419
460
generics : Option < & ast:: Generics > ,
420
461
file_metadata : DIFile ,
421
- span : span ) -> DIArray {
462
+ span : span ,
463
+ name_to_append_suffix_to : & mut ~str )
464
+ -> DIArray {
422
465
// Normalize cases
423
466
let generics = match generics {
424
467
Some ( generics_ref) if generics_ref. is_type_parameterized ( ) => Some ( generics_ref) ,
425
468
_ => None
426
469
} ;
427
470
471
+ let cx = fcx. ccx ;
472
+
428
473
match generics {
429
474
None => {
430
475
if ( fcx. param_substs . is_some ( ) ) {
431
476
cx. sess . span_bug ( span, "debuginfo::create_function_metadata() - \
432
- Mismatch between ast::Generics and FunctionContext::param_substs 111 ") ;
477
+ Mismatch between ast::Generics and FunctionContext::param_substs") ;
433
478
}
434
479
435
480
return ptr:: null ( ) ;
@@ -442,22 +487,31 @@ pub fn create_function_metadata(fcx: &mut FunctionContext) -> DISubprogram {
442
487
}
443
488
None => {
444
489
cx. sess . span_bug ( span, "debuginfo::create_function_metadata() - \
445
- Mismatch between ast::Generics and FunctionContext::param_substs 222 ") ;
490
+ Mismatch between ast::Generics and FunctionContext::param_substs") ;
446
491
}
447
492
} ;
448
493
494
+ name_to_append_suffix_to. push_char ( '<' ) ;
495
+
449
496
let template_params: ~[ DIDescriptor ] = do generics
450
497
. ty_params
451
498
. iter ( )
452
499
. enumerate ( )
453
- . transform |( index, & ast:: TyParam { ident : ident, _ } ) | {
500
+ . map |( index, & ast:: TyParam { ident : ident, _ } ) | {
454
501
455
502
let actual_type = actual_types[ index] ;
456
503
let actual_type_metadata = type_metadata ( cx,
457
504
actual_type,
458
505
codemap:: dummy_sp ( ) ) ;
459
506
460
- do cx. sess . str_of ( ident) . as_c_str |name| {
507
+ // Add actual type name to <...> clause of function name
508
+ let actual_type_name = ty_to_str ( cx. tcx , actual_type) ;
509
+ name_to_append_suffix_to. push_str ( actual_type_name) ;
510
+ if index != generics. ty_params . len ( ) - 1 {
511
+ name_to_append_suffix_to. push_str ( ", " ) ;
512
+ }
513
+
514
+ do cx. sess . str_of ( ident) . to_c_str ( ) . with_ref |name| {
461
515
unsafe {
462
516
llvm:: LLVMDIBuilderCreateTemplateTypeParameter (
463
517
DIB ( cx) ,
@@ -471,6 +525,8 @@ pub fn create_function_metadata(fcx: &mut FunctionContext) -> DISubprogram {
471
525
}
472
526
} . collect ( ) ;
473
527
528
+ name_to_append_suffix_to. push_char ( '>' ) ;
529
+
474
530
return create_DIArray ( DIB ( cx) , template_params) ;
475
531
}
476
532
}
0 commit comments