Auto merge of #64000 - Centril:rollup-70s9ar3, r=Centril
Rollup of 4 pull requests Successful merges: - #62734 (Hide trait default methods) - #63953 (bootstrap: allow specifying mirror for bootstrap compiler download.) - #63956 (rustc: Handle modules in "fat" LTO more robustly) - #63979 (std: Remove the `wasm_syscall` feature) Failed merges: r? @ghost
This commit is contained in:
commit
fbdf1d2a71
23 changed files with 116 additions and 451 deletions
|
@ -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
|
||||
|
|
|
@ -320,7 +320,7 @@ class RustBuild(object):
|
|||
def __init__(self):
|
||||
self.cargo_channel = ''
|
||||
self.date = ''
|
||||
self._download_url = 'https://static.rust-lang.org'
|
||||
self._download_url = ''
|
||||
self.rustc_channel = ''
|
||||
self.build = ''
|
||||
self.build_dir = os.path.join(os.getcwd(), "build")
|
||||
|
@ -733,9 +733,19 @@ class RustBuild(object):
|
|||
self.update_submodule(module[0], module[1], recorded_submodules)
|
||||
print("Submodules updated in %.2f seconds" % (time() - start_time))
|
||||
|
||||
def set_normal_environment(self):
|
||||
"""Set download URL for normal environment"""
|
||||
if 'RUSTUP_DIST_SERVER' in os.environ:
|
||||
self._download_url = os.environ['RUSTUP_DIST_SERVER']
|
||||
else:
|
||||
self._download_url = 'https://static.rust-lang.org'
|
||||
|
||||
def set_dev_environment(self):
|
||||
"""Set download URL for development environment"""
|
||||
self._download_url = 'https://dev-static.rust-lang.org'
|
||||
if 'RUSTUP_DEV_DIST_SERVER' in os.environ:
|
||||
self._download_url = os.environ['RUSTUP_DEV_DIST_SERVER']
|
||||
else:
|
||||
self._download_url = 'https://dev-static.rust-lang.org'
|
||||
|
||||
def check_vendored_status(self):
|
||||
"""Check that vendoring is configured properly"""
|
||||
|
@ -828,6 +838,8 @@ def bootstrap(help_triggered):
|
|||
|
||||
if 'dev' in data:
|
||||
build.set_dev_environment()
|
||||
else:
|
||||
build.set_normal_environment()
|
||||
|
||||
build.update_submodules()
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -495,9 +495,6 @@ impl Build {
|
|||
if self.config.profiler {
|
||||
features.push_str(" profiler");
|
||||
}
|
||||
if self.config.wasm_syscall {
|
||||
features.push_str(" wasm_syscall");
|
||||
}
|
||||
features
|
||||
}
|
||||
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -183,7 +183,7 @@ pub(crate) fn prepare_thin(
|
|||
|
||||
fn fat_lto(cgcx: &CodegenContext<LlvmCodegenBackend>,
|
||||
diag_handler: &Handler,
|
||||
mut modules: Vec<FatLTOInput<LlvmCodegenBackend>>,
|
||||
modules: Vec<FatLTOInput<LlvmCodegenBackend>>,
|
||||
cached_modules: Vec<(SerializedModule<ModuleBuffer>, WorkProduct)>,
|
||||
mut serialized_modules: Vec<(SerializedModule<ModuleBuffer>, CString)>,
|
||||
symbol_white_list: &[*const libc::c_char])
|
||||
|
@ -191,6 +191,32 @@ fn fat_lto(cgcx: &CodegenContext<LlvmCodegenBackend>,
|
|||
{
|
||||
info!("going for a fat lto");
|
||||
|
||||
// Sort out all our lists of incoming modules into two lists.
|
||||
//
|
||||
// * `serialized_modules` (also and argument to this function) contains all
|
||||
// modules that are serialized in-memory.
|
||||
// * `in_memory` contains modules which are already parsed and in-memory,
|
||||
// such as from multi-CGU builds.
|
||||
//
|
||||
// All of `cached_modules` (cached from previous incremental builds) can
|
||||
// immediately go onto the `serialized_modules` modules list and then we can
|
||||
// split the `modules` array into these two lists.
|
||||
let mut in_memory = Vec::new();
|
||||
serialized_modules.extend(cached_modules.into_iter().map(|(buffer, wp)| {
|
||||
info!("pushing cached module {:?}", wp.cgu_name);
|
||||
(buffer, CString::new(wp.cgu_name).unwrap())
|
||||
}));
|
||||
for module in modules {
|
||||
match module {
|
||||
FatLTOInput::InMemory(m) => in_memory.push(m),
|
||||
FatLTOInput::Serialized { name, buffer } => {
|
||||
info!("pushing serialized module {:?}", name);
|
||||
let buffer = SerializedModule::Local(buffer);
|
||||
serialized_modules.push((buffer, CString::new(name).unwrap()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Find the "costliest" module and merge everything into that codegen unit.
|
||||
// All the other modules will be serialized and reparsed into the new
|
||||
// context, so this hopefully avoids serializing and parsing the largest
|
||||
|
@ -200,14 +226,8 @@ fn fat_lto(cgcx: &CodegenContext<LlvmCodegenBackend>,
|
|||
// file copy operations in the backend work correctly. The only other kind
|
||||
// of module here should be an allocator one, and if your crate is smaller
|
||||
// than the allocator module then the size doesn't really matter anyway.
|
||||
let costliest_module = modules.iter()
|
||||
let costliest_module = in_memory.iter()
|
||||
.enumerate()
|
||||
.filter_map(|(i, module)| {
|
||||
match module {
|
||||
FatLTOInput::InMemory(m) => Some((i, m)),
|
||||
FatLTOInput::Serialized { .. } => None,
|
||||
}
|
||||
})
|
||||
.filter(|&(_, module)| module.kind == ModuleKind::Regular)
|
||||
.map(|(i, module)| {
|
||||
let cost = unsafe {
|
||||
|
@ -223,26 +243,14 @@ fn fat_lto(cgcx: &CodegenContext<LlvmCodegenBackend>,
|
|||
// re-executing the LTO passes. If that's the case deserialize the first
|
||||
// module and create a linker with it.
|
||||
let module: ModuleCodegen<ModuleLlvm> = match costliest_module {
|
||||
Some((_cost, i)) => {
|
||||
match modules.remove(i) {
|
||||
FatLTOInput::InMemory(m) => m,
|
||||
FatLTOInput::Serialized { .. } => unreachable!(),
|
||||
}
|
||||
}
|
||||
Some((_cost, i)) => in_memory.remove(i),
|
||||
None => {
|
||||
let pos = modules.iter().position(|m| {
|
||||
match m {
|
||||
FatLTOInput::InMemory(_) => false,
|
||||
FatLTOInput::Serialized { .. } => true,
|
||||
}
|
||||
}).expect("must have at least one serialized module");
|
||||
let (name, buffer) = match modules.remove(pos) {
|
||||
FatLTOInput::Serialized { name, buffer } => (name, buffer),
|
||||
FatLTOInput::InMemory(_) => unreachable!(),
|
||||
};
|
||||
assert!(serialized_modules.len() > 0, "must have at least one serialized module");
|
||||
let (buffer, name) = serialized_modules.remove(0);
|
||||
info!("no in-memory regular modules to choose from, parsing {:?}", name);
|
||||
ModuleCodegen {
|
||||
module_llvm: ModuleLlvm::parse(cgcx, &name, &buffer, diag_handler)?,
|
||||
name,
|
||||
module_llvm: ModuleLlvm::parse(cgcx, &name, buffer.data(), diag_handler)?,
|
||||
name: name.into_string().unwrap(),
|
||||
kind: ModuleKind::Regular,
|
||||
}
|
||||
}
|
||||
|
@ -265,25 +273,13 @@ fn fat_lto(cgcx: &CodegenContext<LlvmCodegenBackend>,
|
|||
// and we want to move everything to the same LLVM context. Currently the
|
||||
// way we know of to do that is to serialize them to a string and them parse
|
||||
// them later. Not great but hey, that's why it's "fat" LTO, right?
|
||||
let mut new_modules = modules.into_iter().map(|module| {
|
||||
match module {
|
||||
FatLTOInput::InMemory(module) => {
|
||||
let buffer = ModuleBuffer::new(module.module_llvm.llmod());
|
||||
let llmod_id = CString::new(&module.name[..]).unwrap();
|
||||
(SerializedModule::Local(buffer), llmod_id)
|
||||
}
|
||||
FatLTOInput::Serialized { name, buffer } => {
|
||||
let llmod_id = CString::new(name).unwrap();
|
||||
(SerializedModule::Local(buffer), llmod_id)
|
||||
}
|
||||
}
|
||||
}).collect::<Vec<_>>();
|
||||
for module in in_memory {
|
||||
let buffer = ModuleBuffer::new(module.module_llvm.llmod());
|
||||
let llmod_id = CString::new(&module.name[..]).unwrap();
|
||||
serialized_modules.push((SerializedModule::Local(buffer), llmod_id));
|
||||
}
|
||||
// Sort the modules to ensure we produce deterministic results.
|
||||
new_modules.sort_by(|module1, module2| module1.1.partial_cmp(&module2.1).unwrap());
|
||||
serialized_modules.extend(new_modules);
|
||||
serialized_modules.extend(cached_modules.into_iter().map(|(buffer, wp)| {
|
||||
(buffer, CString::new(wp.cgu_name).unwrap())
|
||||
}));
|
||||
serialized_modules.sort_by(|module1, module2| module1.1.cmp(&module2.1));
|
||||
|
||||
// For all serialized bitcode files we parse them and link them in as we did
|
||||
// above, this is all mostly handled in C++. Like above, though, we don't
|
||||
|
@ -850,7 +846,7 @@ fn module_name_to_str(c_str: &CStr) -> &str {
|
|||
bug!("Encountered non-utf8 LLVM module name `{}`: {}", c_str.to_string_lossy(), e))
|
||||
}
|
||||
|
||||
fn parse_module<'a>(
|
||||
pub fn parse_module<'a>(
|
||||
cx: &'a llvm::Context,
|
||||
name: &CStr,
|
||||
data: &[u8],
|
||||
|
|
|
@ -54,6 +54,7 @@ use syntax_pos::symbol::InternedString;
|
|||
pub use llvm_util::target_features;
|
||||
use std::any::Any;
|
||||
use std::sync::{mpsc, Arc};
|
||||
use std::ffi::CStr;
|
||||
|
||||
use rustc::dep_graph::DepGraph;
|
||||
use rustc::middle::cstore::{EncodedMetadata, MetadataLoader};
|
||||
|
@ -386,13 +387,13 @@ impl ModuleLlvm {
|
|||
|
||||
fn parse(
|
||||
cgcx: &CodegenContext<LlvmCodegenBackend>,
|
||||
name: &str,
|
||||
buffer: &back::lto::ModuleBuffer,
|
||||
name: &CStr,
|
||||
buffer: &[u8],
|
||||
handler: &Handler,
|
||||
) -> Result<Self, FatalError> {
|
||||
unsafe {
|
||||
let llcx = llvm::LLVMRustContextCreate(cgcx.fewer_names);
|
||||
let llmod_raw = buffer.parse(name, llcx, handler)?;
|
||||
let llmod_raw = back::lto::parse_module(llcx, name, buffer, handler)?;
|
||||
let tm = match (cgcx.tm_factory.0)() {
|
||||
Ok(m) => m,
|
||||
Err(e) => {
|
||||
|
|
|
@ -2405,13 +2405,14 @@ fn document(w: &mut fmt::Formatter<'_>, cx: &Context, item: &clean::Item) -> fmt
|
|||
}
|
||||
|
||||
/// Render md_text as markdown.
|
||||
fn render_markdown(w: &mut fmt::Formatter<'_>,
|
||||
cx: &Context,
|
||||
md_text: &str,
|
||||
links: Vec<(String, String)>,
|
||||
prefix: &str,
|
||||
is_hidden: bool)
|
||||
-> fmt::Result {
|
||||
fn render_markdown(
|
||||
w: &mut fmt::Formatter<'_>,
|
||||
cx: &Context,
|
||||
md_text: &str,
|
||||
links: Vec<(String, String)>,
|
||||
prefix: &str,
|
||||
is_hidden: bool,
|
||||
) -> fmt::Result {
|
||||
let mut ids = cx.id_map.borrow_mut();
|
||||
write!(w, "<div class='docblock{}'>{}{}</div>",
|
||||
if is_hidden { " hidden" } else { "" },
|
||||
|
@ -2425,7 +2426,8 @@ fn document_short(
|
|||
cx: &Context,
|
||||
item: &clean::Item,
|
||||
link: AssocItemLink<'_>,
|
||||
prefix: &str, is_hidden: bool
|
||||
prefix: &str,
|
||||
is_hidden: bool,
|
||||
) -> fmt::Result {
|
||||
if let Some(s) = item.doc_value() {
|
||||
let markdown = if s.contains('\n') {
|
||||
|
@ -4084,9 +4086,10 @@ fn render_impl(w: &mut fmt::Formatter<'_>, cx: &Context, i: &Impl, link: AssocIt
|
|||
RenderMode::ForDeref { mut_: deref_mut_ } => should_render_item(&item, deref_mut_),
|
||||
};
|
||||
|
||||
let (is_hidden, extra_class) = if trait_.is_none() ||
|
||||
item.doc_value().is_some() ||
|
||||
item.inner.is_associated() {
|
||||
let (is_hidden, extra_class) = if (trait_.is_none() ||
|
||||
item.doc_value().is_some() ||
|
||||
item.inner.is_associated()) &&
|
||||
!is_default_item {
|
||||
(false, "")
|
||||
} else {
|
||||
(true, " hidden")
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
// Local js definitions:
|
||||
/* global addClass, getCurrentValue, hasClass */
|
||||
/* global isHidden onEach, removeClass, updateLocalStorage */
|
||||
/* global isHidden, onEach, removeClass, updateLocalStorage */
|
||||
|
||||
if (!String.prototype.startsWith) {
|
||||
String.prototype.startsWith = function(searchString, position) {
|
||||
|
|
|
@ -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 = []
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
12
src/test/run-make-fulldeps/lto-empty/Makefile
Normal file
12
src/test/run-make-fulldeps/lto-empty/Makefile
Normal file
|
@ -0,0 +1,12 @@
|
|||
-include ../tools.mk
|
||||
|
||||
all: cdylib-fat cdylib-thin
|
||||
|
||||
cdylib-fat:
|
||||
$(RUSTC) lib.rs -C lto=fat -C opt-level=3 -C incremental=$(TMPDIR)/inc-fat
|
||||
$(RUSTC) lib.rs -C lto=fat -C opt-level=3 -C incremental=$(TMPDIR)/inc-fat
|
||||
|
||||
cdylib-thin:
|
||||
$(RUSTC) lib.rs -C lto=thin -C opt-level=3 -C incremental=$(TMPDIR)/inc-thin
|
||||
$(RUSTC) lib.rs -C lto=thin -C opt-level=3 -C incremental=$(TMPDIR)/inc-thin
|
||||
|
1
src/test/run-make-fulldeps/lto-empty/lib.rs
Normal file
1
src/test/run-make-fulldeps/lto-empty/lib.rs
Normal file
|
@ -0,0 +1 @@
|
|||
#![crate_type = "cdylib"]
|
|
@ -95,5 +95,5 @@ impl Qux for Bar {
|
|||
/// Docs for QUX_DEFAULT1 in impl.
|
||||
const QUX_DEFAULT1: i16 = 7;
|
||||
// @has - '//*[@id="associatedconstant.QUX_DEFAULT2"]' 'const QUX_DEFAULT2: u32'
|
||||
// @has - '//*[@class="docblock"]' "Docs for QUX_DEFAULT2 in trait."
|
||||
// @has - '//*[@class="docblock hidden"]' "Docs for QUX_DEFAULT2 in trait."
|
||||
}
|
||||
|
|
|
@ -16,15 +16,15 @@ extern crate assoc_items;
|
|||
// @has - '//*[@id="associatedconstant.ConstNoDefault"]' 'const ConstNoDefault: i16'
|
||||
// @has - '//*[@class="docblock"]' 'dox for ConstNoDefault'
|
||||
// @has - '//*[@id="associatedconstant.ConstWithDefault"]' 'const ConstWithDefault: u16'
|
||||
// @has - '//*[@class="docblock"]' 'docs for ConstWithDefault'
|
||||
// @has - '//*[@class="docblock hidden"]' 'docs for ConstWithDefault'
|
||||
// @has - '//*[@id="associatedtype.TypeNoDefault"]' 'type TypeNoDefault = i32'
|
||||
// @has - '//*[@class="docblock"]' 'dox for TypeNoDefault'
|
||||
// @has - '//*[@id="associatedtype.TypeWithDefault"]' 'type TypeWithDefault = u32'
|
||||
// @has - '//*[@class="docblock"]' 'docs for TypeWithDefault'
|
||||
// @has - '//*[@class="docblock hidden"]' 'docs for TypeWithDefault'
|
||||
// @has - '//*[@id="method.method_no_default"]' 'fn method_no_default()'
|
||||
// @has - '//*[@class="docblock"]' 'dox for method_no_default'
|
||||
// @has - '//*[@id="method.method_with_default"]' 'fn method_with_default()'
|
||||
// @has - '//*[@class="docblock"]' 'docs for method_with_default'
|
||||
// @has - '//*[@class="docblock hidden"]' 'docs for method_with_default'
|
||||
pub use assoc_items::MyStruct;
|
||||
|
||||
// @has foo/trait.MyTrait.html
|
||||
|
|
|
@ -8,5 +8,5 @@ extern crate impl_inline_without_trait;
|
|||
|
||||
// @has 'foo/struct.MyStruct.html'
|
||||
// @has - '//*[@id="method.my_trait_method"]' 'fn my_trait_method()'
|
||||
// @has - '//*[@class="docblock"]' 'docs for my_trait_method'
|
||||
// @has - '//*[@class="docblock hidden"]' 'docs for my_trait_method'
|
||||
pub use impl_inline_without_trait::MyStruct;
|
||||
|
|
|
@ -24,10 +24,10 @@ pub trait T {
|
|||
// @has - '//*[@class="docblock"]' 'Docs associated with the S1 trait implementation.'
|
||||
// @has - '//*[@class="docblock"]' 'Docs associated with the S1 trait a_method implementation.'
|
||||
// @!has - '//*[@class="docblock"]' 'Docs associated with the trait a_method definition.'
|
||||
// @has - '//*[@class="docblock"]' 'Docs associated with the trait b_method definition.'
|
||||
// @has - '//*[@class="docblock"]' 'Docs associated with the trait c_method definition.'
|
||||
// @has - '//*[@class="docblock hidden"]' 'Docs associated with the trait b_method definition.'
|
||||
// @has - '//*[@class="docblock hidden"]' 'Docs associated with the trait c_method definition.'
|
||||
// @!has - '//*[@class="docblock"]' 'There is another line'
|
||||
// @has - '//*[@class="docblock"]' 'Read more'
|
||||
// @has - '//*[@class="docblock hidden"]' 'Read more'
|
||||
pub struct S1(usize);
|
||||
|
||||
/// Docs associated with the S1 trait implementation.
|
||||
|
@ -44,7 +44,7 @@ impl T for S1 {
|
|||
// @has - '//*[@class="docblock"]' 'Docs associated with the S2 trait c_method implementation.'
|
||||
// @!has - '//*[@class="docblock"]' 'Docs associated with the trait a_method definition.'
|
||||
// @!has - '//*[@class="docblock"]' 'Docs associated with the trait c_method definition.'
|
||||
// @has - '//*[@class="docblock"]' 'Docs associated with the trait b_method definition.'
|
||||
// @has - '//*[@class="docblock hidden"]' 'Docs associated with the trait b_method definition.'
|
||||
pub struct S2(usize);
|
||||
|
||||
/// Docs associated with the S2 trait implementation.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
warning: Linking globals named 'foo': symbol multiply defined!
|
||||
|
||||
error: failed to load bc of "lto_duplicate_symbols1.3a1fbbbh-cgu.0":
|
||||
error: failed to load bc of "lto_duplicate_symbols2.3a1fbbbh-cgu.0":
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue