servo: Merge #18600 - Improve Promise (from servo:promises); r=<try>
authorAnthony Ramine <n.oxyde@gmail.com>
Fri, 22 Sep 2017 07:36:38 -0500
changeset 669097 381d7636b03dbb7d2f40924702318edce6aed59e
parent 669096 bdfb0bd22f0863a559703f94f42c77741e84d2fa
child 669098 3ed606c9faa030c744d14aaaec814fd7e2a5bb2c
push id81210
push userkgupta@mozilla.com
push dateFri, 22 Sep 2017 14:09:59 +0000
milestone58.0a1
servo: Merge #18600 - Improve Promise (from servo:promises); r=<try> The elephant 🐘 (not PHP's) still remains in the room: `Rc<Promise>` shouldn't require `#⁠[allow(unrooted_must_root)]`. Source-Repo: https://github.com/servo/servo Source-Revision: 4af0d9acb3f5724cac9f40a46ee03ab364a053bc
servo/components/script/body.rs
servo/components/script/dom/bindings/codegen/CodegenRust.py
servo/components/script/dom/bindings/refcounted.rs
servo/components/script/dom/bluetooth.rs
servo/components/script/dom/bluetoothdevice.rs
servo/components/script/dom/bluetoothpermissionresult.rs
servo/components/script/dom/bluetoothremotegattcharacteristic.rs
servo/components/script/dom/bluetoothremotegattdescriptor.rs
servo/components/script/dom/bluetoothremotegattserver.rs
servo/components/script/dom/bluetoothremotegattservice.rs
servo/components/script/dom/customelementregistry.rs
servo/components/script/dom/document.rs
servo/components/script/dom/element.rs
servo/components/script/dom/permissions.rs
servo/components/script/dom/promise.rs
servo/components/script/dom/serviceworkercontainer.rs
servo/components/script/dom/testbinding.rs
servo/components/script/dom/vr.rs
servo/components/script/dom/vrdisplay.rs
servo/components/script/dom/worklet.rs
servo/components/script/fetch.rs
servo/components/script/serviceworkerjob.rs
--- a/servo/components/script/body.rs
+++ b/servo/components/script/body.rs
@@ -39,18 +39,19 @@ pub enum FetchedData {
 
 // https://fetch.spec.whatwg.org/#concept-body-consume-body
 #[allow(unrooted_must_root)]
 pub fn consume_body<T: BodyOperations + DomObject>(object: &T, body_type: BodyType) -> Rc<Promise> {
     let promise = Promise::new(&object.global());
 
     // Step 1
     if object.get_body_used() || object.is_locked() {
-        promise.reject_error(promise.global().get_cx(), Error::Type(
-            "The response's stream is disturbed or locked".to_string()));
+        promise.reject_error(Error::Type(
+            "The response's stream is disturbed or locked".to_string(),
+        ));
         return promise;
     }
 
     object.set_body_promise(&promise, body_type);
 
     // Steps 2-4
     // TODO: Body does not yet have a stream.
 
@@ -70,27 +71,26 @@ pub fn consume_body_with_promise<T: Body
         None => return,
     };
 
     let pkg_data_results = run_package_data_algorithm(object,
                                                       body,
                                                       body_type,
                                                       object.get_mime_type());
 
-    let cx = promise.global().get_cx();
     match pkg_data_results {
         Ok(results) => {
             match results {
-                FetchedData::Text(s) => promise.resolve_native(cx, &USVString(s)),
-                FetchedData::Json(j) => promise.resolve_native(cx, &j),
-                FetchedData::BlobData(b) => promise.resolve_native(cx, &b),
-                FetchedData::FormData(f) => promise.resolve_native(cx, &f),
+                FetchedData::Text(s) => promise.resolve_native(&USVString(s)),
+                FetchedData::Json(j) => promise.resolve_native(&j),
+                FetchedData::BlobData(b) => promise.resolve_native(&b),
+                FetchedData::FormData(f) => promise.resolve_native(&f),
             };
         },
-        Err(err) => promise.reject_error(cx, err),
+        Err(err) => promise.reject_error(err),
     }
 }
 
 // https://fetch.spec.whatwg.org/#concept-body-package-data
 #[allow(unsafe_code)]
 fn run_package_data_algorithm<T: BodyOperations + DomObject>(object: &T,
                                                              bytes: Vec<u8>,
                                                              body_type: BodyType,
--- a/servo/components/script/dom/bindings/codegen/CodegenRust.py
+++ b/servo/components/script/dom/bindings/codegen/CodegenRust.py
@@ -783,17 +783,17 @@ def getJSToNativeConversionInfo(type, de
 
                 rooted!(in(cx) let globalObj = CurrentGlobalOrNull(cx));
                 let promiseGlobal = GlobalScope::from_object_maybe_wrapped(globalObj.handle().get());
 
                 rooted!(in(cx) let mut valueToResolve = $${val}.get());
                 if !JS_WrapValue(cx, valueToResolve.handle_mut()) {
                 $*{exceptionCode}
                 }
-                match Promise::Resolve(&promiseGlobal, cx, valueToResolve.handle()) {
+                match Promise::new_resolved(&promiseGlobal, cx, valueToResolve.handle()) {
                     Ok(value) => value,
                     Err(error) => {
                     throw_dom_exception(cx, &promiseGlobal, error);
                     $*{exceptionCode}
                     }
                 }
             }
             """,
--- a/servo/components/script/dom/bindings/refcounted.rs
+++ b/servo/components/script/dom/bindings/refcounted.rs
@@ -24,17 +24,16 @@
 
 use core::nonzero::NonZero;
 use dom::bindings::conversions::ToJSValConvertible;
 use dom::bindings::error::Error;
 use dom::bindings::js::Root;
 use dom::bindings::reflector::{DomObject, Reflector};
 use dom::bindings::trace::trace_reflector;
 use dom::promise::Promise;
-use js::jsapi::JSAutoCompartment;
 use js::jsapi::JSTracer;
 use libc;
 use std::cell::RefCell;
 use std::collections::hash_map::Entry::{Occupied, Vacant};
 use std::collections::hash_map::HashMap;
 use std::hash::Hash;
 use std::marker::PhantomData;
 use std::os;
@@ -121,36 +120,30 @@ impl TrustedPromise {
     }
 
     /// A task which will reject the promise.
     #[allow(unrooted_must_root)]
     pub fn reject_task(self, error: Error) -> impl TaskOnce {
         let this = self;
         task!(reject_promise: move || {
             debug!("Rejecting promise.");
-            let this = this.root();
-            let cx = this.global().get_cx();
-            let _ac = JSAutoCompartment::new(cx, this.reflector().get_jsobject().get());
-            this.reject_error(cx, error);
+            this.root().reject_error(error);
         })
     }
 
     /// A task which will resolve the promise.
     #[allow(unrooted_must_root)]
     pub fn resolve_task<T>(self, value: T) -> impl TaskOnce
     where
         T: ToJSValConvertible + Send,
     {
         let this = self;
         task!(resolve_promise: move || {
             debug!("Resolving promise.");
-            let this = this.root();
-            let cx = this.global().get_cx();
-            let _ac = JSAutoCompartment::new(cx, this.reflector().get_jsobject().get());
-            this.resolve_native(cx, &value);
+            this.root().resolve_native(&value);
         })
     }
 }
 
 /// A safe wrapper around a raw pointer to a DOM object that can be
 /// shared among threads for use in asynchronous operations. The underlying
 /// DOM object is guaranteed to live at least as long as the last outstanding
 /// `Trusted<T>` instance.
--- a/servo/components/script/dom/bluetooth.rs
+++ b/servo/components/script/dom/bluetooth.rs
@@ -28,17 +28,17 @@ use dom::bluetoothuuid::{BluetoothServic
 use dom::eventtarget::EventTarget;
 use dom::globalscope::GlobalScope;
 use dom::permissions::{get_descriptor_permission_state, PermissionAlgorithm};
 use dom::promise::Promise;
 use dom_struct::dom_struct;
 use ipc_channel::ipc::{self, IpcSender};
 use ipc_channel::router::ROUTER;
 use js::conversions::ConversionResult;
-use js::jsapi::{JSAutoCompartment, JSContext, JSObject};
+use js::jsapi::{JSContext, JSObject};
 use js::jsval::{ObjectValue, UndefinedValue};
 use std::cell::Ref;
 use std::collections::HashMap;
 use std::rc::Rc;
 use std::str::FromStr;
 use std::sync::{Arc, Mutex};
 use task::TaskOnce;
 
@@ -89,33 +89,34 @@ impl BluetoothExtraPermissionData {
 }
 
 struct BluetoothContext<T: AsyncBluetoothListener + DomObject> {
     promise: Option<TrustedPromise>,
     receiver: Trusted<T>,
 }
 
 pub trait AsyncBluetoothListener {
-    fn handle_response(&self, result: BluetoothResponse, cx: *mut JSContext, promise: &Rc<Promise>);
+    fn handle_response(&self, result: BluetoothResponse, promise: &Rc<Promise>);
 }
 
-impl<T: AsyncBluetoothListener + DomObject> BluetoothContext<T> {
+impl<T> BluetoothContext<T>
+where
+    T: AsyncBluetoothListener + DomObject,
+{
     #[allow(unrooted_must_root)]
     fn response(&mut self, response: BluetoothResponseResult) {
         let promise = self.promise.take().expect("bt promise is missing").root();
-        let promise_cx = promise.global().get_cx();
 
         // JSAutoCompartment needs to be manually made.
         // Otherwise, Servo will crash.
-        let _ac = JSAutoCompartment::new(promise_cx, promise.reflector().get_jsobject().get());
         match response {
-            Ok(response) => self.receiver.root().handle_response(response, promise_cx, &promise),
+            Ok(response) => self.receiver.root().handle_response(response, &promise),
             // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetooth-requestdevice
             // Step 3 - 4.
-            Err(error) => promise.reject_error(promise_cx, Error::from(error)),
+            Err(error) => promise.reject_error(Error::from(error)),
         }
     }
 }
 
 // https://webbluetoothcg.github.io/web-bluetooth/#bluetooth
 #[dom_struct]
 pub struct Bluetooth {
     eventtarget: EventTarget,
@@ -153,45 +154,45 @@ impl Bluetooth {
         // TODO: Step 1: Triggered by user activation.
 
         // Step 2.2: There are no requiredServiceUUIDS, we scan for all devices.
         let mut uuid_filters = vec!();
 
         if let &Some(ref filters) = filters {
             // Step 2.1.
             if filters.is_empty()  {
-                p.reject_error(p.global().get_cx(), Type(FILTER_EMPTY_ERROR.to_owned()));
+                p.reject_error(Type(FILTER_EMPTY_ERROR.to_owned()));
                 return;
             }
 
             // Step 2.3: There are no requiredServiceUUIDS, we scan for all devices.
 
             // Step 2.4.
             for filter in filters {
                 // Step 2.4.1.
                 match canonicalize_filter(&filter) {
                     // Step 2.4.2.
                     Ok(f) => uuid_filters.push(f),
                     Err(e) => {
-                        p.reject_error(p.global().get_cx(), e);
+                        p.reject_error(e);
                         return;
                     },
                 }
                 // Step 2.4.3: There are no requiredServiceUUIDS, we scan for all devices.
             }
         }
 
         let mut optional_services_uuids = vec!();
         if let &Some(ref opt_services) = optional_services {
             for opt_service in opt_services {
                 // Step 2.5 - 2.6.
                 let uuid = match BluetoothUUID::service(opt_service.clone()) {
                     Ok(u) => u.to_string(),
                     Err(e) => {
-                        p.reject_error(p.global().get_cx(), e);
+                        p.reject_error(e);
                         return;
                     },
                 };
 
                 // Step 2.7.
                 // Note: What we are doing here, is adding the not blocklisted UUIDs to the result vector,
                 // instead of removing them from an already filled vector.
                 if !uuid_is_blocklisted(uuid.as_ref(), Blocklist::All) {
@@ -200,17 +201,17 @@ impl Bluetooth {
             }
         }
 
         let option = RequestDeviceoptions::new(BluetoothScanfilterSequence::new(uuid_filters),
                                                ServiceUUIDSequence::new(optional_services_uuids));
 
         // Step 4 - 5.
         if let PermissionState::Denied = get_descriptor_permission_state(PermissionName::Bluetooth, None) {
-            return p.reject_error(p.global().get_cx(), Error::NotFound);
+            return p.reject_error(Error::NotFound);
         }
 
         // Note: Step 3, 6 - 8 are implemented in
         // components/net/bluetooth_thread.rs in request_device function.
         self.get_bluetooth_thread().send(BluetoothRequest::RequestDevice(option, sender)).unwrap();
     }
 }
 
@@ -261,40 +262,39 @@ pub fn get_gatt_children<T, F> (
         uuid: Option<StringOrUnsignedLong>,
         instance_id: String,
         connected: bool,
         child_type: GATTType)
         -> Rc<Promise>
         where T: AsyncBluetoothListener + DomObject + 'static,
               F: FnOnce(StringOrUnsignedLong) -> Fallible<UUID> {
     let p = Promise::new(&attribute.global());
-    let p_cx = p.global().get_cx();
 
     let result_uuid = if let Some(u) = uuid {
         // Step 1.
         let canonicalized = match uuid_canonicalizer(u) {
             Ok(canonicalized_uuid) => canonicalized_uuid.to_string(),
             Err(e) => {
-                p.reject_error(p_cx, e);
+                p.reject_error(e);
                 return p;
             }
         };
         // Step 2.
         if uuid_is_blocklisted(canonicalized.as_ref(), Blocklist::All) {
-            p.reject_error(p_cx, Security);
+            p.reject_error(Security);
             return p;
         }
         Some(canonicalized)
     } else {
         None
     };
 
     // Step 3 - 4.
     if !connected {
-        p.reject_error(p_cx, Network);
+        p.reject_error(Network);
         return p;
     }
 
     // TODO: Step 5: Implement representedDevice internal slot for BluetoothDevice.
 
     // Note: Steps 6 - 7 are implemented in components/bluetooth/lib.rs in get_descriptor function
     // and in handle_response function.
     let sender = response_async(&p, attribute);
@@ -474,17 +474,17 @@ impl From<BluetoothError> for Error {
 impl BluetoothMethods for Bluetooth {
     #[allow(unrooted_must_root)]
     // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetooth-requestdevice
     fn RequestDevice(&self, option: &RequestDeviceOptions) -> Rc<Promise> {
         let p = Promise::new(&self.global());
         // Step 1.
         if (option.filters.is_some() && option.acceptAllDevices) ||
            (option.filters.is_none() && !option.acceptAllDevices) {
-            p.reject_error(p.global().get_cx(), Error::Type(OPTIONS_ERROR.to_owned()));
+            p.reject_error(Error::Type(OPTIONS_ERROR.to_owned()));
             return p;
         }
 
         // Step 2.
         let sender = response_async(&p, self);
         self.request_bluetooth_devices(&p, &option.filters, &option.optionalServices, sender);
         //Note: Step 3 - 4. in response function, Step 5. in handle_response function.
         return p;
@@ -502,47 +502,47 @@ impl BluetoothMethods for Bluetooth {
         p
     }
 
     // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetooth-onavailabilitychanged
     event_handler!(availabilitychanged, GetOnavailabilitychanged, SetOnavailabilitychanged);
 }
 
 impl AsyncBluetoothListener for Bluetooth {
-    fn handle_response(&self, response: BluetoothResponse, promise_cx: *mut JSContext, promise: &Rc<Promise>) {
+    fn handle_response(&self, response: BluetoothResponse, promise: &Rc<Promise>) {
         match response {
             // https://webbluetoothcg.github.io/web-bluetooth/#request-bluetooth-devices
             // Step 11, 13 - 14.
             BluetoothResponse::RequestDevice(device) => {
                 let mut device_instance_map = self.device_instance_map.borrow_mut();
                 if let Some(existing_device) = device_instance_map.get(&device.id.clone()) {
-                    return promise.resolve_native(promise_cx, &**existing_device);
+                    return promise.resolve_native(&**existing_device);
                 }
                 let bt_device = BluetoothDevice::new(&self.global(),
                                                      DOMString::from(device.id.clone()),
                                                      device.name.map(DOMString::from),
                                                      &self);
                 device_instance_map.insert(device.id.clone(), JS::from_ref(&bt_device));
 
                 self.global().as_window().bluetooth_extra_permission_data().add_new_allowed_device(
                     AllowedBluetoothDevice {
                         deviceId: DOMString::from(device.id),
                         mayUseGATT: true,
                     }
                 );
                 // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetooth-requestdevice
                 // Step 5.
-                promise.resolve_native(promise_cx, &bt_device);
+                promise.resolve_native(&bt_device);
             },
             // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetooth-getavailability
             // Step 2 - 3.
             BluetoothResponse::GetAvailability(is_available) => {
-                promise.resolve_native(promise_cx, &is_available);
+                promise.resolve_native(&is_available);
             }
-            _ => promise.reject_error(promise_cx, Error::Type("Something went wrong...".to_owned())),
+            _ => promise.reject_error(Error::Type("Something went wrong...".to_owned())),
         }
     }
 }
 
 impl PermissionAlgorithm for Bluetooth {
     type Descriptor = BluetoothPermissionDescriptor;
     type Status = BluetoothPermissionResult;
 
@@ -557,28 +557,31 @@ impl PermissionAlgorithm for Bluetooth {
                 Ok(ConversionResult::Success(descriptor)) => Ok(descriptor),
                 Ok(ConversionResult::Failure(error)) => Err(Error::Type(error.into_owned())),
                 Err(_) => Err(Error::Type(String::from(BT_DESC_CONVERSION_ERROR))),
             }
         }
     }
 
     // https://webbluetoothcg.github.io/web-bluetooth/#query-the-bluetooth-permission
-    fn permission_query(cx: *mut JSContext, promise: &Rc<Promise>,
-                        descriptor: &BluetoothPermissionDescriptor,
-                        status: &BluetoothPermissionResult) {
+    fn permission_query(
+        _cx: *mut JSContext,
+        promise: &Rc<Promise>,
+        descriptor: &BluetoothPermissionDescriptor,
+        status: &BluetoothPermissionResult,
+    ) {
         // Step 1: We are not using the `global` variable.
 
         // Step 2.
         status.set_state(get_descriptor_permission_state(status.get_query(), None));
 
         // Step 3.
         if let PermissionState::Denied = status.get_state() {
             status.set_devices(Vec::new());
-            return promise.resolve_native(cx, status);
+            return promise.resolve_native(status);
         }
 
         // Step 4.
         rooted_vec!(let mut matching_devices);
 
         // Step 5.
         let global = status.global();
         let allowed_devices = global.as_window().bluetooth_extra_permission_data().get_allowed_devices();
@@ -599,59 +602,62 @@ impl PermissionAlgorithm for Bluetooth {
             // Step 6.2.
             if let Some(ref filters) = descriptor.filters {
                 let mut scan_filters: Vec<BluetoothScanfilter> = Vec::new();
 
                 // Step 6.2.1.
                 for filter in filters {
                     match canonicalize_filter(&filter) {
                         Ok(f) => scan_filters.push(f),
-                        Err(error) => return promise.reject_error(cx, error),
+                        Err(error) => return promise.reject_error(error),
                     }
                 }
 
                 // Step 6.2.2.
                 // Instead of creating an internal slot we send an ipc message to the Bluetooth thread
                 // to check if one of the filters matches.
                 let (sender, receiver) = ipc::channel().unwrap();
                 status.get_bluetooth_thread()
                       .send(BluetoothRequest::MatchesFilter(device_id.clone(),
                                                             BluetoothScanfilterSequence::new(scan_filters),
                                                             sender)).unwrap();
 
                 match receiver.recv().unwrap() {
                     Ok(true) => (),
                     Ok(false) => continue,
-                    Err(error) => return promise.reject_error(cx, Error::from(error)),
+                    Err(error) => return promise.reject_error(Error::from(error)),
                 };
             }
 
             // Step 6.3.
             // TODO: Implement this correctly, not just using device ids here.
             // https://webbluetoothcg.github.io/web-bluetooth/#get-the-bluetoothdevice-representing
             if let Some(device) = device_map.get(&device_id) {
                 matching_devices.push(JS::from_ref(&**device));
             }
         }
 
         // Step 7.
         status.set_devices(matching_devices.drain(..).collect());
 
         // https://w3c.github.io/permissions/#dom-permissions-query
         // Step 7.
-        promise.resolve_native(cx, status);
+        promise.resolve_native(status);
     }
 
     // https://webbluetoothcg.github.io/web-bluetooth/#request-the-bluetooth-permission
-    fn permission_request(cx: *mut JSContext, promise: &Rc<Promise>,
-                          descriptor: &BluetoothPermissionDescriptor,
-                          status: &BluetoothPermissionResult) {
+    fn permission_request(
+        _cx: *mut JSContext,
+        promise: &Rc<Promise>,
+        descriptor: &BluetoothPermissionDescriptor,
+        status: &BluetoothPermissionResult,
+    ) {
         // Step 1.
         if descriptor.filters.is_some() == descriptor.acceptAllDevices {
-            return promise.reject_error(cx, Error::Type(OPTIONS_ERROR.to_owned()));
+            return promise.reject_error(Error::Type(OPTIONS_ERROR.to_owned()));
         }
 
         // Step 2.
         let sender = response_async(promise, status);
         let bluetooth = status.get_bluetooth();
         bluetooth.request_bluetooth_devices(promise, &descriptor.filters, &descriptor.optionalServices, sender);
 
         // NOTE: Step 3. is in BluetoothPermissionResult's `handle_response` function.
--- a/servo/components/script/dom/bluetoothdevice.rs
+++ b/servo/components/script/dom/bluetoothdevice.rs
@@ -20,17 +20,16 @@ use dom::bluetoothremotegattcharacterist
 use dom::bluetoothremotegattdescriptor::BluetoothRemoteGATTDescriptor;
 use dom::bluetoothremotegattserver::BluetoothRemoteGATTServer;
 use dom::bluetoothremotegattservice::BluetoothRemoteGATTService;
 use dom::eventtarget::EventTarget;
 use dom::globalscope::GlobalScope;
 use dom::promise::Promise;
 use dom_struct::dom_struct;
 use ipc_channel::ipc::{self, IpcSender};
-use js::jsapi::JSContext;
 use std::cell::Cell;
 use std::collections::HashMap;
 use std::rc::Rc;
 
 // https://webbluetoothcg.github.io/web-bluetooth/#bluetoothdevice
 #[dom_struct]
 pub struct BluetoothDevice {
     eventtarget: EventTarget,
@@ -261,21 +260,21 @@ impl BluetoothDeviceMethods for Bluetoot
         self.watching_advertisements.get()
     }
 
     // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothdeviceeventhandlers-ongattserverdisconnected
     event_handler!(gattserverdisconnected, GetOngattserverdisconnected, SetOngattserverdisconnected);
 }
 
 impl AsyncBluetoothListener for BluetoothDevice {
-    fn handle_response(&self, response: BluetoothResponse, promise_cx: *mut JSContext, promise: &Rc<Promise>) {
+    fn handle_response(&self, response: BluetoothResponse, promise: &Rc<Promise>) {
         match response {
             // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothdevice-unwatchadvertisements
             BluetoothResponse::WatchAdvertisements(_result) => {
                 // Step 3.1.
                 self.watching_advertisements.set(true);
                 // Step 3.2.
-                promise.resolve_native(promise_cx, &());
+                promise.resolve_native(&());
             },
-            _ => promise.reject_error(promise_cx, Error::Type("Something went wrong...".to_owned())),
+            _ => promise.reject_error(Error::Type("Something went wrong...".to_owned())),
         }
     }
 }
--- a/servo/components/script/dom/bluetoothpermissionresult.rs
+++ b/servo/components/script/dom/bluetoothpermissionresult.rs
@@ -15,17 +15,16 @@ use dom::bindings::reflector::{DomObject
 use dom::bindings::str::DOMString;
 use dom::bluetooth::{AsyncBluetoothListener, Bluetooth, AllowedBluetoothDevice};
 use dom::bluetoothdevice::BluetoothDevice;
 use dom::globalscope::GlobalScope;
 use dom::permissionstatus::PermissionStatus;
 use dom::promise::Promise;
 use dom_struct::dom_struct;
 use ipc_channel::ipc::IpcSender;
-use js::jsapi::JSContext;
 use std::rc::Rc;
 
 // https://webbluetoothcg.github.io/web-bluetooth/#bluetoothpermissionresult
 #[dom_struct]
 pub struct BluetoothPermissionResult {
     status: PermissionStatus,
     devices: DOMRefCell<Vec<JS<BluetoothDevice>>>,
 }
@@ -78,32 +77,32 @@ impl BluetoothPermissionResultMethods fo
     fn Devices(&self) -> Vec<Root<BluetoothDevice>> {
         let device_vec: Vec<Root<BluetoothDevice>> =
             self.devices.borrow().iter().map(|d| Root::from_ref(&**d)).collect();
         device_vec
     }
 }
 
 impl AsyncBluetoothListener for BluetoothPermissionResult {
-    fn handle_response(&self, response: BluetoothResponse, promise_cx: *mut JSContext, promise: &Rc<Promise>) {
+    fn handle_response(&self, response: BluetoothResponse, promise: &Rc<Promise>) {
         match response {
             // https://webbluetoothcg.github.io/web-bluetooth/#request-bluetooth-devices
             // Step 3, 11, 13 - 14.
             BluetoothResponse::RequestDevice(device) => {
                 self.set_state(PermissionState::Granted);
                 let bluetooth = self.get_bluetooth();
                 let mut device_instance_map = bluetooth.get_device_map().borrow_mut();
                 if let Some(ref existing_device) = device_instance_map.get(&device.id) {
                     // https://webbluetoothcg.github.io/web-bluetooth/#request-the-bluetooth-permission
                     // Step 3.
                     self.set_devices(vec!(JS::from_ref(&*existing_device)));
 
                     // https://w3c.github.io/permissions/#dom-permissions-request
                     // Step 8.
-                    return promise.resolve_native(promise_cx, self);
+                    return promise.resolve_native(self);
                 }
                 let bt_device = BluetoothDevice::new(&self.global(),
                                                      DOMString::from(device.id.clone()),
                                                      device.name.map(DOMString::from),
                                                      &bluetooth);
                 device_instance_map.insert(device.id.clone(), JS::from_ref(&bt_device));
                 self.global().as_window().bluetooth_extra_permission_data().add_new_allowed_device(
                     AllowedBluetoothDevice {
@@ -112,14 +111,14 @@ impl AsyncBluetoothListener for Bluetoot
                     }
                 );
                 // https://webbluetoothcg.github.io/web-bluetooth/#request-the-bluetooth-permission
                 // Step 3.
                 self.set_devices(vec!(JS::from_ref(&bt_device)));
 
                 // https://w3c.github.io/permissions/#dom-permissions-request
                 // Step 8.
-                promise.resolve_native(promise_cx, self);
+                promise.resolve_native(self);
             },
-            _ => promise.reject_error(promise_cx, Error::Type("Something went wrong...".to_owned())),
+            _ => promise.reject_error(Error::Type("Something went wrong...".to_owned())),
         }
     }
 }
--- a/servo/components/script/dom/bluetoothremotegattcharacteristic.rs
+++ b/servo/components/script/dom/bluetoothremotegattcharacteristic.rs
@@ -21,17 +21,16 @@ use dom::bluetooth::{AsyncBluetoothListe
 use dom::bluetoothcharacteristicproperties::BluetoothCharacteristicProperties;
 use dom::bluetoothremotegattservice::BluetoothRemoteGATTService;
 use dom::bluetoothuuid::{BluetoothDescriptorUUID, BluetoothUUID};
 use dom::eventtarget::EventTarget;
 use dom::globalscope::GlobalScope;
 use dom::promise::Promise;
 use dom_struct::dom_struct;
 use ipc_channel::ipc::IpcSender;
-use js::jsapi::JSContext;
 use std::rc::Rc;
 
 // Maximum length of an attribute value.
 // https://www.bluetooth.org/DocMan/handlers/DownloadDoc.ashx?doc_id=286439 (Vol. 3, page 2169)
 pub const MAXIMUM_ATTRIBUTE_LENGTH: usize = 512;
 
 // https://webbluetoothcg.github.io/web-bluetooth/#bluetoothremotegattcharacteristic
 #[dom_struct]
@@ -119,110 +118,107 @@ impl BluetoothRemoteGATTCharacteristicMe
     fn GetValue(&self) -> Option<ByteString> {
         self.value.borrow().clone()
     }
 
     #[allow(unrooted_must_root)]
     // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-readvalue
     fn ReadValue(&self) -> Rc<Promise> {
         let p = Promise::new(&self.global());
-        let p_cx = p.global().get_cx();
 
         // Step 1.
         if uuid_is_blocklisted(self.uuid.as_ref(), Blocklist::Reads) {
-            p.reject_error(p_cx, Security);
+            p.reject_error(Security);
             return p;
         }
 
         // Step 2.
         if !self.Service().Device().get_gatt().Connected() {
-            p.reject_error(p_cx, Network);
+            p.reject_error(Network);
             return p;
         }
 
         // TODO: Step 5: Implement the `connection-checking-wrapper` algorithm for BluetoothRemoteGATTServer.
 
         // Step 5.1.
         if !self.Properties().Read() {
-            p.reject_error(p_cx, NotSupported);
+            p.reject_error(NotSupported);
             return p;
         }
 
         // Note: Steps 3 - 4 and the remaining substeps of Step 5 are implemented in components/bluetooth/lib.rs
         // in readValue function and in handle_response function.
         let sender = response_async(&p, self);
         self.get_bluetooth_thread().send(
             BluetoothRequest::ReadValue(self.get_instance_id(), sender)).unwrap();
         return p;
     }
 
     #[allow(unrooted_must_root)]
     // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-writevalue
     fn WriteValue(&self, value: Vec<u8>) -> Rc<Promise> {
         let p = Promise::new(&self.global());
-        let p_cx = p.global().get_cx();
 
         // Step 1.
         if uuid_is_blocklisted(self.uuid.as_ref(), Blocklist::Writes) {
-            p.reject_error(p_cx, Security);
+            p.reject_error(Security);
             return p;
         }
 
         // Step 2 - 3.
         if value.len() > MAXIMUM_ATTRIBUTE_LENGTH {
-            p.reject_error(p_cx, InvalidModification);
+            p.reject_error(InvalidModification);
             return p;
         }
 
         // Step 4.
         if !self.Service().Device().get_gatt().Connected() {
-            p.reject_error(p_cx, Network);
+            p.reject_error(Network);
             return p;
         }
 
         // TODO: Step 7: Implement the `connection-checking-wrapper` algorithm for BluetoothRemoteGATTServer.
 
         // Step 7.1.
         if !(self.Properties().Write() ||
              self.Properties().WriteWithoutResponse() ||
              self.Properties().AuthenticatedSignedWrites()) {
-            p.reject_error(p_cx, NotSupported);
+            p.reject_error(NotSupported);
             return p;
         }
 
         // Note: Steps 5 - 6 and the remaining substeps of Step 7 are implemented in components/bluetooth/lib.rs
         // in writeValue function and in handle_response function.
         let sender = response_async(&p, self);
         self.get_bluetooth_thread().send(
             BluetoothRequest::WriteValue(self.get_instance_id(), value, sender)).unwrap();
         return p;
     }
 
     #[allow(unrooted_must_root)]
     // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-startnotifications
     fn StartNotifications(&self) -> Rc<Promise> {
         let p = Promise::new(&self.global());
-        let p_cx = p.global().get_cx();
 
         // Step 1.
         if uuid_is_blocklisted(self.uuid.as_ref(), Blocklist::Reads) {
-            p.reject_error(p_cx, Security);
+            p.reject_error(Security);
             return p;
         }
 
         // Step 2.
         if !self.Service().Device().get_gatt().Connected() {
-            p.reject_error(p_cx, Network);
+            p.reject_error(Network);
             return p;
         }
 
         // Step 5.
         if !(self.Properties().Notify() ||
              self.Properties().Indicate()) {
-            p.reject_error(p_cx, NotSupported);
+            p.reject_error(NotSupported);
             return p;
         }
 
         // TODO: Step 6: Implement `active notification context set` for BluetoothRemoteGATTCharacteristic.
 
         // Note: Steps 3 - 4, 7 - 11 are implemented in components/bluetooth/lib.rs in enable_notification function
         // and in handle_response function.
         let sender = response_async(&p, self);
@@ -250,65 +246,65 @@ impl BluetoothRemoteGATTCharacteristicMe
         return p;
     }
 
     // https://webbluetoothcg.github.io/web-bluetooth/#dom-characteristiceventhandlers-oncharacteristicvaluechanged
     event_handler!(characteristicvaluechanged, GetOncharacteristicvaluechanged, SetOncharacteristicvaluechanged);
 }
 
 impl AsyncBluetoothListener for BluetoothRemoteGATTCharacteristic {
-    fn handle_response(&self, response: BluetoothResponse, promise_cx: *mut JSContext, promise: &Rc<Promise>) {
+    fn handle_response(&self, response: BluetoothResponse, promise: &Rc<Promise>) {
         let device = self.Service().Device();
         match response {
             // https://webbluetoothcg.github.io/web-bluetooth/#getgattchildren
             // Step 7.
             BluetoothResponse::GetDescriptors(descriptors_vec, single) => {
                 if single {
-                    promise.resolve_native(promise_cx, &device.get_or_create_descriptor(&descriptors_vec[0], &self));
+                    promise.resolve_native(&device.get_or_create_descriptor(&descriptors_vec[0], &self));
                     return;
                 }
                 let mut descriptors = vec!();
                 for descriptor in descriptors_vec {
                     let bt_descriptor = device.get_or_create_descriptor(&descriptor, &self);
                     descriptors.push(bt_descriptor);
                 }
-                promise.resolve_native(promise_cx, &descriptors);
+                promise.resolve_native(&descriptors);
             },
             // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-readvalue
             BluetoothResponse::ReadValue(result) => {
                 // TODO: Step 5.5.1: Implement activeAlgorithms internal slot for BluetoothRemoteGATTServer.
 
                 // Step 5.5.2.
                 // TODO(#5014): Replace ByteString with ArrayBuffer when it is implemented.
                 let value = ByteString::new(result);
                 *self.value.borrow_mut() = Some(value.clone());
 
                 // Step 5.5.3.
                 self.upcast::<EventTarget>().fire_bubbling_event(atom!("characteristicvaluechanged"));
 
                 // Step 5.5.4.
-                promise.resolve_native(promise_cx, &value);
+                promise.resolve_native(&value);
             },
             // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-writevalue
             BluetoothResponse::WriteValue(result) => {
                 // TODO: Step 7.5.1: Implement activeAlgorithms internal slot for BluetoothRemoteGATTServer.
 
                 // Step 7.5.2.
                 // TODO(#5014): Replace ByteString with an ArrayBuffer wrapped in a DataView.
                 *self.value.borrow_mut() = Some(ByteString::new(result));
 
                 // Step 7.5.3.
-                promise.resolve_native(promise_cx, &());
+                promise.resolve_native(&());
             },
             // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-startnotifications
             // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-stopnotifications
             BluetoothResponse::EnableNotification(_result) => {
                 // (StartNotification) TODO: Step 10:  Implement `active notification context set`
                 // for BluetoothRemoteGATTCharacteristic.
 
                 // (StartNotification) Step 11.
                 // (StopNotification)  Step 5.
-                promise.resolve_native(promise_cx, self);
+                promise.resolve_native(self);
             },
-            _ => promise.reject_error(promise_cx, Error::Type("Something went wrong...".to_owned())),
+            _ => promise.reject_error(Error::Type("Something went wrong...".to_owned())),
         }
     }
 }
--- a/servo/components/script/dom/bluetoothremotegattdescriptor.rs
+++ b/servo/components/script/dom/bluetoothremotegattdescriptor.rs
@@ -16,17 +16,16 @@ use dom::bindings::js::{JS, Root};
 use dom::bindings::reflector::{DomObject, Reflector, reflect_dom_object};
 use dom::bindings::str::{ByteString, DOMString};
 use dom::bluetooth::{AsyncBluetoothListener, response_async};
 use dom::bluetoothremotegattcharacteristic::{BluetoothRemoteGATTCharacteristic, MAXIMUM_ATTRIBUTE_LENGTH};
 use dom::globalscope::GlobalScope;
 use dom::promise::Promise;
 use dom_struct::dom_struct;
 use ipc_channel::ipc::IpcSender;
-use js::jsapi::JSContext;
 use std::rc::Rc;
 
 // http://webbluetoothcg.github.io/web-bluetooth/#bluetoothremotegattdescriptor
 #[dom_struct]
 pub struct BluetoothRemoteGATTDescriptor {
     reflector_: Reflector,
     characteristic: JS<BluetoothRemoteGATTCharacteristic>,
     uuid: DOMString,
@@ -84,96 +83,94 @@ impl BluetoothRemoteGATTDescriptorMethod
     fn GetValue(&self) -> Option<ByteString> {
         self.value.borrow().clone()
     }
 
     #[allow(unrooted_must_root)]
     // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattdescriptor-readvalue
     fn ReadValue(&self) -> Rc<Promise> {
         let p = Promise::new(&self.global());
-        let p_cx = p.global().get_cx();
 
         // Step 1.
         if uuid_is_blocklisted(self.uuid.as_ref(), Blocklist::Reads) {
-            p.reject_error(p_cx, Security);
+            p.reject_error(Security);
             return p;
         }
 
         // Step 2.
         if !self.Characteristic().Service().Device().get_gatt().Connected() {
-            p.reject_error(p_cx, Network);
+            p.reject_error(Network);
             return p;
         }
 
         // TODO: Step 5: Implement the `connection-checking-wrapper` algorithm for BluetoothRemoteGATTServer.
         // Note: Steps 3 - 4 and substeps of Step 5 are implemented in components/bluetooth/lib.rs
         // in readValue function and in handle_response function.
         let sender = response_async(&p, self);
         self.get_bluetooth_thread().send(
             BluetoothRequest::ReadValue(self.get_instance_id(), sender)).unwrap();
         return p;
     }
 
     #[allow(unrooted_must_root)]
     // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattdescriptor-writevalue
     fn WriteValue(&self, value: Vec<u8>) -> Rc<Promise> {
         let p = Promise::new(&self.global());
-        let p_cx = p.global().get_cx();
 
         // Step 1.
         if uuid_is_blocklisted(self.uuid.as_ref(), Blocklist::Writes) {
-            p.reject_error(p_cx, Security);
+            p.reject_error(Security);
             return p;
         }
 
         // Step 2 - 3.
         if value.len() > MAXIMUM_ATTRIBUTE_LENGTH {
-            p.reject_error(p_cx, InvalidModification);
+            p.reject_error(InvalidModification);
             return p;
         }
 
         // Step 4.
         if !self.Characteristic().Service().Device().get_gatt().Connected() {
-            p.reject_error(p_cx, Network);
+            p.reject_error(Network);
             return p;
         }
 
         // TODO: Step 7: Implement the `connection-checking-wrapper` algorithm for BluetoothRemoteGATTServer.
         // Note: Steps 5 - 6 and substeps of Step 7 are implemented in components/bluetooth/lib.rs
         // in writeValue function and in handle_response function.
         let sender = response_async(&p, self);
         self.get_bluetooth_thread().send(
             BluetoothRequest::WriteValue(self.get_instance_id(), value, sender)).unwrap();
         return p;
     }
 }
 
 impl AsyncBluetoothListener for BluetoothRemoteGATTDescriptor {
-    fn handle_response(&self, response: BluetoothResponse, promise_cx: *mut JSContext, promise: &Rc<Promise>) {
+    fn handle_response(&self, response: BluetoothResponse, promise: &Rc<Promise>) {
         match response {
             // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattdescriptor-readvalue
             BluetoothResponse::ReadValue(result) => {
                 // TODO: Step 5.4.1: Implement activeAlgorithms internal slot for BluetoothRemoteGATTServer.
 
                 // Step 5.4.2.
                 // TODO(#5014): Replace ByteString with ArrayBuffer when it is implemented.
                 let value = ByteString::new(result);
                 *self.value.borrow_mut() = Some(value.clone());
 
                 // Step 5.4.3.
-                promise.resolve_native(promise_cx, &value);
+                promise.resolve_native(&value);
             },
             // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattdescriptor-writevalue
             BluetoothResponse::WriteValue(result) => {
                 // TODO: Step 7.4.1: Implement activeAlgorithms internal slot for BluetoothRemoteGATTServer.
 
                 // Step 7.4.2.
                 // TODO(#5014): Replace ByteString with an ArrayBuffer wrapped in a DataView.
                 *self.value.borrow_mut() = Some(ByteString::new(result));
 
                 // Step 7.4.3.
                 // TODO: Resolve promise with undefined instead of a value.
-                promise.resolve_native(promise_cx, &());
+                promise.resolve_native(&());
             },
-            _ => promise.reject_error(promise_cx, Error::Type("Something went wrong...".to_owned())),
+            _ => promise.reject_error(Error::Type("Something went wrong...".to_owned())),
         }
     }
 }
--- a/servo/components/script/dom/bluetoothremotegattserver.rs
+++ b/servo/components/script/dom/bluetoothremotegattserver.rs
@@ -12,17 +12,16 @@ use dom::bindings::js::{JS, Root};
 use dom::bindings::reflector::{DomObject, Reflector, reflect_dom_object};
 use dom::bluetooth::{AsyncBluetoothListener, get_gatt_children, response_async};
 use dom::bluetoothdevice::BluetoothDevice;
 use dom::bluetoothuuid::{BluetoothServiceUUID, BluetoothUUID};
 use dom::globalscope::GlobalScope;
 use dom::promise::Promise;
 use dom_struct::dom_struct;
 use ipc_channel::ipc::IpcSender;
-use js::jsapi::JSContext;
 use std::cell::Cell;
 use std::rc::Rc;
 
 // https://webbluetoothcg.github.io/web-bluetooth/#bluetoothremotegattserver
 #[dom_struct]
 pub struct BluetoothRemoteGATTServer {
     reflector_: Reflector,
     device: JS<BluetoothDevice>,
@@ -115,45 +114,45 @@ impl BluetoothRemoteGATTServerMethods fo
         // Step 1 - 2.
         get_gatt_children(self, false, BluetoothUUID::service, service, String::from(self.Device().Id()),
                           self.Connected(), GATTType::PrimaryService)
 
     }
 }
 
 impl AsyncBluetoothListener for BluetoothRemoteGATTServer {
-    fn handle_response(&self, response: BluetoothResponse, promise_cx: *mut JSContext, promise: &Rc<Promise>) {
+    fn handle_response(&self, response: BluetoothResponse, promise: &Rc<Promise>) {
         match response {
             // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattserver-connect
             BluetoothResponse::GATTServerConnect(connected) => {
                 // Step 5.2.3
                 if self.Device().is_represented_device_null() {
                     if let Err(e) = self.Device().garbage_collect_the_connection() {
-                        return promise.reject_error(promise_cx, Error::from(e));
+                        return promise.reject_error(Error::from(e));
                     }
-                    return promise.reject_error(promise_cx, Error::Network);
+                    return promise.reject_error(Error::Network);
                 }
 
                 // Step 5.2.4.
                 self.connected.set(connected);
 
                 // Step 5.2.5.
-                promise.resolve_native(promise_cx, self);
+                promise.resolve_native(self);
             },
             // https://webbluetoothcg.github.io/web-bluetooth/#getgattchildren
             // Step 7.
             BluetoothResponse::GetPrimaryServices(services_vec, single) => {
                 let device = self.Device();
                 if single {
-                    promise.resolve_native(promise_cx, &device.get_or_create_service(&services_vec[0], &self));
+                    promise.resolve_native(&device.get_or_create_service(&services_vec[0], &self));
                     return;
                 }
                 let mut services = vec!();
                 for service in services_vec {
                     let bt_service = device.get_or_create_service(&service, &self);
                     services.push(bt_service);
                 }
-                promise.resolve_native(promise_cx, &services);
+                promise.resolve_native(&services);
             },
-            _ => promise.reject_error(promise_cx, Error::Type("Something went wrong...".to_owned())),
+            _ => promise.reject_error(Error::Type("Something went wrong...".to_owned())),
         }
     }
 }
--- a/servo/components/script/dom/bluetoothremotegattservice.rs
+++ b/servo/components/script/dom/bluetoothremotegattservice.rs
@@ -12,17 +12,16 @@ use dom::bindings::reflector::reflect_do
 use dom::bindings::str::DOMString;
 use dom::bluetooth::{AsyncBluetoothListener, get_gatt_children};
 use dom::bluetoothdevice::BluetoothDevice;
 use dom::bluetoothuuid::{BluetoothCharacteristicUUID, BluetoothServiceUUID, BluetoothUUID};
 use dom::eventtarget::EventTarget;
 use dom::globalscope::GlobalScope;
 use dom::promise::Promise;
 use dom_struct::dom_struct;
-use js::jsapi::JSContext;
 use std::rc::Rc;
 
 // https://webbluetoothcg.github.io/web-bluetooth/#bluetoothremotegattservice
 #[dom_struct]
 pub struct BluetoothRemoteGATTService {
     eventtarget: EventTarget,
     device: JS<BluetoothDevice>,
     uuid: DOMString,
@@ -123,44 +122,42 @@ impl BluetoothRemoteGATTServiceMethods f
     // https://webbluetoothcg.github.io/web-bluetooth/#dom-serviceeventhandlers-onservicechanged
     event_handler!(servicechanged, GetOnservicechanged, SetOnservicechanged);
 
     // https://webbluetoothcg.github.io/web-bluetooth/#dom-serviceeventhandlers-onserviceremoved
     event_handler!(serviceremoved, GetOnserviceremoved, SetOnserviceremoved);
 }
 
 impl AsyncBluetoothListener for BluetoothRemoteGATTService {
-    fn handle_response(&self, response: BluetoothResponse, promise_cx: *mut JSContext, promise: &Rc<Promise>) {
+    fn handle_response(&self, response: BluetoothResponse, promise: &Rc<Promise>) {
         let device = self.Device();
         match response {
             // https://webbluetoothcg.github.io/web-bluetooth/#getgattchildren
             // Step 7.
             BluetoothResponse::GetCharacteristics(characteristics_vec, single) => {
                 if single {
-                    promise.resolve_native(promise_cx,
-                                           &device.get_or_create_characteristic(&characteristics_vec[0], &self));
+                    promise.resolve_native(&device.get_or_create_characteristic(&characteristics_vec[0], &self));
                     return;
                 }
                 let mut characteristics = vec!();
                 for characteristic in characteristics_vec {
                     let bt_characteristic = device.get_or_create_characteristic(&characteristic, &self);
                     characteristics.push(bt_characteristic);
                 }
-                promise.resolve_native(promise_cx, &characteristics);
+                promise.resolve_native(&characteristics);
             },
             // https://webbluetoothcg.github.io/web-bluetooth/#getgattchildren
             // Step 7.
             BluetoothResponse::GetIncludedServices(services_vec, single) => {
                 if single {
-                    return promise.resolve_native(promise_cx,
-                                                  &device.get_or_create_service(&services_vec[0], &device.get_gatt()));
+                    return promise.resolve_native(&device.get_or_create_service(&services_vec[0], &device.get_gatt()));
                 }
                 let mut services = vec!();
                 for service in services_vec {
                     let bt_service = device.get_or_create_service(&service, &device.get_gatt());
                     services.push(bt_service);
                 }
-                promise.resolve_native(promise_cx, &services);
+                promise.resolve_native(&services);
             },
-            _ => promise.reject_error(promise_cx, Error::Type("Something went wrong...".to_owned())),
+            _ => promise.reject_error(Error::Type("Something went wrong...".to_owned())),
         }
     }
 }
--- a/servo/components/script/dom/customelementregistry.rs
+++ b/servo/components/script/dom/customelementregistry.rs
@@ -311,20 +311,17 @@ impl CustomElementRegistryMethods for Cu
                 (extends.is_none() || is.as_ref() == Some(&name))
             {
                 ScriptThread::enqueue_upgrade_reaction(&*candidate, definition.clone());
             }
         }
 
         // Step 16, 16.3
         if let Some(promise) = self.when_defined.borrow_mut().remove(&name) {
-            // 16.1
-            let cx = promise.global().get_cx();
-            // 16.2
-            promise.resolve_native(cx, &UndefinedValue());
+            promise.resolve_native(&UndefinedValue());
         }
         Ok(())
     }
 
     /// https://html.spec.whatwg.org/multipage/#dom-customelementregistry-get
     #[allow(unsafe_code)]
     unsafe fn Get(&self, cx: *mut JSContext, name: DOMString) -> JSVal {
         match self.definitions.borrow().get(&LocalName::from(&*name)) {
@@ -341,24 +338,24 @@ impl CustomElementRegistryMethods for Cu
     #[allow(unrooted_must_root)]
     fn WhenDefined(&self, name: DOMString) -> Rc<Promise> {
         let global_scope = self.window.upcast::<GlobalScope>();
         let name = LocalName::from(&*name);
 
         // Step 1
         if !is_valid_custom_element_name(&name) {
             let promise = Promise::new(global_scope);
-            promise.reject_native(global_scope.get_cx(), &DOMException::new(global_scope, DOMErrorName::SyntaxError));
+            promise.reject_native(&DOMException::new(global_scope, DOMErrorName::SyntaxError));
             return promise
         }
 
         // Step 2
         if self.definitions.borrow().contains_key(&name) {
             let promise = Promise::new(global_scope);
-            promise.resolve_native(global_scope.get_cx(), &UndefinedValue());
+            promise.resolve_native(&UndefinedValue());
             return promise
         }
 
         // Step 3
         let mut map = self.when_defined.borrow_mut();
 
         // Steps 4, 5
         let promise = map.get(&name).cloned().unwrap_or_else(|| {
--- a/servo/components/script/dom/document.rs
+++ b/servo/components/script/dom/document.rs
@@ -2666,17 +2666,17 @@ impl Document {
     // https://fullscreen.spec.whatwg.org/#exit-fullscreen
     #[allow(unrooted_must_root)]
     pub fn exit_fullscreen(&self) -> Rc<Promise> {
         let global = self.global();
         // Step 1
         let promise = Promise::new(global.r());
         // Step 2
         if self.fullscreen_element.get().is_none() {
-            promise.reject_error(global.get_cx(), Error::Type(String::from("fullscreen is null")));
+            promise.reject_error(Error::Type(String::from("fullscreen is null")));
             return promise
         }
         // TODO Step 3-6
         let element = self.fullscreen_element.get().unwrap();
 
         // Step 7 Parallel start
 
         let window = self.window();
--- a/servo/components/script/dom/element.rs
+++ b/servo/components/script/dom/element.rs
@@ -77,17 +77,17 @@ use dom::validation::Validatable;
 use dom::virtualmethods::{VirtualMethods, vtable_for};
 use dom::window::ReflowReason;
 use dom_struct::dom_struct;
 use html5ever::{Prefix, LocalName, Namespace, QualName};
 use html5ever::serialize;
 use html5ever::serialize::SerializeOpts;
 use html5ever::serialize::TraversalScope;
 use html5ever::serialize::TraversalScope::{ChildrenOnly, IncludeNode};
-use js::jsapi::{HandleValue, Heap, JSAutoCompartment};
+use js::jsapi::Heap;
 use js::jsval::JSVal;
 use net_traits::request::CorsSettings;
 use ref_filter_map::ref_filter_map;
 use script_layout_interface::message::ReflowQueryType;
 use script_thread::ScriptThread;
 use selectors::attr::{AttrSelectorOperation, NamespaceConstraint, CaseSensitivity};
 use selectors::matching::{ElementSelectorFlags, LocalMatchingContext, MatchingContext, MatchingMode};
 use selectors::matching::{HAS_EDGE_CHILD_SELECTOR, HAS_SLOW_SELECTOR, HAS_SLOW_SELECTOR_LATER_SIBLINGS};
@@ -3052,48 +3052,39 @@ impl ElementPerformFullscreenEnter {
         }
     }
 }
 
 impl TaskOnce for ElementPerformFullscreenEnter {
     #[allow(unrooted_must_root)]
     fn run_once(self) {
         let element = self.element.root();
+        let promise = self.promise.root();
         let document = document_from_node(element.r());
 
         // Step 7.1
         if self.error || !element.fullscreen_element_ready_check() {
-            // JSAutoCompartment needs to be manually made.
-            // Otherwise, Servo will crash.
-            let promise = self.promise.root();
-            let promise_cx = promise.global().get_cx();
-            let _ac = JSAutoCompartment::new(promise_cx, promise.reflector().get_jsobject().get());
             document.upcast::<EventTarget>().fire_event(atom!("fullscreenerror"));
-            promise.reject_error(promise.global().get_cx(), Error::Type(String::from("fullscreen is not connected")));
+            promise.reject_error(Error::Type(String::from("fullscreen is not connected")));
             return
         }
 
         // TODO Step 7.2-4
         // Step 7.5
         element.set_fullscreen_state(true);
         document.set_fullscreen_element(Some(&element));
         document.window().reflow(ReflowGoal::ForDisplay,
                                  ReflowQueryType::NoQuery,
                                  ReflowReason::ElementStateChanged);
 
         // Step 7.6
         document.upcast::<EventTarget>().fire_event(atom!("fullscreenchange"));
 
         // Step 7.7
-        // JSAutoCompartment needs to be manually made.
-        // Otherwise, Servo will crash.
-        let promise = self.promise.root();
-        let promise_cx = promise.global().get_cx();
-        let _ac = JSAutoCompartment::new(promise_cx, promise.reflector().get_jsobject().get());
-        promise.resolve(promise.global().get_cx(), HandleValue::undefined());
+        promise.resolve_native(&());
     }
 }
 
 pub struct ElementPerformFullscreenExit {
     element: Trusted<Element>,
     promise: TrustedPromise,
 }
 
@@ -3120,22 +3111,17 @@ impl TaskOnce for ElementPerformFullscre
                                  ReflowReason::ElementStateChanged);
 
         document.set_fullscreen_element(None);
 
         // Step 9.8
         document.upcast::<EventTarget>().fire_event(atom!("fullscreenchange"));
 
         // Step 9.10
-        let promise = self.promise.root();
-        // JSAutoCompartment needs to be manually made.
-        // Otherwise, Servo will crash.
-        let promise_cx = promise.global().get_cx();
-        let _ac = JSAutoCompartment::new(promise_cx, promise.reflector().get_jsobject().get());
-        promise.resolve(promise.global().get_cx(), HandleValue::undefined());
+        self.promise.root().resolve_native(&());
     }
 }
 
 pub fn reflect_cross_origin_attribute(element: &Element) -> Option<DOMString> {
     let attr = element.get_attribute(&ns!(), &local_name!("crossorigin"));
 
     if let Some(mut val) = attr.map(|v| v.Value()) {
         val.make_ascii_lowercase();
--- a/servo/components/script/dom/permissions.rs
+++ b/servo/components/script/dom/permissions.rs
@@ -84,31 +84,31 @@ impl Permissions {
             Some(promise) => promise,
             None => Promise::new(&self.global()),
         };
 
         // (Query, Request, Revoke) Step 1.
         let root_desc = match Permissions::create_descriptor(cx, permissionDesc) {
             Ok(descriptor) => descriptor,
             Err(error) => {
-                p.reject_error(cx, error);
+                p.reject_error(error);
                 return p;
             },
         };
 
         // (Query, Request) Step 5.
         let status = PermissionStatus::new(&self.global(), &root_desc);
 
         // (Query, Request, Revoke) Step 2.
         match root_desc.name {
             PermissionName::Bluetooth => {
                 let bluetooth_desc = match Bluetooth::create_descriptor(cx, permissionDesc) {
                     Ok(descriptor) => descriptor,
                     Err(error) => {
-                        p.reject_error(cx, error);
+                        p.reject_error(error);
                         return p;
                     },
                 };
 
                 // (Query, Request) Step 5.
                 let result = BluetoothPermissionResult::new(&self.global(), &status);
 
                 match &op {
@@ -135,24 +135,24 @@ impl Permissions {
                 match &op {
                     &Operation::Request => {
                         // (Request) Step 6.
                         Permissions::permission_request(cx, &p, &root_desc, &status);
 
                         // (Request) Step 7. The default algorithm always resolve
 
                         // (Request) Step 8.
-                        p.resolve_native(cx, &status);
+                        p.resolve_native(&status);
                     },
                     &Operation::Query => {
                         // (Query) Step 6.
                         Permissions::permission_query(cx, &p, &root_desc, &status);
 
                         // (Query) Step 7.
-                        p.resolve_native(cx, &status);
+                        p.resolve_native(&status);
                     },
 
                     &Operation::Revoke => {
                         // (Revoke) Step 3.
                         let globalscope = self.global();
                         globalscope.as_window()
                                    .permission_state_invocation_results()
                                    .borrow_mut()
--- a/servo/components/script/dom/promise.rs
+++ b/servo/components/script/dom/promise.rs
@@ -6,27 +6,25 @@
 //!
 //! This implementation differs from the traditional Rust DOM object, because the reflector
 //! is provided by SpiderMonkey and has no knowledge of an associated native representation
 //! (ie. dom::Promise). This means that native instances use native reference counting (Rc)
 //! to ensure that no memory is leaked, which means that there can be multiple instances of
 //! native Promise values that refer to the same JS value yet are distinct native objects
 //! (ie. address equality for the native objects is meaningless).
 
-use dom::bindings::callback::CallbackContainer;
-use dom::bindings::codegen::Bindings::PromiseBinding::AnyCallback;
 use dom::bindings::conversions::root_from_object;
 use dom::bindings::error::{Error, Fallible};
 use dom::bindings::reflector::{DomObject, MutDomObject, Reflector};
 use dom::bindings::utils::AsCCharPtrPtr;
 use dom::globalscope::GlobalScope;
 use dom::promisenativehandler::PromiseNativeHandler;
 use dom_struct::dom_struct;
 use js::conversions::ToJSValConvertible;
-use js::jsapi::{CallOriginalPromiseResolve, CallOriginalPromiseReject, CallOriginalPromiseThen};
+use js::jsapi::{CallOriginalPromiseResolve, CallOriginalPromiseReject};
 use js::jsapi::{JSAutoCompartment, CallArgs, JS_GetFunctionObject, JS_NewFunction};
 use js::jsapi::{JSContext, HandleValue, HandleObject, IsPromiseObject, GetFunctionNativeReserved};
 use js::jsapi::{JS_ClearPendingException, JSObject, AddRawValueRoot, RemoveRawValueRoot, PromiseState};
 use js::jsapi::{MutableHandleObject, NewPromiseObject, ResolvePromise, RejectPromise, GetPromiseState};
 use js::jsapi::{SetFunctionNativeReserved, NewFunctionWithReserved, AddPromiseReactions};
 use js::jsapi::Heap;
 use js::jsval::{JSVal, UndefinedValue, ObjectValue, Int32Value};
 use std::ptr;
@@ -109,105 +107,88 @@ impl Promise {
         assert!(!do_nothing_func.is_null());
         rooted!(in(cx) let do_nothing_obj = JS_GetFunctionObject(do_nothing_func));
         assert!(!do_nothing_obj.is_null());
         obj.set(NewPromiseObject(cx, do_nothing_obj.handle(), proto));
         assert!(!obj.is_null());
     }
 
     #[allow(unrooted_must_root, unsafe_code)]
-    pub fn Resolve(global: &GlobalScope,
-                   cx: *mut JSContext,
-                   value: HandleValue) -> Fallible<Rc<Promise>> {
+    pub unsafe fn new_resolved(
+        global: &GlobalScope,
+        cx: *mut JSContext,
+        value: HandleValue,
+    ) -> Fallible<Rc<Promise>> {
         let _ac = JSAutoCompartment::new(cx, global.reflector().get_jsobject().get());
-        rooted!(in(cx) let p = unsafe { CallOriginalPromiseResolve(cx, value) });
+        rooted!(in(cx) let p = CallOriginalPromiseResolve(cx, value));
         assert!(!p.handle().is_null());
+        Ok(Promise::new_with_js_promise(p.handle(), cx))
+    }
+
+    #[allow(unrooted_must_root, unsafe_code)]
+    pub unsafe fn new_rejected(
+        global: &GlobalScope,
+        cx: *mut JSContext,
+        value: HandleValue,
+    ) -> Fallible<Rc<Promise>> {
+        let _ac = JSAutoCompartment::new(cx, global.reflector().get_jsobject().get());
+        rooted!(in(cx) let p = CallOriginalPromiseReject(cx, value));
+        assert!(!p.handle().is_null());
+        Ok(Promise::new_with_js_promise(p.handle(), cx))
+    }
+
+    #[allow(unsafe_code)]
+    pub fn resolve_native<T>(&self, val: &T) where T: ToJSValConvertible {
+        let cx = self.global().get_cx();
+        let _ac = JSAutoCompartment::new(cx, self.reflector().get_jsobject().get());
+        rooted!(in(cx) let mut v = UndefinedValue());
         unsafe {
-            Ok(Promise::new_with_js_promise(p.handle(), cx))
+            val.to_jsval(cx, v.handle_mut());
+            self.resolve(cx, v.handle());
         }
     }
 
     #[allow(unrooted_must_root, unsafe_code)]
-    pub fn Reject(global: &GlobalScope,
-                  cx: *mut JSContext,
-                  value: HandleValue) -> Fallible<Rc<Promise>> {
-        let _ac = JSAutoCompartment::new(cx, global.reflector().get_jsobject().get());
-        rooted!(in(cx) let p = unsafe { CallOriginalPromiseReject(cx, value) });
-        assert!(!p.handle().is_null());
-        unsafe {
-            Ok(Promise::new_with_js_promise(p.handle(), cx))
-        }
-    }
-
-    #[allow(unsafe_code)]
-    pub fn resolve_native<T>(&self, cx: *mut JSContext, val: &T) where T: ToJSValConvertible {
-        rooted!(in(cx) let mut v = UndefinedValue());
-        unsafe {
-            val.to_jsval(cx, v.handle_mut());
-        }
-        self.resolve(cx, v.handle());
-    }
-
-    #[allow(unrooted_must_root, unsafe_code)]
-    pub fn resolve(&self, cx: *mut JSContext, value: HandleValue) {
-        unsafe {
-            if !ResolvePromise(cx, self.promise_obj(), value) {
-                JS_ClearPendingException(cx);
-            }
+    pub unsafe fn resolve(&self, cx: *mut JSContext, value: HandleValue) {
+        if !ResolvePromise(cx, self.promise_obj(), value) {
+            JS_ClearPendingException(cx);
         }
     }
 
     #[allow(unsafe_code)]
-    pub fn reject_native<T>(&self, cx: *mut JSContext, val: &T) where T: ToJSValConvertible {
+    pub fn reject_native<T>(&self, val: &T) where T: ToJSValConvertible {
+        let cx = self.global().get_cx();
+        let _ac = JSAutoCompartment::new(cx, self.reflector().get_jsobject().get());
         rooted!(in(cx) let mut v = UndefinedValue());
         unsafe {
             val.to_jsval(cx, v.handle_mut());
+            self.reject(cx, v.handle());
         }
-        self.reject(cx, v.handle());
     }
 
     #[allow(unsafe_code)]
-    pub fn reject_error(&self, cx: *mut JSContext, error: Error) {
+    pub fn reject_error(&self, error: Error) {
+        let cx = self.global().get_cx();
+        let _ac = JSAutoCompartment::new(cx, self.reflector().get_jsobject().get());
         rooted!(in(cx) let mut v = UndefinedValue());
         unsafe {
             error.to_jsval(cx, &self.global(), v.handle_mut());
-        }
-        self.reject(cx, v.handle());
-    }
-
-    #[allow(unrooted_must_root, unsafe_code)]
-    pub fn reject(&self,
-                        cx: *mut JSContext,
-                        value: HandleValue) {
-        unsafe {
-            if !RejectPromise(cx, self.promise_obj(), value) {
-                JS_ClearPendingException(cx);
-            }
+            self.reject(cx, v.handle());
         }
     }
 
     #[allow(unrooted_must_root, unsafe_code)]
-    pub fn then(&self,
-                cx: *mut JSContext,
-                _callee: HandleObject,
-                cb_resolve: AnyCallback,
-                cb_reject: AnyCallback,
-                result: MutableHandleObject) {
-        let promise = self.promise_obj();
-        rooted!(in(cx) let resolve = cb_resolve.callback());
-        rooted!(in(cx) let reject = cb_reject.callback());
-        unsafe {
-            rooted!(in(cx) let res =
-                CallOriginalPromiseThen(cx, promise, resolve.handle(), reject.handle()));
-            result.set(*res);
+    pub unsafe fn reject(&self, cx: *mut JSContext, value: HandleValue) {
+        if !RejectPromise(cx, self.promise_obj(), value) {
+            JS_ClearPendingException(cx);
         }
     }
 
     #[allow(unsafe_code)]
-    pub fn is_settled(&self) -> bool {
+    pub fn is_fulfilled(&self) -> bool {
         let state = unsafe { GetPromiseState(self.promise_obj()) };
         match state {
             PromiseState::Rejected | PromiseState::Fulfilled => true,
             _ => false
         }
     }
 
     #[allow(unsafe_code)]
--- a/servo/components/script/dom/serviceworkercontainer.rs
+++ b/servo/components/script/dom/serviceworkercontainer.rs
@@ -53,67 +53,66 @@ impl ServiceWorkerContainerMethods for S
     #[allow(unrooted_must_root)]
     // https://w3c.github.io/ServiceWorker/#service-worker-container-register-method and - A
     // https://w3c.github.io/ServiceWorker/#start-register-algorithm - B
     fn Register(&self,
                 script_url: USVString,
                 options: &RegistrationOptions) -> Rc<Promise> {
         // A: Step 1
         let promise = Promise::new(&*self.global());
-        let ctx = (&*self.global()).get_cx();
         let USVString(ref script_url) = script_url;
         let api_base_url = self.global().api_base_url();
         // A: Step 3-5
         let script_url = match api_base_url.join(script_url) {
             Ok(url) => url,
             Err(_) => {
-                promise.reject_error(ctx, Error::Type("Invalid script URL".to_owned()));
+                promise.reject_error(Error::Type("Invalid script URL".to_owned()));
                 return promise;
             }
         };
         // B: Step 2
         match script_url.scheme() {
             "https" | "http" => {},
             _ => {
-                promise.reject_error(ctx, Error::Type("Only secure origins are allowed".to_owned()));
+                promise.reject_error(Error::Type("Only secure origins are allowed".to_owned()));
                 return promise;
             }
         }
         // B: Step 3
         if script_url.path().to_ascii_lowercase().contains("%2f") ||
         script_url.path().to_ascii_lowercase().contains("%5c") {
-            promise.reject_error(ctx, Error::Type("Script URL contains forbidden characters".to_owned()));
+            promise.reject_error(Error::Type("Script URL contains forbidden characters".to_owned()));
             return promise;
         }
         // B: Step 4-5
         let scope = match options.scope {
             Some(ref scope) => {
                 let &USVString(ref inner_scope) = scope;
                 match api_base_url.join(inner_scope) {
                     Ok(url) => url,
                     Err(_) => {
-                        promise.reject_error(ctx, Error::Type("Invalid scope URL".to_owned()));
+                        promise.reject_error(Error::Type("Invalid scope URL".to_owned()));
                         return promise;
                     }
                 }
             },
             None => script_url.join("./").unwrap()
         };
         // B: Step 6
         match scope.scheme() {
             "https" | "http" => {},
             _ => {
-                promise.reject_error(ctx, Error::Type("Only secure origins are allowed".to_owned()));
+                promise.reject_error(Error::Type("Only secure origins are allowed".to_owned()));
                 return promise;
             }
         }
         // B: Step 7
         if scope.path().to_ascii_lowercase().contains("%2f") ||
         scope.path().to_ascii_lowercase().contains("%5c") {
-            promise.reject_error(ctx, Error::Type("Scope URL contains forbidden characters".to_owned()));
+            promise.reject_error(Error::Type("Scope URL contains forbidden characters".to_owned()));
             return promise;
         }
 
         // B: Step 8
         let job = Job::create_job(JobType::Register, scope, script_url, promise.clone(), &*self.client);
         ScriptThread::schedule_job(job);
         promise
     }
--- a/servo/components/script/dom/testbinding.rs
+++ b/servo/components/script/dom/testbinding.rs
@@ -30,17 +30,17 @@ use dom::bindings::str::{ByteString, DOM
 use dom::bindings::trace::RootedTraceableBox;
 use dom::bindings::weakref::MutableWeakRef;
 use dom::blob::{Blob, BlobImpl};
 use dom::globalscope::GlobalScope;
 use dom::promise::Promise;
 use dom::promisenativehandler::{PromiseNativeHandler, Callback};
 use dom::url::URL;
 use dom_struct::dom_struct;
-use js::jsapi::{HandleObject, HandleValue, Heap, JSContext, JSObject, JSAutoCompartment};
+use js::jsapi::{HandleObject, HandleValue, Heap, JSContext, JSObject};
 use js::jsapi::{JS_NewPlainObject, JS_NewUint8ClampedArray};
 use js::jsval::{JSVal, NullValue};
 use script_traits::MsDuration;
 use servo_config::prefs::PREFS;
 use std::borrow::ToOwned;
 use std::ptr;
 use std::rc::Rc;
 use timers::OneshotTimerCallback;
@@ -670,37 +670,37 @@ impl TestBindingMethods for TestBinding 
     fn ReceiveMozMapOfNullableInts(&self) -> MozMap<Option<i32>> { MozMap::new() }
     fn ReceiveNullableMozMapOfNullableInts(&self) -> Option<MozMap<Option<i32>>> { Some(MozMap::new()) }
     fn ReceiveMozMapOfMozMaps(&self) -> MozMap<MozMap<i32>> { MozMap::new() }
     fn ReceiveAnyMozMap(&self) -> MozMap<JSVal> { MozMap::new() }
 
     #[allow(unrooted_must_root)]
     #[allow(unsafe_code)]
     unsafe fn ReturnResolvedPromise(&self, cx: *mut JSContext, v: HandleValue) -> Fallible<Rc<Promise>> {
-        Promise::Resolve(&self.global(), cx, v)
+        Promise::new_resolved(&self.global(), cx, v)
     }
 
     #[allow(unrooted_must_root)]
     #[allow(unsafe_code)]
     unsafe fn ReturnRejectedPromise(&self, cx: *mut JSContext, v: HandleValue) -> Fallible<Rc<Promise>> {
-        Promise::Reject(&self.global(), cx, v)
+        Promise::new_rejected(&self.global(), cx, v)
     }
 
     #[allow(unsafe_code)]
     unsafe fn PromiseResolveNative(&self, cx: *mut JSContext, p: &Promise, v: HandleValue) {
         p.resolve(cx, v);
     }
 
     #[allow(unsafe_code)]
     unsafe fn PromiseRejectNative(&self, cx: *mut JSContext, p: &Promise, v: HandleValue) {
         p.reject(cx, v);
     }
 
     fn PromiseRejectWithTypeError(&self, p: &Promise, s: USVString) {
-        p.reject_error(self.global().get_cx(), Error::Type(s.0));
+        p.reject_error(Error::Type(s.0));
     }
 
     #[allow(unrooted_must_root)]
     fn ResolvePromiseDelayed(&self, p: &Promise, value: DOMString, delay: u64) {
         let promise = p.duplicate();
         let cb = TestBindingCallback {
             promise: TrustedPromise::new(promise),
             value: value,
@@ -809,14 +809,11 @@ pub struct TestBindingCallback {
     #[ignore_heap_size_of = "unclear ownership semantics"]
     promise: TrustedPromise,
     value: DOMString,
 }
 
 impl TestBindingCallback {
     #[allow(unrooted_must_root)]
     pub fn invoke(self) {
-        let p = self.promise.root();
-        let cx = p.global().get_cx();
-        let _ac = JSAutoCompartment::new(cx, p.reflector().get_jsobject().get());
-        p.resolve_native(cx, &self.value);
+        self.promise.root().resolve_native(&self.value);
     }
 }
--- a/servo/components/script/dom/vr.rs
+++ b/servo/components/script/dom/vr.rs
@@ -68,31 +68,31 @@ impl VRMethods for VR {
             match receiver.recv().unwrap() {
                 Ok(displays) => {
                     // Sync displays
                     for display in displays {
                         self.sync_display(&display);
                     }
                 },
                 Err(e) => {
-                    promise.reject_native(promise.global().get_cx(), &e);
+                    promise.reject_native(&e);
                     return promise;
                 }
             }
         } else {
             // WebVR spec: The Promise MUST be rejected if WebVR is not enabled/supported.
-            promise.reject_error(promise.global().get_cx(), Error::Security);
+            promise.reject_error(Error::Security);
             return promise;
         }
 
         // convert from JS to Root
         let displays: Vec<Root<VRDisplay>> = self.displays.borrow().iter()
                                                           .map(|d| Root::from_ref(&**d))
                                                           .collect();
-        promise.resolve_native(promise.global().get_cx(), &displays);
+        promise.resolve_native(&displays);
 
         promise
     }
 }
 
 
 impl VR {
     fn webvr_thread(&self) -> Option<IpcSender<WebVRMsg>> {
--- a/servo/components/script/dom/vrdisplay.rs
+++ b/servo/components/script/dom/vrdisplay.rs
@@ -279,102 +279,102 @@ impl VRDisplayMethods for VRDisplay {
     // https://w3c.github.io/webvr/#dom-vrdisplay-requestpresent
     fn RequestPresent(&self, layers: Vec<VRLayer>) -> Rc<Promise> {
         let promise = Promise::new(&self.global());
         // TODO: WebVR spec: this method must be called in response to a user gesture
 
         // WebVR spec: If canPresent is false the promise MUST be rejected
         if !self.display.borrow().capabilities.can_present {
             let msg = "VRDisplay canPresent is false".to_string();
-            promise.reject_native(promise.global().get_cx(), &msg);
+            promise.reject_native(&msg);
             return promise;
         }
 
         // Current WebVRSpec only allows 1 VRLayer if the VRDevice can present.
         // Future revisions of this spec may allow multiple layers to enable more complex rendering effects
         // such as compositing WebGL and DOM elements together.
         // That functionality is not allowed by this revision of the spec.
         if layers.len() != 1 {
             let msg = "The number of layers must be 1".to_string();
-            promise.reject_native(promise.global().get_cx(), &msg);
+            promise.reject_native(&msg);
             return promise;
         }
 
         // Parse and validate received VRLayer
         let layer = validate_layer(self.global().get_cx(), &layers[0]);
 
         let layer_bounds;
         let layer_ctx;
 
         match layer {
             Ok((bounds, ctx)) => {
                 layer_bounds = bounds;
                 layer_ctx = ctx;
             },
             Err(msg) => {
                 let msg = msg.to_string();
-                promise.reject_native(promise.global().get_cx(), &msg);
+                promise.reject_native(&msg);
                 return promise;
             }
         };
 
         // WebVR spec: Repeat calls while already presenting will update the VRLayers being displayed.
         if self.presenting.get() {
             *self.layer.borrow_mut() = layer_bounds;
             self.layer_ctx.set(Some(&layer_ctx));
-            promise.resolve_native(promise.global().get_cx(), &());
+            promise.resolve_native(&());
             return promise;
         }
 
         // Request Present
         let (sender, receiver) = ipc::channel().unwrap();
         self.webvr_thread().send(WebVRMsg::RequestPresent(self.global().pipeline_id(),
                                                           self.display.borrow().display_id,
                                                           sender))
                                                           .unwrap();
         match receiver.recv().unwrap() {
             Ok(()) => {
                 *self.layer.borrow_mut() = layer_bounds;
                 self.layer_ctx.set(Some(&layer_ctx));
                 self.init_present();
-                promise.resolve_native(promise.global().get_cx(), &());
+                promise.resolve_native(&());
             },
             Err(e) => {
-                promise.reject_native(promise.global().get_cx(), &e);
+                promise.reject_native(&e);
             }
         }
 
         promise
     }
 
     #[allow(unrooted_must_root)]
     // https://w3c.github.io/webvr/#dom-vrdisplay-exitpresent
     fn ExitPresent(&self) -> Rc<Promise> {
         let promise = Promise::new(&self.global());
 
         // WebVR spec: If the VRDisplay is not presenting the promise MUST be rejected.
         if !self.presenting.get() {
             let msg = "VRDisplay is not presenting".to_string();
-            promise.reject_native(promise.global().get_cx(), &msg);
+            promise.reject_native(&msg);
             return promise;
         }
 
         // Exit present
         let (sender, receiver) = ipc::channel().unwrap();
         self.webvr_thread().send(WebVRMsg::ExitPresent(self.global().pipeline_id(),
                                                        self.display.borrow().display_id,
                                                        Some(sender)))
                                                        .unwrap();
         match receiver.recv().unwrap() {
             Ok(()) => {
                 self.stop_present();
-                promise.resolve_native(promise.global().get_cx(), &());
+                promise.resolve_native(&());
             },
             Err(e) => {
-                promise.reject_native(promise.global().get_cx(), &e);
+                promise.reject_native(&e);
             }
         }
 
         promise
     }
 
     // https://w3c.github.io/webvr/#dom-vrdisplay-submitframe
     fn SubmitFrame(&self) {
--- a/servo/components/script/dom/worklet.rs
+++ b/servo/components/script/dom/worklet.rs
@@ -118,17 +118,17 @@ impl WorkletMethods for Worklet {
         let promise = Promise::new(self.window.upcast());
 
         // Step 3.
         let module_url_record = match self.window.Document().base_url().join(&module_url.0) {
             Ok(url) => url,
             Err(err) => {
                 // Step 4.
                 debug!("URL {:?} parse error {:?}.", module_url.0, err);
-                promise.reject_error(self.window.get_cx(), Error::Syntax);
+                promise.reject_error(Error::Syntax);
                 return promise;
             }
         };
         debug!("Adding Worklet module {}.", module_url_record);
 
         // Steps 6-12 in parallel.
         let pending_tasks_struct = PendingTasksStruct::new();
         let global = self.window.upcast::<GlobalScope>();
--- a/servo/components/script/fetch.rs
+++ b/servo/components/script/fetch.rs
@@ -72,17 +72,17 @@ pub fn Fetch(global: &GlobalScope, input
 
     // Step 1
     let promise = Promise::new(global);
     let response = Response::new(global);
 
     // Step 2
     let request = match Request::Constructor(global, input, init) {
         Err(e) => {
-            promise.reject_error(promise.global().get_cx(), e);
+            promise.reject_error(e);
             return promise;
         },
         Ok(r) => r.get_request(),
     };
     let mut request_init = request_init_from_request(request);
 
     // Step 3
     if global.downcast::<ServiceWorkerGlobalScope>().is_some() {
@@ -130,19 +130,17 @@ impl FetchResponseListener for FetchCont
 
         // JSAutoCompartment needs to be manually made.
         // Otherwise, Servo will crash.
         let promise_cx = promise.global().get_cx();
         let _ac = JSAutoCompartment::new(promise_cx, promise.reflector().get_jsobject().get());
         match fetch_metadata {
             // Step 4.1
             Err(_) => {
-                promise.reject_error(
-                    promise.global().get_cx(),
-                    Error::Type("Network error occurred".to_string()));
+                promise.reject_error(Error::Type("Network error occurred".to_string()));
                 self.fetch_promise = Some(TrustedPromise::new(promise));
                 self.response_object.root().set_type(DOMResponseType::Error);
                 return;
             },
             // Step 4.2
             Ok(metadata) => {
                 match metadata {
                     FetchMetadata::Unfiltered(m) => {
@@ -162,19 +160,17 @@ impl FetchResponseListener for FetchCont
                             self.response_object.root().set_type(DOMResponseType::Opaque),
                         FilteredMetadata::OpaqueRedirect =>
                             self.response_object.root().set_type(DOMResponseType::Opaqueredirect)
                     }
                 }
             }
         }
         // Step 4.3
-        promise.resolve_native(
-            promise_cx,
-            &self.response_object.root());
+        promise.resolve_native(&self.response_object.root());
         self.fetch_promise = Some(TrustedPromise::new(promise));
     }
 
     fn process_response_chunk(&mut self, mut chunk: Vec<u8>) {
         self.body.append(&mut chunk);
     }
 
     fn process_response_eof(&mut self, _response: Result<(), NetworkError>) {
--- a/servo/components/script/serviceworkerjob.rs
+++ b/servo/components/script/serviceworkerjob.rs
@@ -8,21 +8,19 @@
 //! by multiple service worker clients in a Vec.
 
 use dom::bindings::cell::DOMRefCell;
 use dom::bindings::error::Error;
 use dom::bindings::js::JS;
 use dom::bindings::refcounted::{Trusted, TrustedPromise};
 use dom::bindings::reflector::DomObject;
 use dom::client::Client;
-use dom::globalscope::GlobalScope;
 use dom::promise::Promise;
 use dom::serviceworkerregistration::ServiceWorkerRegistration;
 use dom::urlhelper::UrlHelper;
-use js::jsapi::JSAutoCompartment;
 use script_thread::ScriptThread;
 use servo_url::ServoUrl;
 use std::cmp::PartialEq;
 use std::collections::HashMap;
 use std::rc::Rc;
 use task_source::TaskSource;
 use task_source::dom_manipulation::DOMManipulationTaskSource;
 
@@ -111,17 +109,17 @@ impl JobQueue {
         if job_queue.is_empty() {
             let scope_url = job.scope_url.clone();
             job_queue.push(job);
             let _ = script_thread.schedule_job_queue(scope_url);
             debug!("queued task to run newly-queued job");
         } else {
             // Step 2
             let mut last_job = job_queue.pop().unwrap();
-            if job == last_job && !last_job.promise.is_settled() {
+            if job == last_job && !last_job.promise.is_fulfilled() {
                 last_job.append_equivalent_job(job);
                 job_queue.push(last_job);
                 debug!("appended equivalent job");
             } else {
                 // restore the popped last_job
                 job_queue.push(last_job);
                 // and push this new job to job queue
                 job_queue.push(job);
@@ -256,33 +254,32 @@ impl JobQueue {
             // Step 8.1
             resolve_job_promise(job, &*reg, script_thread.dom_manipulation_task_source());
             // Step 8.2 present in run_job
         }
         // TODO Step 9 (create new service worker)
     }
 }
 
-fn settle_job_promise(global: &GlobalScope, promise: &Promise, settle: SettleType) {
-    let _ac = JSAutoCompartment::new(global.get_cx(), promise.reflector().get_jsobject().get());
+fn settle_job_promise(promise: &Promise, settle: SettleType) {
     match settle {
-        SettleType::Resolve(reg) => promise.resolve_native(global.get_cx(), &*reg.root()),
-        SettleType::Reject(err) => promise.reject_error(global.get_cx(), err),
+        SettleType::Resolve(reg) => promise.resolve_native(&*reg.root()),
+        SettleType::Reject(err) => promise.reject_error(err),
     };
 }
 
 #[allow(unrooted_must_root)]
 fn queue_settle_promise_for_job(job: &Job, settle: SettleType, task_source: &DOMManipulationTaskSource) {
     let global = job.client.global();
     let promise = TrustedPromise::new(job.promise.clone());
     // FIXME(nox): Why are errors silenced here?
     let _ = task_source.queue(
         task!(settle_promise_for_job: move || {
             let promise = promise.root();
-            settle_job_promise(&promise.global(), &promise, settle)
+            settle_job_promise(&promise, settle)
         }),
         &*global,
     );
 }
 
 // https://w3c.github.io/ServiceWorker/#reject-job-promise-algorithm
 // https://w3c.github.io/ServiceWorker/#resolve-job-promise-algorithm
 fn queue_settle_promise(job: &Job, settle: SettleType, task_source: &DOMManipulationTaskSource) {