[SPARK-4737] Task set manager properly handles serialization errors

Dealing with [SPARK-4737], the handling of serialization errors should not be the DAGScheduler's responsibility. The task set manager now catches the error and aborts the stage.

If the TaskSetManager throws a TaskNotSerializableException, the TaskSchedulerImpl will return an empty list of task descriptions, because no tasks were started. The scheduler should abort the stage gracefully.

Note that I'm not too familiar with this part of the codebase and its place in the overall architecture of the Spark stack. If implementing it this way will have any averse side effects please voice that loudly.
Actually, I don't think that returning an empty sequence is the right call here, since even though this _particular_ task set might have failed to launch a task, we might still have task sets that can be launched.  So, it seems like we'd like to break out of the innermost loop rather than returning from `resourceOffers`.  To do this, it might make sense to split these nested loops into a pair of functions where we can `return` from the "launch tasks from this particular task set" function.