public void LuaCollectsObjectsAfterReferencesAreDisposed() { // In this test we repeatedly create and destroy table references to make sure the Lua GC is able to collect // them. We create a multiple of 1,000 tables since the runtime rewrites the reference table every 1,000 // reference destructions. This should return the runtime to exactly the same state as it was at the // beginning of the test. using (var runtime = new MemoryConstrainedLuaRuntime()) { using (var collect = (LuaFunction)runtime.Globals["collectgarbage"]) { collect.Call().Dispose(); var begin = runtime.MemoryUse; // Stress the GC a bit by creating and disposing tables, in batches of 100. for (int i = 0; i < 1000; ++i) { foreach (var t in Enumerable.Range(1, 100).Select(j => runtime.CreateTable()).ToList()) { t.Dispose(); } } // Now create a whole bunch of tables all at once. foreach (var t in Enumerable.Range(1, 10000).Select(j => runtime.CreateTable()).ToList()) { t.Dispose(); } collect.Call().Dispose(); Assert.AreEqual(begin, runtime.MemoryUse); } } }
public void NoMemoryErrorWhileInClr() { if (LuaRuntime.LUAJIT && IntPtr.Size == 8) { Assert.Ignore(); } using (var runtime = new MemoryConstrainedLuaRuntime()) { Action fn = () => { runtime.MaxMemoryUse = runtime.MemoryUse + 1; using (var x = runtime.CreateTable()) { x[1] = "This is a string that is way more than one byte long."; } runtime.MaxMemoryUse = long.MaxValue; }; using (var callback = runtime.CreateFunctionFromDelegate(fn)) { runtime.Globals["callback"] = callback; } runtime.DoString("callback()").Dispose(); } }
public void BasicMemoryConstraint() { using (var runtime = new MemoryConstrainedLuaRuntime()) { runtime.MaxMemoryUse = runtime.MemoryUse + 10 * 1024 * 1024; // Exponentially allocate memory. runtime.DoString("x = '.' while true do x = x .. x end"); } }
public void BasicMemoryConstraint() { if (LuaRuntime.LUAJIT && IntPtr.Size == 8) { Assert.Ignore(); } using (var runtime = new MemoryConstrainedLuaRuntime()) { runtime.MaxMemoryUse = runtime.MemoryUse + 10 * 1024 * 1024; // Exponentially allocate memory. runtime.DoString("x = '.' while true do x = x .. x end"); } }
public void NoMemoryErrorWhileInClr() { using (var runtime = new MemoryConstrainedLuaRuntime()) { Action fn = () => { runtime.MaxMemoryUse = runtime.MemoryUse + 1; using (var x = runtime.CreateTable()) { x[1] = "This is a string that is way more than one byte long."; } runtime.MaxMemoryUse = long.MaxValue; }; using (var callback = runtime.CreateFunctionFromDelegate(fn)) { runtime.Globals["callback"] = callback; } runtime.DoString("callback()").Dispose(); } }
public ScriptContext(World world, WorldRenderer worldRenderer, IEnumerable <string> scripts) { runtime = new MemoryConstrainedLuaRuntime(); World = world; WorldRenderer = worldRenderer; knownActorCommands = Game.modData.ObjectCreator .GetTypesImplementing <ScriptActorProperties>() .ToArray(); ActorCommands = new Cache <ActorInfo, Type[]>(FilterActorCommands); PlayerCommands = Game.modData.ObjectCreator .GetTypesImplementing <ScriptPlayerProperties>() .ToArray(); runtime.DoBuffer(GlobalFileSystem.Open(Path.Combine("lua", "scriptwrapper.lua")).ReadAllText(), "scriptwrapper.lua").Dispose(); tick = (LuaFunction)runtime.Globals["Tick"]; // Register globals using (var fn = runtime.CreateFunctionFromDelegate((Action <string>)FatalError)) runtime.Globals["FatalError"] = fn; runtime.Globals["MaxUserScriptInstructions"] = MaxUserScriptInstructions; using (var registerGlobal = (LuaFunction)runtime.Globals["RegisterSandboxedGlobal"]) { using (var fn = runtime.CreateFunctionFromDelegate((Action <string>)Console.WriteLine)) registerGlobal.Call("print", fn).Dispose(); // Register global tables var bindings = Game.modData.ObjectCreator.GetTypesImplementing <ScriptGlobal>(); foreach (var b in bindings) { var ctor = b.GetConstructors(BindingFlags.Public | BindingFlags.Instance).FirstOrDefault(c => { var p = c.GetParameters(); return(p.Length == 1 && p.First().ParameterType == typeof(ScriptContext)); }); if (ctor == null) { throw new InvalidOperationException("{0} must define a constructor that takes a ScriptContext context parameter".F(b.Name)); } var binding = (ScriptGlobal)ctor.Invoke(new[] { this }); using (var obj = binding.ToLuaValue(this)) registerGlobal.Call(binding.Name, obj).Dispose(); } } // System functions do not count towards the memory limit runtime.MaxMemoryUse = runtime.MemoryUse + MaxUserScriptMemory; using (var loadScript = (LuaFunction)runtime.Globals["ExecuteSandboxedScript"]) { foreach (var s in scripts) { loadScript.Call(s, GlobalFileSystem.Open(s).ReadAllText()).Dispose(); } } }
public ScriptContext(World world, WorldRenderer worldRenderer, IEnumerable <string> scripts) { LuaRuntime.LoadAndroidAsset += (string filename) => { using (StreamReader sr = new StreamReader(Android.App.Application.Context.Assets.Open(Platform.ResolvePath(".", "lua", filename)))) { var luaContent = sr.ReadToEnd(); if (!string.IsNullOrEmpty(luaContent)) { runtime.LoadBuffer(luaContent, filename); } } }; runtime = new MemoryConstrainedLuaRuntime(); this.World = world; this.WorldRenderer = worldRenderer; knownActorCommands = WarGame.ModData.ObjectCreator.GetTypesImplementing <ScriptActorProperties>().ToArray(); ActorCommands = new Cache <ActorInfo, Type[]>(FilterActorCommands); var knownPlayerCommands = WarGame.ModData.ObjectCreator.GetTypesImplementing <ScriptPlayerProperties>().ToArray(); PlayerCommands = FilterCommands(world.Map.Rules.Actors["player"], knownPlayerCommands); runtime.Globals["GameDir"] = Platform.SupportDir; //var directory = Directory.GetCurrentDirectory(); //var directory = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); //var directory = Android.App.Application.Context.ApplicationContext.PackageResourcePath; var directory = Platform.ResolvePath(".", "lua", "scriptwrapper.lua"); string content; using (StreamReader sr = new StreamReader(Android.App.Application.Context.Assets.Open(Platform.ResolvePath(".", "lua", "scriptwrapper.lua")))) { content = sr.ReadToEnd(); } //runtime.DoBuffer(File.Open(directory, FileMode.Open, FileAccess.Read).ReadAllText(), "scriptwrapper.lua").Dispose(); runtime.DoBuffer(content, "scriptwrapper.lua").Dispose(); tick = (LuaFunction)runtime.Globals["Tick"]; //Register globals using (var fatalError = runtime.CreateFunctionFromDelegate((Action <string>)FatalError)) { runtime.Globals["FatalError"] = fatalError; } runtime.Globals["MaxUserScriptInstructions"] = MaxUserScriptInstructions; using (var registerGlobal = (LuaFunction)runtime.Globals["RegisterSandboxedGlobal"]) { using (var log = runtime.CreateFunctionFromDelegate((Action <string>)LogDebugMessage)) { registerGlobal.Call("print", log).Dispose(); } //Register global tables var bindings = WarGame.ModData.ObjectCreator.GetTypesImplementing <ScriptGlobal>(); foreach (var bind in bindings) { var ctor = bind.GetConstructors(BindingFlags.Public | BindingFlags.Instance).FirstOrDefault(c => { var p = c.GetParameters(); return(p.Length == 1 && p.First().ParameterType == typeof(ScriptContext)); }); if (ctor == null) { throw new InvalidOperationException("{0} must define a constructor that takes a ScriptContext context parameter"); } var binding = (ScriptGlobal)ctor.Invoke(new[] { this }); using (var obj = binding.ToLuaValue(this)) registerGlobal.Call(binding.Name, obj).Dispose(); } } //System functions do not count towards the memory limit //系统函数不计入内存限制 runtime.MaxMemoryUse = runtime.MemoryUse + MaxUserScriptMemory; using (var loadScript = (LuaFunction)runtime.Globals["ExecuteSandboxedScript"]) { foreach (var s in scripts) { loadScript.Call(s, world.Map.Open(s).ReadAllText()).Dispose(); } } }