Code is setup that if there are no eventResponders that have registered to do interrupt calls, don't have the systic code in place to look for it.
Also yield code. Now figures out if the user has any code that installs their own serialEventX methods, to call them, but if they have left the default weak pointer versions, to not call them in yield. Likewise will only look for eventRespnder events if the sketch has actually attached any events. If none of these conditions are true, yield will just check one flag and return.
T3.x Serial events cleanup
When you do a timer.begin(650) it actually triggered 652 ms from your current time. Did minimal update to see if delay time < 2 set to zero else decrement by 2...
Two issues:
if you called begin or begingRepeating while still in waiting queue, it would create circular state (code did not set state to waiting)
If you called begin on one in active list, it would first remove it from list, but did not update the timings for items left as the timing all rely on items before it
When the run time issue adds an item back in to the list, it adds the item at the appropriate time, however it does not decrease the time of the item after where it was to take in account how much time the new item will take before we that next item starts to process it's _ms time