about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorMazdak Farrokhzad <twingoow@gmail.com>2019-07-29 02:10:52 +0200
committerGitHub <noreply@github.com>2019-07-29 02:10:52 +0200
commit778b631ff06c463fad290ea8ff8f2817ab62a5fd (patch)
tree45b3e2a9c745e5c6956b9556c011c899285a6bdc /src
parentc7312fe4ff85ada30103cea58db25d83e0bec4b0 (diff)
parentdc50a633f3260a3aeb79a4ca9800587be7f732e7 (diff)
downloadrust-778b631ff06c463fad290ea8ff8f2817ab62a5fd.tar.gz
rust-778b631ff06c463fad290ea8ff8f2817ab62a5fd.zip
Rollup merge of #62809 - alexcrichton:wasm-llvm-9, r=nikic
rustc: Update wasm32 support for LLVM 9

This commit brings in a number of minor updates for rustc's support for
the wasm target which has changed in the LLVM 9 update. Notable updates
include:

* The compiler now no longer manually inserts the `producers` section,
  instead relying on LLVM to do so. LLVM uses the `llvm.ident` metadata
  for the `processed-by` directive (which is now emitted on the wasm
  target in this PR) and it uses debuginfo to figure out what `language`
  to put in the `producers` section.

* Threaded WebAssembly code now requires different flags to be passed
  with LLD. In LLD we now pass:

  * `--shared-memory` - required since objects are compiled with
    atomics. This also means that the generated memory will be marked as
    `shared`.
  * `--max-memory=1GB` - required with the `--shared-memory` argument
    since shared memories in WebAssembly must have a maximum size. The
    1GB number is intended to be a conservative estimate for rustc, but
    it should be overridable with `-C link-arg` if necessary.
  * `--passive-segments` - this has become the default for multithreaded
    memory, but when compiling a threaded module all data segments need
    to be marked as passive to ensure they don't re-initialize memory
    for each thread. This will also cause LLD to emit a synthetic
    function to initialize memory which users will have to arrange to
    call.
  * The `__heap_base` and `__data_end` globals are explicitly exported
    since they're now hidden by default due to the `--export` flags we
    pass to LLD.
Diffstat (limited to 'src')
-rw-r--r--src/librustc_codegen_llvm/debuginfo/metadata.rs22
-rw-r--r--src/librustc_codegen_ssa/back/link.rs8
-rw-r--r--src/librustc_codegen_ssa/back/linker.rs47
-rw-r--r--src/librustc_codegen_ssa/back/mod.rs1
-rw-r--r--src/librustc_codegen_ssa/back/wasm.rs191
-rw-r--r--src/librustc_target/spec/wasm32_base.rs8
-rw-r--r--src/libstd/Cargo.toml5
-rw-r--r--src/libstd/sys/wasi/mod.rs2
-rw-r--r--src/libstd/sys/wasm/fast_thread_local.rs9
-rw-r--r--src/libstd/sys/wasm/mod.rs5
-rw-r--r--src/libstd/sys/wasm/thread.rs76
-rw-r--r--src/libstd/sys/wasm/thread_local.rs32
-rw-r--r--src/libstd/sys/wasm/thread_local_atomics.rs61
m---------src/llvm-project0
14 files changed, 130 insertions, 337 deletions
diff --git a/src/librustc_codegen_llvm/debuginfo/metadata.rs b/src/librustc_codegen_llvm/debuginfo/metadata.rs
index fbeda43af42..f0bdb0018ef 100644
--- a/src/librustc_codegen_llvm/debuginfo/metadata.rs
+++ b/src/librustc_codegen_llvm/debuginfo/metadata.rs
@@ -913,9 +913,12 @@ pub fn compile_unit_metadata(
     }
 
     debug!("compile_unit_metadata: {:?}", name_in_debuginfo);
+    let rustc_producer = format!(
+        "rustc version {}",
+        option_env!("CFG_VERSION").expect("CFG_VERSION"),
+    );
     // FIXME(#41252) Remove "clang LLVM" if we can get GDB and LLVM to play nice.
-    let producer = format!("clang LLVM (rustc version {})",
-                           (option_env!("CFG_VERSION")).expect("CFG_VERSION"));
+    let producer = format!("clang LLVM ({})", rustc_producer);
 
     let name_in_debuginfo = name_in_debuginfo.to_string_lossy();
     let name_in_debuginfo = SmallCStr::new(&name_in_debuginfo);
@@ -980,6 +983,21 @@ pub fn compile_unit_metadata(
                                               gcov_metadata);
         }
 
+        // Insert `llvm.ident` metadata on the wasm32 targets since that will
+        // get hooked up to the "producer" sections `processed-by` information.
+        if tcx.sess.opts.target_triple.triple().starts_with("wasm32") {
+            let name_metadata = llvm::LLVMMDStringInContext(
+                debug_context.llcontext,
+                rustc_producer.as_ptr() as *const _,
+                rustc_producer.as_bytes().len() as c_uint,
+            );
+            llvm::LLVMAddNamedMetadataOperand(
+                debug_context.llmod,
+                const_cstr!("llvm.ident").as_ptr(),
+                llvm::LLVMMDNodeInContext(debug_context.llcontext, &name_metadata, 1),
+            );
+        }
+
         return unit_metadata;
     };
 
diff --git a/src/librustc_codegen_ssa/back/link.rs b/src/librustc_codegen_ssa/back/link.rs
index 707b7cae16c..3f6a1a72ea6 100644
--- a/src/librustc_codegen_ssa/back/link.rs
+++ b/src/librustc_codegen_ssa/back/link.rs
@@ -678,14 +678,6 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(sess: &'a Session,
             sess.fatal(&format!("failed to run dsymutil: {}", e))
         }
     }
-
-    if sess.opts.target_triple.triple() == "wasm32-unknown-unknown" {
-        super::wasm::add_producer_section(
-            &out_filename,
-            &sess.edition().to_string(),
-            option_env!("CFG_VERSION").unwrap_or("unknown"),
-        );
-    }
 }
 
 /// Returns a boolean indicating whether the specified crate should be ignored
diff --git a/src/librustc_codegen_ssa/back/linker.rs b/src/librustc_codegen_ssa/back/linker.rs
index cb8870d0be9..26091005f25 100644
--- a/src/librustc_codegen_ssa/back/linker.rs
+++ b/src/librustc_codegen_ssa/back/linker.rs
@@ -901,7 +901,45 @@ pub struct WasmLd<'a> {
 }
 
 impl<'a> WasmLd<'a> {
-    fn new(cmd: Command, sess: &'a Session, info: &'a LinkerInfo) -> WasmLd<'a> {
+    fn new(mut cmd: Command, sess: &'a Session, info: &'a LinkerInfo) -> WasmLd<'a> {
+        // If the atomics feature is enabled for wasm then we need a whole bunch
+        // of flags:
+        //
+        // * `--shared-memory` - the link won't even succeed without this, flags
+        //   the one linear memory as `shared`
+        //
+        // * `--max-memory=1G` - when specifying a shared memory this must also
+        //   be specified. We conservatively choose 1GB but users should be able
+        //   to override this with `-C link-arg`.
+        //
+        // * `--import-memory` - it doesn't make much sense for memory to be
+        //   exported in a threaded module because typically you're
+        //   sharing memory and instantiating the module multiple times. As a
+        //   result if it were exported then we'd just have no sharing.
+        //
+        // * `--passive-segments` - all memory segments should be passive to
+        //   prevent each module instantiation from reinitializing memory.
+        //
+        // * `--export=__wasm_init_memory` - when using `--passive-segments` the
+        //   linker will synthesize this function, and so we need to make sure
+        //   that our usage of `--export` below won't accidentally cause this
+        //   function to get deleted.
+        //
+        // * `--export=*tls*` - when `#[thread_local]` symbols are used these
+        //   symbols are how the TLS segments are initialized and configured.
+        let atomics = sess.opts.cg.target_feature.contains("+atomics") ||
+            sess.target.target.options.features.contains("+atomics");
+        if atomics {
+            cmd.arg("--shared-memory");
+            cmd.arg("--max-memory=1073741824");
+            cmd.arg("--import-memory");
+            cmd.arg("--passive-segments");
+            cmd.arg("--export=__wasm_init_memory");
+            cmd.arg("--export=__wasm_init_tls");
+            cmd.arg("--export=__tls_size");
+            cmd.arg("--export=__tls_align");
+            cmd.arg("--export=__tls_base");
+        }
         WasmLd { cmd, sess, info }
     }
 }
@@ -1004,6 +1042,13 @@ impl<'a> Linker for WasmLd<'a> {
         for sym in self.info.exports[&crate_type].iter() {
             self.cmd.arg("--export").arg(&sym);
         }
+
+        // LLD will hide these otherwise-internal symbols since our `--export`
+        // list above is a whitelist of what to export. Various bits and pieces
+        // of tooling use this, so be sure these symbols make their way out of
+        // the linker as well.
+        self.cmd.arg("--export=__heap_base");
+        self.cmd.arg("--export=__data_end");
     }
 
     fn subsystem(&mut self, _subsystem: &str) {
diff --git a/src/librustc_codegen_ssa/back/mod.rs b/src/librustc_codegen_ssa/back/mod.rs
index a16d099ee3e..901891d85a4 100644
--- a/src/librustc_codegen_ssa/back/mod.rs
+++ b/src/librustc_codegen_ssa/back/mod.rs
@@ -6,4 +6,3 @@ pub mod command;
 pub mod symbol_export;
 pub mod archive;
 pub mod rpath;
-pub mod wasm;
diff --git a/src/librustc_codegen_ssa/back/wasm.rs b/src/librustc_codegen_ssa/back/wasm.rs
deleted file mode 100644
index 2a9e81a788e..00000000000
--- a/src/librustc_codegen_ssa/back/wasm.rs
+++ /dev/null
@@ -1,191 +0,0 @@
-use std::fs;
-use std::path::Path;
-use std::str;
-
-use rustc_serialize::leb128;
-
-// https://webassembly.github.io/spec/core/binary/modules.html#binary-importsec
-const WASM_CUSTOM_SECTION_ID: u8 = 0;
-
-/// Adds or augment the existing `producers` section to encode information about
-/// the Rust compiler used to produce the wasm file.
-pub fn add_producer_section(
-    path: &Path,
-    rust_version: &str,
-    rustc_version: &str,
-) {
-    struct Field<'a> {
-        name: &'a str,
-        values: Vec<FieldValue<'a>>,
-    }
-
-    #[derive(Copy, Clone)]
-    struct FieldValue<'a> {
-        name: &'a str,
-        version: &'a str,
-    }
-
-    let wasm = fs::read(path).expect("failed to read wasm output");
-    let mut ret = WasmEncoder::new();
-    ret.data.extend(&wasm[..8]);
-
-    // skip the 8 byte wasm/version header
-    let rustc_value = FieldValue {
-        name: "rustc",
-        version: rustc_version,
-    };
-    let rust_value = FieldValue {
-        name: "Rust",
-        version: rust_version,
-    };
-    let mut fields = Vec::new();
-    let mut wrote_rustc = false;
-    let mut wrote_rust = false;
-
-    // Move all sections from the original wasm file to our output, skipping
-    // everything except the producers section
-    for (id, raw) in WasmSections(WasmDecoder::new(&wasm[8..])) {
-        if id != WASM_CUSTOM_SECTION_ID {
-            ret.byte(id);
-            ret.bytes(raw);
-            continue
-        }
-        let mut decoder = WasmDecoder::new(raw);
-        if decoder.str() != "producers" {
-            ret.byte(id);
-            ret.bytes(raw);
-            continue
-        }
-
-        // Read off the producers section into our fields outside the loop,
-        // we'll re-encode the producers section when we're done (to handle an
-        // entirely missing producers section as well).
-        info!("rewriting existing producers section");
-
-        for _ in 0..decoder.u32() {
-            let name = decoder.str();
-            let mut values = Vec::new();
-            for _ in 0..decoder.u32() {
-                let name = decoder.str();
-                let version = decoder.str();
-                values.push(FieldValue { name, version });
-            }
-
-            if name == "language" {
-                values.push(rust_value);
-                wrote_rust = true;
-            } else if name == "processed-by" {
-                values.push(rustc_value);
-                wrote_rustc = true;
-            }
-            fields.push(Field { name, values });
-        }
-    }
-
-    if !wrote_rust {
-        fields.push(Field {
-            name: "language",
-            values: vec![rust_value],
-        });
-    }
-    if !wrote_rustc {
-        fields.push(Field {
-            name: "processed-by",
-            values: vec![rustc_value],
-        });
-    }
-
-    // Append the producers section to the end of the wasm file.
-    let mut section = WasmEncoder::new();
-    section.str("producers");
-    section.u32(fields.len() as u32);
-    for field in fields {
-        section.str(field.name);
-        section.u32(field.values.len() as u32);
-        for value in field.values {
-            section.str(value.name);
-            section.str(value.version);
-        }
-    }
-    ret.byte(WASM_CUSTOM_SECTION_ID);
-    ret.bytes(&section.data);
-
-    fs::write(path, &ret.data).expect("failed to write wasm output");
-}
-
-struct WasmSections<'a>(WasmDecoder<'a>);
-
-impl<'a> Iterator for WasmSections<'a> {
-    type Item = (u8, &'a [u8]);
-
-    fn next(&mut self) -> Option<(u8, &'a [u8])> {
-        if self.0.data.is_empty() {
-            return None
-        }
-
-        // see https://webassembly.github.io/spec/core/binary/modules.html#sections
-        let id = self.0.byte();
-        let section_len = self.0.u32();
-        info!("new section {} / {} bytes", id, section_len);
-        let section = self.0.skip(section_len as usize);
-        Some((id, section))
-    }
-}
-
-struct WasmDecoder<'a> {
-    data: &'a [u8],
-}
-
-impl<'a> WasmDecoder<'a> {
-    fn new(data: &'a [u8]) -> WasmDecoder<'a> {
-        WasmDecoder { data }
-    }
-
-    fn byte(&mut self) -> u8 {
-        self.skip(1)[0]
-    }
-
-    fn u32(&mut self) -> u32 {
-        let (n, l1) = leb128::read_u32_leb128(self.data);
-        self.data = &self.data[l1..];
-        return n
-    }
-
-    fn skip(&mut self, amt: usize) -> &'a [u8] {
-        let (data, rest) = self.data.split_at(amt);
-        self.data = rest;
-        data
-    }
-
-    fn str(&mut self) -> &'a str {
-        let len = self.u32();
-        str::from_utf8(self.skip(len as usize)).unwrap()
-    }
-}
-
-struct WasmEncoder {
-    data: Vec<u8>,
-}
-
-impl WasmEncoder {
-    fn new() -> WasmEncoder {
-        WasmEncoder { data: Vec::new() }
-    }
-
-    fn u32(&mut self, val: u32) {
-        leb128::write_u32_leb128(&mut self.data, val);
-    }
-
-    fn byte(&mut self, val: u8) {
-        self.data.push(val);
-    }
-
-    fn bytes(&mut self, val: &[u8]) {
-        self.u32(val.len() as u32);
-        self.data.extend_from_slice(val);
-    }
-
-    fn str(&mut self, val: &str) {
-        self.bytes(val.as_bytes())
-    }
-}
diff --git a/src/librustc_target/spec/wasm32_base.rs b/src/librustc_target/spec/wasm32_base.rs
index 39a8ce92825..6f00245b009 100644
--- a/src/librustc_target/spec/wasm32_base.rs
+++ b/src/librustc_target/spec/wasm32_base.rs
@@ -132,6 +132,14 @@ pub fn options() -> TargetOptions {
         // non-relative calls and such later on).
         relocation_model: "static".to_string(),
 
+        // When the atomics feature is activated then these two keys matter,
+        // otherwise they're basically ignored by the standard library. In this
+        // mode, however, the `#[thread_local]` attribute works (i.e.
+        // `has_elf_tls`) and we need to get it to work by specifying
+        // `local-exec` as that's all that's implemented in LLVM today for wasm.
+        has_elf_tls: true,
+        tls_model: "local-exec".to_string(),
+
         .. Default::default()
     }
 }
diff --git a/src/libstd/Cargo.toml b/src/libstd/Cargo.toml
index 6da77ab57d1..2e0da0409eb 100644
--- a/src/libstd/Cargo.toml
+++ b/src/libstd/Cargo.toml
@@ -75,11 +75,6 @@ panic_immediate_abort = ["core/panic_immediate_abort"]
 # requires rebuilding the standard library to use it.
 wasm_syscall = []
 
-# An off-by-default features to enable libstd to assume that wasm-bindgen is in
-# the environment for hooking up some thread-related information like the
-# current thread id and accessing/getting the current thread's TCB
-wasm-bindgen-threads = []
-
 # Enable std_detect default features for stdarch/crates/std_detect:
 # https://github.com/rust-lang/stdarch/blob/master/crates/std_detect/Cargo.toml
 std_detect_file_io = []
diff --git a/src/libstd/sys/wasi/mod.rs b/src/libstd/sys/wasi/mod.rs
index e22434439f5..f842869e08e 100644
--- a/src/libstd/sys/wasi/mod.rs
+++ b/src/libstd/sys/wasi/mod.rs
@@ -47,6 +47,8 @@ pub mod stdio;
 pub mod thread;
 #[path = "../wasm/thread_local.rs"]
 pub mod thread_local;
+#[path = "../wasm/fast_thread_local.rs"]
+pub mod fast_thread_local;
 pub mod time;
 pub mod ext;
 
diff --git a/src/libstd/sys/wasm/fast_thread_local.rs b/src/libstd/sys/wasm/fast_thread_local.rs
new file mode 100644
index 00000000000..ff2198175f0
--- /dev/null
+++ b/src/libstd/sys/wasm/fast_thread_local.rs
@@ -0,0 +1,9 @@
+#![unstable(feature = "thread_local_internals", issue = "0")]
+
+pub unsafe fn register_dtor(_t: *mut u8, _dtor: unsafe extern fn(*mut u8)) {
+    // FIXME: right now there is no concept of "thread exit", but this is likely
+    // going to show up at some point in the form of an exported symbol that the
+    // wasm runtime is oging to be expected to call. For now we basically just
+    // ignore the arguments, but if such a function starts to exist it will
+    // likely look like the OSX implementation in `unix/fast_thread_local.rs`
+}
diff --git a/src/libstd/sys/wasm/mod.rs b/src/libstd/sys/wasm/mod.rs
index 7d157709eb6..56cbafcfdb8 100644
--- a/src/libstd/sys/wasm/mod.rs
+++ b/src/libstd/sys/wasm/mod.rs
@@ -37,6 +37,8 @@ pub mod stack_overflow;
 pub mod thread;
 pub mod time;
 pub mod stdio;
+pub mod thread_local;
+pub mod fast_thread_local;
 
 pub use crate::sys_common::os_str_bytes as os_str;
 
@@ -48,13 +50,10 @@ cfg_if::cfg_if! {
         pub mod mutex;
         #[path = "rwlock_atomics.rs"]
         pub mod rwlock;
-        #[path = "thread_local_atomics.rs"]
-        pub mod thread_local;
     } else {
         pub mod condvar;
         pub mod mutex;
         pub mod rwlock;
-        pub mod thread_local;
     }
 }
 
diff --git a/src/libstd/sys/wasm/thread.rs b/src/libstd/sys/wasm/thread.rs
index 61b4003cd3d..d06965f3278 100644
--- a/src/libstd/sys/wasm/thread.rs
+++ b/src/libstd/sys/wasm/thread.rs
@@ -59,48 +59,40 @@ pub mod guard {
     pub unsafe fn init() -> Option<Guard> { None }
 }
 
-cfg_if::cfg_if! {
-    if #[cfg(all(target_feature = "atomics", feature = "wasm-bindgen-threads"))] {
-        #[link(wasm_import_module = "__wbindgen_thread_xform__")]
-        extern {
-            fn __wbindgen_current_id() -> u32;
-            fn __wbindgen_tcb_get() -> u32;
-            fn __wbindgen_tcb_set(ptr: u32);
+// This is only used by atomics primitives when the `atomics` feature is
+// enabled. In that mode we currently just use our own thread-local to store our
+// current thread's ID, and then we lazily initialize it to something allocated
+// from a global counter.
+#[cfg(target_feature = "atomics")]
+pub fn my_id() -> u32 {
+    use crate::sync::atomic::{AtomicU32, Ordering::SeqCst};
+
+    static NEXT_ID: AtomicU32 = AtomicU32::new(0);
+
+    #[thread_local]
+    static mut MY_ID: u32 = 0;
+
+    unsafe {
+        // If our thread ID isn't set yet then we need to allocate one. Do so
+        // with with a simple "atomically add to a global counter" strategy.
+        // This strategy doesn't handled what happens when the counter
+        // overflows, however, so just abort everything once the counter
+        // overflows and eventually we could have some sort of recycling scheme
+        // (or maybe this is all totally irrelevant by that point!). In any case
+        // though we're using a CAS loop instead of a `fetch_add` to ensure that
+        // the global counter never overflows.
+        if MY_ID == 0 {
+            let mut cur = NEXT_ID.load(SeqCst);
+            MY_ID = loop {
+                let next = cur.checked_add(1).unwrap_or_else(|| {
+                    crate::arch::wasm32::unreachable()
+                });
+                match NEXT_ID.compare_exchange(cur, next, SeqCst, SeqCst) {
+                    Ok(_) => break next,
+                    Err(i) => cur = i,
+                }
+            };
         }
-        pub fn my_id() -> u32 {
-            unsafe { __wbindgen_current_id() }
-        }
-
-        // These are currently only ever used in `thread_local_atomics.rs`, if
-        // you'd like to use them be sure to update that and make sure everyone
-        // agrees what's what.
-        pub fn tcb_get() -> *mut u8 {
-            use crate::mem;
-            assert_eq!(mem::size_of::<*mut u8>(), mem::size_of::<u32>());
-            unsafe { __wbindgen_tcb_get() as *mut u8 }
-        }
-
-        pub fn tcb_set(ptr: *mut u8) {
-            unsafe { __wbindgen_tcb_set(ptr as u32); }
-        }
-
-        // FIXME: still need something for hooking exiting a thread to free
-        // data...
-
-    } else if #[cfg(target_feature = "atomics")] {
-        pub fn my_id() -> u32 {
-            panic!("thread ids not implemented on wasm with atomics yet")
-        }
-
-        pub fn tcb_get() -> *mut u8 {
-            panic!("thread local data not implemented on wasm with atomics yet")
-        }
-
-        pub fn tcb_set(_ptr: *mut u8) {
-            panic!("thread local data not implemented on wasm with atomics yet")
-        }
-    } else {
-        // stubbed out because no functions actually access these intrinsics
-        // unless atomics are enabled
+        MY_ID
     }
 }
diff --git a/src/libstd/sys/wasm/thread_local.rs b/src/libstd/sys/wasm/thread_local.rs
index 29e9854bcfc..8a0ca6f3d25 100644
--- a/src/libstd/sys/wasm/thread_local.rs
+++ b/src/libstd/sys/wasm/thread_local.rs
@@ -1,40 +1,26 @@
-use crate::boxed::Box;
-use crate::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
+pub unsafe fn create(_dtor: Option<unsafe extern fn(*mut u8)>) -> Key {
+    panic!("should not be used on the wasm target");
 }
 
 #[inline]
-pub unsafe fn set(key: Key, value: *mut u8) {
-    (*(key as *mut Allocated)).value = value;
+pub unsafe fn set(_key: Key, _value: *mut u8) {
+    panic!("should not be used on the wasm target");
 }
 
 #[inline]
-pub unsafe fn get(key: Key) -> *mut u8 {
-    (*(key as *mut Allocated)).value
+pub unsafe fn get(_key: Key) -> *mut u8 {
+    panic!("should not be used on the wasm target");
 }
 
 #[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);
-    }
+pub unsafe fn destroy(_key: Key) {
+    panic!("should not be used on the wasm target");
 }
 
 #[inline]
 pub fn requires_synchronized_create() -> bool {
-    false
+    panic!("should not be used on the wasm target");
 }
diff --git a/src/libstd/sys/wasm/thread_local_atomics.rs b/src/libstd/sys/wasm/thread_local_atomics.rs
deleted file mode 100644
index 3dc0bb24553..00000000000
--- a/src/libstd/sys/wasm/thread_local_atomics.rs
+++ /dev/null
@@ -1,61 +0,0 @@
-use crate::sys::thread;
-use crate::sync::atomic::{AtomicUsize, Ordering::SeqCst};
-
-const MAX_KEYS: usize = 128;
-static NEXT_KEY: AtomicUsize = AtomicUsize::new(0);
-
-struct ThreadControlBlock {
-    keys: [*mut u8; MAX_KEYS],
-}
-
-impl ThreadControlBlock {
-    fn new() -> ThreadControlBlock {
-        ThreadControlBlock {
-            keys: [core::ptr::null_mut(); MAX_KEYS],
-        }
-    }
-
-    fn get() -> *mut ThreadControlBlock {
-        let ptr = thread::tcb_get();
-        if !ptr.is_null() {
-            return ptr as *mut ThreadControlBlock
-        }
-        let tcb = Box::into_raw(Box::new(ThreadControlBlock::new()));
-        thread::tcb_set(tcb as *mut u8);
-        tcb
-    }
-}
-
-pub type Key = usize;
-
-pub unsafe fn create(dtor: Option<unsafe extern fn(*mut u8)>) -> Key {
-    drop(dtor); // FIXME: need to figure out how to hook thread exit to run this
-    let key = NEXT_KEY.fetch_add(1, SeqCst);
-    if key >= MAX_KEYS {
-        NEXT_KEY.store(MAX_KEYS, SeqCst);
-        panic!("cannot allocate space for more TLS keys");
-    }
-    // offset by 1 so we never hand out 0. This is currently required by
-    // `sys_common/thread_local.rs` where it can't cope with keys of value 0
-    // because it messes up the atomic management.
-    return key + 1
-}
-
-pub unsafe fn set(key: Key, value: *mut u8) {
-    (*ThreadControlBlock::get()).keys[key - 1] = value;
-}
-
-pub unsafe fn get(key: Key) -> *mut u8 {
-    (*ThreadControlBlock::get()).keys[key - 1]
-}
-
-pub unsafe fn destroy(_key: Key) {
-    // FIXME: should implement this somehow, this isn't typically called but it
-    // can be called if two threads race to initialize a TLS slot and one ends
-    // up not being needed.
-}
-
-#[inline]
-pub fn requires_synchronized_create() -> bool {
-    false
-}
diff --git a/src/llvm-project b/src/llvm-project
-Subproject f6446fa8e9629ffb1861303f17930c3aa83ef66
+Subproject 9b64ca5b7e1e3583978f9ac8af6d93b220a13d9