Auto merge of #45905 - alexcrichton:add-wasm-target, r=aturon

std: Add a new wasm32-unknown-unknown target

This commit adds a new target to the compiler: wasm32-unknown-unknown. This target is a reimagining of what it looks like to generate WebAssembly code from Rust. Instead of using Emscripten which can bring with it a weighty runtime this instead is a target which uses only the LLVM backend for WebAssembly and a "custom linker" for now which will hopefully one day be direct calls to lld.

Notable features of this target include:

* There is zero runtime footprint. The target assumes nothing exists other than the wasm32 instruction set.
* There is zero toolchain footprint beyond adding the target. No custom linker is needed, rustc contains everything.
* Very small wasm modules can be generated directly from Rust code using this target.
* Most of the standard library is stubbed out to return an error, but anything related to allocation works (aka `HashMap`, `Vec`, etc).
* Naturally, any `#[no_std]` crate should be 100% compatible with this new target.

This target is currently somewhat janky due to how linking works. The "linking" is currently unconditional whole program LTO (aka LLVM is being used as a linker). Naturally that means compiling programs is pretty slow! Eventually though this target should have a linker.

This target is also intended to be quite experimental. I'm hoping that this can act as a catalyst for further experimentation in Rust with WebAssembly. Breaking changes are very likely to land to this target, so it's not recommended to rely on it in any critical capacity yet. We'll let you know when it's "production ready".

### Building yourself

First you'll need to configure the build of LLVM and enable this target

```
$ ./configure --target=wasm32-unknown-unknown --set llvm.experimental-targets=WebAssembly
```

Next you'll want to remove any previously compiled LLVM as it needs to be rebuilt with WebAssembly support. You can do that with:

```
$ rm -rf build
```

And then you're good to go! A `./x.py build` should give you a rustc with the appropriate libstd target.

### Test support

Currently testing-wise this target is looking pretty good but isn't complete. I've got almost the entire `run-pass` test suite working with this target (lots of tests ignored, but many passing as well). The `core` test suite is [still getting LLVM bugs fixed](https://reviews.llvm.org/D39866) to get that working and will take some time. Relatively simple programs all seem to work though!

In general I've only tested this with a local fork that makes use of LLVM 5 rather than our current LLVM 4 on master. The LLVM 4 WebAssembly backend AFAIK isn't broken per se but is likely missing bug fixes available on LLVM 5. I'm hoping though that we can decouple the LLVM 5 upgrade and adding this wasm target!

### But the modules generated are huge!

It's worth nothing that you may not immediately see the "smallest possible wasm module" for the input you feed to rustc. For various reasons it's very difficult to get rid of the final "bloat" in vanilla rustc (again, a real linker should fix all this). For now what you'll have to do is:

    cargo install --git https://github.com/alexcrichton/wasm-gc
    wasm-gc foo.wasm bar.wasm

And then `bar.wasm` should be the smallest we can get it!

---

In any case for now I'd love feedback on this, particularly on the various integration points if you've got better ideas of how to approach them!
diff --git a/.gitmodules b/.gitmodules
index 2802c8d..0a1188e 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 277108c..d0d6271 100644
--- a/src/Cargo.lock
+++ b/src/Cargo.lock
@@ -50,6 +50,7 @@
 dependencies = [
  "alloc 0.0.0",
  "core 0.0.0",
+ "dlmalloc 0.0.0",
  "libc 0.0.0",
 ]
 
@@ -372,9 +373,6 @@
 [[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"
@@ -510,6 +508,14 @@
 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"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1609,6 +1615,15 @@
 ]
 
 [[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"
 dependencies = [
@@ -1880,6 +1895,7 @@
  "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 0000000..1c9bf65
--- /dev/null
+++ b/src/binaryen
@@ -0,0 +1 @@
+Subproject commit 1c9bf65aa0e371b84755a8ddd6e79497fac57171
diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs
index 1401bc8..4d69b19 100644
--- a/src/bootstrap/check.rs
+++ b/src/bootstrap/check.rs
@@ -1211,7 +1211,8 @@
                     // 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 7bf3853..9f7e3de 100644
--- a/src/bootstrap/dist.rs
+++ b/src/bootstrap/dist.rs
@@ -672,6 +672,9 @@
              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 @@
         // (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 @@
             "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 0000000..d3812c3
--- /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 0000000..b595cc1
--- /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 65e035d..a41a04d 100644
--- a/src/liballoc_jemalloc/build.rs
+++ b/src/liballoc_jemalloc/build.rs
@@ -31,7 +31,7 @@
     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 a725a86..f9a57f7 100644
--- a/src/liballoc_system/Cargo.toml
+++ b/src/liballoc_system/Cargo.toml
@@ -13,3 +13,7 @@
 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 7aa5f8a..05cacf6 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 @@
         }
     }
 }
+
+// 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 d1a0a5f..5af63aa 100644
--- a/src/libcore/Cargo.toml
+++ b/src/libcore/Cargo.toml
@@ -9,9 +9,6 @@
 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 96d8308..e2283a7 100644
--- a/src/libcore/tests/lib.rs
+++ b/src/libcore/tests/lib.rs
@@ -28,7 +28,6 @@
 #![feature(iter_rfind)]
 #![feature(iter_rfold)]
 #![feature(nonzero)]
-#![feature(rand)]
 #![feature(raw)]
 #![feature(refcell_replace_swap)]
 #![feature(sip_hash_13)]
@@ -49,7 +48,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 2720c5c..ef01788 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 @@
                       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 17fb99b..286b39d8 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::*;
 
@@ -47,35 +46,6 @@
 }
 
 #[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
     // ignored on MSVC
@@ -86,24 +56,6 @@
 }
 
 #[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 3763683..fa4c2e9 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() {
@@ -307,68 +304,3 @@
         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 8be6f64..29a9e1a 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 @@
         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 @@
 // 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 558286f..6b8da7a 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 @@
 #[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 0000000..8aed61b
--- /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 00a91ee..9f957cd 100644
--- a/src/librustc/session/mod.rs
+++ b/src/librustc/session/mod.rs
@@ -432,7 +432,7 @@
             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 d67de12..824b553 100644
--- a/src/librustc_back/lib.rs
+++ b/src/librustc_back/lib.rs
@@ -84,6 +84,7 @@
 
 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 d60d643..7599a60 100644
--- a/src/librustc_back/target/mod.rs
+++ b/src/librustc_back/target/mod.rs
@@ -218,6 +218,7 @@
 
     ("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 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 @@
     /// 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 @@
             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 @@
             min_global_align: None,
             default_codegen_units: None,
             trap_unreachable: true,
+            requires_lto: false,
+            singlethread: false,
+            no_builtins: false,
         }
     }
 }
@@ -702,6 +720,7 @@
         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 @@
         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 @@
         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 @@
         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 0000000..7e1011a
--- /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 0000000..d1095a7
--- /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 0000000..9573c89
--- /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 0000000..f23ff3c
--- /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 0000000..6c7feb6
--- /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 f8c71d4..aab6139 100644
--- a/src/librustc_llvm/ffi.rs
+++ b/src/librustc_llvm/ffi.rs
@@ -1582,7 +1582,8 @@
                                        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 f797464..96102ca 100644
--- a/src/librustc_trans/Cargo.toml
+++ b/src/librustc_trans/Cargo.toml
@@ -11,16 +11,17 @@
 
 [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 feeef1d..e0eef1f 100644
--- a/src/librustc_trans/back/link.rs
+++ b/src/librustc_trans/back/link.rs
@@ -27,7 +27,7 @@
 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 @@
 /// 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,
@@ -505,7 +505,7 @@
         });
         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());
@@ -565,6 +565,11 @@
     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
@@ -1193,7 +1198,7 @@
             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));
@@ -1246,8 +1251,10 @@
                 // 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);
@@ -1362,3 +1369,30 @@
         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 51f8911..aa29c3c 100644
--- a/src/librustc_trans/back/linker.rs
+++ b/src/librustc_trans/back/linker.rs
@@ -77,6 +77,9 @@
                     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 132b8fa..fa6fe2e 100644
--- a/src/librustc_trans/back/symbol_export.rs
+++ b/src/librustc_trans/back/symbol_export.rs
@@ -21,6 +21,7 @@
 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 @@
         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 e443f13..da67940 100644
--- a/src/librustc_trans/back/write.rs
+++ b/src/librustc_trans/back/write.rs
@@ -22,6 +22,7 @@
                              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::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 @@
         }
     };
 
+    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 @@
                 ffunction_sections,
                 fdata_sections,
                 trap_unreachable,
+                singlethread,
             )
         };
 
@@ -287,7 +291,7 @@
     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 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 @@
         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 @@
             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 @@
             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 @@
                                    &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 @@
 
     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 @@
         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 f6c4153..923d935 100644
--- a/src/librustc_trans/lib.rs
+++ b/src/librustc_trans/lib.rs
@@ -45,18 +45,19 @@
 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 4748448..c1e670c 100644
--- a/src/librustc_trans_utils/link.rs
+++ b/src/librustc_trans_utils/link.rs
@@ -163,15 +163,30 @@
 /// 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 0e6214e..06f11c8 100644
--- a/src/libstd/build.rs
+++ b/src/libstd/build.rs
@@ -19,8 +19,12 @@
 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 7ec6124..14f0edc 100644
--- a/src/libstd/f32.rs
+++ b/src/libstd/f32.rs
@@ -26,7 +26,6 @@
 #[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 6318e2e..9d03734 100644
--- a/src/libstd/macros.rs
+++ b/src/libstd/macros.rs
@@ -663,3 +663,39 @@
     #[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 d91c207..27d6433 100644
--- a/src/libstd/sys/mod.rs
+++ b/src/libstd/sys/mod.rs
@@ -46,6 +46,9 @@
 #[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 0000000..d2a4a7b
--- /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 0000000..9a8c48f
--- /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 0000000..87ac209
--- /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 0000000..afa7afe
--- /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 0000000..1422042
--- /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 0000000..b3c70a6
--- /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 0000000..e611d94
--- /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 0000000..b838dba
--- /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 0000000..4197bdc
--- /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 0000000..e7476ab
--- /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 0000000..c98030f
--- /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 0000000..c5908a7
--- /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 0000000..395b8c1
--- /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 0000000..992e1ac
--- /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 0000000..4febe8a
--- /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 0000000..8b06f54
--- /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 0000000..bed2741
--- /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 0000000..0f75f24
--- /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 0000000..13980e0
--- /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 0000000..442dd33
--- /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 0000000..7907720
--- /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 d7654ce..14e5697 100644
--- a/src/libstd/sys_common/mod.rs
+++ b/src/libstd/sys_common/mod.rs
@@ -44,11 +44,15 @@
 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 c19424f..f1379b6 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 97eec3a..ebe7853 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -415,6 +415,9 @@
 
     // 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 @@
                                       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 76abcb8..ef08b87 100644
--- a/src/libtest/lib.rs
+++ b/src/libtest/lib.rs
@@ -434,7 +434,8 @@
 // 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 @@
     // 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 @@
             }})
     };
 
-    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 @@
         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 @@
 
     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 @@
         // 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 461b49a..5bb1eb9 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 0000000..26376a3
--- /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 0000000..cf8440c4
--- /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 b4116c9..d0c042e 100644
--- a/src/rustllvm/PassWrapper.cpp
+++ b/src/rustllvm/PassWrapper.cpp
@@ -366,7 +366,9 @@
     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 @@
     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 0000000..a010ebb
--- /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 0000000..3db0644
--- /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 0000000..af8a691
--- /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 b46f024..2208167 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 @@
 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 4b987b92..04d2ef4 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 7e6cd9f..155fb5d 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_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 b40774e..8c480d7 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 208b4df..16ca7bc 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 b6199f5..f34a975 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 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 90a4113..7e7c5ee 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 5319693..df4989d 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 84f2202..46b3fd1 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 bf94dd1..5b1677c 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 df54ec9..849132b 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 415607a..1797ad1 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 b6954f7c..0b8574e 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 8e718f3..9c87f2c 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 411df2b..e77fd5f 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 91c9887..4cb3dbe 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 483dbb3..3310d3a 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 933d9a7..af44a65 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 6a9da76..a41ab8d 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 256eedc..ba10895 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 7157d06..825b502 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 afdd53d..a1aa9b6 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 035084a..6442f23 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 cb1a4d2..bfb649c3 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 657348c..1f90d9c 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 9042aed..920e15b 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 38d2918..9c18447 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 ed254ac..691bd62 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 6fc630e..4b351ed 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 ec1c613..b9ce3f45 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 e829e99..686ff16 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 ef7325b..e754674 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 46f2e81..68fe383 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 8ce1f74..123458f 100644
--- a/src/test/run-pass/extern_fat_drop.rs
+++ b/src/test/run-pass/extern_fat_drop.rs
@@ -14,7 +14,8 @@
 
 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 96f3189..4ecb9da 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 fb162d8..b79e6e9 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 a9001a3..ab8e4fb 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 2d45425..65efa57 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 70d4801..5e9e529 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 979e57e..b516cdf 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 d83bd94..d69d697 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 53cd323..36e401a 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 a583f42..0d5bae7 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 b2e2a3e..56511dc 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 cfae990..99edd255 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 1aae813..d01c3b6 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 ddd30ed..00e8aa6 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 1e9f30b..4620d98 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 084b7a1..75a724e 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 ad19a9b..e705539 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 @@
     }
 }
 
-
 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 316e379..7b7ecc9 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 d8d2d50..9a2dbd1 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 8f83e51..a7bee42 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 281dde1..3a7e9ba 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 ecce5df..bcf8a91 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 1093047..c278dce 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 f55d584..e9f8d27 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 56e69a9..7eb09e05 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 aad90bd..2e93279 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 f1ac96ab..0fc1331 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_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 5b9b58f..c45a10e 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 6c07afb..c640f7c 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 a3a7179..517cd13 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 6e5dcca..fcaeda9 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 7300a32..9641ed2 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 e7da435..41cb458 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 ae719ac..81c8b75 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 @@
 
 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_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 @@
     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 @@
     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 @@
     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 @@
     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 @@
     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 @@
     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 @@
     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 @@
     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 @@
     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 @@
     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 @@
     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 @@
 }
 
 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 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 e4d528e..7845c94 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 d1ad561..07c76e2 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)]
+pub struct Fd(u32);
 
-extern crate libc;
-use libc::c_int;
-
-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 2da3e59..9f39146 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 b9a3f78..1ef804f 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 75a2e36..d087be6 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 4863979..d051e05 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 b67612c..8f278a3 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 @@
 
 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 @@
     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 df96907..950c2e0 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 26713a2..c51b33f 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 42f9895..b2e5ff6 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 26fa36f..73ccd28 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 57609ce..ab6adcb 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 24d5848..2b7fa01 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 ed618ce..61a2bcb 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 a47ae52..7f92707 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 @@
 
   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 @@
 
   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 @@
 
   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 @@
 
   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 @@
 
   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 @@
 
   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 @@
 
   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 @@
 
   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 @@
 
   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 @@
 
   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 @@
 
   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 85ab59a..4dadfdf 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 aa9cf76..884633d 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 e665fa4..360d495 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 b3df7d6..dd16bf2 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 ec6261f..2198ead 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 106bf8c..e2e64dd 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 430c02c..c853d53 100644
--- a/src/tools/compiletest/src/header.rs
+++ b/src/tools/compiletest/src/header.rs
@@ -539,7 +539,7 @@
             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 b5a8a15..749d1f4 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -1271,6 +1271,7 @@
             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
@@ -1432,7 +1433,10 @@
             }
         }
 
-        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"]);
         }
 
@@ -1473,6 +1477,10 @@
             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);
@@ -1495,6 +1503,22 @@
             }
         }
 
+        // 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 bd4044b..c00f28e 100644
--- a/src/tools/compiletest/src/util.rs
+++ b/src/tools/compiletest/src/util.rs
@@ -51,10 +51,15 @@
     ("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 c316ec4..598620f 100644
--- a/src/tools/tidy/src/lib.rs
+++ b/src/tools/tidy/src/lib.rs
@@ -50,6 +50,8 @@
 
 fn filter_dirs(path: &Path) -> bool {
     let skip = [
+        "src/binaryen",
+        "src/dlmalloc",
         "src/jemalloc",
         "src/llvm",
         "src/libbacktrace",