servo: Merge #12468 - Removed panic channel, replaced by integrated logging and issue reporting (from asajeffrey:constellation-remove-panic-channel); r=emilio
authorAlan Jeffrey <ajeffrey@mozilla.com>
Thu, 21 Jul 2016 11:20:37 -0500
changeset 339340 21660f6e86ad6301eb1f5927b329b8e548c3a5f8
parent 339339 5c19793bc963013b5b3d7346957d9e800edf20cb
child 339341 9eae875626b805c8a5e4389cedb7aab5a66ebd6f
push id31307
push usergszorc@mozilla.com
push dateSat, 04 Feb 2017 00:59:06 +0000
treeherdermozilla-central@94079d43835f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersemilio
servo: Merge #12468 - Removed panic channel, replaced by integrated logging and issue reporting (from asajeffrey:constellation-remove-panic-channel); r=emilio <!-- Please describe your changes on the following line: --> Remove the previous ad hoc panic channel, replace it by an integrated logging and panicking mechanism, including crash reporting. All thread panics are now reported, not just content threads. --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: --> - [X] `./mach build -d` does not report any errors - [X] `./mach test-tidy` does not report any errors - [X] These changes fix #11838 - [X] These changes do not require tests because we don't test error reporting <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> Source-Repo: https://github.com/servo/servo Source-Revision: df1b00d43db615244e8e4bcf8296ed51b64249ea
servo/components/constellation/constellation.rs
servo/components/constellation/pipeline.rs
servo/components/gfx/paint_thread.rs
servo/components/layout_thread/lib.rs
servo/components/layout_traits/lib.rs
servo/components/msg/constellation_msg.rs
servo/components/script/dom/bindings/global.rs
servo/components/script/dom/dedicatedworkerglobalscope.rs
servo/components/script/dom/htmliframeelement.rs
servo/components/script/dom/window.rs
servo/components/script/dom/workerglobalscope.rs
servo/components/script/script_thread.rs
servo/components/script_layout_interface/message.rs
servo/components/script_traits/lib.rs
servo/components/servo/Cargo.lock
servo/components/servo/main.rs
servo/components/util/Cargo.toml
servo/components/util/lib.rs
servo/components/util/panicking.rs
servo/components/util/thread.rs
servo/ports/cef/Cargo.lock
--- a/servo/components/constellation/constellation.rs
+++ b/servo/components/constellation/constellation.rs
@@ -24,17 +24,16 @@ use gfx_traits::Epoch;
 use ipc_channel::ipc::{self, IpcSender};
 use ipc_channel::router::ROUTER;
 use layout_traits::LayoutThreadFactory;
 use log::{Log, LogLevel, LogLevelFilter, LogMetadata, LogRecord};
 use msg::constellation_msg::{FrameId, FrameType, PipelineId};
 use msg::constellation_msg::{Key, KeyModifiers, KeyState, LoadData};
 use msg::constellation_msg::{PipelineNamespace, PipelineNamespaceId, NavigationDirection};
 use msg::constellation_msg::{SubpageId, WindowSizeType};
-use msg::constellation_msg::{self, PanicMsg};
 use net_traits::bluetooth_thread::BluetoothMethodMsg;
 use net_traits::filemanager_thread::FileManagerThreadMsg;
 use net_traits::image_cache_thread::ImageCacheThread;
 use net_traits::storage_thread::StorageThreadMsg;
 use net_traits::{self, ResourceThreads, IpcSend};
 use offscreen_gl_context::{GLContextAttributes, GLLimits};
 use pipeline::{ChildProcess, InitialPipelineState, Pipeline};
 use profile_traits::mem;
@@ -86,31 +85,25 @@ enum ReadyToSave {
 /// the `script` crate).
 pub struct Constellation<Message, LTF, STF> {
     /// A channel through which script messages can be sent to this object.
     script_sender: IpcSender<FromScriptMsg>,
 
     /// A channel through which layout thread messages can be sent to this object.
     layout_sender: IpcSender<FromLayoutMsg>,
 
-    /// A channel through which panic messages can be sent to this object.
-    panic_sender: IpcSender<PanicMsg>,
-
     /// Receives messages from scripts.
     script_receiver: Receiver<FromScriptMsg>,
 
     /// Receives messages from the compositor
     compositor_receiver: Receiver<FromCompositorMsg>,
 
     /// Receives messages from the layout thread
     layout_receiver: Receiver<FromLayoutMsg>,
 
-    /// Receives panic messages.
-    panic_receiver: Receiver<PanicMsg>,
-
     /// A channel (the implementation of which is port-specific) through which messages can be sent
     /// to the compositor.
     compositor_proxy: Box<CompositorProxy>,
 
     /// Channels through which messages can be sent to the resource-related threads.
     public_resource_threads: ResourceThreads,
 
     /// Channels through which messages can be sent to the resource-related threads.
@@ -184,19 +177,16 @@ pub struct Constellation<Message, LTF, S
     document_states: HashMap<PipelineId, DocumentState>,
 
     // Webrender interface, if enabled.
     webrender_api_sender: Option<webrender_traits::RenderApiSender>,
 
     /// Are we shutting down?
     shutting_down: bool,
 
-    /// Have we seen any panics? Hopefully always false!
-    handled_panic: bool,
-
     /// Have we seen any warnings? Hopefully always empty!
     /// The buffer contains `(thread_name, reason)` entries.
     handled_warnings: VecDeque<(Option<String>, String)>,
 
     /// The random number generator and probability for closing pipelines.
     /// This is for testing the hardening of the constellation.
     random_pipeline_closure: Option<(StdRng, f32)>,
 }
@@ -341,19 +331,20 @@ impl FromScriptLogger {
 
 impl Log for FromScriptLogger {
     fn enabled(&self, metadata: &LogMetadata) -> bool {
         metadata.level() <= LogLevel::Warn
     }
 
     fn log(&self, record: &LogRecord) {
         if let Some(entry) = log_entry(record) {
-            // TODO: Store the pipeline id in TLS so we can recover it here
+            debug!("Sending log entry {:?}.", entry);
+            let pipeline_id = PipelineId::installed();
             let thread_name = thread::current().name().map(ToOwned::to_owned);
-            let msg = FromScriptMsg::LogEntry(None, thread_name, entry);
+            let msg = FromScriptMsg::LogEntry(pipeline_id, thread_name, entry);
             if let Ok(chan) = self.constellation_chan.lock() {
                 let _ = chan.send(msg);
             }
         }
     }
 }
 
 /// A logger directed at the constellation from the compositor
@@ -379,19 +370,20 @@ impl FromCompositorLogger {
 
 impl Log for FromCompositorLogger {
     fn enabled(&self, metadata: &LogMetadata) -> bool {
         metadata.level() <= LogLevel::Warn
     }
 
     fn log(&self, record: &LogRecord) {
         if let Some(entry) = log_entry(record) {
-            // TODO: Store the pipeline id in TLS so we can recover it here
+            debug!("Sending log entry {:?}.", entry);
+            let pipeline_id = PipelineId::installed();
             let thread_name = thread::current().name().map(ToOwned::to_owned);
-            let msg = FromCompositorMsg::LogEntry(None, thread_name, entry);
+            let msg = FromCompositorMsg::LogEntry(pipeline_id, thread_name, entry);
             if let Ok(chan) = self.constellation_chan.lock() {
                 let _ = chan.send(msg);
             }
         }
     }
 }
 
 fn log_entry(record: &LogRecord) -> Option<LogEntry> {
@@ -425,29 +417,24 @@ impl<Message, LTF, STF> Constellation<Me
 
         spawn_named("Constellation".to_owned(), move || {
             let (ipc_script_sender, ipc_script_receiver) = ipc::channel().expect("ipc channel failure");
             let script_receiver = ROUTER.route_ipc_receiver_to_new_mpsc_receiver(ipc_script_receiver);
 
             let (ipc_layout_sender, ipc_layout_receiver) = ipc::channel().expect("ipc channel failure");
             let layout_receiver = ROUTER.route_ipc_receiver_to_new_mpsc_receiver(ipc_layout_receiver);
 
-            let (ipc_panic_sender, ipc_panic_receiver) = ipc::channel().expect("ipc channel failure");
-            let panic_receiver = ROUTER.route_ipc_receiver_to_new_mpsc_receiver(ipc_panic_receiver);
-
             let swmanager_receiver = ROUTER.route_ipc_receiver_to_new_mpsc_receiver(swmanager_receiver);
 
             let mut constellation: Constellation<Message, LTF, STF> = Constellation {
                 script_sender: ipc_script_sender,
                 layout_sender: ipc_layout_sender,
                 script_receiver: script_receiver,
-                panic_sender: ipc_panic_sender,
                 compositor_receiver: compositor_receiver,
                 layout_receiver: layout_receiver,
-                panic_receiver: panic_receiver,
                 compositor_proxy: state.compositor_proxy,
                 devtools_chan: state.devtools_chan,
                 bluetooth_thread: state.bluetooth_thread,
                 public_resource_threads: state.public_resource_threads,
                 private_resource_threads: state.private_resource_threads,
                 image_cache_thread: state.image_cache_thread,
                 font_cache_thread: state.font_cache_thread,
                 swmanager_chan: None,
@@ -473,17 +460,16 @@ impl<Message, LTF, STF> Constellation<Me
                 },
                 phantom: PhantomData,
                 webdriver: WebDriverData::new(),
                 scheduler_chan: TimerScheduler::start(),
                 child_processes: Vec::new(),
                 document_states: HashMap::new(),
                 webrender_api_sender: state.webrender_api_sender,
                 shutting_down: false,
-                handled_panic: false,
                 handled_warnings: VecDeque::new(),
                 random_pipeline_closure: opts::get().random_pipeline_closure_probability.map(|prob| {
                     let seed = opts::get().random_pipeline_closure_seed.unwrap_or_else(random);
                     let rng = StdRng::from_seed(&[seed]);
                     warn!("Randomly closing pipelines.");
                     info!("Using seed {} for random pipeline closure.", seed);
                     (rng, prob)
                 }),
@@ -534,17 +520,16 @@ impl<Message, LTF, STF> Constellation<Me
             None
         };
 
         let result = Pipeline::spawn::<Message, LTF, STF>(InitialPipelineState {
             id: pipeline_id,
             parent_info: parent_info,
             constellation_chan: self.script_sender.clone(),
             layout_to_constellation_chan: self.layout_sender.clone(),
-            panic_chan: self.panic_sender.clone(),
             scheduler_chan: self.scheduler_chan.clone(),
             compositor_proxy: self.compositor_proxy.clone_compositor_proxy(),
             devtools_chan: self.devtools_chan.clone(),
             bluetooth_thread: self.bluetooth_thread.clone(),
             swmanager_thread: self.swmanager_sender.clone(),
             image_cache_thread: self.image_cache_thread.clone(),
             font_cache_thread: self.font_cache_thread.clone(),
             resource_threads: resource_threads,
@@ -612,18 +597,17 @@ impl<Message, LTF, STF> Constellation<Me
 
     /// Handles loading pages, navigation, and granting access to the compositor
     #[allow(unsafe_code)]
     fn handle_request(&mut self) {
         enum Request {
             Script(FromScriptMsg),
             Compositor(FromCompositorMsg),
             Layout(FromLayoutMsg),
-            Panic(PanicMsg),
-            FromSWManager(SWManagerMsg)
+            FromSWManager(SWManagerMsg),
         }
 
         // Get one incoming request.
         // This is one of the few places where the compositor is
         // allowed to panic. If one of the receiver.recv() calls
         // fails, it is because the matching sender has been
         // reclaimed, but this can't happen in normal execution
         // because the constellation keeps a pointer to the sender,
@@ -631,45 +615,39 @@ impl<Message, LTF, STF> Constellation<Me
         // which receiver.recv() fails is if some unsafe code
         // produces undefined behaviour, resulting in the destructor
         // being called. If this happens, there's not much we can do
         // other than panic.
         let request = {
             let receiver_from_script = &self.script_receiver;
             let receiver_from_compositor = &self.compositor_receiver;
             let receiver_from_layout = &self.layout_receiver;
-            let receiver_from_panic = &self.panic_receiver;
             let receiver_from_swmanager = &self.swmanager_receiver;
             select! {
                 msg = receiver_from_script.recv() =>
                     Request::Script(msg.expect("Unexpected script channel panic in constellation")),
                 msg = receiver_from_compositor.recv() =>
                     Request::Compositor(msg.expect("Unexpected compositor channel panic in constellation")),
                 msg = receiver_from_layout.recv() =>
                     Request::Layout(msg.expect("Unexpected layout channel panic in constellation")),
-                msg = receiver_from_panic.recv() =>
-                    Request::Panic(msg.expect("Unexpected panic channel panic in constellation")),
                 msg = receiver_from_swmanager.recv() =>
                     Request::FromSWManager(msg.expect("Unexpected panic channel panic in constellation"))
             }
         };
 
         match request {
             Request::Compositor(message) => {
                 self.handle_request_from_compositor(message)
             },
             Request::Script(message) => {
                 self.handle_request_from_script(message);
             },
             Request::Layout(message) => {
                 self.handle_request_from_layout(message);
             },
-            Request::Panic(message) => {
-                self.handle_request_from_panic(message);
-            },
             Request::FromSWManager(message) => {
                 self.handle_request_from_swmanager(message);
             }
         }
     }
 
     fn handle_request_from_swmanager(&mut self, message: SWManagerMsg) {
         match message {
@@ -952,25 +930,16 @@ impl<Message, LTF, STF> Constellation<Me
             }
             FromLayoutMsg::ViewportConstrained(pipeline_id, constraints) => {
                 debug!("constellation got viewport-constrained event message");
                 self.handle_viewport_constrained_msg(pipeline_id, constraints);
             }
         }
     }
 
-    fn handle_request_from_panic(&mut self, message: PanicMsg) {
-        match message {
-            (pipeline_id, panic_reason, backtrace) => {
-                debug!("handling panic message ({:?})", pipeline_id);
-                self.handle_panic(pipeline_id, panic_reason, backtrace);
-            }
-        }
-    }
-
     fn handle_register_serviceworker(&self, scope_things: ScopeThings, scope: Url) {
         if let Some(ref mgr) = self.swmanager_chan {
             let _ = mgr.send(ServiceWorkerMsg::RegisterServiceWorker(scope_things, scope));
         } else {
             warn!("sending scope info to service worker manager failed");
         }
     }
 
@@ -1048,32 +1017,24 @@ impl<Message, LTF, STF> Constellation<Me
     fn handle_pipeline_exited(&mut self, pipeline_id: PipelineId) {
         debug!("Pipeline {:?} exited.", pipeline_id);
         self.pipelines.remove(&pipeline_id);
     }
 
     fn handle_send_error(&mut self, pipeline_id: PipelineId, err: IOError) {
         // Treat send error the same as receiving a panic message
         debug!("Pipeline {:?} send error ({}).", pipeline_id, err);
-        self.handle_panic(Some(pipeline_id), format!("Send failed ({})", err), String::from("<none>"));
+        self.handle_panic(Some(pipeline_id), format!("Send failed ({})", err), None);
     }
 
-    fn handle_panic(&mut self, pipeline_id: Option<PipelineId>, reason: String, backtrace: String) {
-        error!("Panic: {}", reason);
-        if !self.handled_panic || opts::get().full_backtraces {
-            // For the first panic, we print the full backtrace
-            error!("Backtrace:\n{}", backtrace);
-        } else {
-            error!("Backtrace skipped (run with -Z full-backtraces to see every backtrace).");
-        }
-
+    fn handle_panic(&mut self, pipeline_id: Option<PipelineId>, reason: String, backtrace: Option<String>) {
         if opts::get().hard_fail {
             // It's quite difficult to make Servo exit cleanly if some threads have failed.
             // Hard fail exists for test runners so we crash and that's good enough.
-            error!("Pipeline failed in hard-fail mode.  Crashing!");
+            println!("Pipeline failed in hard-fail mode.  Crashing!\n{}\n{}", reason, backtrace.unwrap_or_default());
             process::exit(1);
         }
 
         debug!("Panic handler for pipeline {:?}: {}.", pipeline_id, reason);
 
         // Notify the browser chrome that the pipeline has failed
         self.trigger_mozbrowsererror(pipeline_id, reason, backtrace);
 
@@ -1104,23 +1065,22 @@ impl<Message, LTF, STF> Constellation<Me
 
             let new_pipeline_id = PipelineId::new();
             let load_data = LoadData::new(failure_url, None, None);
             self.new_pipeline(new_pipeline_id, parent_info, window_size, None, load_data, false);
 
             self.push_pending_frame(new_pipeline_id, Some(pipeline_id));
 
         }
-
-        self.handled_panic = true;
     }
 
     fn handle_log_entry(&mut self, pipeline_id: Option<PipelineId>, thread_name: Option<String>, entry: LogEntry) {
+        debug!("Received log entry {:?}.", entry);
         match entry {
-            LogEntry::Panic(reason, backtrace) => self.trigger_mozbrowsererror(pipeline_id, reason, backtrace),
+            LogEntry::Panic(reason, backtrace) => self.handle_panic(pipeline_id, reason, Some(backtrace)),
             LogEntry::Error(reason) | LogEntry::Warn(reason) => {
                 // VecDeque::truncate is unstable
                 if WARNINGS_BUFFER_SIZE <= self.handled_warnings.len() {
                     self.handled_warnings.pop_front();
                 }
                 self.handled_warnings.push_back((thread_name, reason));
             },
         }
@@ -1434,17 +1394,17 @@ impl<Message, LTF, STF> Constellation<Me
             self.webdriver.load_channel = None;
         }
 
         self.handle_subframe_loaded(pipeline_id);
     }
 
     fn handle_navigate_msg(&mut self,
                            pipeline_info: Option<(PipelineId, SubpageId)>,
-                           direction: constellation_msg::NavigationDirection) {
+                           direction: NavigationDirection) {
         debug!("received message to navigate {:?}", direction);
 
         // Get the frame id associated with the pipeline that sent
         // the navigate message, or use root frame id by default.
         let frame_id = pipeline_info
             .and_then(|info| self.subpage_map.get(&info))
             .and_then(|pipeline_id| self.pipelines.get(&pipeline_id))
             .and_then(|pipeline| pipeline.frame)
@@ -2305,35 +2265,37 @@ impl<Message, LTF, STF> Constellation<Me
                     }
                 }
             }
         }
     }
 
     // https://developer.mozilla.org/en-US/docs/Web/Events/mozbrowsererror
     // Note that this does not require the pipeline to be an immediate child of the root
-    fn trigger_mozbrowsererror(&mut self, pipeline_id: Option<PipelineId>, reason: String, backtrace: String) {
+    fn trigger_mozbrowsererror(&mut self, pipeline_id: Option<PipelineId>, reason: String, backtrace: Option<String>) {
         if !PREFS.is_mozbrowser_enabled() { return; }
 
         let mut report = String::new();
         for (thread_name, warning) in self.handled_warnings.drain(..) {
             report.push_str("\nWARNING: ");
             if let Some(thread_name) = thread_name {
                 report.push_str("<");
                 report.push_str(&*thread_name);
                 report.push_str(">: ");
             }
             report.push_str(&*warning);
         }
         report.push_str("\nERROR: ");
         report.push_str(&*reason);
-        report.push_str("\n\n");
-        report.push_str(&*backtrace);
+        if let Some(backtrace) = backtrace {
+            report.push_str("\n\n");
+            report.push_str(&*backtrace);
+        }
 
-        let event = MozBrowserEvent::Error(MozBrowserErrorType::Fatal, Some(reason), Some(report));
+        let event = MozBrowserEvent::Error(MozBrowserErrorType::Fatal, reason, report);
 
         if let Some(pipeline_id) = pipeline_id {
             if let Some((ancestor_id, subpage_id)) = self.get_mozbrowser_ancestor_info(pipeline_id) {
                 if let Some(ancestor) = self.pipelines.get(&ancestor_id) {
                     return ancestor.trigger_mozbrowser_event(Some(subpage_id), event);
                 }
             }
         }
--- a/servo/components/constellation/pipeline.rs
+++ b/servo/components/constellation/pipeline.rs
@@ -12,17 +12,17 @@ use euclid::size::TypedSize2D;
 use gaol;
 use gfx::font_cache_thread::FontCacheThread;
 use gfx::paint_thread::{LayoutToPaintMsg, PaintThread};
 use gfx_traits::ChromeToPaintMsg;
 use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
 use ipc_channel::router::ROUTER;
 use layers::geometry::DevicePixel;
 use layout_traits::LayoutThreadFactory;
-use msg::constellation_msg::{FrameId, FrameType, LoadData, PanicMsg, PipelineId};
+use msg::constellation_msg::{FrameId, FrameType, LoadData, PipelineId};
 use msg::constellation_msg::{PipelineNamespaceId, SubpageId};
 use net_traits::bluetooth_thread::BluetoothMethodMsg;
 use net_traits::image_cache_thread::ImageCacheThread;
 use net_traits::{ResourceThreads, IpcSend};
 use profile_traits::mem as profile_mem;
 use profile_traits::time;
 use script_traits::{ConstellationControlMsg, InitialScriptState, MozBrowserEvent};
 use script_traits::{LayoutControlMsg, LayoutMsg, NewLayoutInfo, ScriptMsg, SWManagerMsg, SWManagerSenders};
@@ -84,18 +84,16 @@ pub struct InitialPipelineState {
     pub id: PipelineId,
     /// The subpage ID of this pipeline to create in its pipeline parent.
     /// If `None`, this is the root.
     pub parent_info: Option<(PipelineId, SubpageId, FrameType)>,
     /// A channel to the associated constellation.
     pub constellation_chan: IpcSender<ScriptMsg>,
     /// A channel for the layout thread to send messages to the constellation.
     pub layout_to_constellation_chan: IpcSender<LayoutMsg>,
-    /// A channel to report panics
-    pub panic_chan: IpcSender<PanicMsg>,
     /// A channel to schedule timer events.
     pub scheduler_chan: IpcSender<TimerEventRequest>,
     /// A channel to the compositor.
     pub compositor_proxy: Box<CompositorProxy + 'static + Send>,
     /// A channel to the developer tools, if applicable.
     pub devtools_chan: Option<Sender<DevtoolsControlMsg>>,
     /// A channel to the bluetooth thread.
     pub bluetooth_thread: IpcSender<BluetoothMethodMsg>,
@@ -154,17 +152,16 @@ impl Pipeline {
                     state.parent_info.expect("script_pipeline != None but subpage_id == None");
                 let new_layout_info = NewLayoutInfo {
                     containing_pipeline_id: containing_pipeline_id,
                     new_pipeline_id: state.id,
                     subpage_id: subpage_id,
                     frame_type: frame_type,
                     load_data: state.load_data.clone(),
                     paint_chan: layout_to_paint_chan.clone().to_opaque(),
-                    panic_chan: state.panic_chan.clone(),
                     pipeline_port: pipeline_port,
                     layout_to_constellation_chan: state.layout_to_constellation_chan.clone(),
                     content_process_shutdown_chan: layout_content_process_shutdown_chan.clone(),
                 };
 
                 if let Err(e) = script_chan.send(ConstellationControlMsg::AttachLayout(new_layout_info)) {
                     warn!("Sending to script during pipeline creation failed ({})", e);
                 }
@@ -177,17 +174,16 @@ impl Pipeline {
         };
 
         PaintThread::create(state.id,
                             state.load_data.url.clone(),
                             chrome_to_paint_chan.clone(),
                             layout_to_paint_port,
                             chrome_to_paint_port,
                             state.compositor_proxy.clone_compositor_proxy(),
-                            state.panic_chan.clone(),
                             state.font_cache_thread.clone(),
                             state.time_profiler_chan.clone(),
                             state.mem_profiler_chan.clone());
 
         let mut child_process = None;
         if let Some((script_port, pipeline_port)) = content_ports {
             // Route messages coming from content to devtools as appropriate.
             let script_to_devtools_chan = state.devtools_chan.as_ref().map(|devtools_chan| {
@@ -229,17 +225,16 @@ impl Pipeline {
                 font_cache_thread: state.font_cache_thread,
                 resource_threads: state.resource_threads,
                 time_profiler_chan: state.time_profiler_chan,
                 mem_profiler_chan: state.mem_profiler_chan,
                 window_size: window_size,
                 layout_to_constellation_chan: state.layout_to_constellation_chan,
                 script_chan: script_chan.clone(),
                 load_data: state.load_data.clone(),
-                panic_chan: state.panic_chan,
                 script_port: script_port,
                 opts: (*opts::get()).clone(),
                 prefs: PREFS.cloned(),
                 layout_to_paint_chan: layout_to_paint_chan,
                 pipeline_port: pipeline_port,
                 pipeline_namespace_id: state.pipeline_namespace_id,
                 layout_content_process_shutdown_chan: layout_content_process_shutdown_chan,
                 layout_content_process_shutdown_port: layout_content_process_shutdown_port,
@@ -421,17 +416,16 @@ pub struct UnprivilegedPipelineContent {
     image_cache_thread: ImageCacheThread,
     font_cache_thread: FontCacheThread,
     resource_threads: ResourceThreads,
     time_profiler_chan: time::ProfilerChan,
     mem_profiler_chan: profile_mem::ProfilerChan,
     window_size: Option<WindowSizeData>,
     script_chan: IpcSender<ConstellationControlMsg>,
     load_data: LoadData,
-    panic_chan: IpcSender<PanicMsg>,
     script_port: IpcReceiver<ConstellationControlMsg>,
     layout_to_paint_chan: OptionalIpcSender<LayoutToPaintMsg>,
     opts: Opts,
     prefs: HashMap<String, Pref>,
     pipeline_port: IpcReceiver<LayoutControlMsg>,
     pipeline_namespace_id: PipelineNamespaceId,
     layout_content_process_shutdown_chan: IpcSender<()>,
     layout_content_process_shutdown_port: IpcReceiver<()>,
@@ -447,17 +441,16 @@ impl UnprivilegedPipelineContent {
     {
         let layout_pair = STF::create(InitialScriptState {
             id: self.id,
             parent_info: self.parent_info,
             control_chan: self.script_chan.clone(),
             control_port: self.script_port,
             constellation_chan: self.constellation_chan,
             scheduler_chan: self.scheduler_chan,
-            panic_chan: self.panic_chan.clone(),
             bluetooth_thread: self.bluetooth_thread,
             resource_threads: self.resource_threads,
             image_cache_thread: self.image_cache_thread.clone(),
             time_profiler_chan: self.time_profiler_chan.clone(),
             mem_profiler_chan: self.mem_profiler_chan.clone(),
             devtools_chan: self.devtools_chan,
             window_size: self.window_size,
             pipeline_namespace_id: self.pipeline_namespace_id,
@@ -465,17 +458,16 @@ impl UnprivilegedPipelineContent {
         }, self.load_data.clone());
 
         LTF::create(self.id,
                     self.load_data.url,
                     self.parent_info.is_some(),
                     layout_pair,
                     self.pipeline_port,
                     self.layout_to_constellation_chan,
-                    self.panic_chan,
                     self.script_chan,
                     self.layout_to_paint_chan,
                     self.image_cache_thread,
                     self.font_cache_thread,
                     self.time_profiler_chan,
                     self.mem_profiler_chan,
                     self.layout_content_process_shutdown_chan,
                     self.webrender_api_sender);
--- a/servo/components/gfx/paint_thread.rs
+++ b/servo/components/gfx/paint_thread.rs
@@ -12,20 +12,19 @@ use display_list::{LayerInfo, StackingCo
 use euclid::Matrix4D;
 use euclid::point::Point2D;
 use euclid::rect::Rect;
 use euclid::size::Size2D;
 use font_cache_thread::FontCacheThread;
 use font_context::FontContext;
 use gfx_traits::{ChromeToPaintMsg, Epoch, LayerId, LayerKind, LayerProperties};
 use gfx_traits::{PaintListener, PaintRequest, StackingContextId};
-use ipc_channel::ipc::IpcSender;
 use layers::layers::{BufferRequest, LayerBuffer, LayerBufferSet};
 use layers::platform::surface::{NativeDisplay, NativeSurface};
-use msg::constellation_msg::{PanicMsg, PipelineId};
+use msg::constellation_msg::PipelineId;
 use paint_context::PaintContext;
 use profile_traits::mem;
 use profile_traits::time;
 use rand::{self, Rng};
 use std::borrow::ToOwned;
 use std::collections::HashMap;
 use std::mem as std_mem;
 use std::sync::Arc;
@@ -372,23 +371,24 @@ macro_rules! native_display(
 
 impl<C> PaintThread<C> where C: PaintListener + Send + 'static {
     pub fn create(id: PipelineId,
                   url: Url,
                   chrome_to_paint_chan: Sender<ChromeToPaintMsg>,
                   layout_to_paint_port: Receiver<LayoutToPaintMsg>,
                   chrome_to_paint_port: Receiver<ChromeToPaintMsg>,
                   mut compositor: C,
-                  panic_chan: IpcSender<PanicMsg>,
                   font_cache_thread: FontCacheThread,
                   time_profiler_chan: time::ProfilerChan,
                   mem_profiler_chan: mem::ProfilerChan) {
-        thread::spawn_named_with_send_on_panic(format!("PaintThread {:?}", id),
-                                               thread_state::PAINT,
-                                               move || {
+        thread::spawn_named(format!("PaintThread {:?}", id),
+                            move || {
+            thread_state::initialize(thread_state::PAINT);
+            PipelineId::install(id);
+
             let native_display = compositor.native_display();
             let worker_threads = WorkerThreadProxy::spawn(native_display,
                                                           font_cache_thread,
                                                           time_profiler_chan.clone());
 
             let mut paint_thread = PaintThread {
                 id: id,
                 _url: url,
@@ -407,17 +407,17 @@ impl<C> PaintThread<C> where C: PaintLis
             mem_profiler_chan.run_with_memory_reporting(|| {
                 paint_thread.start();
             }, reporter_name, chrome_to_paint_chan, ChromeToPaintMsg::CollectReports);
 
             // Tell all the worker threads to shut down.
             for worker_thread in &mut paint_thread.worker_threads {
                 worker_thread.exit()
             }
-        }, Some(id), panic_chan);
+        });
     }
 
     #[allow(unsafe_code)]
     fn start(&mut self) {
         debug!("PaintThread: beginning painting loop");
 
         loop {
             let message = {
--- a/servo/components/layout_thread/lib.rs
+++ b/servo/components/layout_thread/lib.rs
@@ -71,17 +71,17 @@ use layout::query::process_offset_parent
 use layout::query::{LayoutRPCImpl, LayoutThreadData, process_content_box_request, process_content_boxes_request};
 use layout::query::{process_node_geometry_request, process_node_layer_id_request, process_node_scroll_area_request};
 use layout::query::{process_node_overflow_request, process_resolved_style_request, process_margin_style_query};
 use layout::sequential;
 use layout::traversal::RecalcStyleAndConstructFlows;
 use layout::webrender_helpers::{WebRenderDisplayListConverter, WebRenderFrameBuilder};
 use layout::wrapper::{LayoutNodeLayoutData, NonOpaqueStyleAndLayoutData};
 use layout_traits::LayoutThreadFactory;
-use msg::constellation_msg::{PanicMsg, PipelineId};
+use msg::constellation_msg::PipelineId;
 use net_traits::image_cache_thread::UsePlaceholder;
 use net_traits::image_cache_thread::{ImageCacheChan, ImageCacheResult, ImageCacheThread};
 use profile_traits::mem::{self, Report, ReportKind, ReportsChan};
 use profile_traits::time::{TimerMetadataFrameType, TimerMetadataReflowType};
 use profile_traits::time::{self, TimerMetadata, profile};
 use script::layout_wrapper::ServoLayoutNode;
 use script_layout_interface::message::{Msg, NewLayoutThreadInfo, Reflow, ReflowQueryType, ScriptReflow};
 use script_layout_interface::reporter::CSSErrorReporter;
@@ -239,28 +239,28 @@ impl LayoutThreadFactory for LayoutThrea
 
     /// Spawns a new layout thread.
     fn create(id: PipelineId,
               url: Url,
               is_iframe: bool,
               chan: (Sender<Msg>, Receiver<Msg>),
               pipeline_port: IpcReceiver<LayoutControlMsg>,
               constellation_chan: IpcSender<ConstellationMsg>,
-              panic_chan: IpcSender<PanicMsg>,
               script_chan: IpcSender<ConstellationControlMsg>,
               paint_chan: OptionalIpcSender<LayoutToPaintMsg>,
               image_cache_thread: ImageCacheThread,
               font_cache_thread: FontCacheThread,
               time_profiler_chan: time::ProfilerChan,
               mem_profiler_chan: mem::ProfilerChan,
               content_process_shutdown_chan: IpcSender<()>,
               webrender_api_sender: Option<webrender_traits::RenderApiSender>) {
-        thread::spawn_named_with_send_on_panic(format!("LayoutThread {:?}", id),
-                                               thread_state::LAYOUT,
-                                               move || {
+        thread::spawn_named(format!("LayoutThread {:?}", id),
+                      move || {
+            thread_state::initialize(thread_state::LAYOUT);
+            PipelineId::install(id);
             { // Ensures layout thread is destroyed before we send shutdown message
                 let sender = chan.0;
                 let layout = LayoutThread::new(id,
                                              url,
                                              is_iframe,
                                              chan.1,
                                              pipeline_port,
                                              constellation_chan,
@@ -273,17 +273,17 @@ impl LayoutThreadFactory for LayoutThrea
                                              webrender_api_sender);
 
                 let reporter_name = format!("layout-reporter-{}", id);
                 mem_profiler_chan.run_with_memory_reporting(|| {
                     layout.start();
                 }, reporter_name, sender, Msg::CollectReports);
             }
             let _ = content_process_shutdown_chan.send(());
-        }, Some(id), panic_chan);
+        });
     }
 }
 
 /// The `LayoutThread` `rw_data` lock must remain locked until the first reflow,
 /// as RPC calls don't make sense until then. Use this in combination with
 /// `LayoutThread::lock_rw_data` and `LayoutThread::return_rw_data`.
 pub enum RWGuard<'a> {
     /// If the lock was previously held, from when the thread started.
@@ -742,17 +742,16 @@ impl LayoutThread {
 
     fn create_layout_thread(&self, info: NewLayoutThreadInfo) {
         LayoutThread::create(info.id,
                              info.url.clone(),
                              info.is_parent,
                              info.layout_pair,
                              info.pipeline_port,
                              info.constellation_chan,
-                             info.panic_chan,
                              info.script_chan.clone(),
                              info.paint_chan.to::<LayoutToPaintMsg>(),
                              self.image_cache_thread.clone(),
                              self.font_cache_thread.clone(),
                              self.time_profiler_chan.clone(),
                              self.mem_profiler_chan.clone(),
                              info.content_process_shutdown_chan,
                              self.webrender_api.as_ref().map(|wr| wr.clone_sender()));
--- a/servo/components/layout_traits/lib.rs
+++ b/servo/components/layout_traits/lib.rs
@@ -17,17 +17,17 @@ extern crate webrender_traits;
 // This module contains traits in layout used generically
 //   in the rest of Servo.
 // The traits are here instead of in layout so
 //   that these modules won't have to depend on layout.
 
 use gfx::font_cache_thread::FontCacheThread;
 use gfx::paint_thread::LayoutToPaintMsg;
 use ipc_channel::ipc::{IpcReceiver, IpcSender};
-use msg::constellation_msg::{PanicMsg, PipelineId};
+use msg::constellation_msg::PipelineId;
 use net_traits::image_cache_thread::ImageCacheThread;
 use profile_traits::{mem, time};
 use script_traits::LayoutMsg as ConstellationMsg;
 use script_traits::{LayoutControlMsg, ConstellationControlMsg};
 use std::sync::mpsc::{Sender, Receiver};
 use url::Url;
 use util::ipc::OptionalIpcSender;
 
@@ -36,17 +36,16 @@ use util::ipc::OptionalIpcSender;
 pub trait LayoutThreadFactory {
     type Message;
     fn create(id: PipelineId,
               url: Url,
               is_iframe: bool,
               chan: (Sender<Self::Message>, Receiver<Self::Message>),
               pipeline_port: IpcReceiver<LayoutControlMsg>,
               constellation_chan: IpcSender<ConstellationMsg>,
-              panic_chan: IpcSender<PanicMsg>,
               script_chan: IpcSender<ConstellationControlMsg>,
               layout_to_paint_chan: OptionalIpcSender<LayoutToPaintMsg>,
               image_cache_thread: ImageCacheThread,
               font_cache_thread: FontCacheThread,
               time_profiler_chan: time::ProfilerChan,
               mem_profiler_chan: mem::ProfilerChan,
               content_process_shutdown_chan: IpcSender<()>,
               webrender_api_sender: Option<webrender_traits::RenderApiSender>);
--- a/servo/components/msg/constellation_msg.rs
+++ b/servo/components/msg/constellation_msg.rs
@@ -8,18 +8,16 @@
 use hyper::header::Headers;
 use hyper::method::Method;
 use ipc_channel::ipc::IpcSharedMemory;
 use std::cell::Cell;
 use std::fmt;
 use url::Url;
 use webrender_traits;
 
-pub type PanicMsg = (Option<PipelineId>, String, String);
-
 #[derive(Deserialize, Eq, PartialEq, Serialize, Copy, Clone, HeapSizeOf)]
 pub enum WindowSizeType {
     Initial,
     Resize,
 }
 
 #[derive(PartialEq, Eq, Copy, Clone, Debug, Deserialize, Serialize)]
 pub enum KeyState {
@@ -264,16 +262,18 @@ impl PipelineNamespace {
         self.next_index = PipelineIndex(current_index + 1);
 
         pipeline_id
     }
 }
 
 thread_local!(pub static PIPELINE_NAMESPACE: Cell<Option<PipelineNamespace>> = Cell::new(None));
 
+thread_local!(pub static PIPELINE_ID: Cell<Option<PipelineId>> = Cell::new(None));
+
 #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Copy, Hash, Debug, Deserialize, Serialize, HeapSizeOf)]
 pub struct PipelineNamespaceId(pub u32);
 
 #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Copy, Hash, Debug, Deserialize, Serialize, HeapSizeOf)]
 pub struct PipelineIndex(pub u32);
 
 #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Copy, Hash, Debug, Deserialize, Serialize, HeapSizeOf)]
 pub struct PipelineId {
@@ -303,16 +303,25 @@ impl PipelineId {
         }
     }
 
     pub fn to_webrender(&self) -> webrender_traits::PipelineId {
         let PipelineNamespaceId(namespace_id) = self.namespace_id;
         let PipelineIndex(index) = self.index;
         webrender_traits::PipelineId(namespace_id, index)
     }
+
+    pub fn install(id: PipelineId) {
+        PIPELINE_ID.with(|tls| tls.set(Some(id)))
+    }
+
+    pub fn installed() -> Option<PipelineId> {
+        PIPELINE_ID.with(|tls| tls.get())
+    }
+
 }
 
 impl fmt::Display for PipelineId {
     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
         let PipelineNamespaceId(namespace_id) = self.namespace_id;
         let PipelineIndex(index) = self.index;
         write!(fmt, "({},{})", namespace_id, index)
     }
--- a/servo/components/script/dom/bindings/global.rs
+++ b/servo/components/script/dom/bindings/global.rs
@@ -13,17 +13,17 @@ use dom::bindings::conversions::root_fro
 use dom::bindings::js::Root;
 use dom::bindings::reflector::{Reflectable, Reflector};
 use dom::window::{self, ScriptHelpers};
 use dom::workerglobalscope::WorkerGlobalScope;
 use ipc_channel::ipc::IpcSender;
 use js::jsapi::{CurrentGlobalOrNull, GetGlobalForObjectCrossCompartment};
 use js::jsapi::{JSContext, JSObject, JS_GetClass, MutableHandleValue};
 use js::{JSCLASS_IS_DOMJSCLASS, JSCLASS_IS_GLOBAL};
-use msg::constellation_msg::{PipelineId, PanicMsg};
+use msg::constellation_msg::PipelineId;
 use net_traits::filemanager_thread::FileManagerThreadMsg;
 use net_traits::{ResourceThreads, CoreResourceThread, IpcSend};
 use profile_traits::{mem, time};
 use script_runtime::{CommonScriptMsg, ScriptChan, ScriptPort};
 use script_thread::{MainThreadScriptChan, ScriptThread, RunnableWrapper};
 use script_traits::{MsDuration, ScriptMsg as ConstellationMsg, TimerEventRequest};
 use task_source::dom_manipulation::DOMManipulationTaskSource;
 use task_source::file_reading::FileReadingTaskSource;
@@ -278,24 +278,16 @@ impl<'a> GlobalRef<'a> {
     /// Returns the receiver's reflector.
     pub fn reflector(&self) -> &Reflector {
         match *self {
             GlobalRef::Window(ref window) => window.reflector(),
             GlobalRef::Worker(ref worker) => worker.reflector(),
         }
     }
 
-    /// Returns an `IpcSender` to report panics on.
-    pub fn panic_chan(&self) -> &IpcSender<PanicMsg> {
-        match *self {
-            GlobalRef::Window(ref window) => window.panic_chan(),
-            GlobalRef::Worker(ref worker) => worker.panic_chan(),
-        }
-    }
-
     /// Returns a wrapper for runnables to ensure they are cancelled if the global
     /// is being destroyed.
     pub fn get_runnable_wrapper(&self) -> RunnableWrapper {
         match *self {
             GlobalRef::Window(ref window) => window.get_runnable_wrapper(),
             GlobalRef::Worker(ref worker) => worker.get_runnable_wrapper(),
         }
     }
--- a/servo/components/script/dom/dedicatedworkerglobalscope.rs
+++ b/servo/components/script/dom/dedicatedworkerglobalscope.rs
@@ -33,18 +33,18 @@ use rand::random;
 use script_runtime::ScriptThreadEventCategory::WorkerEvent;
 use script_runtime::{CommonScriptMsg, ScriptChan, ScriptPort, StackRootTLS, get_reports, new_rt_and_cx};
 use script_traits::{TimerEvent, TimerSource, WorkerScriptLoadOrigin, WorkerGlobalScopeInit};
 use std::mem::replace;
 use std::sync::atomic::AtomicBool;
 use std::sync::mpsc::{Receiver, RecvError, Select, Sender, channel};
 use std::sync::{Arc, Mutex};
 use url::Url;
-use util::thread::spawn_named_with_send_on_panic;
-use util::thread_state::{IN_WORKER, SCRIPT};
+use util::thread::spawn_named;
+use util::thread_state;
 
 /// Set the `worker` field of a related DedicatedWorkerGlobalScope object to a particular
 /// value for the duration of this object's lifetime. This ensures that the related Worker
 /// object only lives as long as necessary (ie. while events are being executed), while
 /// providing a reference that can be cloned freely.
 struct AutoWorkerReset<'a> {
     workerscope: &'a DedicatedWorkerGlobalScope,
     old_worker: Option<TrustedWorkerAddress>,
@@ -156,18 +156,20 @@ impl DedicatedWorkerGlobalScope {
                             worker: TrustedWorkerAddress,
                             parent_sender: Box<ScriptChan + Send>,
                             own_sender: Sender<(TrustedWorkerAddress, WorkerScriptMsg)>,
                             receiver: Receiver<(TrustedWorkerAddress, WorkerScriptMsg)>,
                             worker_load_origin: WorkerScriptLoadOrigin,
                             closing: Arc<AtomicBool>) {
         let serialized_worker_url = worker_url.to_string();
         let name = format!("WebWorker for {}", serialized_worker_url);
-        let panic_chan = init.panic_chan.clone();
-        spawn_named_with_send_on_panic(name, SCRIPT | IN_WORKER, move || {
+        spawn_named(name, move || {
+            thread_state::initialize(thread_state::SCRIPT | thread_state::IN_WORKER);
+            PipelineId::install(id);
+
             let roots = RootCollection::new();
             let _stack_roots_tls = StackRootTLS::new(&roots);
             let (url, source) = match load_whole_resource(LoadContext::Script,
                                                           &init.resource_threads.sender(),
                                                           worker_url,
                                                           &worker_load_origin) {
                 Err(_) => {
                     println!("error loading script {}", serialized_worker_url);
@@ -220,17 +222,17 @@ impl DedicatedWorkerGlobalScope {
             scope.mem_profiler_chan().run_with_memory_reporting(|| {
                 while let Ok(event) = global.receive_event() {
                     if scope.is_closing() {
                         break;
                     }
                     global.handle_event(event);
                 }
             }, reporter_name, parent_sender, CommonScriptMsg::CollectReports);
-        }, Some(id.clone()), panic_chan);
+        });
     }
 
     pub fn script_chan(&self) -> Box<ScriptChan + Send> {
         box WorkerThreadWorkerChan {
             sender: self.own_sender.clone(),
             worker: self.worker.borrow().as_ref().unwrap().clone(),
         }
     }
--- a/servo/components/script/dom/htmliframeelement.rs
+++ b/servo/components/script/dom/htmliframeelement.rs
@@ -348,18 +348,18 @@ unsafe fn build_mozbrowser_event_detail(
         MozBrowserEvent::LoadEnd | MozBrowserEvent::LoadStart |
         MozBrowserEvent::Connected | MozBrowserEvent::OpenSearch  |
         MozBrowserEvent::UsernameAndPasswordRequired => {
             rval.set(NullValue());
         }
         MozBrowserEvent::Error(error_type, description, report) => {
             BrowserElementErrorEventDetail {
                 type_: Some(DOMString::from(error_type.name())),
-                description: description.map(DOMString::from),
-                report: report.map(DOMString::from),
+                description: Some(DOMString::from(description)),
+                report: Some(DOMString::from(report)),
                 version: Some(DOMString::from_string(servo_version().into())),
             }.to_jsval(cx, rval);
         },
         MozBrowserEvent::SecurityChange(https_state) => {
             BrowserElementSecurityChangeDetail {
                 // https://developer.mozilla.org/en-US/docs/Web/Events/mozbrowsersecuritychange
                 state: Some(DOMString::from(match https_state {
                     HttpsState::Modern => "secure",
--- a/servo/components/script/dom/window.rs
+++ b/servo/components/script/dom/window.rs
@@ -40,17 +40,17 @@ use dom::storage::Storage;
 use euclid::{Point2D, Rect, Size2D};
 use gfx_traits::LayerId;
 use ipc_channel::ipc::{self, IpcSender};
 use js::jsapi::{Evaluate2, HandleObject, HandleValue, JSAutoCompartment, JSContext};
 use js::jsapi::{JS_GetRuntime, JS_GC, MutableHandleValue, SetWindowProxy};
 use js::rust::CompileOptionsWrapper;
 use js::rust::Runtime;
 use libc;
-use msg::constellation_msg::{FrameType, LoadData, PanicMsg, PipelineId, SubpageId, WindowSizeType};
+use msg::constellation_msg::{FrameType, LoadData, PipelineId, SubpageId, WindowSizeType};
 use net_traits::ResourceThreads;
 use net_traits::bluetooth_thread::BluetoothMethodMsg;
 use net_traits::image_cache_thread::{ImageCacheChan, ImageCacheThread};
 use net_traits::storage_thread::StorageType;
 use num_traits::ToPrimitive;
 use open;
 use profile_traits::mem;
 use profile_traits::time::{ProfilerCategory, TimerMetadata, TimerMetadataFrameType};
@@ -261,19 +261,16 @@ pub struct Window {
     /// A flag to prevent async events from attempting to interact with this window.
     #[ignore_heap_size_of = "defined in std"]
     ignore_further_async_events: Arc<AtomicBool>,
 
     error_reporter: CSSErrorReporter,
 
     /// A list of scroll offsets for each scrollable element.
     scroll_offsets: DOMRefCell<HashMap<UntrustedNodeAddress, Point2D<f32>>>,
-
-    #[ignore_heap_size_of = "Defined in ipc-channel"]
-    panic_chan: IpcSender<PanicMsg>,
 }
 
 impl Window {
     #[allow(unsafe_code)]
     pub fn clear_js_runtime_for_script_deallocation(&self) {
         unsafe {
             *self.js_runtime.borrow_for_script_deallocation() = None;
             self.browsing_context.set(None);
@@ -1419,20 +1416,16 @@ impl Window {
     pub fn constellation_chan(&self) -> &IpcSender<ConstellationMsg> {
         &self.constellation_chan
     }
 
     pub fn scheduler_chan(&self) -> &IpcSender<TimerEventRequest> {
         &self.scheduler_chan
     }
 
-    pub fn panic_chan(&self) -> &IpcSender<PanicMsg> {
-        &self.panic_chan
-    }
-
     pub fn schedule_callback(&self, callback: OneshotTimerCallback, duration: MsDuration) -> OneshotTimerHandle {
         self.timers.schedule_callback(callback,
                                       duration,
                                       TimerSource::FromWindow(self.id.clone()))
     }
 
     pub fn unschedule_callback(&self, handle: OneshotTimerHandle) {
         self.timers.unschedule_callback(handle);
@@ -1618,17 +1611,16 @@ impl Window {
                resource_threads: ResourceThreads,
                bluetooth_thread: IpcSender<BluetoothMethodMsg>,
                mem_profiler_chan: mem::ProfilerChan,
                time_profiler_chan: ProfilerChan,
                devtools_chan: Option<IpcSender<ScriptToDevtoolsControlMsg>>,
                constellation_chan: IpcSender<ConstellationMsg>,
                control_chan: IpcSender<ConstellationControlMsg>,
                scheduler_chan: IpcSender<TimerEventRequest>,
-               panic_chan: IpcSender<PanicMsg>,
                timer_event_chan: IpcSender<TimerEvent>,
                layout_chan: Sender<Msg>,
                id: PipelineId,
                parent_info: Option<(PipelineId, SubpageId, FrameType)>,
                window_size: Option<WindowSizeData>)
                -> Root<Window> {
         let layout_rpc: Box<LayoutRPC> = {
             let (rpc_send, rpc_recv) = channel();
@@ -1688,17 +1680,16 @@ impl Window {
 
             devtools_marker_sender: DOMRefCell::new(None),
             devtools_markers: DOMRefCell::new(HashSet::new()),
             devtools_wants_updates: Cell::new(false),
             webdriver_script_chan: DOMRefCell::new(None),
             ignore_further_async_events: Arc::new(AtomicBool::new(false)),
             error_reporter: error_reporter,
             scroll_offsets: DOMRefCell::new(HashMap::new()),
-            panic_chan: panic_chan,
         };
 
         WindowBinding::Wrap(runtime.cx(), win)
     }
     pub fn live_devtools_updates(&self) -> bool {
         return self.devtools_wants_updates.get();
     }
 }
--- a/servo/components/script/dom/workerglobalscope.rs
+++ b/servo/components/script/dom/workerglobalscope.rs
@@ -18,17 +18,17 @@ use dom::eventtarget::EventTarget;
 use dom::serviceworkerglobalscope::ServiceWorkerGlobalScope;
 use dom::window::{base64_atob, base64_btoa};
 use dom::workerlocation::WorkerLocation;
 use dom::workernavigator::WorkerNavigator;
 use ipc_channel::ipc::IpcSender;
 use js::jsapi::{HandleValue, JSContext, JSRuntime};
 use js::jsval::UndefinedValue;
 use js::rust::Runtime;
-use msg::constellation_msg::{PipelineId, ReferrerPolicy, PanicMsg};
+use msg::constellation_msg::{PipelineId, ReferrerPolicy};
 use net_traits::{LoadContext, ResourceThreads, load_whole_resource};
 use net_traits::{LoadOrigin, IpcSend};
 use profile_traits::{mem, time};
 use script_runtime::{CommonScriptMsg, ScriptChan, ScriptPort, maybe_take_panic_result};
 use script_thread::RunnableWrapper;
 use script_traits::ScriptMsg as ConstellationMsg;
 use script_traits::WorkerGlobalScopeInit;
 use script_traits::{MsDuration, TimerEvent, TimerEventId, TimerEventRequest, TimerSource};
@@ -53,17 +53,16 @@ pub fn prepare_workerscope_init(global: 
     let worker_id = global.get_next_worker_id();
     let init = WorkerGlobalScopeInit {
             resource_threads: global.resource_threads(),
             mem_profiler_chan: global.mem_profiler_chan().clone(),
             to_devtools_sender: global.devtools_chan(),
             time_profiler_chan: global.time_profiler_chan().clone(),
             from_devtools_sender: devtools_sender,
             constellation_chan: global.constellation_chan().clone(),
-            panic_chan: global.panic_chan().clone(),
             scheduler_chan: global.scheduler_chan().clone(),
             worker_id: worker_id
         };
 
     init
 }
 
 // https://html.spec.whatwg.org/multipage/#the-workerglobalscope-common-interface
@@ -105,19 +104,16 @@ pub struct WorkerGlobalScope {
     /// from the worker
     devtools_wants_updates: Cell<bool>,
 
     #[ignore_heap_size_of = "Defined in std"]
     constellation_chan: IpcSender<ConstellationMsg>,
 
     #[ignore_heap_size_of = "Defined in std"]
     scheduler_chan: IpcSender<TimerEventRequest>,
-
-    #[ignore_heap_size_of = "Defined in ipc-channel"]
-    panic_chan: IpcSender<PanicMsg>,
 }
 
 impl WorkerGlobalScope {
     pub fn new_inherited(init: WorkerGlobalScopeInit,
                          worker_url: Url,
                          runtime: Runtime,
                          from_devtools_receiver: Receiver<DevtoolScriptControlMsg>,
                          timer_event_chan: IpcSender<TimerEvent>,
@@ -139,17 +135,16 @@ impl WorkerGlobalScope {
             mem_profiler_chan: init.mem_profiler_chan,
             time_profiler_chan: init.time_profiler_chan,
             to_devtools_sender: init.to_devtools_sender,
             from_devtools_sender: init.from_devtools_sender,
             from_devtools_receiver: from_devtools_receiver,
             devtools_wants_updates: Cell::new(false),
             constellation_chan: init.constellation_chan,
             scheduler_chan: init.scheduler_chan,
-            panic_chan: init.panic_chan,
         }
     }
 
     pub fn mem_profiler_chan(&self) -> &mem::ProfilerChan {
         &self.mem_profiler_chan
     }
 
     pub fn time_profiler_chan(&self) -> &time::ProfilerChan {
@@ -216,20 +211,16 @@ impl WorkerGlobalScope {
 
     pub fn get_next_worker_id(&self) -> WorkerId {
         let worker_id = self.next_worker_id.get();
         let WorkerId(id_num) = worker_id;
         self.next_worker_id.set(WorkerId(id_num + 1));
         worker_id
     }
 
-    pub fn panic_chan(&self) -> &IpcSender<PanicMsg> {
-        &self.panic_chan
-    }
-
     pub fn get_runnable_wrapper(&self) -> RunnableWrapper {
         RunnableWrapper {
             cancelled: self.closing.clone().unwrap(),
         }
     }
 }
 
 impl LoadOrigin for WorkerGlobalScope {
--- a/servo/components/script/script_thread.rs
+++ b/servo/components/script/script_thread.rs
@@ -59,17 +59,17 @@ use ipc_channel::ipc::{self, IpcSender};
 use ipc_channel::router::ROUTER;
 use js::glue::GetWindowProxyClass;
 use js::jsapi::{DOMProxyShadowsResult, HandleId, HandleObject};
 use js::jsapi::{JSAutoCompartment, JSContext, JS_SetWrapObjectCallbacks};
 use js::jsapi::{JSTracer, SetWindowProxyClass};
 use js::jsval::UndefinedValue;
 use js::rust::Runtime;
 use mem::heap_size_of_self_and_children;
-use msg::constellation_msg::{FrameType, LoadData, PanicMsg, PipelineId, PipelineNamespace};
+use msg::constellation_msg::{FrameType, LoadData, PipelineId, PipelineNamespace};
 use msg::constellation_msg::{SubpageId, WindowSizeType, ReferrerPolicy};
 use net_traits::bluetooth_thread::BluetoothMethodMsg;
 use net_traits::image_cache_thread::{ImageCacheChan, ImageCacheResult, ImageCacheThread};
 use net_traits::{AsyncResponseTarget, CoreResourceMsg, LoadConsumer, LoadContext, Metadata, ResourceThreads};
 use net_traits::{IpcSend, LoadData as NetLoadData};
 use network_listener::NetworkListener;
 use parse::ParserRoot;
 use parse::html::{ParseContext, parse_html};
@@ -388,18 +388,16 @@ pub struct ScriptThread {
     /// List of pipelines that have been owned and closed by this script thread.
     closed_pipelines: DOMRefCell<HashSet<PipelineId>>,
 
     scheduler_chan: IpcSender<TimerEventRequest>,
     timer_event_chan: Sender<TimerEvent>,
     timer_event_port: Receiver<TimerEvent>,
 
     content_process_shutdown_chan: IpcSender<()>,
-
-    panic_chan: IpcSender<PanicMsg>,
 }
 
 /// In the event of thread panic, all data on the stack runs its destructor. However, there
 /// are no reachable, owning pointers to the DOM memory, so it never gets freed by default
 /// when the script thread fails. The ScriptMemoryFailsafe uses the destructor bomb pattern
 /// to forcibly tear down the JS compartments for pages associated with the failing ScriptThread.
 struct ScriptMemoryFailsafe<'a> {
     owner: Option<&'a ScriptThread>,
@@ -436,25 +434,25 @@ impl<'a> Drop for ScriptMemoryFailsafe<'
 }
 
 impl ScriptThreadFactory for ScriptThread {
     type Message = message::Msg;
 
     fn create(state: InitialScriptState,
               load_data: LoadData)
               -> (Sender<message::Msg>, Receiver<message::Msg>) {
-        let panic_chan = state.panic_chan.clone();
         let (script_chan, script_port) = channel();
 
         let (sender, receiver) = channel();
         let layout_chan = sender.clone();
         let pipeline_id = state.id;
-        thread::spawn_named_with_send_on_panic(format!("ScriptThread {:?}", state.id),
-                                               thread_state::SCRIPT,
-                                               move || {
+        thread::spawn_named(format!("ScriptThread {:?}", state.id),
+                            move || {
+            thread_state::initialize(thread_state::SCRIPT);
+            PipelineId::install(pipeline_id);
             PipelineNamespace::install(state.pipeline_namespace_id);
             let roots = RootCollection::new();
             let _stack_roots_tls = StackRootTLS::new(&roots);
             let id = state.id;
             let parent_info = state.parent_info;
             let mem_profiler_chan = state.mem_profiler_chan.clone();
             let window_size = state.window_size;
             let script_thread = ScriptThread::new(state,
@@ -474,17 +472,17 @@ impl ScriptThreadFactory for ScriptThrea
             let reporter_name = format!("script-reporter-{}", id);
             mem_profiler_chan.run_with_memory_reporting(|| {
                 script_thread.start();
                 let _ = script_thread.content_process_shutdown_chan.send(());
             }, reporter_name, script_chan, CommonScriptMsg::CollectReports);
 
             // This must always be the very last operation performed before the thread completes
             failsafe.neuter();
-        }, Some(pipeline_id), panic_chan);
+        });
 
         (sender, receiver)
     }
 }
 
 pub unsafe extern "C" fn shadow_check_callback(_cx: *mut JSContext,
     _object: HandleObject, _id: HandleId) -> DOMProxyShadowsResult {
     // XXX implement me
@@ -587,17 +585,16 @@ impl ScriptThread {
             history_traversal_task_source: HistoryTraversalTaskSource(chan),
             file_reading_task_source: FileReadingTaskSource(boxed_script_sender),
 
             control_chan: state.control_chan,
             control_port: control_port,
             constellation_chan: state.constellation_chan,
             time_profiler_chan: state.time_profiler_chan,
             mem_profiler_chan: state.mem_profiler_chan,
-            panic_chan: state.panic_chan,
 
             devtools_chan: state.devtools_chan,
             devtools_port: devtools_port,
             devtools_sender: ipc_devtools_sender,
 
             js_runtime: Rc::new(runtime),
             topmost_mouse_over_target: MutNullableHeap::new(Default::default()),
             closed_pipelines: DOMRefCell::new(HashSet::new()),
@@ -1137,33 +1134,31 @@ impl ScriptThread {
     fn handle_new_layout(&self, new_layout_info: NewLayoutInfo) {
         let NewLayoutInfo {
             containing_pipeline_id,
             new_pipeline_id,
             subpage_id,
             frame_type,
             load_data,
             paint_chan,
-            panic_chan,
             pipeline_port,
             layout_to_constellation_chan,
             content_process_shutdown_chan,
         } = new_layout_info;
 
         let layout_pair = channel();
         let layout_chan = layout_pair.0.clone();
 
         let layout_creation_info = NewLayoutThreadInfo {
             id: new_pipeline_id,
             url: load_data.url.clone(),
             is_parent: false,
             layout_pair: layout_pair,
             pipeline_port: pipeline_port,
             constellation_chan: layout_to_constellation_chan,
-            panic_chan: panic_chan,
             paint_chan: paint_chan,
             script_chan: self.control_chan.clone(),
             image_cache_thread: self.image_cache_thread.clone(),
             content_process_shutdown_chan: content_process_shutdown_chan,
         };
 
         let context = self.root_browsing_context();
         let parent_context = context.find(containing_pipeline_id).expect("ScriptThread: received a layout
@@ -1598,17 +1593,16 @@ impl ScriptThread {
                                  self.resource_threads.clone(),
                                  self.bluetooth_thread.clone(),
                                  self.mem_profiler_chan.clone(),
                                  self.time_profiler_chan.clone(),
                                  self.devtools_chan.clone(),
                                  self.constellation_chan.clone(),
                                  self.control_chan.clone(),
                                  self.scheduler_chan.clone(),
-                                 self.panic_chan.clone(),
                                  ipc_timer_event_chan,
                                  incomplete.layout_chan,
                                  incomplete.pipeline_id,
                                  incomplete.parent_info,
                                  incomplete.window_size);
         let frame_element = frame_element.r().map(Castable::upcast);
 
         enum ContextToRemove {
--- a/servo/components/script_layout_interface/message.rs
+++ b/servo/components/script_layout_interface/message.rs
@@ -2,17 +2,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use app_units::Au;
 use euclid::point::Point2D;
 use euclid::rect::Rect;
 use gfx_traits::{Epoch, LayerId};
 use ipc_channel::ipc::{IpcReceiver, IpcSender};
-use msg::constellation_msg::{PanicMsg, PipelineId};
+use msg::constellation_msg::PipelineId;
 use net_traits::image_cache_thread::ImageCacheThread;
 use profile_traits::mem::ReportsChan;
 use rpc::LayoutRPC;
 use script_traits::{ConstellationControlMsg, LayoutControlMsg};
 use script_traits::{LayoutMsg as ConstellationMsg, StackingContextScrollState, WindowSizeData};
 use std::sync::Arc;
 use std::sync::mpsc::{Receiver, Sender};
 use string_cache::Atom;
@@ -140,14 +140,13 @@ impl Drop for ScriptReflow {
 
 pub struct NewLayoutThreadInfo {
     pub id: PipelineId,
     pub url: Url,
     pub is_parent: bool,
     pub layout_pair: (Sender<Msg>, Receiver<Msg>),
     pub pipeline_port: IpcReceiver<LayoutControlMsg>,
     pub constellation_chan: IpcSender<ConstellationMsg>,
-    pub panic_chan: IpcSender<PanicMsg>,
     pub script_chan: IpcSender<ConstellationControlMsg>,
     pub image_cache_thread: ImageCacheThread,
     pub paint_chan: OptionalOpaqueIpcSender,
     pub content_process_shutdown_chan: IpcSender<()>,
 }
--- a/servo/components/script_traits/lib.rs
+++ b/servo/components/script_traits/lib.rs
@@ -46,17 +46,17 @@ use euclid::size::TypedSize2D;
 use gfx_traits::Epoch;
 use gfx_traits::LayerId;
 use gfx_traits::StackingContextId;
 use heapsize::HeapSizeOf;
 use ipc_channel::ipc::{IpcReceiver, IpcSender};
 use layers::geometry::DevicePixel;
 use libc::c_void;
 use msg::constellation_msg::{FrameId, FrameType, Image, Key, KeyModifiers, KeyState, LoadData};
-use msg::constellation_msg::{NavigationDirection, PanicMsg, PipelineId, ReferrerPolicy};
+use msg::constellation_msg::{NavigationDirection, PipelineId, ReferrerPolicy};
 use msg::constellation_msg::{PipelineNamespaceId, SubpageId, WindowSizeType};
 use net_traits::bluetooth_thread::BluetoothMethodMsg;
 use net_traits::image_cache_thread::ImageCacheThread;
 use net_traits::response::HttpsState;
 use net_traits::{LoadOrigin, ResourceThreads};
 use profile_traits::mem;
 use profile_traits::time as profile_time;
 use serde::{Deserialize, Deserializer, Serialize, Serializer};
@@ -137,18 +137,16 @@ pub struct NewLayoutInfo {
     pub frame_type: FrameType,
     /// Network request data which will be initiated by the script thread.
     pub load_data: LoadData,
     /// The paint channel, cast to `OptionalOpaqueIpcSender`. This is really an
     /// `Sender<LayoutToPaintMsg>`.
     pub paint_chan: OptionalOpaqueIpcSender,
     /// A port on which layout can receive messages from the pipeline.
     pub pipeline_port: IpcReceiver<LayoutControlMsg>,
-    /// A channel for sending panics on
-    pub panic_chan: IpcSender<PanicMsg>,
     /// A sender for the layout thread to communicate to the constellation.
     pub layout_to_constellation_chan: IpcSender<LayoutMsg>,
     /// A shutdown channel so that layout can tell the content process to shut down when it's done.
     pub content_process_shutdown_chan: IpcSender<()>,
 }
 
 /// Messages sent from the constellation or layout to the script thread.
 #[derive(Deserialize, Serialize)]
@@ -389,18 +387,16 @@ pub struct InitialScriptState {
     /// If `None`, this is the root.
     pub parent_info: Option<(PipelineId, SubpageId, FrameType)>,
     /// A channel with which messages can be sent to us (the script thread).
     pub control_chan: IpcSender<ConstellationControlMsg>,
     /// A port on which messages sent by the constellation to script can be received.
     pub control_port: IpcReceiver<ConstellationControlMsg>,
     /// A channel on which messages can be sent to the constellation from script.
     pub constellation_chan: IpcSender<ScriptMsg>,
-    /// A channel for sending panics to the constellation.
-    pub panic_chan: IpcSender<PanicMsg>,
     /// A channel to schedule timer events.
     pub scheduler_chan: IpcSender<TimerEventRequest>,
     /// A channel to the resource manager thread.
     pub resource_threads: ResourceThreads,
     /// A channel to the bluetooth thread.
     pub bluetooth_thread: IpcSender<BluetoothMethodMsg>,
     /// A channel to the image cache thread.
     pub image_cache_thread: ImageCacheThread,
@@ -466,18 +462,18 @@ pub enum MozBrowserEvent {
     /// Sent when the scroll position within a browser `<iframe>` changes.
     AsyncScroll,
     /// Sent when window.close() is called within a browser `<iframe>`.
     Close,
     /// Sent when a browser `<iframe>` tries to open a context menu. This allows
     /// handling `<menuitem>` element available within the browser `<iframe>`'s content.
     ContextMenu,
     /// Sent when an error occurred while trying to load content within a browser `<iframe>`.
-    /// Includes an optional human-readable description, and an optional machine-readable report.
-    Error(MozBrowserErrorType, Option<String>, Option<String>),
+    /// Includes a human-readable description, and a machine-readable report.
+    Error(MozBrowserErrorType, String, String),
     /// Sent when the favicon of a browser `<iframe>` changes.
     IconChange(String, String, String),
     /// Sent when the browser `<iframe>` has reached the server.
     Connected,
     /// Sent when the browser `<iframe>` has finished loading all its assets.
     LoadEnd,
     /// Sent when the browser `<iframe>` starts to load a new page.
     LoadStart,
@@ -651,18 +647,16 @@ pub struct WorkerGlobalScopeInit {
     /// To devtools sender
     pub to_devtools_sender: Option<IpcSender<ScriptToDevtoolsControlMsg>>,
     /// From devtools sender
     pub from_devtools_sender: Option<IpcSender<DevtoolScriptControlMsg>>,
     /// Messages to send to constellation
     pub constellation_chan: IpcSender<ScriptMsg>,
     /// Message to send to the scheduler
     pub scheduler_chan: IpcSender<TimerEventRequest>,
-    /// Sender which sends panic messages
-    pub panic_chan: IpcSender<PanicMsg>,
     /// The worker id
     pub worker_id: WorkerId,
 }
 
 /// Common entities representing a network load origin
 #[derive(Deserialize, Serialize, Clone)]
 pub struct WorkerScriptLoadOrigin {
     /// referrer url
--- a/servo/components/servo/Cargo.lock
+++ b/servo/components/servo/Cargo.lock
@@ -2404,17 +2404,16 @@ name = "utf8-ranges"
 version = "0.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "util"
 version = "0.0.1"
 dependencies = [
  "app_units 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "backtrace 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "euclid 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
  "heapsize 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "ipc-channel 0.4.0 (git+https://github.com/servo/ipc-channel)",
  "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "num_cpus 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)",
--- a/servo/components/servo/main.rs
+++ b/servo/components/servo/main.rs
@@ -21,30 +21,29 @@
 #[macro_use]
 extern crate android_glue;
 #[cfg(not(target_os = "android"))]
 extern crate backtrace;
 // The window backed by glutin
 extern crate glutin_app as app;
 #[cfg(target_os = "android")]
 extern crate libc;
-#[cfg(target_os = "android")]
 #[macro_use]
 extern crate log;
 // The Servo engine
 extern crate servo;
 #[cfg(not(target_os = "android"))]
 #[macro_use]
 extern crate sig;
 
 use servo::Browser;
 use servo::compositing::windowing::WindowEvent;
 use servo::util::opts::{self, ArgumentParsingResult};
-use servo::util::panicking::initiate_panic_hook;
 use servo::util::servo_version;
+use std::panic;
 use std::process;
 use std::rc::Rc;
 
 pub mod platform {
     #[cfg(target_os = "macos")]
     pub use platform::macos::deinit;
 
     #[cfg(target_os = "macos")]
@@ -89,17 +88,30 @@ fn main() {
     } else {
         if opts::get().is_running_problem_test && ::std::env::var("RUST_LOG").is_err() {
             ::std::env::set_var("RUST_LOG", "compositing::constellation");
         }
 
         None
     };
 
-    initiate_panic_hook();
+    // TODO: once log-panics is released, this can be replaced by
+    // log_panics::init();
+    panic::set_hook(Box::new(|info| {
+        warn!("Panic hook called.");
+        let msg = match info.payload().downcast_ref::<&'static str>() {
+            Some(s) => *s,
+            None => match info.payload().downcast_ref::<String>() {
+                Some(s) => &**s,
+                None => "Box<Any>",
+            },
+        };
+        error!("{}", msg);
+    }));
+
     setup_logging();
 
     if let Some(token) = content_process_token {
         return servo::run_content_process(token)
     }
 
     if opts::get().is_printing_version {
         println!("{}", servo_version());
--- a/servo/components/util/Cargo.toml
+++ b/servo/components/util/Cargo.toml
@@ -6,22 +6,21 @@ license = "MPL-2.0"
 publish = false
 
 [lib]
 name = "util"
 path = "lib.rs"
 
 [features]
 # servo as opposed to geckolib
-servo = ["serde", "serde_macros", "backtrace", "ipc-channel", "app_units/plugins",
+servo = ["serde", "serde_macros", "ipc-channel", "app_units/plugins",
          "euclid/plugins", "euclid/unstable", "url/heap_size", "url/serde", "plugins"]
 
 [dependencies]
 app_units = "0.2.5"
-backtrace = {version = "0.2.1", optional = true}
 bitflags = "0.7"
 euclid = "0.7.1"
 getopts = "0.2.11"
 heapsize = "0.3.0"
 ipc-channel = {git = "https://github.com/servo/ipc-channel", optional = true}
 lazy_static = "0.2"
 log = "0.3.5"
 num_cpus = "0.2.2"
--- a/servo/components/util/lib.rs
+++ b/servo/components/util/lib.rs
@@ -1,23 +1,21 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #![cfg_attr(feature = "servo", feature(custom_derive))]
-#![cfg_attr(feature = "servo", feature(fnbox))]
 #![cfg_attr(feature = "servo", feature(plugin))]
 #![cfg_attr(feature = "servo", feature(reflect_marker))]
 #![cfg_attr(feature = "servo", plugin(serde_macros))]
 #![cfg_attr(feature = "servo", plugin(plugins))]
 
 #![deny(unsafe_code)]
 
 extern crate app_units;
-#[cfg(feature = "servo")] extern crate backtrace;
 #[allow(unused_extern_crates)] #[macro_use] extern crate bitflags;
 extern crate euclid;
 extern crate getopts;
 #[macro_use] extern crate heapsize;
 #[cfg(feature = "servo")] extern crate ipc_channel;
 #[allow(unused_extern_crates)] #[macro_use] extern crate lazy_static;
 #[macro_use] extern crate log;
 extern crate num_cpus;
@@ -26,17 +24,16 @@ extern crate rustc_serialize;
 extern crate url;
 #[cfg(all(unix, not(target_os = "macos"), not(target_os = "ios"), not(target_os = "android")))]
 extern crate xdg;
 
 pub mod basedir;
 pub mod geometry;
 #[cfg(feature = "servo")] #[allow(unsafe_code)] pub mod ipc;
 #[allow(unsafe_code)] pub mod opts;
-#[cfg(feature = "servo")] pub mod panicking;
 pub mod prefs;
 pub mod resource_files;
 pub mod thread;
 pub mod thread_state;
 
 pub fn servo_version() -> &'static str {
     concat!("Servo ", env!("CARGO_PKG_VERSION"), env!("GIT_INFO"))
 }
deleted file mode 100644
--- a/servo/components/util/panicking.rs
+++ /dev/null
@@ -1,52 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-use std::any::Any;
-use std::boxed::FnBox;
-use std::cell::RefCell;
-use std::panic::{PanicInfo, take_hook, set_hook};
-use std::sync::{Once, ONCE_INIT};
-use std::thread;
-
-// only set the panic hook once
-static HOOK_SET: Once = ONCE_INIT;
-
-/// TLS data pertaining to how failures should be reported
-pub struct PanicHandlerLocal {
-    /// failure handler passed through spawn_named_with_send_on_failure
-    pub fail: Box<FnBox(&Any)>
-}
-
-thread_local!(pub static LOCAL_INFO: RefCell<Option<PanicHandlerLocal>> = RefCell::new(None));
-
-/// Set the thread-local panic hook
-pub fn set_thread_local_hook(local: Box<FnBox(&Any)>) {
-    LOCAL_INFO.with(|i| *i.borrow_mut() = Some(PanicHandlerLocal { fail: local }));
-}
-
-/// Initiates the custom panic hook
-/// Should be called in main() after arguments have been parsed
-pub fn initiate_panic_hook() {
-    // Set the panic handler only once. It is global.
-    HOOK_SET.call_once(|| {
-        // The original backtrace-printing hook. We still want to call this
-        let hook = take_hook();
-
-        let new_hook = move |info: &PanicInfo| {
-            let payload = info.payload();
-            let name = thread::current().name().unwrap_or("<unknown thread>").to_string();
-            // Notify error handlers stored in LOCAL_INFO if any
-            LOCAL_INFO.with(|i| {
-                if let Some(local_info) = i.borrow_mut().take() {
-                    debug!("Thread `{}` failed, notifying error handlers", name);
-                    (local_info.fail).call_box((payload, ));
-                } else {
-                    hook(&info);
-                }
-            });
-        };
-        set_hook(Box::new(new_hook));
-    });
-
-}
--- a/servo/components/util/thread.rs
+++ b/servo/components/util/thread.rs
@@ -1,53 +1,11 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#[cfg(feature = "servo")] use backtrace::Backtrace;
-#[cfg(feature = "servo")] use ipc_channel::ipc::IpcSender;
-#[cfg(feature = "servo")] use panicking;
-#[cfg(feature = "servo")] use serde::Serialize;
-#[cfg(feature = "servo")] use std::any::Any;
-#[cfg(feature = "servo")] use thread_state;
 use std::thread;
 
 pub fn spawn_named<F>(name: String, f: F)
     where F: FnOnce() + Send + 'static
 {
     thread::Builder::new().name(name).spawn(f).expect("Thread spawn failed");
 }
-
-/// Arrange to send a particular message to a channel if the thread fails.
-#[cfg(feature = "servo")]
-pub fn spawn_named_with_send_on_panic<F, Id>(name: String,
-                                             state: thread_state::ThreadState,
-                                             f: F,
-                                             id: Id,
-                                             panic_chan: IpcSender<(Id, String, String)>)
-    where F: FnOnce() + Send + 'static,
-          Id: Copy + Send + Serialize + 'static,
-{
-    thread::Builder::new().name(name).spawn(move || {
-        thread_state::initialize(state);
-        panicking::set_thread_local_hook(Box::new(move |payload: &Any| {
-            debug!("Thread failed, notifying constellation");
-            let reason = payload.downcast_ref::<String>().map(|s| String::from(&**s))
-                .or(payload.downcast_ref::<&'static str>().map(|s| String::from(*s)))
-                .unwrap_or_else(|| String::from("<unknown reason>"));
-            // FIXME(ajeffrey): Really we should send the backtrace itself,
-            // not just a string representation. Unfortunately we can't, because
-            // Servo won't compile backtrace with the serialize-serde feature:
-            //
-            // .../quasi_macros-0.9.0/src/lib.rs:19:29: 19:32 error: mismatched types:
-            //  expected `&mut syntex::Registry`,
-            //     found `&mut rustc_plugin::Registry<'_>`
-            // (expected struct `syntex::Registry`,
-            //     found struct `rustc_plugin::Registry`) [E0308]
-            // .../quasi_macros-0.9.0/src/lib.rs:19     quasi_codegen::register(reg);
-            //
-            // so for the moment we just send a debug string.
-            let backtrace = format!("{:?}", Backtrace::new());
-            let _ = panic_chan.send((id, reason, backtrace));
-        }));
-        f()
-    }).expect("Thread spawn failed");
-}
--- a/servo/ports/cef/Cargo.lock
+++ b/servo/ports/cef/Cargo.lock
@@ -2273,17 +2273,16 @@ name = "utf8-ranges"
 version = "0.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "util"
 version = "0.0.1"
 dependencies = [
  "app_units 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "backtrace 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "euclid 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
  "heapsize 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "ipc-channel 0.4.0 (git+https://github.com/servo/ipc-channel)",
  "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "num_cpus 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)",