From 32c5c9251dfeb91037f2ba06503c5de16fef3ae4 Mon Sep 17 00:00:00 2001 From: "Enzo Persillet (Tutez)" Date: Thu, 5 Mar 2026 03:22:08 +0100 Subject: [PATCH] perf: cache instance fields in timelines Cache Type.getInstanceFields() results per class name in SymbolTimeline and AnimateTimeline to avoid repeated reflection during clip attachment/update. This reduces CPU and GC pressure when many symbols are instantiated. --- src/swf/exporters/animate/AnimateTimeline.hx | 30 +++++++++++++++++-- .../swflite/timeline/SymbolTimeline.hx | 30 +++++++++++++++++-- 2 files changed, 56 insertions(+), 4 deletions(-) diff --git a/src/swf/exporters/animate/AnimateTimeline.hx b/src/swf/exporters/animate/AnimateTimeline.hx index 5e4046e..4bac758 100644 --- a/src/swf/exporters/animate/AnimateTimeline.hx +++ b/src/swf/exporters/animate/AnimateTimeline.hx @@ -34,6 +34,8 @@ import hscript.Parser; @:access(openfl.geom.ColorTransform) class AnimateTimeline extends Timeline { + @:noCompletion private static var __instanceFieldsCacheByClassName:Map> = new Map(); + #if 0 // Suppress checkstyle warning private static var __unusedImport:Array> = [ @@ -420,7 +422,7 @@ class AnimateTimeline extends Timeline } #if !openfljs - __instanceFields = Type.getInstanceFields(Type.getClass(__sprite)); + __instanceFields = __getCachedInstanceFields(__sprite); #end enterFrame(1); @@ -496,7 +498,7 @@ class AnimateTimeline extends Timeline displayObject.filters = filters; } - else + else if (reset && displayObject.filters != null) { displayObject.filters = null; } @@ -547,6 +549,30 @@ class AnimateTimeline extends Timeline } } + @:noCompletion private static function __getCachedInstanceFields(displayObject:DisplayObject):Array + { + var clazz = Type.getClass(displayObject); + if (clazz == null) + { + return []; + } + + var className = Type.getClassName(clazz); + if (className == null) + { + return Type.getInstanceFields(clazz); + } + + var cached = __instanceFieldsCacheByClassName.get(className); + if (cached == null) + { + cached = Type.getInstanceFields(clazz); + __instanceFieldsCacheByClassName.set(className, cached); + } + + return cached; + } + #if hscript @:noCompletion private function __createScriptCallback(parser:Parser, scriptSource:String):MovieClip->Void { diff --git a/src/swf/exporters/swflite/timeline/SymbolTimeline.hx b/src/swf/exporters/swflite/timeline/SymbolTimeline.hx index 4fb5274..87b0982 100644 --- a/src/swf/exporters/swflite/timeline/SymbolTimeline.hx +++ b/src/swf/exporters/swflite/timeline/SymbolTimeline.hx @@ -39,6 +39,8 @@ import hscript.Parser; @:access(openfl.geom.ColorTransform) class SymbolTimeline extends Timeline { + @:noCompletion private static var __instanceFieldsCacheByClassName:Map> = new Map(); + #if openfljs @:noCompletion private static var __useParentFPS:Bool; #else @@ -256,7 +258,7 @@ class SymbolTimeline extends Timeline } #if !openfljs - __instanceFields = Type.getInstanceFields(Type.getClass(movieClip)); + __instanceFields = __getCachedInstanceFields(movieClip); #end enterFrame(1); @@ -468,7 +470,7 @@ class SymbolTimeline extends Timeline displayObject.filters = filters; } - else + else if (reset && displayObject.filters != null) { displayObject.filters = null; } @@ -511,6 +513,30 @@ class SymbolTimeline extends Timeline } } } + + @:noCompletion private static function __getCachedInstanceFields(displayObject:DisplayObject):Array + { + var clazz = Type.getClass(displayObject); + if (clazz == null) + { + return []; + } + + var className = Type.getClassName(clazz); + if (className == null) + { + return Type.getInstanceFields(clazz); + } + + var cached = __instanceFieldsCacheByClassName.get(className); + if (cached == null) + { + cached = Type.getInstanceFields(clazz); + __instanceFieldsCacheByClassName.set(className, cached); + } + + return cached; + } } #if !openfl_debug