Skip to content

Commit 6b42bc2

Browse files
authored
Initial description of a declarative custom section (#19)
Describe a custom section used to declaratively configure `DescriptorOptions` objects to be passed as imports to core instantiation and populated using exported functions after core instantiation.
1 parent 6d42313 commit 6b42bc2

File tree

1 file changed

+140
-1
lines changed

1 file changed

+140
-1
lines changed

proposals/custom-descriptors/Overview.md

Lines changed: 140 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -542,7 +542,146 @@ console.log(counter.get()); // 1
542542
543543
## Declarative Prototype Initialization
544544

545-
TODO
545+
We expect toolchains to need to configure thousands of JS prototypes and tens of thousands of methods,
546+
so we expect there to be startup latency problems
547+
if all the configuration is done directly via the raw `DescriptorOptions` API
548+
and JS glue code as shown above.
549+
550+
The proposed solution is to provide a declarative method of constructing, importing,
551+
and populating the `DescriptorOptions` objects.
552+
553+
The declarative API must support these features:
554+
555+
- Constructing new prototype objects
556+
- Using existing prototype objects provided at instantiation time
557+
- Creating prototype chains
558+
- Synthesizing and attaching methods (including getters and setters) to prototypes
559+
560+
Furthermore, the design goals are to be:
561+
562+
- Polyfillable by generated JS glue using the underlying `DescriptorOptions` JS API,
563+
i.e. to not introduce any new expressivity.
564+
565+
We define such an API in the form of a new custom section to be specified as part of the JS embedding.
566+
This custom section will be used in the constructor of `WebAssembly.Instance`
567+
to populate the imports with additional `DescriptorOptions` before core instantiation
568+
and to populate the prototypes using exported functions after core instantiation.
569+
570+
### Custom Section
571+
572+
```
573+
descindex ::= u32
574+
575+
descriptorsec ::= section_0(descriptordata)
576+
577+
descriptordata ::= n:name (if n = 'descriptors')
578+
modulename:name
579+
vec(descriptorentry)
580+
581+
descriptorentry ::= 0x00 importentry
582+
| 0x01 declentry
583+
584+
importentry ::= importname:name descconfig
585+
586+
declentry ::= protoconfig descconfig
587+
588+
protoconfig ::= v:vec(descindex) (if |v| <= 1)
589+
590+
descconfig ::= exportnames vec(methodconfig)
591+
592+
exportnames ::= vec(name)
593+
594+
methodconfig ::= kind:methodkind
595+
methodname:name
596+
exportname:name
597+
598+
methodkind ::= 0x00 => method
599+
| 0x01 => getter
600+
| 0x02 => setter
601+
| 0x03 => constructor
602+
```
603+
604+
The descriptors custom section starts with `modulename`,
605+
which is the module name from which the configured `DescriptorOptions` values
606+
will be imported by the Wasm module.
607+
A module may import configured `DescriptorOptions` values
608+
from multiple different module names
609+
by including multiple descriptors sections.
610+
611+
Following the `modulename` is a sequence of `descriptorentry`,
612+
each of which describes a single `DescriptorOptions` value.
613+
Each value can either be imported,
614+
meaning that it is provided as an argument to instantiation,
615+
or it is declared,
616+
meaning that the instantiation procedure will create it.
617+
A declared value can optionally specify the index of a previous value
618+
to serve as the parent in the configured prototype chain.
619+
Imported values are assumed to already have their prototype chain configured.
620+
621+
Each configured descriptor has a vector of export names.
622+
These are the names from which the Wasm module will import the descriptor values.
623+
624+
Whether imported or declared,
625+
each `descriptorentry` contains a vector of `methodconfig`
626+
describing the methods that should be attached to the prototype
627+
after instantiation.
628+
Each configured method can be either a
629+
normal method, a getter, a setter, or a constructor.
630+
Methods also have two associated names: the first their property name
631+
in the configured prototype and the second
632+
the name of the exported function they wrap.
633+
634+
All methods pass the receiver as the first argument:
635+
636+
```js
637+
function methodname() { return exports[exportname](this, ...arguments); }
638+
```
639+
640+
Getters and setters are additionally configured as getters and setters
641+
when they are attached to the prototype.
642+
643+
Constructors are a little different.
644+
They do not pass the receiver as a parameter to the exported function:
645+
646+
```js
647+
function methodname() { return exports[exportname](...arguments); }
648+
```
649+
650+
Furthermore, they are not installed on the configured prototype.
651+
Instead, they are added to the `exports` object.
652+
The configured prototype is added as the `prototype` property of the generated function
653+
and the generated function is added as the `constructor` property of the configured prototype.
654+
655+
### Instantiation
656+
657+
When constructing a WebAssembly instance,
658+
the descriptors sections are first processed
659+
to create any new declared `DescriptorOptions`.
660+
Descriptor values imported by these sections are read from the main imports
661+
argument passed to instantiation using the module names
662+
given at the beginning of the sections.
663+
664+
The imports for core Wasm instantiation are then determined,
665+
giving precedence to the exports from the descriptors sections.
666+
667+
After core instantiation,
668+
the methods are populated based on the core exports.
669+
Since this does not happen until after core instantiation,
670+
when the exports have been made available,
671+
imports called by the start function will be able to observe
672+
the unpopulated prototypes that do not yet have the method properties.
673+
674+
If there is a decoding error in a descriptors section
675+
or if at any point a required import or export is missing,
676+
an error will be thrown.
677+
678+
> TODO: Describe the effect of the descriptors section on Module.imports and Module.exports.
679+
680+
> TODO: Make sure the prototypes can be read from the exports for further manual configuration.
681+
682+
> TODO: Consider supporting declarative static methods attached to constructors instead of methods.
683+
684+
> TODO: Declarative support for installing Symbol.hasInstance methods to support instanceof.
546685
547686
## Type Section Field Deduplication
548687

0 commit comments

Comments
 (0)