From b48b9da3e4fc4a760a5f269fd35f605a41c6542d Mon Sep 17 00:00:00 2001 From: RoosterDragon Date: Fri, 6 Nov 2015 21:49:25 +0000 Subject: [PATCH 1/3] Add a missing GC.SuppressFinalize call in LuaReference. This missing call meant even if the caller took care to dispose a LuaReference it was still being finalized. Adding this call prevents this needless finalization from taking place. --- Eluant/LuaReference.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Eluant/LuaReference.cs b/Eluant/LuaReference.cs index b5088c6..1a16d50 100644 --- a/Eluant/LuaReference.cs +++ b/Eluant/LuaReference.cs @@ -1,10 +1,12 @@ // // LuaReference.cs // -// Author: +// Authors: // Chris Howie +// Tom Roostan // // Copyright (c) 2013 Chris Howie +// Copyright (c) 2015 Tom Roostan // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -50,6 +52,7 @@ internal LuaReference(LuaRuntime runtime, int reference) public sealed override void Dispose() { Dispose(true); + GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) From 112dd1f3c62958e91d9082b0028514047155f097 Mon Sep 17 00:00:00 2001 From: RoosterDragon Date: Fri, 6 Nov 2015 00:38:08 +0000 Subject: [PATCH 2/3] Cache MetamethodAttributes used in LuaClrObjectValue. This allows us to speed up LuaRuntime.PushCustomClrObject when pushing an object multiple times since we can do this costly reflection on construction on the object and retain it thereafter. Calling code that uses LuaTransparentClrObject benefits since we can cache this information for the proxy type. It can also benefit calling code that is able to reuse a LuaCustomClrObject instance across multiple Lua calls. --- Eluant/LuaClrObjectValue.cs | 15 ++++++++++++++- Eluant/LuaCustomClrObject.cs | 12 +++++++++++- Eluant/LuaOpaqueClrObject.cs | 10 +++++++++- Eluant/LuaRuntime.cs | 9 ++++----- Eluant/LuaTransparentClrObject.cs | 11 ++++++++++- 5 files changed, 48 insertions(+), 9 deletions(-) diff --git a/Eluant/LuaClrObjectValue.cs b/Eluant/LuaClrObjectValue.cs index d8e4995..1498468 100644 --- a/Eluant/LuaClrObjectValue.cs +++ b/Eluant/LuaClrObjectValue.cs @@ -1,10 +1,12 @@ // // LuaClrObjectValue.cs // -// Author: +// Authors: // Chris Howie +// Tom Roostan // // Copyright (c) 2013 Chris Howie +// Copyright (c) 2015 Tom Roostan // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -25,6 +27,8 @@ // THE SOFTWARE. using System; +using System.Linq; +using Eluant.ObjectBinding; namespace Eluant { @@ -54,6 +58,15 @@ public override string ToString() internal abstract object BackingCustomObject { get; } + internal abstract MetamethodAttribute[] BackingCustomObjectMetamethods { get; } + + static internal MetamethodAttribute[] Metamethods(Type backingCustomObjectType) + { + return backingCustomObjectType.GetInterfaces() + .SelectMany(iface => iface.GetCustomAttributes(typeof(MetamethodAttribute), false).Cast()) + .ToArray(); + } + internal override object ToClrType(Type type) { if (type == null) { throw new ArgumentNullException("type"); } diff --git a/Eluant/LuaCustomClrObject.cs b/Eluant/LuaCustomClrObject.cs index 76d0cb0..18dda5b 100644 --- a/Eluant/LuaCustomClrObject.cs +++ b/Eluant/LuaCustomClrObject.cs @@ -1,10 +1,12 @@ // // LuaCustomClrObject.cs // -// Author: +// Authors: // Chris Howie +// Tom Roostan // // Copyright (c) 2013 Chris Howie +// Copyright (c) 2015 Tom Roostan // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -25,6 +27,7 @@ // THE SOFTWARE. using System; +using Eluant.ObjectBinding; namespace Eluant { @@ -51,6 +54,13 @@ internal override object BackingCustomObject { get { return ClrObject; } } + + private MetamethodAttribute[] metamethods; + + internal override MetamethodAttribute[] BackingCustomObjectMetamethods + { + get { return metamethods ?? (metamethods = Metamethods(BackingCustomObject.GetType())); } + } } } diff --git a/Eluant/LuaOpaqueClrObject.cs b/Eluant/LuaOpaqueClrObject.cs index 98ec940..1531f16 100644 --- a/Eluant/LuaOpaqueClrObject.cs +++ b/Eluant/LuaOpaqueClrObject.cs @@ -1,10 +1,12 @@ // // LuaOpaqueClrObject.cs // -// Author: +// Authors: // Chris Howie +// Tom Roostan // // Copyright (c) 2013 Chris Howie +// Copyright (c) 2015 Tom Roostan // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -25,6 +27,7 @@ // THE SOFTWARE. using System; +using Eluant.ObjectBinding; namespace Eluant { @@ -51,6 +54,11 @@ internal override object BackingCustomObject { get { return null; } } + + internal override MetamethodAttribute[] BackingCustomObjectMetamethods + { + get { return null; } + } } } diff --git a/Eluant/LuaRuntime.cs b/Eluant/LuaRuntime.cs index b1d97e9..889fd67 100644 --- a/Eluant/LuaRuntime.cs +++ b/Eluant/LuaRuntime.cs @@ -1,10 +1,12 @@ // // LuaRuntime.cs // -// Author: +// Authors: // Chris Howie +// Tom Roostan // // Copyright (c) 2013 Chris Howie +// Copyright (c) 2015 Tom Roostan // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -762,10 +764,7 @@ internal void PushCustomClrObject(LuaClrObjectValue obj) LuaApi.lua_settable(LuaState, -3); // For all others, we use MetamethodAttribute on the interface to make this code less repetitive. - var metamethods = obj.BackingCustomObject.GetType().GetInterfaces() - .SelectMany(iface => iface.GetCustomAttributes(typeof(MetamethodAttribute), false).Cast()); - - foreach (var metamethod in metamethods) { + foreach (var metamethod in obj.BackingCustomObjectMetamethods) { LuaApi.lua_pushstring(LuaState, metamethod.MethodName); Push(metamethodCallbacks[metamethod.MethodName]); LuaApi.lua_settable(LuaState, -3); diff --git a/Eluant/LuaTransparentClrObject.cs b/Eluant/LuaTransparentClrObject.cs index 592884b..42b6daa 100644 --- a/Eluant/LuaTransparentClrObject.cs +++ b/Eluant/LuaTransparentClrObject.cs @@ -1,10 +1,12 @@ // // LuaTransparentClrObject.cs // -// Author: +// Authors: // Chris Howie +// Tom Roostan // // Copyright (c) 2013 Chris Howie +// Copyright (c) 2015 Tom Roostan // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -71,8 +73,15 @@ internal override object BackingCustomObject get { return proxy; } } + internal override MetamethodAttribute[] BackingCustomObjectMetamethods + { + get { return TransparentClrObjectProxy.Metamethods; } + } + private class TransparentClrObjectProxy : ILuaTableBinding, ILuaEqualityBinding { + public static readonly MetamethodAttribute[] Metamethods = LuaClrObjectValue.Metamethods(typeof(TransparentClrObjectProxy)); + private LuaTransparentClrObject clrObject; public TransparentClrObjectProxy(LuaTransparentClrObject obj) From 4c483a4a6c2dfe461b9b5c672e6cccc8a70b8450 Mon Sep 17 00:00:00 2001 From: RoosterDragon Date: Tue, 29 Dec 2015 00:17:01 +0000 Subject: [PATCH 3/3] Cache metamethods in each LuaRuntime. This reflection is expensive, so by allowing it to be cached against each runtime we can remove most of the cost. Since each runtime is likely to only deal with a handful of custom objects, it shouldn't be an issue for memory usage. --- Eluant/LuaClrObjectValue.cs | 2 +- Eluant/LuaCustomClrObject.cs | 4 ++-- Eluant/LuaOpaqueClrObject.cs | 4 ++-- Eluant/LuaRuntime.cs | 16 +++++++++++++++- Eluant/LuaTransparentClrObject.cs | 4 ++-- 5 files changed, 22 insertions(+), 8 deletions(-) diff --git a/Eluant/LuaClrObjectValue.cs b/Eluant/LuaClrObjectValue.cs index 1498468..be45862 100644 --- a/Eluant/LuaClrObjectValue.cs +++ b/Eluant/LuaClrObjectValue.cs @@ -58,7 +58,7 @@ public override string ToString() internal abstract object BackingCustomObject { get; } - internal abstract MetamethodAttribute[] BackingCustomObjectMetamethods { get; } + internal abstract MetamethodAttribute[] BackingCustomObjectMetamethods(LuaRuntime runtime); static internal MetamethodAttribute[] Metamethods(Type backingCustomObjectType) { diff --git a/Eluant/LuaCustomClrObject.cs b/Eluant/LuaCustomClrObject.cs index 18dda5b..946cffc 100644 --- a/Eluant/LuaCustomClrObject.cs +++ b/Eluant/LuaCustomClrObject.cs @@ -57,9 +57,9 @@ internal override object BackingCustomObject private MetamethodAttribute[] metamethods; - internal override MetamethodAttribute[] BackingCustomObjectMetamethods + internal override MetamethodAttribute[] BackingCustomObjectMetamethods(LuaRuntime runtime) { - get { return metamethods ?? (metamethods = Metamethods(BackingCustomObject.GetType())); } + return metamethods ?? (metamethods = runtime.CachedMetamethods(BackingCustomObject.GetType())); } } } diff --git a/Eluant/LuaOpaqueClrObject.cs b/Eluant/LuaOpaqueClrObject.cs index 1531f16..b6ebd45 100644 --- a/Eluant/LuaOpaqueClrObject.cs +++ b/Eluant/LuaOpaqueClrObject.cs @@ -55,9 +55,9 @@ internal override object BackingCustomObject get { return null; } } - internal override MetamethodAttribute[] BackingCustomObjectMetamethods + internal override MetamethodAttribute[] BackingCustomObjectMetamethods(LuaRuntime runtime) { - get { return null; } + return null; } } } diff --git a/Eluant/LuaRuntime.cs b/Eluant/LuaRuntime.cs index 889fd67..edbe744 100644 --- a/Eluant/LuaRuntime.cs +++ b/Eluant/LuaRuntime.cs @@ -78,6 +78,7 @@ protected GCHandle SelfHandle private const string OPAQUECLROBJECT_METATABLE = "eluant_opaqueclrobject"; private Dictionary metamethodCallbacks = new Dictionary(); + private Dictionary metamethodAttributes = new Dictionary(); private LuaFunction createManagedCallWrapper; @@ -764,7 +765,7 @@ internal void PushCustomClrObject(LuaClrObjectValue obj) LuaApi.lua_settable(LuaState, -3); // For all others, we use MetamethodAttribute on the interface to make this code less repetitive. - foreach (var metamethod in obj.BackingCustomObjectMetamethods) { + foreach (var metamethod in obj.BackingCustomObjectMetamethods(this)) { LuaApi.lua_pushstring(LuaState, metamethod.MethodName); Push(metamethodCallbacks[metamethod.MethodName]); LuaApi.lua_settable(LuaState, -3); @@ -777,6 +778,19 @@ internal void PushCustomClrObject(LuaClrObjectValue obj) } } + internal MetamethodAttribute[] CachedMetamethods(Type backingCustomObjectType) + { + MetamethodAttribute[] metamethods; + if (metamethodAttributes.TryGetValue(backingCustomObjectType, out metamethods)) { + return metamethods; + } + + metamethods = LuaClrObjectValue.Metamethods(backingCustomObjectType); + metamethodAttributes.Add(backingCustomObjectType, metamethods); + + return metamethods; + } + private int NewindexCallback(IntPtr state) { return LuaToClrBoundary(state, toDispose => { diff --git a/Eluant/LuaTransparentClrObject.cs b/Eluant/LuaTransparentClrObject.cs index 42b6daa..936136e 100644 --- a/Eluant/LuaTransparentClrObject.cs +++ b/Eluant/LuaTransparentClrObject.cs @@ -73,9 +73,9 @@ internal override object BackingCustomObject get { return proxy; } } - internal override MetamethodAttribute[] BackingCustomObjectMetamethods + internal override MetamethodAttribute[] BackingCustomObjectMetamethods(LuaRuntime runtime) { - get { return TransparentClrObjectProxy.Metamethods; } + return TransparentClrObjectProxy.Metamethods; } private class TransparentClrObjectProxy : ILuaTableBinding, ILuaEqualityBinding