提交 8b003551 编写于 作者: B bors 提交者: GitHub

Auto merge of #36339 - brson:emscripten-new, r=alexcrichton

Working asmjs and wasm targets

This patch set results in a working standard library for the asmjs-unknown-emscripten and wasm32-unknown-emscripten targets. It is based on the work of @badboy and @rschulman.

It does a few things:

- Updates LLVM with the emscripten [fastcomp](https://github.com/rust-lang/llvm/pull/50) patches, which include the pnacl IR legalizer and the asm.js backend. This patch is thought not to have any significant effect on existing targets.
- Teaches rustbuild to correctly link C code with emscripten
- Updates gcc-rs to work correctly with emscripten
- Teaches rustbuild to run crate tests for emscripten with node
- Modifies Thread::new to return an error on emscripten, to facilitate debugging a common failure mode
- Modifies libtest to run in single-threaded mode for emscripten
- Ignores a host of tests that don't work yet, mostly dealing with threads and I/O
- Updates libc with wasm32 definitions (presently the same as asmjs)
- Adds a wasm32-unknown-emscripten target that feeds the output of LLVM's asmjs backend through emcc to generate wasm

Notes and caveats:

- This is only known to work with `--enable-rustbuild`.
- The wasm32 target can't be tested correctly yet because of issues in compiletest and limitations in node https://github.com/kripken/emscripten/issues/4542, but hello.rs does seem to work when run on node via the binaryen interpreter
- This requires an up to date installation of the emscripten sdk from its incoming branch
- Unwinding is very broken
- When enabling the emscripten targets jemalloc is disabled for all targets, which results in test failures for the host

Next steps are to fix the jemalloc issue, start building the two emscripten targets on the auto builders, then start producing nightlies.

https://github.com/rust-lang/rust/issues/36317 tracks work on this.

Fixes https://github.com/rust-lang/rust/issues/36515
Fixes https://github.com/rust-lang/rust/issues/36515
Fixes https://github.com/rust-lang/rust/issues/36356
# wasm32-unknown-emscripten configuration
CC_wasm32-unknown-emscripten=emcc
CXX_wasm32-unknown-emscripten=em++
CPP_wasm32-unknown-emscripten=$(CPP)
AR_wasm32-unknown-emscripten=emar
CFG_LIB_NAME_wasm32-unknown-emscripten=lib$(1).so
CFG_STATIC_LIB_NAME_wasm32-unknown-emscripten=lib$(1).a
CFG_LIB_GLOB_wasm32-unknown-emscripten=lib$(1)-*.so
CFG_LIB_DSYM_GLOB_wasm32-unknown-emscripten=lib$(1)-*.dylib.dSYM
CFG_JEMALLOC_CFLAGS_wasm32-unknown-emscripten := -m32 $(CFLAGS)
CFG_GCCISH_CFLAGS_wasm32-unknown-emscripten := -g -fPIC -m32 -s BINARYEN=1 $(CFLAGS)
CFG_GCCISH_CXXFLAGS_wasm32-unknown-emscripten := -fno-rtti -s BINARYEN=1 $(CXXFLAGS)
CFG_GCCISH_LINK_FLAGS_wasm32-unknown-emscripten := -shared -fPIC -ldl -pthread -lrt -g -m32 -s BINARYEN=1
CFG_GCCISH_DEF_FLAG_wasm32-unknown-emscripten := -Wl,--export-dynamic,--dynamic-list=
CFG_LLC_FLAGS_wasm32-unknown-emscripten :=
CFG_INSTALL_NAME_wasm32-unknown-emscripten =
CFG_EXE_SUFFIX_wasm32-unknown-emscripten =
CFG_WINDOWSY_wasm32-unknown-emscripten :=
CFG_UNIXY_wasm32-unknown-emscripten := 1
CFG_LDPATH_wasm32-unknown-emscripten :=
CFG_RUN_wasm32-unknown-emscripten=$(2)
CFG_RUN_TARG_wasm32-unknown-emscripten=$(call CFG_RUN_wasm32-unknown-emscripten,,$(2))
CFG_GNU_TRIPLE_wasm32-unknown-emscripten := wasm32-unknown-emscripten
CFG_DISABLE_JEMALLOC_wasm32-unknown-emscripten := 1
......@@ -300,7 +300,7 @@ endif
# LLVM macros
######################################################################
LLVM_OPTIONAL_COMPONENTS=x86 arm aarch64 mips powerpc pnacl systemz
LLVM_OPTIONAL_COMPONENTS=x86 arm aarch64 mips powerpc pnacl systemz jsbackend
LLVM_REQUIRED_COMPONENTS=ipo bitreader bitwriter linker asmparser mcjit \
interpreter instrumentation
......
......@@ -5,16 +5,16 @@ dependencies = [
"build_helper 0.1.0",
"cmake 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
"filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"gcc 0.3.31 (git+https://github.com/alexcrichton/gcc-rs)",
"gcc 0.3.35 (git+https://github.com/alexcrichton/gcc-rs)",
"getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
"md5 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.1.73 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
"toml 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"toml 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
......@@ -34,7 +34,7 @@ name = "cmake"
version = "0.1.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"gcc 0.3.31 (registry+https://github.com/rust-lang/crates.io-index)",
"gcc 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
......@@ -42,17 +42,17 @@ name = "filetime"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "gcc"
version = "0.3.31"
source = "git+https://github.com/alexcrichton/gcc-rs#b8e2400883f1a2749b323354dad372cdd1c838c7"
version = "0.3.35"
source = "git+https://github.com/alexcrichton/gcc-rs#8ff5360b6e0dc4f3c9d3f71036f1ff403c68469d"
[[package]]
name = "gcc"
version = "0.3.31"
version = "0.3.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
......@@ -65,13 +65,13 @@ name = "kernel32-sys"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "libc"
version = "0.2.10"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
......@@ -84,15 +84,15 @@ name = "memchr"
version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num_cpus"
version = "0.2.11"
version = "0.2.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
......@@ -123,7 +123,7 @@ version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
......@@ -136,7 +136,7 @@ dependencies = [
[[package]]
name = "toml"
version = "0.1.28"
version = "0.1.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
......@@ -149,7 +149,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi"
version = "0.2.6"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
......@@ -161,20 +161,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum aho-corasick 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2b3fb52b09c1710b961acb35390d514be82e4ac96a9969a8e38565a29b878dc9"
"checksum cmake 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "dfcf5bcece56ef953b8ea042509e9dcbdfe97820b7e20d86beb53df30ed94978"
"checksum filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "5363ab8e4139b8568a6237db5248646e5a8a2f89bd5ccb02092182b11fd3e922"
"checksum gcc 0.3.31 (git+https://github.com/alexcrichton/gcc-rs)" = "<none>"
"checksum gcc 0.3.31 (registry+https://github.com/rust-lang/crates.io-index)" = "cfe877476e53690ebb0ce7325d0bf43e198d9500291b54b3c65e518de5039b07"
"checksum gcc 0.3.35 (git+https://github.com/alexcrichton/gcc-rs)" = "<none>"
"checksum gcc 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)" = "91ecd03771effb0c968fd6950b37e89476a578aaf1c70297d8e92b6516ec3312"
"checksum getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9047cfbd08a437050b363d35ef160452c5fe8ea5187ae0a624708c91581d685"
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
"checksum libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "55f3730be7e803cf350d32061958171731c2395831fbd67a61083782808183e0"
"checksum libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)" = "23e3757828fa702a20072c37ff47938e9dd331b92fac6e223d26d4b7a55f7ee2"
"checksum md5 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a5539a8dee9b4ae308c9c406a379838b435a8f2c84cf9fedc6d5a576be9888db"
"checksum memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d8b629fb514376c675b98c1421e80b151d3817ac42d7c667717d282761418d20"
"checksum num_cpus 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "51fedae97a05f7353612fe017ab705a37e6db8f4d67c5c6fe739a9e70d6eed09"
"checksum num_cpus 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "cee7e88156f3f9e19bdd598f8d6c9db7bf4078f99f8381f43a55b09648d1a6e3"
"checksum regex 0.1.73 (registry+https://github.com/rust-lang/crates.io-index)" = "56b7ee9f764ecf412c6e2fff779bca4b22980517ae335a21aeaf4e32625a5df2"
"checksum regex-syntax 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "31040aad7470ad9d8c46302dcffba337bb4289ca5da2e3cd6e37b64109a85199"
"checksum rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)" = "6159e4e6e559c81bd706afe9c8fd68f547d3e851ce12e76b1de7914bab61691b"
"checksum thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9539db560102d1cef46b8b78ce737ff0bb64e7e18d35b2a5688f7d097d0ff03"
"checksum thread_local 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "55dd963dbaeadc08aa7266bf7f91c3154a7805e32bb94b820b769d2ef3b4744d"
"checksum toml 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "fcd27a04ca509aff336ba5eb2abc58d456f52c4ff64d9724d88acb85ead560b6"
"checksum toml 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)" = "0590d72182e50e879c4da3b11c6488dae18fccb1ae0c7a3eda18e16795844796"
"checksum utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1ca13c08c41c9c3e04224ed9ff80461d97e121589ff27c753a16cb10830ae0f"
"checksum winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "4dfaaa8fbdaa618fa6914b59b2769d690dd7521920a18d84b42d254678dd5fd4"
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
......@@ -108,6 +108,10 @@ pub fn compiletest(build: &Build,
cmd.arg("--host").arg(compiler.host);
cmd.arg("--llvm-filecheck").arg(build.llvm_filecheck(&build.config.build));
if let Some(nodejs) = build.config.nodejs.as_ref() {
cmd.arg("--nodejs").arg(nodejs);
}
let mut flags = vec!["-Crpath".to_string()];
if build.config.rust_optimize_tests {
flags.push("-O".to_string());
......@@ -323,6 +327,9 @@ pub fn krate(build: &Build,
if target.contains("android") {
build.run(cargo.arg("--no-run"));
krate_android(build, compiler, target, mode);
} else if target.contains("emscripten") {
build.run(cargo.arg("--no-run"));
krate_emscripten(build, compiler, target, mode);
} else {
cargo.args(&build.flags.args);
build.run(&mut cargo);
......@@ -371,6 +378,35 @@ fn krate_android(build: &Build,
}
}
fn krate_emscripten(build: &Build,
compiler: &Compiler,
target: &str,
mode: Mode) {
let mut tests = Vec::new();
let out_dir = build.cargo_out(compiler, mode, target);
find_tests(&out_dir, target, &mut tests);
find_tests(&out_dir.join("deps"), target, &mut tests);
for test in tests {
let test_file_name = test.to_string_lossy().into_owned();
println!("running {}", test_file_name);
let nodejs = build.config.nodejs.as_ref().expect("nodejs not configured");
let status = Command::new(nodejs)
.arg(&test_file_name)
.stderr(::std::process::Stdio::inherit())
.status();
match status {
Ok(status) => {
if !status.success() {
panic!("some tests failed");
}
}
Err(e) => panic!(format!("failed to execute command: {}", e)),
};
}
}
fn find_tests(dir: &Path,
target: &str,
dst: &mut Vec<PathBuf>) {
......@@ -381,7 +417,8 @@ fn find_tests(dir: &Path,
}
let filename = e.file_name().into_string().unwrap();
if (target.contains("windows") && filename.ends_with(".exe")) ||
(!target.contains("windows") && !filename.contains(".")) {
(!target.contains("windows") && !filename.contains(".")) ||
(target.contains("emscripten") && filename.contains(".js")){
dst.push(e.path());
}
}
......
......@@ -975,7 +975,8 @@ fn rustc_flags(&self, target: &str) -> Vec<String> {
// than an entry here.
let mut base = Vec::new();
if target != self.config.build && !target.contains("msvc") {
if target != self.config.build && !target.contains("msvc") &&
!target.contains("emscripten") {
base.push(format!("-Clinker={}", self.cc(target).display()));
}
return base
......
......@@ -65,7 +65,7 @@ pub fn llvm(build: &Build, target: &str) {
.out_dir(&dst)
.profile(if build.config.llvm_optimize {"Release"} else {"Debug"})
.define("LLVM_ENABLE_ASSERTIONS", assertions)
.define("LLVM_TARGETS_TO_BUILD", "X86;ARM;AArch64;Mips;PowerPC;SystemZ")
.define("LLVM_TARGETS_TO_BUILD", "X86;ARM;AArch64;Mips;PowerPC;SystemZ;JSBackend")
.define("LLVM_INCLUDE_EXAMPLES", "OFF")
.define("LLVM_INCLUDE_TESTS", "OFF")
.define("LLVM_INCLUDE_DOCS", "OFF")
......
......@@ -95,6 +95,13 @@ pub fn check(build: &mut Build) {
// We're gonna build some custom C code here and there, host triples
// also build some C++ shims for LLVM so we need a C++ compiler.
for target in build.config.target.iter() {
// On emscripten we don't actually need the C compiler to just
// build the target artifacts, only for testing. For the sake
// of easier bot configuration, just skip detection.
if target.contains("emscripten") {
continue;
}
need_cmd(build.cc(target).as_ref());
if let Some(ar) = build.ar(target) {
need_cmd(ar.as_ref());
......@@ -104,6 +111,14 @@ pub fn check(build: &mut Build) {
need_cmd(build.cxx(host).as_ref());
}
// The msvc hosts don't use jemalloc, turn it off globally to
// avoid packaging the dummy liballoc_jemalloc on that platform.
for host in build.config.host.iter() {
if host.contains("msvc") {
build.config.use_jemalloc = false;
}
}
// Externally configured LLVM requires FileCheck to exist
let filecheck = build.llvm_filecheck(&build.config.build);
if !filecheck.starts_with(&build.out) && !filecheck.exists() && build.config.codegen_tests {
......@@ -111,15 +126,6 @@ pub fn check(build: &mut Build) {
}
for target in build.config.target.iter() {
// Either can't build or don't want to run jemalloc on these targets
if target.contains("rumprun") ||
target.contains("bitrig") ||
target.contains("openbsd") ||
target.contains("msvc") ||
target.contains("emscripten") {
build.config.use_jemalloc = false;
}
// Can't compile for iOS unless we're on OSX
if target.contains("apple-ios") &&
!build.config.build.contains("apple-darwin") {
......
......@@ -418,7 +418,6 @@ pub fn deps(&self, build: &'a Build) -> Vec<Step<'a>> {
self.check_crate_std(compiler),
self.check_crate_test(compiler),
self.check_debuginfo(compiler),
self.dist(stage),
];
// If we're testing the build triple, then we know we can
......@@ -463,6 +462,9 @@ pub fn deps(&self, build: &'a Build) -> Vec<Step<'a>> {
// misc
self.check_linkcheck(stage),
self.check_tidy(stage),
// can we make the distributables?
self.dist(stage),
]);
}
return base
......
......@@ -1000,6 +1000,7 @@ fn drop(&mut self) {
}
#[test]
#[cfg_attr(target_os = "emscripten", ignore)]
fn manually_share_arc() {
let v = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let arc_v = Arc::new(v);
......
......@@ -27,6 +27,24 @@ fn main() {
let build_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap());
let src_dir = env::current_dir().unwrap();
// FIXME: This is a hack to support building targets that don't
// support jemalloc alongside hosts that do. The jemalloc build is
// controlled by a feature of the std crate, and if that feature
// changes between targets, it invalidates the fingerprint of
// std's build script (this is a cargo bug); so we must ensure
// that the feature set used by std is the same across all
// targets, which means we have to build the alloc_jemalloc crate
// for targets like emscripten, even if we don't use it.
if target.contains("rumprun") ||
target.contains("bitrig") ||
target.contains("openbsd") ||
target.contains("msvc") ||
target.contains("emscripten")
{
println!("cargo:rustc-cfg=dummy_jemalloc");
return;
}
if let Some(jemalloc) = env::var_os("JEMALLOC_OVERRIDE") {
let jemalloc = PathBuf::from(jemalloc);
println!("cargo:rustc-link-search=native={}",
......
......@@ -23,124 +23,170 @@
extern crate libc;
use libc::{c_int, c_void, size_t};
pub use imp::*;
// Linkage directives to pull in jemalloc and its dependencies.
//
// On some platforms we need to be sure to link in `pthread` which jemalloc
// depends on, and specifically on android we need to also link to libgcc.
// Currently jemalloc is compiled with gcc which will generate calls to
// intrinsics that are libgcc specific (e.g. those intrinsics aren't present in
// libcompiler-rt), so link that in to get that support.
#[link(name = "jemalloc", kind = "static")]
#[cfg_attr(target_os = "android", link(name = "gcc"))]
#[cfg_attr(all(not(windows),
not(target_os = "android"),
not(target_env = "musl")),
link(name = "pthread"))]
#[cfg(not(cargobuild))]
extern "C" {}
// Note that the symbols here are prefixed by default on OSX and Windows (we
// don't explicitly request it), and on Android and DragonFly we explicitly
// request it as unprefixing cause segfaults (mismatches in allocators).
extern "C" {
#[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
target_os = "dragonfly", target_os = "windows"),
link_name = "je_mallocx")]
fn mallocx(size: size_t, flags: c_int) -> *mut c_void;
#[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
target_os = "dragonfly", target_os = "windows"),
link_name = "je_rallocx")]
fn rallocx(ptr: *mut c_void, size: size_t, flags: c_int) -> *mut c_void;
#[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
target_os = "dragonfly", target_os = "windows"),
link_name = "je_xallocx")]
fn xallocx(ptr: *mut c_void, size: size_t, extra: size_t, flags: c_int) -> size_t;
#[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
target_os = "dragonfly", target_os = "windows"),
link_name = "je_sdallocx")]
fn sdallocx(ptr: *mut c_void, size: size_t, flags: c_int);
#[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
target_os = "dragonfly", target_os = "windows"),
link_name = "je_nallocx")]
fn nallocx(size: size_t, flags: c_int) -> size_t;
}
// See comments in build.rs for why we sometimes build a crate that does nothing
#[cfg(not(dummy_jemalloc))]
mod imp {
use libc::{c_int, c_void, size_t};
// The minimum alignment guaranteed by the architecture. This value is used to
// add fast paths for low alignment values. In practice, the alignment is a
// constant at the call site and the branch will be optimized out.
#[cfg(all(any(target_arch = "arm",
target_arch = "mips",
target_arch = "powerpc")))]
const MIN_ALIGN: usize = 8;
#[cfg(all(any(target_arch = "x86",
target_arch = "x86_64",
target_arch = "aarch64",
target_arch = "powerpc64",
target_arch = "mips64",
target_arch = "s390x")))]
const MIN_ALIGN: usize = 16;
// MALLOCX_ALIGN(a) macro
fn mallocx_align(a: usize) -> c_int {
a.trailing_zeros() as c_int
}
// Linkage directives to pull in jemalloc and its dependencies.
//
// On some platforms we need to be sure to link in `pthread` which jemalloc
// depends on, and specifically on android we need to also link to libgcc.
// Currently jemalloc is compiled with gcc which will generate calls to
// intrinsics that are libgcc specific (e.g. those intrinsics aren't present in
// libcompiler-rt), so link that in to get that support.
#[link(name = "jemalloc", kind = "static")]
#[cfg_attr(target_os = "android", link(name = "gcc"))]
#[cfg_attr(all(not(windows),
not(target_os = "android"),
not(target_env = "musl")),
link(name = "pthread"))]
#[cfg(not(cargobuild))]
extern "C" {}
// Note that the symbols here are prefixed by default on OSX and Windows (we
// don't explicitly request it), and on Android and DragonFly we explicitly
// request it as unprefixing cause segfaults (mismatches in allocators).
extern "C" {
#[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
target_os = "dragonfly", target_os = "windows"),
link_name = "je_mallocx")]
fn mallocx(size: size_t, flags: c_int) -> *mut c_void;
#[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
target_os = "dragonfly", target_os = "windows"),
link_name = "je_rallocx")]
fn rallocx(ptr: *mut c_void, size: size_t, flags: c_int) -> *mut c_void;
#[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
target_os = "dragonfly", target_os = "windows"),
link_name = "je_xallocx")]
fn xallocx(ptr: *mut c_void, size: size_t, extra: size_t, flags: c_int) -> size_t;
#[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
target_os = "dragonfly", target_os = "windows"),
link_name = "je_sdallocx")]
fn sdallocx(ptr: *mut c_void, size: size_t, flags: c_int);
#[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
target_os = "dragonfly", target_os = "windows"),
link_name = "je_nallocx")]
fn nallocx(size: size_t, flags: c_int) -> size_t;
}
// The minimum alignment guaranteed by the architecture. This value is used to
// add fast paths for low alignment values. In practice, the alignment is a
// constant at the call site and the branch will be optimized out.
#[cfg(all(any(target_arch = "arm",
target_arch = "mips",
target_arch = "powerpc")))]
const MIN_ALIGN: usize = 8;
#[cfg(all(any(target_arch = "x86",
target_arch = "x86_64",
target_arch = "aarch64",
target_arch = "powerpc64",
target_arch = "mips64",
target_arch = "s390x")))]
const MIN_ALIGN: usize = 16;
// MALLOCX_ALIGN(a) macro
fn mallocx_align(a: usize) -> c_int {
a.trailing_zeros() as c_int
}
fn align_to_flags(align: usize) -> c_int {
if align <= MIN_ALIGN {
0
} else {
mallocx_align(align)
}
}
#[no_mangle]
pub extern "C" fn __rust_allocate(size: usize, align: usize) -> *mut u8 {
let flags = align_to_flags(align);
unsafe { mallocx(size as size_t, flags) as *mut u8 }
}
#[no_mangle]
pub extern "C" fn __rust_reallocate(ptr: *mut u8,
_old_size: usize,
size: usize,
align: usize)
-> *mut u8 {
let flags = align_to_flags(align);
unsafe { rallocx(ptr as *mut c_void, size as size_t, flags) as *mut u8 }
}
#[no_mangle]
pub extern "C" fn __rust_reallocate_inplace(ptr: *mut u8,
_old_size: usize,
size: usize,
align: usize)
-> usize {
let flags = align_to_flags(align);
unsafe { xallocx(ptr as *mut c_void, size as size_t, 0, flags) as usize }
}
fn align_to_flags(align: usize) -> c_int {
if align <= MIN_ALIGN {
#[no_mangle]
pub extern "C" fn __rust_deallocate(ptr: *mut u8, old_size: usize, align: usize) {
let flags = align_to_flags(align);
unsafe { sdallocx(ptr as *mut c_void, old_size as size_t, flags) }
}
#[no_mangle]
pub extern "C" fn __rust_usable_size(size: usize, align: usize) -> usize {
let flags = align_to_flags(align);
unsafe { nallocx(size as size_t, flags) as usize }
}
// These symbols are used by jemalloc on android but the really old android
// we're building on doesn't have them defined, so just make sure the symbols
// are available.
#[no_mangle]
#[cfg(target_os = "android")]
pub extern "C" fn pthread_atfork(_prefork: *mut u8,
_postfork_parent: *mut u8,
_postfork_child: *mut u8)
-> i32 {
0
} else {
mallocx_align(align)
}
}
#[no_mangle]
pub extern "C" fn __rust_allocate(size: usize, align: usize) -> *mut u8 {
let flags = align_to_flags(align);
unsafe { mallocx(size as size_t, flags) as *mut u8 }
}
#[cfg(dummy_jemalloc)]
mod imp {
fn bogus() -> ! {
panic!("jemalloc is not implemented for this platform");
}
#[no_mangle]
pub extern "C" fn __rust_reallocate(ptr: *mut u8,
_old_size: usize,
size: usize,
align: usize)
-> *mut u8 {
let flags = align_to_flags(align);
unsafe { rallocx(ptr as *mut c_void, size as size_t, flags) as *mut u8 }
}
#[no_mangle]
pub extern "C" fn __rust_allocate(_size: usize, _align: usize) -> *mut u8 {
bogus()
}
#[no_mangle]
pub extern "C" fn __rust_reallocate_inplace(ptr: *mut u8,
_old_size: usize,
size: usize,
align: usize)
-> usize {
let flags = align_to_flags(align);
unsafe { xallocx(ptr as *mut c_void, size as size_t, 0, flags) as usize }
}
#[no_mangle]
pub extern "C" fn __rust_reallocate(_ptr: *mut u8,
_old_size: usize,
_size: usize,
_align: usize)
-> *mut u8 {
bogus()
}
#[no_mangle]
pub extern "C" fn __rust_deallocate(ptr: *mut u8, old_size: usize, align: usize) {
let flags = align_to_flags(align);
unsafe { sdallocx(ptr as *mut c_void, old_size as size_t, flags) }
}
#[no_mangle]
pub extern "C" fn __rust_reallocate_inplace(_ptr: *mut u8,
_old_size: usize,
_size: usize,
_align: usize)
-> usize {
bogus()
}
#[no_mangle]
pub extern "C" fn __rust_usable_size(size: usize, align: usize) -> usize {
let flags = align_to_flags(align);
unsafe { nallocx(size as size_t, flags) as usize }
}
#[no_mangle]
pub extern "C" fn __rust_deallocate(_ptr: *mut u8, _old_size: usize, _align: usize) {
bogus()
}
// These symbols are used by jemalloc on android but the really old android
// we're building on doesn't have them defined, so just make sure the symbols
// are available.
#[no_mangle]
#[cfg(target_os = "android")]
pub extern "C" fn pthread_atfork(_prefork: *mut u8,
_postfork_parent: *mut u8,
_postfork_child: *mut u8)
-> i32 {
0
#[no_mangle]
pub extern "C" fn __rust_usable_size(_size: usize, _align: usize) -> usize {
bogus()
}
}
......@@ -29,7 +29,8 @@
target_arch = "mips",
target_arch = "powerpc",
target_arch = "powerpc64",
target_arch = "asmjs")))]
target_arch = "asmjs",
target_arch = "wasm32")))]
const MIN_ALIGN: usize = 8;
#[cfg(all(any(target_arch = "x86_64",
target_arch = "aarch64",
......
......@@ -1294,6 +1294,7 @@ fn test_insert_prev() {
}
#[test]
#[cfg_attr(target_os = "emscripten", ignore)]
fn test_send() {
let n = list_from(&[1, 2, 3]);
thread::spawn(move || {
......
......@@ -1116,6 +1116,7 @@ fn test_box_slice_clone() {
}
#[test]
#[cfg_attr(target_os = "emscripten", ignore)]
fn test_box_slice_clone_panics() {
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
......
......@@ -73,6 +73,12 @@ fn extend(&mut self, sources: &[&'static str]) {
fn main() {
let target = env::var("TARGET").expect("TARGET was not set");
// Emscripten's runtime includes all the builtins
if target.contains("emscripten") {
return;
}
let cfg = &mut gcc::Config::new();
if target.contains("msvc") {
......
......@@ -8,6 +8,11 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// FIXME https://github.com/kripken/emscripten/issues/4563
// NB we have to actually not compile this test to avoid
// an undefined symbol error
#![cfg(not(target_os = "emscripten"))]
use core::num::flt2dec::estimator::*;
#[test]
......
......@@ -5,6 +5,7 @@ dependencies = [
"alloc 0.0.0",
"core 0.0.0",
"libc 0.0.0",
"unwind 0.0.0",
]
[[package]]
......@@ -25,3 +26,11 @@ dependencies = [
"core 0.0.0",
]
[[package]]
name = "unwind"
version = "0.0.0"
dependencies = [
"core 0.0.0",
"libc 0.0.0",
]
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Unwinding for emscripten
//!
//! Whereas Rust's usual unwinding implementation for Unix platforms
//! calls into the libunwind APIs directly, on emscripten we instead
//! call into the C++ unwinding APIs. This is just an expedience since
//! emscripten's runtime always implements those APIs and does not
//! implement libunwind.
#![allow(private_no_mangle_fns)]
use core::any::Any;
use core::ptr;
use alloc::boxed::Box;
use libc::{self, c_int};
use unwind as uw;
use core::mem;
pub fn payload() -> *mut u8 {
ptr::null_mut()
}
pub unsafe fn cleanup(ptr: *mut u8) -> Box<Any + Send> {
assert!(!ptr.is_null());
let ex = ptr::read(ptr as *mut _);
__cxa_free_exception(ptr as *mut _);
ex
}
pub unsafe fn panic(data: Box<Any + Send>) -> u32 {
let sz = mem::size_of_val(&data);
let exception = __cxa_allocate_exception(sz);
if exception == ptr::null_mut() {
return uw::_URC_FATAL_PHASE1_ERROR as u32;
}
let exception = exception as *mut Box<Any + Send>;
ptr::write(exception, data);
__cxa_throw(exception as *mut _, ptr::null_mut(), ptr::null_mut());
unreachable!()
}
#[lang = "eh_personality"]
#[no_mangle]
unsafe extern "C" fn rust_eh_personality(version: c_int,
actions: uw::_Unwind_Action,
exception_class: uw::_Unwind_Exception_Class,
exception_object: *mut uw::_Unwind_Exception,
context: *mut uw::_Unwind_Context)
-> uw::_Unwind_Reason_Code {
__gxx_personality_v0(version, actions,
exception_class,
exception_object,
context)
}
extern {
fn __cxa_allocate_exception(thrown_size: libc::size_t) -> *mut libc::c_void;
fn __cxa_free_exception(thrown_exception: *mut libc::c_void);
fn __cxa_throw(thrown_exception: *mut libc::c_void,
tinfo: *mut libc::c_void,
dest: *mut libc::c_void);
fn __gxx_personality_v0(version: c_int,
actions: uw::_Unwind_Action,
exception_class: uw::_Unwind_Exception_Class,
exception_object: *mut uw::_Unwind_Exception,
context: *mut uw::_Unwind_Context)
-> uw::_Unwind_Reason_Code;
}
......@@ -68,10 +68,16 @@
mod imp;
// i686-pc-windows-gnu and all others
#[cfg(any(unix, all(windows, target_arch = "x86", target_env = "gnu")))]
#[cfg(any(all(unix, not(target_os = "emscripten")),
all(windows, target_arch = "x86", target_env = "gnu")))]
#[path = "gcc.rs"]
mod imp;
// emscripten
#[cfg(target_os = "emscripten")]
#[path = "emcc.rs"]
mod imp;
mod dwarf;
mod windows;
......
......@@ -22,6 +22,7 @@ pub fn target() -> Result<Target, String> {
allow_asm: false,
obj_is_bitcode: true,
max_atomic_width: 32,
post_link_args: vec!["-s".to_string(), "ERROR_ON_UNDEFINED_SYMBOLS=1".to_string()],
.. Default::default()
};
Ok(Target {
......
......@@ -190,7 +190,8 @@ fn $module() {
("i586-pc-windows-msvc", i586_pc_windows_msvc),
("le32-unknown-nacl", le32_unknown_nacl),
("asmjs-unknown-emscripten", asmjs_unknown_emscripten)
("asmjs-unknown-emscripten", asmjs_unknown_emscripten),
("wasm32-unknown-emscripten", wasm32_unknown_emscripten)
}
/// Everything `rustc` knows about how to compile for a specific target.
......
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use super::{Target, TargetOptions};
pub fn target() -> Result<Target, String> {
let opts = TargetOptions {
linker: "emcc".to_string(),
ar: "emar".to_string(),
dynamic_linking: false,
executables: true,
// Today emcc emits two files - a .js file to bootstrap and
// possibly interpret the wasm, and a .wasm file
exe_suffix: ".js".to_string(),
linker_is_gnu: true,
allow_asm: false,
obj_is_bitcode: true,
max_atomic_width: 32,
post_link_args: vec!["-s".to_string(), "BINARYEN=1".to_string(),
"-s".to_string(), "ERROR_ON_UNDEFINED_SYMBOLS=1".to_string()],
.. Default::default()
};
Ok(Target {
llvm_target: "asmjs-unknown-emscripten".to_string(),
target_endian: "little".to_string(),
target_pointer_width: "32".to_string(),
target_os: "emscripten".to_string(),
target_env: "".to_string(),
target_vendor: "unknown".to_string(),
data_layout: "e-p:32:32-i64:64-v128:32:128-n32-S128".to_string(),
arch: "wasm32".to_string(),
options: opts,
})
}
......@@ -1075,7 +1075,7 @@ fn flush(&mut self) -> io::Result<()> {
}
let thread = cfg.spawn(move || {
io::set_panic(box err);
io::set_panic(Some(box err));
f()
});
......@@ -1121,7 +1121,7 @@ fn exit_on_err() -> ! {
// Panic so the process returns a failure code, but don't pollute the
// output with some unnecessary panic messages, we've already
// printed everything that we needed to.
io::set_panic(box io::sink());
io::set_panic(Some(box io::sink()));
panic!();
}
......
......@@ -66,7 +66,8 @@ fn main() {
let host = env::var("HOST").expect("HOST was not set");
let is_crossed = target != host;
let optional_components = ["x86", "arm", "aarch64", "mips", "powerpc", "pnacl", "systemz"];
let optional_components = ["x86", "arm", "aarch64", "mips", "powerpc", "pnacl", "systemz",
"jsbackend"];
// FIXME: surely we don't need all these components, right? Stuff like mcjit
// or interpreter the compiler itself never uses.
......
......@@ -434,6 +434,10 @@ fn init() { }
LLVMInitializeSystemZTargetMC,
LLVMInitializeSystemZAsmPrinter,
LLVMInitializeSystemZAsmParser);
init_target!(llvm_component = "jsbackend",
LLVMInitializeJSBackendTargetInfo,
LLVMInitializeJSBackendTarget,
LLVMInitializeJSBackendTargetMC);
}
pub fn last_error() -> Option<String> {
......
......@@ -519,6 +519,7 @@ pub fn adjust_for_abi<'a, 'tcx>(&mut self,
"powerpc64" => cabi_powerpc64::compute_abi_info(ccx, self),
"s390x" => cabi_s390x::compute_abi_info(ccx, self),
"asmjs" => cabi_asmjs::compute_abi_info(ccx, self),
"wasm32" => cabi_asmjs::compute_abi_info(ccx, self),
a => ccx.sess().fatal(&format!("unrecognized arch \"{}\" in target specification", a))
}
......
......@@ -228,7 +228,7 @@ fn drop(&mut self) {
let codemap = Rc::new(CodeMap::new());
let emitter = errors::emitter::EmitterWriter::new(box Sink(data.clone()),
Some(codemap.clone()));
let old = io::set_panic(box Sink(data.clone()));
let old = io::set_panic(Some(box Sink(data.clone())));
let _bomb = Bomb(data.clone(), old.unwrap_or(box io::stdout()));
// Compile the code
......
......@@ -892,7 +892,18 @@ mod os {
pub const EXE_EXTENSION: &'static str = "pexe";
}
#[cfg(target_os = "emscripten")]
#[cfg(all(target_os = "emscripten", target_arch = "asmjs"))]
mod os {
pub const FAMILY: &'static str = "unix";
pub const OS: &'static str = "emscripten";
pub const DLL_PREFIX: &'static str = "lib";
pub const DLL_SUFFIX: &'static str = ".so";
pub const DLL_EXTENSION: &'static str = "so";
pub const EXE_SUFFIX: &'static str = ".js";
pub const EXE_EXTENSION: &'static str = "js";
}
#[cfg(all(target_os = "emscripten", target_arch = "wasm32"))]
mod os {
pub const FAMILY: &'static str = "unix";
pub const OS: &'static str = "emscripten";
......@@ -969,6 +980,11 @@ mod arch {
pub const ARCH: &'static str = "asmjs";
}
#[cfg(target_arch = "wasm32")]
mod arch {
pub const ARCH: &'static str = "wasm32";
}
#[cfg(test)]
mod tests {
use super::*;
......@@ -1017,6 +1033,7 @@ fn test_set_var_overwrite() {
}
#[test]
#[cfg_attr(target_os = "emscripten", ignore)]
fn test_var_big() {
let mut s = "".to_string();
let mut i = 0;
......@@ -1030,6 +1047,7 @@ fn test_var_big() {
}
#[test]
#[cfg_attr(target_os = "emscripten", ignore)]
fn test_self_exe_path() {
let path = current_exe();
assert!(path.is_ok());
......@@ -1040,6 +1058,7 @@ fn test_self_exe_path() {
}
#[test]
#[cfg_attr(target_os = "emscripten", ignore)]
fn test_env_set_get_huge() {
let n = make_rand_name();
let s = repeat("x").take(10000).collect::<String>();
......
......@@ -1686,7 +1686,7 @@ fn as_inner_mut(&mut self) -> &mut fs_imp::DirBuilder {
}
}
#[cfg(test)]
#[cfg(all(test, not(target_os = "emscripten")))]
mod tests {
use io::prelude::*;
......
......@@ -1107,6 +1107,7 @@ fn flush(&mut self) -> io::Result<()> {
}
#[test]
#[cfg_attr(target_os = "emscripten", ignore)]
fn panic_in_write_doesnt_flush_in_drop() {
static WRITES: AtomicUsize = AtomicUsize::new(0);
......
......@@ -1757,6 +1757,7 @@ mod tests {
use super::repeat;
#[test]
#[cfg_attr(target_os = "emscripten", ignore)]
fn read_until() {
let mut buf = Cursor::new(&b"12"[..]);
let mut v = Vec::new();
......@@ -1967,6 +1968,7 @@ fn chain_zero_length_read_is_not_eof() {
}
#[bench]
#[cfg_attr(target_os = "emscripten", ignore)]
fn bench_read_to_end(b: &mut test::Bencher) {
b.iter(|| {
let mut lr = repeat(1).take(10000000);
......
......@@ -593,11 +593,11 @@ fn flush(&mut self) -> io::Result<()> {
with a more general mechanism",
issue = "0")]
#[doc(hidden)]
pub fn set_panic(sink: Box<Write + Send>) -> Option<Box<Write + Send>> {
pub fn set_panic(sink: Option<Box<Write + Send>>) -> Option<Box<Write + Send>> {
use panicking::LOCAL_STDERR;
use mem;
LOCAL_STDERR.with(move |slot| {
mem::replace(&mut *slot.borrow_mut(), Some(sink))
mem::replace(&mut *slot.borrow_mut(), sink)
}).and_then(|mut s| {
let _ = s.flush();
Some(s)
......@@ -617,10 +617,10 @@ pub fn set_panic(sink: Box<Write + Send>) -> Option<Box<Write + Send>> {
with a more general mechanism",
issue = "0")]
#[doc(hidden)]
pub fn set_print(sink: Box<Write + Send>) -> Option<Box<Write + Send>> {
pub fn set_print(sink: Option<Box<Write + Send>>) -> Option<Box<Write + Send>> {
use mem;
LOCAL_STDOUT.with(move |slot| {
mem::replace(&mut *slot.borrow_mut(), Some(sink))
mem::replace(&mut *slot.borrow_mut(), sink)
}).and_then(|mut s| {
let _ = s.flush();
Some(s)
......@@ -668,6 +668,7 @@ mod tests {
use super::*;
#[test]
#[cfg_attr(target_os = "emscripten", ignore)]
fn panic_doesnt_poison() {
thread::spawn(|| {
let _a = stdin();
......
......@@ -519,7 +519,7 @@ fn to_socket_addrs(&self) -> io::Result<T::Iter> {
}
}
#[cfg(test)]
#[cfg(all(test, not(target_os = "emscripten")))]
mod tests {
use net::*;
use net::test::{tsa, sa6, sa4};
......
......@@ -669,7 +669,7 @@ fn from_inner(addr: c::in6_addr) -> Ipv6Addr {
}
// Tests for this module
#[cfg(test)]
#[cfg(all(test, not(target_os = "emscripten")))]
mod tests {
use net::*;
use net::Ipv6MulticastScope::*;
......
......@@ -31,7 +31,8 @@
mod tcp;
mod udp;
mod parser;
#[cfg(test)] mod test;
#[cfg(all(test, not(target_os = "emscripten")))]
mod test;
/// Possible values which can be passed to the [`shutdown`] method of
/// [`TcpStream`].
......
......@@ -428,7 +428,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
}
}
#[cfg(test)]
#[cfg(all(test, not(target_os = "emscripten")))]
mod tests {
use io::ErrorKind;
use io::prelude::*;
......
......@@ -353,7 +353,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
}
}
#[cfg(test)]
#[cfg(all(test, not(target_os = "emscripten")))]
mod tests {
use io::ErrorKind;
use net::*;
......
......@@ -34,7 +34,8 @@
target_arch = "le32",
target_arch = "powerpc",
target_arch = "arm",
target_arch = "asmjs"))]
target_arch = "asmjs",
target_arch = "wasm32"))]
mod arch {
use os::raw::{c_long, c_short, c_uint};
......
......@@ -825,7 +825,7 @@ pub fn exit(code: i32) -> ! {
::sys::os::exit(code)
}
#[cfg(test)]
#[cfg(all(test, not(target_os = "emscripten")))]
mod tests {
use io::prelude::*;
......
......@@ -242,6 +242,7 @@ fn test_os_rng() {
}
#[test]
#[cfg_attr(target_os = "emscripten", ignore)]
fn test_os_rng_tasks() {
let mut txs = vec!();
......
......@@ -118,6 +118,7 @@ mod tests {
use thread;
#[test]
#[cfg_attr(target_os = "emscripten", ignore)]
fn test_barrier() {
const N: usize = 10;
......
......@@ -270,6 +270,7 @@ fn smoke() {
}
#[test]
#[cfg_attr(target_os = "emscripten", ignore)]
fn notify_one() {
let m = Arc::new(Mutex::new(()));
let m2 = m.clone();
......@@ -286,6 +287,7 @@ fn notify_one() {
}
#[test]
#[cfg_attr(target_os = "emscripten", ignore)]
fn notify_all() {
const N: usize = 10;
......@@ -322,6 +324,7 @@ fn notify_all() {
}
#[test]
#[cfg_attr(target_os = "emscripten", ignore)]
fn wait_timeout_ms() {
let m = Arc::new(Mutex::new(()));
let m2 = m.clone();
......@@ -343,6 +346,7 @@ fn wait_timeout_ms() {
#[test]
#[should_panic]
#[cfg_attr(target_os = "emscripten", ignore)]
fn two_mutexes() {
let m = Arc::new(Mutex::new(()));
let m2 = m.clone();
......
......@@ -1268,7 +1268,7 @@ fn cause(&self) -> Option<&error::Error> {
}
}
#[cfg(test)]
#[cfg(all(test, not(target_os = "emscripten")))]
mod tests {
use env;
use super::*;
......@@ -1942,7 +1942,7 @@ fn destroy_upgraded_shared_port_when_sender_still_active() {
}
}
#[cfg(test)]
#[cfg(all(test, not(target_os = "emscripten")))]
mod sync_tests {
use env;
use thread;
......
......@@ -146,7 +146,7 @@ fn drop(&mut self) {
}
}
#[cfg(test)]
#[cfg(all(test, not(target_os = "emscripten")))]
mod tests {
use sync::mpsc::channel;
use super::{Queue, Data, Empty, Inconsistent};
......
......@@ -366,7 +366,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
}
}
#[cfg(test)]
#[cfg(all(test, not(target_os = "emscripten")))]
#[allow(unused_imports)]
mod tests {
use thread;
......
......@@ -231,7 +231,7 @@ fn drop(&mut self) {
}
}
#[cfg(test)]
#[cfg(all(test, not(target_os = "emscripten")))]
mod tests {
use sync::Arc;
use super::Queue;
......
......@@ -352,7 +352,7 @@ pub fn guard_poison<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a poison::Fla
&guard.__lock.poison
}
#[cfg(test)]
#[cfg(all(test, not(target_os = "emscripten")))]
mod tests {
use sync::mpsc::channel;
use sync::{Arc, Mutex, Condvar};
......
......@@ -367,7 +367,7 @@ pub fn poisoned(&self) -> bool {
}
}
#[cfg(test)]
#[cfg(all(test, not(target_os = "emscripten")))]
mod tests {
use panic;
use sync::mpsc::channel;
......
......@@ -380,7 +380,7 @@ fn drop(&mut self) {
}
}
#[cfg(test)]
#[cfg(all(test, not(target_os = "emscripten")))]
mod tests {
#![allow(deprecated)] // rand
......
......@@ -50,7 +50,7 @@ pub unsafe fn read_to_end_uninitialized(r: &mut Read, buf: &mut Vec<u8>) -> io::
}
}
#[cfg(test)]
#[cfg(all(test, not(target_os = "emscripten")))]
pub mod test {
use path::{Path, PathBuf};
use env;
......@@ -165,6 +165,7 @@ fn read_to_end_uninit_good() {
}
#[bench]
#[cfg_attr(target_os = "emscripten", ignore)]
fn bench_uninitialized(b: &mut ::test::Bencher) {
b.iter(|| {
let mut lr = repeat(1).take(10000000);
......
......@@ -156,7 +156,7 @@ fn drop(&mut self) {
}
#[cfg(test)]
#[cfg(all(test, not(target_os = "emscripten")))]
mod tests {
use sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard};
use cell::RefCell;
......
......@@ -786,7 +786,7 @@ fn into_raw_fd(self) -> RawFd {
}
}
#[cfg(test)]
#[cfg(all(test, not(target_os = "emscripten")))]
mod test {
use thread;
use io;
......
......@@ -369,7 +369,7 @@ unsafe fn do_exec(&mut self, stdio: ChildPipes) -> io::Error {
}
// NaCl has no signal support.
if cfg!(not(target_os = "nacl")) {
if cfg!(not(any(target_os = "nacl", target_os = "emscripten"))) {
// Reset signal handling so the child process starts in a
// standardized state. libstd ignores SIGPIPE, and signal-handling
// libraries often set a mask. Child processes inherit ignored
......@@ -589,7 +589,7 @@ pub fn wait(&mut self) -> io::Result<ExitStatus> {
}
}
#[cfg(test)]
#[cfg(all(test, not(target_os = "emscripten")))]
mod tests {
use super::*;
......
......@@ -29,6 +29,20 @@ pub struct Thread {
unsafe impl Send for Thread {}
unsafe impl Sync for Thread {}
// The pthread_attr_setstacksize symbol doesn't exist in the emscripten libc,
// so we have to not link to it to satisfy emcc's ERROR_ON_UNDEFINED_SYMBOLS.
#[cfg(not(target_os = "emscripten"))]
unsafe fn pthread_attr_setstacksize(attr: *mut libc::pthread_attr_t,
stack_size: libc::size_t) -> libc::c_int {
libc::pthread_attr_setstacksize(attr, stack_size)
}
#[cfg(target_os = "emscripten")]
unsafe fn pthread_attr_setstacksize(_attr: *mut libc::pthread_attr_t,
_stack_size: libc::size_t) -> libc::c_int {
panic!()
}
impl Thread {
pub unsafe fn new<'a>(stack: usize, p: Box<FnBox() + 'a>)
-> io::Result<Thread> {
......@@ -38,8 +52,8 @@ pub unsafe fn new<'a>(stack: usize, p: Box<FnBox() + 'a>)
assert_eq!(libc::pthread_attr_init(&mut attr), 0);
let stack_size = cmp::max(stack, min_stack_size(&attr));
match libc::pthread_attr_setstacksize(&mut attr,
stack_size as libc::size_t) {
match pthread_attr_setstacksize(&mut attr,
stack_size as libc::size_t) {
0 => {}
n => {
assert_eq!(n, libc::EINVAL);
......
......@@ -524,7 +524,7 @@ pub fn get(&'static self) -> Option<&'static UnsafeCell<Option<T>>> {
}
}
#[cfg(test)]
#[cfg(all(test, not(target_os = "emscripten")))]
mod tests {
use sync::mpsc::{channel, Sender};
use cell::{Cell, UnsafeCell};
......
......@@ -741,7 +741,7 @@ fn _assert_both<T: Send + Sync>() {}
// Tests
////////////////////////////////////////////////////////////////////////////////
#[cfg(test)]
#[cfg(all(test, not(target_os = "emscripten")))]
mod tests {
use any::Any;
use sync::mpsc::{channel, Sender};
......
......@@ -1182,26 +1182,59 @@ fn flush(&mut self) -> io::Result<()> {
}
}
thread::spawn(move || {
let data = Arc::new(Mutex::new(Vec::new()));
let data2 = data.clone();
let cfg = thread::Builder::new().name(match desc.name {
DynTestName(ref name) => name.clone(),
StaticTestName(name) => name.to_owned(),
// If the platform is single-threaded we're just going to run
// the test synchronously, regardless of the concurrency
// level.
let supports_threads = !cfg!(target_os = "emscripten");
// Buffer for capturing standard I/O
let data = Arc::new(Mutex::new(Vec::new()));
let data2 = data.clone();
if supports_threads {
thread::spawn(move || {
let cfg = thread::Builder::new().name(match desc.name {
DynTestName(ref name) => name.clone(),
StaticTestName(name) => name.to_owned(),
});
let result_guard = cfg.spawn(move || {
if !nocapture {
io::set_print(Some(box Sink(data2.clone())));
io::set_panic(Some(box Sink(data2)));
}
testfn()
})
.unwrap();
let test_result = calc_result(&desc, result_guard.join());
let stdout = data.lock().unwrap().to_vec();
monitor_ch.send((desc.clone(), test_result, stdout)).unwrap();
});
} else {
let oldio = if !nocapture {
Some((
io::set_print(Some(box Sink(data2.clone()))),
io::set_panic(Some(box Sink(data2)))
))
} else {
None
};
let result_guard = cfg.spawn(move || {
if !nocapture {
io::set_print(box Sink(data2.clone()));
io::set_panic(box Sink(data2));
}
testfn()
})
.unwrap();
let test_result = calc_result(&desc, result_guard.join());
use std::panic::{catch_unwind, AssertUnwindSafe};
let result = catch_unwind(AssertUnwindSafe(|| {
testfn()
}));
if let Some((printio, panicio)) = oldio {
io::set_print(printio);
io::set_panic(panicio);
};
let test_result = calc_result(&desc, result);
let stdout = data.lock().unwrap().to_vec();
monitor_ch.send((desc.clone(), test_result, stdout)).unwrap();
});
}
}
match testfn {
......@@ -1291,7 +1324,7 @@ pub fn fmt_metrics(&self) -> String {
///
/// This function is a no-op, and does not even read from `dummy`.
#[cfg(not(any(all(target_os = "nacl", target_arch = "le32"),
target_arch = "asmjs")))]
target_arch = "asmjs", target_arch = "wasm32")))]
pub fn black_box<T>(dummy: T) -> T {
// we need to "use" the argument in some way LLVM can't
// introspect.
......@@ -1299,7 +1332,7 @@ pub fn black_box<T>(dummy: T) -> T {
dummy
}
#[cfg(any(all(target_os = "nacl", target_arch = "le32"),
target_arch = "asmjs"))]
target_arch = "asmjs", target_arch = "wasm32"))]
#[inline(never)]
pub fn black_box<T>(dummy: T) -> T {
dummy
......
......@@ -65,7 +65,7 @@ pub enum _Unwind_Reason_Code {
#[cfg(target_arch = "s390x")]
pub const unwinder_private_data_size: usize = 2;
#[cfg(target_arch = "asmjs")]
#[cfg(target_os = "emscripten")]
pub const unwinder_private_data_size: usize = 20;
#[repr(C)]
......
Subproject commit 7801978ec1f3637fcda1b564048ebc732bf586af
Subproject commit 3e03f7374169cd41547d75e62ac2ab8a103a913c
# If this file is modified, then llvm will be forcibly cleaned and then rebuilt.
# The actual contents of this file do not matter, but to trigger a change on the
# build bots then the contents should be changed so git updates the mtime.
2016-09-17
2016-09-25
......@@ -18,6 +18,8 @@
// system allocator. Do this by linking in jemalloc and making sure that we get
// an error.
// ignore-emscripten FIXME: What "other allocator" should we use for emcc?
#![feature(alloc_jemalloc)]
extern crate allocator_dylib;
......
......@@ -16,6 +16,8 @@
// Ensure that rust dynamic libraries use jemalloc as their allocator, verifying
// by linking in the system allocator here and ensuring that we get a complaint.
// ignore-emscripten FIXME: What "other allocator" is correct for emscripten?
#![feature(alloc_system)]
extern crate allocator_dylib2;
......
......@@ -9,6 +9,7 @@
// except according to those terms.
// error-pattern:thread '<unnamed>' panicked at 'test'
// ignore-emscripten Needs threads
use std::thread;
......
......@@ -9,6 +9,7 @@
// except according to those terms.
// error-pattern:thread 'owned name' panicked at 'test'
// ignore-emscripten Needs threads.
use std::thread::Builder;
......
......@@ -9,6 +9,7 @@
// except according to those terms.
// error-pattern:Ensure that the child thread runs by panicking
// ignore-emscripten Needs threads.
use std::thread;
......
......@@ -12,6 +12,7 @@
// error-pattern:thread 'test_foo' panicked at
// compile-flags: --test
// ignore-pretty: does not work well with `--test`
// ignore-emscripten
#[test]
fn test_foo() {
......
......@@ -12,6 +12,7 @@
// error-pattern:thread 'test_foo' panicked at
// compile-flags: --test
// ignore-pretty: does not work well with `--test`
// ignore-emscripten
#[test]
#[should_panic(expected = "foobar")]
......
......@@ -15,6 +15,7 @@
// compile-flags: --test
// exec-env:RUST_TEST_THREADS=foo
// ignore-pretty: does not work well with `--test`
// ignore-emscripten
#[test]
fn do_nothing() {}
......@@ -10,6 +10,7 @@
// no-prefer-dynamic
// aux-build:allocator-dummy.rs
// ignore-emscripten
#![feature(test)]
......
......@@ -12,6 +12,7 @@
// pretty-expanded FIXME #23616
// ignore-msvc
// ignore-emscripten
struct TwoU8s {
one: u8,
......
......@@ -8,6 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// ignore-emscripten missing rust_begin_unwind
#![feature(lang_items, start, collections)]
#![no_std]
......
......@@ -7,6 +7,7 @@
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// ignore-emscripten Not sure what's happening here.
use std::mem;
......
......@@ -7,6 +7,7 @@
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// ignore-emscripten
use std::mem;
......
......@@ -11,6 +11,7 @@
// compile-flags:-C panic=abort
// aux-build:exit-success-if-unwind.rs
// no-prefer-dynamic
// ignore-emscripten Function not implemented
extern crate exit_success_if_unwind;
......
......@@ -10,6 +10,7 @@
// compile-flags:-C panic=abort
// no-prefer-dynamic
// ignore-emscripten Function not implemented.
use std::process::Command;
use std::env;
......
......@@ -10,6 +10,7 @@
// compile-flags:-C lto -C panic=abort
// no-prefer-dynamic
// ignore-emscripten Function not implemented.
use std::process::Command;
use std::env;
......
......@@ -10,6 +10,7 @@
// compile-flags:-C lto -C panic=unwind
// no-prefer-dynamic
// ignore-emscripten Function not implemented.
use std::process::Command;
use std::env;
......
......@@ -7,6 +7,7 @@
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// ignore-emscripten Function not implemented.
use std::env;
use std::io;
......
......@@ -7,6 +7,7 @@
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// ignore-emscripten linking with emcc failed
#![feature(repr_simd, platform_intrinsics, concat_idents, test)]
#![allow(non_camel_case_types)]
......
......@@ -30,7 +30,7 @@ fn main() {
let data = Arc::new(Mutex::new(Vec::new()));
let sink = Sink(data.clone());
let res = thread::Builder::new().spawn(move|| -> () {
io::set_panic(Box::new(sink));
io::set_panic(Some(Box::new(sink)));
panic!("Hello, world!")
}).unwrap().join();
assert!(res.is_err());
......
......@@ -183,4 +183,5 @@ pub struct Config {
pub cflags: String,
pub llvm_components: String,
pub llvm_cxxflags: String,
pub nodejs: Option<String>,
}
......@@ -109,6 +109,7 @@ pub fn parse_config(args: Vec<String> ) -> Config {
reqopt("", "cflags", "flags for the C compiler", "FLAGS"),
reqopt("", "llvm-components", "list of LLVM components built in", "LIST"),
reqopt("", "llvm-cxxflags", "C++ flags for LLVM", "FLAGS"),
optopt("", "nodejs", "the name of nodejs", "PATH"),
optflag("h", "help", "show this message"));
let (argv0, args_) = args.split_first().unwrap();
......@@ -190,6 +191,7 @@ fn make_absolute(path: PathBuf) -> PathBuf {
cflags: matches.opt_str("cflags").unwrap(),
llvm_components: matches.opt_str("llvm-components").unwrap(),
llvm_cxxflags: matches.opt_str("llvm-cxxflags").unwrap(),
nodejs: matches.opt_str("nodejs"),
}
}
......@@ -431,10 +433,17 @@ pub fn make_test(config: &Config, testpaths: &TestPaths) -> test::TestDescAndFn
}
};
// Debugging emscripten code doesn't make sense today
let mut ignore = early_props.ignore;
if (config.mode == DebugInfoGdb || config.mode == DebugInfoLldb) &&
config.target.contains("emscripten") {
ignore = true;
}
test::TestDescAndFn {
desc: test::TestDesc {
name: make_test_name(config, testpaths),
ignore: early_props.ignore,
ignore: ignore,
should_panic: should_panic,
},
testfn: make_test_closure(config, testpaths),
......
......@@ -1168,7 +1168,6 @@ fn exec_compiled_test(&self) -> ProcRes {
"arm-linux-androideabi" | "armv7-linux-androideabi" | "aarch64-linux-android" => {
self._arm_exec_compiled_test(env)
}
_=> {
let aux_dir = self.aux_output_dir_name();
self.compose_and_run(self.make_run_args(),
......@@ -1421,7 +1420,7 @@ fn make_lib_name(&self, auxfile: &Path) -> PathBuf {
fn make_exe_name(&self) -> PathBuf {
let mut f = self.output_base_name();
// FIXME: This is using the host architecture exe suffix, not target!
if self.config.target == "asmjs-unknown-emscripten" {
if self.config.target.contains("emscripten") {
let mut fname = f.file_name().unwrap().to_os_string();
fname.push(".js");
f.set_file_name(&fname);
......@@ -1439,8 +1438,9 @@ fn make_run_args(&self) -> ProcArgs {
let mut args = self.split_maybe_args(&self.config.runtool);
// If this is emscripten, then run tests under nodejs
if self.config.target == "asmjs-unknown-emscripten" {
args.push("nodejs".to_owned());
if self.config.target.contains("emscripten") {
let nodejs = self.config.nodejs.clone().unwrap_or("nodejs".to_string());
args.push(nodejs);
}
let exe_file = self.make_exe_name();
......
......@@ -43,7 +43,8 @@
("sparc", "sparc"),
("x86_64", "x86_64"),
("xcore", "xcore"),
("asmjs", "asmjs")];
("asmjs", "asmjs"),
("wasm32", "wasm32")];
pub fn get_os(triple: &str) -> &'static str {
for &(triple_os, os) in OS_TABLE {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册