Marshalling/Proxying between V8 and .Net

Feb 22, 2014 at 12:05 AM
Hey guys, first off this project is fantastic. I'm really surprised by the ease of use here. My main question is that of performance and best practices.
  • 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?
  • Are there any related recommended best practices?
  • What is the relative cost of adding host types?
  • What happens when "Compile" occurs? What costs does this mitigate?
  • Do you see this as something that could be used enterprise-scale or more of a utility?
Thanks!
Eric
Coordinator
Feb 24, 2014 at 6:07 AM
Edited Feb 24, 2014 at 12:52 PM
Hi Eric,

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 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 to dynamic 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.
Note that these are optimization ideas, not rules. ClearScript aims to combine ease of use with reasonable performance in most cases.

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 V8's compiled script representation are not well documented. Presumably 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!
Feb 24, 2014 at 5:55 PM
Thanks for the thorough reply!
Mar 17, 2014 at 4:53 PM
Edited Mar 17, 2014 at 4:53 PM
If this helps anybody, I encapsulated some of the ideas in this post into a project:
https://github.com/eswann/ClearScript.Manager

And a Nuget package:
https://www.nuget.org/packages/ClearScript.Manager/