Skip to content

Commit 0b7ba6e

Browse files
committed
std: Improve downstream codegen in Command::env
This commit rejiggers the generics used in the implementation of `Command::env` with the purpose of reducing the amount of codegen that needs to happen in consumer crates, instead preferring to generate code into libstd. This was found when profiling the compile times of the `cc` crate where the binary rlib produced had a lot of `BTreeMap` code compiled into it but the crate doesn't actually use `BTreeMap`. It turns out that `Command::env` is generic enough to codegen the entire implementation in calling crates, but in this case there's no performance concern so it's fine to compile the code into the standard library. This change is done by removing the generic on the `CommandEnv` map which is intended to handle case-insensitive variables on Windows. Instead now a generic isn't used but rather a `use` statement defined per-platform is used. With this commit a debug build of `Command::new("foo").env("a", "b")` drops from 21k lines of LLVM IR to 10k.
1 parent 6187684 commit 0b7ba6e

File tree

9 files changed

+56
-70
lines changed

9 files changed

+56
-70
lines changed

src/libstd/sys/cloudabi/shims/process.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,16 @@ use crate::io;
44
use crate::sys::fs::File;
55
use crate::sys::pipe::AnonPipe;
66
use crate::sys::{unsupported, Void};
7-
use crate::sys_common::process::{CommandEnv, DefaultEnvKey};
7+
use crate::sys_common::process::CommandEnv;
8+
9+
pub use crate::ffi::OsString as EnvKey;
810

911
////////////////////////////////////////////////////////////////////////////////
1012
// Command
1113
////////////////////////////////////////////////////////////////////////////////
1214

1315
pub struct Command {
14-
env: CommandEnv<DefaultEnvKey>,
16+
env: CommandEnv,
1517
}
1618

1719
// passed back to std::process with the pipes connected to the child, if any
@@ -37,7 +39,7 @@ impl Command {
3739

3840
pub fn arg(&mut self, _arg: &OsStr) {}
3941

40-
pub fn env_mut(&mut self) -> &mut CommandEnv<DefaultEnvKey> {
42+
pub fn env_mut(&mut self) -> &mut CommandEnv {
4143
&mut self.env
4244
}
4345

src/libstd/sys/sgx/process.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,16 @@ use crate::io;
44
use crate::sys::fs::File;
55
use crate::sys::pipe::AnonPipe;
66
use crate::sys::{unsupported, Void};
7-
use crate::sys_common::process::{CommandEnv, DefaultEnvKey};
7+
use crate::sys_common::process::CommandEnv;
8+
9+
pub use crate::ffi::OsString as EnvKey;
810

911
////////////////////////////////////////////////////////////////////////////////
1012
// Command
1113
////////////////////////////////////////////////////////////////////////////////
1214

1315
pub struct Command {
14-
env: CommandEnv<DefaultEnvKey>
16+
env: CommandEnv,
1517
}
1618

1719
// passed back to std::process with the pipes connected to the child, if any
@@ -38,7 +40,7 @@ impl Command {
3840
pub fn arg(&mut self, _arg: &OsStr) {
3941
}
4042

41-
pub fn env_mut(&mut self) -> &mut CommandEnv<DefaultEnvKey> {
43+
pub fn env_mut(&mut self) -> &mut CommandEnv {
4244
&mut self.env
4345
}
4446

src/libstd/sys/unix/process/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
pub use self::process_common::{Command, ExitStatus, ExitCode, Stdio, StdioPipes};
22
pub use self::process_inner::Process;
3+
pub use crate::ffi::OsString as EnvKey;
34

45
mod process_common;
56
#[cfg(not(target_os = "fuchsia"))]

src/libstd/sys/unix/process/process_common.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use crate::ptr;
77
use crate::sys::fd::FileDesc;
88
use crate::sys::fs::{File, OpenOptions};
99
use crate::sys::pipe::{self, AnonPipe};
10-
use crate::sys_common::process::{CommandEnv, DefaultEnvKey};
10+
use crate::sys_common::process::CommandEnv;
1111
use crate::collections::BTreeMap;
1212

1313
use libc::{c_int, gid_t, uid_t, c_char, EXIT_SUCCESS, EXIT_FAILURE};
@@ -69,7 +69,7 @@ pub struct Command {
6969
program: CString,
7070
args: Vec<CString>,
7171
argv: Argv,
72-
env: CommandEnv<DefaultEnvKey>,
72+
env: CommandEnv,
7373

7474
cwd: Option<CString>,
7575
uid: Option<uid_t>,
@@ -201,7 +201,7 @@ impl Command {
201201
self.stderr = Some(stderr);
202202
}
203203

204-
pub fn env_mut(&mut self) -> &mut CommandEnv<DefaultEnvKey> {
204+
pub fn env_mut(&mut self) -> &mut CommandEnv {
205205
&mut self.env
206206
}
207207

@@ -271,7 +271,7 @@ impl CStringArray {
271271
}
272272
}
273273

274-
fn construct_envp(env: BTreeMap<DefaultEnvKey, OsString>, saw_nul: &mut bool) -> CStringArray {
274+
fn construct_envp(env: BTreeMap<OsString, OsString>, saw_nul: &mut bool) -> CStringArray {
275275
let mut result = CStringArray::with_capacity(env.len());
276276
for (k, v) in env {
277277
let mut k: OsString = k.into();

src/libstd/sys/vxworks/process/process_common.rs

+6-4
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,13 @@ use crate::ptr;
77
use crate::sys::fd::FileDesc;
88
use crate::sys::fs::{File, OpenOptions};
99
use crate::sys::pipe::{self, AnonPipe};
10-
use crate::sys_common::process::{CommandEnv, DefaultEnvKey};
10+
use crate::sys_common::process::CommandEnv;
1111
use crate::collections::BTreeMap;
1212

1313
use libc::{c_int, gid_t, uid_t, c_char, EXIT_SUCCESS, EXIT_FAILURE};
1414

15+
pub use crate::ffi::OsString as EnvKey;
16+
1517
////////////////////////////////////////////////////////////////////////////////
1618
// Command
1719
////////////////////////////////////////////////////////////////////////////////
@@ -37,7 +39,7 @@ pub struct Command {
3739
program: CString,
3840
args: Vec<CString>,
3941
argv: Argv,
40-
env: CommandEnv<DefaultEnvKey>,
42+
env: CommandEnv,
4143

4244
cwd: Option<CString>,
4345
uid: Option<uid_t>,
@@ -170,7 +172,7 @@ impl Command {
170172
self.stderr = Some(stderr);
171173
}
172174

173-
pub fn env_mut(&mut self) -> &mut CommandEnv<DefaultEnvKey> {
175+
pub fn env_mut(&mut self) -> &mut CommandEnv {
174176
&mut self.env
175177
}
176178

@@ -240,7 +242,7 @@ impl CStringArray {
240242
}
241243
}
242244

243-
fn construct_envp(env: BTreeMap<DefaultEnvKey, OsString>, saw_nul: &mut bool) -> CStringArray {
245+
fn construct_envp(env: BTreeMap<OsString, OsString>, saw_nul: &mut bool) -> CStringArray {
244246
let mut result = CStringArray::with_capacity(env.len());
245247
for (k, v) in env {
246248
let mut k: OsString = k.into();

src/libstd/sys/wasi/process.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,16 @@ use crate::io;
44
use crate::sys::fs::File;
55
use crate::sys::pipe::AnonPipe;
66
use crate::sys::{unsupported, Void};
7-
use crate::sys_common::process::{CommandEnv, DefaultEnvKey};
7+
use crate::sys_common::process::CommandEnv;
8+
9+
pub use crate::ffi::OsString as EnvKey;
810

911
////////////////////////////////////////////////////////////////////////////////
1012
// Command
1113
////////////////////////////////////////////////////////////////////////////////
1214

1315
pub struct Command {
14-
env: CommandEnv<DefaultEnvKey>
16+
env: CommandEnv
1517
}
1618

1719
// passed back to std::process with the pipes connected to the child, if any
@@ -38,7 +40,7 @@ impl Command {
3840
pub fn arg(&mut self, _arg: &OsStr) {
3941
}
4042

41-
pub fn env_mut(&mut self) -> &mut CommandEnv<DefaultEnvKey> {
43+
pub fn env_mut(&mut self) -> &mut CommandEnv {
4244
&mut self.env
4345
}
4446

src/libstd/sys/wasm/process.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,16 @@ use crate::io;
44
use crate::sys::fs::File;
55
use crate::sys::pipe::AnonPipe;
66
use crate::sys::{unsupported, Void};
7-
use crate::sys_common::process::{CommandEnv, DefaultEnvKey};
7+
use crate::sys_common::process::CommandEnv;
8+
9+
pub use crate::ffi::OsString as EnvKey;
810

911
////////////////////////////////////////////////////////////////////////////////
1012
// Command
1113
////////////////////////////////////////////////////////////////////////////////
1214

1315
pub struct Command {
14-
env: CommandEnv<DefaultEnvKey>
16+
env: CommandEnv,
1517
}
1618

1719
// passed back to std::process with the pipes connected to the child, if any
@@ -38,7 +40,7 @@ impl Command {
3840
pub fn arg(&mut self, _arg: &OsStr) {
3941
}
4042

41-
pub fn env_mut(&mut self) -> &mut CommandEnv<DefaultEnvKey> {
43+
pub fn env_mut(&mut self) -> &mut CommandEnv {
4244
&mut self.env
4345
}
4446

src/libstd/sys/windows/process.rs

+11-13
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use crate::sys::pipe::{self, AnonPipe};
1919
use crate::sys::stdio;
2020
use crate::sys::cvt;
2121
use crate::sys_common::{AsInner, FromInner, IntoInner};
22-
use crate::sys_common::process::{CommandEnv, EnvKey};
22+
use crate::sys_common::process::CommandEnv;
2323
use crate::borrow::Borrow;
2424

2525
use libc::{c_void, EXIT_SUCCESS, EXIT_FAILURE};
@@ -30,30 +30,28 @@ use libc::{c_void, EXIT_SUCCESS, EXIT_FAILURE};
3030

3131
#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
3232
#[doc(hidden)]
33-
pub struct WindowsEnvKey(OsString);
33+
pub struct EnvKey(OsString);
3434

35-
impl From<OsString> for WindowsEnvKey {
35+
impl From<OsString> for EnvKey {
3636
fn from(k: OsString) -> Self {
3737
let mut buf = k.into_inner().into_inner();
3838
buf.make_ascii_uppercase();
39-
WindowsEnvKey(FromInner::from_inner(FromInner::from_inner(buf)))
39+
EnvKey(FromInner::from_inner(FromInner::from_inner(buf)))
4040
}
4141
}
4242

43-
impl From<WindowsEnvKey> for OsString {
44-
fn from(k: WindowsEnvKey) -> Self { k.0 }
43+
impl From<EnvKey> for OsString {
44+
fn from(k: EnvKey) -> Self { k.0 }
4545
}
4646

47-
impl Borrow<OsStr> for WindowsEnvKey {
47+
impl Borrow<OsStr> for EnvKey {
4848
fn borrow(&self) -> &OsStr { &self.0 }
4949
}
5050

51-
impl AsRef<OsStr> for WindowsEnvKey {
51+
impl AsRef<OsStr> for EnvKey {
5252
fn as_ref(&self) -> &OsStr { &self.0 }
5353
}
5454

55-
impl EnvKey for WindowsEnvKey {}
56-
5755

5856
fn ensure_no_nuls<T: AsRef<OsStr>>(str: T) -> io::Result<T> {
5957
if str.as_ref().encode_wide().any(|b| b == 0) {
@@ -66,7 +64,7 @@ fn ensure_no_nuls<T: AsRef<OsStr>>(str: T) -> io::Result<T> {
6664
pub struct Command {
6765
program: OsString,
6866
args: Vec<OsString>,
69-
env: CommandEnv<WindowsEnvKey>,
67+
env: CommandEnv,
7068
cwd: Option<OsString>,
7169
flags: u32,
7270
detach: bool, // not currently exposed in std::process
@@ -110,7 +108,7 @@ impl Command {
110108
pub fn arg(&mut self, arg: &OsStr) {
111109
self.args.push(arg.to_os_string())
112110
}
113-
pub fn env_mut(&mut self) -> &mut CommandEnv<WindowsEnvKey> {
111+
pub fn env_mut(&mut self) -> &mut CommandEnv {
114112
&mut self.env
115113
}
116114
pub fn cwd(&mut self, dir: &OsStr) {
@@ -498,7 +496,7 @@ fn make_command_line(prog: &OsStr, args: &[OsString]) -> io::Result<Vec<u16>> {
498496
}
499497
}
500498

501-
fn make_envp(maybe_env: Option<BTreeMap<WindowsEnvKey, OsString>>)
499+
fn make_envp(maybe_env: Option<BTreeMap<EnvKey, OsString>>)
502500
-> io::Result<(*mut c_void, Vec<u16>)> {
503501
// On Windows we pass an "environment block" which is not a char**, but
504502
// rather a concatenation of null-terminated k=v\0 sequences, with a final

src/libstd/sys_common/process.rs

+14-37
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,20 @@
11
#![allow(dead_code)]
22
#![unstable(feature = "process_internals", issue = "0")]
33

4-
use crate::ffi::{OsStr, OsString};
5-
use crate::env;
64
use crate::collections::BTreeMap;
7-
use crate::borrow::Borrow;
8-
9-
pub trait EnvKey:
10-
From<OsString> + Into<OsString> +
11-
Borrow<OsStr> + Borrow<Self> + AsRef<OsStr> +
12-
Ord + Clone {}
13-
14-
// Implement a case-sensitive environment variable key
15-
#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
16-
pub struct DefaultEnvKey(OsString);
17-
18-
impl From<OsString> for DefaultEnvKey {
19-
fn from(k: OsString) -> Self { DefaultEnvKey(k) }
20-
}
21-
22-
impl From<DefaultEnvKey> for OsString {
23-
fn from(k: DefaultEnvKey) -> Self { k.0 }
24-
}
25-
26-
impl Borrow<OsStr> for DefaultEnvKey {
27-
fn borrow(&self) -> &OsStr { &self.0 }
28-
}
29-
30-
impl AsRef<OsStr> for DefaultEnvKey {
31-
fn as_ref(&self) -> &OsStr { &self.0 }
32-
}
33-
34-
impl EnvKey for DefaultEnvKey {}
5+
use crate::env;
6+
use crate::ffi::{OsStr, OsString};
7+
use crate::sys::process::EnvKey;
358

369
// Stores a set of changes to an environment
3710
#[derive(Clone, Debug)]
38-
pub struct CommandEnv<K> {
11+
pub struct CommandEnv {
3912
clear: bool,
4013
saw_path: bool,
41-
vars: BTreeMap<K, Option<OsString>>
14+
vars: BTreeMap<EnvKey, Option<OsString>>
4215
}
4316

44-
impl<K: EnvKey> Default for CommandEnv<K> {
17+
impl Default for CommandEnv {
4518
fn default() -> Self {
4619
CommandEnv {
4720
clear: false,
@@ -51,10 +24,10 @@ impl<K: EnvKey> Default for CommandEnv<K> {
5124
}
5225
}
5326

54-
impl<K: EnvKey> CommandEnv<K> {
27+
impl CommandEnv {
5528
// Capture the current environment with these changes applied
56-
pub fn capture(&self) -> BTreeMap<K, OsString> {
57-
let mut result = BTreeMap::<K, OsString>::new();
29+
pub fn capture(&self) -> BTreeMap<EnvKey, OsString> {
30+
let mut result = BTreeMap::<EnvKey, OsString>::new();
5831
if !self.clear {
5932
for (k, v) in env::vars_os() {
6033
result.insert(k.into(), v);
@@ -90,7 +63,7 @@ impl<K: EnvKey> CommandEnv<K> {
9063
!self.clear && self.vars.is_empty()
9164
}
9265

93-
pub fn capture_if_changed(&self) -> Option<BTreeMap<K, OsString>> {
66+
pub fn capture_if_changed(&self) -> Option<BTreeMap<EnvKey, OsString>> {
9467
if self.is_unchanged() {
9568
None
9669
} else {
@@ -103,6 +76,7 @@ impl<K: EnvKey> CommandEnv<K> {
10376
self.maybe_saw_path(&key);
10477
self.vars.insert(key.to_owned().into(), Some(value.to_owned()));
10578
}
79+
10680
pub fn remove(&mut self, key: &OsStr) {
10781
self.maybe_saw_path(&key);
10882
if self.clear {
@@ -111,13 +85,16 @@ impl<K: EnvKey> CommandEnv<K> {
11185
self.vars.insert(key.to_owned().into(), None);
11286
}
11387
}
88+
11489
pub fn clear(&mut self) {
11590
self.clear = true;
11691
self.vars.clear();
11792
}
93+
11894
pub fn have_changed_path(&self) -> bool {
11995
self.saw_path || self.clear
12096
}
97+
12198
fn maybe_saw_path(&mut self, key: &OsStr) {
12299
if !self.saw_path && key == "PATH" {
123100
self.saw_path = true;

0 commit comments

Comments
 (0)