You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Previously, the instantiate function had some kind of complicated logic
to make it so just one JS object per memory, table or exported function
would be created per address in the store without having a global mapping.
This patch switches to a global mapping to make the specification
easier to read and modify over time.
The change here was discussed in this comment thread:
WebAssembly#591 (comment)
Copy file name to clipboardexpand all lines: document/js-api/index.bs
+50-60
Original file line number
Diff line number
Diff line change
@@ -288,13 +288,7 @@ A {{Module}} object represents a single WebAssembly module. Each {{Module}} obje
288
288
To <dfn>instantiate a WebAssembly module</dfn> from a {{Module}} |moduleObject| and imports |importObject|, perform the following steps:
289
289
1. Let |module| be |moduleObject|.\[[Module]].
290
290
1. If |module|.[=𝗂𝗆𝗉𝗈𝗋𝗍𝗌=] is not an empty list, and |importObject| is undefined, throw a {{TypeError}} exception.
291
-
1. Let |funcs| be an empty [=list=] of callable JavaScript objects.
292
-
1. Let |memories| be an empty [=list=] of {{Memory}} objects.
293
-
1. Let |tables| be an empty [=list=] of {{Table}} objects.
294
-
295
-
Note: The |funcs|, |memories| and |tables| lists are collected and used in order to cache the JavaScript objects corresponding to WebAssembly objects. If a WebAssembly object is exported multiple times, it will appear in exports as the same object instance. Moreover, if a JavaScript wrapper of a WebAssembly object was imported, and then present on the export, a new wrapper will not need to be created. However, if an ordinary JS function is imported, it will appear as wrapped by an [=Exported Function=].
296
-
297
-
6. Let |imports| be an empty [=list=] of [=external value=]s.
291
+
1. Let |imports| be an empty [=list=] of [=external value=]s.
298
292
1. For each (|moduleName|, |componentName|, |externtype|) in [=module_imports=](|module|), do
299
293
1. Let |o| be ? [=Get=](|importObject|, |moduleName|).
300
294
1. If [=Type=](|o|) is not [=Object=], throw a {{TypeError}} exception.
@@ -305,11 +299,9 @@ A {{Module}} object represents a single WebAssembly module. Each {{Module}} obje
305
299
1. Let |funcaddr| be the value of |v|'s \[[FunctionAddress]] internal slot.
306
300
307
301
Note: The signature is checked by [=instantiate_module=] invoked below.
308
-
309
-
2. [=Append=] |v| to |funcs|.
310
302
1. Otherwise,
311
303
1. [=Create a host function=] from |v| and let |funcaddr| be the result.
312
-
1. Let |externfunc| be the [=external value=][=external value|𝖿𝗎𝗇𝖼=] |funcaddr|
304
+
1. Let |externfunc| be the [=external value=][=external value|𝖿𝗎𝗇𝖼=] |funcaddr|.
313
305
1. [=Append=] |externfunc| to |imports|.
314
306
1. If |externtype| is of the form [=𝗀𝗅𝗈𝖻𝖺𝗅=] |globaltype|,
315
307
1. If |globaltype| is [=𝗂𝟨𝟦=] or [=Type=](|v|) is not [=Number=], throw a {{LinkError}} exception.
@@ -325,72 +317,46 @@ A {{Module}} object represents a single WebAssembly module. Each {{Module}} obje
325
317
326
318
Note: [=instantiate_module=] invoked below will check the imported {{Memory}}'s size against the importing module's requirements.
327
319
328
-
2. [=Append=] |v| to |memories|.
329
-
1. Let |externmem| be the [=external value=][=external value|𝗆𝖾𝗆=] |v|.\[[Memory]].
320
+
2. Let |externmem| be the [=external value=][=external value|𝗆𝖾𝗆=] |v|.\[[Memory]].
330
321
1. [=Append=] |externmem| to |imports|.
331
322
1. Otherwise, |externtype| is of the form [=𝗍𝖺𝖻𝗅𝖾=] |tabletype|,
332
323
1. If |v| is not a {{Table}} instance, throw a {{LinkError}} exception.
333
324
334
325
Note: The table's length, etc. is checked by [=instantiate_module=] invoked below.
335
326
336
-
2. [=Append=] |v| to |tables|.
337
-
1. Let |tableaddr| be |v|.\[[Table]]
327
+
2. Let |tableaddr| be |v|.\[[Table]]
338
328
1. Let |externtable| be the [=external value=][=external value|𝗍𝖺𝖻𝗅𝖾=] |tableaddr|.
339
329
1. [=Append=] |externtable| to |imports|.
340
-
1. For each element |func| of |v|.\[[Values]],
341
-
1. If |func| is not null, append |func| to |funcs|.
342
-
1. Let (|store|, |instance|) be [=instantiate_module=](|store|, |module|, |imports|), up through step 16 of [=the instantiation algorithm=], but omitting execution of the start function.
343
-
1. If |instance| is [=error=], throw a {{LinkError}} exception, or other <a href="#errors">appropriate exception type</a>.
344
-
1. For each |tableaddr| in |instance|.𝗍𝖺𝖻𝗅𝖾𝖺𝖽𝖽𝗋𝗌,
345
-
1. If there is no element in |tables| whose |table|.\[[Table]] is |tableaddr|:
346
-
1. Let |table| be [=create a table object|a new table object=] from |tableaddr|.
347
-
1. [=Append=] |table| to |tables|.
348
-
1. Otherwise:
349
-
1. Let |table| be the element in |tables| where |table|.\[[Table]] is |tableaddr|.
350
-
1. For each index |i| from 0 to the length of |table|.\[[Values]] − 1, do
351
-
1. Let |funcaddr| be [=read_table=](|store|, |tableaddr|, |i|).
352
-
1. Assert: |funcaddr| is not [=error=] because this read is in bounds.
353
-
1. If |funcaddr| is not empty,
354
-
1. If |funcs| contains any |func| where |func|.\[[ExportedAddress]] is |funcaddr|,
355
-
1. Let |func| be that function object.
356
-
1. Otherwise:
357
-
1. Let |func| be a [=a new Exported Function=] created from |funcaddr|.
358
-
1. [=Append=] |func| to |funcs|.
359
-
1. Set the |table|.\[[Values]][|i|] to |func|.
360
-
361
-
Note: The table and function objects created by the above steps are only observable for tables that are either imported or exported.
362
-
363
-
1. Let |startfuncaddr| be the start function of |instance|.
364
-
1. Let (|store|, |ret|) be [=invoke_func=](|store|, |startfuncaddr|, empty).
365
-
1. If |ret| is [=error=], throw an exception. This exception should be a WebAssembly {{RuntimeError}} exception, unless otherwise indicated by <a href="#errors">the WebAssembly error mapping</a>.
366
-
1. Assert: |ret| is empty.
330
+
1. Let (|store|, |instance|) be [=instantiate_module=](|store|, |module|, |imports|).
331
+
1. If |instance| is [=error=], throw an appropriate exception type:
332
+
* A {{LinkError}} exception for most cases which occur during linking.
333
+
* If the error came when running the start function, throw a {{RuntimeError}} for most errors which occur from WebAssembly, or the error object propagated from inner ECMAScript code.
334
+
* Another error type if appropriate, for example an out-of-memory exception, as documented in <a href="#errors">the WebAssembly error mapping</a>.
367
335
1. Let |exportsObject| be ! [=ObjectCreate=](null).
368
336
1. For each pair (|name|, |externtype|) in [=module_exports=](|module|),
369
337
1. Let |externval| be [=get_export=](|instance|, |name|).
338
+
1. Assert: |externval| is not [=error=].
370
339
1. If |externtype| is of the form [=𝖿𝗎𝗇𝖼=] |functype|,
371
-
1. If |funcs| contains an entry |func| where 𝖿𝗎𝗇𝖼 |func|.\[[FunctionAddress]] is |externval|, let |value| be |func|
372
-
1. Otherwise,
373
-
1. Let |func| be the result of [=a new Exported Function=] from |externval|.
374
-
1. [=Append=] |func| to |funcs|.
375
-
1. Let |value| be |func|.
340
+
1. Then, |externval| is of the form [=external value|𝖿𝗎𝗇𝖼=] |funcaddr|.
341
+
1. Let |func| be the result of [=a new Exported Function=] from |funcaddr|.
342
+
1. Let |value| be |func|.
376
343
1. If |externtype| is of the form [=𝗀𝗅𝗈𝖻𝖺𝗅=] |globaltype|,
377
344
1. If |globaltype|.<em>[=global type|valtype=]</em>) is [=𝗂𝟨𝟦=], throw a {{LinkError}} exception.
378
345
1. Assert: |globaltype|.<em>[=global type|mut=]</em> is [=global type|𝖼𝗈𝗇𝗌𝗍=], as verified by WebAssembly validation.
379
346
1. Let |value| be [=ToJSValue=]([=read_global=](|store|, |externval|)).
380
347
1. If |externtype| is of the form [=𝗆𝖾𝗆=] |memtype|,
381
-
1. If there is an element |memory| in |memories| such that 𝗆𝖾𝗆 |memory|.\[[Memory]] is |externval|, then let |value| be |memory|
382
-
1. Otherwise:
383
-
1. Let |memory| be [=create a memory object|a new Memory object=] from |externval|.
384
-
1. [=Append=] |memory| to |memories|.
385
-
1. Let |value| be |memory|.
348
+
1. Then, |externval| is of the form [=external value|𝗆𝖾𝗆=] |memaddr|.
349
+
1. Let |memory| be [=create a memory object|a new Memory object=] from |memaddr|.
350
+
1. Let |value| be |memory|.
386
351
1. Otherwise, |externtype| is of the form [=𝗍𝖺𝖻𝗅𝖾=] |tabletype|,
387
-
1. Let |value| be the unique |table| in |tables| such that 𝗍𝖺𝖻𝗅𝖾 |table|.\[[Table]] is |externval|.
352
+
1. Then, |externval| is of the form [=external value|𝗍𝖺𝖻𝗅𝖾=] |tableaddr|.
353
+
1. Let |table| be [=create a Table object|a new Table object=] from |tableaddr|.
354
+
1. Let |value| be |table|.
388
355
1. Let |status| be ! [=CreateDataProperty=](|exportsObject|, |name|, |value|).
389
356
1. Assert: |status| is true.
390
357
391
358
Note: the validity and uniqueness checks performed during [=WebAssembly module validation=] ensure that each property name is valid and no properties are defined twice.
1. Let |instanceObject| be a new {{Instance}} object whose internal \[[Instance]] slot is set to |instance| and the \[[Exports]] slot to |exportsObject|.
395
361
1. Return |instanceObject|.
396
362
</div>
@@ -472,8 +438,6 @@ interface Module {
472
438
1. Let |module| be |moduleObject|.\[[Module]].
473
439
1. Let |exports| be an empty [=list=].
474
440
1. For each (|name|, |type|) in [=module_exports=](|module|)
475
-
1. Let |nameString| be String value consisting of the [=UTF16Encoding=] of each code point of |name|.
476
-
1. Assert: |name| is not failure (|module| is [=valid=]).
477
441
1. Let |kind| be the [=string value of the extern type=] |type|.
478
442
1. Let |obj| be a new {{ModuleExportDescriptor}} dictionary with {{ModuleExportDescriptor/name}} |name| and {{ModuleExportDescriptor/kind}} |kind|.
479
443
1. [=Append=] |obj| to the end of |exports|.
@@ -551,22 +515,31 @@ which can be simultaneously referenced by multiple {{Instance}} objects. Each
551
515
552
516
* \[[Memory]] : a [=memory address=]
553
517
* \[[BufferObject]] : an {{ArrayBuffer}} whose [=Data Block=] is [=identified with=] the above memory address
518
+
519
+
Each [=agent=] has an associated [=ordered map=] known as the <dfn>Memory object cache</dfn> mapping [=memory address=]es to {{Memory}} objects.
520
+
521
+
Note: This mapping is used to ensure that, for a given [=agent=], there exists at most one {{Memory}} object for a particular [=memory address=].
554
522
</div>
555
523
556
524
<div algorithm>
557
525
To <dfn>create a memory object</dfn> from a [=memory address=] |memaddr|, perform the following steps:
558
526
527
+
1. Let |map| be the current [=agent=]'s associated [=Memory object cache=].
528
+
1. If |map|[|memaddr|][=map/exists=],
529
+
1. Return |map|[|memaddr|].
559
530
1. Let |block| be a Data Block which is [=identified with=] the underlying memory of |memaddr|
560
531
1. Let |buffer| be a new {{ArrayBuffer}} whose \[[ArrayBufferData]] is |block| and \[[ArrayBufferByteLength]] is set to the length of |block|.
561
-
1. Return a new {{Memory}} instance with \[[Memory]] set to |memaddr| and \[[BufferObject]] set to |buffer|.
532
+
1. Let |memory| be a new {{Memory}} instance with \[[Memory]] set to |memaddr| and \[[BufferObject]] set to |buffer|.
533
+
1. [=map/Set=] |map|[|memaddr|] to |memory|.
534
+
1. Return |memory|.
562
535
563
536
Issue: Any attempts to [=DetachArrayBuffer|detach=] |buffer|, other than the detachment performed by {{Memory/grow(delta)}}, will throw a {{TypeError}} exception. Specifying this behavior <a href="https://github.com/tc39/ecma262/issues/1024">requires changes to the ECMAScript specification</a>.
564
537
</div>
565
538
566
539
<div algorithm>
567
540
The <dfn constructor for="Memory">Memory(descriptor)</dfn> constructor, when invoked, performs the following steps:
568
-
1. If |descriptor|\["initial"] is [=present=], let |initial| be |descriptor|\["initial"]; otherwise, let |initial| be 0.
569
-
1. If |descriptor|\["maximum"] is [=present=], let |maximum| be |descriptor|\["maximum"]; otherwise, let |maximum| be empty.
541
+
1. If |descriptor|["initial"] is [=present=], let |initial| be |descriptor|["initial"]; otherwise, let |initial| be 0.
542
+
1. If |descriptor|["maximum"] is [=present=], let |maximum| be |descriptor|["maximum"]; otherwise, let |maximum| be empty.
570
543
1. Let |memtype| be { min |initial|, max |maximum| }
571
544
1. Let |store| be the current agent's [=associated store=].
572
545
1. Let (|store|, |memaddr|) be [=alloc_mem=](|store|, |memtype|). If allocation fails, throw a {{RangeError}} exception.
@@ -621,12 +594,21 @@ which can be simultaneously referenced by multiple {{Instance}} objects. Each
621
594
622
595
* \[[Table]] : a [=table address=]
623
596
* \[[Values]] : a List whose elements are either null or [=Exported Function=]s.
597
+
598
+
Each [=agent=] has an associated [=ordered map=] known as the <dfn>Table object cache</dfn> mapping [=table address=]es to {{Table}} objects.
599
+
600
+
Note: This mapping is used to ensure that, for a given [=agent=], there exists at most one {{Table}} object for a particular [=table address=].
624
601
</div>
625
602
626
603
<div algorithm>
627
604
To <dfn>create a table object</dfn> from a [=table address=] |tableaddr|, perform the following steps:
605
+
1. Let |map| be the current [=agent=]'s associated [=Table object cache=].
606
+
1. If |map|[|tableaddr|][=map/exists=],
607
+
1. Return |map|[|tableaddr|].
628
608
1. Let |values| be a list whose length is [=size_table=](|store|, |tableaddr|) where each element is null.
629
-
1. Return a new {{Table}} instance with \[[Table]] set to |tableaddr| and \[[Values]] set to |values|.
609
+
1. Let |table| be a new {{Table}} instance with \[[Table]] set to |tableaddr| and \[[Values]] set to |values|.
610
+
1. [=map/Set=] |map|[|tableaddr|] to |table|.
611
+
1. Return |table|.
630
612
</div>
631
613
632
614
<div algorithm>
@@ -690,6 +672,10 @@ A WebAssembly function is made available in JavaScript as an <dfn>Exported Funct
690
672
Exported Functions are [=Built-in Function Objects=] which are not constructors, and which have a \[[FunctionAddress]] internal slot.
691
673
This slot holds a [=function address=] relative to the current agent's [=associated store=].
692
674
675
+
Each [=agent=] has an associated [=ordered map=] known as the <dfn>Exported Function cache</dfn> mapping [=function address=]es to [=Exported Function=] objects.
676
+
677
+
Note: This mapping is used to ensure that, for a given [=agent=], there exists at most one [=Exported Function=] object for a particular [=function address=].
678
+
693
679
<div algorithm>
694
680
The <dfn>name of the WebAssembly function</dfn> |funcaddr| is found by performing the following steps:
695
681
@@ -709,6 +695,9 @@ This slot holds a [=function address=] relative to the current agent's [=associa
709
695
<div algorithm>
710
696
To create <dfn>a new Exported Function</dfn> from a WebAssembly [=function address=] |funcaddr|, perform the following steps:
711
697
698
+
1. Let |map| be the current [=agent=]'s associated [=Exported Function cache=].
699
+
1. If |map|[|funcaddr|][=map/exists=],
700
+
1. Return |map|[|funcaddr|].
712
701
1. Let |steps| be "[=call an Exported Function|call the Exported Function=] |funcaddr| with arguments."
713
702
1. Let |realm| be the [=current Realm=].
714
703
1. Let |function| be [=CreateBuiltinFunction=](|realm|, |steps|, [=%FunctionPrototype%=], « \[[FunctionAddress]]).
@@ -720,6 +709,7 @@ This slot holds a [=function address=] relative to the current agent's [=associa
0 commit comments