Hi Eric,
Thanks for your kind words!
Unfortunately there isn't much documentation on ClearScript internals other than the code itself.
Generally speaking, each exposed .NET object or type is wrapped in an instance of the internal class
These cross-runtime references prevent their targets from being garbage-collected, so care should be taken to avoid cross-runtime circular references that leak memory. You can dispose a script object to release its managed reference, but an exposed .NET reference can only be released when its V8-side proxy is collected - and V8 is extremely leisurely when it comes to garbage collection.
Here are a few that come to mind:
Exposing a host type is very similar to exposing a host object; it just provides access to a different set of members - constructors, static methods, nested types, etc. If the host type is a class that defines extension methods, then exposing it adds overhead to the method binding process for all exposed objects.
The
ClearScript started life as a tool for automated testing, initially supporting only JScript and VBScript. In theory, V8 support should make it more suitable for server-side work, but to be honest, enterprise-level scalability has not been a priority for us so far. However, if you choose to evaluate ClearScript in that capacity, we'd love to get your feedback!
Cheers!
Thanks for your kind words!
Probably not a one-sentence answer, is there any documentation on how marshalling between the runtimes works so that I don't do something really terrible?
Unfortunately there isn't much documentation on ClearScript internals other than the code itself.
Generally speaking, each exposed .NET object or type is wrapped in an instance of the internal class
HostItem
, which is then referenced by a JavaScript proxy object on the V8 side. Conversely, when a script returns a reference to a native JavaScript object, ClearScript wraps it in an instance of the internal class ScriptItem
, which subclasses System.Dynamic.DynamicObject
to support .NET's dynamic infrastructure.These cross-runtime references prevent their targets from being garbage-collected, so care should be taken to avoid cross-runtime circular references that leak memory. You can dispose a script object to release its managed reference, but an exposed .NET reference can only be released when its V8-side proxy is collected - and V8 is extremely leisurely when it comes to garbage collection.
Are there any related recommended best practices?
Here are a few that come to mind:
- Try not to compile the same script code more than once. Instead, reuse the output of the
Compile()
method, or hold references to compiled script functions for repeated execution. - Minimize your use of cross-runtime calls. Consider whether an expression such as
a.b.c.d()
can be simplified by caching a direct reference to a nested object. This is relevant in both host-to-script and script-to-host scenarios. - Control your use of .NET's dynamic machinery. Instead of declaring a variable as
dynamic
, consider casting it todynamic
where necessary. Otherwise the compiler may emit expensive dynamic operations in inconspicuous places. - Remember that direct access is convenient but relatively expensive. It may be cheaper to transfer a complex object in one step (via JSON or something similar) than to access its properties and nested objects one by one from the other side.
- Consider sharing V8 runtimes among engine instances to reduce memory usage.
-
Use
V8ScriptEngineFlags.DisableGlobalMembers
in performance-critical applications.
What is the relative cost of adding host types?
Exposing a host type is very similar to exposing a host object; it just provides access to a different set of members - constructors, static methods, nested types, etc. If the host type is a class that defines extension methods, then exposing it adds overhead to the method binding process for all exposed objects.
What happens when "Compile" occurs? What costs does this mitigate?
The
Compile()
method returns an opaque script representation that can be executed multiple times without recompilation. Sorry about the recursive explanation, but the details of the compiled script representation are not well documented. We assume that compilation involves at least parsing the script source code into a syntax tree of some sort.
Do you see this as something that could be used enterprise-scale or more of a utility?
ClearScript started life as a tool for automated testing, initially supporting only JScript and VBScript. In theory, V8 support should make it more suitable for server-side work, but to be honest, enterprise-level scalability has not been a priority for us so far. However, if you choose to evaluate ClearScript in that capacity, we'd love to get your feedback!
Cheers!