ClearScript Library
by ClearScript Library
2 min read

ClearScript 7.2 includes enhancements for sharing objects across V8 script engines and runtimes.

Introduction

In ClearScript 7.1 and earlier, passing a script object from one engine to another always results in the latter holding a “proxy to a proxy” – a special object that forwards property access to a managed proxy to the original script object.

The overhead of that arrangement is usually unavoidable, as script engines generally can’t be given direct access to foreign script objects.

However, there are specific scenarios in which alternate means of sharing are not only possible but preferable. ClearScript 7.2 enables the following exceptions to the normal behavior.

Engines That Share a V8 Runtime

Consider the following C# code:

using var runtime = new V8Runtime();
using var engine1 = runtime.CreateScriptEngine();
using var engine2 = runtime.CreateScriptEngine();

This creates a V8 runtime with two script engines – an arrangement that looks something like this:

Two Engines One Runtime

Now let’s create a script object in one engine and copy a reference to the other:

engine1.Execute("foo = { bar: 123 }");
engine2.Script.foo = engine1.Script.foo;

Executing this code in ClearScript 7.1 or earlier results in the following:

Two Engines One Runtime Double Proxy

With this setup, foo in engine2 is very expensive to access and may be missing some functionality. For example, JavaScript iteration protocols can’t be routed through the managed proxy.

This “double proxy” construction is usually required, as different script engines generally can’t access each other’s objects directly. In this instance, however, they can do just that – safely and without ClearScript’s involvement.

ClearScript 7.2 detects this case and produces the following configuration for the same code:

Two Engines One Runtime Shared Object

All script engines in the same V8 runtime can be given direct access to each other’s objects with full functionality, performance, and safety.

V8 Shared Array Buffers and Views

Suppose you create two V8 script engines, each within its own runtime:

using var engine1 = new V8ScriptEngine();
using var engine2 = new V8ScriptEngine();

In memory, this setup looks something like this:

Two Engines Two Runtimes

Normally, script engines in separate runtimes can’t share objects. However, SharedArrayBuffer was designed specifically for sharing memory across runtimes.

ClearScript 7.1 and earlier don’t support this form of sharing. Let’s say you create a shared array buffer in one script engine and copy a reference to the other:

engine1.Execute("sab = new SharedArrayBuffer(1024)");
engine2.Script.sab = engine1.Script.sab;

In ClearScript 7.1 and earlier, this code results in the following:

Two Engines Two Runtimes Double Proxy

In this configuration, sab in engine2 is a “double proxy” that really isn’t very useful. For example, you can’t create data views or typed arrays on top of it. Additionally, it incurs a lot of overhead, as all access is routed through the host back to engine1.

However, the same code in ClearScript 7.2 results in this:

Two Engines Two Runtimes Shared Backing Store

This arrangement supports the full functionality and performance of shared array buffers in both script engines, with independent access to the shared backing store.

Finally, note that shared data views and typed arrays – that is, data views and typed arrays backed by shared array buffers – are also marshaled in this manner, enabling easy memory sharing across V8 runtimes. You can use the standard Atomics object to synchronize access to these resources.

Good luck!