That's great news. I was beginning to think there may be a problem with my system or I was going crazy.
Any time
frame on getting the fix sent out?
Any time
frame on getting the fix sent out?
public static void TestClear(string script, bool disableGlobal)
{
var engine = new V8ScriptEngine(disableGlobal ? V8ScriptEngineFlags.DisableGlobalMembers : V8ScriptEngineFlags.None);
var sw = new Stopwatch();
sw.Start();
//var compiled = engine.Compile(script);
for (int i = 0; i < 10000; i++)
{
//engine.Evaluate(compiled);
engine.Evaluate(script);
}
sw.Stop();
Console.WriteLine("Clearscript" + (disableGlobal ? " with DisableGlobalMembers" : "") + " in " + sw.ElapsedMilliseconds);
}
var uniqueName = documentNameManager.GetUniqueName(documentName, "Script Document");
It is generating a new name even the same script is being executed twice. If I changed it to uniqueName = code.GetHashCode().ToString() // Just an example to create a unique code based on the script
If the same script is being executed twice, it will run extremely fast and efficient (Should have the same performance as compiling the script). for (int i = 0; i < 10000; i++)
{
engine.Run("Math.random() + " + i);
}
for (int i = 0; i < 10000; i++)
{
engine.Run("Math.random()");
}
V8ScriptEngine
for API compatibility. It allows you to expose a host object so that its members (rather than the object itself) appear as global properties within the script environment. Support for this feature is expensive on V8 even when it remains unused, so the only way to avoid the performance hit is to disable it completely.It is generating a new name even the same script is being executed twice.
If the same script is being executed twice, it will run extremely fast and efficient (Should have the same performance as compiling the script).
I think Javascript.NET has similar optimization because the first code below runs almost 8~10x slower than the second one
I just realize that the script still works even no unique name is generated (Using a same document name). Is there any pitfall or anything that I should be aware of if i plan on using that?
Heh, it looks like we were investigating simultaneously :)Yeah, love the extension method and ability to add host type (enum, static class) in Clearscript. Just trying to make it work.
Only that you might confuse script debuggers. Come to think of it, we've never tested debugging support without unique script names.Good point but maybe you can consider only turning on unique script name generation when this flag is present? V8ScriptEngineFlags.EnableDebugging
Good point but maybe you can consider only turning on unique script name generation when this flag is present? V8ScriptEngineFlags.EnableDebugging
public class Konsoll
{
public void log(dynamic o)
{
Console.WriteLine("Type:" + o.GetType());
Console.WriteLine(o.ToString());
// var p = (Microsoft.ClearScript.V8.V8ScriptItem)o;
// foreach (o.GetType().)
}
}
used like this using (var engine = new V8ScriptEngine())
{
engine.AddHostObject("console", new Konsoll());
string str;
while ((str = Console.ReadLine()) != "end")
{
engine.Execute(str);
}
}
Console.ReadLine();
}
How would you recommend to do this? It would be a very nice start if you made V8ScriptItem public. Maybe this object should rather be of type ExpandoObject? public class Konsoll
{
private void logg(int indent, dynamic o)
{
foreach (string egenskap in o.GetDynamicMemberNames())
{
Console.Write(new String(' ', indent));
Console.Write(egenskap);
Console.Write(':');
if (o[egenskap] is System.Dynamic.DynamicObject)
{
Console.WriteLine();
logg(indent + 1, o[egenskap]);
}
else
{
Console.WriteLine(o[egenskap].ToString());
}
}
}
public void log(dynamic o)
{
logg(0, o);
}
}
soengine.Execute("console.log({v1:4,v2:['a','bc', 'de', {f:'g'}],h:1,i:2,j:3,k:4});");
will outputv1:4
v2:
0:a
1:bc
2:de
3:
f:g
h:1
i:2
j:3
k:4
Clearscript is really cool stuff.V8ScriptItem
is just a concrete implementation of DynamicObject
. It doesn't have any additional members that would be useful to the host. The idea is that you either use its DynamicObject
members, or you use it via the dynamic
keyword.dynamic
causes the compiler to emit a dynamic callsite everywhere that variable is used, and that could get very expensive, especially when combined with the overhead of invoking V8. Consider rewriting your class something like this:publicclass Konsoll { privatevoid logg(int indent, DynamicObject od) { foreach (string egenskap in od.GetDynamicMemberNames()) { Console.Write(new String(' ', indent) + egenskap + ':'); object m = ((dynamic)od)[egenskap]; // this is the only dynamic callsitevar md = m as DynamicObject; if (md != null) { Console.WriteLine(); logg(indent + 1, md); } else { Console.WriteLine(m); } } } publicvoid log(DynamicObject od) { logg(0, od); } }
System.Console
and implement console
entirely in script code.public class Konsoll
{
public int Indent = 0;
public JavaScriptSerializer jss = new JavaScriptSerializer();
public void logs(string s)
{
object o = jss.DeserializeObject(s);
loggs(0, o);
}
private void loggs(int indent, object o)
{
if (o is Dictionary<string, object>)
{
foreach (KeyValuePair<string, object> kvp in (Dictionary<string, object>)o )
{
Console.Write(kvp.Key);
Console.Write(':');
loggs(indent + Indent, kvp.Value);
}
}
else if (o is Object[])
{
for (int i = 0; i < ((Object[])o).Length; i++)
{
Console.Write(i);
Console.Write(':');
loggs(indent + Indent, ((Object[])o)[i]);
}
}
else if (o == null)
{
Console.Write("null");
}
else
{
Console.Write(o.ToString());
}
}
private void logg(int indent, object o)
{
if (o is System.Dynamic.DynamicObject)
{
foreach (string egenskap in ((System.Dynamic.DynamicObject)o).GetDynamicMemberNames())
{
// Console.Write(new String(' ', indent));
Console.Write(egenskap);
Console.Write(':');
logg(indent + Indent, ((dynamic)o)[egenskap]);
}
}
else if (o == null)
{
Console.Write("null");
}
else
{
Console.Write(o.ToString());
}
}
public void log(object o)
{
logg(0, o);
}
}
Writing a test: using (var engine = new V8ScriptEngine())
{
engine.AddHostObject("console", new Konsoll());
engine.AddHostType("Console", typeof(System.Console));
var start3 = DateTime.Now;
for (int i = 0; i < 1000; i++)
{
engine.Execute("Console.Write(JSON.stringify({v1:4,v2:['a','bc', 'de', {f:'g'}],h:1,i:2,j:3,k:4}));");
}
var tid3 = DateTime.Now.Subtract(start3);
var start = DateTime.Now;
for (int i = 0; i < 1000; i++ )
{
engine.Execute("console.logs(JSON.stringify({v1:4,v2:['a','bc', 'de', {f:'g'}],h:1,i:2,j:3,k:4}));");
}
var tid = DateTime.Now.Subtract(start);
var start2 = DateTime.Now;
for (int i = 0; i < 1000; i++)
{
engine.Execute("console.log({v1:4,v2:['a','bc', 'de', {f:'g'}],h:1,i:2,j:3,k:4});");
}
var tid2 = DateTime.Now.Subtract(start2);
Console.WriteLine("static tok : " + tid.ToString());
Console.WriteLine("dynamic tok : " + tid2.ToString());
Console.WriteLine("Console.Write tok: " + tid3.ToString());
string str;
while ((str = Console.ReadLine()) != "end")
{
engine.Execute(str);
}
}
Getting the result:static tok : 00:00:05.3335333
dynamic tok : 00:00:05.6545654
Console.Write tok: 00:00:02.4172417
So the "static" console.logs alternative to dynamic only slightly cheaper. So the "static" console.logs alternative to dynamic only slightly cheaper.
o
as a dynamic parameter, which led to unnecessary dynamic calls to GetDynamicMemberNames()
and ToString()
. You also redundantly evaluated o[egenskap]
several times; each of those indexing operations is a dynamic call into the underlying script engine.I think, however, there is one weakness in GetDynamicMemberNames: that you don't know if its an array or object. Is there another way of knowing?
GetDynamicMemberNames()
returns the valid indices as strings. If that's not what you're looking for, remember that examining script objects is often easiest to do in script code:dynamic isScriptArray = engine.Evaluate("(function (x) { return x instanceof Array; })"); var result = engine.Evaluate("[1,2,3,4,5]"); if (isScriptArray(result)) { // do something }
Cannot load V8 interface assembly; verify that the following files are installed with your application: ClearScriptV8-32.dll, ClearScriptV8-64.dll, v8-ia32.dll, v8-x64.dllI run it on Win7 x64 on VS 2013 with installed all C++ packages.