diff --git a/crates/wasm-bindgen-cli-support/src/js.rs b/crates/wasm-bindgen-cli-support/src/js.rs
index 4fb9b061..f48cbd01 100644
--- a/crates/wasm-bindgen-cli-support/src/js.rs
+++ b/crates/wasm-bindgen-cli-support/src/js.rs
@@ -536,6 +536,8 @@ impl<'a> Js<'a> {
             self.expose_get_object();
         }
 
+        let mut extra = String::new();
+
         for (i, arg) in import.arguments.iter().enumerate() {
             if invocation.len() > 0 {
                 invocation.push_str(", ");
@@ -557,6 +559,15 @@ impl<'a> Js<'a> {
                     invocation.push_str(&format!("getStringFromWasm(ptr{0}, len{0})", i));
                     dst.push_str(&format!("ptr{0}, len{0}", i));
                 }
+                shared::TYPE_STRING => {
+                    self.expose_get_string_from_wasm();
+                    dst.push_str(&format!("ptr{0}, len{0}", i));
+                    extra.push_str(&format!("
+                        let arg{0} = getStringFromWasm(ptr{0}, len{0});
+                        wasm.__wbindgen_free(ptr{0}, len{0});
+                    ", i));
+                    invocation.push_str(&format!("arg{}", i));
+                }
                 shared::TYPE_JS_OWNED => {
                     self.expose_take_object();
                     invocation.push_str(&format!("takeObject(arg{})", i));
@@ -572,20 +583,32 @@ impl<'a> Js<'a> {
                 }
             }
         }
-        dst.push_str(")");
         let invoc = format!("{}({})", shim_delegate, invocation);
         let invoc = match import.ret {
-            Some(shared::TYPE_NUMBER) => invoc,
-            Some(shared::TYPE_BOOLEAN) => format!("{} ? 1 : 0", invoc),
+            Some(shared::TYPE_NUMBER) => format!("return {};", invoc),
+            Some(shared::TYPE_BOOLEAN) => format!("return {} ? 1 : 0;", invoc),
             Some(shared::TYPE_JS_OWNED) => {
                 self.expose_add_heap_object();
-                format!("addHeapObject({})", invoc)
+                format!("return addHeapObject({});", invoc)
+            }
+            Some(shared::TYPE_STRING) => {
+                self.expose_pass_string_to_wasm();
+                if import.arguments.len() > 0 || is_method {
+                    dst.push_str(", ");
+                }
+                dst.push_str("wasmretptr");
+                format!("
+                    const [retptr, retlen] = passStringToWasm({});
+                    (new Uint32Array(wasm.memory.buffer))[wasmretptr / 4] = retlen;
+                    return retptr;
+                ", invoc)
             }
             None => invoc,
             _ => unimplemented!(),
         };
-        dst.push_str(" {\n");
-        dst.push_str(&format!("return {};\n}}", invoc));
+        dst.push_str(") {\n");
+        dst.push_str(&extra);
+        dst.push_str(&format!("{}\n}}", invoc));
 
         self.globals.push_str("export ");
         self.globals.push_str(&dst);
diff --git a/crates/wasm-bindgen-macro/src/lib.rs b/crates/wasm-bindgen-macro/src/lib.rs
index 7372bc5f..aa13a41b 100644
--- a/crates/wasm-bindgen-macro/src/lib.rs
+++ b/crates/wasm-bindgen-macro/src/lib.rs
@@ -583,15 +583,18 @@ fn bindgen_import_function(import: &ast::ImportFunction,
         // TODO: add a test for this
         Some(ast::Type::String) => {
             let name = syn::Ident::from("__ret_strlen");
-            abi_argument_names.push(name);
-            abi_arguments.push(my_quote! { #name: *mut usize });
+            let name_ptr = syn::Ident::from("__ret_strlen_ptr");
+            abi_argument_names.push(name_ptr);
+            abi_arguments.push(my_quote! { #name_ptr: *mut usize });
             arg_conversions.push(my_quote! {
                 let mut #name = 0;
+                let mut #name_ptr = &mut #name as *mut usize;
             });
-            abi_ret = my_quote! { *const u8 };
+            abi_ret = my_quote! { *mut u8 };
             convert_ret = my_quote! {
-                let __v = Vec::from_raw_parts(#ret_ident, #name, #name);
-                String::from_utf8_unchecked(__v)
+                String::from_utf8_unchecked(
+                    Vec::from_raw_parts(#ret_ident, #name, #name)
+                )
             };
         }
         Some(ast::Type::BorrowedStr) |
diff --git a/tests/imports.rs b/tests/imports.rs
index 545af4af..2ef9215d 100644
--- a/tests/imports.rs
+++ b/tests/imports.rs
@@ -107,3 +107,44 @@ fn unused() {
         "#)
         .test();
 }
+
+#[test]
+fn strings() {
+    test_support::project()
+        .file("src/lib.rs", r#"
+            #![feature(proc_macro)]
+
+            extern crate wasm_bindgen;
+
+            use wasm_bindgen::prelude::*;
+
+            wasm_bindgen! {
+                #[wasm_module = "./test"]
+                extern "JS" {
+                    fn foo(a: String) -> String;
+                }
+
+                pub fn bar(a: &str) -> String {
+                    foo(a.to_string())
+                }
+
+                pub fn bar2(a: String) -> String {
+                    foo(a)
+                }
+            }
+        "#)
+        .file("test.ts", r#"
+            import * as wasm from "./out";
+            import * as assert from "assert";
+
+            export function foo(a: string): string {
+                return a + 'b';
+            }
+
+            export function test() {
+                assert.strictEqual(wasm.bar('a'), 'ab');
+                assert.strictEqual(wasm.bar2('a'), 'ab');
+            }
+        "#)
+        .test();
+}