diff --git a/.gitmodules b/.gitmodules
index 2802c8d63913f..0a1188e83eae6 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -42,3 +42,9 @@
 [submodule "src/tools/miri"]
 	path = src/tools/miri
 	url = https://github.com/solson/miri.git
+[submodule "src/dlmalloc"]
+	path = src/dlmalloc
+	url = https://github.com/alexcrichton/dlmalloc-rs.git
+[submodule "src/binaryen"]
+	path = src/binaryen
+	url = https://github.com/alexcrichton/binaryen.git
diff --git a/src/Cargo.lock b/src/Cargo.lock
index bc20304945357..276980699a2f4 100644
--- a/src/Cargo.lock
+++ b/src/Cargo.lock
@@ -50,6 +50,7 @@ version = "0.0.0"
 dependencies = [
  "alloc 0.0.0",
  "core 0.0.0",
+ "dlmalloc 0.0.0",
  "libc 0.0.0",
 ]
 
@@ -372,9 +373,6 @@ version = "0.1.0"
 [[package]]
 name = "core"
 version = "0.0.0"
-dependencies = [
- "rand 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)",
-]
 
 [[package]]
 name = "core-foundation"
@@ -509,6 +507,14 @@ name = "diff"
 version = "0.1.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
+[[package]]
+name = "dlmalloc"
+version = "0.0.0"
+dependencies = [
+ "alloc 0.0.0",
+ "core 0.0.0",
+]
+
 [[package]]
 name = "docopt"
 version = "0.8.1"
@@ -1608,6 +1614,15 @@ dependencies = [
  "syntax 0.0.0",
 ]
 
+[[package]]
+name = "rustc_binaryen"
+version = "0.0.0"
+dependencies = [
+ "cc 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cmake 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
 [[package]]
 name = "rustc_borrowck"
 version = "0.0.0"
@@ -1880,6 +1895,7 @@ dependencies = [
  "rustc_allocator 0.0.0",
  "rustc_apfloat 0.0.0",
  "rustc_back 0.0.0",
+ "rustc_binaryen 0.0.0",
  "rustc_const_math 0.0.0",
  "rustc_data_structures 0.0.0",
  "rustc_errors 0.0.0",
diff --git a/src/binaryen b/src/binaryen
new file mode 160000
index 0000000000000..1c9bf65aa0e37
--- /dev/null
+++ b/src/binaryen
@@ -0,0 +1 @@
+Subproject commit 1c9bf65aa0e371b84755a8ddd6e79497fac57171
diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs
index 1401bc80a1ac2..4d69b19c7310f 100644
--- a/src/bootstrap/check.rs
+++ b/src/bootstrap/check.rs
@@ -1211,7 +1211,8 @@ impl Step for Crate {
                     // ends up messing with various mtime calculations and such.
                     if !name.contains("jemalloc") &&
                        *name != *"build_helper" &&
-                       !(name.starts_with("rustc_") && name.ends_with("san")) {
+                       !(name.starts_with("rustc_") && name.ends_with("san")) &&
+                       name != "dlmalloc" {
                         cargo.arg("-p").arg(&format!("{}:0.0.0", name));
                     }
                     for dep in build.crates[&name].deps.iter() {
diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs
index 7bf385301fab5..9f7e3de9dc051 100644
--- a/src/bootstrap/dist.rs
+++ b/src/bootstrap/dist.rs
@@ -672,6 +672,9 @@ fn copy_src_dirs(build: &Build, src_dirs: &[&str], exclude_dirs: &[&str], dst_di
              spath.ends_with(".s")) {
             return false
         }
+        if spath.contains("test/emscripten") || spath.contains("test\\emscripten") {
+            return false
+        }
 
         let full_path = Path::new(dir).join(path);
         if exclude_dirs.iter().any(|excl| full_path == Path::new(excl)) {
@@ -736,6 +739,7 @@ impl Step for Src {
         // (essentially libstd and all of its path dependencies)
         let std_src_dirs = [
             "src/build_helper",
+            "src/dlmalloc",
             "src/liballoc",
             "src/liballoc_jemalloc",
             "src/liballoc_system",
@@ -754,6 +758,7 @@ impl Step for Src {
             "src/libunwind",
             "src/rustc/compiler_builtins_shim",
             "src/rustc/libc_shim",
+            "src/rustc/dlmalloc_shim",
             "src/libtest",
             "src/libterm",
             "src/jemalloc",
diff --git a/src/dlmalloc b/src/dlmalloc
new file mode 160000
index 0000000000000..d3812c3accaee
--- /dev/null
+++ b/src/dlmalloc
@@ -0,0 +1 @@
+Subproject commit d3812c3accaee7ad23068ed4fc089cc05c7a538f
diff --git a/src/etc/wasm32-shim.js b/src/etc/wasm32-shim.js
new file mode 100644
index 0000000000000..b595cc1205336
--- /dev/null
+++ b/src/etc/wasm32-shim.js
@@ -0,0 +1,119 @@
+// Copyright 2017 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.
+
+// This is a small "shim" program which is used when wasm32 unit tests are run
+// in this repository. This program is intended to be run in node.js and will
+// load a wasm module into memory, instantiate it with a set of imports, and
+// then run it.
+//
+// There's a bunch of helper functions defined here in `imports.env`, but note
+// that most of them aren't actually needed to execute most programs. Many of
+// these are just intended for completeness or debugging. Hopefully over time
+// nothing here is needed for completeness.
+
+const fs = require('fs');
+const process = require('process');
+const buffer = fs.readFileSync(process.argv[2]);
+
+Error.stackTraceLimit = 20;
+
+let m = new WebAssembly.Module(buffer);
+
+let memory = null;
+
+function copystr(a, b) {
+  if (memory === null) {
+    return null
+  }
+  let view = new Uint8Array(memory.buffer).slice(a, a + b);
+  return String.fromCharCode.apply(null, view);
+}
+
+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); },
+  log10: function(x) { return Math.log10(x); },
+  log10f: function(x) { return Math.log10(x); },
+
+  // These are called in src/libstd/sys/wasm/stdio.rs and are used when
+  // debugging is enabled.
+  rust_wasm_write_stdout: function(a, b) {
+    let s = copystr(a, b);
+    if (s !== null) {
+      process.stdout.write(s);
+    }
+  },
+  rust_wasm_write_stderr: function(a, b) {
+    let s = copystr(a, b);
+    if (s !== null) {
+      process.stderr.write(s);
+    }
+  },
+
+  // These are called in src/libstd/sys/wasm/args.rs and are used when
+  // debugging is enabled.
+  rust_wasm_args_count: function() {
+    if (memory === null)
+      return 0;
+    return process.argv.length - 2;
+  },
+  rust_wasm_args_arg_size: function(i) {
+    return process.argv[i + 2].length;
+  },
+  rust_wasm_args_arg_fill: function(idx, ptr) {
+    let arg = process.argv[idx + 2];
+    let view = new Uint8Array(memory.buffer);
+    for (var i = 0; i < arg.length; i++) {
+      view[ptr + i] = arg.charCodeAt(i);
+    }
+  },
+
+  // These are called in src/libstd/sys/wasm/os.rs and are used when
+  // debugging is enabled.
+  rust_wasm_getenv_len: function(a, b) {
+    let key = copystr(a, b);
+    if (key === null) {
+      return -1;
+    }
+    if (!(key in process.env)) {
+      return -1;
+    }
+    return process.env[key].length;
+  },
+  rust_wasm_getenv_data: function(a, b, ptr) {
+    let key = copystr(a, b);
+    let value = process.env[key];
+    let view = new Uint8Array(memory.buffer);
+    for (var i = 0; i < value.length; i++) {
+      view[ptr + i] = value.charCodeAt(i);
+    }
+  },
+};
+
+let module_imports = WebAssembly.Module.imports(m);
+
+for (var i = 0; i < module_imports.length; i++) {
+  let imp = module_imports[i];
+  if (imp.module != 'env') {
+    continue
+  }
+  if (imp.name == 'memory' && imp.kind == 'memory') {
+    memory = new WebAssembly.Memory({initial: 20});
+    imports.env.memory = memory;
+  }
+}
+
+let instance = new WebAssembly.Instance(m, imports);
diff --git a/src/liballoc_jemalloc/build.rs b/src/liballoc_jemalloc/build.rs
index 65e035d4ffdef..a41a04d7cd4f6 100644
--- a/src/liballoc_jemalloc/build.rs
+++ b/src/liballoc_jemalloc/build.rs
@@ -31,7 +31,7 @@ fn main() {
     let host = env::var("HOST").expect("HOST was not set");
     if target.contains("rumprun") || target.contains("bitrig") || target.contains("openbsd") ||
        target.contains("msvc") || target.contains("emscripten") || target.contains("fuchsia") ||
-       target.contains("redox") {
+       target.contains("redox") || target.contains("wasm32") {
         println!("cargo:rustc-cfg=dummy_jemalloc");
         return;
     }
diff --git a/src/liballoc_system/Cargo.toml b/src/liballoc_system/Cargo.toml
index a725a8608be29..f9a57f7d97a74 100644
--- a/src/liballoc_system/Cargo.toml
+++ b/src/liballoc_system/Cargo.toml
@@ -13,3 +13,7 @@ doc = false
 alloc = { path = "../liballoc" }
 core = { path = "../libcore" }
 libc = { path = "../rustc/libc_shim" }
+
+# See comments in the source for what this dependency is
+[target.'cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))'.dependencies]
+dlmalloc = { path = "../rustc/dlmalloc_shim" }
diff --git a/src/liballoc_system/lib.rs b/src/liballoc_system/lib.rs
index 7aa5f8a9186b0..05cacf6e88195 100644
--- a/src/liballoc_system/lib.rs
+++ b/src/liballoc_system/lib.rs
@@ -34,12 +34,14 @@
               target_arch = "powerpc64",
               target_arch = "asmjs",
               target_arch = "wasm32")))]
+#[allow(dead_code)]
 const MIN_ALIGN: usize = 8;
 #[cfg(all(any(target_arch = "x86_64",
               target_arch = "aarch64",
               target_arch = "mips64",
               target_arch = "s390x",
               target_arch = "sparc64")))]
+#[allow(dead_code)]
 const MIN_ALIGN: usize = 16;
 
 extern crate alloc;
@@ -458,3 +460,91 @@ mod platform {
         }
     }
 }
+
+// This is an implementation of a global allocator on the wasm32 platform when
+// emscripten is not in use. In that situation there's no actual runtime for us
+// to lean on for allocation, so instead we provide our own!
+//
+// The wasm32 instruction set has two instructions for getting the current
+// amount of memory and growing the amount of memory. These instructions are the
+// foundation on which we're able to build an allocator, so we do so! Note that
+// the instructions are also pretty "global" and this is the "global" allocator
+// after all!
+//
+// The current allocator here is the `dlmalloc` crate which we've got included
+// in the rust-lang/rust repository as a submodule. The crate is a port of
+// dlmalloc.c from C to Rust and is basically just so we can have "pure Rust"
+// for now which is currently technically required (can't link with C yet).
+//
+// The crate itself provides a global allocator which on wasm has no
+// synchronization as there are no threads!
+#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
+mod platform {
+    extern crate dlmalloc;
+
+    use alloc::heap::{Alloc, AllocErr, Layout, Excess, CannotReallocInPlace};
+    use System;
+    use self::dlmalloc::GlobalDlmalloc;
+
+    #[unstable(feature = "allocator_api", issue = "32838")]
+    unsafe impl<'a> Alloc for &'a System {
+        #[inline]
+        unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> {
+            GlobalDlmalloc.alloc(layout)
+        }
+
+        #[inline]
+        unsafe fn alloc_zeroed(&mut self, layout: Layout)
+            -> Result<*mut u8, AllocErr>
+        {
+            GlobalDlmalloc.alloc_zeroed(layout)
+        }
+
+        #[inline]
+        unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) {
+            GlobalDlmalloc.dealloc(ptr, layout)
+        }
+
+        #[inline]
+        unsafe fn realloc(&mut self,
+                          ptr: *mut u8,
+                          old_layout: Layout,
+                          new_layout: Layout) -> Result<*mut u8, AllocErr> {
+            GlobalDlmalloc.realloc(ptr, old_layout, new_layout)
+        }
+
+        #[inline]
+        fn usable_size(&self, layout: &Layout) -> (usize, usize) {
+            GlobalDlmalloc.usable_size(layout)
+        }
+
+        #[inline]
+        unsafe fn alloc_excess(&mut self, layout: Layout) -> Result<Excess, AllocErr> {
+            GlobalDlmalloc.alloc_excess(layout)
+        }
+
+        #[inline]
+        unsafe fn realloc_excess(&mut self,
+                                 ptr: *mut u8,
+                                 layout: Layout,
+                                 new_layout: Layout) -> Result<Excess, AllocErr> {
+            GlobalDlmalloc.realloc_excess(ptr, layout, new_layout)
+        }
+
+        #[inline]
+        unsafe fn grow_in_place(&mut self,
+                                ptr: *mut u8,
+                                layout: Layout,
+                                new_layout: Layout) -> Result<(), CannotReallocInPlace> {
+            GlobalDlmalloc.grow_in_place(ptr, layout, new_layout)
+        }
+
+        #[inline]
+        unsafe fn shrink_in_place(&mut self,
+                                  ptr: *mut u8,
+                                  layout: Layout,
+                                  new_layout: Layout) -> Result<(), CannotReallocInPlace> {
+            GlobalDlmalloc.shrink_in_place(ptr, layout, new_layout)
+        }
+    }
+}
diff --git a/src/libcore/Cargo.toml b/src/libcore/Cargo.toml
index d1a0a5f09e0d5..5af63aa970f2c 100644
--- a/src/libcore/Cargo.toml
+++ b/src/libcore/Cargo.toml
@@ -9,9 +9,6 @@ path = "lib.rs"
 test = false
 bench = false
 
-[dev-dependencies]
-rand = "0.3"
-
 [[test]]
 name = "coretests"
 path = "../libcore/tests/lib.rs"
diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs
index afc5de7b0ee35..edf7f44e5925c 100644
--- a/src/libcore/tests/lib.rs
+++ b/src/libcore/tests/lib.rs
@@ -27,7 +27,6 @@
 #![feature(iter_rfind)]
 #![feature(iter_rfold)]
 #![feature(nonzero)]
-#![feature(rand)]
 #![feature(raw)]
 #![feature(refcell_replace_swap)]
 #![feature(sip_hash_13)]
@@ -48,7 +47,6 @@
 
 extern crate core;
 extern crate test;
-extern crate rand;
 
 mod any;
 mod array;
diff --git a/src/libcore/tests/num/flt2dec/mod.rs b/src/libcore/tests/num/flt2dec/mod.rs
index 2720c5c8677af..ef0178815f98b 100644
--- a/src/libcore/tests/num/flt2dec/mod.rs
+++ b/src/libcore/tests/num/flt2dec/mod.rs
@@ -9,9 +9,7 @@
 // except according to those terms.
 
 use std::prelude::v1::*;
-use std::{str, mem, i16, f32, f64, fmt};
-use rand::{self, Rand, XorShiftRng};
-use rand::distributions::{IndependentSample, Range};
+use std::{str, i16, f32, f64, fmt};
 
 use core::num::flt2dec::{decode, DecodableFloat, FullDecoded, Decoded};
 use core::num::flt2dec::{MAX_SIG_DIGITS, round_up, Part, Formatted, Sign};
@@ -463,87 +461,6 @@ pub fn more_shortest_sanity_test<F>(mut f: F) where F: FnMut(&Decoded, &mut [u8]
                       exp: 0, inclusive: false} => b"99999999999999999", 17);
 }
 
-fn iterate<F, G, V>(func: &str, k: usize, n: usize, mut f: F, mut g: G, mut v: V) -> (usize, usize)
-        where F: FnMut(&Decoded, &mut [u8]) -> Option<(usize, i16)>,
-              G: FnMut(&Decoded, &mut [u8]) -> (usize, i16),
-              V: FnMut(usize) -> Decoded {
-    assert!(k <= 1024);
-
-    let mut npassed = 0; // f(x) = Some(g(x))
-    let mut nignored = 0; // f(x) = None
-
-    for i in 0..n {
-        if (i & 0xfffff) == 0 {
-            println!("in progress, {:x}/{:x} (ignored={} passed={} failed={})",
-                     i, n, nignored, npassed, i - nignored - npassed);
-        }
-
-        let decoded = v(i);
-        let mut buf1 = [0; 1024];
-        if let Some((len1, e1)) = f(&decoded, &mut buf1[..k]) {
-            let mut buf2 = [0; 1024];
-            let (len2, e2) = g(&decoded, &mut buf2[..k]);
-            if e1 == e2 && &buf1[..len1] == &buf2[..len2] {
-                npassed += 1;
-            } else {
-                println!("equivalence test failed, {:x}/{:x}: {:?} f(i)={}e{} g(i)={}e{}",
-                         i, n, decoded, str::from_utf8(&buf1[..len1]).unwrap(), e1,
-                                        str::from_utf8(&buf2[..len2]).unwrap(), e2);
-            }
-        } else {
-            nignored += 1;
-        }
-    }
-    println!("{}({}): done, ignored={} passed={} failed={}",
-             func, k, nignored, npassed, n - nignored - npassed);
-    assert!(nignored + npassed == n,
-            "{}({}): {} out of {} values returns an incorrect value!",
-            func, k, n - nignored - npassed, n);
-    (npassed, nignored)
-}
-
-pub fn f32_random_equivalence_test<F, G>(f: F, g: G, k: usize, n: usize)
-        where F: FnMut(&Decoded, &mut [u8]) -> Option<(usize, i16)>,
-              G: FnMut(&Decoded, &mut [u8]) -> (usize, i16) {
-    let mut rng: XorShiftRng = Rand::rand(&mut rand::thread_rng());
-    let f32_range = Range::new(0x0000_0001u32, 0x7f80_0000);
-    iterate("f32_random_equivalence_test", k, n, f, g, |_| {
-        let i: u32 = f32_range.ind_sample(&mut rng);
-        let x: f32 = unsafe {mem::transmute(i)};
-        decode_finite(x)
-    });
-}
-
-pub fn f64_random_equivalence_test<F, G>(f: F, g: G, k: usize, n: usize)
-        where F: FnMut(&Decoded, &mut [u8]) -> Option<(usize, i16)>,
-              G: FnMut(&Decoded, &mut [u8]) -> (usize, i16) {
-    let mut rng: XorShiftRng = Rand::rand(&mut rand::thread_rng());
-    let f64_range = Range::new(0x0000_0000_0000_0001u64, 0x7ff0_0000_0000_0000);
-    iterate("f64_random_equivalence_test", k, n, f, g, |_| {
-        let i: u64 = f64_range.ind_sample(&mut rng);
-        let x: f64 = unsafe {mem::transmute(i)};
-        decode_finite(x)
-    });
-}
-
-pub fn f32_exhaustive_equivalence_test<F, G>(f: F, g: G, k: usize)
-        where F: FnMut(&Decoded, &mut [u8]) -> Option<(usize, i16)>,
-              G: FnMut(&Decoded, &mut [u8]) -> (usize, i16) {
-    // we have only 2^23 * (2^8 - 1) - 1 = 2,139,095,039 positive finite f32 values,
-    // so why not simply testing all of them?
-    //
-    // this is of course very stressful (and thus should be behind an `#[ignore]` attribute),
-    // but with `-C opt-level=3 -C lto` this only takes about an hour or so.
-
-    // iterate from 0x0000_0001 to 0x7f7f_ffff, i.e. all finite ranges
-    let (npassed, nignored) = iterate("f32_exhaustive_equivalence_test",
-                                      k, 0x7f7f_ffff, f, g, |i: usize| {
-        let x: f32 = unsafe {mem::transmute(i as u32 + 1)};
-        decode_finite(x)
-    });
-    assert_eq!((npassed, nignored), (2121451881, 17643158));
-}
-
 fn to_string_with_parts<F>(mut f: F) -> String
         where F: for<'a> FnMut(&'a mut [u8], &'a mut [Part<'a>]) -> Formatted<'a> {
     let mut buf = [0; 1024];
diff --git a/src/libcore/tests/num/flt2dec/strategy/grisu.rs b/src/libcore/tests/num/flt2dec/strategy/grisu.rs
index 17fb99bcc9224..286b39d8cf3b3 100644
--- a/src/libcore/tests/num/flt2dec/strategy/grisu.rs
+++ b/src/libcore/tests/num/flt2dec/strategy/grisu.rs
@@ -8,7 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use std::i16;
 use super::super::*;
 use core::num::flt2dec::strategy::grisu::*;
 
@@ -46,35 +45,6 @@ fn shortest_sanity_test() {
     more_shortest_sanity_test(format_shortest);
 }
 
-#[test]
-fn shortest_random_equivalence_test() {
-    use core::num::flt2dec::strategy::dragon::format_shortest as fallback;
-    f64_random_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS, 10_000);
-    f32_random_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS, 10_000);
-}
-
-#[test] #[ignore] // it is too expensive
-fn shortest_f32_exhaustive_equivalence_test() {
-    // it is hard to directly test the optimality of the output, but we can at least test if
-    // two different algorithms agree to each other.
-    //
-    // this reports the progress and the number of f32 values returned `None`.
-    // with `--nocapture` (and plenty of time and appropriate rustc flags), this should print:
-    // `done, ignored=17643158 passed=2121451881 failed=0`.
-
-    use core::num::flt2dec::strategy::dragon::format_shortest as fallback;
-    f32_exhaustive_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS);
-}
-
-#[test] #[ignore] // it is too expensive
-fn shortest_f64_hard_random_equivalence_test() {
-    // this again probably has to use appropriate rustc flags.
-
-    use core::num::flt2dec::strategy::dragon::format_shortest as fallback;
-    f64_random_equivalence_test(format_shortest_opt, fallback,
-                                         MAX_SIG_DIGITS, 100_000_000);
-}
-
 #[test]
 fn exact_sanity_test() {
     // See comments in dragon.rs's exact_sanity_test for why this test is
@@ -85,24 +55,6 @@ fn exact_sanity_test() {
     f32_exact_sanity_test(format_exact);
 }
 
-#[test]
-fn exact_f32_random_equivalence_test() {
-    use core::num::flt2dec::strategy::dragon::format_exact as fallback;
-    for k in 1..21 {
-        f32_random_equivalence_test(|d, buf| format_exact_opt(d, buf, i16::MIN),
-                                             |d, buf| fallback(d, buf, i16::MIN), k, 1_000);
-    }
-}
-
-#[test]
-fn exact_f64_random_equivalence_test() {
-    use core::num::flt2dec::strategy::dragon::format_exact as fallback;
-    for k in 1..21 {
-        f64_random_equivalence_test(|d, buf| format_exact_opt(d, buf, i16::MIN),
-                                             |d, buf| fallback(d, buf, i16::MIN), k, 1_000);
-    }
-}
-
 #[test]
 fn test_to_shortest_str() {
     to_shortest_str_test(format_shortest);
diff --git a/src/libcore/tests/slice.rs b/src/libcore/tests/slice.rs
index 7835080db1d45..60e4e6d2ff328 100644
--- a/src/libcore/tests/slice.rs
+++ b/src/libcore/tests/slice.rs
@@ -8,10 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use core::cmp::Ordering::{Equal, Greater, Less};
-use core::slice::heapsort;
 use core::result::Result::{Ok, Err};
-use rand::{Rng, XorShiftRng};
 
 #[test]
 fn test_binary_search() {
@@ -290,68 +287,3 @@ fn test_rotate() {
         assert_eq!(a[(i+k)%N], i);
     }
 }
-
-#[test]
-fn sort_unstable() {
-    let mut v = [0; 600];
-    let mut tmp = [0; 600];
-    let mut rng = XorShiftRng::new_unseeded();
-
-    for len in (2..25).chain(500..510) {
-        let v = &mut v[0..len];
-        let tmp = &mut tmp[0..len];
-
-        for &modulus in &[5, 10, 100, 1000] {
-            for _ in 0..100 {
-                for i in 0..len {
-                    v[i] = rng.gen::<i32>() % modulus;
-                }
-
-                // Sort in default order.
-                tmp.copy_from_slice(v);
-                tmp.sort_unstable();
-                assert!(tmp.windows(2).all(|w| w[0] <= w[1]));
-
-                // Sort in ascending order.
-                tmp.copy_from_slice(v);
-                tmp.sort_unstable_by(|a, b| a.cmp(b));
-                assert!(tmp.windows(2).all(|w| w[0] <= w[1]));
-
-                // Sort in descending order.
-                tmp.copy_from_slice(v);
-                tmp.sort_unstable_by(|a, b| b.cmp(a));
-                assert!(tmp.windows(2).all(|w| w[0] >= w[1]));
-
-                // Test heapsort using `<` operator.
-                tmp.copy_from_slice(v);
-                heapsort(tmp, |a, b| a < b);
-                assert!(tmp.windows(2).all(|w| w[0] <= w[1]));
-
-                // Test heapsort using `>` operator.
-                tmp.copy_from_slice(v);
-                heapsort(tmp, |a, b| a > b);
-                assert!(tmp.windows(2).all(|w| w[0] >= w[1]));
-            }
-        }
-    }
-
-    // Sort using a completely random comparison function.
-    // This will reorder the elements *somehow*, but won't panic.
-    for i in 0..v.len() {
-        v[i] = i as i32;
-    }
-    v.sort_unstable_by(|_, _| *rng.choose(&[Less, Equal, Greater]).unwrap());
-    v.sort_unstable();
-    for i in 0..v.len() {
-        assert_eq!(v[i], i as i32);
-    }
-
-    // Should not panic.
-    [0i32; 0].sort_unstable();
-    [(); 10].sort_unstable();
-    [(); 100].sort_unstable();
-
-    let mut v = [0xDEADBEEFu64];
-    v.sort_unstable();
-    assert!(v == [0xDEADBEEF]);
-}
diff --git a/src/libpanic_abort/lib.rs b/src/libpanic_abort/lib.rs
index 8be6f6470231d..29a9e1aadaf3c 100644
--- a/src/libpanic_abort/lib.rs
+++ b/src/libpanic_abort/lib.rs
@@ -20,13 +20,13 @@
        html_root_url = "https://doc.rust-lang.org/nightly/",
        issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/")]
 #![deny(warnings)]
-
-#![feature(staged_api)]
-
 #![panic_runtime]
+#![allow(unused_features)]
+
+#![feature(core_intrinsics)]
+#![feature(libc)]
 #![feature(panic_runtime)]
-#![cfg_attr(unix, feature(libc))]
-#![cfg_attr(any(target_os = "redox", windows), feature(core_intrinsics))]
+#![feature(staged_api)]
 
 // Rust's "try" function, but if we're aborting on panics we just call the
 // function as there's nothing else we need to do here.
@@ -59,7 +59,9 @@ pub unsafe extern fn __rust_start_panic(_data: usize, _vtable: usize) -> u32 {
         libc::abort();
     }
 
-    #[cfg(any(target_os = "redox", windows))]
+    #[cfg(any(target_os = "redox",
+              windows,
+              all(target_arch = "wasm32", not(target_os = "emscripten"))))]
     unsafe fn abort() -> ! {
         core::intrinsics::abort();
     }
@@ -92,7 +94,6 @@ pub unsafe extern fn __rust_start_panic(_data: usize, _vtable: usize) -> u32 {
 // binaries, but it should never be called as we don't link in an unwinding
 // runtime at all.
 pub mod personalities {
-
     #[no_mangle]
     #[cfg(not(all(target_os = "windows",
                   target_env = "gnu",
diff --git a/src/libpanic_unwind/lib.rs b/src/libpanic_unwind/lib.rs
index 558286f4ec070..6b8da7a51ceb8 100644
--- a/src/libpanic_unwind/lib.rs
+++ b/src/libpanic_unwind/lib.rs
@@ -34,9 +34,7 @@
 #![feature(core_intrinsics)]
 #![feature(lang_items)]
 #![feature(libc)]
-#![cfg_attr(not(any(target_env = "msvc",
-                    all(windows, target_arch = "x86_64", target_env = "gnu"))),
-            feature(panic_unwind))]
+#![feature(panic_unwind)]
 #![feature(raw)]
 #![feature(staged_api)]
 #![feature(unwind_attributes)]
@@ -80,6 +78,10 @@ mod imp;
 #[path = "emcc.rs"]
 mod imp;
 
+#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
+#[path = "wasm32.rs"]
+mod imp;
+
 mod dwarf;
 mod windows;
 
diff --git a/src/libpanic_unwind/wasm32.rs b/src/libpanic_unwind/wasm32.rs
new file mode 100644
index 0000000000000..8aed61b3c385a
--- /dev/null
+++ b/src/libpanic_unwind/wasm32.rs
@@ -0,0 +1,29 @@
+// 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 wasm32
+//!
+//! Right now we don't support this, so this is just stubs
+
+use alloc::boxed::Box;
+use core::any::Any;
+use core::intrinsics;
+
+pub fn payload() -> *mut u8 {
+    0 as *mut u8
+}
+
+pub unsafe fn cleanup(_ptr: *mut u8) -> Box<Any + Send> {
+    intrinsics::abort()
+}
+
+pub unsafe fn panic(_data: Box<Any + Send>) -> u32 {
+    intrinsics::abort()
+}
diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs
index 00a91eeb9c18e..9f957cd780829 100644
--- a/src/librustc/session/mod.rs
+++ b/src/librustc/session/mod.rs
@@ -432,7 +432,7 @@ impl Session {
             self.opts.debugging_opts.borrowck_mir
     }
     pub fn lto(&self) -> bool {
-        self.opts.cg.lto
+        self.opts.cg.lto || self.target.target.options.requires_lto
     }
     /// Returns the panic strategy for this compile session. If the user explicitly selected one
     /// using '-C panic', use that, otherwise use the panic strategy defined by the target.
diff --git a/src/librustc_back/lib.rs b/src/librustc_back/lib.rs
index d67de123415f2..824b553104760 100644
--- a/src/librustc_back/lib.rs
+++ b/src/librustc_back/lib.rs
@@ -84,6 +84,7 @@ macro_rules! linker_flavor {
 
 linker_flavor! {
     (Em, "em"),
+    (Binaryen, "binaryen"),
     (Gcc, "gcc"),
     (Ld, "ld"),
     (Msvc, "msvc"),
diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs
index d60d6438b4d61..7599a60ba5ada 100644
--- a/src/librustc_back/target/mod.rs
+++ b/src/librustc_back/target/mod.rs
@@ -218,6 +218,7 @@ supported_targets! {
 
     ("asmjs-unknown-emscripten", asmjs_unknown_emscripten),
     ("wasm32-unknown-emscripten", wasm32_unknown_emscripten),
+    ("wasm32-unknown-unknown", wasm32_unknown_unknown),
     ("wasm32-experimental-emscripten", wasm32_experimental_emscripten),
 
     ("thumbv6m-none-eabi", thumbv6m_none_eabi),
@@ -303,6 +304,8 @@ pub struct TargetOptions {
     pub features: String,
     /// Whether dynamic linking is available on this target. Defaults to false.
     pub dynamic_linking: bool,
+    /// If dynamic linking is available, whether only cdylibs are supported.
+    pub only_cdylib: bool,
     /// Whether executables are available on this target. iOS, for example, only allows static
     /// libraries. Defaults to false.
     pub executables: bool,
@@ -439,6 +442,17 @@ pub struct TargetOptions {
     /// Whether to generate trap instructions in places where optimization would
     /// otherwise produce control flow that falls through into unrelated memory.
     pub trap_unreachable: bool,
+
+    /// This target requires everything to be compiled with LTO to emit a final
+    /// executable, aka there is no native linker for this target.
+    pub requires_lto: bool,
+
+    /// This target has no support for threads.
+    pub singlethread: bool,
+
+    /// Whether library functions call lowering/optimization is disabled in LLVM
+    /// for this target unconditionally.
+    pub no_builtins: bool,
 }
 
 impl Default for TargetOptions {
@@ -454,6 +468,7 @@ impl Default for TargetOptions {
             cpu: "generic".to_string(),
             features: "".to_string(),
             dynamic_linking: false,
+            only_cdylib: false,
             executables: false,
             relocation_model: "pic".to_string(),
             code_model: "default".to_string(),
@@ -503,6 +518,9 @@ impl Default for TargetOptions {
             min_global_align: None,
             default_codegen_units: None,
             trap_unreachable: true,
+            requires_lto: false,
+            singlethread: false,
+            no_builtins: false,
         }
     }
 }
@@ -702,6 +720,7 @@ impl Target {
         key!(cpu);
         key!(features);
         key!(dynamic_linking, bool);
+        key!(only_cdylib, bool);
         key!(executables, bool);
         key!(relocation_model);
         key!(code_model);
@@ -745,6 +764,9 @@ impl Target {
         key!(min_global_align, Option<u64>);
         key!(default_codegen_units, Option<u64>);
         key!(trap_unreachable, bool);
+        key!(requires_lto, bool);
+        key!(singlethread, bool);
+        key!(no_builtins, bool);
 
         if let Some(array) = obj.find("abi-blacklist").and_then(Json::as_array) {
             for name in array.iter().filter_map(|abi| abi.as_string()) {
@@ -896,6 +918,7 @@ impl ToJson for Target {
         target_option_val!(cpu);
         target_option_val!(features);
         target_option_val!(dynamic_linking);
+        target_option_val!(only_cdylib);
         target_option_val!(executables);
         target_option_val!(relocation_model);
         target_option_val!(code_model);
@@ -939,6 +962,9 @@ impl ToJson for Target {
         target_option_val!(min_global_align);
         target_option_val!(default_codegen_units);
         target_option_val!(trap_unreachable);
+        target_option_val!(requires_lto);
+        target_option_val!(singlethread);
+        target_option_val!(no_builtins);
 
         if default.abi_blacklist != self.options.abi_blacklist {
             d.insert("abi-blacklist".to_string(), self.options.abi_blacklist.iter()
diff --git a/src/librustc_back/target/wasm32_unknown_unknown.rs b/src/librustc_back/target/wasm32_unknown_unknown.rs
new file mode 100644
index 0000000000000..7e1011ab8af96
--- /dev/null
+++ b/src/librustc_back/target/wasm32_unknown_unknown.rs
@@ -0,0 +1,104 @@
+// Copyright 2017 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.
+
+// The wasm32-unknown-unknown target is currently a highly experimental version
+// of a wasm-based target which does *not* use the Emscripten toolchain. Instead
+// this is a pretty flavorful (aka hacked up) target right now. The definition
+// and semantics of this target are likely to change and so this shouldn't be
+// relied on just yet.
+//
+// In general everyone is currently waiting on a linker for wasm code. In the
+// meantime we have no means of actually making use of the traditional separate
+// compilation model. At a high level this means that assembling Rust programs
+// into a WebAssembly program looks like:
+//
+//  1. All intermediate artifacts are LLVM bytecode. We'll be using LLVM as
+//     a linker later on.
+//  2. For the final artifact we emit one giant assembly file (WebAssembly
+//     doesn't have an object file format). To do this we force LTO to be turned
+//     on (`requires_lto` below) to ensure all Rust code is in one module. Any
+//     "linked" C library is basically just ignored.
+//  3. Using LLVM we emit a `foo.s` file (assembly) with some... what I can only
+//     describe as arcane syntax. From there we need to actually change this
+//     into a wasm module. For this step we use the `binaryen` project. This
+//     project is mostly intended as a WebAssembly code generator, but for now
+//     we're just using its LLVM-assembly-to-wasm-module conversion utilities.
+//
+// And voila, out comes a web assembly module! There's some various tweaks here
+// and there, but that's the high level at least. Note that this will be
+// rethought from the ground up once a linker (lld) is available, so this is all
+// temporary and should improve in the future.
+
+use LinkerFlavor;
+use super::{Target, TargetOptions, PanicStrategy};
+
+pub fn target() -> Result<Target, String> {
+    let opts = TargetOptions {
+        linker: "not-used".to_string(),
+
+        // we allow dynamic linking, but only cdylibs. Basically we allow a
+        // final library artifact that exports some symbols (a wasm module) but
+        // we don't allow intermediate `dylib` crate types
+        dynamic_linking: true,
+        only_cdylib: true,
+
+        // This means we'll just embed a `start` function in the wasm module
+        executables: true,
+
+        // relatively self-explanatory!
+        exe_suffix: ".wasm".to_string(),
+        dll_prefix: "".to_string(),
+        dll_suffix: ".wasm".to_string(),
+        linker_is_gnu: false,
+
+        // We're storing bitcode for now in all the rlibs
+        obj_is_bitcode: true,
+
+        // A bit of a lie, but "eh"
+        max_atomic_width: Some(32),
+
+        // Unwinding doesn't work right now, so the whole target unconditionally
+        // defaults to panic=abort. Note that this is guaranteed to change in
+        // the future once unwinding is implemented. Don't rely on this.
+        panic_strategy: PanicStrategy::Abort,
+
+        // There's no linker yet so we're forced to use LLVM as a linker. This
+        // means that we must always enable LTO for final artifacts.
+        requires_lto: true,
+
+        // Wasm doesn't have atomics yet, so tell LLVM that we're in a single
+        // threaded model which will legalize atomics to normal operations.
+        singlethread: true,
+
+        // Because we're always enabling LTO we can't enable builtin lowering as
+        // otherwise we'll lower the definition of the `memcpy` function to
+        // memcpy itself. Note that this is specifically because we're
+        // performing LTO with compiler-builtins.
+        no_builtins: true,
+
+        .. Default::default()
+    };
+    Ok(Target {
+        llvm_target: "wasm32-unknown-unknown".to_string(),
+        target_endian: "little".to_string(),
+        target_pointer_width: "32".to_string(),
+        target_c_int_width: "32".to_string(),
+        // This is basically guaranteed to change in the future, don't rely on
+        // this. Use `not(target_os = "emscripten")` for now.
+        target_os: "unknown".to_string(),
+        target_env: "".to_string(),
+        target_vendor: "unknown".to_string(),
+        data_layout: "e-m:e-p:32:32-i64:64-n32:64-S128".to_string(),
+        arch: "wasm32".to_string(),
+        // A bit of a lie, but it gets the job done
+        linker_flavor: LinkerFlavor::Binaryen,
+        options: opts,
+    })
+}
diff --git a/src/librustc_binaryen/BinaryenWrapper.cpp b/src/librustc_binaryen/BinaryenWrapper.cpp
new file mode 100644
index 0000000000000..d1095a7819d4a
--- /dev/null
+++ b/src/librustc_binaryen/BinaryenWrapper.cpp
@@ -0,0 +1,132 @@
+// Copyright 2017 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.
+
+// This is a small C API inserted on top of the Binaryen C++ API which we use
+// from Rust. Once we have a real linker for we'll be able to remove all this,
+// and otherwise this is just all on a "as we need it" basis for now.
+
+#include <stdint.h>
+#include <string>
+#include <stdlib.h>
+
+#include "s2wasm.h"
+#include "wasm-binary.h"
+#include "wasm-linker.h"
+
+using namespace wasm;
+
+struct BinaryenRustModule {
+  BufferWithRandomAccess buffer;
+};
+
+struct BinaryenRustModuleOptions {
+  uint64_t globalBase;
+  bool debug;
+  uint64_t stackAllocation;
+  uint64_t initialMem;
+  uint64_t maxMem;
+  bool importMemory;
+  bool ignoreUnknownSymbols;
+  bool debugInfo;
+  std::string startFunction;
+
+  BinaryenRustModuleOptions() :
+    globalBase(0),
+    debug(false),
+    stackAllocation(0),
+    initialMem(0),
+    maxMem(0),
+    importMemory(false),
+    ignoreUnknownSymbols(false),
+    debugInfo(false),
+    startFunction("")
+  {}
+
+};
+
+extern "C" BinaryenRustModuleOptions*
+BinaryenRustModuleOptionsCreate() {
+  return new BinaryenRustModuleOptions;
+}
+
+extern "C" void
+BinaryenRustModuleOptionsFree(BinaryenRustModuleOptions *options) {
+  delete options;
+}
+
+extern "C" void
+BinaryenRustModuleOptionsSetDebugInfo(BinaryenRustModuleOptions *options,
+                                      bool debugInfo) {
+  options->debugInfo = debugInfo;
+}
+
+extern "C" void
+BinaryenRustModuleOptionsSetStart(BinaryenRustModuleOptions *options,
+                                  char *start) {
+  options->startFunction = start;
+}
+
+extern "C" void
+BinaryenRustModuleOptionsSetStackAllocation(BinaryenRustModuleOptions *options,
+                                            uint64_t stack) {
+  options->stackAllocation = stack;
+}
+
+extern "C" void
+BinaryenRustModuleOptionsSetImportMemory(BinaryenRustModuleOptions *options,
+                                         bool import) {
+  options->importMemory = import;
+}
+
+extern "C" BinaryenRustModule*
+BinaryenRustModuleCreate(const BinaryenRustModuleOptions *options,
+                         const char *assembly) {
+  Linker linker(
+      options->globalBase,
+      options->stackAllocation,
+      options->initialMem,
+      options->maxMem,
+      options->importMemory,
+      options->ignoreUnknownSymbols,
+      options->startFunction,
+      options->debug);
+
+  S2WasmBuilder mainbuilder(assembly, options->debug);
+  linker.linkObject(mainbuilder);
+  linker.layout();
+
+  auto ret = make_unique<BinaryenRustModule>();
+  {
+    WasmBinaryWriter writer(&linker.getOutput().wasm, ret->buffer, options->debug);
+    writer.setNamesSection(options->debugInfo);
+    // FIXME: support source maps?
+    // writer.setSourceMap(sourceMapStream.get(), sourceMapUrl);
+
+    // FIXME: support symbol maps?
+    // writer.setSymbolMap(symbolMap);
+    writer.write();
+  }
+  return ret.release();
+}
+
+extern "C" const uint8_t*
+BinaryenRustModulePtr(const BinaryenRustModule *M) {
+  return M->buffer.data();
+}
+
+extern "C" size_t
+BinaryenRustModuleLen(const BinaryenRustModule *M) {
+  return M->buffer.size();
+}
+
+extern "C" void
+BinaryenRustModuleFree(BinaryenRustModule *M) {
+  delete M;
+}
diff --git a/src/librustc_binaryen/Cargo.toml b/src/librustc_binaryen/Cargo.toml
new file mode 100644
index 0000000000000..9573c89471404
--- /dev/null
+++ b/src/librustc_binaryen/Cargo.toml
@@ -0,0 +1,16 @@
+# Wondering what this crate is? Take a look at the `lib.rs`!
+
+[package]
+name = "rustc_binaryen"
+version = "0.0.0"
+authors = ["The Rust Project Developers"]
+
+[lib]
+path = "lib.rs"
+
+[dependencies]
+libc = "0.2"
+
+[build-dependencies]
+cmake = "0.1"
+cc = "1.0"
diff --git a/src/librustc_binaryen/build.rs b/src/librustc_binaryen/build.rs
new file mode 100644
index 0000000000000..f23ff3cee555b
--- /dev/null
+++ b/src/librustc_binaryen/build.rs
@@ -0,0 +1,60 @@
+// Copyright 2017 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.
+
+extern crate cc;
+extern crate cmake;
+
+use std::env;
+
+use cmake::Config;
+
+fn main() {
+    let target = env::var("TARGET").unwrap();
+
+    // Bring in `__emutls_get_address` which is apparently needed for now
+    if target.contains("pc-windows-gnu") {
+        println!("cargo:rustc-link-lib=gcc_eh");
+        println!("cargo:rustc-link-lib=pthread");
+    }
+
+    Config::new("../binaryen")
+        .define("BUILD_STATIC_LIB", "ON")
+        .build_target("binaryen")
+        .build();
+
+    // I couldn't figure out how to link just one of these, so link everything.
+    println!("cargo:rustc-link-lib=static=asmjs");
+    println!("cargo:rustc-link-lib=static=binaryen");
+    println!("cargo:rustc-link-lib=static=cfg");
+    println!("cargo:rustc-link-lib=static=emscripten-optimizer");
+    println!("cargo:rustc-link-lib=static=ir");
+    println!("cargo:rustc-link-lib=static=passes");
+    println!("cargo:rustc-link-lib=static=support");
+    println!("cargo:rustc-link-lib=static=wasm");
+
+    let out_dir = env::var("OUT_DIR").unwrap();
+    println!("cargo:rustc-link-search=native={}/build/lib", out_dir);
+
+    // Add in our own little shim along with some extra files that weren't
+    // included in the main build.
+    let mut cfg = cc::Build::new();
+    cfg.file("BinaryenWrapper.cpp")
+        .file("../binaryen/src/wasm-linker.cpp")
+        .file("../binaryen/src/wasm-emscripten.cpp")
+        .include("../binaryen/src")
+        .cpp_link_stdlib(None)
+        .warnings(false)
+        .cpp(true);
+
+    if !target.contains("msvc") {
+        cfg.flag("-std=c++11");
+    }
+    cfg.compile("binaryen_wrapper");
+}
diff --git a/src/librustc_binaryen/lib.rs b/src/librustc_binaryen/lib.rs
new file mode 100644
index 0000000000000..6c7feb6a7a9d3
--- /dev/null
+++ b/src/librustc_binaryen/lib.rs
@@ -0,0 +1,150 @@
+// Copyright 2017 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.
+
+//! Rustc bindings to the binaryen project.
+//!
+//! This crate is a small shim around the binaryen project which provides us the
+//! ability to take LLVM's output and generate a wasm module. Specifically this
+//! only supports one operation, creating a module from LLVM's assembly format
+//! and then serializing that module to a wasm module.
+
+extern crate libc;
+
+use std::slice;
+use std::ffi::{CString, CStr};
+
+/// In-memory representation of a serialized wasm module.
+pub struct Module {
+    ptr: *mut BinaryenRustModule,
+}
+
+impl Module {
+    /// Creates a new wasm module from the LLVM-assembly provided (in a C string
+    /// format).
+    ///
+    /// The actual module creation can be tweaked through the various options in
+    /// `ModuleOptions` as well. Any errors are just returned as a bland string.
+    pub fn new(assembly: &CStr, opts: &ModuleOptions) -> Result<Module, String> {
+        unsafe {
+            let ptr = BinaryenRustModuleCreate(opts.ptr, assembly.as_ptr());
+            if ptr.is_null() {
+                Err(format!("failed to create binaryen module"))
+            } else {
+                Ok(Module { ptr })
+            }
+        }
+    }
+
+    /// Returns the data of the serialized wasm module. This is a `foo.wasm`
+    /// file contents.
+    pub fn data(&self) -> &[u8] {
+        unsafe {
+            let ptr = BinaryenRustModulePtr(self.ptr);
+            let len = BinaryenRustModuleLen(self.ptr);
+            slice::from_raw_parts(ptr, len)
+        }
+    }
+}
+
+impl Drop for Module {
+    fn drop(&mut self) {
+        unsafe {
+            BinaryenRustModuleFree(self.ptr);
+        }
+    }
+}
+
+pub struct ModuleOptions {
+    ptr: *mut BinaryenRustModuleOptions,
+}
+
+impl ModuleOptions {
+    pub fn new() -> ModuleOptions {
+        unsafe {
+            let ptr = BinaryenRustModuleOptionsCreate();
+            ModuleOptions { ptr }
+        }
+    }
+
+    /// Turns on or off debug info.
+    ///
+    /// From what I can tell this just creates a "names" section of the wasm
+    /// module which contains a table of the original function names.
+    pub fn debuginfo(&mut self, debug: bool) -> &mut Self {
+        unsafe {
+            BinaryenRustModuleOptionsSetDebugInfo(self.ptr, debug);
+        }
+        self
+    }
+
+    /// Configures a `start` function for the module, to be executed when it's
+    /// loaded.
+    pub fn start(&mut self, func: &str) -> &mut Self {
+        let func = CString::new(func).unwrap();
+        unsafe {
+            BinaryenRustModuleOptionsSetStart(self.ptr, func.as_ptr());
+        }
+        self
+    }
+
+    /// Configures how much stack is initially allocated for the module. 1MB is
+    /// probably good enough for now.
+    pub fn stack(&mut self, amt: u64) -> &mut Self {
+        unsafe {
+            BinaryenRustModuleOptionsSetStackAllocation(self.ptr, amt);
+        }
+        self
+    }
+
+    /// Flags whether the initial memory should be imported or exported. So far
+    /// we export it by default.
+    pub fn import_memory(&mut self, import: bool) -> &mut Self {
+        unsafe {
+            BinaryenRustModuleOptionsSetImportMemory(self.ptr, import);
+        }
+        self
+    }
+}
+
+impl Drop for ModuleOptions {
+    fn drop(&mut self) {
+        unsafe {
+            BinaryenRustModuleOptionsFree(self.ptr);
+        }
+    }
+}
+
+enum BinaryenRustModule {}
+enum BinaryenRustModuleOptions {}
+
+extern {
+    fn BinaryenRustModuleCreate(opts: *const BinaryenRustModuleOptions,
+                                assembly: *const libc::c_char)
+        -> *mut BinaryenRustModule;
+    fn BinaryenRustModulePtr(module: *const BinaryenRustModule) -> *const u8;
+    fn BinaryenRustModuleLen(module: *const BinaryenRustModule) -> usize;
+    fn BinaryenRustModuleFree(module: *mut BinaryenRustModule);
+
+    fn BinaryenRustModuleOptionsCreate()
+        -> *mut BinaryenRustModuleOptions;
+    fn BinaryenRustModuleOptionsSetDebugInfo(module: *mut BinaryenRustModuleOptions,
+                                             debuginfo: bool);
+    fn BinaryenRustModuleOptionsSetStart(module: *mut BinaryenRustModuleOptions,
+                                         start: *const libc::c_char);
+    fn BinaryenRustModuleOptionsSetStackAllocation(
+        module: *mut BinaryenRustModuleOptions,
+        stack: u64,
+    );
+    fn BinaryenRustModuleOptionsSetImportMemory(
+        module: *mut BinaryenRustModuleOptions,
+        import: bool,
+    );
+    fn BinaryenRustModuleOptionsFree(module: *mut BinaryenRustModuleOptions);
+}
diff --git a/src/librustc_llvm/ffi.rs b/src/librustc_llvm/ffi.rs
index 24c3963fbc4b3..cff584c16802e 100644
--- a/src/librustc_llvm/ffi.rs
+++ b/src/librustc_llvm/ffi.rs
@@ -1606,7 +1606,8 @@ extern "C" {
                                        PositionIndependentExecutable: bool,
                                        FunctionSections: bool,
                                        DataSections: bool,
-                                       TrapUnreachable: bool)
+                                       TrapUnreachable: bool,
+                                       Singlethread: bool)
                                        -> TargetMachineRef;
     pub fn LLVMRustDisposeTargetMachine(T: TargetMachineRef);
     pub fn LLVMRustAddAnalysisPasses(T: TargetMachineRef, PM: PassManagerRef, M: ModuleRef);
diff --git a/src/librustc_trans/Cargo.toml b/src/librustc_trans/Cargo.toml
index f797464c1f8f1..96102cad3ef5e 100644
--- a/src/librustc_trans/Cargo.toml
+++ b/src/librustc_trans/Cargo.toml
@@ -11,16 +11,17 @@ test = false
 
 [dependencies]
 bitflags = "1.0"
-num_cpus = "1.0"
 flate2 = "0.2"
 jobserver = "0.1.5"
 log = "0.3"
+num_cpus = "1.0"
 owning_ref = "0.3.3"
-rustc-demangle = "0.1.4"
 rustc = { path = "../librustc" }
+rustc-demangle = "0.1.4"
 rustc_allocator = { path = "../librustc_allocator" }
 rustc_apfloat = { path = "../librustc_apfloat" }
 rustc_back = { path = "../librustc_back" }
+rustc_binaryen = { path = "../librustc_binaryen" }
 rustc_const_math = { path = "../librustc_const_math" }
 rustc_data_structures = { path = "../librustc_data_structures" }
 rustc_errors = { path = "../librustc_errors" }
diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs
index 1d2bfd001f1fe..89f182d178b94 100644
--- a/src/librustc_trans/back/link.rs
+++ b/src/librustc_trans/back/link.rs
@@ -27,7 +27,7 @@ use rustc::util::common::time;
 use rustc::util::fs::fix_windows_verbatim_for_gcc;
 use rustc::hir::def_id::CrateNum;
 use rustc_back::tempdir::TempDir;
-use rustc_back::{PanicStrategy, RelroLevel};
+use rustc_back::{PanicStrategy, RelroLevel, LinkerFlavor};
 use context::get_reloc_model;
 use llvm;
 
@@ -245,12 +245,12 @@ pub fn each_linked_rlib(sess: &Session,
 /// It's unusual for a crate to not participate in LTO. Typically only
 /// compiler-specific and unstable crates have a reason to not participate in
 /// LTO.
-pub fn ignored_for_lto(info: &CrateInfo, cnum: CrateNum) -> bool {
-    // `#![no_builtins]` crates don't participate in LTO because the state
-    // of builtins gets messed up (our crate isn't tagged with no builtins).
-    // Similarly `#![compiler_builtins]` doesn't participate because we want
-    // those builtins!
-    info.is_no_builtins.contains(&cnum) || info.compiler_builtins == Some(cnum)
+pub fn ignored_for_lto(sess: &Session, info: &CrateInfo, cnum: CrateNum) -> bool {
+    // If our target enables builtin function lowering in LLVM then the
+    // crates providing these functions don't participate in LTO (e.g.
+    // no_builtins or compiler builtins crates).
+    !sess.target.target.options.no_builtins &&
+        (info.is_no_builtins.contains(&cnum) || info.compiler_builtins == Some(cnum))
 }
 
 fn link_binary_output(sess: &Session,
@@ -488,7 +488,7 @@ fn link_staticlib(sess: &Session,
         });
         ab.add_rlib(path,
                     &name.as_str(),
-                    sess.lto() && !ignored_for_lto(&trans.crate_info, cnum),
+                    sess.lto() && !ignored_for_lto(sess, &trans.crate_info, cnum),
                     skip_object_files).unwrap();
 
         all_native_libs.extend(trans.crate_info.native_libraries[&cnum].iter().cloned());
@@ -548,6 +548,11 @@ fn link_natively(sess: &Session,
     info!("preparing {:?} to {:?}", crate_type, out_filename);
     let flavor = sess.linker_flavor();
 
+    // The "binaryen linker" is massively special, so skip everything below.
+    if flavor == LinkerFlavor::Binaryen {
+        return link_binaryen(sess, crate_type, out_filename, trans, tmpdir);
+    }
+
     // The invocations of cc share some flags across platforms
     let (pname, mut cmd, envs) = get_linker(sess);
     // This will set PATH on windows
@@ -1176,7 +1181,7 @@ fn add_upstream_rust_crates(cmd: &mut Linker,
             lib.kind == NativeLibraryKind::NativeStatic && !relevant_lib(sess, lib)
         });
 
-        if (!sess.lto() || ignored_for_lto(&trans.crate_info, cnum)) &&
+        if (!sess.lto() || ignored_for_lto(sess, &trans.crate_info, cnum)) &&
            crate_type != config::CrateTypeDylib &&
            !skip_native {
             cmd.link_rlib(&fix_windows_verbatim_for_gcc(cratepath));
@@ -1229,8 +1234,10 @@ fn add_upstream_rust_crates(cmd: &mut Linker,
                 // file, then we don't need the object file as it's part of the
                 // LTO module. Note that `#![no_builtins]` is excluded from LTO,
                 // though, so we let that object file slide.
-                let skip_because_lto = sess.lto() && is_rust_object &&
-                                        !trans.crate_info.is_no_builtins.contains(&cnum);
+                let skip_because_lto = sess.lto() &&
+                    is_rust_object &&
+                    (sess.target.target.options.no_builtins ||
+                     !trans.crate_info.is_no_builtins.contains(&cnum));
 
                 if skip_because_cfg_say_so || skip_because_lto {
                     archive.remove_file(&f);
@@ -1345,3 +1352,30 @@ fn relevant_lib(sess: &Session, lib: &NativeLibrary) -> bool {
         None => true,
     }
 }
+
+/// For now "linking with binaryen" is just "move the one module we generated in
+/// the backend to the final output"
+///
+/// That is, all the heavy lifting happens during the `back::write` phase. Here
+/// we just clean up after that.
+///
+/// Note that this is super temporary and "will not survive the night", this is
+/// guaranteed to get removed as soon as a linker for wasm exists. This should
+/// not be used for anything other than wasm.
+fn link_binaryen(sess: &Session,
+                 _crate_type: config::CrateType,
+                 out_filename: &Path,
+                 trans: &CrateTranslation,
+                 _tmpdir: &Path) {
+    assert!(trans.allocator_module.is_none());
+    assert_eq!(trans.modules.len(), 1);
+
+    let object = trans.modules[0].object.as_ref().expect("object must exist");
+    let res = fs::hard_link(object, out_filename)
+        .or_else(|_| fs::copy(object, out_filename).map(|_| ()));
+    if let Err(e) = res {
+        sess.fatal(&format!("failed to create `{}`: {}",
+                            out_filename.display(),
+                            e));
+    }
+}
diff --git a/src/librustc_trans/back/linker.rs b/src/librustc_trans/back/linker.rs
index 51f89110eb4ae..aa29c3cc12058 100644
--- a/src/librustc_trans/back/linker.rs
+++ b/src/librustc_trans/back/linker.rs
@@ -77,6 +77,9 @@ impl LinkerInfo {
                     is_ld: true,
                 }) as Box<Linker>
             }
+            LinkerFlavor::Binaryen => {
+                panic!("can't instantiate binaryen linker")
+            }
         }
     }
 }
diff --git a/src/librustc_trans/back/symbol_export.rs b/src/librustc_trans/back/symbol_export.rs
index 132b8fa7acfb0..fa6fe2e9e93ef 100644
--- a/src/librustc_trans/back/symbol_export.rs
+++ b/src/librustc_trans/back/symbol_export.rs
@@ -21,6 +21,7 @@ use rustc::ty::TyCtxt;
 use rustc::ty::maps::Providers;
 use rustc::util::nodemap::FxHashMap;
 use rustc_allocator::ALLOCATOR_METHODS;
+use rustc_back::LinkerFlavor;
 use syntax::attr;
 
 pub type ExportedSymbols = FxHashMap<
@@ -154,12 +155,26 @@ pub fn provide_extern(providers: &mut Providers) {
         let special_runtime_crate =
             tcx.is_panic_runtime(cnum) || tcx.is_compiler_builtins(cnum);
 
+        // Dealing with compiler-builtins and wasm right now is super janky.
+        // There's no linker! As a result we need all of the compiler-builtins
+        // exported symbols to make their way through all the way to the end of
+        // compilation. We want to make sure that LLVM doesn't remove them as
+        // well because we may or may not need them in the final output
+        // artifact. For now just force them to always get exported at the C
+        // layer, and we'll worry about gc'ing them later.
+        let compiler_builtins_and_binaryen =
+            tcx.is_compiler_builtins(cnum) &&
+            tcx.sess.linker_flavor() == LinkerFlavor::Binaryen;
+
         let mut crate_exports: Vec<_> = tcx
             .exported_symbol_ids(cnum)
             .iter()
             .map(|&def_id| {
                 let name = tcx.symbol_name(Instance::mono(tcx, def_id));
-                let export_level = if special_runtime_crate {
+                let export_level = if compiler_builtins_and_binaryen &&
+                                      tcx.contains_extern_indicator(def_id) {
+                    SymbolExportLevel::C
+                } else if special_runtime_crate {
                     // We can probably do better here by just ensuring that
                     // it has hidden visibility rather than public
                     // visibility, as this is primarily here to ensure it's
diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs
index e443f13a7a1ca..da67940abcb77 100644
--- a/src/librustc_trans/back/write.rs
+++ b/src/librustc_trans/back/write.rs
@@ -22,6 +22,7 @@ use rustc::session::config::{self, OutputFilenames, OutputType, OutputTypes, Pas
                              AllPasses, Sanitizer};
 use rustc::session::Session;
 use rustc::util::nodemap::FxHashMap;
+use rustc_back::LinkerFlavor;
 use time_graph::{self, TimeGraph, Timeline};
 use llvm;
 use llvm::{ModuleRef, TargetMachineRef, PassManagerRef, DiagnosticInfoRef};
@@ -47,7 +48,7 @@ use std::any::Any;
 use std::ffi::{CString, CStr};
 use std::fs::{self, File};
 use std::io;
-use std::io::Write;
+use std::io::{Read, Write};
 use std::mem;
 use std::path::{Path, PathBuf};
 use std::str;
@@ -186,6 +187,8 @@ pub fn target_machine_factory(sess: &Session)
         }
     };
 
+    let singlethread = sess.target.target.options.singlethread;
+
     let triple = &sess.target.target.llvm_target;
 
     let triple = CString::new(triple.as_bytes()).unwrap();
@@ -210,6 +213,7 @@ pub fn target_machine_factory(sess: &Session)
                 ffunction_sections,
                 fdata_sections,
                 trap_unreachable,
+                singlethread,
             )
         };
 
@@ -287,7 +291,7 @@ impl ModuleConfig {
     fn set_flags(&mut self, sess: &Session, no_builtins: bool) {
         self.no_verify = sess.no_verify();
         self.no_prepopulate_passes = sess.opts.cg.no_prepopulate_passes;
-        self.no_builtins = no_builtins;
+        self.no_builtins = no_builtins || sess.target.target.options.no_builtins;
         self.time_passes = sess.time_passes();
         self.inline_threshold = sess.opts.cg.inline_threshold;
         self.obj_is_bitcode = sess.target.target.options.obj_is_bitcode;
@@ -330,6 +334,9 @@ pub struct CodegenContext {
     pub tm_factory: Arc<Fn() -> Result<TargetMachineRef, String> + Send + Sync>,
     pub msvc_imps_needed: bool,
     pub target_pointer_width: String,
+    binaryen_linker: bool,
+    debuginfo: config::DebugInfoLevel,
+    wasm_import_memory: bool,
 
     // Number of cgus excluding the allocator/metadata modules
     pub total_cgus: usize,
@@ -625,14 +632,21 @@ unsafe fn codegen(cgcx: &CodegenContext,
         f(cpm)
     }
 
+    // If we're going to generate wasm code from the assembly that llvm
+    // generates then we'll be transitively affecting a ton of options below.
+    // This only happens on the wasm target now.
+    let asm2wasm = cgcx.binaryen_linker &&
+        !cgcx.crate_types.contains(&config::CrateTypeRlib) &&
+        mtrans.kind == ModuleKind::Regular;
+
     // Change what we write and cleanup based on whether obj files are
     // just llvm bitcode. In that case write bitcode, and possibly
     // delete the bitcode if it wasn't requested. Don't generate the
     // machine code, instead copy the .o file from the .bc
-    let write_bc = config.emit_bc || config.obj_is_bitcode;
-    let rm_bc = !config.emit_bc && config.obj_is_bitcode;
-    let write_obj = config.emit_obj && !config.obj_is_bitcode;
-    let copy_bc_to_obj = config.emit_obj && config.obj_is_bitcode;
+    let write_bc = config.emit_bc || (config.obj_is_bitcode && !asm2wasm);
+    let rm_bc = !config.emit_bc && config.obj_is_bitcode && !asm2wasm;
+    let write_obj = config.emit_obj && !config.obj_is_bitcode && !asm2wasm;
+    let copy_bc_to_obj = config.emit_obj && config.obj_is_bitcode && !asm2wasm;
 
     let bc_out = cgcx.output_filenames.temp_path(OutputType::Bitcode, module_name);
     let obj_out = cgcx.output_filenames.temp_path(OutputType::Object, module_name);
@@ -711,7 +725,7 @@ unsafe fn codegen(cgcx: &CodegenContext,
             timeline.record("ir");
         }
 
-        if config.emit_asm {
+        if config.emit_asm || (asm2wasm && config.emit_obj) {
             let path = cgcx.output_filenames.temp_path(OutputType::Assembly, module_name);
 
             // We can't use the same module for asm and binary output, because that triggers
@@ -732,7 +746,15 @@ unsafe fn codegen(cgcx: &CodegenContext,
             timeline.record("asm");
         }
 
-        if write_obj {
+        if asm2wasm && config.emit_obj {
+            let assembly = cgcx.output_filenames.temp_path(OutputType::Assembly, module_name);
+            binaryen_assemble(cgcx, diag_handler, &assembly, &obj_out);
+            timeline.record("binaryen");
+
+            if !config.emit_asm {
+                drop(fs::remove_file(&assembly));
+            }
+        } else if write_obj {
             with_codegen(tm, llmod, config.no_builtins, |cpm| {
                 write_output_file(diag_handler, tm, cpm, llmod, &obj_out,
                                   llvm::FileType::ObjectFile)
@@ -764,6 +786,44 @@ unsafe fn codegen(cgcx: &CodegenContext,
                                    &cgcx.output_filenames))
 }
 
+/// Translates the LLVM-generated `assembly` on the filesystem into a wasm
+/// module using binaryen, placing the output at `object`.
+///
+/// In this case the "object" is actually a full and complete wasm module. We
+/// won't actually be doing anything else to the output for now. This is all
+/// pretty janky and will get removed as soon as a linker for wasm exists.
+fn binaryen_assemble(cgcx: &CodegenContext,
+                     handler: &Handler,
+                     assembly: &Path,
+                     object: &Path) {
+    use rustc_binaryen::{Module, ModuleOptions};
+
+    let input = File::open(&assembly).and_then(|mut f| {
+        let mut contents = Vec::new();
+        f.read_to_end(&mut contents)?;
+        Ok(CString::new(contents)?)
+    });
+    let mut options = ModuleOptions::new();
+    if cgcx.debuginfo != config::NoDebugInfo {
+        options.debuginfo(true);
+    }
+    if cgcx.crate_types.contains(&config::CrateTypeExecutable) {
+        options.start("main");
+    }
+    options.stack(1024 * 1024);
+    options.import_memory(cgcx.wasm_import_memory);
+    let assembled = input.and_then(|input| {
+        Module::new(&input, &options)
+            .map_err(|e| io::Error::new(io::ErrorKind::Other, e))
+    });
+    let err = assembled.and_then(|binary| {
+        File::create(&object).and_then(|mut f| f.write_all(binary.data()))
+    });
+    if let Err(e) = err {
+        handler.err(&format!("failed to run binaryen assembler: {}", e));
+    }
+}
+
 pub struct CompiledModules {
     pub modules: Vec<CompiledModule>,
     pub metadata_module: CompiledModule,
@@ -1318,17 +1378,33 @@ fn start_executing_work(tcx: TyCtxt,
 
     let mut each_linked_rlib_for_lto = Vec::new();
     drop(link::each_linked_rlib(sess, crate_info, &mut |cnum, path| {
-        if link::ignored_for_lto(crate_info, cnum) {
+        if link::ignored_for_lto(sess, crate_info, cnum) {
             return
         }
         each_linked_rlib_for_lto.push((cnum, path.to_path_buf()));
     }));
 
+    let crate_types = sess.crate_types.borrow();
+    let only_rlib = crate_types.len() == 1 &&
+        crate_types[0] == config::CrateTypeRlib;
+
+    let wasm_import_memory =
+        attr::contains_name(&tcx.hir.krate().attrs, "wasm_import_memory");
+
     let cgcx = CodegenContext {
         crate_types: sess.crate_types.borrow().clone(),
         each_linked_rlib_for_lto,
-        lto: sess.lto(),
-        thinlto: sess.opts.debugging_opts.thinlto,
+        // If we're only building an rlibc then allow the LTO flag to be passed
+        // but don't actually do anything, the full LTO will happen later
+        lto: sess.lto() && !only_rlib,
+
+        // Enable ThinLTO if requested, but only if the target we're compiling
+        // for doesn't require full LTO. Some targets require one LLVM module
+        // (they effectively don't have a linker) so it's up to us to use LTO to
+        // link everything together.
+        thinlto: sess.opts.debugging_opts.thinlto &&
+            !sess.target.target.options.requires_lto,
+
         no_landing_pads: sess.no_landing_pads(),
         save_temps: sess.opts.cg.save_temps,
         opts: Arc::new(sess.opts.clone()),
@@ -1349,6 +1425,9 @@ fn start_executing_work(tcx: TyCtxt,
         total_cgus,
         msvc_imps_needed: msvc_imps_needed(tcx),
         target_pointer_width: tcx.sess.target.target.target_pointer_width.clone(),
+        binaryen_linker: tcx.sess.linker_flavor() == LinkerFlavor::Binaryen,
+        debuginfo: tcx.sess.opts.debuginfo,
+        wasm_import_memory: wasm_import_memory,
     };
 
     // This is the "main loop" of parallel work happening for parallel codegen.
diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs
index 96e11d366423a..ae25e7d94bffa 100644
--- a/src/librustc_trans/lib.rs
+++ b/src/librustc_trans/lib.rs
@@ -43,18 +43,19 @@ extern crate flate2;
 extern crate libc;
 extern crate owning_ref;
 #[macro_use] extern crate rustc;
+extern crate jobserver;
+extern crate num_cpus;
 extern crate rustc_allocator;
 extern crate rustc_apfloat;
 extern crate rustc_back;
+extern crate rustc_binaryen;
+extern crate rustc_const_math;
 extern crate rustc_data_structures;
+extern crate rustc_demangle;
 extern crate rustc_incremental;
 extern crate rustc_llvm as llvm;
 extern crate rustc_platform_intrinsics as intrinsics;
-extern crate rustc_const_math;
 extern crate rustc_trans_utils;
-extern crate rustc_demangle;
-extern crate jobserver;
-extern crate num_cpus;
 
 #[macro_use] extern crate log;
 #[macro_use] extern crate syntax;
diff --git a/src/librustc_trans_utils/link.rs b/src/librustc_trans_utils/link.rs
index 47484488fb8e8..c1e670cc7caf5 100644
--- a/src/librustc_trans_utils/link.rs
+++ b/src/librustc_trans_utils/link.rs
@@ -163,15 +163,30 @@ pub fn default_output_for_target(sess: &Session) -> config::CrateType {
 /// Checks if target supports crate_type as output
 pub fn invalid_output_for_target(sess: &Session,
                                  crate_type: config::CrateType) -> bool {
-    match (sess.target.target.options.dynamic_linking,
-           sess.target.target.options.executables, crate_type) {
-        (false, _, config::CrateTypeCdylib) |
-        (false, _, config::CrateTypeDylib) |
-        (false, _, config::CrateTypeProcMacro) => true,
-        (true, _, config::CrateTypeCdylib) |
-        (true, _, config::CrateTypeDylib) => sess.crt_static() &&
-            !sess.target.target.options.crt_static_allows_dylibs,
-        (_, false, config::CrateTypeExecutable) => true,
-        _ => false
+    match crate_type {
+        config::CrateTypeCdylib |
+        config::CrateTypeDylib |
+        config::CrateTypeProcMacro => {
+            if !sess.target.target.options.dynamic_linking {
+                return true
+            }
+            if sess.crt_static() && !sess.target.target.options.crt_static_allows_dylibs {
+                return true
+            }
+        }
+        _ => {}
     }
+    if sess.target.target.options.only_cdylib {
+        match crate_type {
+            config::CrateTypeProcMacro | config::CrateTypeDylib => return true,
+            _ => {}
+        }
+    }
+    if !sess.target.target.options.executables {
+        if crate_type == config::CrateTypeExecutable {
+            return true
+        }
+    }
+
+    false
 }
diff --git a/src/libstd/build.rs b/src/libstd/build.rs
index 0e6214ea04fc0..06f11c8deb458 100644
--- a/src/libstd/build.rs
+++ b/src/libstd/build.rs
@@ -19,8 +19,12 @@ use build_helper::{run, native_lib_boilerplate, BuildExpectation};
 fn main() {
     let target = env::var("TARGET").expect("TARGET was not set");
     let host = env::var("HOST").expect("HOST was not set");
-    if cfg!(feature = "backtrace") && !target.contains("msvc") &&
-        !target.contains("emscripten") && !target.contains("fuchsia") {
+    if cfg!(feature = "backtrace") &&
+        !target.contains("msvc") &&
+        !target.contains("emscripten") &&
+        !target.contains("fuchsia") &&
+        !target.contains("wasm32")
+    {
         let _ = build_libbacktrace(&host, &target);
     }
 
diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs
index 7ec6124dfa462..14f0edc369058 100644
--- a/src/libstd/f32.rs
+++ b/src/libstd/f32.rs
@@ -26,7 +26,6 @@ use num::FpCategory;
 #[cfg(not(test))]
 use sys::cmath;
 
-
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use core::f32::{RADIX, MANTISSA_DIGITS, DIGITS, EPSILON};
 #[stable(feature = "rust1", since = "1.0.0")]
diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs
index 6318e2e40875f..9d0373404aaa7 100644
--- a/src/libstd/macros.rs
+++ b/src/libstd/macros.rs
@@ -663,3 +663,39 @@ pub mod builtin {
     #[macro_export]
     macro_rules! include { ($file:expr) => ({ /* compiler built-in */ }) }
 }
+
+/// A macro for defining #[cfg] if-else statements.
+///
+/// This is similar to the `if/elif` C preprocessor macro by allowing definition
+/// of a cascade of `#[cfg]` cases, emitting the implementation which matches
+/// first.
+///
+/// This allows you to conveniently provide a long list #[cfg]'d blocks of code
+/// without having to rewrite each clause multiple times.
+macro_rules! cfg_if {
+    ($(
+        if #[cfg($($meta:meta),*)] { $($it:item)* }
+    ) else * else {
+        $($it2:item)*
+    }) => {
+        __cfg_if_items! {
+            () ;
+            $( ( ($($meta),*) ($($it)*) ), )*
+            ( () ($($it2)*) ),
+        }
+    }
+}
+
+macro_rules! __cfg_if_items {
+    (($($not:meta,)*) ; ) => {};
+    (($($not:meta,)*) ; ( ($($m:meta),*) ($($it:item)*) ), $($rest:tt)*) => {
+        __cfg_if_apply! { cfg(all(not(any($($not),*)), $($m,)*)), $($it)* }
+        __cfg_if_items! { ($($not,)* $($m,)*) ; $($rest)* }
+    }
+}
+
+macro_rules! __cfg_if_apply {
+    ($m:meta, $($it:item)*) => {
+        $(#[$m] $it)*
+    }
+}
diff --git a/src/libstd/sys/mod.rs b/src/libstd/sys/mod.rs
index d91c2073a23a8..27d6433b329bb 100644
--- a/src/libstd/sys/mod.rs
+++ b/src/libstd/sys/mod.rs
@@ -46,6 +46,9 @@ mod imp;
 #[path = "redox/mod.rs"]
 mod imp;
 
+#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
+#[path = "wasm/mod.rs"]
+mod imp;
 
 // Import essential modules from both platforms when documenting.
 
diff --git a/src/libstd/sys/wasm/args.rs b/src/libstd/sys/wasm/args.rs
new file mode 100644
index 0000000000000..d2a4a7b19d548
--- /dev/null
+++ b/src/libstd/sys/wasm/args.rs
@@ -0,0 +1,90 @@
+// Copyright 2017 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 ffi::OsString;
+use marker::PhantomData;
+use mem;
+use vec;
+
+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
+}
+
+pub unsafe fn cleanup() {
+}
+
+pub fn args() -> Args {
+    // When the runtime debugging is enabled we'll link to some extra runtime
+    // functions to actually implement this. These are for now just implemented
+    // in a node.js script but they're off by default as they're sort of weird
+    // in a web-wasm world.
+    if !super::DEBUG {
+        return Args {
+            iter: Vec::new().into_iter(),
+            _dont_send_or_sync_me: PhantomData,
+        }
+    }
+
+    // You'll find the definitions of these in `src/etc/wasm32-shim.js`. These
+    // are just meant for debugging and should not be relied on.
+    extern {
+        fn rust_wasm_args_count() -> usize;
+        fn rust_wasm_args_arg_size(a: usize) -> usize;
+        fn rust_wasm_args_arg_fill(a: usize, ptr: *mut u8);
+    }
+
+    unsafe {
+        let cnt = rust_wasm_args_count();
+        let mut v = Vec::with_capacity(cnt);
+        for i in 0..cnt {
+            let n = rust_wasm_args_arg_size(i);
+            let mut data = vec![0; n];
+            rust_wasm_args_arg_fill(i, data.as_mut_ptr());
+            v.push(mem::transmute::<Vec<u8>, OsString>(data));
+        }
+        Args {
+            iter: v.into_iter(),
+            _dont_send_or_sync_me: PhantomData,
+        }
+    }
+}
+
+pub struct Args {
+    iter: vec::IntoIter<OsString>,
+    _dont_send_or_sync_me: PhantomData<*mut ()>,
+}
+
+impl Args {
+    pub fn inner_debug(&self) -> &[OsString] {
+        self.iter.as_slice()
+    }
+}
+
+impl Iterator for Args {
+    type Item = OsString;
+    fn next(&mut self) -> Option<OsString> {
+        self.iter.next()
+    }
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        self.iter.size_hint()
+    }
+}
+
+impl ExactSizeIterator for Args {
+    fn len(&self) -> usize {
+        self.iter.len()
+    }
+}
+
+impl DoubleEndedIterator for Args {
+    fn next_back(&mut self) -> Option<OsString> {
+        self.iter.next_back()
+    }
+}
diff --git a/src/libstd/sys/wasm/backtrace.rs b/src/libstd/sys/wasm/backtrace.rs
new file mode 100644
index 0000000000000..9a8c48ff29fc7
--- /dev/null
+++ b/src/libstd/sys/wasm/backtrace.rs
@@ -0,0 +1,37 @@
+// Copyright 2017 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 io;
+use sys::unsupported;
+use sys_common::backtrace::Frame;
+
+pub struct BacktraceContext;
+
+pub fn unwind_backtrace(_frames: &mut [Frame])
+    -> io::Result<(usize, BacktraceContext)>
+{
+    unsupported()
+}
+
+pub fn resolve_symname<F>(_frame: Frame,
+                          _callback: F,
+                          _: &BacktraceContext) -> io::Result<()>
+    where F: FnOnce(Option<&str>) -> io::Result<()>
+{
+    unsupported()
+}
+
+pub fn foreach_symbol_fileline<F>(_: Frame,
+                                  _: F,
+                                  _: &BacktraceContext) -> io::Result<bool>
+    where F: FnMut(&[u8], u32) -> io::Result<()>
+{
+    unsupported()
+}
diff --git a/src/libstd/sys/wasm/cmath.rs b/src/libstd/sys/wasm/cmath.rs
new file mode 100644
index 0000000000000..87ac2091cad41
--- /dev/null
+++ b/src/libstd/sys/wasm/cmath.rs
@@ -0,0 +1,119 @@
+// Copyright 2017 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.
+
+#[inline]
+pub unsafe fn cbrtf(n: f32) -> f32 {
+    f64::cbrt(n as f64) as f32
+}
+
+#[inline]
+pub unsafe fn expm1f(n: f32) -> f32 {
+    f64::exp_m1(n as f64) as f32
+}
+
+#[inline]
+#[allow(deprecated)]
+pub unsafe fn fdimf(a: f32, b: f32) -> f32 {
+    f64::abs_sub(a as f64, b as f64) as f32
+}
+
+#[inline]
+pub unsafe fn log1pf(n: f32) -> f32 {
+    f64::ln_1p(n as f64) as f32
+}
+
+#[inline]
+pub unsafe fn hypotf(x: f32, y: f32) -> f32 {
+    f64::hypot(x as f64, y as f64) as f32
+}
+
+#[inline]
+pub unsafe fn acosf(n: f32) -> f32 {
+    f64::acos(n as f64) as f32
+}
+
+#[inline]
+pub unsafe fn asinf(n: f32) -> f32 {
+    f64::asin(n as f64) as f32
+}
+
+#[inline]
+pub unsafe fn atan2f(n: f32, b: f32) -> f32 {
+    f64::atan2(n as f64, b as f64) as f32
+}
+
+#[inline]
+pub unsafe fn atanf(n: f32) -> f32 {
+    f64::atan(n as f64) as f32
+}
+
+#[inline]
+pub unsafe fn coshf(n: f32) -> f32 {
+    f64::cosh(n as f64) as f32
+}
+
+#[inline]
+pub unsafe fn sinhf(n: f32) -> f32 {
+    f64::sinh(n as f64) as f32
+}
+
+#[inline]
+pub unsafe fn tanf(n: f32) -> f32 {
+    f64::tan(n as f64) as f32
+}
+
+#[inline]
+pub unsafe fn tanhf(n: f32) -> f32 {
+    f64::tanh(n as f64) as f32
+}
+
+// Right now all these functions, the f64 version of the functions above, all
+// shell out to random names. These names aren't actually defined anywhere, per
+// se, but we need this to compile somehow.
+//
+// The idea with this is that when you're using wasm then, for now, we have no
+// way of providing an implementation of these which delegates to a "correct"
+// implementation. For example most wasm applications probably just want to
+// delegate to the javascript `Math` object and its related functions, but wasm
+// doesn't currently have the ability to seamlessly do that (when you
+// instantiate a module you have to set that up).
+//
+// As a result these are just defined here with "hopefully helpful" names. The
+// symbols won't ever be needed or show up unless these functions are called,
+// and hopefully when they're called the errors are self-explanatory enough to
+// figure out what's going on.
+
+extern {
+    #[link_name = "Math_acos"]
+    pub fn acos(n: f64) -> f64;
+    #[link_name = "Math_asin"]
+    pub fn asin(n: f64) -> f64;
+    #[link_name = "Math_atan"]
+    pub fn atan(n: f64) -> f64;
+    #[link_name = "Math_atan2"]
+    pub fn atan2(a: f64, b: f64) -> f64;
+    #[link_name = "Math_cbrt"]
+    pub fn cbrt(n: f64) -> f64;
+    #[link_name = "Math_cosh"]
+    pub fn cosh(n: f64) -> f64;
+    #[link_name = "Math_expm1"]
+    pub fn expm1(n: f64) -> f64;
+    pub fn fdim(a: f64, b: f64) -> f64;
+    #[link_name = "Math_log1p"]
+    pub fn log1p(n: f64) -> f64;
+    #[link_name = "Math_sinh"]
+    pub fn sinh(n: f64) -> f64;
+    #[link_name = "Math_tan"]
+    pub fn tan(n: f64) -> f64;
+    #[link_name = "Math_tanh"]
+    pub fn tanh(n: f64) -> f64;
+    #[link_name = "Math_hypot"]
+    pub fn hypot(x: f64, y: f64) -> f64;
+}
diff --git a/src/libstd/sys/wasm/condvar.rs b/src/libstd/sys/wasm/condvar.rs
new file mode 100644
index 0000000000000..afa7afeef5988
--- /dev/null
+++ b/src/libstd/sys/wasm/condvar.rs
@@ -0,0 +1,43 @@
+// Copyright 2017 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 sys::mutex::Mutex;
+use time::Duration;
+
+pub struct Condvar { }
+
+impl Condvar {
+    pub const fn new() -> Condvar {
+        Condvar { }
+    }
+
+    #[inline]
+    pub unsafe fn init(&mut self) {}
+
+    #[inline]
+    pub unsafe fn notify_one(&self) {
+    }
+
+    #[inline]
+    pub unsafe fn notify_all(&self) {
+    }
+
+    pub unsafe fn wait(&self, _mutex: &Mutex) {
+        panic!("can't block with web assembly")
+    }
+
+    pub unsafe fn wait_timeout(&self, _mutex: &Mutex, _dur: Duration) -> bool {
+        panic!("can't block with web assembly");
+    }
+
+    #[inline]
+    pub unsafe fn destroy(&self) {
+    }
+}
diff --git a/src/libstd/sys/wasm/env.rs b/src/libstd/sys/wasm/env.rs
new file mode 100644
index 0000000000000..1422042bd0228
--- /dev/null
+++ b/src/libstd/sys/wasm/env.rs
@@ -0,0 +1,19 @@
+// Copyright 2017 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.
+
+pub mod os {
+    pub const FAMILY: &'static str = "";
+    pub const OS: &'static str = "";
+    pub const DLL_PREFIX: &'static str = "";
+    pub const DLL_SUFFIX: &'static str = ".wasm";
+    pub const DLL_EXTENSION: &'static str = "wasm";
+    pub const EXE_SUFFIX: &'static str = ".wasm";
+    pub const EXE_EXTENSION: &'static str = "wasm";
+}
diff --git a/src/libstd/sys/wasm/fs.rs b/src/libstd/sys/wasm/fs.rs
new file mode 100644
index 0000000000000..b3c70a6685a6c
--- /dev/null
+++ b/src/libstd/sys/wasm/fs.rs
@@ -0,0 +1,304 @@
+// Copyright 2017 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 ffi::OsString;
+use fmt;
+use hash::{Hash, Hasher};
+use io::{self, SeekFrom};
+use path::{Path, PathBuf};
+use sys::time::SystemTime;
+use sys::{unsupported, Void};
+
+pub struct File(Void);
+
+pub struct FileAttr(Void);
+
+pub struct ReadDir(Void);
+
+pub struct DirEntry(Void);
+
+#[derive(Clone, Debug)]
+pub struct OpenOptions { }
+
+pub struct FilePermissions(Void);
+
+pub struct FileType(Void);
+
+#[derive(Debug)]
+pub struct DirBuilder { }
+
+impl FileAttr {
+    pub fn size(&self) -> u64 {
+        match self.0 {}
+    }
+
+    pub fn perm(&self) -> FilePermissions {
+        match self.0 {}
+    }
+
+    pub fn file_type(&self) -> FileType {
+        match self.0 {}
+    }
+
+    pub fn modified(&self) -> io::Result<SystemTime> {
+        match self.0 {}
+    }
+
+    pub fn accessed(&self) -> io::Result<SystemTime> {
+        match self.0 {}
+    }
+
+    pub fn created(&self) -> io::Result<SystemTime> {
+        match self.0 {}
+    }
+}
+
+impl Clone for FileAttr {
+    fn clone(&self) -> FileAttr {
+        match self.0 {}
+    }
+}
+
+impl FilePermissions {
+    pub fn readonly(&self) -> bool {
+        match self.0 {}
+    }
+
+    pub fn set_readonly(&mut self, _readonly: bool) {
+        match self.0 {}
+    }
+}
+
+impl Clone for FilePermissions {
+    fn clone(&self) -> FilePermissions {
+        match self.0 {}
+    }
+}
+
+impl PartialEq for FilePermissions {
+    fn eq(&self, _other: &FilePermissions) -> bool {
+        match self.0 {}
+    }
+}
+
+impl Eq for FilePermissions {
+}
+
+impl fmt::Debug for FilePermissions {
+    fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
+        match self.0 {}
+    }
+}
+
+impl FileType {
+    pub fn is_dir(&self) -> bool {
+        match self.0 {}
+    }
+
+    pub fn is_file(&self) -> bool {
+        match self.0 {}
+    }
+
+    pub fn is_symlink(&self) -> bool {
+        match self.0 {}
+    }
+}
+
+impl Clone for FileType {
+    fn clone(&self) -> FileType {
+        match self.0 {}
+    }
+}
+
+impl Copy for FileType {}
+
+impl PartialEq for FileType {
+    fn eq(&self, _other: &FileType) -> bool {
+        match self.0 {}
+    }
+}
+
+impl Eq for FileType {
+}
+
+impl Hash for FileType {
+    fn hash<H: Hasher>(&self, _h: &mut H) {
+        match self.0 {}
+    }
+}
+
+impl fmt::Debug for FileType {
+    fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
+        match self.0 {}
+    }
+}
+
+impl fmt::Debug for ReadDir {
+    fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
+        match self.0 {}
+    }
+}
+
+impl Iterator for ReadDir {
+    type Item = io::Result<DirEntry>;
+
+    fn next(&mut self) -> Option<io::Result<DirEntry>> {
+        match self.0 {}
+    }
+}
+
+impl DirEntry {
+    pub fn path(&self) -> PathBuf {
+        match self.0 {}
+    }
+
+    pub fn file_name(&self) -> OsString {
+        match self.0 {}
+    }
+
+    pub fn metadata(&self) -> io::Result<FileAttr> {
+        match self.0 {}
+    }
+
+    pub fn file_type(&self) -> io::Result<FileType> {
+        match self.0 {}
+    }
+}
+
+impl OpenOptions {
+    pub fn new() -> OpenOptions {
+        OpenOptions { }
+    }
+
+    pub fn read(&mut self, _read: bool) { }
+    pub fn write(&mut self, _write: bool) { }
+    pub fn append(&mut self, _append: bool) { }
+    pub fn truncate(&mut self, _truncate: bool) { }
+    pub fn create(&mut self, _create: bool) { }
+    pub fn create_new(&mut self, _create_new: bool) { }
+}
+
+impl File {
+    pub fn open(_path: &Path, _opts: &OpenOptions) -> io::Result<File> {
+        unsupported()
+    }
+
+    pub fn file_attr(&self) -> io::Result<FileAttr> {
+        match self.0 {}
+    }
+
+    pub fn fsync(&self) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn datasync(&self) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn truncate(&self, _size: u64) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn read(&self, _buf: &mut [u8]) -> io::Result<usize> {
+        match self.0 {}
+    }
+
+    pub fn write(&self, _buf: &[u8]) -> io::Result<usize> {
+        match self.0 {}
+    }
+
+    pub fn flush(&self) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn seek(&self, _pos: SeekFrom) -> io::Result<u64> {
+        match self.0 {}
+    }
+
+    pub fn duplicate(&self) -> io::Result<File> {
+        match self.0 {}
+    }
+
+    pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn diverge(&self) -> ! {
+        match self.0 {}
+    }
+}
+
+impl DirBuilder {
+    pub fn new() -> DirBuilder {
+        DirBuilder { }
+    }
+
+    pub fn mkdir(&self, _p: &Path) -> io::Result<()> {
+        unsupported()
+    }
+}
+
+impl fmt::Debug for File {
+    fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
+        match self.0 {}
+    }
+}
+
+pub fn readdir(_p: &Path) -> io::Result<ReadDir> {
+    unsupported()
+}
+
+pub fn unlink(_p: &Path) -> io::Result<()> {
+    unsupported()
+}
+
+pub fn rename(_old: &Path, _new: &Path) -> io::Result<()> {
+    unsupported()
+}
+
+pub fn set_perm(_p: &Path, perm: FilePermissions) -> io::Result<()> {
+    match perm.0 {}
+}
+
+pub fn rmdir(_p: &Path) -> io::Result<()> {
+    unsupported()
+}
+
+pub fn remove_dir_all(_path: &Path) -> io::Result<()> {
+    unsupported()
+}
+
+pub fn readlink(_p: &Path) -> io::Result<PathBuf> {
+    unsupported()
+}
+
+pub fn symlink(_src: &Path, _dst: &Path) -> io::Result<()> {
+    unsupported()
+}
+
+pub fn link(_src: &Path, _dst: &Path) -> io::Result<()> {
+    unsupported()
+}
+
+pub fn stat(_p: &Path) -> io::Result<FileAttr> {
+    unsupported()
+}
+
+pub fn lstat(_p: &Path) -> io::Result<FileAttr> {
+    unsupported()
+}
+
+pub fn canonicalize(_p: &Path) -> io::Result<PathBuf> {
+    unsupported()
+}
+
+pub fn copy(_from: &Path, _to: &Path) -> io::Result<u64> {
+    unsupported()
+}
diff --git a/src/libstd/sys/wasm/memchr.rs b/src/libstd/sys/wasm/memchr.rs
new file mode 100644
index 0000000000000..e611d94af30b1
--- /dev/null
+++ b/src/libstd/sys/wasm/memchr.rs
@@ -0,0 +1,11 @@
+// Copyright 2017 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.
+
+pub use sys_common::memchr::fallback::{memchr, memrchr};
diff --git a/src/libstd/sys/wasm/mod.rs b/src/libstd/sys/wasm/mod.rs
new file mode 100644
index 0000000000000..b838dbafd6f0c
--- /dev/null
+++ b/src/libstd/sys/wasm/mod.rs
@@ -0,0 +1,104 @@
+// Copyright 2017 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.
+
+//! System bindings for the wasm/web platform
+//!
+//! This module contains the facade (aka platform-specific) implementations of
+//! OS level functionality for wasm. Note that this wasm is *not* the emscripten
+//! wasm, so we have no runtime here.
+//!
+//! This is all super highly experimental and not actually intended for
+//! wide/production use yet, it's still all in the experimental category. This
+//! will likely change over time.
+//!
+//! Currently all functions here are basically stubs that immediately return
+//! errors. The hope is that with a portability lint we can turn actually just
+//! remove all this and just omit parts of the standard library if we're
+//! compiling for wasm. That way it's a compile time error for something that's
+//! guaranteed to be a runtime error!
+
+use io;
+use os::raw::c_char;
+
+// Right now the wasm backend doesn't even have the ability to print to the
+// console by default. Wasm can't import anything from JS! (you have to
+// explicitly provide it).
+//
+// Sometimes that's a real bummer, though, so this flag can be set to `true` to
+// enable calling various shims defined in `src/etc/wasm32-shim.js` which should
+// help receive debug output and see what's going on. In general this flag
+// currently controls "will we call out to our own defined shims in node.js",
+// and this flag should always be `false` for release builds.
+const DEBUG: bool = false;
+
+pub mod args;
+pub mod backtrace;
+pub mod cmath;
+pub mod condvar;
+pub mod env;
+pub mod fs;
+pub mod memchr;
+pub mod mutex;
+pub mod net;
+pub mod os;
+pub mod os_str;
+pub mod path;
+pub mod pipe;
+pub mod process;
+pub mod rwlock;
+pub mod stack_overflow;
+pub mod thread;
+pub mod thread_local;
+pub mod time;
+pub mod stdio;
+
+#[cfg(not(test))]
+pub fn init() {
+}
+
+pub fn unsupported<T>() -> io::Result<T> {
+    Err(unsupported_err())
+}
+
+pub fn unsupported_err() -> io::Error {
+    io::Error::new(io::ErrorKind::Other,
+                   "operation not supported on wasm yet")
+}
+
+pub fn decode_error_kind(_code: i32) -> io::ErrorKind {
+    io::ErrorKind::Other
+}
+
+// This enum is used as the storage for a bunch of types which can't actually
+// exist.
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
+pub enum Void {}
+
+pub unsafe fn strlen(mut s: *const c_char) -> usize {
+    let mut n = 0;
+    while *s != 0 {
+        n += 1;
+        s = s.offset(1);
+    }
+    return n
+}
+
+pub unsafe fn abort_internal() -> ! {
+    ::intrinsics::abort();
+}
+
+// We don't have randomness yet, but I totally used a random number generator to
+// generate these numbers.
+//
+// More seriously though this is just for DOS protection in hash maps. It's ok
+// if we don't do that on wasm just yet.
+pub fn hashmap_random_keys() -> (u64, u64) {
+    (1, 2)
+}
diff --git a/src/libstd/sys/wasm/mutex.rs b/src/libstd/sys/wasm/mutex.rs
new file mode 100644
index 0000000000000..4197bdcc80839
--- /dev/null
+++ b/src/libstd/sys/wasm/mutex.rs
@@ -0,0 +1,79 @@
+// Copyright 2017 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 cell::UnsafeCell;
+
+pub struct Mutex {
+    locked: UnsafeCell<bool>,
+}
+
+unsafe impl Send for Mutex {}
+unsafe impl Sync for Mutex {} // no threads on wasm
+
+impl Mutex {
+    pub const fn new() -> Mutex {
+        Mutex { locked: UnsafeCell::new(false) }
+    }
+
+    #[inline]
+    pub unsafe fn init(&mut self) {
+    }
+
+    #[inline]
+    pub unsafe fn lock(&self) {
+        let locked = self.locked.get();
+        assert!(!*locked, "cannot recursively acquire mutex");
+        *locked = true;
+    }
+
+    #[inline]
+    pub unsafe fn unlock(&self) {
+        *self.locked.get() = false;
+    }
+
+    #[inline]
+    pub unsafe fn try_lock(&self) -> bool {
+        let locked = self.locked.get();
+        if *locked {
+            false
+        } else {
+            *locked = true;
+            true
+        }
+    }
+
+    #[inline]
+    pub unsafe fn destroy(&self) {
+    }
+}
+
+// All empty stubs because wasm has no threads yet, so lock acquisition always
+// succeeds.
+pub struct ReentrantMutex {
+}
+
+impl ReentrantMutex {
+    pub unsafe fn uninitialized() -> ReentrantMutex {
+        ReentrantMutex { }
+    }
+
+    pub unsafe fn init(&mut self) {}
+
+    pub unsafe fn lock(&self) {}
+
+    #[inline]
+    pub unsafe fn try_lock(&self) -> bool {
+        true
+    }
+
+    pub unsafe fn unlock(&self) {}
+
+    pub unsafe fn destroy(&self) {}
+}
diff --git a/src/libstd/sys/wasm/net.rs b/src/libstd/sys/wasm/net.rs
new file mode 100644
index 0000000000000..e7476ab37f7c8
--- /dev/null
+++ b/src/libstd/sys/wasm/net.rs
@@ -0,0 +1,337 @@
+// Copyright 2017 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 fmt;
+use io;
+use net::{SocketAddr, Shutdown, Ipv4Addr, Ipv6Addr};
+use time::Duration;
+use sys::{unsupported, Void};
+
+pub struct TcpStream(Void);
+
+impl TcpStream {
+    pub fn connect(_: &SocketAddr) -> io::Result<TcpStream> {
+        unsupported()
+    }
+
+    pub fn connect_timeout(_: &SocketAddr, _: Duration) -> io::Result<TcpStream> {
+        unsupported()
+    }
+
+    pub fn set_read_timeout(&self, _: Option<Duration>) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn set_write_timeout(&self, _: Option<Duration>) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
+        match self.0 {}
+    }
+
+    pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
+        match self.0 {}
+    }
+
+    pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> {
+        match self.0 {}
+    }
+
+    pub fn read(&self, _: &mut [u8]) -> io::Result<usize> {
+        match self.0 {}
+    }
+
+    pub fn write(&self, _: &[u8]) -> io::Result<usize> {
+        match self.0 {}
+    }
+
+    pub fn peer_addr(&self) -> io::Result<SocketAddr> {
+        match self.0 {}
+    }
+
+    pub fn socket_addr(&self) -> io::Result<SocketAddr> {
+        match self.0 {}
+    }
+
+    pub fn shutdown(&self, _: Shutdown) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn duplicate(&self) -> io::Result<TcpStream> {
+        match self.0 {}
+    }
+
+    pub fn set_nodelay(&self, _: bool) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn nodelay(&self) -> io::Result<bool> {
+        match self.0 {}
+    }
+
+    pub fn set_ttl(&self, _: u32) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn ttl(&self) -> io::Result<u32> {
+        match self.0 {}
+    }
+
+    pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+        match self.0 {}
+    }
+
+    pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
+        match self.0 {}
+    }
+}
+
+impl fmt::Debug for TcpStream {
+    fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
+        match self.0 {}
+    }
+}
+
+pub struct TcpListener(Void);
+
+impl TcpListener {
+    pub fn bind(_: &SocketAddr) -> io::Result<TcpListener> {
+        unsupported()
+    }
+
+    pub fn socket_addr(&self) -> io::Result<SocketAddr> {
+        match self.0 {}
+    }
+
+    pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
+        match self.0 {}
+    }
+
+    pub fn duplicate(&self) -> io::Result<TcpListener> {
+        match self.0 {}
+    }
+
+    pub fn set_ttl(&self, _: u32) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn ttl(&self) -> io::Result<u32> {
+        match self.0 {}
+    }
+
+    pub fn set_only_v6(&self, _: bool) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn only_v6(&self) -> io::Result<bool> {
+        match self.0 {}
+    }
+
+    pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+        match self.0 {}
+    }
+
+    pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
+        match self.0 {}
+    }
+}
+
+impl fmt::Debug for TcpListener {
+    fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
+        match self.0 {}
+    }
+}
+
+pub struct UdpSocket(Void);
+
+impl UdpSocket {
+    pub fn bind(_: &SocketAddr) -> io::Result<UdpSocket> {
+        unsupported()
+    }
+
+    pub fn socket_addr(&self) -> io::Result<SocketAddr> {
+        match self.0 {}
+    }
+
+    pub fn recv_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+        match self.0 {}
+    }
+
+    pub fn peek_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+        match self.0 {}
+    }
+
+    pub fn send_to(&self, _: &[u8], _: &SocketAddr) -> io::Result<usize> {
+        match self.0 {}
+    }
+
+    pub fn duplicate(&self) -> io::Result<UdpSocket> {
+        match self.0 {}
+    }
+
+    pub fn set_read_timeout(&self, _: Option<Duration>) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn set_write_timeout(&self, _: Option<Duration>) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
+        match self.0 {}
+    }
+
+    pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
+        match self.0 {}
+    }
+
+    pub fn set_broadcast(&self, _: bool) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn broadcast(&self) -> io::Result<bool> {
+        match self.0 {}
+    }
+
+    pub fn set_multicast_loop_v4(&self, _: bool) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn multicast_loop_v4(&self) -> io::Result<bool> {
+        match self.0 {}
+    }
+
+    pub fn set_multicast_ttl_v4(&self, _: u32) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn multicast_ttl_v4(&self) -> io::Result<u32> {
+        match self.0 {}
+    }
+
+    pub fn set_multicast_loop_v6(&self, _: bool) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn multicast_loop_v6(&self) -> io::Result<bool> {
+        match self.0 {}
+    }
+
+    pub fn join_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr)
+                         -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn join_multicast_v6(&self, _: &Ipv6Addr, _: u32)
+                         -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn leave_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr)
+                          -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn leave_multicast_v6(&self, _: &Ipv6Addr, _: u32)
+                          -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn set_ttl(&self, _: u32) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn ttl(&self) -> io::Result<u32> {
+        match self.0 {}
+    }
+
+    pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+        match self.0 {}
+    }
+
+    pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn recv(&self, _: &mut [u8]) -> io::Result<usize> {
+        match self.0 {}
+    }
+
+    pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> {
+        match self.0 {}
+    }
+
+    pub fn send(&self, _: &[u8]) -> io::Result<usize> {
+        match self.0 {}
+    }
+
+    pub fn connect(&self, _: &SocketAddr) -> io::Result<()> {
+        match self.0 {}
+    }
+}
+
+impl fmt::Debug for UdpSocket {
+    fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
+        match self.0 {}
+    }
+}
+
+pub struct LookupHost(Void);
+
+impl Iterator for LookupHost {
+    type Item = SocketAddr;
+    fn next(&mut self) -> Option<SocketAddr> {
+        match self.0 {}
+    }
+}
+
+pub fn lookup_host(_: &str) -> io::Result<LookupHost> {
+    unsupported()
+}
+
+#[allow(bad_style)]
+pub mod netc {
+    pub const AF_INET: u8 = 0;
+    pub const AF_INET6: u8 = 1;
+    pub type sa_family_t = u8;
+
+    #[derive(Copy, Clone)]
+    pub struct in_addr {
+        pub s_addr: u32,
+    }
+
+    #[derive(Copy, Clone)]
+    pub struct sockaddr_in {
+        pub sin_family: sa_family_t,
+        pub sin_port: u16,
+        pub sin_addr: in_addr,
+    }
+
+    #[derive(Copy, Clone)]
+    pub struct in6_addr {
+        pub s6_addr: [u8; 16],
+    }
+
+    #[derive(Copy, Clone)]
+    pub struct sockaddr_in6 {
+        pub sin6_family: sa_family_t,
+        pub sin6_port: u16,
+        pub sin6_addr: in6_addr,
+        pub sin6_flowinfo: u32,
+        pub sin6_scope_id: u32,
+    }
+
+    #[derive(Copy, Clone)]
+    pub struct sockaddr {
+    }
+
+    pub type socklen_t = usize;
+}
diff --git a/src/libstd/sys/wasm/os.rs b/src/libstd/sys/wasm/os.rs
new file mode 100644
index 0000000000000..c98030f7ebf53
--- /dev/null
+++ b/src/libstd/sys/wasm/os.rs
@@ -0,0 +1,136 @@
+// Copyright 2017 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 core::intrinsics;
+
+use error::Error as StdError;
+use ffi::{OsString, OsStr};
+use fmt;
+use io;
+use mem;
+use path::{self, PathBuf};
+use str;
+use sys::{unsupported, Void};
+
+pub fn errno() -> i32 {
+    0
+}
+
+pub fn error_string(_errno: i32) -> String {
+    format!("operation successful")
+}
+
+pub fn getcwd() -> io::Result<PathBuf> {
+    unsupported()
+}
+
+pub fn chdir(_: &path::Path) -> io::Result<()> {
+    unsupported()
+}
+
+pub struct SplitPaths<'a>(&'a Void);
+
+pub fn split_paths(_unparsed: &OsStr) -> SplitPaths {
+    panic!("unsupported")
+}
+
+impl<'a> Iterator for SplitPaths<'a> {
+    type Item = PathBuf;
+    fn next(&mut self) -> Option<PathBuf> {
+        match *self.0 {}
+    }
+}
+
+#[derive(Debug)]
+pub struct JoinPathsError;
+
+pub fn join_paths<I, T>(_paths: I) -> Result<OsString, JoinPathsError>
+    where I: Iterator<Item=T>, T: AsRef<OsStr>
+{
+    Err(JoinPathsError)
+}
+
+impl fmt::Display for JoinPathsError {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        "not supported on wasm yet".fmt(f)
+    }
+}
+
+impl StdError for JoinPathsError {
+    fn description(&self) -> &str {
+        "not supported on wasm yet"
+    }
+}
+
+pub fn current_exe() -> io::Result<PathBuf> {
+    unsupported()
+}
+
+pub struct Env(Void);
+
+impl Iterator for Env {
+    type Item = (OsString, OsString);
+    fn next(&mut self) -> Option<(OsString, OsString)> {
+        match self.0 {}
+    }
+}
+
+pub fn env() -> Env {
+    panic!("not supported on web assembly")
+}
+
+pub fn getenv(k: &OsStr) -> io::Result<Option<OsString>> {
+    // If we're debugging the runtime then we actually probe node.js to ask for
+    // the value of environment variables to help provide inputs to programs.
+    // The `extern` shims here are defined in `src/etc/wasm32-shim.js` and are
+    // intended for debugging only, you should not rely on them.
+    if !super::DEBUG {
+        return Ok(None)
+    }
+
+    extern {
+        fn rust_wasm_getenv_len(k: *const u8, kl: usize) -> isize;
+        fn rust_wasm_getenv_data(k: *const u8, kl: usize, v: *mut u8);
+    }
+    unsafe {
+        let k: &[u8] = mem::transmute(k);
+        let n = rust_wasm_getenv_len(k.as_ptr(), k.len());
+        if n == -1 {
+            return Ok(None)
+        }
+        let mut data = vec![0; n as usize];
+        rust_wasm_getenv_data(k.as_ptr(), k.len(), data.as_mut_ptr());
+        Ok(Some(mem::transmute(data)))
+    }
+}
+
+pub fn setenv(_k: &OsStr, _v: &OsStr) -> io::Result<()> {
+    unsupported()
+}
+
+pub fn unsetenv(_n: &OsStr) -> io::Result<()> {
+    unsupported()
+}
+
+pub fn temp_dir() -> PathBuf {
+    panic!("no filesystem on wasm")
+}
+
+pub fn home_dir() -> Option<PathBuf> {
+    None
+}
+
+pub fn exit(_code: i32) -> ! {
+    unsafe { intrinsics::abort() }
+}
+
+pub fn getpid() -> u32 {
+    panic!("no pids on wasm")
+}
diff --git a/src/libstd/sys/wasm/os_str.rs b/src/libstd/sys/wasm/os_str.rs
new file mode 100644
index 0000000000000..c5908a7a8dc22
--- /dev/null
+++ b/src/libstd/sys/wasm/os_str.rs
@@ -0,0 +1,159 @@
+// Copyright 2017 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.
+
+/// The underlying OsString/OsStr implementation on Unix systems: just
+/// a `Vec<u8>`/`[u8]`.
+
+use borrow::Cow;
+use fmt;
+use str;
+use mem;
+use sys_common::{AsInner, IntoInner};
+use std_unicode::lossy::Utf8Lossy;
+
+#[derive(Clone, Hash)]
+pub struct Buf {
+    pub inner: Vec<u8>
+}
+
+pub struct Slice {
+    pub inner: [u8]
+}
+
+impl fmt::Debug for Slice {
+    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+        fmt::Debug::fmt(&Utf8Lossy::from_bytes(&self.inner), formatter)
+    }
+}
+
+impl fmt::Display for Slice {
+    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+        fmt::Display::fmt(&Utf8Lossy::from_bytes(&self.inner), formatter)
+    }
+}
+
+impl fmt::Debug for Buf {
+    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+        fmt::Debug::fmt(self.as_slice(), formatter)
+    }
+}
+
+impl fmt::Display for Buf {
+    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+        fmt::Display::fmt(self.as_slice(), formatter)
+    }
+}
+
+impl IntoInner<Vec<u8>> for Buf {
+    fn into_inner(self) -> Vec<u8> {
+        self.inner
+    }
+}
+
+impl AsInner<[u8]> for Buf {
+    fn as_inner(&self) -> &[u8] {
+        &self.inner
+    }
+}
+
+
+impl Buf {
+    pub fn from_string(s: String) -> Buf {
+        Buf { inner: s.into_bytes() }
+    }
+
+    #[inline]
+    pub fn with_capacity(capacity: usize) -> Buf {
+        Buf {
+            inner: Vec::with_capacity(capacity)
+        }
+    }
+
+    #[inline]
+    pub fn clear(&mut self) {
+        self.inner.clear()
+    }
+
+    #[inline]
+    pub fn capacity(&self) -> usize {
+        self.inner.capacity()
+    }
+
+    #[inline]
+    pub fn reserve(&mut self, additional: usize) {
+        self.inner.reserve(additional)
+    }
+
+    #[inline]
+    pub fn reserve_exact(&mut self, additional: usize) {
+        self.inner.reserve_exact(additional)
+    }
+
+    #[inline]
+    pub fn shrink_to_fit(&mut self) {
+        self.inner.shrink_to_fit()
+    }
+
+    pub fn as_slice(&self) -> &Slice {
+        unsafe { mem::transmute(&*self.inner) }
+    }
+
+    pub fn into_string(self) -> Result<String, Buf> {
+        String::from_utf8(self.inner).map_err(|p| Buf { inner: p.into_bytes() } )
+    }
+
+    pub fn push_slice(&mut self, s: &Slice) {
+        self.inner.extend_from_slice(&s.inner)
+    }
+
+    #[inline]
+    pub fn into_box(self) -> Box<Slice> {
+        unsafe { mem::transmute(self.inner.into_boxed_slice()) }
+    }
+
+    #[inline]
+    pub fn from_box(boxed: Box<Slice>) -> Buf {
+        let inner: Box<[u8]> = unsafe { mem::transmute(boxed) };
+        Buf { inner: inner.into_vec() }
+    }
+}
+
+impl Slice {
+    fn from_u8_slice(s: &[u8]) -> &Slice {
+        unsafe { mem::transmute(s) }
+    }
+
+    pub fn from_str(s: &str) -> &Slice {
+        Slice::from_u8_slice(s.as_bytes())
+    }
+
+    pub fn to_str(&self) -> Option<&str> {
+        str::from_utf8(&self.inner).ok()
+    }
+
+    pub fn to_string_lossy(&self) -> Cow<str> {
+        String::from_utf8_lossy(&self.inner)
+    }
+
+    pub fn to_owned(&self) -> Buf {
+        Buf { inner: self.inner.to_vec() }
+    }
+
+    #[inline]
+    pub fn into_box(&self) -> Box<Slice> {
+        let boxed: Box<[u8]> = self.inner.into();
+        unsafe { mem::transmute(boxed) }
+    }
+
+    pub fn empty_box() -> Box<Slice> {
+        let boxed: Box<[u8]> = Default::default();
+        unsafe { mem::transmute(boxed) }
+    }
+}
diff --git a/src/libstd/sys/wasm/path.rs b/src/libstd/sys/wasm/path.rs
new file mode 100644
index 0000000000000..395b8c1e40e98
--- /dev/null
+++ b/src/libstd/sys/wasm/path.rs
@@ -0,0 +1,29 @@
+// Copyright 2017 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 path::Prefix;
+use ffi::OsStr;
+
+#[inline]
+pub fn is_sep_byte(b: u8) -> bool {
+    b == b'/'
+}
+
+#[inline]
+pub fn is_verbatim_sep(b: u8) -> bool {
+    b == b'/'
+}
+
+pub fn parse_prefix(_: &OsStr) -> Option<Prefix> {
+    None
+}
+
+pub const MAIN_SEP_STR: &'static str = "/";
+pub const MAIN_SEP: char = '/';
diff --git a/src/libstd/sys/wasm/pipe.rs b/src/libstd/sys/wasm/pipe.rs
new file mode 100644
index 0000000000000..992e1ac409cfb
--- /dev/null
+++ b/src/libstd/sys/wasm/pipe.rs
@@ -0,0 +1,35 @@
+// Copyright 2017 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 io;
+use sys::Void;
+
+pub struct AnonPipe(Void);
+
+impl AnonPipe {
+    pub fn read(&self, _buf: &mut [u8]) -> io::Result<usize> {
+        match self.0 {}
+    }
+
+    pub fn write(&self, _buf: &[u8]) -> io::Result<usize> {
+        match self.0 {}
+    }
+
+    pub fn diverge(&self) -> ! {
+        match self.0 {}
+    }
+}
+
+pub fn read2(p1: AnonPipe,
+             _v1: &mut Vec<u8>,
+             _p2: AnonPipe,
+             _v2: &mut Vec<u8>) -> io::Result<()> {
+    match p1.0 {}
+}
diff --git a/src/libstd/sys/wasm/process.rs b/src/libstd/sys/wasm/process.rs
new file mode 100644
index 0000000000000..4febe8a146382
--- /dev/null
+++ b/src/libstd/sys/wasm/process.rs
@@ -0,0 +1,151 @@
+// Copyright 2017 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 ffi::OsStr;
+use fmt;
+use io;
+use sys::fs::File;
+use sys::pipe::AnonPipe;
+use sys::{unsupported, Void};
+
+////////////////////////////////////////////////////////////////////////////////
+// Command
+////////////////////////////////////////////////////////////////////////////////
+
+pub struct Command {
+}
+
+// passed back to std::process with the pipes connected to the child, if any
+// were requested
+pub struct StdioPipes {
+    pub stdin: Option<AnonPipe>,
+    pub stdout: Option<AnonPipe>,
+    pub stderr: Option<AnonPipe>,
+}
+
+pub enum Stdio {
+    Inherit,
+    Null,
+    MakePipe,
+}
+
+impl Command {
+    pub fn new(_program: &OsStr) -> Command {
+        Command {}
+    }
+
+    pub fn arg(&mut self, _arg: &OsStr) {
+    }
+
+    pub fn env(&mut self, _key: &OsStr, _val: &OsStr) {
+    }
+
+    pub fn env_remove(&mut self, _key: &OsStr) {
+    }
+
+    pub fn env_clear(&mut self) {
+    }
+
+    pub fn cwd(&mut self, _dir: &OsStr) {
+    }
+
+    pub fn stdin(&mut self, _stdin: Stdio) {
+    }
+
+    pub fn stdout(&mut self, _stdout: Stdio) {
+    }
+
+    pub fn stderr(&mut self, _stderr: Stdio) {
+    }
+
+    pub fn spawn(&mut self, _default: Stdio, _needs_stdin: bool)
+        -> io::Result<(Process, StdioPipes)> {
+        unsupported()
+    }
+}
+
+impl From<AnonPipe> for Stdio {
+    fn from(pipe: AnonPipe) -> Stdio {
+        pipe.diverge()
+    }
+}
+
+impl From<File> for Stdio {
+    fn from(file: File) -> Stdio {
+        file.diverge()
+    }
+}
+
+impl fmt::Debug for Command {
+    fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
+        Ok(())
+    }
+}
+
+pub struct ExitStatus(Void);
+
+impl ExitStatus {
+    pub fn success(&self) -> bool {
+        match self.0 {}
+    }
+
+    pub fn code(&self) -> Option<i32> {
+        match self.0 {}
+    }
+}
+
+impl Clone for ExitStatus {
+    fn clone(&self) -> ExitStatus {
+        match self.0 {}
+    }
+}
+
+impl Copy for ExitStatus {}
+
+impl PartialEq for ExitStatus {
+    fn eq(&self, _other: &ExitStatus) -> bool {
+        match self.0 {}
+    }
+}
+
+impl Eq for ExitStatus {
+}
+
+impl fmt::Debug for ExitStatus {
+    fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
+        match self.0 {}
+    }
+}
+
+impl fmt::Display for ExitStatus {
+    fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
+        match self.0 {}
+    }
+}
+
+pub struct Process(Void);
+
+impl Process {
+    pub fn id(&self) -> u32 {
+        match self.0 {}
+    }
+
+    pub fn kill(&mut self) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn wait(&mut self) -> io::Result<ExitStatus> {
+        match self.0 {}
+    }
+
+    pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
+        match self.0 {}
+    }
+}
diff --git a/src/libstd/sys/wasm/rwlock.rs b/src/libstd/sys/wasm/rwlock.rs
new file mode 100644
index 0000000000000..8b06f54167487
--- /dev/null
+++ b/src/libstd/sys/wasm/rwlock.rs
@@ -0,0 +1,82 @@
+// Copyright 2017 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 cell::UnsafeCell;
+
+pub struct RWLock {
+    mode: UnsafeCell<isize>,
+}
+
+unsafe impl Send for RWLock {}
+unsafe impl Sync for RWLock {} // no threads on wasm
+
+impl RWLock {
+    pub const fn new() -> RWLock {
+        RWLock {
+            mode: UnsafeCell::new(0),
+        }
+    }
+
+    #[inline]
+    pub unsafe fn read(&self) {
+        let mode = self.mode.get();
+        if *mode >= 0 {
+            *mode += 1;
+        } else {
+            panic!("rwlock locked for writing");
+        }
+    }
+
+    #[inline]
+    pub unsafe fn try_read(&self) -> bool {
+        let mode = self.mode.get();
+        if *mode >= 0 {
+            *mode += 1;
+            true
+        } else {
+            false
+        }
+    }
+
+    #[inline]
+    pub unsafe fn write(&self) {
+        let mode = self.mode.get();
+        if *mode == 0 {
+            *mode = -1;
+        } else {
+            panic!("rwlock locked for reading")
+        }
+    }
+
+    #[inline]
+    pub unsafe fn try_write(&self) -> bool {
+        let mode = self.mode.get();
+        if *mode == 0 {
+            *mode = -1;
+            true
+        } else {
+            false
+        }
+    }
+
+    #[inline]
+    pub unsafe fn read_unlock(&self) {
+        *self.mode.get() -= 1;
+    }
+
+    #[inline]
+    pub unsafe fn write_unlock(&self) {
+        *self.mode.get() += 1;
+    }
+
+    #[inline]
+    pub unsafe fn destroy(&self) {
+    }
+}
diff --git a/src/libstd/sys/wasm/stack_overflow.rs b/src/libstd/sys/wasm/stack_overflow.rs
new file mode 100644
index 0000000000000..bed274142f1ce
--- /dev/null
+++ b/src/libstd/sys/wasm/stack_overflow.rs
@@ -0,0 +1,23 @@
+// Copyright 2017 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.
+
+pub struct Handler;
+
+impl Handler {
+    pub unsafe fn new() -> Handler {
+        Handler
+    }
+}
+
+pub unsafe fn init() {
+}
+
+pub unsafe fn cleanup() {
+}
diff --git a/src/libstd/sys/wasm/stdio.rs b/src/libstd/sys/wasm/stdio.rs
new file mode 100644
index 0000000000000..0f75f24025183
--- /dev/null
+++ b/src/libstd/sys/wasm/stdio.rs
@@ -0,0 +1,92 @@
+// Copyright 2017 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 io;
+use sys::{Void, unsupported};
+
+pub struct Stdin(Void);
+pub struct Stdout;
+pub struct Stderr;
+
+impl Stdin {
+    pub fn new() -> io::Result<Stdin> {
+        unsupported()
+    }
+
+    pub fn read(&self, _data: &mut [u8]) -> io::Result<usize> {
+        match self.0 {}
+    }
+}
+
+impl Stdout {
+    pub fn new() -> io::Result<Stdout> {
+        Ok(Stdout)
+    }
+
+    pub fn write(&self, data: &[u8]) -> io::Result<usize> {
+        // If runtime debugging is enabled at compile time we'll invoke some
+        // runtime functions that are defined in our src/etc/wasm32-shim.js
+        // debugging script. Note that this ffi function call is intended
+        // *purely* for debugging only and should not be relied upon.
+        if !super::DEBUG {
+            return unsupported()
+        }
+        extern {
+            fn rust_wasm_write_stdout(data: *const u8, len: usize);
+        }
+        unsafe {
+            rust_wasm_write_stdout(data.as_ptr(), data.len())
+        }
+        Ok(data.len())
+    }
+
+    pub fn flush(&self) -> io::Result<()> {
+        Ok(())
+    }
+}
+
+impl Stderr {
+    pub fn new() -> io::Result<Stderr> {
+        Ok(Stderr)
+    }
+
+    pub fn write(&self, data: &[u8]) -> io::Result<usize> {
+        // See comments in stdout for what's going on here.
+        if !super::DEBUG {
+            return unsupported()
+        }
+        extern {
+            fn rust_wasm_write_stderr(data: *const u8, len: usize);
+        }
+        unsafe {
+            rust_wasm_write_stderr(data.as_ptr(), data.len())
+        }
+        Ok(data.len())
+    }
+
+    pub fn flush(&self) -> io::Result<()> {
+        Ok(())
+    }
+}
+
+impl io::Write for Stderr {
+    fn write(&mut self, data: &[u8]) -> io::Result<usize> {
+        (&*self).write(data)
+    }
+    fn flush(&mut self) -> io::Result<()> {
+        (&*self).flush()
+    }
+}
+
+pub const STDIN_BUF_SIZE: usize = 0;
+
+pub fn is_ebadf(_err: &io::Error) -> bool {
+    true
+}
diff --git a/src/libstd/sys/wasm/thread.rs b/src/libstd/sys/wasm/thread.rs
new file mode 100644
index 0000000000000..13980e0cc19d1
--- /dev/null
+++ b/src/libstd/sys/wasm/thread.rs
@@ -0,0 +1,48 @@
+// Copyright 2017 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 alloc::boxed::FnBox;
+use ffi::CStr;
+use io;
+use sys::{unsupported, Void};
+use time::Duration;
+
+pub struct Thread(Void);
+
+pub const DEFAULT_MIN_STACK_SIZE: usize = 4096;
+
+impl Thread {
+    pub unsafe fn new<'a>(_stack: usize, _p: Box<FnBox() + 'a>)
+        -> io::Result<Thread>
+    {
+        unsupported()
+    }
+
+    pub fn yield_now() {
+        // do nothing
+    }
+
+    pub fn set_name(_name: &CStr) {
+        // nope
+    }
+
+    pub fn sleep(_dur: Duration) {
+        panic!("can't sleep");
+    }
+
+    pub fn join(self) {
+        match self.0 {}
+    }
+}
+
+pub mod guard {
+    pub unsafe fn current() -> Option<usize> { None }
+    pub unsafe fn init() -> Option<usize> { None }
+}
diff --git a/src/libstd/sys/wasm/thread_local.rs b/src/libstd/sys/wasm/thread_local.rs
new file mode 100644
index 0000000000000..442dd3302a058
--- /dev/null
+++ b/src/libstd/sys/wasm/thread_local.rs
@@ -0,0 +1,50 @@
+// Copyright 2017 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 boxed::Box;
+use ptr;
+
+pub type Key = usize;
+
+struct Allocated {
+    value: *mut u8,
+    dtor: Option<unsafe extern fn(*mut u8)>,
+}
+
+#[inline]
+pub unsafe fn create(dtor: Option<unsafe extern fn(*mut u8)>) -> Key {
+    Box::into_raw(Box::new(Allocated {
+        value: ptr::null_mut(),
+        dtor,
+    })) as usize
+}
+
+#[inline]
+pub unsafe fn set(key: Key, value: *mut u8) {
+    (*(key as *mut Allocated)).value = value;
+}
+
+#[inline]
+pub unsafe fn get(key: Key) -> *mut u8 {
+    (*(key as *mut Allocated)).value
+}
+
+#[inline]
+pub unsafe fn destroy(key: Key) {
+    let key = Box::from_raw(key as *mut Allocated);
+    if let Some(f) = key.dtor {
+        f(key.value);
+    }
+}
+
+#[inline]
+pub fn requires_synchronized_create() -> bool {
+    false
+}
diff --git a/src/libstd/sys/wasm/time.rs b/src/libstd/sys/wasm/time.rs
new file mode 100644
index 0000000000000..7907720e4dac6
--- /dev/null
+++ b/src/libstd/sys/wasm/time.rs
@@ -0,0 +1,63 @@
+// Copyright 2017 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 fmt;
+use time::Duration;
+
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
+pub struct Instant;
+
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
+pub struct SystemTime;
+
+pub const UNIX_EPOCH: SystemTime = SystemTime;
+
+impl Instant {
+    pub fn now() -> Instant {
+        panic!("not supported on web assembly");
+    }
+
+    pub fn sub_instant(&self, _other: &Instant) -> Duration {
+        panic!("can't sub yet");
+    }
+
+    pub fn add_duration(&self, _other: &Duration) -> Instant {
+        panic!("can't add yet");
+    }
+
+    pub fn sub_duration(&self, _other: &Duration) -> Instant {
+        panic!("can't sub yet");
+    }
+}
+
+impl SystemTime {
+    pub fn now() -> SystemTime {
+        panic!("not supported on web assembly");
+    }
+
+    pub fn sub_time(&self, _other: &SystemTime)
+                    -> Result<Duration, Duration> {
+        panic!()
+    }
+
+    pub fn add_duration(&self, _other: &Duration) -> SystemTime {
+        panic!()
+    }
+
+    pub fn sub_duration(&self, _other: &Duration) -> SystemTime {
+        panic!()
+    }
+}
+
+impl fmt::Debug for SystemTime {
+    fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
+        panic!()
+    }
+}
diff --git a/src/libstd/sys_common/mod.rs b/src/libstd/sys_common/mod.rs
index d7654ce9300b3..14e5697b94e57 100644
--- a/src/libstd/sys_common/mod.rs
+++ b/src/libstd/sys_common/mod.rs
@@ -44,11 +44,15 @@ pub mod thread_local;
 pub mod util;
 pub mod wtf8;
 
-#[cfg(any(target_os = "redox", target_os = "l4re"))]
-pub use sys::net;
-
-#[cfg(not(any(target_os = "redox", target_os = "l4re")))]
-pub mod net;
+cfg_if! {
+    if #[cfg(any(target_os = "redox", target_os = "l4re"))] {
+        pub use sys::net;
+    } else if #[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))] {
+        pub use sys::net;
+    } else {
+        pub mod net;
+    }
+}
 
 #[cfg(feature = "backtrace")]
 #[cfg(any(all(unix, not(target_os = "emscripten")),
diff --git a/src/libstd/sys_common/thread.rs b/src/libstd/sys_common/thread.rs
index c19424f295226..f1379b6ec6375 100644
--- a/src/libstd/sys_common/thread.rs
+++ b/src/libstd/sys_common/thread.rs
@@ -8,12 +8,13 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use env;
 use alloc::boxed::FnBox;
+use env;
 use sync::atomic::{self, Ordering};
 use sys::stack_overflow;
 use sys::thread as imp;
 
+#[allow(dead_code)]
 pub unsafe fn start_thread(main: *mut u8) {
     // Next, set up our stack overflow handler which may get triggered if we run
     // out of stack.
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index 97eec3a21e9d1..ebe7853b8abdb 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -415,6 +415,9 @@ declare_features! (
 
     // Allow trait methods with arbitrary self types
     (active, arbitrary_self_types, "1.23.0", Some(44874)),
+
+    // #![wasm_import_memory] attribute
+    (active, wasm_import_memory, "1.22.0", None),
 );
 
 declare_features! (
@@ -928,6 +931,11 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG
                                       never be stable",
                                      cfg_fn!(rustc_attrs))),
 
+    ("wasm_import_memory", Whitelisted, Gated(Stability::Unstable,
+                                 "wasm_import_memory",
+                                 "wasm_import_memory attribute is currently unstable",
+                                 cfg_fn!(wasm_import_memory))),
+
     // Crate level attributes
     ("crate_name", CrateLevel, Ungated),
     ("crate_type", CrateLevel, Ungated),
diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs
index 76abcb83edc53..ef08b877262fc 100644
--- a/src/libtest/lib.rs
+++ b/src/libtest/lib.rs
@@ -434,7 +434,8 @@ Test Attributes:
 // Parses command line arguments into test options
 pub fn parse_opts(args: &[String]) -> Option<OptRes> {
     let opts = optgroups();
-    let matches = match opts.parse(&args[1..]) {
+    let args = args.get(1..).unwrap_or(args);
+    let matches = match opts.parse(args) {
         Ok(m) => m,
         Err(f) => return Some(Err(f.to_string())),
     };
@@ -1034,6 +1035,10 @@ fn stdout_isatty() -> bool {
     // FIXME: Implement isatty on Redox
     false
 }
+#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
+fn stdout_isatty() -> bool {
+    false
+}
 #[cfg(unix)]
 fn stdout_isatty() -> bool {
     unsafe { libc::isatty(libc::STDOUT_FILENO) != 0 }
@@ -1132,45 +1137,47 @@ pub fn run_tests<F>(opts: &TestOpts, tests: Vec<TestDescAndFn>, mut callback: F)
             }})
     };
 
-    while pending > 0 || !remaining.is_empty() {
-        while pending < concurrency && !remaining.is_empty() {
+    if concurrency == 1 {
+        while !remaining.is_empty() {
             let test = remaining.pop().unwrap();
-            if concurrency == 1 {
-                // We are doing one test at a time so we can print the name
-                // of the test before we run it. Useful for debugging tests
-                // that hang forever.
-                callback(TeWait(test.desc.clone(), test.testfn.padding()))?;
-            }
-            let timeout = Instant::now() + Duration::from_secs(TEST_WARN_TIMEOUT_S);
-            running_tests.insert(test.desc.clone(), timeout);
+            callback(TeWait(test.desc.clone(), test.testfn.padding()))?;
             run_test(opts, !opts.run_tests, test, tx.clone());
-            pending += 1;
+            let (test, result, stdout) = rx.recv().unwrap();
+            callback(TeResult(test, result, stdout))?;
         }
+    } else {
+        while pending > 0 || !remaining.is_empty() {
+            while pending < concurrency && !remaining.is_empty() {
+                let test = remaining.pop().unwrap();
+                let timeout = Instant::now() + Duration::from_secs(TEST_WARN_TIMEOUT_S);
+                running_tests.insert(test.desc.clone(), timeout);
+                run_test(opts, !opts.run_tests, test, tx.clone());
+                pending += 1;
+            }
 
-        let mut res;
-        loop {
-            if let Some(timeout) = calc_timeout(&running_tests) {
-                res = rx.recv_timeout(timeout);
-                for test in get_timed_out_tests(&mut running_tests) {
-                    callback(TeTimeout(test))?;
-                }
-                if res != Err(RecvTimeoutError::Timeout) {
+            let mut res;
+            loop {
+                if let Some(timeout) = calc_timeout(&running_tests) {
+                    res = rx.recv_timeout(timeout);
+                    for test in get_timed_out_tests(&mut running_tests) {
+                        callback(TeTimeout(test))?;
+                    }
+                    if res != Err(RecvTimeoutError::Timeout) {
+                        break;
+                    }
+                } else {
+                    res = rx.recv().map_err(|_| RecvTimeoutError::Disconnected);
                     break;
                 }
-            } else {
-                res = rx.recv().map_err(|_| RecvTimeoutError::Disconnected);
-                break;
             }
-        }
 
-        let (desc, result, stdout) = res.unwrap();
-        running_tests.remove(&desc);
+            let (desc, result, stdout) = res.unwrap();
+            running_tests.remove(&desc);
 
-        if concurrency != 1 {
             callback(TeWait(desc.clone(), PadNone))?;
+            callback(TeResult(desc, result, stdout))?;
+            pending -= 1;
         }
-        callback(TeResult(desc, result, stdout))?;
-        pending -= 1;
     }
 
     if opts.bench_benchmarks {
@@ -1235,6 +1242,11 @@ fn get_concurrency() -> usize {
         1
     }
 
+    #[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
+    fn num_cpus() -> usize {
+        1
+    }
+
     #[cfg(any(target_os = "linux",
               target_os = "macos",
               target_os = "ios",
@@ -1393,7 +1405,12 @@ pub fn run_test(opts: &TestOpts,
 
     let TestDescAndFn {desc, testfn} = test;
 
-    if force_ignore || desc.ignore {
+    let ignore_because_panic_abort =
+        cfg!(target_arch = "wasm32") &&
+        !cfg!(target_os = "emscripten") &&
+        desc.should_panic != ShouldPanic::No;
+
+    if force_ignore || desc.ignore || ignore_because_panic_abort {
         monitor_ch.send((desc, TrIgnored, Vec::new())).unwrap();
         return;
     }
@@ -1445,7 +1462,9 @@ pub fn run_test(opts: &TestOpts,
         // 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");
+        let supports_threads =
+            !cfg!(target_os = "emscripten") &&
+            !cfg!(target_arch = "wasm32");
         if supports_threads {
             let cfg = thread::Builder::new().name(match name {
                 DynTestName(ref name) => name.clone(),
diff --git a/src/libunwind/lib.rs b/src/libunwind/lib.rs
index 461b49aa363b4..5bb1eb96dcfad 100644
--- a/src/libunwind/lib.rs
+++ b/src/libunwind/lib.rs
@@ -20,13 +20,20 @@
 
 #![cfg_attr(not(target_env = "msvc"), feature(libc))]
 
-#[cfg(not(target_env = "msvc"))]
-extern crate libc;
+#[macro_use]
+mod macros;
 
-#[cfg(not(target_env = "msvc"))]
-mod libunwind;
-#[cfg(not(target_env = "msvc"))]
-pub use libunwind::*;
+cfg_if! {
+    if #[cfg(target_env = "msvc")] {
+        // no extra unwinder support needed
+    } else if #[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))] {
+        // no unwinder on the system!
+    } else {
+        extern crate libc;
+        mod libunwind;
+        pub use libunwind::*;
+    }
+}
 
 #[cfg(all(target_env = "musl", not(target_arch = "mips")))]
 #[link(name = "unwind", kind = "static", cfg(target_feature = "crt-static"))]
diff --git a/src/libunwind/macros.rs b/src/libunwind/macros.rs
new file mode 100644
index 0000000000000..26376a3733f4f
--- /dev/null
+++ b/src/libunwind/macros.rs
@@ -0,0 +1,45 @@
+// Copyright 2017 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.
+
+/// A macro for defining #[cfg] if-else statements.
+///
+/// This is similar to the `if/elif` C preprocessor macro by allowing definition
+/// of a cascade of `#[cfg]` cases, emitting the implementation which matches
+/// first.
+///
+/// This allows you to conveniently provide a long list #[cfg]'d blocks of code
+/// without having to rewrite each clause multiple times.
+macro_rules! cfg_if {
+    ($(
+        if #[cfg($($meta:meta),*)] { $($it:item)* }
+    ) else * else {
+        $($it2:item)*
+    }) => {
+        __cfg_if_items! {
+            () ;
+            $( ( ($($meta),*) ($($it)*) ), )*
+            ( () ($($it2)*) ),
+        }
+    }
+}
+
+macro_rules! __cfg_if_items {
+    (($($not:meta,)*) ; ) => {};
+    (($($not:meta,)*) ; ( ($($m:meta),*) ($($it:item)*) ), $($rest:tt)*) => {
+        __cfg_if_apply! { cfg(all(not(any($($not),*)), $($m,)*)), $($it)* }
+        __cfg_if_items! { ($($not,)* $($m,)*) ; $($rest)* }
+    }
+}
+
+macro_rules! __cfg_if_apply {
+    ($m:meta, $($it:item)*) => {
+        $(#[$m] $it)*
+    }
+}
diff --git a/src/rustc/dlmalloc_shim/Cargo.toml b/src/rustc/dlmalloc_shim/Cargo.toml
new file mode 100644
index 0000000000000..cf8440c40da1a
--- /dev/null
+++ b/src/rustc/dlmalloc_shim/Cargo.toml
@@ -0,0 +1,14 @@
+[package]
+name = "dlmalloc"
+version = "0.0.0"
+authors = ["The Rust Project Developers"]
+
+[lib]
+path = "../../dlmalloc/src/lib.rs"
+test = false
+bench = false
+doc = false
+
+[dependencies]
+core = { path = "../../libcore" }
+alloc = { path = "../../liballoc" }
diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp
index b4116c96ba130..d0c042e6451c7 100644
--- a/src/rustllvm/PassWrapper.cpp
+++ b/src/rustllvm/PassWrapper.cpp
@@ -366,7 +366,9 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine(
     LLVMRustCodeModel RustCM, LLVMRustRelocMode RustReloc,
     LLVMRustCodeGenOptLevel RustOptLevel, bool UseSoftFloat,
     bool PositionIndependentExecutable, bool FunctionSections,
-    bool DataSections, bool TrapUnreachable) {
+    bool DataSections,
+    bool TrapUnreachable,
+    bool Singlethread) {
 
   auto CM = fromRust(RustCM);
   auto OptLevel = fromRust(RustOptLevel);
@@ -406,6 +408,10 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine(
     Options.TrapUnreachable = true;
   }
 
+  if (Singlethread) {
+    Options.ThreadModel = ThreadModel::Single;
+  }
+
   TargetMachine *TM = TheTarget->createTargetMachine(
       Trip.getTriple(), RealCPU, Feature, Options, RM, CM, OptLevel);
   return wrap(TM);
diff --git a/src/test/compile-fail/feature-gate-wasm_import_memory.rs b/src/test/compile-fail/feature-gate-wasm_import_memory.rs
new file mode 100644
index 0000000000000..a010ebb3551d0
--- /dev/null
+++ b/src/test/compile-fail/feature-gate-wasm_import_memory.rs
@@ -0,0 +1,14 @@
+// Copyright 2017 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.
+
+#![wasm_import_memory] //~ ERROR: currently unstable
+
+fn main() {}
+
diff --git a/src/test/run-pass-fulldeps/flt2dec.rs b/src/test/run-pass-fulldeps/flt2dec.rs
new file mode 100644
index 0000000000000..3db0644d1ef3c
--- /dev/null
+++ b/src/test/run-pass-fulldeps/flt2dec.rs
@@ -0,0 +1,163 @@
+// Copyright 2017 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.
+
+// compile-flags:--test
+
+#![feature(rustc_private, flt2dec)]
+
+extern crate core;
+extern crate rand;
+
+use std::i16;
+use std::mem;
+use std::str;
+
+use core::num::flt2dec::MAX_SIG_DIGITS;
+use core::num::flt2dec::strategy::grisu::format_exact_opt;
+use core::num::flt2dec::strategy::grisu::format_shortest_opt;
+use core::num::flt2dec::{decode, DecodableFloat, FullDecoded, Decoded};
+
+use rand::{Rand, XorShiftRng};
+use rand::distributions::{IndependentSample, Range};
+pub fn decode_finite<T: DecodableFloat>(v: T) -> Decoded {
+    match decode(v).1 {
+        FullDecoded::Finite(decoded) => decoded,
+        full_decoded => panic!("expected finite, got {:?} instead", full_decoded)
+    }
+}
+
+
+fn iterate<F, G, V>(func: &str, k: usize, n: usize, mut f: F, mut g: G, mut v: V) -> (usize, usize)
+        where F: FnMut(&Decoded, &mut [u8]) -> Option<(usize, i16)>,
+              G: FnMut(&Decoded, &mut [u8]) -> (usize, i16),
+              V: FnMut(usize) -> Decoded {
+    assert!(k <= 1024);
+
+    let mut npassed = 0; // f(x) = Some(g(x))
+    let mut nignored = 0; // f(x) = None
+
+    for i in 0..n {
+        if (i & 0xfffff) == 0 {
+            println!("in progress, {:x}/{:x} (ignored={} passed={} failed={})",
+                     i, n, nignored, npassed, i - nignored - npassed);
+        }
+
+        let decoded = v(i);
+        let mut buf1 = [0; 1024];
+        if let Some((len1, e1)) = f(&decoded, &mut buf1[..k]) {
+            let mut buf2 = [0; 1024];
+            let (len2, e2) = g(&decoded, &mut buf2[..k]);
+            if e1 == e2 && &buf1[..len1] == &buf2[..len2] {
+                npassed += 1;
+            } else {
+                println!("equivalence test failed, {:x}/{:x}: {:?} f(i)={}e{} g(i)={}e{}",
+                         i, n, decoded, str::from_utf8(&buf1[..len1]).unwrap(), e1,
+                                        str::from_utf8(&buf2[..len2]).unwrap(), e2);
+            }
+        } else {
+            nignored += 1;
+        }
+    }
+    println!("{}({}): done, ignored={} passed={} failed={}",
+             func, k, nignored, npassed, n - nignored - npassed);
+    assert!(nignored + npassed == n,
+            "{}({}): {} out of {} values returns an incorrect value!",
+            func, k, n - nignored - npassed, n);
+    (npassed, nignored)
+}
+
+pub fn f32_random_equivalence_test<F, G>(f: F, g: G, k: usize, n: usize)
+        where F: FnMut(&Decoded, &mut [u8]) -> Option<(usize, i16)>,
+              G: FnMut(&Decoded, &mut [u8]) -> (usize, i16) {
+    let mut rng: XorShiftRng = Rand::rand(&mut rand::thread_rng());
+    let f32_range = Range::new(0x0000_0001u32, 0x7f80_0000);
+    iterate("f32_random_equivalence_test", k, n, f, g, |_| {
+        let i: u32 = f32_range.ind_sample(&mut rng);
+        let x: f32 = unsafe {mem::transmute(i)};
+        decode_finite(x)
+    });
+}
+
+pub fn f64_random_equivalence_test<F, G>(f: F, g: G, k: usize, n: usize)
+        where F: FnMut(&Decoded, &mut [u8]) -> Option<(usize, i16)>,
+              G: FnMut(&Decoded, &mut [u8]) -> (usize, i16) {
+    let mut rng: XorShiftRng = Rand::rand(&mut rand::thread_rng());
+    let f64_range = Range::new(0x0000_0000_0000_0001u64, 0x7ff0_0000_0000_0000);
+    iterate("f64_random_equivalence_test", k, n, f, g, |_| {
+        let i: u64 = f64_range.ind_sample(&mut rng);
+        let x: f64 = unsafe {mem::transmute(i)};
+        decode_finite(x)
+    });
+}
+
+pub fn f32_exhaustive_equivalence_test<F, G>(f: F, g: G, k: usize)
+        where F: FnMut(&Decoded, &mut [u8]) -> Option<(usize, i16)>,
+              G: FnMut(&Decoded, &mut [u8]) -> (usize, i16) {
+    // we have only 2^23 * (2^8 - 1) - 1 = 2,139,095,039 positive finite f32 values,
+    // so why not simply testing all of them?
+    //
+    // this is of course very stressful (and thus should be behind an `#[ignore]` attribute),
+    // but with `-C opt-level=3 -C lto` this only takes about an hour or so.
+
+    // iterate from 0x0000_0001 to 0x7f7f_ffff, i.e. all finite ranges
+    let (npassed, nignored) = iterate("f32_exhaustive_equivalence_test",
+                                      k, 0x7f7f_ffff, f, g, |i: usize| {
+        let x: f32 = unsafe {mem::transmute(i as u32 + 1)};
+        decode_finite(x)
+    });
+    assert_eq!((npassed, nignored), (2121451881, 17643158));
+}
+
+#[test]
+fn shortest_random_equivalence_test() {
+    use core::num::flt2dec::strategy::dragon::format_shortest as fallback;
+    f64_random_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS, 10_000);
+    f32_random_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS, 10_000);
+}
+
+#[test] #[ignore] // it is too expensive
+fn shortest_f32_exhaustive_equivalence_test() {
+    // it is hard to directly test the optimality of the output, but we can at least test if
+    // two different algorithms agree to each other.
+    //
+    // this reports the progress and the number of f32 values returned `None`.
+    // with `--nocapture` (and plenty of time and appropriate rustc flags), this should print:
+    // `done, ignored=17643158 passed=2121451881 failed=0`.
+
+    use core::num::flt2dec::strategy::dragon::format_shortest as fallback;
+    f32_exhaustive_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS);
+}
+
+#[test] #[ignore] // it is too expensive
+fn shortest_f64_hard_random_equivalence_test() {
+    // this again probably has to use appropriate rustc flags.
+
+    use core::num::flt2dec::strategy::dragon::format_shortest as fallback;
+    f64_random_equivalence_test(format_shortest_opt, fallback,
+                                         MAX_SIG_DIGITS, 100_000_000);
+}
+
+#[test]
+fn exact_f32_random_equivalence_test() {
+    use core::num::flt2dec::strategy::dragon::format_exact as fallback;
+    for k in 1..21 {
+        f32_random_equivalence_test(|d, buf| format_exact_opt(d, buf, i16::MIN),
+                                             |d, buf| fallback(d, buf, i16::MIN), k, 1_000);
+    }
+}
+
+#[test]
+fn exact_f64_random_equivalence_test() {
+    use core::num::flt2dec::strategy::dragon::format_exact as fallback;
+    for k in 1..21 {
+        f64_random_equivalence_test(|d, buf| format_exact_opt(d, buf, i16::MIN),
+                                             |d, buf| fallback(d, buf, i16::MIN), k, 1_000);
+    }
+}
diff --git a/src/test/run-pass-fulldeps/sort-unstable.rs b/src/test/run-pass-fulldeps/sort-unstable.rs
new file mode 100644
index 0000000000000..af8a691aa3ec6
--- /dev/null
+++ b/src/test/run-pass-fulldeps/sort-unstable.rs
@@ -0,0 +1,83 @@
+// Copyright 2017 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.
+
+#![feature(rustc_private, sort_internals)]
+
+extern crate core;
+extern crate rand;
+
+use std::cmp::Ordering::{Equal, Greater, Less};
+use core::slice::heapsort;
+
+use rand::{Rng, XorShiftRng};
+
+fn main() {
+    let mut v = [0; 600];
+    let mut tmp = [0; 600];
+    let mut rng = XorShiftRng::new_unseeded();
+
+    for len in (2..25).chain(500..510) {
+        let v = &mut v[0..len];
+        let tmp = &mut tmp[0..len];
+
+        for &modulus in &[5, 10, 100, 1000] {
+            for _ in 0..100 {
+                for i in 0..len {
+                    v[i] = rng.gen::<i32>() % modulus;
+                }
+
+                // Sort in default order.
+                tmp.copy_from_slice(v);
+                tmp.sort_unstable();
+                assert!(tmp.windows(2).all(|w| w[0] <= w[1]));
+
+                // Sort in ascending order.
+                tmp.copy_from_slice(v);
+                tmp.sort_unstable_by(|a, b| a.cmp(b));
+                assert!(tmp.windows(2).all(|w| w[0] <= w[1]));
+
+                // Sort in descending order.
+                tmp.copy_from_slice(v);
+                tmp.sort_unstable_by(|a, b| b.cmp(a));
+                assert!(tmp.windows(2).all(|w| w[0] >= w[1]));
+
+                // Test heapsort using `<` operator.
+                tmp.copy_from_slice(v);
+                heapsort(tmp, |a, b| a < b);
+                assert!(tmp.windows(2).all(|w| w[0] <= w[1]));
+
+                // Test heapsort using `>` operator.
+                tmp.copy_from_slice(v);
+                heapsort(tmp, |a, b| a > b);
+                assert!(tmp.windows(2).all(|w| w[0] >= w[1]));
+            }
+        }
+    }
+
+    // Sort using a completely random comparison function.
+    // This will reorder the elements *somehow*, but won't panic.
+    for i in 0..v.len() {
+        v[i] = i as i32;
+    }
+    v.sort_unstable_by(|_, _| *rng.choose(&[Less, Equal, Greater]).unwrap());
+    v.sort_unstable();
+    for i in 0..v.len() {
+        assert_eq!(v[i], i as i32);
+    }
+
+    // Should not panic.
+    [0i32; 0].sort_unstable();
+    [(); 10].sort_unstable();
+    [(); 100].sort_unstable();
+
+    let mut v = [0xDEADBEEFu64];
+    v.sort_unstable();
+    assert!(v == [0xDEADBEEF]);
+}
diff --git a/src/test/run-pass/allocator/custom.rs b/src/test/run-pass/allocator/custom.rs
index b46f024b5bff3..22081678fb999 100644
--- a/src/test/run-pass/allocator/custom.rs
+++ b/src/test/run-pass/allocator/custom.rs
@@ -15,7 +15,6 @@
 
 extern crate helper;
 
-use std::env;
 use std::heap::{Heap, Alloc, System, Layout, AllocErr};
 use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};
 
@@ -39,8 +38,7 @@ unsafe impl<'a> Alloc for &'a A {
 static GLOBAL: A = A;
 
 fn main() {
-    env::set_var("FOO", "bar");
-    drop(env::var("FOO"));
+    println!("hello!");
 
     let n = HITS.load(Ordering::SeqCst);
     assert!(n > 0);
diff --git a/src/test/run-pass/allocator/xcrate-use.rs b/src/test/run-pass/allocator/xcrate-use.rs
index 4b987b9223d6d..04d2ef466e73d 100644
--- a/src/test/run-pass/allocator/xcrate-use.rs
+++ b/src/test/run-pass/allocator/xcrate-use.rs
@@ -17,7 +17,6 @@
 extern crate custom;
 extern crate helper;
 
-use std::env;
 use std::heap::{Heap, Alloc, System, Layout};
 use std::sync::atomic::{Ordering, ATOMIC_USIZE_INIT};
 
diff --git a/src/test/run-pass/allocator/xcrate-use2.rs b/src/test/run-pass/allocator/xcrate-use2.rs
index 7e6cd9fdf4950..155fb5d6c5de9 100644
--- a/src/test/run-pass/allocator/xcrate-use2.rs
+++ b/src/test/run-pass/allocator/xcrate-use2.rs
@@ -19,7 +19,6 @@ extern crate custom;
 extern crate custom_as_global;
 extern crate helper;
 
-use std::env;
 use std::heap::{Heap, Alloc, System, Layout};
 use std::sync::atomic::{Ordering, ATOMIC_USIZE_INIT};
 
diff --git a/src/test/run-pass/anon-extern-mod-cross-crate-2.rs b/src/test/run-pass/anon-extern-mod-cross-crate-2.rs
index b40774e2be82f..8c480d7deebd9 100644
--- a/src/test/run-pass/anon-extern-mod-cross-crate-2.rs
+++ b/src/test/run-pass/anon-extern-mod-cross-crate-2.rs
@@ -10,6 +10,7 @@
 
 // aux-build:anon-extern-mod-cross-crate-1.rs
 // pretty-expanded FIXME #23616
+// ignore-wasm32-bare no libc to test ffi with
 
 extern crate anonexternmod;
 
diff --git a/src/test/run-pass/anon-extern-mod.rs b/src/test/run-pass/anon-extern-mod.rs
index 208b4df3c3e7e..16ca7bce95b59 100644
--- a/src/test/run-pass/anon-extern-mod.rs
+++ b/src/test/run-pass/anon-extern-mod.rs
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 // pretty-expanded FIXME #23616
+// ignore-wasm32-bare no libc to test ffi with
 
 #![feature(libc)]
 
diff --git a/src/test/run-pass/auxiliary/issue-3012-1.rs b/src/test/run-pass/auxiliary/issue-3012-1.rs
index b6199f59ebe06..f34a97519e77d 100644
--- a/src/test/run-pass/auxiliary/issue-3012-1.rs
+++ b/src/test/run-pass/auxiliary/issue-3012-1.rs
@@ -10,13 +10,10 @@
 
 #![crate_name="socketlib"]
 #![crate_type = "lib"]
-#![feature(libc)]
 
 pub mod socket {
-    extern crate libc;
-
     pub struct socket_handle {
-        sockfd: libc::c_int,
+        sockfd: u32,
     }
 
     impl Drop for socket_handle {
@@ -25,7 +22,7 @@ pub mod socket {
         }
     }
 
-    pub fn socket_handle(x: libc::c_int) -> socket_handle {
+    pub fn socket_handle(x: u32) -> socket_handle {
         socket_handle {
             sockfd: x
         }
diff --git a/src/test/run-pass/builtin-clone-unwind.rs b/src/test/run-pass/builtin-clone-unwind.rs
index 90a411352869c..7e7c5ee412556 100644
--- a/src/test/run-pass/builtin-clone-unwind.rs
+++ b/src/test/run-pass/builtin-clone-unwind.rs
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// ignore-wasm32-bare compiled with panic=abort by default
+
 // Test that builtin implementations of `Clone` cleanup everything
 // in case of unwinding.
 
diff --git a/src/test/run-pass/c-stack-as-value.rs b/src/test/run-pass/c-stack-as-value.rs
index 5319693405b5d..df4989d89ab5e 100644
--- a/src/test/run-pass/c-stack-as-value.rs
+++ b/src/test/run-pass/c-stack-as-value.rs
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 // pretty-expanded FIXME #23616
+// ignore-wasm32-bare no libc to test ffi with
 
 #![feature(libc)]
 
diff --git a/src/test/run-pass/c-stack-returning-int64.rs b/src/test/run-pass/c-stack-returning-int64.rs
index 84f22025a1d7a..46b3fd1f1e746 100644
--- a/src/test/run-pass/c-stack-returning-int64.rs
+++ b/src/test/run-pass/c-stack-returning-int64.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-
+// ignore-wasm32-bare no libc to test with
 
 #![feature(libc, std_misc)]
 
diff --git a/src/test/run-pass/cabi-int-widening.rs b/src/test/run-pass/cabi-int-widening.rs
index bf94dd178821a..5b1677c184c74 100644
--- a/src/test/run-pass/cabi-int-widening.rs
+++ b/src/test/run-pass/cabi-int-widening.rs
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// ignore-wasm32-bare no libc to test ffi with
+
 #[link(name = "rust_test_helpers", kind = "static")]
 extern {
     fn rust_int8_to_int32(_: i8) -> i32;
diff --git a/src/test/run-pass/catch-unwind-bang.rs b/src/test/run-pass/catch-unwind-bang.rs
index df54ec90022ee..849132b8ebfab 100644
--- a/src/test/run-pass/catch-unwind-bang.rs
+++ b/src/test/run-pass/catch-unwind-bang.rs
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// ignore-wasm32-bare compiled with panic=abort by default
+
 fn worker() -> ! {
     panic!()
 }
diff --git a/src/test/run-pass/cfg-family.rs b/src/test/run-pass/cfg-family.rs
index 415607aa72bfc..1797ad1019c3d 100644
--- a/src/test/run-pass/cfg-family.rs
+++ b/src/test/run-pass/cfg-family.rs
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 // pretty-expanded FIXME #23616
+// ignore-wasm32-bare no target_family
 
 #[cfg(windows)]
 pub fn main() {
diff --git a/src/test/run-pass/cfg-target-family.rs b/src/test/run-pass/cfg-target-family.rs
index b6954f7c2eeaf..0b8574e117478 100644
--- a/src/test/run-pass/cfg-target-family.rs
+++ b/src/test/run-pass/cfg-target-family.rs
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// ignore-wasm32-bare no target_family
+
 // pretty-expanded FIXME #23616
 
 #[cfg(target_family = "windows")]
diff --git a/src/test/run-pass/check-static-recursion-foreign.rs b/src/test/run-pass/check-static-recursion-foreign.rs
index 8e718f328ff91..9c87f2ca68203 100644
--- a/src/test/run-pass/check-static-recursion-foreign.rs
+++ b/src/test/run-pass/check-static-recursion-foreign.rs
@@ -11,6 +11,7 @@
 // Static recursion check shouldn't fail when given a foreign item (#18279)
 
 // aux-build:check_static_recursion_foreign_helper.rs
+// ignore-wasm32-bare no libc to test ffi with
 
 // pretty-expanded FIXME #23616
 
diff --git a/src/test/run-pass/const-cast.rs b/src/test/run-pass/const-cast.rs
index 411df2b3e0759..e77fd5f71394e 100644
--- a/src/test/run-pass/const-cast.rs
+++ b/src/test/run-pass/const-cast.rs
@@ -8,21 +8,16 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-
-#![feature(libc)]
-
-extern crate libc;
-
 struct TestStruct {
-    x: *const libc::c_void
+    x: *const u8,
 }
 
 unsafe impl Sync for TestStruct {}
 
 extern fn foo() {}
 const x: extern "C" fn() = foo;
-static y: TestStruct = TestStruct { x: x as *const libc::c_void };
+static y: TestStruct = TestStruct { x: x as *const u8 };
 
 pub fn main() {
-    assert_eq!(x as *const libc::c_void, y.x);
+    assert_eq!(x as *const u8, y.x);
 }
diff --git a/src/test/run-pass/duplicated-external-mods.rs b/src/test/run-pass/duplicated-external-mods.rs
index 91c9887300935..4cb3dbe027a16 100644
--- a/src/test/run-pass/duplicated-external-mods.rs
+++ b/src/test/run-pass/duplicated-external-mods.rs
@@ -11,6 +11,7 @@
 // aux-build:anon-extern-mod-cross-crate-1.rs
 // aux-build:anon-extern-mod-cross-crate-1.rs
 // pretty-expanded FIXME #23616
+// ignore-wasm32-bare no libc to test ffi with
 
 extern crate anonexternmod;
 
diff --git a/src/test/run-pass/dynamic-drop.rs b/src/test/run-pass/dynamic-drop.rs
index 483dbb356ce6a..3310d3a89b92b 100644
--- a/src/test/run-pass/dynamic-drop.rs
+++ b/src/test/run-pass/dynamic-drop.rs
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// ignore-wasm32-bare compiled with panic=abort by default
+
 #![feature(generators, generator_trait, untagged_unions)]
 
 use std::cell::{Cell, RefCell};
diff --git a/src/test/run-pass/env-vars.rs b/src/test/run-pass/env-vars.rs
index 933d9a728dbe7..af44a6567e405 100644
--- a/src/test/run-pass/env-vars.rs
+++ b/src/test/run-pass/env-vars.rs
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// ignore-wasm32-bare no env vars
 
 use std::env::*;
 
diff --git a/src/test/run-pass/extern-call-deep.rs b/src/test/run-pass/extern-call-deep.rs
index 6a9da767ad6eb..a41ab8da9de11 100644
--- a/src/test/run-pass/extern-call-deep.rs
+++ b/src/test/run-pass/extern-call-deep.rs
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// ignore-wasm32-bare no libc to test ffi with
+
 #![feature(libc)]
 
 extern crate libc;
diff --git a/src/test/run-pass/extern-call-indirect.rs b/src/test/run-pass/extern-call-indirect.rs
index 256eedccb8bfa..ba108955c28d6 100644
--- a/src/test/run-pass/extern-call-indirect.rs
+++ b/src/test/run-pass/extern-call-indirect.rs
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// ignore-wasm32-bare no libc to test ffi with
+
 #![feature(libc)]
 
 extern crate libc;
diff --git a/src/test/run-pass/extern-crosscrate.rs b/src/test/run-pass/extern-crosscrate.rs
index 7157d0658be34..825b502d95485 100644
--- a/src/test/run-pass/extern-crosscrate.rs
+++ b/src/test/run-pass/extern-crosscrate.rs
@@ -8,7 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-//aux-build:extern-crosscrate-source.rs
+// aux-build:extern-crosscrate-source.rs
+// ignore-wasm32-bare no libc to test ffi with
 
 #![feature(libc)]
 
diff --git a/src/test/run-pass/extern-pass-TwoU16s.rs b/src/test/run-pass/extern-pass-TwoU16s.rs
index afdd53db775a8..a1aa9b69fadaa 100644
--- a/src/test/run-pass/extern-pass-TwoU16s.rs
+++ b/src/test/run-pass/extern-pass-TwoU16s.rs
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// ignore-wasm32-bare no libc for ffi testing
+
 // Test a foreign function that accepts and returns a struct
 // by value.
 
diff --git a/src/test/run-pass/extern-pass-TwoU32s.rs b/src/test/run-pass/extern-pass-TwoU32s.rs
index 035084ae9bd3a..6442f230d3024 100644
--- a/src/test/run-pass/extern-pass-TwoU32s.rs
+++ b/src/test/run-pass/extern-pass-TwoU32s.rs
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// ignore-wasm32-bare no libc for ffi testing
+
 // Test a foreign function that accepts and returns a struct
 // by value.
 
diff --git a/src/test/run-pass/extern-pass-TwoU64s.rs b/src/test/run-pass/extern-pass-TwoU64s.rs
index cb1a4d278256a..bfb649c3f74ea 100644
--- a/src/test/run-pass/extern-pass-TwoU64s.rs
+++ b/src/test/run-pass/extern-pass-TwoU64s.rs
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// ignore-wasm32-bare no libc for ffi testing
+
 // Test a foreign function that accepts and returns a struct
 // by value.
 
diff --git a/src/test/run-pass/extern-pass-TwoU8s.rs b/src/test/run-pass/extern-pass-TwoU8s.rs
index 657348c99aad8..1f90d9c436677 100644
--- a/src/test/run-pass/extern-pass-TwoU8s.rs
+++ b/src/test/run-pass/extern-pass-TwoU8s.rs
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// ignore-wasm32-bare no libc for ffi testing
+
 // Test a foreign function that accepts and returns a struct
 // by value.
 
diff --git a/src/test/run-pass/extern-pass-char.rs b/src/test/run-pass/extern-pass-char.rs
index 9042aed6639b8..920e15bf2c119 100644
--- a/src/test/run-pass/extern-pass-char.rs
+++ b/src/test/run-pass/extern-pass-char.rs
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// ignore-wasm32-bare no libc for ffi testing
+
 // Test a function that takes/returns a u8.
 
 
diff --git a/src/test/run-pass/extern-pass-double.rs b/src/test/run-pass/extern-pass-double.rs
index 38d29180fbc8f..9c184477ad340 100644
--- a/src/test/run-pass/extern-pass-double.rs
+++ b/src/test/run-pass/extern-pass-double.rs
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// ignore-wasm32-bare no libc for ffi testing
 
 #[link(name = "rust_test_helpers", kind = "static")]
 extern {
diff --git a/src/test/run-pass/extern-pass-u32.rs b/src/test/run-pass/extern-pass-u32.rs
index ed254ac46f20b..691bd6295b143 100644
--- a/src/test/run-pass/extern-pass-u32.rs
+++ b/src/test/run-pass/extern-pass-u32.rs
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// ignore-wasm32-bare no libc for ffi testing
+
 // Test a function that takes/returns a u32.
 
 
diff --git a/src/test/run-pass/extern-pass-u64.rs b/src/test/run-pass/extern-pass-u64.rs
index 6fc630e6d7e1a..4b351ed2836cc 100644
--- a/src/test/run-pass/extern-pass-u64.rs
+++ b/src/test/run-pass/extern-pass-u64.rs
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// ignore-wasm32-bare no libc for ffi testing
+
 // Test a call to a function that takes/returns a u64.
 
 
diff --git a/src/test/run-pass/extern-return-TwoU16s.rs b/src/test/run-pass/extern-return-TwoU16s.rs
index ec1c6130e7adc..b9ce3f4588688 100644
--- a/src/test/run-pass/extern-return-TwoU16s.rs
+++ b/src/test/run-pass/extern-return-TwoU16s.rs
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// ignore-wasm32-bare no libc to test ffi with
 
 pub struct TwoU16s {
     one: u16, two: u16
diff --git a/src/test/run-pass/extern-return-TwoU32s.rs b/src/test/run-pass/extern-return-TwoU32s.rs
index e829e993052a5..686ff16fe4d6b 100644
--- a/src/test/run-pass/extern-return-TwoU32s.rs
+++ b/src/test/run-pass/extern-return-TwoU32s.rs
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// ignore-wasm32-bare no libc to test ffi with
 
 pub struct TwoU32s {
     one: u32, two: u32
diff --git a/src/test/run-pass/extern-return-TwoU64s.rs b/src/test/run-pass/extern-return-TwoU64s.rs
index ef7325b33fe3d..e754674fd1ebd 100644
--- a/src/test/run-pass/extern-return-TwoU64s.rs
+++ b/src/test/run-pass/extern-return-TwoU64s.rs
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// ignore-wasm32-bare no libc to test ffi with
 
 pub struct TwoU64s {
     one: u64, two: u64
diff --git a/src/test/run-pass/extern-return-TwoU8s.rs b/src/test/run-pass/extern-return-TwoU8s.rs
index 46f2e81a5564a..68fe3832e90ab 100644
--- a/src/test/run-pass/extern-return-TwoU8s.rs
+++ b/src/test/run-pass/extern-return-TwoU8s.rs
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// ignore-wasm32-bare no libc to test ffi with
 
 pub struct TwoU8s {
     one: u8, two: u8
diff --git a/src/test/run-pass/extern_fat_drop.rs b/src/test/run-pass/extern_fat_drop.rs
index 8ce1f744dee17..123458ff97e13 100644
--- a/src/test/run-pass/extern_fat_drop.rs
+++ b/src/test/run-pass/extern_fat_drop.rs
@@ -14,7 +14,8 @@ extern crate fat_drop;
 
 fn main() {
     unsafe {
-        let s: &mut fat_drop::S = std::mem::uninitialized();
+        let data: &mut [u8] = &mut [0];
+        let s: &mut fat_drop::S = std::mem::transmute::<&mut [u8], _>(data);
         std::ptr::drop_in_place(s);
         assert!(fat_drop::DROPPED);
     }
diff --git a/src/test/run-pass/fmt-pointer-trait.rs b/src/test/run-pass/fmt-pointer-trait.rs
index 96f31891f2f34..4ecb9da4eb9c6 100644
--- a/src/test/run-pass/fmt-pointer-trait.rs
+++ b/src/test/run-pass/fmt-pointer-trait.rs
@@ -8,14 +8,12 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(libc)]
-extern crate libc;
 use std::ptr;
 use std::rc::Rc;
 use std::sync::Arc;
 
 fn main() {
-    let p: *const libc::c_void = ptr::null();
+    let p: *const u8 = ptr::null();
     let rc = Rc::new(1usize);
     let arc = Arc::new(1usize);
     let b = Box::new("hi");
diff --git a/src/test/run-pass/foreign-dupe.rs b/src/test/run-pass/foreign-dupe.rs
index fb162d8793356..b79e6e98fc056 100644
--- a/src/test/run-pass/foreign-dupe.rs
+++ b/src/test/run-pass/foreign-dupe.rs
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 // aux-build:foreign_lib.rs
+// ignore-wasm32-bare no libc to test ffi with
 
 // Check that we can still call duplicated extern (imported) functions
 // which were declared in another crate. See issues #32740 and #32783.
diff --git a/src/test/run-pass/foreign-fn-linkname.rs b/src/test/run-pass/foreign-fn-linkname.rs
index a9001a3cdcf6e..ab8e4fbedcff7 100644
--- a/src/test/run-pass/foreign-fn-linkname.rs
+++ b/src/test/run-pass/foreign-fn-linkname.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-
+// ignore-wasm32-bare no libc to test ffi with
 
 #![feature(std_misc, libc)]
 
diff --git a/src/test/run-pass/foreign-fn-with-byval.rs b/src/test/run-pass/foreign-fn-with-byval.rs
index 2d4542540e7a3..65efa571a9b4b 100644
--- a/src/test/run-pass/foreign-fn-with-byval.rs
+++ b/src/test/run-pass/foreign-fn-with-byval.rs
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// ignore-wasm32-bare no libc to test ffi with
 
 #[derive(Copy, Clone)]
 pub struct S {
diff --git a/src/test/run-pass/foreign-mod-unused-const.rs b/src/test/run-pass/foreign-mod-unused-const.rs
index 70d4801ae3b3c..5e9e529669a01 100644
--- a/src/test/run-pass/foreign-mod-unused-const.rs
+++ b/src/test/run-pass/foreign-mod-unused-const.rs
@@ -8,18 +8,11 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-
 // pretty-expanded FIXME #23616
 
-#![feature(libc)]
-
-extern crate libc;
-
 mod foo {
-    use libc::c_int;
-
     extern {
-        pub static errno: c_int;
+        pub static errno: u32;
     }
 }
 
diff --git a/src/test/run-pass/foreign-no-abi.rs b/src/test/run-pass/foreign-no-abi.rs
index 979e57eba9d1a..b516cdf4416b8 100644
--- a/src/test/run-pass/foreign-no-abi.rs
+++ b/src/test/run-pass/foreign-no-abi.rs
@@ -10,6 +10,7 @@
 
 // ABI is cdecl by default
 
+// ignore-wasm32-bare no libc to test ffi with
 // pretty-expanded FIXME #23616
 
 #![feature(libc)]
diff --git a/src/test/run-pass/foreign2.rs b/src/test/run-pass/foreign2.rs
index d83bd940d1978..d69d6976e4a90 100644
--- a/src/test/run-pass/foreign2.rs
+++ b/src/test/run-pass/foreign2.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-
+// ignore-wasm32-bare no libc to test ffi with
 // pretty-expanded FIXME #23616
 
 #![feature(libc)]
diff --git a/src/test/run-pass/generator/panic-drops.rs b/src/test/run-pass/generator/panic-drops.rs
index 53cd3235d9d0c..36e401a54bcdd 100644
--- a/src/test/run-pass/generator/panic-drops.rs
+++ b/src/test/run-pass/generator/panic-drops.rs
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// ignore-wasm32-bare compiled as panic=abort by default
+
 #![feature(generators, generator_trait)]
 
 use std::ops::Generator;
diff --git a/src/test/run-pass/generator/panic-safe.rs b/src/test/run-pass/generator/panic-safe.rs
index a583f42b93d8c..0d5bae7876bd3 100644
--- a/src/test/run-pass/generator/panic-safe.rs
+++ b/src/test/run-pass/generator/panic-safe.rs
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// ignore-wasm32-bare compiled with panic=abort by default
+
 #![feature(generators, generator_trait)]
 
 use std::ops::Generator;
diff --git a/src/test/run-pass/generator/resume-after-return.rs b/src/test/run-pass/generator/resume-after-return.rs
index b2e2a3e7e9d5b..56511dcd53a6a 100644
--- a/src/test/run-pass/generator/resume-after-return.rs
+++ b/src/test/run-pass/generator/resume-after-return.rs
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// ignore-wasm32-bare compiled with panic=abort by default
+
 #![feature(generators, generator_trait)]
 
 use std::ops::{GeneratorState, Generator};
diff --git a/src/test/run-pass/intrinsic-alignment.rs b/src/test/run-pass/intrinsic-alignment.rs
index cfae9903a95e5..99edd2550c01b 100644
--- a/src/test/run-pass/intrinsic-alignment.rs
+++ b/src/test/run-pass/intrinsic-alignment.rs
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// ignore-wasm32-bare seems not important to test here
 
 #![feature(intrinsics, main)]
 
diff --git a/src/test/run-pass/invoke-external-foreign.rs b/src/test/run-pass/invoke-external-foreign.rs
index 1aae8131d8008..d01c3b67895e6 100644
--- a/src/test/run-pass/invoke-external-foreign.rs
+++ b/src/test/run-pass/invoke-external-foreign.rs
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 // aux-build:foreign_lib.rs
+// ignore-wasm32-bare no libc to test ffi with
 
 // The purpose of this test is to check that we can
 // successfully (and safely) invoke external, cdecl
diff --git a/src/test/run-pass/issue-1251.rs b/src/test/run-pass/issue-1251.rs
index ddd30ed3bb0c0..00e8aa69a8942 100644
--- a/src/test/run-pass/issue-1251.rs
+++ b/src/test/run-pass/issue-1251.rs
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 // pretty-expanded FIXME #23616
+// ignore-wasm32-bare no libc to test ffi with
 
 #![feature(libc)]
 
diff --git a/src/test/run-pass/issue-12699.rs b/src/test/run-pass/issue-12699.rs
index 1e9f30bb766b2..4620d982c1ea5 100644
--- a/src/test/run-pass/issue-12699.rs
+++ b/src/test/run-pass/issue-12699.rs
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// ignore-wasm32-bare can't block the thread
+
 use std::thread;
 
 fn main() {
diff --git a/src/test/run-pass/issue-13507-2.rs b/src/test/run-pass/issue-13507-2.rs
index 084b7a166cdd3..75a724e55fb11 100644
--- a/src/test/run-pass/issue-13507-2.rs
+++ b/src/test/run-pass/issue-13507-2.rs
@@ -10,9 +10,6 @@
 
 // aux-build:issue13507.rs
 
-
-#![feature(core)]
-
 extern crate issue13507;
 use issue13507::testtypes;
 
diff --git a/src/test/run-pass/issue-14875.rs b/src/test/run-pass/issue-14875.rs
index ad19a9be76f88..e705539bb4772 100644
--- a/src/test/run-pass/issue-14875.rs
+++ b/src/test/run-pass/issue-14875.rs
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// ignore-wasm32-bare always compiled as panic=abort right now
+
 // Check that values are not leaked when a dtor panics (#14875)
 
 use std::panic::{self, UnwindSafe};
@@ -29,7 +31,6 @@ impl Drop for PanicOnDrop {
     }
 }
 
-
 fn main() {
     let mut set_on_drop = false;
     {
diff --git a/src/test/run-pass/issue-2214.rs b/src/test/run-pass/issue-2214.rs
index 316e379e664ae..7b7ecc91484ba 100644
--- a/src/test/run-pass/issue-2214.rs
+++ b/src/test/run-pass/issue-2214.rs
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// ignore-wasm32-bare no libc to test ffi with
 
 #![feature(libc)]
 
diff --git a/src/test/run-pass/issue-25185.rs b/src/test/run-pass/issue-25185.rs
index d8d2d5078c5e7..9a2dbd1c96e31 100644
--- a/src/test/run-pass/issue-25185.rs
+++ b/src/test/run-pass/issue-25185.rs
@@ -10,6 +10,7 @@
 
 // aux-build:issue-25185-1.rs
 // aux-build:issue-25185-2.rs
+// ignore-wasm32-bare no libc for ffi testing
 
 extern crate issue_25185_2;
 
diff --git a/src/test/run-pass/issue-28676.rs b/src/test/run-pass/issue-28676.rs
index 8f83e51f0a02d..a7bee427a813c 100644
--- a/src/test/run-pass/issue-28676.rs
+++ b/src/test/run-pass/issue-28676.rs
@@ -7,7 +7,8 @@
 // <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-wasm32-bare no libc to test ffi with
 
 #[derive(Copy, Clone)]
 pub struct Quad { a: u64, b: u64, c: u64, d: u64 }
diff --git a/src/test/run-pass/issue-29948.rs b/src/test/run-pass/issue-29948.rs
index 281dde15bd336..3a7e9ba93e190 100644
--- a/src/test/run-pass/issue-29948.rs
+++ b/src/test/run-pass/issue-29948.rs
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// ignore-wasm32-bare compiled with panic=abort by default
+
 use std::panic;
 
 impl<'a> panic::UnwindSafe for Foo<'a> {}
diff --git a/src/test/run-pass/issue-3012-2.rs b/src/test/run-pass/issue-3012-2.rs
index ecce5df0fc200..bcf8a9180918c 100644
--- a/src/test/run-pass/issue-3012-2.rs
+++ b/src/test/run-pass/issue-3012-2.rs
@@ -12,15 +12,11 @@
 
 // pretty-expanded FIXME #23616
 
-#![allow(unknown_features)]
-#![feature(box_syntax, libc)]
-
 extern crate socketlib;
-extern crate libc;
 
 use socketlib::socket;
 
 pub fn main() {
-    let fd: libc::c_int = 1 as libc::c_int;
-    let _sock: Box<_> = box socket::socket_handle(fd);
+    let fd: u32 = 1 as u32;
+    let _sock: Box<_> = Box::new(socket::socket_handle(fd));
 }
diff --git a/src/test/run-pass/issue-3656.rs b/src/test/run-pass/issue-3656.rs
index 10930474799c5..c278dcef9dde7 100644
--- a/src/test/run-pass/issue-3656.rs
+++ b/src/test/run-pass/issue-3656.rs
@@ -13,6 +13,7 @@
 // the alignment of elements into account.
 
 // pretty-expanded FIXME #23616
+// ignore-wasm32-bare no libc to test with
 
 #![feature(libc)]
 
diff --git a/src/test/run-pass/issue-43853.rs b/src/test/run-pass/issue-43853.rs
index f55d584ea24fb..e9f8d2744a16a 100644
--- a/src/test/run-pass/issue-43853.rs
+++ b/src/test/run-pass/issue-43853.rs
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// ignore-wasm32-bare compiled with panic=abort by default
+
 use std::panic;
 
 fn test() {
diff --git a/src/test/run-pass/issue-4735.rs b/src/test/run-pass/issue-4735.rs
index 56e69a9f36e78..7eb09e055a292 100644
--- a/src/test/run-pass/issue-4735.rs
+++ b/src/test/run-pass/issue-4735.rs
@@ -8,28 +8,21 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-
 // pretty-expanded FIXME #23616
 
-#![allow(unknown_features)]
-#![feature(box_syntax, libc)]
-
-extern crate libc;
-
 use std::mem::transmute;
-use libc::c_void;
 
-struct NonCopyable(*const c_void);
+struct NonCopyable(*const u8);
 
 impl Drop for NonCopyable {
     fn drop(&mut self) {
         let NonCopyable(p) = *self;
-        let _v = unsafe { transmute::<*const c_void, Box<isize>>(p) };
+        let _v = unsafe { transmute::<*const u8, Box<isize>>(p) };
     }
 }
 
 pub fn main() {
-    let t = box 0;
-    let p = unsafe { transmute::<Box<isize>, *const c_void>(t) };
+    let t = Box::new(0);
+    let p = unsafe { transmute::<Box<isize>, *const u8>(t) };
     let _z = NonCopyable(p);
 }
diff --git a/src/test/run-pass/issue-5791.rs b/src/test/run-pass/issue-5791.rs
index aad90bd4181d9..2e93279f756f0 100644
--- a/src/test/run-pass/issue-5791.rs
+++ b/src/test/run-pass/issue-5791.rs
@@ -10,15 +10,11 @@
 
 // pretty-expanded FIXME #23616
 
-#![feature(libc)]
-
-extern crate libc;
-
 extern {
     #[link_name = "malloc"]
-    fn malloc1(len: libc::c_int) -> *const libc::c_void;
+    fn malloc1(len: i32) -> *const u8;
     #[link_name = "malloc"]
-    fn malloc2(len: libc::c_int, foo: libc::c_int) -> *const libc::c_void;
+    fn malloc2(len: i32, foo: i32) -> *const u8;
 }
 
 pub fn main () {}
diff --git a/src/test/run-pass/item-attributes.rs b/src/test/run-pass/item-attributes.rs
index f1ac96ab63e5c..0fc13319b8734 100644
--- a/src/test/run-pass/item-attributes.rs
+++ b/src/test/run-pass/item-attributes.rs
@@ -12,8 +12,7 @@
 // for completeness since .rs files linked from .rc files support this
 // notation to specify their module's attributes
 
-
-#![feature(custom_attribute, libc)]
+#![feature(custom_attribute)]
 #![allow(unused_attribute)]
 #![attr1 = "val"]
 #![attr2 = "val"]
@@ -159,13 +158,11 @@ mod test_other_forms {
 
 mod test_foreign_items {
     pub mod rustrt {
-        extern crate libc;
-
         extern {
             #![attr]
 
             #[attr]
-            fn rust_get_test_int() -> libc::intptr_t;
+            fn rust_get_test_int() -> u32;
         }
     }
 }
diff --git a/src/test/run-pass/iter-step-overflow-debug.rs b/src/test/run-pass/iter-step-overflow-debug.rs
index 5b9b58f028894..c45a10eac52b1 100644
--- a/src/test/run-pass/iter-step-overflow-debug.rs
+++ b/src/test/run-pass/iter-step-overflow-debug.rs
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// ignore-wasm32-bare compiled with panic=abort by default
 // compile-flags: -C debug_assertions=yes
 
 use std::panic;
diff --git a/src/test/run-pass/iter-sum-overflow-debug.rs b/src/test/run-pass/iter-sum-overflow-debug.rs
index 6c07afb37b8a0..c640f7cd28045 100644
--- a/src/test/run-pass/iter-sum-overflow-debug.rs
+++ b/src/test/run-pass/iter-sum-overflow-debug.rs
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// ignore-wasm32-bare compiled with panic=abort by default
 // compile-flags: -C debug_assertions=yes
 
 use std::panic;
diff --git a/src/test/run-pass/iter-sum-overflow-overflow-checks.rs b/src/test/run-pass/iter-sum-overflow-overflow-checks.rs
index a3a7179fb7112..517cd139cf354 100644
--- a/src/test/run-pass/iter-sum-overflow-overflow-checks.rs
+++ b/src/test/run-pass/iter-sum-overflow-overflow-checks.rs
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// ignore-wasm32-bare compiled with panic=abort by default
 // compile-flags: -C overflow-checks
 
 use std::panic;
diff --git a/src/test/run-pass/lib-defaults.rs b/src/test/run-pass/lib-defaults.rs
index 6e5dccae0a07d..fcaeda9a5495b 100644
--- a/src/test/run-pass/lib-defaults.rs
+++ b/src/test/run-pass/lib-defaults.rs
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// ignore-wasm32-bare no libc to test ffi with
+
 // compile-flags: -lrust_test_helpers
 
 #[link(name = "rust_test_helpers", kind = "static")]
diff --git a/src/test/run-pass/mir_calls_to_shims.rs b/src/test/run-pass/mir_calls_to_shims.rs
index 7300a322ec4b7..9641ed282936f 100644
--- a/src/test/run-pass/mir_calls_to_shims.rs
+++ b/src/test/run-pass/mir_calls_to_shims.rs
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// ignore-wasm32-bare compiled with panic=abort by default
+
 #![feature(fn_traits)]
 #![feature(never_type)]
 
diff --git a/src/test/run-pass/mir_drop_order.rs b/src/test/run-pass/mir_drop_order.rs
index e7da43597f169..41cb458c0b8b4 100644
--- a/src/test/run-pass/mir_drop_order.rs
+++ b/src/test/run-pass/mir_drop_order.rs
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// ignore-wasm32-bare compiled with panic=abort by default
+
 use std::cell::RefCell;
 use std::panic;
 
diff --git a/src/test/run-pass/mir_misc_casts.rs b/src/test/run-pass/mir_misc_casts.rs
index ae719ac2800ee..81c8b75fb9b6a 100644
--- a/src/test/run-pass/mir_misc_casts.rs
+++ b/src/test/run-pass/mir_misc_casts.rs
@@ -8,10 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(libc)]
-
-extern crate libc;
-
 fn func(){}
 
 const STR: &'static str = "hello";
@@ -19,7 +15,7 @@ const BSTR: &'static [u8; 5] = b"hello";
 
 fn from_ptr()
 -> (isize, usize, i8, i16, i32, i64, u8, u16, u32, u64, *const ()) {
-    let f = 1_usize as *const libc::FILE;
+    let f = 1_usize as *const String;
     let c1 = f as isize;
     let c2 = f as usize;
     let c3 = f as i8;
@@ -35,7 +31,7 @@ fn from_ptr()
 }
 
 fn from_1()
--> (isize, usize, i8, i16, i32, i64, u8, u16, u32, u64, f32, f64, *const libc::FILE) {
+-> (isize, usize, i8, i16, i32, i64, u8, u16, u32, u64, f32, f64, *const String) {
     let c1 = 1 as isize;
     let c2 = 1 as usize;
     let c3 = 1 as i8;
@@ -48,12 +44,12 @@ fn from_1()
     let c10 = 1 as u64;
     let c11 = 1 as f32;
     let c12 = 1 as f64;
-    let c13 = 1 as *const libc::FILE;
+    let c13 = 1 as *const String;
     (c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13)
 }
 
 fn from_1usize()
--> (isize, usize, i8, i16, i32, i64, u8, u16, u32, u64, f32, f64, *const libc::FILE) {
+-> (isize, usize, i8, i16, i32, i64, u8, u16, u32, u64, f32, f64, *const String) {
     let c1 = 1_usize as isize;
     let c2 = 1_usize as usize;
     let c3 = 1_usize as i8;
@@ -66,12 +62,12 @@ fn from_1usize()
     let c10 = 1_usize as u64;
     let c11 = 1_usize as f32;
     let c12 = 1_usize as f64;
-    let c13 = 1_usize as *const libc::FILE;
+    let c13 = 1_usize as *const String;
     (c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13)
 }
 
 fn from_1isize()
--> (isize, usize, i8, i16, i32, i64, u8, u16, u32, u64, f32, f64, *const libc::FILE) {
+-> (isize, usize, i8, i16, i32, i64, u8, u16, u32, u64, f32, f64, *const String) {
     let c1 = 1_isize as isize;
     let c2 = 1_isize as usize;
     let c3 = 1_isize as i8;
@@ -84,12 +80,12 @@ fn from_1isize()
     let c10 = 1_isize as u64;
     let c11 = 1_isize as f32;
     let c12 = 1_isize as f64;
-    let c13 = 1_isize as *const libc::FILE;
+    let c13 = 1_isize as *const String;
     (c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13)
 }
 
 fn from_1u8()
--> (isize, usize, i8, i16, i32, i64, u8, u16, u32, u64, f32, f64, *const libc::FILE) {
+-> (isize, usize, i8, i16, i32, i64, u8, u16, u32, u64, f32, f64, *const String) {
     let c1 = 1_u8 as isize;
     let c2 = 1_u8 as usize;
     let c3 = 1_u8 as i8;
@@ -102,12 +98,12 @@ fn from_1u8()
     let c10 = 1_u8 as u64;
     let c11 = 1_u8 as f32;
     let c12 = 1_u8 as f64;
-    let c13 = 1_u8 as *const libc::FILE;
+    let c13 = 1_u8 as *const String;
     (c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13)
 }
 
 fn from_1i8()
--> (isize, usize, i8, i16, i32, i64, u8, u16, u32, u64, f32, f64, *const libc::FILE) {
+-> (isize, usize, i8, i16, i32, i64, u8, u16, u32, u64, f32, f64, *const String) {
     let c1 = 1_i8 as isize;
     let c2 = 1_i8 as usize;
     let c3 = 1_i8 as i8;
@@ -120,12 +116,12 @@ fn from_1i8()
     let c10 = 1_i8 as u64;
     let c11 = 1_i8 as f32;
     let c12 = 1_i8 as f64;
-    let c13 = 1_i8 as *const libc::FILE;
+    let c13 = 1_i8 as *const String;
     (c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13)
 }
 
 fn from_1u16()
--> (isize, usize, i8, i16, i32, i64, u8, u16, u32, u64, f32, f64, *const libc::FILE) {
+-> (isize, usize, i8, i16, i32, i64, u8, u16, u32, u64, f32, f64, *const String) {
     let c1 = 1_u16 as isize;
     let c2 = 1_u16 as usize;
     let c3 = 1_u16 as i8;
@@ -138,12 +134,12 @@ fn from_1u16()
     let c10 = 1_u16 as u64;
     let c11 = 1_u16 as f32;
     let c12 = 1_u16 as f64;
-    let c13 = 1_u16 as *const libc::FILE;
+    let c13 = 1_u16 as *const String;
     (c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13)
 }
 
 fn from_1i16()
--> (isize, usize, i8, i16, i32, i64, u8, u16, u32, u64, f32, f64, *const libc::FILE) {
+-> (isize, usize, i8, i16, i32, i64, u8, u16, u32, u64, f32, f64, *const String) {
     let c1 = 1_i16 as isize;
     let c2 = 1_i16 as usize;
     let c3 = 1_i16 as i8;
@@ -156,12 +152,12 @@ fn from_1i16()
     let c10 = 1_i16 as u64;
     let c11 = 1_i16 as f32;
     let c12 = 1_i16 as f64;
-    let c13 = 1_i16 as *const libc::FILE;
+    let c13 = 1_i16 as *const String;
     (c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13)
 }
 
 fn from_1u32()
--> (isize, usize, i8, i16, i32, i64, u8, u16, u32, u64, f32, f64, *const libc::FILE) {
+-> (isize, usize, i8, i16, i32, i64, u8, u16, u32, u64, f32, f64, *const String) {
     let c1 = 1_u32 as isize;
     let c2 = 1_u32 as usize;
     let c3 = 1_u32 as i8;
@@ -174,12 +170,12 @@ fn from_1u32()
     let c10 = 1_u32 as u64;
     let c11 = 1_u32 as f32;
     let c12 = 1_u32 as f64;
-    let c13 = 1_u32 as *const libc::FILE;
+    let c13 = 1_u32 as *const String;
     (c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13)
 }
 
 fn from_1i32()
--> (isize, usize, i8, i16, i32, i64, u8, u16, u32, u64, f32, f64, *const libc::FILE) {
+-> (isize, usize, i8, i16, i32, i64, u8, u16, u32, u64, f32, f64, *const String) {
     let c1 = 1_i32 as isize;
     let c2 = 1_i32 as usize;
     let c3 = 1_i32 as i8;
@@ -192,12 +188,12 @@ fn from_1i32()
     let c10 = 1_i32 as u64;
     let c11 = 1_i32 as f32;
     let c12 = 1_i32 as f64;
-    let c13 = 1_i32 as *const libc::FILE;
+    let c13 = 1_i32 as *const String;
     (c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13)
 }
 
 fn from_1u64()
--> (isize, usize, i8, i16, i32, i64, u8, u16, u32, u64, f32, f64, *const libc::FILE) {
+-> (isize, usize, i8, i16, i32, i64, u8, u16, u32, u64, f32, f64, *const String) {
     let c1 = 1_u64 as isize;
     let c2 = 1_u64 as usize;
     let c3 = 1_u64 as i8;
@@ -210,12 +206,12 @@ fn from_1u64()
     let c10 = 1_u64 as u64;
     let c11 = 1_u64 as f32;
     let c12 = 1_u64 as f64;
-    let c13 = 1_u64 as *const libc::FILE;
+    let c13 = 1_u64 as *const String;
     (c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13)
 }
 
 fn from_1i64()
--> (isize, usize, i8, i16, i32, i64, u8, u16, u32, u64, f32, f64, *const libc::FILE) {
+-> (isize, usize, i8, i16, i32, i64, u8, u16, u32, u64, f32, f64, *const String) {
     let c1 = 1_i64 as isize;
     let c2 = 1_i64 as usize;
     let c3 = 1_i64 as i8;
@@ -228,7 +224,7 @@ fn from_1i64()
     let c10 = 1_i64 as u64;
     let c11 = 1_i64 as f32;
     let c12 = 1_i64 as f64;
-    let c13 = 1_i64 as *const libc::FILE;
+    let c13 = 1_i64 as *const String;
     (c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13)
 }
 
@@ -297,9 +293,9 @@ fn other_casts()
 }
 
 pub fn assert_eq_13(l: (isize, usize, i8, i16, i32, i64, u8,
-                        u16, u32, u64, f32, f64, *const libc::FILE),
+                        u16, u32, u64, f32, f64, *const String),
                     r: (isize, usize, i8, i16, i32, i64, u8,
-                        u16, u32, u64, f32, f64, *const libc::FILE)) -> bool {
+                        u16, u32, u64, f32, f64, *const String)) -> bool {
     let (l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12, l13) = l;
     let (r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13) = r;
     l1 == r1 && l2 == r2 && l3 == r3 && l4 == r4 && l5 == r5 && l6 == r6 && l7 == r7 &&
@@ -308,7 +304,7 @@ pub fn assert_eq_13(l: (isize, usize, i8, i16, i32, i64, u8,
 
 
 pub fn main() {
-    let f = 1_usize as *const libc::FILE;
+    let f = 1_usize as *const String;
     let t13 = (1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1.0, 1.0, f);
     let t12 = (1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1.0, 1.0);
     assert_eq_13(from_1(), t13);
diff --git a/src/test/run-pass/mir_trans_calls_variadic.rs b/src/test/run-pass/mir_trans_calls_variadic.rs
index e4d528e80e104..7845c9426e23b 100644
--- a/src/test/run-pass/mir_trans_calls_variadic.rs
+++ b/src/test/run-pass/mir_trans_calls_variadic.rs
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// ignore-wasm32-bare no libc to test ffi with
+
 #[link(name = "rust_test_helpers", kind = "static")]
 extern {
     fn rust_interesting_average(_: i64, ...) -> f64;
diff --git a/src/test/run-pass/newtype-struct-with-dtor.rs b/src/test/run-pass/newtype-struct-with-dtor.rs
index d1ad5614e3f35..07c76e27284f5 100644
--- a/src/test/run-pass/newtype-struct-with-dtor.rs
+++ b/src/test/run-pass/newtype-struct-with-dtor.rs
@@ -8,21 +8,17 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-
 // pretty-expanded FIXME #23616
 
-#![feature(libc)]
-
-extern crate libc;
-use libc::c_int;
+pub struct Fd(u32);
 
-pub struct Fd(c_int);
+fn foo(a: u32) {}
 
 impl Drop for Fd {
     fn drop(&mut self) {
         unsafe {
             let Fd(s) = *self;
-            libc::close(s);
+            foo(s);
         }
     }
 }
diff --git a/src/test/run-pass/paths-containing-nul.rs b/src/test/run-pass/paths-containing-nul.rs
index 2da3e59e54c58..9f39146e238d6 100644
--- a/src/test/run-pass/paths-containing-nul.rs
+++ b/src/test/run-pass/paths-containing-nul.rs
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// ignore-wasm32-bare no files or I/O
+
 use std::fs;
 use std::io;
 
diff --git a/src/test/run-pass/pub-extern-privacy.rs b/src/test/run-pass/pub-extern-privacy.rs
index b9a3f788f9794..1ef804fe8feea 100644
--- a/src/test/run-pass/pub-extern-privacy.rs
+++ b/src/test/run-pass/pub-extern-privacy.rs
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// ignore-wasm32-bare no libc to test ffi with
+
 // pretty-expanded FIXME #23616
 
 use std::mem::transmute;
diff --git a/src/test/run-pass/reachable-unnameable-items.rs b/src/test/run-pass/reachable-unnameable-items.rs
index 75a2e36ffb7a4..d087be6d10cfc 100644
--- a/src/test/run-pass/reachable-unnameable-items.rs
+++ b/src/test/run-pass/reachable-unnameable-items.rs
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// ignore-wasm32-bare compiled with panic=abort by default
 // aux-build:reachable-unnameable-items.rs
 
 extern crate reachable_unnameable_items;
diff --git a/src/test/run-pass/rec-align-u64.rs b/src/test/run-pass/rec-align-u64.rs
index 4863979b3f6c2..d051e05b5f9e7 100644
--- a/src/test/run-pass/rec-align-u64.rs
+++ b/src/test/run-pass/rec-align-u64.rs
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// ignore-wasm32-bare seems unimportant to test
+
 // Issue #2303
 
 #![feature(intrinsics)]
diff --git a/src/test/run-pass/regions-mock-trans.rs b/src/test/run-pass/regions-mock-trans.rs
index b67612c94b009..8f278a315d1af 100644
--- a/src/test/run-pass/regions-mock-trans.rs
+++ b/src/test/run-pass/regions-mock-trans.rs
@@ -10,10 +10,9 @@
 
 // pretty-expanded FIXME #23616
 
-#![feature(libc)]
+#![feature(allocator_api)]
 
-extern crate libc;
-use std::mem;
+use std::heap::{Alloc, Heap, Layout};
 
 struct arena(());
 
@@ -32,8 +31,9 @@ struct Ccx {
 
 fn alloc<'a>(_bcx : &'a arena) -> &'a Bcx<'a> {
     unsafe {
-        mem::transmute(libc::malloc(mem::size_of::<Bcx<'a>>()
-            as libc::size_t))
+        let ptr = Heap.alloc(Layout::new::<Bcx>())
+            .unwrap_or_else(|e| Heap.oom(e));
+        &*(ptr as *const _)
     }
 }
 
@@ -45,7 +45,7 @@ fn g(fcx : &Fcx) {
     let bcx = Bcx { fcx: fcx };
     let bcx2 = h(&bcx);
     unsafe {
-        libc::free(mem::transmute(bcx2));
+        Heap.dealloc(bcx2 as *const _ as *mut _, Layout::new::<Bcx>());
     }
 }
 
diff --git a/src/test/run-pass/rfc-1014.rs b/src/test/run-pass/rfc-1014.rs
index df969070a2ad4..950c2e0c4dfab 100644
--- a/src/test/run-pass/rfc-1014.rs
+++ b/src/test/run-pass/rfc-1014.rs
@@ -7,6 +7,9 @@
 // <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-wasm32-bare no libc
+
 #![feature(libc)]
 
 extern crate libc;
diff --git a/src/test/run-pass/rfc1717/library-override.rs b/src/test/run-pass/rfc1717/library-override.rs
index 26713a2554377..c51b33f9c4af6 100644
--- a/src/test/run-pass/rfc1717/library-override.rs
+++ b/src/test/run-pass/rfc1717/library-override.rs
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// ignore-wasm32-bare no libc to test ffi with
 // compile-flags: -lstatic=wronglibrary:rust_test_helpers
 
 #[link(name = "wronglibrary", kind = "dylib")]
diff --git a/src/test/run-pass/rfc1857-drop-order.rs b/src/test/run-pass/rfc1857-drop-order.rs
index 42f989538c890..b2e5ff62eb86e 100644
--- a/src/test/run-pass/rfc1857-drop-order.rs
+++ b/src/test/run-pass/rfc1857-drop-order.rs
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// ignore-wasm32-bare compiled with panic=abort by default
+
 #![allow(dead_code, unreachable_code)]
 
 use std::cell::RefCell;
diff --git a/src/test/run-pass/signal-alternate-stack-cleanup.rs b/src/test/run-pass/signal-alternate-stack-cleanup.rs
index 26fa36f0c13d4..73ccd28a3e963 100644
--- a/src/test/run-pass/signal-alternate-stack-cleanup.rs
+++ b/src/test/run-pass/signal-alternate-stack-cleanup.rs
@@ -13,6 +13,7 @@
 // triggers this situation by sending signal from atexit handler.
 //
 // ignore-windows
+// ignore-wasm32-bare no libc
 
 #![feature(libc)]
 extern crate libc;
diff --git a/src/test/run-pass/static-method-xcrate.rs b/src/test/run-pass/static-method-xcrate.rs
index 57609cec9f2b0..ab6adcbbffe7a 100644
--- a/src/test/run-pass/static-method-xcrate.rs
+++ b/src/test/run-pass/static-method-xcrate.rs
@@ -10,7 +10,6 @@
 
 // aux-build:static-methods-crate.rs
 
-
 extern crate static_methods_crate;
 
 use static_methods_crate::read;
diff --git a/src/test/run-pass/static-mut-foreign.rs b/src/test/run-pass/static-mut-foreign.rs
index 24d58487f061e..2b7fa0166a8ed 100644
--- a/src/test/run-pass/static-mut-foreign.rs
+++ b/src/test/run-pass/static-mut-foreign.rs
@@ -12,6 +12,7 @@
 // statics cannot. This ensures that there's some form of error if this is
 // attempted.
 
+// ignore-wasm32-bare no libc to test ffi with
 
 #![feature(libc)]
 
diff --git a/src/test/run-pass/struct-return.rs b/src/test/run-pass/struct-return.rs
index ed618cea98ac0..61a2bcb3a9b75 100644
--- a/src/test/run-pass/struct-return.rs
+++ b/src/test/run-pass/struct-return.rs
@@ -7,7 +7,8 @@
 // <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-wasm32-bare no libc to test ffi with
 
 #[repr(C)]
 #[derive(Copy, Clone)]
diff --git a/src/test/run-pass/supported-cast.rs b/src/test/run-pass/supported-cast.rs
index a47ae52f5902c..7f92707586b28 100644
--- a/src/test/run-pass/supported-cast.rs
+++ b/src/test/run-pass/supported-cast.rs
@@ -8,12 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(libc)]
-
-extern crate libc;
-
 pub fn main() {
-  let f = 1_usize as *const libc::FILE;
+  let f = 1_usize as *const String;
   println!("{:?}", f as isize);
   println!("{:?}", f as usize);
   println!("{:?}", f as i8);
@@ -27,7 +23,7 @@ pub fn main() {
 
   println!("{:?}", 1 as isize);
   println!("{:?}", 1 as usize);
-  println!("{:?}", 1 as *const libc::FILE);
+  println!("{:?}", 1 as *const String);
   println!("{:?}", 1 as i8);
   println!("{:?}", 1 as i16);
   println!("{:?}", 1 as i32);
@@ -41,7 +37,7 @@ pub fn main() {
 
   println!("{:?}", 1_usize as isize);
   println!("{:?}", 1_usize as usize);
-  println!("{:?}", 1_usize as *const libc::FILE);
+  println!("{:?}", 1_usize as *const String);
   println!("{:?}", 1_usize as i8);
   println!("{:?}", 1_usize as i16);
   println!("{:?}", 1_usize as i32);
@@ -55,7 +51,7 @@ pub fn main() {
 
   println!("{:?}", 1i8 as isize);
   println!("{:?}", 1i8 as usize);
-  println!("{:?}", 1i8 as *const libc::FILE);
+  println!("{:?}", 1i8 as *const String);
   println!("{:?}", 1i8 as i8);
   println!("{:?}", 1i8 as i16);
   println!("{:?}", 1i8 as i32);
@@ -69,7 +65,7 @@ pub fn main() {
 
   println!("{:?}", 1u8 as isize);
   println!("{:?}", 1u8 as usize);
-  println!("{:?}", 1u8 as *const libc::FILE);
+  println!("{:?}", 1u8 as *const String);
   println!("{:?}", 1u8 as i8);
   println!("{:?}", 1u8 as i16);
   println!("{:?}", 1u8 as i32);
@@ -83,7 +79,7 @@ pub fn main() {
 
   println!("{:?}", 1i16 as isize);
   println!("{:?}", 1i16 as usize);
-  println!("{:?}", 1i16 as *const libc::FILE);
+  println!("{:?}", 1i16 as *const String);
   println!("{:?}", 1i16 as i8);
   println!("{:?}", 1i16 as i16);
   println!("{:?}", 1i16 as i32);
@@ -97,7 +93,7 @@ pub fn main() {
 
   println!("{:?}", 1u16 as isize);
   println!("{:?}", 1u16 as usize);
-  println!("{:?}", 1u16 as *const libc::FILE);
+  println!("{:?}", 1u16 as *const String);
   println!("{:?}", 1u16 as i8);
   println!("{:?}", 1u16 as i16);
   println!("{:?}", 1u16 as i32);
@@ -111,7 +107,7 @@ pub fn main() {
 
   println!("{:?}", 1i32 as isize);
   println!("{:?}", 1i32 as usize);
-  println!("{:?}", 1i32 as *const libc::FILE);
+  println!("{:?}", 1i32 as *const String);
   println!("{:?}", 1i32 as i8);
   println!("{:?}", 1i32 as i16);
   println!("{:?}", 1i32 as i32);
@@ -125,7 +121,7 @@ pub fn main() {
 
   println!("{:?}", 1u32 as isize);
   println!("{:?}", 1u32 as usize);
-  println!("{:?}", 1u32 as *const libc::FILE);
+  println!("{:?}", 1u32 as *const String);
   println!("{:?}", 1u32 as i8);
   println!("{:?}", 1u32 as i16);
   println!("{:?}", 1u32 as i32);
@@ -139,7 +135,7 @@ pub fn main() {
 
   println!("{:?}", 1i64 as isize);
   println!("{:?}", 1i64 as usize);
-  println!("{:?}", 1i64 as *const libc::FILE);
+  println!("{:?}", 1i64 as *const String);
   println!("{:?}", 1i64 as i8);
   println!("{:?}", 1i64 as i16);
   println!("{:?}", 1i64 as i32);
@@ -153,7 +149,7 @@ pub fn main() {
 
   println!("{:?}", 1u64 as isize);
   println!("{:?}", 1u64 as usize);
-  println!("{:?}", 1u64 as *const libc::FILE);
+  println!("{:?}", 1u64 as *const String);
   println!("{:?}", 1u64 as i8);
   println!("{:?}", 1u64 as i16);
   println!("{:?}", 1u64 as i32);
@@ -167,7 +163,7 @@ pub fn main() {
 
   println!("{:?}", 1u64 as isize);
   println!("{:?}", 1u64 as usize);
-  println!("{:?}", 1u64 as *const libc::FILE);
+  println!("{:?}", 1u64 as *const String);
   println!("{:?}", 1u64 as i8);
   println!("{:?}", 1u64 as i16);
   println!("{:?}", 1u64 as i32);
diff --git a/src/test/run-pass/sync-send-in-std.rs b/src/test/run-pass/sync-send-in-std.rs
index 85ab59a298323..4dadfdf9c756e 100644
--- a/src/test/run-pass/sync-send-in-std.rs
+++ b/src/test/run-pass/sync-send-in-std.rs
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// ignore-wasm32-bare networking not available
+
 #![feature(lookup_host)]
 
 use std::net::lookup_host;
diff --git a/src/test/run-pass/test-allow-fail-attr.rs b/src/test/run-pass/test-allow-fail-attr.rs
index aa9cf76617f69..884633df66b1b 100644
--- a/src/test/run-pass/test-allow-fail-attr.rs
+++ b/src/test/run-pass/test-allow-fail-attr.rs
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// ignore-wasm32-bare compiled with panic=abort by default
 // compile-flags: --test
 #![feature(allow_fail)]
 
diff --git a/src/test/run-pass/test-should-fail-good-message.rs b/src/test/run-pass/test-should-fail-good-message.rs
index e665fa4fc7b58..360d4952d16aa 100644
--- a/src/test/run-pass/test-should-fail-good-message.rs
+++ b/src/test/run-pass/test-should-fail-good-message.rs
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// ignore-wasm32-bare compiled with panic=abort by default
 // compile-flags: --test
 #[test]
 #[should_panic(expected = "foo")]
diff --git a/src/test/run-pass/union/union-c-interop.rs b/src/test/run-pass/union/union-c-interop.rs
index b3df7d658b15f..dd16bf2e4a38e 100644
--- a/src/test/run-pass/union/union-c-interop.rs
+++ b/src/test/run-pass/union/union-c-interop.rs
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// ignore-wasm32-bare no libc to test ffi with
+
 #[derive(Clone, Copy)]
 #[repr(C)]
 struct LARGE_INTEGER_U {
diff --git a/src/test/run-pass/variadic-ffi.rs b/src/test/run-pass/variadic-ffi.rs
index ec6261febc54d..2198ead106bb7 100644
--- a/src/test/run-pass/variadic-ffi.rs
+++ b/src/test/run-pass/variadic-ffi.rs
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// ignore-wasm32-bare no libc to test ffi with
+
 #[link(name = "rust_test_helpers", kind = "static")]
 extern {
     fn rust_interesting_average(_: u64, ...) -> f64;
diff --git a/src/test/run-pass/x86stdcall.rs b/src/test/run-pass/x86stdcall.rs
index 106bf8ce7dfa4..e2e64ddfa3158 100644
--- a/src/test/run-pass/x86stdcall.rs
+++ b/src/test/run-pass/x86stdcall.rs
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// ignore-wasm32-bare no libc to test ffi with
+
 // GetLastError doesn't seem to work with stack switching
 
 #[cfg(windows)]
diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
index e03d9f89e5d8c..39f41f57d11df 100644
--- a/src/tools/compiletest/src/header.rs
+++ b/src/tools/compiletest/src/header.rs
@@ -531,7 +531,7 @@ impl Config {
             let name = line[prefix.len()+1 ..].split(&[':', ' '][..]).next().unwrap();
 
             name == "test" ||
-                name == util::get_os(&self.target) ||               // target
+                util::matches_os(&self.target, name) ||             // target
                 name == util::get_arch(&self.target) ||             // architecture
                 name == util::get_pointer_width(&self.target) ||    // pointer width
                 name == self.stage_id.split('-').next().unwrap() || // stage
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 2ff3eb7678f1a..3e3c56a07962a 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -1271,6 +1271,7 @@ actual:\n\
             let crate_type = if aux_props.no_prefer_dynamic {
                 None
             } else if (self.config.target.contains("musl") && !aux_props.force_host) ||
+                      self.config.target.contains("wasm32") ||
                       self.config.target.contains("emscripten") {
                 // We primarily compile all auxiliary libraries as dynamic libraries
                 // to avoid code size bloat and large binaries as much as possible
@@ -1431,7 +1432,10 @@ actual:\n\
             }
         }
 
-        if !self.props.no_prefer_dynamic {
+
+        if self.config.target == "wasm32-unknown-unknown" {
+            // rustc.arg("-g"); // get any backtrace at all on errors
+        } else if !self.props.no_prefer_dynamic {
             rustc.args(&["-C", "prefer-dynamic"]);
         }
 
@@ -1472,6 +1476,10 @@ actual:\n\
             let mut fname = f.file_name().unwrap().to_os_string();
             fname.push(".js");
             f.set_file_name(&fname);
+        } else if self.config.target.contains("wasm32") {
+            let mut fname = f.file_name().unwrap().to_os_string();
+            fname.push(".wasm");
+            f.set_file_name(&fname);
         } else if !env::consts::EXE_SUFFIX.is_empty() {
             let mut fname = f.file_name().unwrap().to_os_string();
             fname.push(env::consts::EXE_SUFFIX);
@@ -1494,6 +1502,22 @@ actual:\n\
             }
         }
 
+        // If this is otherwise wasm , then run tests under nodejs with our
+        // shim
+        if self.config.target.contains("wasm32") {
+            if let Some(ref p) = self.config.nodejs {
+                args.push(p.clone());
+            } else {
+                self.fatal("no NodeJS binary found (--nodejs)");
+            }
+
+            let src = self.config.src_base
+                .parent().unwrap() // chop off `run-pass`
+                .parent().unwrap() // chop off `test`
+                .parent().unwrap(); // chop off `src`
+            args.push(src.join("src/etc/wasm32-shim.js").display().to_string());
+        }
+
         let exe_file = self.make_exe_name();
 
         // FIXME (#9639): This needs to handle non-utf8 paths
diff --git a/src/tools/compiletest/src/util.rs b/src/tools/compiletest/src/util.rs
index bd4044b4df3b4..c00f28eae67af 100644
--- a/src/tools/compiletest/src/util.rs
+++ b/src/tools/compiletest/src/util.rs
@@ -51,10 +51,15 @@ const ARCH_TABLE: &'static [(&'static str, &'static str)] = &[
     ("wasm32", "wasm32"),
 ];
 
-pub fn get_os(triple: &str) -> &'static str {
+pub fn matches_os(triple: &str, name: &str) -> bool {
+    // For the wasm32 bare target we ignore anything also ignored on emscripten
+    // and then we also recognize `wasm32-bare` as the os for the target
+    if triple == "wasm32-unknown-unknown" {
+        return name == "emscripten" || name == "wasm32-bare"
+    }
     for &(triple_os, os) in OS_TABLE {
         if triple.contains(triple_os) {
-            return os;
+            return os == name;
         }
     }
     panic!("Cannot determine OS from triple");
diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs
index c316ec467620a..598620fa29392 100644
--- a/src/tools/tidy/src/lib.rs
+++ b/src/tools/tidy/src/lib.rs
@@ -50,6 +50,8 @@ pub mod unstable_book;
 
 fn filter_dirs(path: &Path) -> bool {
     let skip = [
+        "src/binaryen",
+        "src/dlmalloc",
         "src/jemalloc",
         "src/llvm",
         "src/libbacktrace",