diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs
index 530b2f52c0df2..4c0eb1eeb5530 100644
--- a/src/libcore/fmt/mod.rs
+++ b/src/libcore/fmt/mod.rs
@@ -1036,6 +1036,27 @@ pub fn write(output: &mut dyn Write, args: Arguments) -> Result {
     Ok(())
 }
 
+/// Padding after the end of something. Returned by `Formatter::padding`.
+#[must_use = "don't forget to write the post padding"]
+struct PostPadding {
+    fill: char,
+    padding: usize,
+}
+
+impl PostPadding {
+    fn new(fill: char, padding: usize) -> PostPadding {
+        PostPadding { fill, padding }
+    }
+
+    /// Write this post padding.
+    fn write(self, buf: &mut dyn Write) -> Result {
+        for _ in 0..self.padding {
+            buf.write_char(self.fill)?;
+        }
+        Ok(())
+    }
+}
+
 impl<'a> Formatter<'a> {
     fn wrap_buf<'b, 'c, F>(&'b mut self, wrap: F) -> Formatter<'c>
         where 'b: 'c, F: FnOnce(&'b mut (dyn Write+'b)) -> &'c mut (dyn Write+'c)
@@ -1153,47 +1174,56 @@ impl<'a> Formatter<'a> {
             sign = Some('+'); width += 1;
         }
 
-        let prefixed = self.alternate();
-        if prefixed {
+        let prefix = if self.alternate() {
             width += prefix.chars().count();
-        }
+            Some(prefix)
+        } else {
+            None
+        };
 
         // Writes the sign if it exists, and then the prefix if it was requested
-        let write_prefix = |f: &mut Formatter| {
+        #[inline(never)]
+        fn write_prefix(f: &mut Formatter, sign: Option<char>, prefix: Option<&str>) -> Result {
             if let Some(c) = sign {
                 f.buf.write_char(c)?;
             }
-            if prefixed { f.buf.write_str(prefix) }
-            else { Ok(()) }
-        };
+            if let Some(prefix) = prefix {
+                f.buf.write_str(prefix)
+            } else {
+                Ok(())
+            }
+        }
 
         // The `width` field is more of a `min-width` parameter at this point.
         match self.width {
             // If there's no minimum length requirements then we can just
             // write the bytes.
             None => {
-                write_prefix(self)?; self.buf.write_str(buf)
+                write_prefix(self, sign, prefix)?;
+                self.buf.write_str(buf)
             }
             // Check if we're over the minimum width, if so then we can also
             // just write the bytes.
             Some(min) if width >= min => {
-                write_prefix(self)?; self.buf.write_str(buf)
+                write_prefix(self, sign, prefix)?;
+                self.buf.write_str(buf)
             }
             // The sign and prefix goes before the padding if the fill character
             // is zero
             Some(min) if self.sign_aware_zero_pad() => {
                 self.fill = '0';
                 self.align = rt::v1::Alignment::Right;
-                write_prefix(self)?;
-                self.with_padding(min - width, rt::v1::Alignment::Right, |f| {
-                    f.buf.write_str(buf)
-                })
+                write_prefix(self, sign, prefix)?;
+                let post_padding = self.padding(min - width, rt::v1::Alignment::Right)?;
+                self.buf.write_str(buf)?;
+                post_padding.write(self.buf)
             }
             // Otherwise, the sign and prefix goes after the padding
             Some(min) => {
-                self.with_padding(min - width, rt::v1::Alignment::Right, |f| {
-                    write_prefix(f)?; f.buf.write_str(buf)
-                })
+                let post_padding = self.padding(min - width, rt::v1::Alignment::Right)?;
+                write_prefix(self, sign, prefix)?;
+                self.buf.write_str(buf)?;
+                post_padding.write(self.buf)
             }
         }
     }
@@ -1264,19 +1294,21 @@ impl<'a> Formatter<'a> {
             // up the minimum width with the specified string + some alignment.
             Some(width) => {
                 let align = rt::v1::Alignment::Left;
-                self.with_padding(width - s.chars().count(), align, |me| {
-                    me.buf.write_str(s)
-                })
+                let post_padding = self.padding(width - s.chars().count(), align)?;
+                self.buf.write_str(s)?;
+                post_padding.write(self.buf)
             }
         }
     }
 
-    /// Runs a callback, emitting the correct padding either before or
-    /// afterwards depending on whether right or left alignment is requested.
-    fn with_padding<F>(&mut self, padding: usize, default: rt::v1::Alignment,
-                       f: F) -> Result
-        where F: FnOnce(&mut Formatter) -> Result,
-    {
+    /// Write the pre-padding and return the unwritten post-padding. Callers are
+    /// responsible for ensuring post-padding is written after the thing that is
+    /// being padded.
+    fn padding(
+        &mut self,
+        padding: usize,
+        default: rt::v1::Alignment
+    ) -> result::Result<PostPadding, Error> {
         let align = match self.align {
             rt::v1::Alignment::Unknown => default,
             _ => self.align
@@ -1289,20 +1321,11 @@ impl<'a> Formatter<'a> {
             rt::v1::Alignment::Center => (padding / 2, (padding + 1) / 2),
         };
 
-        let mut fill = [0; 4];
-        let fill = self.fill.encode_utf8(&mut fill);
-
         for _ in 0..pre_pad {
-            self.buf.write_str(fill)?;
-        }
-
-        f(self)?;
-
-        for _ in 0..post_pad {
-            self.buf.write_str(fill)?;
+            self.buf.write_char(self.fill)?;
         }
 
-        Ok(())
+        Ok(PostPadding::new(self.fill, post_pad))
     }
 
     /// Takes the formatted parts and applies the padding.
@@ -1334,9 +1357,9 @@ impl<'a> Formatter<'a> {
             let ret = if width <= len { // no padding
                 self.write_formatted_parts(&formatted)
             } else {
-                self.with_padding(width - len, align, |f| {
-                    f.write_formatted_parts(&formatted)
-                })
+                let post_padding = self.padding(width - len, align)?;
+                self.write_formatted_parts(&formatted)?;
+                post_padding.write(self.buf)
             };
             self.fill = old_fill;
             self.align = old_align;
diff --git a/src/libcore/fmt/num.rs b/src/libcore/fmt/num.rs
index 3a812337bb111..b9fa364037108 100644
--- a/src/libcore/fmt/num.rs
+++ b/src/libcore/fmt/num.rs
@@ -178,7 +178,8 @@ integer! { i32, u32 }
 integer! { i64, u64 }
 integer! { i128, u128 }
 
-const DEC_DIGITS_LUT: &'static[u8] =
+
+static DEC_DIGITS_LUT: &[u8; 200] =
     b"0001020304050607080910111213141516171819\
       2021222324252627282930313233343536373839\
       4041424344454647484950515253545556575859\
@@ -186,18 +187,8 @@ const DEC_DIGITS_LUT: &'static[u8] =
       8081828384858687888990919293949596979899";
 
 macro_rules! impl_Display {
-    ($($t:ident),*: $conv_fn:ident) => ($(
-    #[stable(feature = "rust1", since = "1.0.0")]
-    impl fmt::Display for $t {
-        #[allow(unused_comparisons)]
-        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-            let is_nonnegative = *self >= 0;
-            let mut n = if is_nonnegative {
-                self.$conv_fn()
-            } else {
-                // convert the negative num to positive by summing 1 to it's 2 complement
-                (!self.$conv_fn()).wrapping_add(1)
-            };
+    ($($t:ident),* as $u:ident via $conv_fn:ident named $name:ident) => {
+        fn $name(mut n: $u, is_nonnegative: bool, f: &mut fmt::Formatter) -> fmt::Result {
             let mut buf = uninitialized_array![u8; 39];
             let mut curr = buf.len() as isize;
             let buf_ptr = MaybeUninit::first_ptr_mut(&mut buf);
@@ -205,18 +196,18 @@ macro_rules! impl_Display {
 
             unsafe {
                 // need at least 16 bits for the 4-characters-at-a-time to work.
-                if ::mem::size_of::<$t>() >= 2 {
-                    // eagerly decode 4 characters at a time
-                    while n >= 10000 {
-                        let rem = (n % 10000) as isize;
-                        n /= 10000;
-
-                        let d1 = (rem / 100) << 1;
-                        let d2 = (rem % 100) << 1;
-                        curr -= 4;
-                        ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2);
-                        ptr::copy_nonoverlapping(lut_ptr.offset(d2), buf_ptr.offset(curr + 2), 2);
-                    }
+                assert!(::mem::size_of::<$u>() >= 2);
+
+                // eagerly decode 4 characters at a time
+                while n >= 10000 {
+                    let rem = (n % 10000) as isize;
+                    n /= 10000;
+
+                    let d1 = (rem / 100) << 1;
+                    let d2 = (rem % 100) << 1;
+                    curr -= 4;
+                    ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2);
+                    ptr::copy_nonoverlapping(lut_ptr.offset(d2), buf_ptr.offset(curr + 2), 2);
                 }
 
                 // if we reach here numbers are <= 9999, so at most 4 chars long
@@ -247,15 +238,41 @@ macro_rules! impl_Display {
             };
             f.pad_integral(is_nonnegative, "", buf_slice)
         }
-    })*);
+
+        $(
+            #[stable(feature = "rust1", since = "1.0.0")]
+            impl fmt::Display for $t {
+                #[allow(unused_comparisons)]
+                fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+                    let is_nonnegative = *self >= 0;
+                    let n = if is_nonnegative {
+                        self.$conv_fn()
+                    } else {
+                        // convert the negative num to positive by summing 1 to it's 2 complement
+                        (!self.$conv_fn()).wrapping_add(1)
+                    };
+                    $name(n, is_nonnegative, f)
+                }
+            })*
+    };
+}
+
+// Include wasm32 in here since it doesn't reflect the native pointer size, and
+// often cares strongly about getting a smaller code size.
+#[cfg(any(target_pointer_width = "64", target_arch = "wasm32"))]
+mod imp {
+    use super::*;
+    impl_Display!(
+        i8, u8, i16, u16, i32, u32, i64, u64, usize, isize
+            as u64 via to_u64 named fmt_u64
+    );
+}
+
+#[cfg(not(any(target_pointer_width = "64", target_arch = "wasm32")))]
+mod imp {
+    use super::*;
+    impl_Display!(i8, u8, i16, u16, i32, u32, isize, usize as u32 via to_u32 named fmt_u32);
+    impl_Display!(i64, u64 as u64 via to_u64 named fmt_u64);
 }
 
-impl_Display!(i8, u8, i16, u16, i32, u32: to_u32);
-impl_Display!(i64, u64: to_u64);
-impl_Display!(i128, u128: to_u128);
-#[cfg(target_pointer_width = "16")]
-impl_Display!(isize, usize: to_u16);
-#[cfg(target_pointer_width = "32")]
-impl_Display!(isize, usize: to_u32);
-#[cfg(target_pointer_width = "64")]
-impl_Display!(isize, usize: to_u64);
+impl_Display!(i128, u128 as u128 via to_u128 named fmt_u128);
diff --git a/src/test/run-make/wasm-stringify-ints-small/Makefile b/src/test/run-make/wasm-stringify-ints-small/Makefile
new file mode 100644
index 0000000000000..26de6a0c68990
--- /dev/null
+++ b/src/test/run-make/wasm-stringify-ints-small/Makefile
@@ -0,0 +1,10 @@
+-include ../../run-make-fulldeps/tools.mk
+
+ifeq ($(TARGET),wasm32-unknown-unknown)
+all:
+	$(RUSTC) foo.rs -C lto -O --target wasm32-unknown-unknown
+	wc -c < $(TMPDIR)/foo.wasm
+	[ "`wc -c < $(TMPDIR)/foo.wasm`" -lt "20500" ]
+else
+all:
+endif
diff --git a/src/test/run-make/wasm-stringify-ints-small/foo.rs b/src/test/run-make/wasm-stringify-ints-small/foo.rs
new file mode 100644
index 0000000000000..7a947f013ad48
--- /dev/null
+++ b/src/test/run-make/wasm-stringify-ints-small/foo.rs
@@ -0,0 +1,33 @@
+#![crate_type = "cdylib"]
+
+extern "C" {
+    fn observe(ptr: *const u8, len: usize);
+}
+
+macro_rules! s {
+    ( $( $f:ident -> $t:ty );* $(;)* ) => {
+        $(
+            extern "C" {
+                fn $f() -> $t;
+            }
+            let s = $f().to_string();
+            observe(s.as_ptr(), s.len());
+        )*
+    };
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn foo() {
+    s! {
+        get_u8 -> u8;
+        get_i8 -> i8;
+        get_u16 -> u16;
+        get_i16 -> i16;
+        get_u32 -> u32;
+        get_i32 -> i32;
+        get_u64 -> u64;
+        get_i64 -> i64;
+        get_usize -> usize;
+        get_isize -> isize;
+    }
+}