In Windows 10, we have made significant advancements to the JSRT APIs, making them a true first class citizen for hosting Chakra across various application types supported on Windows 10. Developers can now utilize these APIs to host Chakra for scripting in both Classic Windows (Win32) applications and Universal Windows applications. These APIs now provide native access to the underlying Universal Windows Platform (UWP) and ECMAScript 6 support. For the curious, and as an example, the recently announced Node support based on Chakra for Windows 10 IoT devices is built using these APIs.
Design Choices: Scalability, Performance and Resource Throttling
Ever since JSRT APIs were first introduced in IE11/Windows 8.1, they have supported features that help build scalable, reliable and efficient applications and services by hosting Chakra.
Threading flexibility: Rental Threading for Scalability
Multithreading is a common approach to improve parallelism in computing, particularly in server environments where I/O commonly causes apps to pause while waiting for an I/O request to be serviced. However, multithreading imposes significant difficulties on the developer; locks must be used in order to protect critical data structures from being corrupted. COM tackled this problem by creating threading models and then requiring individual components to declare whether they were apartment-threaded (single-threaded) or free-threaded (any thread can interact with it), and then COM would provide automatic binding and marshaling between different threading models.
JSRT APIs utilize a different threading model, called rental-threading. In a rental threading model, a script execution context (defined here) is always single-threaded, but is not hard-bound to the thread it was created on. In other words, at any given time, script operation from one context can be executed in one thread only, but the context can change its thread affinity from time to time. For example, the application may do some work and then decide to relinquish the thread to wait for an I/O request to complete. Once the I/O request completes, the script context can pick any idle thread to continue script execution by using the JsSetCurrentContext API, which allows the script context to start operating again, albeit on another thread.
In a rental-threaded model, hosts could create thread pools to ensure that they do not exceed a particular thread (and CPU) utilization quota. Such a model enables high scalability at low cost as it does not require the application to create a new thread for every request that comes in and requests need not block for other requests to be serviced.
With JSRT APIs, hosts also get the flexibility for managing the runtime’s background operations. Chakra provides a high-performance concurrent JIT compiler and garbage collector. By default, each runtime manages its own set of threads for both background compilation and background garbage collection. Based on the app needs, hosts can provide their own threads for those operations or can force the runtime to perform those tasks on the primary thread, ensuring that applications have predictable behavior and performance characteristics.
Startup and execution efficiency: Script Serialization
Resource Throttling: Managing Memory & CPU Utilization
Limits on memory utilization
Limits on CPU utilization
Avoiding runaway execution is often scenario specific as the host best knows when to limit or throttle utilization. While there could be valid long running scripts, a malicious script might force running an infinite loop, like below.
By default, the JIT code emitted for the above function is optimized for execution speed and does not have any “script interruption” checks inserted by default. By executing the emitted code, a thread will become a runaway, making it impossible to break the loop.
Developers can configure the runtime to allow such loops to be interrupted by passing the AllowScriptInterrupt flag when creating a runtime. When used, a supervisor thread can request that the runtime terminates execution by calling JsDisableRuntimeExecution at any point, which in turn terminates the script runtime and exits any executing code. The runtime can later be re-enabled by using the JsEnableRuntimeExecution function. This provides developers with a straightforward way to terminate script while keeping the script environment alive.
Edge JSRT: Universal Windows Platform & ECMAScript6 support
- Jscript9.dll, a version of Chakra that is supported by IE11 and retains full backward compatibility
- Chakra.dll, a version of Chakra that is supported by Microsoft Edge, will be actively developed and be ever evolving, just like the rendering engine for Microsoft Edge
As a result of this change, JSRT APIs have also split into two
- Legacy JSRT APIs, which use jscript9.dll and provide full backward compatibility for Classic (Win32) Windows applications that were built using JSRT APIs that shipped with Windows8.1/IE11
- Edge JSRT APIs, which use Chakra.dll and become the actively developed JSRT APIs that leverage the continuous performance and language updates that will be coming to Chakra
All of the design choices mentioned in the above section are still supported in Edge JSRT. However, unlike the legacy JSRT APIs, Edge JSRT APIs enable support for hosting Chakra in any Universal Windows applications providing scripts native access to the underlying platform, provide ECMAScript6 support on par with ES6 support enabled by default in Microsoft Edge, and enables debugging of scripts in Universal Windows applications via Visual Studio. The whitepaper on Targeting Edge vs. Legacy Engine with JSRT APIs provides more information about the API split and how to target Edge JSRT APIs.
JSRT and Universal Windows Applications
Universal Windows platform supported by Windows 10 allows developers to use the same code to build applications that run across a family of Windows 10 devices including Desktop, Mobile, Xbox, and IoT. To use Chakra for scriptability in Universal Windows applications, developers can use all the Edge JSRT APIs, with the exception of the following profiling APIs – JsStartProfiling, JsStopProfiling, JsEnumerateHeap, and JsIsEnumeratingHeap, which are currently supported only in Classic (Win32) Windows applications.
Edge JSRT APIs also allow scripts to natively access UWP APIs. An example of this feature is the uwp npm package that allows UWP access in Node.js apps running on Windows 10 using Chakra. The JsProjectWinRTNamespace allows exposing a UWP namespace to scripts. The following example utilizes UWP APIs to create an http client to get content from Uri:
While Universal Windows applications have full support, to use asynchronous UWP APIs and events in a Classic (Win32) Windows application, a COM initialized delegate pumping mechanism needs to be enabled through JsSetProjectionEnqueueCallback. A sample is provided here.
ECMAScript 6 Language Support
Scripts using ES6 language features require no setup to run with Edge JSRT, except for ES6 Promises. For ES6 promises, a hosting application needs to provide an EnqueueJob abstract operation to queue up the promise tasks. JsSetPromiseContinuationCallback allows application to provide an EnqueueJob style callback to process the promise task queue. The following sample showcases how to store the promise tasks and execute them after the current execution context is finished:
Apart from providing ES6 support for scripts, Edge JSRT also provides APIs to maneuver new ES6 types and objects, such as Symbol or TypedArray, in native code for better JS/native integration and performance.
JSRT APIs support script debugging with Visual Studio. In legacy JSRT, the host needs to provide an IDebugApplication pointer to put the script context in debug mode. In Edge JSRT, instead of using IDebugApplication, scripts can be debugged using the following steps:
- In Visual Studio, right click on your project -> Select “Properties” -> Select “Debugging” -> In “Debugger Type”, select “Script Only” or “Script and Native”.
- In your application, after creating an execution context, call JsStartDebugging to put the current context in debug mode. When working with multiple contexts, JsStartDebugging should be called every time a new context is set as current context.
- Debug the script!
We are excited to share some of the JSRT features that have been long completed – rental threading, script serialization, memory & CPU throttling, and the more recent Edge JSRT specific updates – availability in Universal Windows Applications, native UWP access and ECMAScript 6 language support. These changes put together make Chakra a great option to add scriptability to applications and services running on Windows10.
The JSRT APIs with all features mentioned above are available in the latest Windows 10 Insider Preview and Windows SDK, which can be download from here. A sample Universal Windows application and the JSRT API documentation are resources that might be helpful to get started. We are eager to see applications use Chakra for scriptability and would love to hear your feedback to advance these APIs. You could reach us and share your feedback on Twitter at @MSEdgeDev or on Connect. Thanks!