script optimization - #1044
Conversation
Actually, this is certain. However, there's one thing I'm not entirely sure about — for such small collections, is hash-based lookup actually faster than linear search using contains()? Hash reading involves some computation, and the memory might not be very contiguous, so it's hard to guess which one performs better. I think it would be more appropriate to let the test results speak for themselves. |
Okay, I'll take a look and see if this change can be made. |
|
Through my testing, I found that |
|
Is this good to go? |
Yes. |
|
I wonder if it can be optimized further, but for now this is fine |
|
One more thing — CodenameCrew/hscript-improved#21 may also need to be merged in a relatively synchronized manner. This is because the original parser re‑initialization code didn't fully reset all parameters, which could sometimes cause script errors to be reported even when the script itself was actually fine. I fixed this issue in that pull request. |
Actually, I originally had more changes in mind, but I ended up canceling them due to concerns about potential compatibility issues. In reality, new objects are still being created every frame — and even new classes in some cases. If I had removed those allocations, scripts might end up holding references to classes that no longer exist in the next frame, or values might change unexpectedly. That said, such scenarios seem to be quite rare in practice; most mods don't rely on this behavior and tend to reuse individual parameters instead. If you think this trade‑off is acceptable, I can open a new PR with those changes. |
|
Never mind — I think it would be better to open a new PR tomorrow so you can see exactly what changes are involved. |
Optimized script classes to reduce memory usage, GC pressure, and improve performance.
Script.hx:
Type.resolveClasscalls don't need to be rebuilt every time a script is created.stateandwindoware excluded from this cache because they can change — they remain dynamic and are still reassigned on each creation._EMPTY_ARGSvariable for use in places where an empty array is needed. Previously,var result = onCall(func, parameters == null ? [] : parameters);would create a new array whenparameterswas null, which was unnecessary. This optimization has been moved to Optimization hscript-improved#21, where the same empty array reuse is also applied.HScript.hx:
__parserPoolvariable to reuse theParserinstance. Since theParserclass is relatively large, reusing it may improve script startup speed and slightly reduce memory usage.if (!interp.variables.exists(funcName)) return null;becauseinterp.variables.get(funcName);combined with the subsequentif (func != null && Reflect.isFunction(func))effectively already serves as a null check.set()could cause incorrect caching invarLocationCache. Addedinterp.invalidateCache()to clear the cache when necessary.MultiThreadedScript.hx:
Array-basedcontains()O(n) operation withMap'sexists()O(1) lookup for the__variablesvariable.ScriptPack.hx:
e.call(func, [event])would create a new array every time — and it did this for every single script. This change significantly reduces unnecessary memory allocations.GlobalScript.hx:
call("preStateSwitch", [])to eliminate the[]empty array allocation.These changes have been tested with mods containing a large number of scripts, and no issues were observed.