Now that the sample is out, I wanted to take a few posts to walk through some of the basics of hosting the Chakra engine in your application. Some of this will repeat the MSDN documentation a bit, but I’ll try and expand on some of the details.
Runtimes represent a single thread of execution, so more than one runtime can be active at the same time within a process, but within a runtime there will only ever be one active thread of execution. Runtimes are not tied to a particular system thread, however, but are rental threaded. That means that a runtime can move from one system thread to another provided that the runtime is not currently executing any code. So while a runtime is running code (or is in a host callback while running code), it cannot be moved to another thread. But if it’s not running anything, the host is free to use that runtime on another thread. This means that if a runtime isn’t active for some reason (maybe it’s waiting for something to happen), the thread is free to run something in another runtime.
When creating a runtime, a number of choices can be made about the behavior of the runtime. The most important is how background work will be done. By default, creating a runtime will create two additional threads: a GC thread for the garbage collector and JIT thread for the native code compiler. These threads allow garbage collection and JIT compilation to happen in the background while code is running in the foreground. There are two other configurations possible, though. If you don’t want any background work done, you can specify the
JsRuntimeAttributeDisableBackgroundWork flag, and all GC and JIT work will be done on the foreground on demand. Or you can choose to run the background work yourself by passing in a
JsThreadServiceCallback routine when you create the runtime. In that case, the runtime will call the callback when it has GC or JIT work that needs to be done. The callback can either run the work on any thread it likes, or it can return
false, meaning that the work should just be run on the foreground thread. Using a callback allows a host to pool GC and JIT threads across runtimes, for example.
Code that is running inside a runtime can be interrupted by calling
JsDisableRuntimeExecution. The way that interruption works is that all code compiled by the runtime inserts calls to a check routine that will fail if execution has been disabled. So code will continue to run, even after the disable API has been called, until it hits one of these checks. By default, these checks are fairly conservative to avoid impacting performance too much. In particular, we don’t insert checks in loops by default. This means you don’t have any additional overhead when running a tight loop, but it also means that if you happen to hit an infinite loop, your script will hang and will not be interruptible. If you specify the
JsRuntimeAttributeAllowScriptInterrupt flag, the runtime will insert additional script interruption checks into places like the bottom of loops so that script interruption becomes more reliable, at the cost of some small amount of performance.
There are some bookkeeping tasks that the runtime may need to do, particularly in longer-running runtimes. For example, if a lot of memory has been freed up by the GC, it can be advantageous to decommit memory pages that are no longer in use, freeing them up for use by the system. This kind of work is what we consider “idle” work, and if your host is long running enough, there can be benefit in passing in the
JsRuntimeEnableIdleProcessing flag and then periodically calling the
JsIdle API when the host is idle. If idle processing isn’t enabled and we need to do some bookkeeping work, we’ll typically do that when a script finishes running.
And, finally, there may be situations where a host might want to turn off some of the runtime capabilities for safety or security. If you don’t want scripts you run to be able to dynamically run code (i.e. call
eval or the
function constructor), you can specify the
JsRuntimeAttributeDisableEval flag. If you don’t want the JIT compiler to generate native code, and instead just run everything under the interpreter (for example, if you have some concern about native code generation in your process), you can specify the
JsRuntimeAttributeDisableNativeCodeGeneration flag. This last flag should be used with a great deal of caution–as you can imagine, JITted code is vastly more efficient than interpreted byte codes, so you’ll pay a significant penalty for turning off the JIT. Use only when absolutely necessary.
The last thing you can choose when creating a runtime is the version of the language you want. This is fairly straightforward–you can pick IE10 (corresponds to ES5), IE11 (ES5 + some ES6 features + some compatibility features like
__proto__), or “edge” which will give you the latest version. The edge version will float, so be warned–if your host is run on some future platform with some version higher than IE11 (whatever that will be), you’ll get that newest version. Caveat emptor.
I think that about covers it for runtimes. Up next will be execution contexts…
You should also follow me on Twitter here.