1 // Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 //! System bindings for the wasm/web platform
13 //! This module contains the facade (aka platform-specific) implementations of
14 //! OS level functionality for wasm. Note that this wasm is *not* the emscripten
15 //! wasm, so we have no runtime here.
17 //! This is all super highly experimental and not actually intended for
18 //! wide/production use yet, it's still all in the experimental category. This
19 //! will likely change over time.
21 //! Currently all functions here are basically stubs that immediately return
22 //! errors. The hope is that with a portability lint we can turn actually just
23 //! remove all this and just omit parts of the standard library if we're
24 //! compiling for wasm. That way it's a compile time error for something that's
25 //! guaranteed to be a runtime error!
31 use sys_common::{AsInner, FromInner};
32 use ffi::{OsString, OsStr};
36 #[cfg(feature = "backtrace")]
51 pub mod stack_overflow;
61 pub fn unsupported<T>() -> io::Result<T> {
62 Err(unsupported_err())
65 pub fn unsupported_err() -> io::Error {
66 io::Error::new(io::ErrorKind::Other,
67 "operation not supported on wasm yet")
70 pub fn decode_error_kind(_code: i32) -> io::ErrorKind {
74 // This enum is used as the storage for a bunch of types which can't actually
76 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
79 pub unsafe fn strlen(mut s: *const c_char) -> usize {
88 pub unsafe fn abort_internal() -> ! {
89 ExitSysCall::perform(1)
92 // We don't have randomness yet, but I totally used a random number generator to
93 // generate these numbers.
95 // More seriously though this is just for DOS protection in hash maps. It's ok
96 // if we don't do that on wasm just yet.
97 pub fn hashmap_random_keys() -> (u64, u64) {
101 // Implement a minimal set of system calls to enable basic IO
102 pub enum SysCallIndex {
113 pub struct ReadSysCall {
121 pub fn perform(fd: usize, buffer: &mut [u8]) -> usize {
122 let mut call_record = ReadSysCall {
125 ptr: buffer.as_mut_ptr(),
128 if unsafe { syscall(SysCallIndex::Read, &mut call_record) } {
137 pub struct WriteSysCall {
144 pub fn perform(fd: usize, buffer: &[u8]) {
145 let mut call_record = WriteSysCall {
150 unsafe { syscall(SysCallIndex::Write, &mut call_record); }
155 pub struct ExitSysCall {
160 pub fn perform(code: usize) -> ! {
161 let mut call_record = ExitSysCall {
165 syscall(SysCallIndex::Exit, &mut call_record);
166 ::intrinsics::abort();
171 fn receive_buffer<E, F: FnMut(&mut [u8]) -> Result<usize, E>>(estimate: usize, mut f: F)
172 -> Result<Vec<u8>, E>
174 let mut buffer = vec![0; estimate];
176 let result = f(&mut buffer)?;
177 if result <= buffer.len() {
178 buffer.truncate(result);
181 buffer.resize(result, 0);
187 pub struct ArgsSysCall {
194 pub fn perform() -> Vec<OsString> {
195 receive_buffer(1024, |buffer| -> Result<usize, !> {
196 let mut call_record = ArgsSysCall {
198 ptr: buffer.as_mut_ptr(),
201 if unsafe { syscall(SysCallIndex::Args, &mut call_record) } {
202 Ok(call_record.result)
209 .map(|s| FromInner::from_inner(Buf { inner: s.to_owned() }))
215 pub struct GetEnvSysCall {
224 pub fn perform(key: &OsStr) -> Option<OsString> {
225 let key_buf = &AsInner::as_inner(key).inner;
226 receive_buffer(64, |buffer| {
227 let mut call_record = GetEnvSysCall {
228 key_len: key_buf.len(),
229 key_ptr: key_buf.as_ptr(),
230 value_len: buffer.len(),
231 value_ptr: buffer.as_mut_ptr(),
234 if unsafe { syscall(SysCallIndex::GetEnv, &mut call_record) } {
235 if call_record.result == !0usize {
238 Ok(call_record.result)
244 FromInner::from_inner(Buf { inner: s })
250 pub struct SetEnvSysCall {
253 value_ptr: *const u8,
258 pub fn perform(key: &OsStr, value: Option<&OsStr>) {
259 let key_buf = &AsInner::as_inner(key).inner;
260 let value_buf = value.map(|v| &AsInner::as_inner(v).inner);
261 let mut call_record = SetEnvSysCall {
262 key_len: key_buf.len(),
263 key_ptr: key_buf.as_ptr(),
264 value_len: value_buf.map(|v| v.len()).unwrap_or(!0usize),
265 value_ptr: value_buf.map(|v| v.as_ptr()).unwrap_or(ptr::null())
267 unsafe { syscall(SysCallIndex::SetEnv, &mut call_record); }
277 pub struct TimeSysCall {
285 pub fn perform(clock: TimeClock) -> Duration {
286 let mut call_record = TimeSysCall {
287 clock: clock as usize,
292 if unsafe { syscall(SysCallIndex::Time, &mut call_record) } {
294 ((call_record.secs_hi as u64) << 32) | (call_record.secs_lo as u64),
295 call_record.nanos as u32
298 panic!("Time system call is not implemented by WebAssembly host");
303 unsafe fn syscall<T>(index: SysCallIndex, data: &mut T) -> bool {
304 #[cfg(feature = "wasm_syscall")]
307 fn rust_wasm_syscall(index: usize, data: *mut Void) -> usize;
310 #[cfg(not(feature = "wasm_syscall"))]
311 unsafe fn rust_wasm_syscall(_index: usize, _data: *mut Void) -> usize { 0 }
313 rust_wasm_syscall(index as usize, data as *mut T as *mut Void) != 0