@@ -40,6 +40,7 @@ use crate::spec::crt_objects::{CrtObjects, CrtObjectsFallback};
40
40
use rustc_serialize:: json:: { Json , ToJson } ;
41
41
use rustc_span:: symbol:: { sym, Symbol } ;
42
42
use std:: collections:: BTreeMap ;
43
+ use std:: convert:: TryFrom ;
43
44
use std:: ops:: { Deref , DerefMut } ;
44
45
use std:: path:: { Path , PathBuf } ;
45
46
use std:: str:: FromStr ;
@@ -479,6 +480,83 @@ macro_rules! supported_targets {
479
480
} ;
480
481
}
481
482
483
+ #[ derive( Clone , Debug , PartialEq , Eq ) ]
484
+ pub enum StackProbeType {
485
+ /// Don't emit any stack probes.
486
+ None ,
487
+ /// It is harmless to use this option even on targets that do not have backend support for
488
+ /// stack probes as the failure mode is the same as if no stack-probe option was specified in
489
+ /// the first place.
490
+ Inline ,
491
+ /// Call `__rust_probestack` whenever stack needs to be probed.
492
+ Call ,
493
+ /// Use inline option for LLVM versions later than specified in `min_llvm_version_for_inline`
494
+ /// and call `__rust_probestack` otherwise.
495
+ InlineOrCall { min_llvm_version_for_inline : ( u32 , u32 , u32 ) } ,
496
+ }
497
+
498
+ impl StackProbeType {
499
+ fn from_json ( json : & Json ) -> Result < Self , String > {
500
+ let object = json. as_object ( ) . ok_or_else ( || "expected a JSON object" ) ?;
501
+ let kind = object
502
+ . get ( "kind" )
503
+ . and_then ( |o| o. as_string ( ) )
504
+ . ok_or_else ( || "expected `kind` to be a string" ) ?;
505
+ match kind {
506
+ "none" => Ok ( StackProbeType :: None ) ,
507
+ "inline" => Ok ( StackProbeType :: Inline ) ,
508
+ "call" => Ok ( StackProbeType :: Call ) ,
509
+ "inline-or-call" => {
510
+ let min_version = object
511
+ . get ( "min-llvm-version-for-inline" )
512
+ . and_then ( |o| o. as_array ( ) )
513
+ . ok_or_else ( || "expected `min-llvm-version-for-inline` to be an array" ) ?;
514
+ let mut iter = min_version. into_iter ( ) . map ( |v| {
515
+ let int = v. as_u64 ( ) . ok_or_else (
516
+ || "expected `min-llvm-version-for-inline` values to be integers" ,
517
+ ) ?;
518
+ u32:: try_from ( int)
519
+ . map_err ( |_| "`min-llvm-version-for-inline` values don't convert to u32" )
520
+ } ) ;
521
+ let min_llvm_version_for_inline = (
522
+ iter. next ( ) . unwrap_or ( Ok ( 11 ) ) ?,
523
+ iter. next ( ) . unwrap_or ( Ok ( 0 ) ) ?,
524
+ iter. next ( ) . unwrap_or ( Ok ( 0 ) ) ?,
525
+ ) ;
526
+ Ok ( StackProbeType :: InlineOrCall { min_llvm_version_for_inline } )
527
+ }
528
+ _ => Err ( String :: from (
529
+ "`kind` expected to be one of `inline-or-none`, `call` or `inline-or-call`" ,
530
+ ) ) ,
531
+ }
532
+ }
533
+ }
534
+
535
+ impl ToJson for StackProbeType {
536
+ fn to_json ( & self ) -> Json {
537
+ Json :: Object ( match self {
538
+ StackProbeType :: None => {
539
+ vec ! [ ( String :: from( "kind" ) , "none" . to_json( ) ) ] . into_iter ( ) . collect ( )
540
+ }
541
+ StackProbeType :: Inline => {
542
+ vec ! [ ( String :: from( "kind" ) , "inline" . to_json( ) ) ] . into_iter ( ) . collect ( )
543
+ }
544
+ StackProbeType :: Call => {
545
+ vec ! [ ( String :: from( "kind" ) , "call" . to_json( ) ) ] . into_iter ( ) . collect ( )
546
+ }
547
+ StackProbeType :: InlineOrCall { min_llvm_version_for_inline } => vec ! [
548
+ ( String :: from( "kind" ) , "inline-or-call" . to_json( ) ) ,
549
+ (
550
+ String :: from( "min-llvm-version-for-inline" ) ,
551
+ min_llvm_version_for_inline. to_json( ) ,
552
+ ) ,
553
+ ]
554
+ . into_iter ( )
555
+ . collect ( ) ,
556
+ } )
557
+ }
558
+ }
559
+
482
560
supported_targets ! {
483
561
( "x86_64-unknown-linux-gnu" , x86_64_unknown_linux_gnu) ,
484
562
( "x86_64-unknown-linux-gnux32" , x86_64_unknown_linux_gnux32) ,
@@ -926,8 +1004,8 @@ pub struct TargetOptions {
926
1004
/// Whether or not crt-static is respected by the compiler (or is a no-op).
927
1005
pub crt_static_respected : bool ,
928
1006
929
- /// Whether or not stack probes (__rust_probestack) are enabled
930
- pub stack_probes : bool ,
1007
+ /// The implementation of stack probes to use.
1008
+ pub stack_probes : StackProbeType ,
931
1009
932
1010
/// The minimum alignment for global symbols.
933
1011
pub min_global_align : Option < u64 > ,
@@ -1085,7 +1163,7 @@ impl Default for TargetOptions {
1085
1163
crt_static_allows_dylibs : false ,
1086
1164
crt_static_default : false ,
1087
1165
crt_static_respected : false ,
1088
- stack_probes : false ,
1166
+ stack_probes : StackProbeType :: None ,
1089
1167
min_global_align : None ,
1090
1168
default_codegen_units : None ,
1091
1169
trap_unreachable : true ,
@@ -1361,6 +1439,18 @@ impl Target {
1361
1439
Some ( Ok ( ( ) ) )
1362
1440
} ) ) . unwrap_or( Ok ( ( ) ) )
1363
1441
} ) ;
1442
+ ( $key_name: ident, StackProbeType ) => ( {
1443
+ let name = ( stringify!( $key_name) ) . replace( "_" , "-" ) ;
1444
+ obj. find( & name[ ..] ) . and_then( |o| match StackProbeType :: from_json( o) {
1445
+ Ok ( v) => {
1446
+ base. $key_name = v;
1447
+ Some ( Ok ( ( ) ) )
1448
+ } ,
1449
+ Err ( s) => Some ( Err (
1450
+ format!( "`{:?}` is not a valid value for `{}`: {}" , o, name, s)
1451
+ ) ) ,
1452
+ } ) . unwrap_or( Ok ( ( ) ) )
1453
+ } ) ;
1364
1454
( $key_name: ident, crt_objects_fallback) => ( {
1365
1455
let name = ( stringify!( $key_name) ) . replace( "_" , "-" ) ;
1366
1456
obj. find( & name[ ..] ) . and_then( |o| o. as_string( ) . and_then( |s| {
@@ -1516,7 +1606,7 @@ impl Target {
1516
1606
key ! ( crt_static_allows_dylibs, bool ) ;
1517
1607
key ! ( crt_static_default, bool ) ;
1518
1608
key ! ( crt_static_respected, bool ) ;
1519
- key ! ( stack_probes, bool ) ;
1609
+ key ! ( stack_probes, StackProbeType ) ? ;
1520
1610
key ! ( min_global_align, Option <u64 >) ;
1521
1611
key ! ( default_codegen_units, Option <u64 >) ;
1522
1612
key ! ( trap_unreachable, bool ) ;
0 commit comments