XS Engine Updates for ECMAScript 2020
ECMAScript 2020 Features
XS supports all the new language features included in the current draft of the ECMAScript 2020 specification.
Note: As of this writing the ECMAScript 2020 specification is available from the Ecma TC39 committee web site. Once it is officially approved, the standard will be available on the Ecma International web site.
??. The operator is a convenient shortcut to test if a value is equal to
let x = (value !== undefined) ? value : defaultValue;
Using the nullish coalescing operator simplifies the code:
let x = value ?? defaultValue;
The two are not entirely identical as
?? checks for both
null while the original code checks for
undefined for missing values, so the behavior of the nullish coalescing operator gives the correct result in both cases.
Developers have long used the logical or operator to achieve a similar result:
let x = value || defaultValue;
This often works, but it is imperfect. The logical or operator treats many values as
false including 0, the empty string,
undefined. This makes it unsafe to use the logical or operator in all circumstances. Therefore, it is recommended to use the nullish coalescing operator instead, now that it is available.
The optional chaining operator is an efficient way to confirm a value is an object before getting a property or calling a method. For example. the MQTT client in the Moddable SDK has code like this:
Using the optional chaining operator, this can be written as:
This operator is also convenient when working with data structures, such as objects instantiated from JSON. Code often needs to check if a property exists in JSON before accessing its values.
let record = JSON.parse(text);
zip = record.address.zip;
Using optional chaining this can be written more compactly.
let record = JSON.parse(text);
let zip = record.address?.zip;
brightness property of
this.light is missing or the
brightness value is
undefined, a default value of zero is used.
let brightness = this?.light.brightness ?? 0;
In addition to being more compact, the byte code generated using optional chaining is smaller and runs faster. Consider this code fragment that does not use optional chaining:
It generates the following ten byte codes.
Rewriting the code with optional chaining...
...generates only eight byte codes.
While saving two byte codes may not appear important, in an embedded system where every byte of flash storage and every CPU cycle are precious resources, this is a welcome improvement. Further, note that the
resolver property is only retrieved once in the optional chaining version. Property look-up is not always fast, so eliminating the unnecessary look-up helps.
replace method for strings. Using a Regular Expression with
replace supports replacing multiple occurrences of a string with a single call to
replace. However, when using string, only the first occurrence is replaced. The behavior of
replace cannot be safely changed as it would likely break existing web sites. Therefore, a new
replaceAll method has been added to provide the ability to replace all occurrences of a string.
To implement the equivalent of
replaceAll the Moddable SDK sometimes uses
split followed by
join. For example, the following fragment replaces all colons with an empty string.
let mac = Net.get("MAC").split(":").join("");
replaceAll is more clear, concise, and efficient.
let mac = Net.get("MAC").replaceAll(":", "");
Using Regular Expressions with
replaceAll function is a welcome addition that is easy for developers to understand while allowing for efficient implementation on embedded systems.
Promise.any and RegExp Match Array Offsets
This release of XS also implements new features for Promises and Regular Expressions. Neither is commonly used in embedded systems, so they are only described here briefly.
Promise.any is a useful helper function when resolving a group of promises simultaneously. It completes the suite of promises helper functions that includes
Regular Expressions have been extended to provide additional information about captured substrings. It adds an
indices property to the regular expression that contains the start and end indices of captured substrings.
To help developers better understand when their code is using floating point numbers, the Instruments pane in the xsbug debugger has been enhanced with a count of the number of floating point operations performed by XS. This value is updated once a second. The image below shows the Floating Point instrumentation when running the Piu Cards example.
Because Cards makes extensive use of Timeline for animations, there are a large number of floating point operations. The Piu Balls example, on the other hand, has no floating point operations after its initial set-up. There is nothing inherently wrong with floating point operations. They are useful, even essential. However, they can have a performance cost so it is helpful to measure and visualize when they occur.
Monitoring of the floating point instrumentation in xsbug brought to light some places where XS used floating point numbers where an integer was sufficient. Two of these are worth noting. The first is the
Int32Array. Getting and setting values into TypedArrays was using floating point operations because the code was generalized to also work with floating point arrays like
Float32Array. The code has been modified to allow integer-only operations to bypass unnecessary floating point conversion. Because TypedArrays are commonly used in embedded development to work with binary data, this behind-the-scenes improvement benefits many different modules.
Bocoup independently runs Test262 on all major engines and posts the results at the Test262 Report web site. The results differ in places from Moddable's run of the same tests, primarily because Test262 Report terminates some tests before they complete because they require more time to execute with XS. Still, the Test262 report results show XS is the most conformant engine in the language tests and second most conformant in built-in tests.
This version of XS contains many changes, large and small, to improve conformance. Of particular note are changes to the function calling conventions. This is the first time in the development of XS that these have changed. The changes were necessary to support certain required behaviors and to efficiently implement optional chaining.
Secure ECMAScript Update
Compartment class to match the latest draft of the proposal presented to TC39.
The Compartment API design in the current SES proposal is the result of initial work by Agoric on their SES shim and the original XS implementation of SES. Those two efforts were reconciled and combined into the current design by JF Paradis. The result is an API that is remarkable both for its simplicity and power.
The Moddable SDK contains a small suite of SES examples that exercise the features of Compartments. The documentation for the examples provides detailed walkthroughs of the code.