From 4c98f917e8f1f013469cda9ec84409e291ff280a Mon Sep 17 00:00:00 2001
From: Ryan Hunt <rhunt@eqrion.net>
Date: Tue, 6 Aug 2024 17:06:11 -0500
Subject: [PATCH 1/6] Initial outline of builtin support

---
 document/core/appendix/embedding.rst |  9 +++
 document/js-api/index.bs             | 82 ++++++++++++++++++++++++----
 document/web-api/index.bs            | 14 ++---
 3 files changed, 86 insertions(+), 19 deletions(-)

diff --git a/document/core/appendix/embedding.rst b/document/core/appendix/embedding.rst
index 737230ef..cccaa1eb 100644
--- a/document/core/appendix/embedding.rst
+++ b/document/core/appendix/embedding.rst
@@ -161,6 +161,15 @@ Modules
    \end{array}
 
 
+.. index:: validation
+.. _embed-module-module-validate-partial-imports:
+
+:math:`\F{module\_validate\_partial\_imports}(\module, \imports) : \error^?`
+................................................
+
+// TODO
+1. Return :math:`\ERROR`.
+
 .. index:: instantiation, module instance
 .. _embed-module-instantiate:
 
diff --git a/document/js-api/index.bs b/document/js-api/index.bs
index b666ef07..1117026f 100644
--- a/document/js-api/index.bs
+++ b/document/js-api/index.bs
@@ -93,6 +93,7 @@ urlPrefix: https://webassembly.github.io/spec/core/; spec: WebAssembly; type: df
     text: store_init; url: appendix/embedding.html#embed-store-init
     text: module_decode; url: appendix/embedding.html#embed-module-decode
     text: module_validate; url: appendix/embedding.html#embed-module-validate
+    text: module_validate_partial_imports; url: appendix/embedding.html#embed-module-validate-partial-imports
     text: module_instantiate; url: appendix/embedding.html#embed-module-instantiate
     text: module_imports; url: appendix/embedding.html#embed-module-imports
     text: module_exports; url: appendix/embedding.html#embed-module-exports
@@ -302,13 +303,18 @@ dictionary WebAssemblyInstantiatedSource {
     required Instance instance;
 };
 
+dictionary WebAssemblyCompileOptions {
+    USVString? importedStringConstants;
+    sequence&lt;USVString> builtins;
+};
+
 [Exposed=*]
 namespace WebAssembly {
-    boolean validate(BufferSource bytes);
-    Promise&lt;Module> compile(BufferSource bytes);
+    boolean validate(BufferSource bytes, optional WebAssemblyCompileOptions options);
+    Promise&lt;Module> compile(BufferSource bytes, optional WebAssemblyCompileOptions options);
 
     Promise&lt;WebAssemblyInstantiatedSource> instantiate(
-        BufferSource bytes, optional object importObject);
+        BufferSource bytes, optional object importObject, optional WebAssemblyCompileOptions options);
 
     Promise&lt;Instance> instantiate(
         Module moduleObject, optional object importObject);
@@ -335,10 +341,21 @@ Note:
 </div>
 
 <div algorithm>
-  The <dfn method for="WebAssembly">validate(|bytes|)</dfn> method, when invoked, performs the following steps:
+  To <dfn>Validate builtins for WebAssembly module</dfn> from module |module| and enabled builtins |builtins|, perform the following steps:
+    1. Let |store| be the [=surrounding agent=]'s [=associated store=].
+    1. Let |imports| be ... // TODO: create imports from a builtin set name
+    1. Let |result| be [=module_validate_partial_imports=](|store|, |module|, |imports|).
+    1. If |result| is [=error=], return [=error=].
+    1. Return true.
+</div>
+
+<div algorithm>
+  The <dfn method for="WebAssembly">validate(|bytes|, |options|)</dfn> method, when invoked, performs the following steps:
     1. Let |stableBytes| be a [=get a copy of the buffer source|copy of the bytes held by the buffer=] |bytes|.
     1. [=Compile a WebAssembly module|Compile=] |stableBytes| as a WebAssembly module and store the results as |module|.
     1. If |module| is [=error=], return false.
+    1. Let |builtins| be options["builtins"]
+    1. If [=Validate builtins for WebAssembly module=] |module| |builtins| is [=error=], return false.
     1. Return true.
 </div>
 
@@ -346,41 +363,47 @@ A {{Module}} object represents a single WebAssembly module. Each {{Module}} obje
 
     * \[[Module]] : a WebAssembly [=/module=]
     * \[[Bytes]] : the source bytes of \[[Module]].
+    * \[[Builtins]] : an ordered set of names of <a href="#builtins">builtin sets</a>
 
 <div algorithm>
-  To <dfn>construct a WebAssembly module object</dfn> from a module |module| and source bytes |bytes|, perform the following steps:
+  To <dfn>construct a WebAssembly module object</dfn> from a module |module|, source bytes |bytes|, builtins |builtins|, perform the following steps:
 
     1. Let |moduleObject| be a new {{Module}} object.
     1. Set |moduleObject|.\[[Module]] to |module|.
     1. Set |moduleObject|.\[[Bytes]] to |bytes|.
+    1. Set |moduleObject|.\[[Builtins]] to |builtins|.
     1. Return |moduleObject|.
 </div>
 
 <div algorithm>
-  To <dfn>asynchronously compile a WebAssembly module</dfn> from source bytes |bytes|, using optional [=task source=] |taskSource|, perform the following steps:
+  To <dfn>asynchronously compile a WebAssembly module</dfn> from source bytes |bytes| and {{WebAssemblyCompileOptions}} |options| using optional [=task source=] |taskSource|, perform the following steps:
 
     1. Let |promise| be [=a new promise=].
     1. Run the following steps [=in parallel=]:
         1. [=compile a WebAssembly module|Compile the WebAssembly module=] |bytes| and store the result as |module|.
         1. [=Queue a task=] to perform the following steps. If |taskSource| was provided, queue the task on that task source.
             1. If |module| is [=error=], reject |promise| with a {{CompileError}} exception.
+            1. Let |builtins| be options["builtins"]
+            1. If [=Validate builtins for WebAssembly module=] |module| |builtins| is [=error=], reject |promise| with a {{CompileError}} exception.
             1. Otherwise,
-                1. [=Construct a WebAssembly module object=] from |module| and |bytes|, and let |moduleObject| be the result.
+                1. [=Construct a WebAssembly module object=] from |module|, |bytes|, |builtins|, and let |moduleObject| be the result.
                 1. [=Resolve=] |promise| with |moduleObject|.
     1. Return |promise|.
 </div>
 
 <div algorithm>
-    The <dfn method for="WebAssembly">compile(|bytes|)</dfn> method, when invoked, performs the following steps:
+    The <dfn method for="WebAssembly">compile(|bytes|, |options|)</dfn> method, when invoked, performs the following steps:
     1. Let |stableBytes| be a [=get a copy of the buffer source|copy of the bytes held by the buffer=] |bytes|.
-    1. [=Asynchronously compile a WebAssembly module=] from |stableBytes| and return the result.
+    1. [=Asynchronously compile a WebAssembly module=] from |stableBytes| using |options| and return the result.
 </div>
 
 <div algorithm="read-the-imports">
   To <dfn>read the imports</dfn> from a WebAssembly module |module| from imports object |importObject|, perform the following steps:
     1. If |module|.[=imports=] [=list/is empty|is not empty=], and |importObject| is undefined, throw a {{TypeError}} exception.
+        // TODO: instantiate builtin sets
     1. Let |imports| be « ».
     1. [=list/iterate|For each=] (|moduleName|, |componentName|, |externtype|) of [=module_imports=](|module|),
+        // TODO: get exports from a builtin set if enabled
         1. Let |o| be [=?=] [$Get$](|importObject|, |moduleName|).
         1. If [=Type=](|o|) is not Object, throw a {{TypeError}} exception.
         1. Let |v| be [=?=] [$Get$](|o|, |componentName|).
@@ -527,9 +550,9 @@ The verification of WebAssembly type requirements is deferred to the
 </div>
 
 <div algorithm>
-  The <dfn method for="WebAssembly">instantiate(|bytes|, |importObject|)</dfn> method, when invoked, performs the following steps:
+  The <dfn method for="WebAssembly">instantiate(|bytes|, |importObject|, |options|)</dfn> method, when invoked, performs the following steps:
     1. Let |stableBytes| be a [=get a copy of the buffer source|copy of the bytes held by the buffer=] |bytes|.
-    1. [=Asynchronously compile a WebAssembly module=] from |stableBytes| and let |promiseOfModule| be the result.
+    1. [=Asynchronously compile a WebAssembly module=] from |stableBytes| using |options| and let |promiseOfModule| be the result.
     1. [=Instantiate a promise of a module|Instantiate=] |promiseOfModule| with imports |importObject| and return the result.
 </div>
 
@@ -570,7 +593,7 @@ dictionary ModuleImportDescriptor {
 
 [LegacyNamespace=WebAssembly, Exposed=*]
 interface Module {
-  constructor(BufferSource bytes);
+  constructor(BufferSource bytes, optional WebAssemblyCompileOptions options);
   static sequence&lt;ModuleExportDescriptor> exports(Module moduleObject);
   static sequence&lt;ModuleImportDescriptor> imports(Module moduleObject);
   static sequence&lt;ArrayBuffer> customSections(Module moduleObject, DOMString sectionName);
@@ -602,6 +625,7 @@ interface Module {
     1. Let |module| be |moduleObject|.\[[Module]].
     1. Let |imports| be « ».
     1. [=list/iterate|For each=] (|moduleName|, |name|, |type|) of [=module_imports=](|module|),
+        // TODO: skip import if in builtin module set
         1. Let |kind| be the [=string value of the extern type=] |type|.
         1. Let |obj| be «[ "{{ModuleImportDescriptor/module}}" → |moduleName|, "{{ModuleImportDescriptor/name}}" → |name|, "{{ModuleImportDescriptor/kind}}" → |kind| ]».
         1. [=list/Append=] |obj| to |imports|.
@@ -1646,6 +1670,40 @@ They expose the same interface as native JavaScript errors like {{TypeError}} an
 Note: It is not currently possible to define this behavior using Web IDL.
 
 
+<h2 id="builtins">Builtins</h2>
+
+The JS-API defines sets of builtin functions which can be imported through a flag when compiling a module. WebAssembly builtin functions mirror existing JavaScript builtins, but adapt them to be useable directly as WebAssembly functions.
+
+All builtin functions are grouped into builtin sets. Every builtin set has a name that [=read the imports|is used during import lookup=]. All names are prefixed by the `wasm:` namespace.
+
+
+<h3 id="builtins-js-string">String Builtins</h3>
+
+String builtins adapt the interface of the String builtin object. The import name for this set is `wasm:js-string`.
+
+<div algorithm="js-string-unwrapString">
+
+The <dfn>unwrapString(|v|)</dfn> method, when invoked, performs the following steps:
+
+1. If [=Type=](|v|) is not String
+    1. Throw a {{RuntimeError}} exception. TODO: this needs to not be catchable, like a trap.
+1. Return |v|
+
+</div>
+
+<h4 id="js-string-charCodeAt">charCodeAt</h4>
+
+The type of this function is `(func (param externref i32) (result i32))`.
+
+<div algorithm="js-string-charCodeAt">
+When this builtin is invoked, the following steps must be run:
+
+1. Let |string| be [$unwrapString$](param0)
+1. TODO
+
+</div>
+
+
 <h2 id="errors">Error Condition Mappings to JavaScript</h2>
 
 Running WebAssembly programs encounter certain events which halt execution of the WebAssembly code.
diff --git a/document/web-api/index.bs b/document/web-api/index.bs
index efc6a666..4439fbb5 100644
--- a/document/web-api/index.bs
+++ b/document/web-api/index.bs
@@ -89,25 +89,25 @@ This document builds off of the WebAssembly specification [[WEBASSEMBLY]] and th
 <pre class="idl">
 [Exposed=(Window,Worker)]
 partial namespace WebAssembly {
-  Promise&lt;Module> compileStreaming(Promise&lt;Response> source);
+  Promise&lt;Module> compileStreaming(Promise&lt;Response> source, optional WebAssemblyCompileOptions options);
   Promise&lt;WebAssemblyInstantiatedSource> instantiateStreaming(
-      Promise&lt;Response> source, optional object importObject);
+      Promise&lt;Response> source, optional object importObject, optional WebAssemblyCompileOptions options);
 };
 </pre>
 
 <div algorithm>
-The <dfn method for="WebAssembly">compileStreaming(|source|)</dfn> method, when invoked, returns the result of [=compile a potential WebAssembly response|compiling a potential WebAssembly response=] with |source|.
+The <dfn method for="WebAssembly">compileStreaming(|source|, |options|)</dfn> method, when invoked, returns the result of [=compile a potential WebAssembly response|compiling a potential WebAssembly response=] with |source| using |options|.
 </div>
 
 <div algorithm>
-The <dfn method for="WebAssembly">instantiateStreaming(|source|, |importObject|)</dfn> method, when invoked, performs the following steps:
+The <dfn method for="WebAssembly">instantiateStreaming(|source|, |importObject|, |options|)</dfn> method, when invoked, performs the following steps:
 
-    1. Let |promiseOfModule| be the result of [=compile a potential WebAssembly response|compiling a potential WebAssembly response=] with |source|.
+    1. Let |promiseOfModule| be the result of [=compile a potential WebAssembly response|compiling a potential WebAssembly response=] with |source| using |options|.
     1. Return the result of [=instantiate a promise of a module|instantiating the promise of a module=] |promiseOfModule| with imports |importObject|.
 </div>
 
 <div algorithm>
-To <dfn>compile a potential WebAssembly response</dfn> with a promise of a {{Response}} |source|, perform the following steps:
+To <dfn>compile a potential WebAssembly response</dfn> with a promise of a {{Response}} |source| and {{WebAssemblyCompileOptions}} |options|, perform the following steps:
 
 Note: This algorithm accepts a {{Response}} object, or a
     promise for one, and compiles and instantiates the resulting bytes of the response. This compilation
@@ -136,7 +136,7 @@ Note: This algorithm accepts a {{Response}} object, or a
 
         1. [=Upon fulfillment=] of |bodyPromise| with value |bodyArrayBuffer|:
             1. Let |stableBytes| be a [=get a copy of the buffer source|copy of the bytes held by the buffer=] |bodyArrayBuffer|.
-            1. [=Asynchronously compile a WebAssembly module|Asynchronously compile the WebAssembly module=] |stableBytes| using the [=networking task source=] and [=resolve=] |returnValue| with the result.
+            1. [=Asynchronously compile a WebAssembly module|Asynchronously compile the WebAssembly module=] |stableBytes| using the [=networking task source=] and |options| and [=resolve=] |returnValue| with the result.
         1. [=Upon rejection=] of |bodyPromise| with reason |reason|:
             1. [=Reject=] |returnValue| with |reason|.
      1. [=Upon rejection=] of |source| with reason |reason|:

From 8deb337cd8b18100ea761a4ae676158585a7214c Mon Sep 17 00:00:00 2001
From: Ryan Hunt <rhunt@eqrion.net>
Date: Wed, 7 Aug 2024 13:19:08 -0500
Subject: [PATCH 2/6] Expand specification of builtins

---
 document/js-api/index.bs | 134 +++++++++++++++++++++++++++++++--------
 1 file changed, 108 insertions(+), 26 deletions(-)

diff --git a/document/js-api/index.bs b/document/js-api/index.bs
index 1117026f..50740dfb 100644
--- a/document/js-api/index.bs
+++ b/document/js-api/index.bs
@@ -93,7 +93,6 @@ urlPrefix: https://webassembly.github.io/spec/core/; spec: WebAssembly; type: df
     text: store_init; url: appendix/embedding.html#embed-store-init
     text: module_decode; url: appendix/embedding.html#embed-module-decode
     text: module_validate; url: appendix/embedding.html#embed-module-validate
-    text: module_validate_partial_imports; url: appendix/embedding.html#embed-module-validate-partial-imports
     text: module_instantiate; url: appendix/embedding.html#embed-module-instantiate
     text: module_imports; url: appendix/embedding.html#embed-module-imports
     text: module_exports; url: appendix/embedding.html#embed-module-exports
@@ -120,6 +119,7 @@ urlPrefix: https://webassembly.github.io/spec/core/; spec: WebAssembly; type: df
     text: ref_type; url: appendix/embedding.html#embed-ref-type
     text: val_default; url: appendix/embedding.html#embed-val-default
     text: match_valtype; url: appendix/embedding.html#embed-match-valtype
+    text: match_externtype; url: appendix/embedding.html#embed-match-externtype
     text: error; url: appendix/embedding.html#embed-error
     text: store; url: exec/runtime.html#syntax-store
     text: table type; url: syntax/types.html#syntax-tabletype
@@ -341,11 +341,10 @@ Note:
 </div>
 
 <div algorithm>
-  To <dfn>Validate builtins for WebAssembly module</dfn> from module |module| and enabled builtins |builtins|, perform the following steps:
-    1. Let |store| be the [=surrounding agent=]'s [=associated store=].
-    1. Let |imports| be ... // TODO: create imports from a builtin set name
-    1. Let |result| be [=module_validate_partial_imports=](|store|, |module|, |imports|).
-    1. If |result| is [=error=], return [=error=].
+  To <dfn>validate builtins for a WebAssembly module</dfn> from module |module| and enabled builtins |builtinSetNames|, perform the following steps:
+    1. If [=validate builtin set names|validating builtin set names=] for |builtinSetNames| is false, return false.
+    1. [=list/iterate|For each=] |import| of [=module_imports=](|module|),
+        1. If [=validate an import for builtins|validating a import for builtin=] with |import| and |builtinSetNames| is false, return false.
     1. Return true.
 </div>
 
@@ -354,8 +353,8 @@ Note:
     1. Let |stableBytes| be a [=get a copy of the buffer source|copy of the bytes held by the buffer=] |bytes|.
     1. [=Compile a WebAssembly module|Compile=] |stableBytes| as a WebAssembly module and store the results as |module|.
     1. If |module| is [=error=], return false.
-    1. Let |builtins| be options["builtins"]
-    1. If [=Validate builtins for WebAssembly module=] |module| |builtins| is [=error=], return false.
+    1. Let |builtinSetNames| be options["builtins"]
+    1. If [=validate builtins for a WebAssembly module|validating builtins for WebAssembly module=] |module| with |builtinSetNames| returns false, return false.
     1. Return true.
 </div>
 
@@ -363,15 +362,15 @@ A {{Module}} object represents a single WebAssembly module. Each {{Module}} obje
 
     * \[[Module]] : a WebAssembly [=/module=]
     * \[[Bytes]] : the source bytes of \[[Module]].
-    * \[[Builtins]] : an ordered set of names of <a href="#builtins">builtin sets</a>
+    * \[[BuiltinSets]] : an ordered set of names of <a href="#builtins">builtin sets</a>
 
 <div algorithm>
-  To <dfn>construct a WebAssembly module object</dfn> from a module |module|, source bytes |bytes|, builtins |builtins|, perform the following steps:
+  To <dfn>construct a WebAssembly module object</dfn> from a module |module|, source bytes |bytes|, enabled builtins |builtinSetNames|, perform the following steps:
 
     1. Let |moduleObject| be a new {{Module}} object.
     1. Set |moduleObject|.\[[Module]] to |module|.
     1. Set |moduleObject|.\[[Bytes]] to |bytes|.
-    1. Set |moduleObject|.\[[Builtins]] to |builtins|.
+    1. Set |moduleObject|.\[[BuiltinSets]] to |builtinSetNames|.
     1. Return |moduleObject|.
 </div>
 
@@ -383,10 +382,10 @@ A {{Module}} object represents a single WebAssembly module. Each {{Module}} obje
         1. [=compile a WebAssembly module|Compile the WebAssembly module=] |bytes| and store the result as |module|.
         1. [=Queue a task=] to perform the following steps. If |taskSource| was provided, queue the task on that task source.
             1. If |module| is [=error=], reject |promise| with a {{CompileError}} exception.
-            1. Let |builtins| be options["builtins"]
-            1. If [=Validate builtins for WebAssembly module=] |module| |builtins| is [=error=], reject |promise| with a {{CompileError}} exception.
+            1. Let |builtinSetNames| be options["builtins"]
+            1. If [=validate builtins for a WebAssembly module|validating builtins=] for |module| |builtinSetNames| is false, reject |promise| with a {{CompileError}} exception.
             1. Otherwise,
-                1. [=Construct a WebAssembly module object=] from |module|, |bytes|, |builtins|, and let |moduleObject| be the result.
+                1. [=Construct a WebAssembly module object=] from |module|, |bytes|, |builtinSetNames|, and let |moduleObject| be the result.
                 1. [=Resolve=] |promise| with |moduleObject|.
     1. Return |promise|.
 </div>
@@ -398,13 +397,19 @@ A {{Module}} object represents a single WebAssembly module. Each {{Module}} obje
 </div>
 
 <div algorithm="read-the-imports">
-  To <dfn>read the imports</dfn> from a WebAssembly module |module| from imports object |importObject|, perform the following steps:
+  To <dfn>read the imports</dfn> from a WebAssembly module |module| from imports object |importObject| and enabled builtins |builtinSetNames|, perform the following steps:
     1. If |module|.[=imports=] [=list/is empty|is not empty=], and |importObject| is undefined, throw a {{TypeError}} exception.
-        // TODO: instantiate builtin sets
+    1. Let |instantiatedBuiltins| be the ordered map « ».
+    1. [=list/iterate|For each=] |builtinSetName| of |builtinSetNames|,
+        1. Assert: |instantiatedBuiltins| does not contain |builtinSetName|
+        1. Let |exportsObject| be the result of [=instantiate a builtin set=] with |builtinSetName|
+        1. [=map/set|Set=] |instantiatedBuiltins|[|builtinSetName|] to |exportsObject|
     1. Let |imports| be « ».
     1. [=list/iterate|For each=] (|moduleName|, |componentName|, |externtype|) of [=module_imports=](|module|),
-        // TODO: get exports from a builtin set if enabled
-        1. Let |o| be [=?=] [$Get$](|importObject|, |moduleName|).
+        1. If |instantiatedBuiltins| [=map/exist|contains=] |moduleName|,
+            1. Let |o| be |instantiatedBuiltins|[|moduleName|]
+        1. Else,
+            1. Let |o| be [=?=] [$Get$](|importObject|, |moduleName|).
         1. If [=Type=](|o|) is not Object, throw a {{TypeError}} exception.
         1. Let |v| be [=?=] [$Get$](|o|, |componentName|).
         1. If |externtype| is of the form [=external-type/func=] |functype|,
@@ -519,7 +524,8 @@ The verification of WebAssembly type requirements is deferred to the
   To <dfn>asynchronously instantiate a WebAssembly module</dfn> from a {{Module}} |moduleObject| and imports |importObject|, perform the following steps:
     1. Let |promise| be [=a new promise=].
     1. Let |module| be |moduleObject|.\[[Module]].
-    1. [=Read the imports=] of |module| with imports |importObject|, and let |imports| be the result.
+    1. Let |builtinSetNames| be |moduleObject|.\[[BuiltinSets]].
+    1. [=Read the imports=] of |module| with imports |importObject| and |builtinSetNames|, and let |imports| be the result.
         If this operation throws an exception, catch it, [=reject=] |promise| with the exception, and return |promise|.
     1. Run the following steps [=in parallel=]:
         1. [=Queue a task=] to perform the following steps:
@@ -623,12 +629,13 @@ interface Module {
 <div algorithm>
     The <dfn method for="Module">imports(|moduleObject|)</dfn> method, when invoked, performs the following steps:
     1. Let |module| be |moduleObject|.\[[Module]].
+    1. Let |builtinSetNames| be |moduleObject|.\[[BuiltinSets]].
     1. Let |imports| be « ».
     1. [=list/iterate|For each=] (|moduleName|, |name|, |type|) of [=module_imports=](|module|),
-        // TODO: skip import if in builtin module set
-        1. Let |kind| be the [=string value of the extern type=] |type|.
-        1. Let |obj| be «[ "{{ModuleImportDescriptor/module}}" → |moduleName|, "{{ModuleImportDescriptor/name}}" → |name|, "{{ModuleImportDescriptor/kind}}" → |kind| ]».
-        1. [=list/Append=] |obj| to |imports|.
+        1. If [=find a builtin=] for (|moduleName|, |name|, |type|) and |builtinSetNames| is null,
+            1. Let |kind| be the [=string value of the extern type=] |type|.
+            1. Let |obj| be «[ "{{ModuleImportDescriptor/module}}" → |moduleName|, "{{ModuleImportDescriptor/name}}" → |name|, "{{ModuleImportDescriptor/kind}}" → |kind| ]».
+            1. [=list/Append=] |obj| to |imports|.
     1. Return |imports|.
 </div>
 
@@ -669,7 +676,8 @@ interface Instance {
 <div algorithm>
   The <dfn constructor for="Instance">Instance(|module|, |importObject|)</dfn> constructor, when invoked, runs the following steps:
     1. Let |module| be |module|.\[[Module]].
-    1. [=Read the imports=] of |module| with imports |importObject|, and let |imports| be the result.
+    1. Let |builtinSetNames| be |module|.\[[BuiltinSets]].
+    1. [=Read the imports=] of |module| with imports |importObject| and |builtinSetNames|, and let |imports| be the result.
     1. [=Instantiate the core of a WebAssembly module=] |module| with |imports|, and let |instance| be the result.
     1. [=initialize an instance object|Initialize=] **this** from |module| and |instance|.
 
@@ -1672,9 +1680,83 @@ Note: It is not currently possible to define this behavior using Web IDL.
 
 <h2 id="builtins">Builtins</h2>
 
-The JS-API defines sets of builtin functions which can be imported through a flag when compiling a module. WebAssembly builtin functions mirror existing JavaScript builtins, but adapt them to be useable directly as WebAssembly functions.
+The JS-API defines sets of builtin functions which can be imported through {{WebAssemblyCompileOptions|options}} when compiling a module. WebAssembly builtin functions mirror existing JavaScript builtins, but adapt them to be useable directly as WebAssembly functions with minimal overhead.
+
+All builtin functions are grouped into sets. Every builtin set has a unique name that [=read the imports|is used during import lookup=]. All names are prefixed by the `wasm:` namespace (e.g. `wasm:js-string`).
+
+<div algorithm>
+To <dfn>get the builtins for a builtin set</dfn> with |builtinSetName|, perform the following steps:
+
+1. Return a list of (|name|, |funcType|, |steps|) for the set with name |builtinSetName| defined within this section.
+
+</div>
+
+<div algorithm>
+To <dfn>find a builtin</dfn> with |import| and enabled builtins |builtinSetNames|, perform the following steps:
 
-All builtin functions are grouped into builtin sets. Every builtin set has a name that [=read the imports|is used during import lookup=]. All names are prefixed by the `wasm:` namespace.
+1. Assert: [=validate builtin set names=] |builtinSetNames| is true.
+1. Let |importModuleName| be |import|[0]
+1. Let |importName| be |import|[1]
+1.  [=list/iterate|For each=] |builtinSetName| of |builtinSetNames|,
+    1. If |importModuleName| equals |builtinSetName|
+        1. Let |builtins| be the result of [=get the builtins for a builtin set=] |builtinSetName|
+        1. [=list/iterate|For each=] |builtin| of |builtins|
+            1. Let |builtinName| be |builtin|[0]
+            1. If |importName| equals |builtinName|, return (|builtinSetName|, |builtin|).
+1. Return null.
+
+</div>
+
+<div algorithm>
+To <dfn>validate builtin set names</dfn> with |builtinSetNames|, perform the following steps:
+
+1. If |builtinSetNames| contains any duplicates, return false.
+1. [=list/iterate|For each=] |builtinSetName| of |builtinSetNames|,
+    1. If |builtinSetName| does not equal the name of one of the builtin sets defined in this section, return false.
+1. Return false.
+
+</div>
+
+<div algorithm>
+  To <dfn>create a builtin function</dfn> from type |functype| and execution steps |steps|, perform the following steps:
+
+    1. Let |stored settings| be the <a spec=HTML>incumbent settings object</a>.
+    1. Let |hostfunc| be a [=host function=] which executes |steps| when called.
+    1. Let (|store|, |funcaddr|) be [=func_alloc=](|store|, |functype|, |hostfunc|).
+    1. Set the [=surrounding agent=]'s [=associated store=] to |store|.
+    1. Return |funcaddr|.
+
+</div>
+
+<div algorithm>
+To <dfn>instantiate a builtin set</dfn> with name |builtinSetName|, perform the following steps:
+
+1. Let |builtins| be the result of [=get the builtins for a builtin set=] |builtinSetName|
+1. Let |exportsObject| be [=!=] [$OrdinaryObjectCreate$](null).
+        1. If |externtype| is of the form [=external-type/func=] <var ignore>functype</var>,
+1. [=list/iterate|For each=] (|name|, |funcType|, |algorithm|) of |builtins|,
+    1. Let |funcaddr| be the result fo [=create a builtin function=] with |funcType| and |algorithm|
+    1. Let |func| be the result of creating [=a new Exported Function=] from |funcaddr|.
+    1. Let |value| be |func|.
+    1. Let |status| be [=!=] [$CreateDataProperty$](|exportsObject|, |name|, |value|).
+    1. Assert: |status| is true.
+1. Perform [=!=] [$SetIntegrityLevel$](|exportsObject|, `"frozen"`).
+1. Return |exportsObject|.
+
+</div>
+
+<div algorithm>
+To <dfn>validate an import for builtins</dfn> with |import| and enabled builtins |builtinSetNames|, perform the following steps:
+
+1. Assert: [=validate builtin set names=] |builtinSetNames| is true.
+1. Let |maybeBuiltin| be the result of [=find a builtin|finding a builtin=] for |import| and |builtinSetNames|
+1. If |maybeBuiltin| is null, return true.
+1. Let |importExternType| be |import|[2]
+1. Let |builtinFuncType| be |maybeBuiltin|[0][1]
+1. Let |builtinExternType| be `func |builtinFuncType|`
+1. Return [=match_externtype=](|builtinExternType|, |importExternType|)
+
+</div>
 
 
 <h3 id="builtins-js-string">String Builtins</h3>

From 8ef28ff6f1b5febd2f88c5e25c7cc1afc3c2e23d Mon Sep 17 00:00:00 2001
From: Ryan Hunt <rhunt@eqrion.net>
Date: Wed, 7 Aug 2024 13:20:31 -0500
Subject: [PATCH 3/6] Remove unneeded modification to embedding spec

---
 document/core/appendix/embedding.rst | 9 ---------
 1 file changed, 9 deletions(-)

diff --git a/document/core/appendix/embedding.rst b/document/core/appendix/embedding.rst
index cccaa1eb..737230ef 100644
--- a/document/core/appendix/embedding.rst
+++ b/document/core/appendix/embedding.rst
@@ -161,15 +161,6 @@ Modules
    \end{array}
 
 
-.. index:: validation
-.. _embed-module-module-validate-partial-imports:
-
-:math:`\F{module\_validate\_partial\_imports}(\module, \imports) : \error^?`
-................................................
-
-// TODO
-1. Return :math:`\ERROR`.
-
 .. index:: instantiation, module instance
 .. _embed-module-instantiate:
 

From d68698fa37b8dbb4ef8d6a1eeb90812819596931 Mon Sep 17 00:00:00 2001
From: Ryan Hunt <rhunt@eqrion.net>
Date: Wed, 7 Aug 2024 13:51:32 -0500
Subject: [PATCH 4/6] Initial string constants support

---
 document/js-api/index.bs | 69 +++++++++++++++++++++++++++++-----------
 1 file changed, 50 insertions(+), 19 deletions(-)

diff --git a/document/js-api/index.bs b/document/js-api/index.bs
index 50740dfb..3fed558d 100644
--- a/document/js-api/index.bs
+++ b/document/js-api/index.bs
@@ -341,10 +341,15 @@ Note:
 </div>
 
 <div algorithm>
-  To <dfn>validate builtins for a WebAssembly module</dfn> from module |module| and enabled builtins |builtinSetNames|, perform the following steps:
+  To <dfn>validate builtins and imported string for a WebAssembly module</dfn> from module |module|, enabled builtins |builtinSetNames|, and |importedStringModule|, perform the following steps:
     1. If [=validate builtin set names|validating builtin set names=] for |builtinSetNames| is false, return false.
     1. [=list/iterate|For each=] |import| of [=module_imports=](|module|),
-        1. If [=validate an import for builtins|validating a import for builtin=] with |import| and |builtinSetNames| is false, return false.
+        1. If |importedStringModule| is not null and |import|[0] equals |importedStringModule|,
+            1. Let |importExternType| be |import|[2]
+            1. Let |stringExternType| be `global const (ref extern)`
+            1. If [=match_externtype=](|stringExternType|, |importExternType|) is false, return false
+        1. Else,
+            1. If [=validate an import for builtins|validating a import for builtin=] with |import| and |builtinSetNames| is false, return false.
     1. Return true.
 </div>
 
@@ -354,7 +359,8 @@ Note:
     1. [=Compile a WebAssembly module|Compile=] |stableBytes| as a WebAssembly module and store the results as |module|.
     1. If |module| is [=error=], return false.
     1. Let |builtinSetNames| be options["builtins"]
-    1. If [=validate builtins for a WebAssembly module|validating builtins for WebAssembly module=] |module| with |builtinSetNames| returns false, return false.
+    1. Let |importedStringModule| be options["importedStringConstants"]
+    1. If [=validate builtins and imported string for a WebAssembly module|validating builtins and imported strings=] for |module| with |builtinSetNames| and |importedStringModule| returns false, return false.
     1. Return true.
 </div>
 
@@ -363,14 +369,16 @@ A {{Module}} object represents a single WebAssembly module. Each {{Module}} obje
     * \[[Module]] : a WebAssembly [=/module=]
     * \[[Bytes]] : the source bytes of \[[Module]].
     * \[[BuiltinSets]] : an ordered set of names of <a href="#builtins">builtin sets</a>
+    * \[[ImportedStringModule]] : an optional module specifier string where any string constant can be imported from.
 
 <div algorithm>
-  To <dfn>construct a WebAssembly module object</dfn> from a module |module|, source bytes |bytes|, enabled builtins |builtinSetNames|, perform the following steps:
+  To <dfn>construct a WebAssembly module object</dfn> from a module |module|, source bytes |bytes|, enabled builtins |builtinSetNames|, and |importedStringModule|, perform the following steps:
 
     1. Let |moduleObject| be a new {{Module}} object.
     1. Set |moduleObject|.\[[Module]] to |module|.
     1. Set |moduleObject|.\[[Bytes]] to |bytes|.
     1. Set |moduleObject|.\[[BuiltinSets]] to |builtinSetNames|.
+    1. Set |moduleObject|.\[[ImportedStringModule]] to |importedStringModule|.
     1. Return |moduleObject|.
 </div>
 
@@ -383,9 +391,10 @@ A {{Module}} object represents a single WebAssembly module. Each {{Module}} obje
         1. [=Queue a task=] to perform the following steps. If |taskSource| was provided, queue the task on that task source.
             1. If |module| is [=error=], reject |promise| with a {{CompileError}} exception.
             1. Let |builtinSetNames| be options["builtins"]
-            1. If [=validate builtins for a WebAssembly module|validating builtins=] for |module| |builtinSetNames| is false, reject |promise| with a {{CompileError}} exception.
+            1. Let |importedStringModule| be options["importedStringConstants"]
+            1. If [=validate builtins and imported string for a WebAssembly module|validating builtins and imported strings=] for |module| with |builtinSetNames| and |importedStringModule| is false, reject |promise| with a {{CompileError}} exception.
             1. Otherwise,
-                1. [=Construct a WebAssembly module object=] from |module|, |bytes|, |builtinSetNames|, and let |moduleObject| be the result.
+                1. [=Construct a WebAssembly module object=] from |module|, |bytes|, |builtinSetNames|, |importedStringModule|, and let |moduleObject| be the result.
                 1. [=Resolve=] |promise| with |moduleObject|.
     1. Return |promise|.
 </div>
@@ -396,18 +405,36 @@ A {{Module}} object represents a single WebAssembly module. Each {{Module}} obje
     1. [=Asynchronously compile a WebAssembly module=] from |stableBytes| using |options| and return the result.
 </div>
 
+<div algorithm>
+To <dfn>instantiate imported strings</dfn> with module |module| and |importedStringModule|, perform the following steps:
+1. Assert: |importedStringModule| is not null.
+1. Let |exportsObject| be [=!=] [$OrdinaryObjectCreate$](null).
+        1. If |externtype| is of the form [=external-type/func=] <var ignore>functype</var>,
+1. [=list/iterate|For each=] (|moduleName|, |componentName|, |externtype|) of [=module_imports=](|module|),
+    1. If |moduleName| does not equal |importedStringModule|, then [=iteration/continue=].
+    1. Let |stringConstant| be |componentName|.
+    1. Let |status| be [=!=] [$CreateDataProperty$](|exportsObject|, |stringConstant|, |stringConstant|).
+    1. Assert: |status| is true.
+1. Perform [=!=] [$SetIntegrityLevel$](|exportsObject|, `"frozen"`).
+1. Return |exportsObject|.
+
+</div>
+
 <div algorithm="read-the-imports">
-  To <dfn>read the imports</dfn> from a WebAssembly module |module| from imports object |importObject| and enabled builtins |builtinSetNames|, perform the following steps:
+  To <dfn>read the imports</dfn> from a WebAssembly module |module| from imports object |importObject|, enabled builtins |builtinSetNames|, and |importedStringModule|, perform the following steps:
     1. If |module|.[=imports=] [=list/is empty|is not empty=], and |importObject| is undefined, throw a {{TypeError}} exception.
-    1. Let |instantiatedBuiltins| be the ordered map « ».
+    1. Let |builtinOrStringImports| be the ordered map « ».
     1. [=list/iterate|For each=] |builtinSetName| of |builtinSetNames|,
-        1. Assert: |instantiatedBuiltins| does not contain |builtinSetName|
+        1. Assert: |builtinOrStringImports| does not contain |builtinSetName|
         1. Let |exportsObject| be the result of [=instantiate a builtin set=] with |builtinSetName|
-        1. [=map/set|Set=] |instantiatedBuiltins|[|builtinSetName|] to |exportsObject|
+        1. [=map/set|Set=] |builtinOrStringImports|[|builtinSetName|] to |exportsObject|
+    1. If |importedStringModule| is not null,
+        1. Let |exportsObject| be the result of [=instantiate imported strings=] with |module| and |importedStringModule|
+        1. [=map/set|Set=] |builtinOrStringImports|[|importedStringModule|] to |exportsObject|
     1. Let |imports| be « ».
     1. [=list/iterate|For each=] (|moduleName|, |componentName|, |externtype|) of [=module_imports=](|module|),
-        1. If |instantiatedBuiltins| [=map/exist|contains=] |moduleName|,
-            1. Let |o| be |instantiatedBuiltins|[|moduleName|]
+        1. If |builtinOrStringImports| [=map/exist|contains=] |moduleName|,
+            1. Let |o| be |builtinOrStringImports|[|moduleName|]
         1. Else,
             1. Let |o| be [=?=] [$Get$](|importObject|, |moduleName|).
         1. If [=Type=](|o|) is not Object, throw a {{TypeError}} exception.
@@ -525,7 +552,8 @@ The verification of WebAssembly type requirements is deferred to the
     1. Let |promise| be [=a new promise=].
     1. Let |module| be |moduleObject|.\[[Module]].
     1. Let |builtinSetNames| be |moduleObject|.\[[BuiltinSets]].
-    1. [=Read the imports=] of |module| with imports |importObject| and |builtinSetNames|, and let |imports| be the result.
+    1. Let |importedStringModule| be |moduleObject|.\[[ImportedStringModule]].
+    1. [=Read the imports=] of |module| with imports |importObject|, |builtinSetNames| and |importedStringModule|, and let |imports| be the result.
         If this operation throws an exception, catch it, [=reject=] |promise| with the exception, and return |promise|.
     1. Run the following steps [=in parallel=]:
         1. [=Queue a task=] to perform the following steps:
@@ -630,12 +658,14 @@ interface Module {
     The <dfn method for="Module">imports(|moduleObject|)</dfn> method, when invoked, performs the following steps:
     1. Let |module| be |moduleObject|.\[[Module]].
     1. Let |builtinSetNames| be |moduleObject|.\[[BuiltinSets]].
+    1. Let |importedStringModule| be |moduleObject|.\[[ImportedStringModule]].
     1. Let |imports| be « ».
     1. [=list/iterate|For each=] (|moduleName|, |name|, |type|) of [=module_imports=](|module|),
-        1. If [=find a builtin=] for (|moduleName|, |name|, |type|) and |builtinSetNames| is null,
-            1. Let |kind| be the [=string value of the extern type=] |type|.
-            1. Let |obj| be «[ "{{ModuleImportDescriptor/module}}" → |moduleName|, "{{ModuleImportDescriptor/name}}" → |name|, "{{ModuleImportDescriptor/kind}}" → |kind| ]».
-            1. [=list/Append=] |obj| to |imports|.
+        1. If [=find a builtin=] for (|moduleName|, |name|, |type|) and |builtinSetNames| is not null, then [=iteration/continue=]
+        1. If |importedStringModule| is not null and |moduleName| equals |importedStringModule|, then [=iteration/continue=]
+        1. Let |kind| be the [=string value of the extern type=] |type|.
+        1. Let |obj| be «[ "{{ModuleImportDescriptor/module}}" → |moduleName|, "{{ModuleImportDescriptor/name}}" → |name|, "{{ModuleImportDescriptor/kind}}" → |kind| ]».
+        1. [=list/Append=] |obj| to |imports|.
     1. Return |imports|.
 </div>
 
@@ -677,7 +707,8 @@ interface Instance {
   The <dfn constructor for="Instance">Instance(|module|, |importObject|)</dfn> constructor, when invoked, runs the following steps:
     1. Let |module| be |module|.\[[Module]].
     1. Let |builtinSetNames| be |module|.\[[BuiltinSets]].
-    1. [=Read the imports=] of |module| with imports |importObject| and |builtinSetNames|, and let |imports| be the result.
+    1. Let |importedStringModule| be |module|.\[[ImportedStringModule]].
+    1. [=Read the imports=] of |module| with imports |importObject|, |builtinSetNames|, and |importedStringModule|, and let |imports| be the result.
     1. [=Instantiate the core of a WebAssembly module=] |module| with |imports|, and let |instance| be the result.
     1. [=initialize an instance object|Initialize=] **this** from |module| and |instance|.
 
@@ -1746,7 +1777,7 @@ To <dfn>instantiate a builtin set</dfn> with name |builtinSetName|, perform the
 </div>
 
 <div algorithm>
-To <dfn>validate an import for builtins</dfn> with |import| and enabled builtins |builtinSetNames|, perform the following steps:
+To <dfn>validate an import for builtins</dfn> with |import|, enabled builtins |builtinSetNames|, perform the following steps:
 
 1. Assert: [=validate builtin set names=] |builtinSetNames| is true.
 1. Let |maybeBuiltin| be the result of [=find a builtin|finding a builtin=] for |import| and |builtinSetNames|

From 666d754cd8a4bbb342f85886eb11ebcfccce6434 Mon Sep 17 00:00:00 2001
From: Ryan Hunt <rhunt@eqrion.net>
Date: Wed, 7 Aug 2024 13:54:38 -0500
Subject: [PATCH 5/6] Fix module constructor to handle options

---
 document/js-api/index.bs | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/document/js-api/index.bs b/document/js-api/index.bs
index 3fed558d..4b1c3f8f 100644
--- a/document/js-api/index.bs
+++ b/document/js-api/index.bs
@@ -682,13 +682,18 @@ interface Module {
 </div>
 
 <div algorithm>
-    The <dfn constructor for="Module">Module(|bytes|)</dfn> constructor, when invoked, performs the following steps:
+    The <dfn constructor for="Module">Module(|bytes|, |options|)</dfn> constructor, when invoked, performs the following steps:
 
     1. Let |stableBytes| be a [=get a copy of the buffer source|copy of the bytes held by the buffer=] |bytes|.
     1. [=Compile a WebAssembly module|Compile the WebAssembly module=] |stableBytes| and store the result as |module|.
     1. If |module| is [=error=], throw a {{CompileError}} exception.
+    1. Let |builtinSetNames| be options["builtins"]
+    1. Let |importedStringModule| be options["importedStringConstants"]
+    1. If [=validate builtins and imported string for a WebAssembly module|validating builtins and imported strings=] for |module| with |builtinSetNames| and |importedStringModule| returns false, throw a {{CompileError}} exception.
     1. Set **this**.\[[Module]] to |module|.
     1. Set **this**.\[[Bytes]] to |stableBytes|.
+    1. Set **this**.\[[BuiltinSets]] to |builtinSetNames|.
+    1. Set **this**.\[[ImportedStringModule]] to |importedStringModule|.
 
 Note: Some implementations enforce a size limitation on |bytes|. Use of this API is discouraged, in favor of asynchronous APIs.
 </div>

From 5aba5db607cc40923cd9319f01755b3845da0c8a Mon Sep 17 00:00:00 2001
From: Ryan Hunt <rhunt@eqrion.net>
Date: Thu, 8 Aug 2024 12:40:03 -0500
Subject: [PATCH 6/6] Don't freeze internal instantiation of builtins and
 string constants

---
 document/js-api/index.bs | 2 --
 1 file changed, 2 deletions(-)

diff --git a/document/js-api/index.bs b/document/js-api/index.bs
index 4b1c3f8f..aa979134 100644
--- a/document/js-api/index.bs
+++ b/document/js-api/index.bs
@@ -415,7 +415,6 @@ To <dfn>instantiate imported strings</dfn> with module |module| and |importedStr
     1. Let |stringConstant| be |componentName|.
     1. Let |status| be [=!=] [$CreateDataProperty$](|exportsObject|, |stringConstant|, |stringConstant|).
     1. Assert: |status| is true.
-1. Perform [=!=] [$SetIntegrityLevel$](|exportsObject|, `"frozen"`).
 1. Return |exportsObject|.
 
 </div>
@@ -1776,7 +1775,6 @@ To <dfn>instantiate a builtin set</dfn> with name |builtinSetName|, perform the
     1. Let |value| be |func|.
     1. Let |status| be [=!=] [$CreateDataProperty$](|exportsObject|, |name|, |value|).
     1. Assert: |status| is true.
-1. Perform [=!=] [$SetIntegrityLevel$](|exportsObject|, `"frozen"`).
 1. Return |exportsObject|.
 
 </div>
