std: Remove the `wasm_syscall` feature

This commit removes the `wasm_syscall` feature from the
wasm32-unknown-unknown build of the standard library. This feature was
originally intended to allow an opt-in way to interact with the
operating system in a posix-like way but it was never stabilized.
Nowadays with the advent of the `wasm32-wasi` target that should
entirely replace the intentions of the `wasm_syscall` feature.
This commit is contained in:
Alex Crichton 2019-07-23 07:25:34 -07:00
parent ac21131f78
commit 8fe65da935
11 changed files with 19 additions and 379 deletions

View File

@ -382,11 +382,6 @@
# This is the name of the directory in which codegen backends will get installed
#codegen-backends-dir = "codegen-backends"
# Flag indicating whether `libstd` calls an imported function to handle basic IO
# when targeting WebAssembly. Enable this to debug tests for the `wasm32-unknown-unknown`
# target, as without this option the test output will not be captured.
#wasm-syscall = false
# Indicates whether LLD will be compiled and made available in the sysroot for
# rustc to execute.
#lld = false

View File

@ -122,7 +122,6 @@ pub struct Config {
// libstd features
pub backtrace: bool, // support for RUST_BACKTRACE
pub wasm_syscall: bool,
// misc
pub low_priority: bool,
@ -318,7 +317,6 @@ struct Rust {
save_toolstates: Option<String>,
codegen_backends: Option<Vec<String>>,
codegen_backends_dir: Option<String>,
wasm_syscall: Option<bool>,
lld: Option<bool>,
lldb: Option<bool>,
llvm_tools: Option<bool>,
@ -558,7 +556,6 @@ impl Config {
if let Some(true) = rust.incremental {
config.incremental = true;
}
set(&mut config.wasm_syscall, rust.wasm_syscall);
set(&mut config.lld_enabled, rust.lld);
set(&mut config.lldb_enabled, rust.lldb);
set(&mut config.llvm_tools_enabled, rust.llvm_tools);

View File

@ -498,9 +498,6 @@ impl Build {
if self.config.profiler {
features.push_str(" profiler");
}
if self.config.wasm_syscall {
features.push_str(" wasm_syscall");
}
features
}

View File

@ -1811,16 +1811,6 @@ impl Step for Crate {
.expect("nodejs not configured"),
);
} else if target.starts_with("wasm32") {
// Warn about running tests without the `wasm_syscall` feature enabled.
// The javascript shim implements the syscall interface so that test
// output can be correctly reported.
if !builder.config.wasm_syscall {
builder.info(
"Libstd was built without `wasm_syscall` feature enabled: \
test output may not be visible."
);
}
// On the wasm32-unknown-unknown target we're using LTO which is
// incompatible with `-C prefer-dynamic`, so disable that here
cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1");

View File

@ -15,113 +15,7 @@ const buffer = fs.readFileSync(process.argv[2]);
Error.stackTraceLimit = 20;
let m = new WebAssembly.Module(buffer);
let memory = null;
function viewstruct(data, fields) {
return new Uint32Array(memory.buffer).subarray(data/4, data/4 + fields);
}
function copystr(a, b) {
let view = new Uint8Array(memory.buffer).subarray(a, a + b);
return String.fromCharCode.apply(null, view);
}
function syscall_write([fd, ptr, len]) {
let s = copystr(ptr, len);
switch (fd) {
case 1: process.stdout.write(s); break;
case 2: process.stderr.write(s); break;
}
}
function syscall_exit([code]) {
process.exit(code);
}
function syscall_args(params) {
let [ptr, len] = params;
// Calculate total required buffer size
let totalLen = -1;
for (let i = 2; i < process.argv.length; ++i) {
totalLen += Buffer.byteLength(process.argv[i]) + 1;
}
if (totalLen < 0) { totalLen = 0; }
params[2] = totalLen;
// If buffer is large enough, copy data
if (len >= totalLen) {
let view = new Uint8Array(memory.buffer);
for (let i = 2; i < process.argv.length; ++i) {
let value = process.argv[i];
Buffer.from(value).copy(view, ptr);
ptr += Buffer.byteLength(process.argv[i]) + 1;
}
}
}
function syscall_getenv(params) {
let [keyPtr, keyLen, valuePtr, valueLen] = params;
let key = copystr(keyPtr, keyLen);
let value = process.env[key];
if (value == null) {
params[4] = 0xFFFFFFFF;
} else {
let view = new Uint8Array(memory.buffer);
let totalLen = Buffer.byteLength(value);
params[4] = totalLen;
if (valueLen >= totalLen) {
Buffer.from(value).copy(view, valuePtr);
}
}
}
function syscall_time(params) {
let t = Date.now();
let secs = Math.floor(t / 1000);
let millis = t % 1000;
params[1] = Math.floor(secs / 0x100000000);
params[2] = secs % 0x100000000;
params[3] = Math.floor(millis * 1000000);
}
let imports = {};
imports.env = {
// These are generated by LLVM itself for various intrinsic calls. Hopefully
// one day this is not necessary and something will automatically do this.
fmod: function(x, y) { return x % y; },
exp2: function(x) { return Math.pow(2, x); },
exp2f: function(x) { return Math.pow(2, x); },
ldexp: function(x, y) { return x * Math.pow(2, y); },
ldexpf: function(x, y) { return x * Math.pow(2, y); },
sin: Math.sin,
sinf: Math.sin,
cos: Math.cos,
cosf: Math.cos,
log: Math.log,
log2: Math.log2,
log10: Math.log10,
log10f: Math.log10,
rust_wasm_syscall: function(index, data) {
switch (index) {
case 1: syscall_write(viewstruct(data, 3)); return true;
case 2: syscall_exit(viewstruct(data, 1)); return true;
case 3: syscall_args(viewstruct(data, 3)); return true;
case 4: syscall_getenv(viewstruct(data, 5)); return true;
case 6: syscall_time(viewstruct(data, 4)); return true;
default:
console.log("Unsupported syscall: " + index);
return false;
}
}
};
let instance = new WebAssembly.Instance(m, imports);
memory = instance.exports.memory;
let instance = new WebAssembly.Instance(m, {});
try {
instance.exports.main();
} catch (e) {

View File

@ -70,11 +70,6 @@ llvm-libunwind = ["unwind/llvm-libunwind"]
# Make panics and failed asserts immediately abort without formatting any message
panic_immediate_abort = ["core/panic_immediate_abort"]
# An off-by-default feature which enables a linux-syscall-like ABI for libstd to
# interoperate with the host environment. Currently not well documented and
# requires rebuilding the standard library to use it.
wasm_syscall = []
# Enable std_detect default features for stdarch/crates/std_detect:
# https://github.com/rust-lang/stdarch/blob/master/crates/std_detect/Cargo.toml
std_detect_file_io = []

View File

@ -1,7 +1,6 @@
use crate::ffi::OsString;
use crate::marker::PhantomData;
use crate::vec;
use crate::sys::ArgsSysCall;
pub unsafe fn init(_argc: isize, _argv: *const *const u8) {
// On wasm these should always be null, so there's nothing for us to do here
@ -11,9 +10,8 @@ pub unsafe fn cleanup() {
}
pub fn args() -> Args {
let v = ArgsSysCall::perform();
Args {
iter: v.into_iter(),
iter: Vec::new().into_iter(),
_dont_send_or_sync_me: PhantomData,
}
}

View File

@ -15,11 +15,6 @@
//! guaranteed to be a runtime error!
use crate::os::raw::c_char;
use crate::ptr;
use crate::sys::os_str::Buf;
use crate::sys_common::{AsInner, FromInner};
use crate::ffi::{OsString, OsStr};
use crate::time::Duration;
pub mod alloc;
pub mod args;
@ -89,7 +84,7 @@ pub unsafe fn strlen(mut s: *const c_char) -> usize {
}
pub unsafe fn abort_internal() -> ! {
ExitSysCall::perform(1)
crate::arch::wasm32::unreachable()
}
// We don't have randomness yet, but I totally used a random number generator to
@ -100,218 +95,3 @@ pub unsafe fn abort_internal() -> ! {
pub fn hashmap_random_keys() -> (u64, u64) {
(1, 2)
}
// Implement a minimal set of system calls to enable basic IO
pub enum SysCallIndex {
Read = 0,
Write = 1,
Exit = 2,
Args = 3,
GetEnv = 4,
SetEnv = 5,
Time = 6,
}
#[repr(C)]
pub struct ReadSysCall {
fd: usize,
ptr: *mut u8,
len: usize,
result: usize,
}
impl ReadSysCall {
pub fn perform(fd: usize, buffer: &mut [u8]) -> usize {
let mut call_record = ReadSysCall {
fd,
len: buffer.len(),
ptr: buffer.as_mut_ptr(),
result: 0
};
if unsafe { syscall(SysCallIndex::Read, &mut call_record) } {
call_record.result
} else {
0
}
}
}
#[repr(C)]
pub struct WriteSysCall {
fd: usize,
ptr: *const u8,
len: usize,
}
impl WriteSysCall {
pub fn perform(fd: usize, buffer: &[u8]) {
let mut call_record = WriteSysCall {
fd,
len: buffer.len(),
ptr: buffer.as_ptr()
};
unsafe { syscall(SysCallIndex::Write, &mut call_record); }
}
}
#[repr(C)]
pub struct ExitSysCall {
code: usize,
}
impl ExitSysCall {
pub fn perform(code: usize) -> ! {
let mut call_record = ExitSysCall {
code
};
unsafe {
syscall(SysCallIndex::Exit, &mut call_record);
crate::intrinsics::abort();
}
}
}
fn receive_buffer<E, F: FnMut(&mut [u8]) -> Result<usize, E>>(estimate: usize, mut f: F)
-> Result<Vec<u8>, E>
{
let mut buffer = vec![0; estimate];
loop {
let result = f(&mut buffer)?;
if result <= buffer.len() {
buffer.truncate(result);
break;
}
buffer.resize(result, 0);
}
Ok(buffer)
}
#[repr(C)]
pub struct ArgsSysCall {
ptr: *mut u8,
len: usize,
result: usize
}
impl ArgsSysCall {
pub fn perform() -> Vec<OsString> {
receive_buffer(1024, |buffer| -> Result<usize, !> {
let mut call_record = ArgsSysCall {
len: buffer.len(),
ptr: buffer.as_mut_ptr(),
result: 0
};
if unsafe { syscall(SysCallIndex::Args, &mut call_record) } {
Ok(call_record.result)
} else {
Ok(0)
}
})
.unwrap()
.split(|b| *b == 0)
.map(|s| FromInner::from_inner(Buf { inner: s.to_owned() }))
.collect()
}
}
#[repr(C)]
pub struct GetEnvSysCall {
key_ptr: *const u8,
key_len: usize,
value_ptr: *mut u8,
value_len: usize,
result: usize
}
impl GetEnvSysCall {
pub fn perform(key: &OsStr) -> Option<OsString> {
let key_buf = &AsInner::as_inner(key).inner;
receive_buffer(64, |buffer| {
let mut call_record = GetEnvSysCall {
key_len: key_buf.len(),
key_ptr: key_buf.as_ptr(),
value_len: buffer.len(),
value_ptr: buffer.as_mut_ptr(),
result: !0usize
};
if unsafe { syscall(SysCallIndex::GetEnv, &mut call_record) } {
if call_record.result == !0usize {
Err(())
} else {
Ok(call_record.result)
}
} else {
Err(())
}
}).ok().map(|s| {
FromInner::from_inner(Buf { inner: s })
})
}
}
#[repr(C)]
pub struct SetEnvSysCall {
key_ptr: *const u8,
key_len: usize,
value_ptr: *const u8,
value_len: usize
}
impl SetEnvSysCall {
pub fn perform(key: &OsStr, value: Option<&OsStr>) {
let key_buf = &AsInner::as_inner(key).inner;
let value_buf = value.map(|v| &AsInner::as_inner(v).inner);
let mut call_record = SetEnvSysCall {
key_len: key_buf.len(),
key_ptr: key_buf.as_ptr(),
value_len: value_buf.map(|v| v.len()).unwrap_or(!0usize),
value_ptr: value_buf.map(|v| v.as_ptr()).unwrap_or(ptr::null())
};
unsafe { syscall(SysCallIndex::SetEnv, &mut call_record); }
}
}
pub enum TimeClock {
Monotonic = 0,
System = 1,
}
#[repr(C)]
pub struct TimeSysCall {
clock: usize,
secs_hi: usize,
secs_lo: usize,
nanos: usize
}
impl TimeSysCall {
pub fn perform(clock: TimeClock) -> Duration {
let mut call_record = TimeSysCall {
clock: clock as usize,
secs_hi: 0,
secs_lo: 0,
nanos: 0
};
if unsafe { syscall(SysCallIndex::Time, &mut call_record) } {
Duration::new(
((call_record.secs_hi as u64) << 32) | (call_record.secs_lo as u64),
call_record.nanos as u32
)
} else {
panic!("Time system call is not implemented by WebAssembly host");
}
}
}
unsafe fn syscall<T>(index: SysCallIndex, data: &mut T) -> bool {
#[cfg(feature = "wasm_syscall")]
extern {
#[no_mangle]
fn rust_wasm_syscall(index: usize, data: *mut Void) -> usize;
}
#[cfg(not(feature = "wasm_syscall"))]
unsafe fn rust_wasm_syscall(_index: usize, _data: *mut Void) -> usize { 0 }
rust_wasm_syscall(index as usize, data as *mut T as *mut Void) != 0
}

View File

@ -4,7 +4,7 @@ use crate::fmt;
use crate::io;
use crate::path::{self, PathBuf};
use crate::str;
use crate::sys::{unsupported, Void, ExitSysCall, GetEnvSysCall, SetEnvSysCall};
use crate::sys::{unsupported, Void};
pub fn errno() -> i32 {
0
@ -73,16 +73,16 @@ pub fn env() -> Env {
panic!("not supported on web assembly")
}
pub fn getenv(k: &OsStr) -> io::Result<Option<OsString>> {
Ok(GetEnvSysCall::perform(k))
pub fn getenv(_: &OsStr) -> io::Result<Option<OsString>> {
Ok(None)
}
pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> {
Ok(SetEnvSysCall::perform(k, Some(v)))
pub fn setenv(_: &OsStr, _: &OsStr) -> io::Result<()> {
Err(io::Error::new(io::ErrorKind::Other, "cannot set env vars on wasm32-unknown-unknown"))
}
pub fn unsetenv(k: &OsStr) -> io::Result<()> {
Ok(SetEnvSysCall::perform(k, None))
pub fn unsetenv(_: &OsStr) -> io::Result<()> {
Err(io::Error::new(io::ErrorKind::Other, "cannot unset env vars on wasm32-unknown-unknown"))
}
pub fn temp_dir() -> PathBuf {
@ -94,7 +94,9 @@ pub fn home_dir() -> Option<PathBuf> {
}
pub fn exit(_code: i32) -> ! {
ExitSysCall::perform(_code as isize as usize)
unsafe {
crate::arch::wasm32::unreachable();
}
}
pub fn getpid() -> u32 {

View File

@ -1,5 +1,4 @@
use crate::io;
use crate::sys::{ReadSysCall, WriteSysCall};
pub struct Stdin;
pub struct Stdout;
@ -12,8 +11,8 @@ impl Stdin {
}
impl io::Read for Stdin {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
Ok(ReadSysCall::perform(0, buf))
fn read(&mut self, _buf: &mut [u8]) -> io::Result<usize> {
Ok(0)
}
}
@ -25,7 +24,6 @@ impl Stdout {
impl io::Write for Stdout {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
WriteSysCall::perform(1, buf);
Ok(buf.len())
}
@ -42,7 +40,6 @@ impl Stderr {
impl io::Write for Stderr {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
WriteSysCall::perform(2, buf);
Ok(buf.len())
}
@ -57,10 +54,6 @@ pub fn is_ebadf(_err: &io::Error) -> bool {
true
}
pub fn panic_output() -> Option<impl io::Write> {
if cfg!(feature = "wasm_syscall") {
Stderr::new().ok()
} else {
None
}
pub fn panic_output() -> Option<Vec<u8>> {
None
}

View File

@ -1,5 +1,4 @@
use crate::time::Duration;
use crate::sys::{TimeSysCall, TimeClock};
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
pub struct Instant(Duration);
@ -11,7 +10,7 @@ pub const UNIX_EPOCH: SystemTime = SystemTime(Duration::from_secs(0));
impl Instant {
pub fn now() -> Instant {
Instant(TimeSysCall::perform(TimeClock::Monotonic))
panic!("time not implemented on wasm32-unknown-unknown")
}
pub const fn zero() -> Instant {
@ -37,7 +36,7 @@ impl Instant {
impl SystemTime {
pub fn now() -> SystemTime {
SystemTime(TimeSysCall::perform(TimeClock::System))
panic!("time not implemented on wasm32-unknown-unknown")
}
pub fn sub_time(&self, other: &SystemTime)