<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def join_or_die(self):
 """Wait for thread to finish, returning a PhaseExecutionOutcome instance."""

    if self._phase_desc.options.timeout_s is not None:
      self.join(self._phase_desc.options.timeout_s)
    else:
      self.join(DEFAULT_PHASE_TIMEOUT_S)

    # We got a return value or an exception and handled it.
    if isinstance(self._phase_execution_outcome, PhaseExecutionOutcome):
      return self._phase_execution_outcome

    # Check for timeout, indicated by None for
    # PhaseExecutionOutcome.phase_result.
    if self.is_alive():
      self.kill()
      return PhaseExecutionOutcome(None)

    # Phase was killed.
    return PhaseExecutionOutcome(threads.ThreadTerminationError())