Title: button.bar = nil in HideBlizzard.lua causes a ~300ms freeze on every shapeshift form change (MoP Classic) #2429


Open
  • prof1x created this issue Jul 13, 2026

    Client: World of Warcraft Classic — Mists of Pandaria (5.5.x)
    Class affected: Warlock (Demonology, Metamorphosis toggle), but likely any class with temp shapeshift bar swaps
    Bartender4 version: current MoP Classic release

    Summary

    Toggling Metamorphosis (entering or leaving the form) causes a single-frame stall of roughly 300–400 ms. The stall is fully reproducible with all Bartender4 bars disabled and even with an empty/default profile, as long as Bartender4 itself is loaded. After bisecting HideBlizzard(), the freeze comes down to a single line in hideActionButton():

    local function hideActionButton(button)
    	if not button then return end
    
    	button:Hide()
    	button:UnregisterAllEvents()
    	button:SetAttribute("statehidden", true)
    
    	button.bar = nil   -- <-- this line
    end

     

    Commenting out button.bar = nil (and only that line — Hide/UnregisterAllEvents/SetAttribute all restored) completely removes the freeze. Restoring the line brings the freeze back.

    Investigation details

    • /etrace shows that the entire form-change event burst (UPDATE_SHAPESHIFT_FORM, multiple ACTIONBAR_SLOT_CHANGED, ~11× SPELL_UPDATE_ICON, SPELLS_CHANGED) is processed in one frame that takes 0.3–0.4 s (frame counter in etrace shows "1 frame" for a 335–406 ms gap).
    • The etrace also shows Blizzard's native ActionButton.OnActionChanged callbacks firing on ~30 of the hidden Blizzard buttons during that same frame, i.e. Blizzard code still touches these buttons on form changes even though they are hidden, unregistered, and parented to the UIHider.
    • CPU profiling (scriptProfile 1) attributes only ~20 ms to addon Lua during the toggle, so the remaining ~300 ms is spent inside the client engine, not in addon code — which is consistent with the cost being taint/secure-state bookkeeping triggered when Blizzard's secure code reads the addon-modified bar field on those buttons. taintLog is 0, and no Lua errors are raised (verified with a custom error handler), so the exact engine mechanism is unclear — but the correlation with that single line is 100% reproducible.
    • Freeze does not scale with the number of Bartender bars/buttons (reproducible with all BT4 bars disabled) and does not depend on the profile, Masque, or any other addons (tested with only Bartender4 + LibActionButton enabled).

    Suggested fix

    Remove (or make conditional for Classic clients) the button.bar = nil line in hideActionButton() in HideBlizzard.lua. As far as I can tell, bar on the Blizzard action buttons is only read by Blizzard's own code; Bartender4 never reads it, so clearing it only serves to sever the button→bar link — and on this client that severed link makes every shapeshift-triggered touch of the hidden buttons pathologically expensive. With the line removed, the hidden buttons behave normally (still hidden, still event-free, still statehidden), and form changes are smooth.

    Steps to reproduce

    1. MoP Classic, Demonology Warlock, Bartender4 enabled (default profile is enough; all other addons disabled).
    2. Toggle Metamorphosis on/off.
    3. Observe a ~300 ms hitch on every toggle.
    4. Comment out button.bar = nil in HideBlizzard.lua, /reload, toggle again — hitch is gone.

To post a comment, please login or register a new account.