Write documentation for EM_JS (#6506)

diff --git a/site/source/docs/api_reference/emscripten.h.rst b/site/source/docs/api_reference/emscripten.h.rst
index 5337729..494701f 100644
--- a/site/source/docs/api_reference/emscripten.h.rst
+++ b/site/source/docs/api_reference/emscripten.h.rst
@@ -22,6 +22,91 @@
 Defines
 -------
 
+.. c:macro:: EM_JS(return_type, function_name, arguments, code)
+
+	Convenient syntax for JavaScript library functions.
+
+	This allows you to declare JavaScript in your C code as a function, which can
+	be called like a normal C function. For example, the following C program would
+	display two alerts if it was compiled with Emscripten and run in the browser: ::
+		EM_JS(void, two_alerts, (), {
+		  alert('hai');
+		  alert('bai');
+		});
+
+		int main() {
+		  two_alerts();
+		  return 0;
+		}
+
+	Arguments can be passed as normal C arguments, and have the same name in the
+	JavaScript code. These arguments can either be of type ``int32_t`` or
+	``double``. ::
+		EM_JS(void, take_args, (int x, float y), {
+		  console.log('I received: ' + [x, y]);
+		});
+
+		int main() {
+		  take_args(100, 35.5);
+		  return 0;
+		}
+
+	Null-terminated C strings can also be passed into ``EM_JS`` functions, but to
+	operate on them, they need to be copied out from the heap to convert to
+	high-level JavaScript strings. ::
+		EM_JS(void, say_hello, (const char* str), {
+		  console.log('hello ' + UTF8ToString(str));
+		}
+
+	In the same manner, pointers to any type (including ``void *``) can be passed
+	inside ``EM_JS`` code, where they appear as integers like ``char *`` pointers
+	above did. Accessing the data can be managed by reading the heap directly. ::
+		EM_JS(void, read_data, (int* data), {
+		  console.log('Data: ' + HEAP32[data>>2] + ', ' + HEAP32[(data+4)>>2]);
+		});
+
+		int main() {
+		  int arr[2] = { 30, 45 };
+		  read_data(arr);
+		  return 0;
+		}
+
+	In addition, EM_JS functions can return a value back to C code. The output
+	value is passed back with a ``return`` statement: ::
+		EM_JS(int, add_forty_two, (int n), {
+		  return n + 42;
+		});
+
+		EM_JS(int, get_total_memory, (), {
+		  return TOTAL_MEMORY;
+		});
+
+		int main() {
+		  int x = add_forty_two(100);
+		  int y = get_total_memory();
+		  // ...
+		}
+
+	Strings can be returned back to C from JavaScript, but one needs to be careful
+	about memory management. ::
+		EM_JS(const char*, get_unicode_str, (), {
+		  var jsString = 'Hello with some exotic Unicode characters: Tässä on yksi lumiukko: ☃, ole hyvä.';
+		  // 'jsString.length' would return the length of the string as UTF-16
+		  // units, but Emscripten C strings operate as UTF-8.
+		  var lengthBytes = lengthBytesUTF8(jsString)+1;
+		  var stringOnWasmHeap = _malloc(lengthBytes);
+		  stringToUTF8(jsString, stringOnWasmHeap, lengthBytes+1);
+		  return stringOnWasmHeap;
+		});
+
+		int main() {
+		  const char* str = get_unicode_str();
+		  printf("UTF8 string says: %s\n", str);
+		  // Each call to _malloc() must be paired with free(), or heap memory will leak!
+		  free(str);
+		  return 0;
+		}
+
 .. c:macro:: EM_ASM(...)
 
 	Convenient syntax for inline assembly/JavaScript.
diff --git a/site/source/docs/porting/connecting_cpp_and_javascript/Interacting-with-code.rst b/site/source/docs/porting/connecting_cpp_and_javascript/Interacting-with-code.rst
index 5df2811..ec987f2 100644
--- a/site/source/docs/porting/connecting_cpp_and_javascript/Interacting-with-code.rst
+++ b/site/source/docs/porting/connecting_cpp_and_javascript/Interacting-with-code.rst
@@ -21,6 +21,7 @@
 - Call JavaScript functions from **C/C++**:
 
   - :ref:`Using emscripten_run_script() <interacting-with-code-call-javascript-from-native>`.
+  - :ref:`Using EM_JS() <interacting-with-code-call-javascript-from-native>` (faster).
   - :ref:`Using EM_ASM() <interacting-with-code-call-javascript-from-native>` (faster).
   - :ref:`Using a C API implemented in JavaScript <implement-c-in-javascript>`.
   - :ref:`As function pointers from C <interacting-with-code-call-function-pointers-from-c>`.
@@ -257,9 +258,30 @@
 
 
 A faster way to call JavaScript from C is to write "inline JavaScript",
-using :c:func:`EM_ASM` (and related macros). These are used in a similar
-manner to inline assembly code. The "alert" example above might be
-written using inline JavaScript as:
+using :c:func:`EM_JS` or :c:func:`EM_ASM` (and related macros).
+
+EM_JS is used to declare JavaScript functions from inside a C file. The "alert"
+example might be written using EM_JS like:
+
+.. code-block:: c++
+
+   #include <emscripten.h>
+
+   EM_JS(void, call_alert, (), {
+     alert('hello world!');
+     throw 'all done';
+   });
+
+   int main() {
+     call_alert();
+     return 0;
+   }
+
+EM_JS's implementation is essentially a shorthand for :ref:`implementing a
+JavaScript library<implement-c-in-javascript>`.
+
+EM_ASM is used in a similar manner to inline assembly code. The "alert" example
+might be written with inline JavaScript as:
 
 .. code-block:: c++
 
diff --git a/tests/core/test_em_js.cpp b/tests/core/test_em_js.cpp
index 5590221..8d8cde4 100644
--- a/tests/core/test_em_js.cpp
+++ b/tests/core/test_em_js.cpp
@@ -41,6 +41,14 @@
   return 15;
 });
 
+EM_JS(const char*, return_str, (), {
+  var jsString = 'hello from js';
+  var lengthBytes = jsString.length+1;
+  var stringOnWasmHeap = _malloc(lengthBytes);
+  stringToUTF8(jsString, stringOnWasmHeap, lengthBytes+1);
+  return stringOnWasmHeap;
+});
+
 int main() {
   printf("BEGIN\n");
   noarg();
@@ -57,6 +65,8 @@
   printf("    add_outer returned: %f\n", add_outer(5.5, 7.0, 14.375));
   printf("    user_separator returned: %d\n", user_separator());
 
+  printf("    return_str returned: %s\n", return_str());
+
   printf("END\n");
   return 0;
 }
diff --git a/tests/core/test_em_js.out b/tests/core/test_em_js.out
index 253c68c..f35c436 100644
--- a/tests/core/test_em_js.out
+++ b/tests/core/test_em_js.out
@@ -20,4 +20,5 @@
     add_outer returned: 19.875000
   can use <::> separator in user code
     user_separator returned: 15
+    return_str returned: hello from js
 END