Merge mozilla-central to autoland. a=merge on a CLOSED TREE
authorRazvan Maries <rmaries@mozilla.com>
Wed, 16 Jan 2019 19:06:30 +0200
changeset 511215 fb629855a3bbed86fb68cb7d2e42f9486f7f81be
parent 511214 0eafc7a464331f4955977d169485c24b8b57661c (current diff)
parent 511194 1312db5d495953cc6e18b16d082d06d611a21166 (diff)
child 511216 7f25f8bee25bcd1f5da9ef7cc8c4026560f9d356
push id10547
push userffxbld-merge
push dateMon, 21 Jan 2019 13:03:58 +0000
treeherdermozilla-beta@24ec1916bffe [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone66.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge mozilla-central to autoland. a=merge on a CLOSED TREE
servo/components/style_traits/cursor.rs
--- a/dom/base/Document.cpp
+++ b/dom/base/Document.cpp
@@ -10694,17 +10694,17 @@ PointerLockRequest::Run() {
       return NS_OK;
     }
   }
   // If it is neither user input initiated, nor requested in fullscreen,
   // it should be rejected.
   if (!error && !mUserInputOrChromeCaller && !doc->GetFullscreenElement()) {
     error = "PointerLockDeniedNotInputDriven";
   }
-  if (!error && !doc->SetPointerLock(e, NS_STYLE_CURSOR_NONE)) {
+  if (!error && !doc->SetPointerLock(e, StyleCursorKind::None)) {
     error = "PointerLockDeniedFailedToLock";
   }
   if (error) {
     DispatchPointerLockError(doc, error);
     return NS_OK;
   }
 
   ChangePointerLockedElement(e, doc, nullptr);
@@ -10732,17 +10732,17 @@ void Document::RequestPointerLock(Elemen
 
   bool userInputOrSystemCaller = EventStateManager::IsHandlingUserInput() ||
                                  aCallerType == CallerType::System;
   nsCOMPtr<nsIRunnable> request =
       new PointerLockRequest(aElement, userInputOrSystemCaller);
   Dispatch(TaskCategory::Other, request.forget());
 }
 
-bool Document::SetPointerLock(Element* aElement, int aCursorStyle) {
+bool Document::SetPointerLock(Element* aElement, StyleCursorKind aCursorStyle) {
   MOZ_ASSERT(!aElement || aElement->OwnerDoc() == this,
              "We should be either unlocking pointer (aElement is nullptr), "
              "or locking pointer to an element in this document");
 #ifdef DEBUG
   if (!aElement) {
     nsCOMPtr<Document> pointerLockedDoc =
         do_QueryReferent(EventStateManager::sPointerLockedDoc);
     MOZ_ASSERT(pointerLockedDoc == this);
@@ -10792,17 +10792,17 @@ void Document::UnlockPointer(Document* a
     return;
   }
 
   nsCOMPtr<Document> pointerLockedDoc =
       do_QueryReferent(EventStateManager::sPointerLockedDoc);
   if (!pointerLockedDoc || (aDoc && aDoc != pointerLockedDoc)) {
     return;
   }
-  if (!pointerLockedDoc->SetPointerLock(nullptr, NS_STYLE_CURSOR_AUTO)) {
+  if (!pointerLockedDoc->SetPointerLock(nullptr, StyleCursorKind::Auto)) {
     return;
   }
 
   nsCOMPtr<Element> pointerLockedElement =
       do_QueryReferent(EventStateManager::sPointerLockedElement);
   ChangePointerLockedElement(nullptr, pointerLockedDoc, pointerLockedElement);
 
   RefPtr<AsyncEventDispatcher> asyncDispatcher = new AsyncEventDispatcher(
--- a/dom/base/Document.h
+++ b/dom/base/Document.h
@@ -131,16 +131,17 @@ class Encoding;
 class ErrorResult;
 class EventStates;
 class EventListenerManager;
 class FullscreenExit;
 class FullscreenRequest;
 class PendingAnimationTracker;
 class ServoStyleSet;
 class SMILAnimationController;
+enum class StyleCursorKind : uint8_t;
 template <typename>
 class OwningNonNull;
 struct URLExtraData;
 
 namespace css {
 class Loader;
 class ImageLoader;
 class Rule;
@@ -1816,18 +1817,18 @@ class Document : public nsINode,
 
   /**
    * Handles any pending fullscreen in aDocument or its subdocuments.
    *
    * Returns whether there is any fullscreen request handled.
    */
   static bool HandlePendingFullscreenRequests(Document* aDocument);
 
-  void RequestPointerLock(Element* aElement, mozilla::dom::CallerType);
-  bool SetPointerLock(Element* aElement, int aCursorStyle);
+  void RequestPointerLock(Element* aElement, CallerType);
+  bool SetPointerLock(Element* aElement, StyleCursorKind);
 
   static void UnlockPointer(Document* aDoc = nullptr);
 
   // ScreenOrientation related APIs
 
   void SetCurrentOrientation(mozilla::dom::OrientationType aType,
                              uint16_t aAngle) {
     mCurrentOrientationType = aType;
--- a/dom/base/nsGlobalWindowOuter.cpp
+++ b/dom/base/nsGlobalWindowOuter.cpp
@@ -7046,28 +7046,31 @@ already_AddRefed<nsWindowRoot> nsGlobalW
 nsIDOMWindowUtils* nsGlobalWindowOuter::WindowUtils() {
   if (!mWindowUtils) {
     mWindowUtils = new nsDOMWindowUtils(this);
   }
   return mWindowUtils;
 }
 
 // Note: This call will lock the cursor, it will not change as it moves.
-// To unlock, the cursor must be set back to CURSOR_AUTO.
+// To unlock, the cursor must be set back to Auto.
 void nsGlobalWindowOuter::SetCursorOuter(const nsAString& aCursor,
                                          ErrorResult& aError) {
-  int32_t cursor;
-
-  if (aCursor.EqualsLiteral("auto"))
-    cursor = NS_STYLE_CURSOR_AUTO;
-  else {
+  StyleCursorKind cursor;
+
+  if (aCursor.EqualsLiteral("auto")) {
+    cursor = StyleCursorKind::Auto;
+  } else {
+    // TODO(emilio): Use Servo for this instead.
     nsCSSKeyword keyword = nsCSSKeywords::LookupKeyword(aCursor);
-    if (!nsCSSProps::FindKeyword(keyword, nsCSSProps::kCursorKTable, cursor)) {
+    int32_t c;
+    if (!nsCSSProps::FindKeyword(keyword, nsCSSProps::kCursorKTable, c)) {
       return;
     }
+    cursor = static_cast<StyleCursorKind>(c);
   }
 
   RefPtr<nsPresContext> presContext;
   if (mDocShell) {
     presContext = mDocShell->GetPresContext();
   }
 
   if (presContext) {
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -216,22 +216,24 @@ TimeStamp EventStateManager::sHandlingIn
 EventStateManager::WheelPrefs* EventStateManager::WheelPrefs::sInstance =
     nullptr;
 bool EventStateManager::WheelPrefs::sWheelEventsEnabledOnPlugins = true;
 bool EventStateManager::WheelPrefs::sIsAutoDirEnabled = false;
 bool EventStateManager::WheelPrefs::sHonoursRootForAutoDir = false;
 EventStateManager::DeltaAccumulator*
     EventStateManager::DeltaAccumulator::sInstance = nullptr;
 
+constexpr const StyleCursorKind kInvalidCursorKind =
+  static_cast<StyleCursorKind>(255);
+
 EventStateManager::EventStateManager()
-    : mLockCursor(0),
+    : mLockCursor(kInvalidCursorKind),
       mLastFrameConsumedSetCursor(false),
-      mCurrentTarget(nullptr)
+      mCurrentTarget(nullptr),
       // init d&d gesture state machine variables
-      ,
       mGestureDownPoint(0, 0),
       mGestureModifiers(0),
       mGestureDownButtons(0),
       mPresContext(nullptr),
       mLClickCount(0),
       mMClickCount(0),
       mRClickCount(0),
       mInTouchDrag(false),
@@ -3607,23 +3609,23 @@ void EventStateManager::ClearFrameRefs(n
 void EventStateManager::UpdateCursor(nsPresContext* aPresContext,
                                      WidgetEvent* aEvent,
                                      nsIFrame* aTargetFrame,
                                      nsEventStatus* aStatus) {
   if (aTargetFrame && IsRemoteTarget(aTargetFrame->GetContent())) {
     return;
   }
 
-  int32_t cursor = NS_STYLE_CURSOR_DEFAULT;
+  auto cursor = StyleCursorKind::Default;
   imgIContainer* container = nullptr;
   bool haveHotspot = false;
   float hotspotX = 0.0f, hotspotY = 0.0f;
 
   // If cursor is locked just use the locked one
-  if (mLockCursor) {
+  if (mLockCursor != kInvalidCursorKind) {
     cursor = mLockCursor;
   }
   // If not locked, look for correct cursor
   else if (aTargetFrame) {
     nsIFrame::Cursor framecursor;
     nsPoint pt =
         nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, aTargetFrame);
     // Avoid setting cursor when the mouse is over a windowless pluign.
@@ -3658,171 +3660,171 @@ void EventStateManager::UpdateCursor(nsP
     // Check whether or not to show the busy cursor
     nsCOMPtr<nsIDocShell> docShell(aPresContext->GetDocShell());
     if (!docShell) return;
     auto busyFlags = docShell->GetBusyFlags();
 
     // Show busy cursor everywhere before page loads
     // and just replace the arrow cursor after page starts loading
     if (busyFlags & nsIDocShell::BUSY_FLAGS_BUSY &&
-        (cursor == NS_STYLE_CURSOR_AUTO || cursor == NS_STYLE_CURSOR_DEFAULT)) {
-      cursor = NS_STYLE_CURSOR_SPINNING;
+        (cursor == StyleCursorKind::Auto || cursor == StyleCursorKind::Default)) {
+      cursor = StyleCursorKind::Progress;
       container = nullptr;
     }
   }
 
   if (aTargetFrame) {
     SetCursor(cursor, container, haveHotspot, hotspotX, hotspotY,
               aTargetFrame->GetNearestWidget(), false);
     gLastCursorSourceFrame = aTargetFrame;
     gLastCursorUpdateTime = TimeStamp::NowLoRes();
   }
 
-  if (mLockCursor || NS_STYLE_CURSOR_AUTO != cursor) {
+  if (mLockCursor != kInvalidCursorKind || StyleCursorKind::Auto != cursor) {
     *aStatus = nsEventStatus_eConsumeDoDefault;
   }
 }
 
 void EventStateManager::ClearCachedWidgetCursor(nsIFrame* aTargetFrame) {
   if (!aTargetFrame) {
     return;
   }
   nsIWidget* aWidget = aTargetFrame->GetNearestWidget();
   if (!aWidget) {
     return;
   }
   aWidget->ClearCachedCursor();
 }
 
-nsresult EventStateManager::SetCursor(int32_t aCursor,
+nsresult EventStateManager::SetCursor(StyleCursorKind aCursor,
                                       imgIContainer* aContainer,
                                       bool aHaveHotspot, float aHotspotX,
                                       float aHotspotY, nsIWidget* aWidget,
                                       bool aLockCursor) {
   EnsureDocument(mPresContext);
   NS_ENSURE_TRUE(mDocument, NS_ERROR_FAILURE);
   sMouseOverDocument = mDocument.get();
 
   nsCursor c;
 
   NS_ENSURE_TRUE(aWidget, NS_ERROR_FAILURE);
   if (aLockCursor) {
-    if (NS_STYLE_CURSOR_AUTO != aCursor) {
+    if (StyleCursorKind::Auto != aCursor) {
       mLockCursor = aCursor;
     } else {
       // If cursor style is set to auto we unlock the cursor again.
-      mLockCursor = 0;
+      mLockCursor = kInvalidCursorKind;
     }
   }
   switch (aCursor) {
     default:
-    case NS_STYLE_CURSOR_AUTO:
-    case NS_STYLE_CURSOR_DEFAULT:
+    case StyleCursorKind::Auto:
+    case StyleCursorKind::Default:
       c = eCursor_standard;
       break;
-    case NS_STYLE_CURSOR_POINTER:
+    case StyleCursorKind::Pointer:
       c = eCursor_hyperlink;
       break;
-    case NS_STYLE_CURSOR_CROSSHAIR:
+    case StyleCursorKind::Crosshair:
       c = eCursor_crosshair;
       break;
-    case NS_STYLE_CURSOR_MOVE:
+    case StyleCursorKind::Move:
       c = eCursor_move;
       break;
-    case NS_STYLE_CURSOR_TEXT:
+    case StyleCursorKind::Text:
       c = eCursor_select;
       break;
-    case NS_STYLE_CURSOR_WAIT:
+    case StyleCursorKind::Wait:
       c = eCursor_wait;
       break;
-    case NS_STYLE_CURSOR_HELP:
+    case StyleCursorKind::Help:
       c = eCursor_help;
       break;
-    case NS_STYLE_CURSOR_N_RESIZE:
+    case StyleCursorKind::NResize:
       c = eCursor_n_resize;
       break;
-    case NS_STYLE_CURSOR_S_RESIZE:
+    case StyleCursorKind::SResize:
       c = eCursor_s_resize;
       break;
-    case NS_STYLE_CURSOR_W_RESIZE:
+    case StyleCursorKind::WResize:
       c = eCursor_w_resize;
       break;
-    case NS_STYLE_CURSOR_E_RESIZE:
+    case StyleCursorKind::EResize:
       c = eCursor_e_resize;
       break;
-    case NS_STYLE_CURSOR_NW_RESIZE:
+    case StyleCursorKind::NwResize:
       c = eCursor_nw_resize;
       break;
-    case NS_STYLE_CURSOR_SE_RESIZE:
+    case StyleCursorKind::SeResize:
       c = eCursor_se_resize;
       break;
-    case NS_STYLE_CURSOR_NE_RESIZE:
+    case StyleCursorKind::NeResize:
       c = eCursor_ne_resize;
       break;
-    case NS_STYLE_CURSOR_SW_RESIZE:
+    case StyleCursorKind::SwResize:
       c = eCursor_sw_resize;
       break;
-    case NS_STYLE_CURSOR_COPY:  // CSS3
+    case StyleCursorKind::Copy:  // CSS3
       c = eCursor_copy;
       break;
-    case NS_STYLE_CURSOR_ALIAS:
+    case StyleCursorKind::Alias:
       c = eCursor_alias;
       break;
-    case NS_STYLE_CURSOR_CONTEXT_MENU:
+    case StyleCursorKind::ContextMenu:
       c = eCursor_context_menu;
       break;
-    case NS_STYLE_CURSOR_CELL:
+    case StyleCursorKind::Cell:
       c = eCursor_cell;
       break;
-    case NS_STYLE_CURSOR_GRAB:
+    case StyleCursorKind::Grab:
       c = eCursor_grab;
       break;
-    case NS_STYLE_CURSOR_GRABBING:
+    case StyleCursorKind::Grabbing:
       c = eCursor_grabbing;
       break;
-    case NS_STYLE_CURSOR_SPINNING:
+    case StyleCursorKind::Progress:
       c = eCursor_spinning;
       break;
-    case NS_STYLE_CURSOR_ZOOM_IN:
+    case StyleCursorKind::ZoomIn:
       c = eCursor_zoom_in;
       break;
-    case NS_STYLE_CURSOR_ZOOM_OUT:
+    case StyleCursorKind::ZoomOut:
       c = eCursor_zoom_out;
       break;
-    case NS_STYLE_CURSOR_NOT_ALLOWED:
+    case StyleCursorKind::NotAllowed:
       c = eCursor_not_allowed;
       break;
-    case NS_STYLE_CURSOR_COL_RESIZE:
+    case StyleCursorKind::ColResize:
       c = eCursor_col_resize;
       break;
-    case NS_STYLE_CURSOR_ROW_RESIZE:
+    case StyleCursorKind::RowResize:
       c = eCursor_row_resize;
       break;
-    case NS_STYLE_CURSOR_NO_DROP:
+    case StyleCursorKind::NoDrop:
       c = eCursor_no_drop;
       break;
-    case NS_STYLE_CURSOR_VERTICAL_TEXT:
+    case StyleCursorKind::VerticalText:
       c = eCursor_vertical_text;
       break;
-    case NS_STYLE_CURSOR_ALL_SCROLL:
+    case StyleCursorKind::AllScroll:
       c = eCursor_all_scroll;
       break;
-    case NS_STYLE_CURSOR_NESW_RESIZE:
+    case StyleCursorKind::NeswResize:
       c = eCursor_nesw_resize;
       break;
-    case NS_STYLE_CURSOR_NWSE_RESIZE:
+    case StyleCursorKind::NwseResize:
       c = eCursor_nwse_resize;
       break;
-    case NS_STYLE_CURSOR_NS_RESIZE:
+    case StyleCursorKind::NsResize:
       c = eCursor_ns_resize;
       break;
-    case NS_STYLE_CURSOR_EW_RESIZE:
+    case StyleCursorKind::EwResize:
       c = eCursor_ew_resize;
       break;
-    case NS_STYLE_CURSOR_NONE:
+    case StyleCursorKind::None:
       c = eCursor_none;
       break;
   }
 
   // First, try the imgIContainer, if non-null
   nsresult rv = NS_ERROR_FAILURE;
   if (aContainer) {
     uint32_t hotspotX, hotspotY;
--- a/dom/events/EventStateManager.h
+++ b/dom/events/EventStateManager.h
@@ -226,17 +226,17 @@ class EventStateManager : public nsSuppo
    * aEvent in the process but won't execute it.
    *
    * @return            true if there is accesskey which aEvent matches with
    *                    in this process.  Otherwise, false.
    */
   bool CheckIfEventMatchesAccessKey(WidgetKeyboardEvent* aEvent,
                                     nsPresContext* aPresContext);
 
-  nsresult SetCursor(int32_t aCursor, imgIContainer* aContainer,
+  nsresult SetCursor(StyleCursorKind aCursor, imgIContainer* aContainer,
                      bool aHaveHotspot, float aHotspotX, float aHotspotY,
                      nsIWidget* aWidget, bool aLockCursor);
 
   /**
    * StartHandlingUserInput() is called when we start to handle a user input.
    * StopHandlingUserInput() is called when we finish handling a user input.
    * If the caller knows which input event caused that, it should set
    * aMessage to the event message.  Otherwise, set eVoidEvent.
@@ -1166,17 +1166,17 @@ class EventStateManager : public nsSuppo
    * gestures which are eKeyUp, eMouseUp, eTouchEnd.
    */
   void NotifyTargetUserActivation(WidgetEvent* aEvent,
                                   nsIContent* aTargetContent);
 
   already_AddRefed<EventStateManager> ESMFromContentOrThis(
       nsIContent* aContent);
 
-  int32_t mLockCursor;
+  StyleCursorKind mLockCursor;
   bool mLastFrameConsumedSetCursor;
 
   // Last mouse event mRefPoint (the offset from the widget's origin in
   // device pixels) when mouse was locked, used to restore mouse position
   // after unlocking.
   static LayoutDeviceIntPoint sPreLockPoint;
 
   // Stores the mRefPoint of the last synthetic mouse move we dispatched
--- a/gfx/src/FilterSupport.h
+++ b/gfx/src/FilterSupport.h
@@ -13,16 +13,24 @@
 #include "mozilla/gfx/Matrix.h"
 #include "mozilla/gfx/2D.h"
 #include "nsClassHashtable.h"
 #include "nsTArray.h"
 #include "nsRegion.h"
 
 namespace mozilla {
 namespace gfx {
+class FilterPrimitiveDescription;
+} // namespace gfx
+} // namespace mozilla
+
+DECLARE_USE_COPY_CONSTRUCTORS(mozilla::gfx::FilterPrimitiveDescription)
+
+namespace mozilla {
+namespace gfx {
 
 // Morphology Operators
 const unsigned short SVG_OPERATOR_UNKNOWN = 0;
 const unsigned short SVG_OPERATOR_ERODE = 1;
 const unsigned short SVG_OPERATOR_DILATE = 2;
 
 // ColorMatrix types
 const unsigned short SVG_FECOLORMATRIX_TYPE_UNKNOWN = 0;
@@ -456,20 +464,20 @@ class FilterPrimitiveDescription final {
 
   bool operator==(const FilterPrimitiveDescription& aOther) const;
   bool operator!=(const FilterPrimitiveDescription& aOther) const {
     return !(*this == aOther);
   }
 
  private:
   PrimitiveAttributes mAttributes;
-  nsTArray<int32_t> mInputPrimitives;
+  AutoTArray<int32_t, 2> mInputPrimitives;
   IntRect mFilterPrimitiveSubregion;
   IntRect mFilterSpaceBounds;
-  nsTArray<ColorSpace> mInputColorSpaces;
+  AutoTArray<ColorSpace, 2> mInputColorSpaces;
   ColorSpace mOutputColorSpace;
   bool mIsTainted;
 };
 
 /**
  * A data structure that contains one or more FilterPrimitiveDescriptions.
  * Designed to be serializable via IPDL, so it must not contain complex
  * functionality.
--- a/image/test/mochitest/mochitest.ini
+++ b/image/test/mochitest/mochitest.ini
@@ -97,17 +97,17 @@ support-files =
 skip-if = os == 'android'
 [test_animation_operators.html]
 skip-if = os == 'android'
 [test_animation2.html]
 skip-if = os == 'android'
 [test_animSVGImage.html]
 skip-if = os == 'android' || os == 'win' # Bug 1370784
 [test_animSVGImage2.html]
-skip-if = os == 'android' || (webrender && os == 'win') #Bug 1354561
+skip-if = os == 'android' || (webrender && os == 'win') || (webrender && os == 'linux') #Bug 1354561
 [test_background_image_anim.html]
 skip-if = os == 'android'
 [test_bug399925.html]
 [test_bug435296.html]
 skip-if = true # disabled - See bug 578591
 [test_bug466586.html]
 [test_bug468160.html]
 [test_bug478398.html]
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/wasm/float-unaligned.js
@@ -0,0 +1,118 @@
+// Various tests for unaligned float accesses.  These are specifically meant to
+// test the SIGBUS handling on 32-bit ARM by exercising odd addresses and odd
+// offsets.
+
+// For a triple of (numBallast, ty, offset), create the text for a pair of
+// functions "get_ty_offset" and "set_ty_offset" where each has numBallast live
+// dummy values across the operation of interest to force the use of different
+// register numbers.  (This is primarily for the FP registers as ARM code
+// generation currently always uses the same scratch register for the base
+// address of the access.)
+//
+// These must be augmented with a memory.  Memory addresses 0-255 are reserved
+// for internal use by these functions.  The memory must start as zero.
+
+function makeLoadStore(numBallast, ty, offset) {
+    // The general idea of the ballast is that we occupy some FP registers and
+    // some int registers with non-dead values before we perform an operation,
+    // and then we consume the occupied registers after.
+    //
+    // In the case of load, the loaded result is stored back in memory before we
+    // consume the ballast, thus the ion regalloc will not simply always load
+    // the result into d0, but usually into some temp other than d0.  Thus the
+    // amount of ballast affects the register.  (Ditto baseline though the
+    // reasoning is simpler.)
+    //
+    // In the case of store, we keep the parameter value live until the end so
+    // that the tmp that we compute for the store is moved into a different
+    // register.  The tmp has the same value as the parameter value but a
+    // non-JIT compiler can't know that.
+
+    let loadtxt =
+      `(func (export "get_${ty}_${offset}") (param $p i32) (result ${ty})
+         ${ballast(() => `
+              (i32.const 8)
+              (i32.store (i32.const 8) (i32.add (i32.load (i32.const 8)) (i32.const 1)))
+              (${ty}.load (i32.const 8))`)}
+
+         (${ty}.store (i32.const 0) (${ty}.load offset=${offset} (get_local $p)))
+
+         ${ballast(() => `
+             ${ty}.store`)}
+
+         (${ty}.load (i32.const 0)))`;
+
+    // This will assume the value at mem[16] is zero.
+    let storetxt =
+      `(func (export "set_${ty}_${offset}") (param $p i32) (param $v ${ty})
+         (local $tmp ${ty})
+         ${ballast(() => `
+              (i32.const 8)
+              (i32.store (i32.const 8) (i32.add (i32.load (i32.const 8)) (i32.const 1)))
+              (${ty}.load (i32.const 8))`)}
+
+         (set_local $tmp (${ty}.add (get_local $v) (${ty}.load (i32.const 16))))
+         (${ty}.store offset=${offset} (get_local $p) (get_local $tmp))
+
+         ${ballast(() => `
+             ${ty}.store`)}
+         (${ty}.store (i32.const 8) (get_local $v)))`;
+
+    return `${loadtxt}
+            ${storetxt}`;
+
+    function ballast(thunk) {
+        let s = "";
+        for ( let i=0 ; i < numBallast; i++ )
+            s += thunk();
+        return s;
+    }
+}
+
+// The complexity here comes from trying to force the source/target FP registers
+// in the FP access instruction to vary.  For Baseline this is not hard; for Ion
+// trickier.
+
+function makeInstance(numBallast, offset) {
+    let txt =
+        `(module
+           (memory (export "memory") 1 1)
+           ${makeLoadStore(numBallast, 'f64', offset)}
+           ${makeLoadStore(numBallast, 'f32', offset)})`;
+    return new WebAssembly.Instance(new WebAssembly.Module(wasmTextToBinary(txt)));
+}
+
+// `offset` corresponds to the "offset" directive in the instruction
+for ( let offset=0 ; offset < 8; offset++ ) {
+
+    // `numBallast` represents the amount of ballast registers we're trying to use,
+    // see comments above.
+    for ( let numBallast=0; numBallast < 16; numBallast++ ) {
+        let ins = makeInstance(numBallast, offset);
+        let mem = ins.exports.memory;
+        let buf = new DataView(mem.buffer);
+
+        // `i` represents the offset in the pointer from a proper boundary
+        for ( let i=0; i < 9; i++ ) {
+	    let offs = 256+i;
+            let val = Math.PI+i;
+
+            buf.setFloat64(offs + offset, val, true);
+            assertEq(ins.exports["get_f64_" + offset](offs), val);
+
+            ins.exports["set_f64_" + offset](offs + 32, val);
+            assertEq(buf.getFloat64(offs + 32 + offset, true), val);
+        }
+
+        for ( let i=0; i < 9; i++ ) {
+            let offs = 512+i;
+            let val = Math.fround(Math.PI+i);
+
+            buf.setFloat32(offs + offset, val, true);
+            assertEq(ins.exports["get_f32_" + offset](offs), val);
+
+            ins.exports["set_f32_" + offset](offs + 32, val);
+            assertEq(buf.getFloat32(offs + 32 + offset, true), val);
+        }
+    }
+}
--- a/js/src/jit-test/tests/wasm/spec/address.wast.js
+++ b/js/src/jit-test/tests/wasm/spec/address.wast.js
@@ -1,10 +1,8 @@
-// |jit-test| skip-if: getBuildConfiguration()['arm']
-// skip due to bug 1517351
 
 // address.wast:3
 let $1 = instance("\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x8a\x80\x80\x80\x00\x02\x60\x01\x7f\x01\x7f\x60\x01\x7f\x00\x03\x9f\x80\x80\x80\x00\x1e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x01\x01\x01\x01\x05\x83\x80\x80\x80\x00\x01\x00\x01\x07\xcd\x82\x80\x80\x00\x1e\x08\x38\x75\x5f\x67\x6f\x6f\x64\x31\x00\x00\x08\x38\x75\x5f\x67\x6f\x6f\x64\x32\x00\x01\x08\x38\x75\x5f\x67\x6f\x6f\x64\x33\x00\x02\x08\x38\x75\x5f\x67\x6f\x6f\x64\x34\x00\x03\x08\x38\x75\x5f\x67\x6f\x6f\x64\x35\x00\x04\x08\x38\x73\x5f\x67\x6f\x6f\x64\x31\x00\x05\x08\x38\x73\x5f\x67\x6f\x6f\x64\x32\x00\x06\x08\x38\x73\x5f\x67\x6f\x6f\x64\x33\x00\x07\x08\x38\x73\x5f\x67\x6f\x6f\x64\x34\x00\x08\x08\x38\x73\x5f\x67\x6f\x6f\x64\x35\x00\x09\x09\x31\x36\x75\x5f\x67\x6f\x6f\x64\x31\x00\x0a\x09\x31\x36\x75\x5f\x67\x6f\x6f\x64\x32\x00\x0b\x09\x31\x36\x75\x5f\x67\x6f\x6f\x64\x33\x00\x0c\x09\x31\x36\x75\x5f\x67\x6f\x6f\x64\x34\x00\x0d\x09\x31\x36\x75\x5f\x67\x6f\x6f\x64\x35\x00\x0e\x09\x31\x36\x73\x5f\x67\x6f\x6f\x64\x31\x00\x0f\x09\x31\x36\x73\x5f\x67\x6f\x6f\x64\x32\x00\x10\x09\x31\x36\x73\x5f\x67\x6f\x6f\x64\x33\x00\x11\x09\x31\x36\x73\x5f\x67\x6f\x6f\x64\x34\x00\x12\x09\x31\x36\x73\x5f\x67\x6f\x6f\x64\x35\x00\x13\x08\x33\x32\x5f\x67\x6f\x6f\x64\x31\x00\x14\x08\x33\x32\x5f\x67\x6f\x6f\x64\x32\x00\x15\x08\x33\x32\x5f\x67\x6f\x6f\x64\x33\x00\x16\x08\x33\x32\x5f\x67\x6f\x6f\x64\x34\x00\x17\x08\x33\x32\x5f\x67\x6f\x6f\x64\x35\x00\x18\x06\x38\x75\x5f\x62\x61\x64\x00\x19\x06\x38\x73\x5f\x62\x61\x64\x00\x1a\x07\x31\x36\x75\x5f\x62\x61\x64\x00\x1b\x07\x31\x36\x73\x5f\x62\x61\x64\x00\x1c\x06\x33\x32\x5f\x62\x61\x64\x00\x1d\x0a\x82\x83\x80\x80\x00\x1e\x87\x80\x80\x80\x00\x00\x20\x00\x2d\x00\x00\x0b\x87\x80\x80\x80\x00\x00\x20\x00\x2d\x00\x00\x0b\x87\x80\x80\x80\x00\x00\x20\x00\x2d\x00\x01\x0b\x87\x80\x80\x80\x00\x00\x20\x00\x2d\x00\x02\x0b\x87\x80\x80\x80\x00\x00\x20\x00\x2d\x00\x19\x0b\x87\x80\x80\x80\x00\x00\x20\x00\x2c\x00\x00\x0b\x87\x80\x80\x80\x00\x00\x20\x00\x2c\x00\x00\x0b\x87\x80\x80\x80\x00\x00\x20\x00\x2c\x00\x01\x0b\x87\x80\x80\x80\x00\x00\x20\x00\x2c\x00\x02\x0b\x87\x80\x80\x80\x00\x00\x20\x00\x2c\x00\x19\x0b\x87\x80\x80\x80\x00\x00\x20\x00\x2f\x01\x00\x0b\x87\x80\x80\x80\x00\x00\x20\x00\x2f\x00\x00\x0b\x87\x80\x80\x80\x00\x00\x20\x00\x2f\x00\x01\x0b\x87\x80\x80\x80\x00\x00\x20\x00\x2f\x01\x02\x0b\x87\x80\x80\x80\x00\x00\x20\x00\x2f\x01\x19\x0b\x87\x80\x80\x80\x00\x00\x20\x00\x2e\x01\x00\x0b\x87\x80\x80\x80\x00\x00\x20\x00\x2e\x00\x00\x0b\x87\x80\x80\x80\x00\x00\x20\x00\x2e\x00\x01\x0b\x87\x80\x80\x80\x00\x00\x20\x00\x2e\x01\x02\x0b\x87\x80\x80\x80\x00\x00\x20\x00\x2e\x01\x19\x0b\x87\x80\x80\x80\x00\x00\x20\x00\x28\x02\x00\x0b\x87\x80\x80\x80\x00\x00\x20\x00\x28\x00\x00\x0b\x87\x80\x80\x80\x00\x00\x20\x00\x28\x00\x01\x0b\x87\x80\x80\x80\x00\x00\x20\x00\x28\x01\x02\x0b\x87\x80\x80\x80\x00\x00\x20\x00\x28\x02\x19\x0b\x8c\x80\x80\x80\x00\x00\x20\x00\x2d\x00\xff\xff\xff\xff\x0f\x1a\x0b\x8c\x80\x80\x80\x00\x00\x20\x00\x2c\x00\xff\xff\xff\xff\x0f\x1a\x0b\x8c\x80\x80\x80\x00\x00\x20\x00\x2f\x01\xff\xff\xff\xff\x0f\x1a\x0b\x8c\x80\x80\x80\x00\x00\x20\x00\x2e\x01\xff\xff\xff\xff\x0f\x1a\x0b\x8c\x80\x80\x80\x00\x00\x20\x00\x28\x02\xff\xff\xff\xff\x0f\x1a\x0b\x0b\xa0\x80\x80\x80\x00\x01\x00\x41\x00\x0b\x1a\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a");
 
 // address.wast:104
 assert_return(() => call($1, "8u_good1", [0]), 97);
 
 // address.wast:105
--- a/js/src/jit-test/tests/wasm/spec/call_indirect.wast.js
+++ b/js/src/jit-test/tests/wasm/spec/call_indirect.wast.js
@@ -1,10 +1,8 @@
-// |jit-test| skip-if: getBuildConfiguration()['arm']
-// skip due to bug 1517351
 
 // call_indirect.wast:3
 let $1 = instance("\x00\x61\x73\x6d\x01\x00\x00\x00\x01\xfb\x80\x80\x80\x00\x18\x60\x00\x00\x60\x00\x01\x7f\x60\x00\x01\x7e\x60\x00\x01\x7d\x60\x00\x01\x7c\x60\x01\x7f\x01\x7f\x60\x01\x7e\x01\x7e\x60\x01\x7d\x01\x7d\x60\x01\x7c\x01\x7c\x60\x02\x7d\x7f\x01\x7f\x60\x02\x7f\x7e\x01\x7e\x60\x02\x7c\x7d\x01\x7d\x60\x02\x7e\x7c\x01\x7c\x60\x01\x7f\x01\x7f\x60\x01\x7e\x01\x7e\x60\x01\x7d\x01\x7d\x60\x01\x7c\x01\x7c\x60\x04\x7e\x7c\x7f\x7e\x01\x7f\x60\x01\x7e\x01\x7f\x60\x04\x7e\x7c\x7f\x7e\x00\x60\x01\x7e\x00\x60\x01\x7f\x01\x7e\x60\x01\x7f\x01\x7d\x60\x01\x7f\x01\x7c\x03\xca\x80\x80\x80\x00\x49\x01\x02\x03\x04\x05\x06\x07\x08\x0a\x0c\x09\x0b\x0d\x0e\x0f\x10\x00\x01\x02\x03\x04\x02\x01\x02\x03\x04\x01\x02\x03\x04\x0a\x15\x05\x16\x17\x06\x06\x05\x07\x08\x05\x07\x08\x05\x05\x00\x00\x00\x01\x01\x01\x01\x02\x01\x03\x01\x00\x00\x01\x01\x00\x03\x04\x04\x04\x01\x03\x01\x01\x01\x01\x01\x02\x04\x85\x80\x80\x80\x00\x01\x70\x01\x1d\x1d\x05\x83\x80\x80\x80\x00\x01\x00\x01\x06\x8d\x80\x80\x80\x00\x01\x7c\x01\x44\x00\x00\x00\x00\x00\x00\x24\x40\x0b\x07\xfc\x86\x80\x80\x00\x37\x08\x74\x79\x70\x65\x2d\x69\x33\x32\x00\x11\x08\x74\x79\x70\x65\x2d\x69\x36\x34\x00\x12\x08\x74\x79\x70\x65\x2d\x66\x33\x32\x00\x13\x08\x74\x79\x70\x65\x2d\x66\x36\x34\x00\x14\x0a\x74\x79\x70\x65\x2d\x69\x6e\x64\x65\x78\x00\x15\x0e\x74\x79\x70\x65\x2d\x66\x69\x72\x73\x74\x2d\x69\x33\x32\x00\x16\x0e\x74\x79\x70\x65\x2d\x66\x69\x72\x73\x74\x2d\x69\x36\x34\x00\x17\x0e\x74\x79\x70\x65\x2d\x66\x69\x72\x73\x74\x2d\x66\x33\x32\x00\x18\x0e\x74\x79\x70\x65\x2d\x66\x69\x72\x73\x74\x2d\x66\x36\x34\x00\x19\x0f\x74\x79\x70\x65\x2d\x73\x65\x63\x6f\x6e\x64\x2d\x69\x33\x32\x00\x1a\x0f\x74\x79\x70\x65\x2d\x73\x65\x63\x6f\x6e\x64\x2d\x69\x36\x34\x00\x1b\x0f\x74\x79\x70\x65\x2d\x73\x65\x63\x6f\x6e\x64\x2d\x66\x33\x32\x00\x1c\x0f\x74\x79\x70\x65\x2d\x73\x65\x63\x6f\x6e\x64\x2d\x66\x36\x34\x00\x1d\x08\x64\x69\x73\x70\x61\x74\x63\x68\x00\x1e\x17\x64\x69\x73\x70\x61\x74\x63\x68\x2d\x73\x74\x72\x75\x63\x74\x75\x72\x61\x6c\x2d\x69\x36\x34\x00\x1f\x17\x64\x69\x73\x70\x61\x74\x63\x68\x2d\x73\x74\x72\x75\x63\x74\x75\x72\x61\x6c\x2d\x69\x33\x32\x00\x20\x17\x64\x69\x73\x70\x61\x74\x63\x68\x2d\x73\x74\x72\x75\x63\x74\x75\x72\x61\x6c\x2d\x66\x33\x32\x00\x21\x17\x64\x69\x73\x70\x61\x74\x63\x68\x2d\x73\x74\x72\x75\x63\x74\x75\x72\x61\x6c\x2d\x66\x36\x34\x00\x22\x07\x66\x61\x63\x2d\x69\x36\x34\x00\x23\x07\x66\x69\x62\x2d\x69\x36\x34\x00\x24\x07\x66\x61\x63\x2d\x69\x33\x32\x00\x25\x07\x66\x61\x63\x2d\x66\x33\x32\x00\x26\x07\x66\x61\x63\x2d\x66\x36\x34\x00\x27\x07\x66\x69\x62\x2d\x69\x33\x32\x00\x28\x07\x66\x69\x62\x2d\x66\x33\x32\x00\x29\x07\x66\x69\x62\x2d\x66\x36\x34\x00\x2a\x04\x65\x76\x65\x6e\x00\x2b\x03\x6f\x64\x64\x00\x2c\x07\x72\x75\x6e\x61\x77\x61\x79\x00\x2d\x0e\x6d\x75\x74\x75\x61\x6c\x2d\x72\x75\x6e\x61\x77\x61\x79\x00\x2e\x0f\x61\x73\x2d\x73\x65\x6c\x65\x63\x74\x2d\x66\x69\x72\x73\x74\x00\x30\x0d\x61\x73\x2d\x73\x65\x6c\x65\x63\x74\x2d\x6d\x69\x64\x00\x31\x0e\x61\x73\x2d\x73\x65\x6c\x65\x63\x74\x2d\x6c\x61\x73\x74\x00\x32\x0f\x61\x73\x2d\x69\x66\x2d\x63\x6f\x6e\x64\x69\x74\x69\x6f\x6e\x00\x33\x0e\x61\x73\x2d\x62\x72\x5f\x69\x66\x2d\x66\x69\x72\x73\x74\x00\x34\x0d\x61\x73\x2d\x62\x72\x5f\x69\x66\x2d\x6c\x61\x73\x74\x00\x35\x11\x61\x73\x2d\x62\x72\x5f\x74\x61\x62\x6c\x65\x2d\x66\x69\x72\x73\x74\x00\x36\x10\x61\x73\x2d\x62\x72\x5f\x74\x61\x62\x6c\x65\x2d\x6c\x61\x73\x74\x00\x37\x0e\x61\x73\x2d\x73\x74\x6f\x72\x65\x2d\x66\x69\x72\x73\x74\x00\x38\x0d\x61\x73\x2d\x73\x74\x6f\x72\x65\x2d\x6c\x61\x73\x74\x00\x39\x14\x61\x73\x2d\x6d\x65\x6d\x6f\x72\x79\x2e\x67\x72\x6f\x77\x2d\x76\x61\x6c\x75\x65\x00\x3a\x0f\x61\x73\x2d\x72\x65\x74\x75\x72\x6e\x2d\x76\x61\x6c\x75\x65\x00\x3b\x0f\x61\x73\x2d\x64\x72\x6f\x70\x2d\x6f\x70\x65\x72\x61\x6e\x64\x00\x3c\x0b\x61\x73\x2d\x62\x72\x2d\x76\x61\x6c\x75\x65\x00\x3d\x12\x61\x73\x2d\x6c\x6f\x63\x61\x6c\x2e\x73\x65\x74\x2d\x76\x61\x6c\x75\x65\x00\x3e\x12\x61\x73\x2d\x6c\x6f\x63\x61\x6c\x2e\x74\x65\x65\x2d\x76\x61\x6c\x75\x65\x00\x3f\x13\x61\x73\x2d\x67\x6c\x6f\x62\x61\x6c\x2e\x73\x65\x74\x2d\x76\x61\x6c\x75\x65\x00\x40\x0f\x61\x73\x2d\x6c\x6f\x61\x64\x2d\x6f\x70\x65\x72\x61\x6e\x64\x00\x41\x10\x61\x73\x2d\x75\x6e\x61\x72\x79\x2d\x6f\x70\x65\x72\x61\x6e\x64\x00\x42\x0e\x61\x73\x2d\x62\x69\x6e\x61\x72\x79\x2d\x6c\x65\x66\x74\x00\x43\x0f\x61\x73\x2d\x62\x69\x6e\x61\x72\x79\x2d\x72\x69\x67\x68\x74\x00\x44\x0f\x61\x73\x2d\x74\x65\x73\x74\x2d\x6f\x70\x65\x72\x61\x6e\x64\x00\x45\x0f\x61\x73\x2d\x63\x6f\x6d\x70\x61\x72\x65\x2d\x6c\x65\x66\x74\x00\x46\x10\x61\x73\x2d\x63\x6f\x6d\x70\x61\x72\x65\x2d\x72\x69\x67\x68\x74\x00\x47\x12\x61\x73\x2d\x63\x6f\x6e\x76\x65\x72\x74\x2d\x6f\x70\x65\x72\x61\x6e\x64\x00\x48\x09\xa3\x80\x80\x80\x00\x01\x00\x41\x00\x0b\x1d\x00\x01\x02\x03\x04\x05\x06\x07\x0a\x08\x0b\x09\x23\x24\x2b\x2c\x2d\x2e\x2f\x0c\x0d\x0e\x0f\x25\x26\x27\x28\x29\x2a\x0a\xba\x8b\x80\x80\x00\x49\x85\x80\x80\x80\x00\x00\x41\xb2\x02\x0b\x85\x80\x80\x80\x00\x00\x42\xe4\x02\x0b\x87\x80\x80\x80\x00\x00\x43\x00\x20\x73\x45\x0b\x8b\x80\x80\x80\x00\x00\x44\x00\x00\x00\x00\x00\xc8\xae\x40\x0b\x84\x80\x80\x80\x00\x00\x20\x00\x0b\x84\x80\x80\x80\x00\x00\x20\x00\x0b\x84\x80\x80\x80\x00\x00\x20\x00\x0b\x84\x80\x80\x80\x00\x00\x20\x00\x0b\x84\x80\x80\x80\x00\x00\x20\x01\x0b\x84\x80\x80\x80\x00\x00\x20\x01\x0b\x84\x80\x80\x80\x00\x00\x20\x01\x0b\x84\x80\x80\x80\x00\x00\x20\x01\x0b\x84\x80\x80\x80\x00\x00\x20\x00\x0b\x84\x80\x80\x80\x00\x00\x20\x00\x0b\x84\x80\x80\x80\x00\x00\x20\x00\x0b\x84\x80\x80\x80\x00\x00\x20\x00\x0b\xdd\x80\x80\x80\x00\x00\x41\x00\x11\x00\x00\x42\x00\x41\x00\x11\x14\x00\x42\x00\x44\x00\x00\x00\x00\x00\x00\x00\x00\x41\x00\x42\x00\x41\x00\x11\x13\x00\x41\x00\x11\x00\x00\x41\x00\x11\x01\x00\x45\x1a\x41\x00\x11\x01\x00\x45\x1a\x42\x00\x41\x00\x11\x12\x00\x45\x1a\x42\x00\x44\x00\x00\x00\x00\x00\x00\x00\x00\x41\x00\x42\x00\x41\x00\x11\x11\x00\x45\x1a\x42\x00\x41\x00\x11\x06\x00\x50\x1a\x0b\x87\x80\x80\x80\x00\x00\x41\x00\x11\x01\x00\x0b\x87\x80\x80\x80\x00\x00\x41\x01\x11\x02\x00\x0b\x87\x80\x80\x80\x00\x00\x41\x02\x11\x03\x00\x0b\x87\x80\x80\x80\x00\x00\x41\x03\x11\x04\x00\x0b\x8a\x80\x80\x80\x00\x00\x42\xe4\x00\x41\x05\x11\x06\x00\x0b\x89\x80\x80\x80\x00\x00\x41\x20\x41\x04\x11\x05\x00\x0b\x8a\x80\x80\x80\x00\x00\x42\xc0\x00\x41\x05\x11\x06\x00\x0b\x8c\x80\x80\x80\x00\x00\x43\xc3\xf5\xa8\x3f\x41\x06\x11\x07\x00\x0b\x90\x80\x80\x80\x00\x00\x44\x3d\x0a\xd7\xa3\x70\x3d\xfa\x3f\x41\x07\x11\x08\x00\x0b\x8e\x80\x80\x80\x00\x00\x43\x66\x66\x00\x42\x41\x20\x41\x08\x11\x09\x00\x0b\x8c\x80\x80\x80\x00\x00\x41\x20\x42\xc0\x00\x41\x09\x11\x0a\x00\x0b\x95\x80\x80\x80\x00\x00\x44\x00\x00\x00\x00\x00\x00\x50\x40\x43\x00\x00\x00\x42\x41\x0a\x11\x0b\x00\x0b\x93\x80\x80\x80\x00\x00\x42\xc0\x00\x44\x66\x66\x66\x66\x66\x06\x50\x40\x41\x0b\x11\x0c\x00\x0b\x89\x80\x80\x80\x00\x00\x20\x01\x20\x00\x11\x06\x00\x0b\x89\x80\x80\x80\x00\x00\x42\x09\x20\x00\x11\x0e\x00\x0b\x89\x80\x80\x80\x00\x00\x41\x09\x20\x00\x11\x0d\x00\x0b\x8c\x80\x80\x80\x00\x00\x43\x00\x00\x10\x41\x20\x00\x11\x0f\x00\x0b\x90\x80\x80\x80\x00\x00\x44\x00\x00\x00\x00\x00\x00\x22\x40\x20\x00\x11\x10\x00\x0b\x98\x80\x80\x80\x00\x00\x20\x00\x50\x04\x7e\x42\x01\x05\x20\x00\x20\x00\x42\x01\x7d\x41\x0c\x11\x06\x00\x7e\x0b\x0b\xa2\x80\x80\x80\x00\x00\x20\x00\x42\x01\x58\x04\x7e\x42\x01\x05\x20\x00\x42\x02\x7d\x41\x0d\x11\x06\x00\x20\x00\x42\x01\x7d\x41\x0d\x11\x06\x00\x7c\x0b\x0b\x98\x80\x80\x80\x00\x00\x20\x00\x45\x04\x7f\x41\x01\x05\x20\x00\x20\x00\x41\x01\x6b\x41\x17\x11\x05\x00\x6c\x0b\x0b\xa3\x80\x80\x80\x00\x00\x20\x00\x43\x00\x00\x00\x00\x5b\x04\x7d\x43\x00\x00\x80\x3f\x05\x20\x00\x20\x00\x43\x00\x00\x80\x3f\x93\x41\x18\x11\x07\x00\x94\x0b\x0b\xaf\x80\x80\x80\x00\x00\x20\x00\x44\x00\x00\x00\x00\x00\x00\x00\x00\x61\x04\x7c\x44\x00\x00\x00\x00\x00\x00\xf0\x3f\x05\x20\x00\x20\x00\x44\x00\x00\x00\x00\x00\x00\xf0\x3f\xa1\x41\x19\x11\x08\x00\xa2\x0b\x0b\xa2\x80\x80\x80\x00\x00\x20\x00\x41\x01\x4d\x04\x7f\x41\x01\x05\x20\x00\x41\x02\x6b\x41\x1a\x11\x05\x00\x20\x00\x41\x01\x6b\x41\x1a\x11\x05\x00\x6a\x0b\x0b\xae\x80\x80\x80\x00\x00\x20\x00\x43\x00\x00\x80\x3f\x5f\x04\x7d\x43\x00\x00\x80\x3f\x05\x20\x00\x43\x00\x00\x00\x40\x93\x41\x1b\x11\x07\x00\x20\x00\x43\x00\x00\x80\x3f\x93\x41\x1b\x11\x07\x00\x92\x0b\x0b\xbe\x80\x80\x80\x00\x00\x20\x00\x44\x00\x00\x00\x00\x00\x00\xf0\x3f\x65\x04\x7c\x44\x00\x00\x00\x00\x00\x00\xf0\x3f\x05\x20\x00\x44\x00\x00\x00\x00\x00\x00\x00\x40\xa1\x41\x1c\x11\x08\x00\x20\x00\x44\x00\x00\x00\x00\x00\x00\xf0\x3f\xa1\x41\x1c\x11\x08\x00\xa0\x0b\x0b\x95\x80\x80\x80\x00\x00\x20\x00\x45\x04\x7f\x41\x2c\x05\x20\x00\x41\x01\x6b\x41\x0f\x11\x05\x00\x0b\x0b\x96\x80\x80\x80\x00\x00\x20\x00\x45\x04\x7f\x41\xe3\x00\x05\x20\x00\x41\x01\x6b\x41\x0e\x11\x05\x00\x0b\x0b\x87\x80\x80\x80\x00\x00\x41\x10\x11\x00\x00\x0b\x87\x80\x80\x80\x00\x00\x41\x12\x11\x00\x00\x0b\x87\x80\x80\x80\x00\x00\x41\x11\x11\x00\x00\x0b\x8c\x80\x80\x80\x00\x00\x41\x00\x11\x01\x00\x41\x02\x41\x03\x1b\x0b\x8c\x80\x80\x80\x00\x00\x41\x02\x41\x00\x11\x01\x00\x41\x03\x1b\x0b\x8c\x80\x80\x80\x00\x00\x41\x02\x41\x03\x41\x00\x11\x01\x00\x1b\x0b\x8f\x80\x80\x80\x00\x00\x41\x00\x11\x01\x00\x04\x7f\x41\x01\x05\x41\x02\x0b\x0b\x8e\x80\x80\x80\x00\x00\x02\x7e\x41\x01\x11\x02\x00\x41\x02\x0d\x00\x0b\x0b\x8e\x80\x80\x80\x00\x00\x02\x7f\x41\x02\x41\x00\x11\x01\x00\x0d\x00\x0b\x0b\x90\x80\x80\x80\x00\x00\x02\x7d\x41\x02\x11\x03\x00\x41\x02\x0e\x01\x00\x00\x0b\x0b\x90\x80\x80\x80\x00\x00\x02\x7f\x41\x02\x41\x00\x11\x01\x00\x0e\x01\x00\x00\x0b\x0b\x8c\x80\x80\x80\x00\x00\x41\x00\x11\x01\x00\x41\x01\x36\x02\x00\x0b\x8c\x80\x80\x80\x00\x00\x41\x0a\x41\x03\x11\x04\x00\x39\x03\x00\x0b\x89\x80\x80\x80\x00\x00\x41\x00\x11\x01\x00\x40\x00\x0b\x8a\x80\x80\x80\x00\x00\x41\x01\x41\x04\x11\x05\x00\x0f\x0b\x8a\x80\x80\x80\x00\x00\x42\x01\x41\x05\x11\x06\x00\x1a\x0b\x91\x80\x80\x80\x00\x00\x02\x7d\x43\x00\x00\x80\x3f\x41\x06\x11\x07\x00\x0c\x00\x0b\x0b\x96\x80\x80\x80\x00\x01\x01\x7c\x44\x00\x00\x00\x00\x00\x00\xf0\x3f\x41\x07\x11\x08\x00\x21\x00\x20\x00\x0b\x94\x80\x80\x80\x00\x01\x01\x7c\x44\x00\x00\x00\x00\x00\x00\xf0\x3f\x41\x07\x11\x08\x00\x22\x00\x0b\x94\x80\x80\x80\x00\x00\x44\x00\x00\x00\x00\x00\x00\xf0\x3f\x41\x07\x11\x08\x00\x24\x00\x23\x00\x0b\x8a\x80\x80\x80\x00\x00\x41\x00\x11\x01\x00\x28\x02\x00\x0b\x90\x80\x80\x80\x00\x00\x02\x7d\x43\x00\x00\x00\x00\x41\x06\x11\x07\x00\x91\x0b\x0b\x8f\x80\x80\x80\x00\x00\x02\x7f\x41\x01\x41\x04\x11\x05\x00\x41\x0a\x6a\x0b\x0b\x8f\x80\x80\x80\x00\x00\x02\x7f\x41\x0a\x41\x01\x41\x04\x11\x05\x00\x6b\x0b\x0b\x8d\x80\x80\x80\x00\x00\x02\x7f\x41\x01\x41\x04\x11\x05\x00\x45\x0b\x0b\x8f\x80\x80\x80\x00\x00\x02\x7f\x41\x01\x41\x04\x11\x05\x00\x41\x0a\x4d\x0b\x0b\x8f\x80\x80\x80\x00\x00\x02\x7f\x41\x0a\x41\x01\x41\x04\x11\x05\x00\x47\x0b\x0b\x8d\x80\x80\x80\x00\x00\x02\x7e\x41\x01\x41\x04\x11\x05\x00\xac\x0b\x0b");
 
 // call_indirect.wast:447
 assert_return(() => call($1, "type-i32", []), 306);
 
 // call_indirect.wast:448
--- a/js/src/jit-test/tests/wasm/spec/float_memory.wast.js
+++ b/js/src/jit-test/tests/wasm/spec/float_memory.wast.js
@@ -1,10 +1,8 @@
-// |jit-test| skip-if: getBuildConfiguration()['arm']
-// skip arm7 due to bug 1513231
 
 // float_memory.wast:5
 let $1 = instance("\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x8c\x80\x80\x80\x00\x03\x60\x00\x01\x7d\x60\x00\x01\x7f\x60\x00\x00\x03\x86\x80\x80\x80\x00\x05\x00\x01\x02\x02\x02\x05\x84\x80\x80\x80\x00\x01\x01\x01\x01\x07\xb7\x80\x80\x80\x00\x05\x08\x66\x33\x32\x2e\x6c\x6f\x61\x64\x00\x00\x08\x69\x33\x32\x2e\x6c\x6f\x61\x64\x00\x01\x09\x66\x33\x32\x2e\x73\x74\x6f\x72\x65\x00\x02\x09\x69\x33\x32\x2e\x73\x74\x6f\x72\x65\x00\x03\x05\x72\x65\x73\x65\x74\x00\x04\x0a\xca\x80\x80\x80\x00\x05\x87\x80\x80\x80\x00\x00\x41\x00\x2a\x02\x00\x0b\x87\x80\x80\x80\x00\x00\x41\x00\x28\x02\x00\x0b\x8c\x80\x80\x80\x00\x00\x41\x00\x43\x00\x00\xa0\x7f\x38\x02\x00\x0b\x8d\x80\x80\x80\x00\x00\x41\x00\x41\x80\x80\x80\xfd\x07\x36\x02\x00\x0b\x89\x80\x80\x80\x00\x00\x41\x00\x41\x00\x36\x02\x00\x0b\x0b\x8a\x80\x80\x80\x00\x01\x00\x41\x00\x0b\x04\x00\x00\xa0\x7f");
 
 // float_memory.wast:15
 assert_return(() => call($1, "i32.load", []), 2141192192);
 
 // float_memory.wast:16
--- a/js/src/jit-test/tests/wasm/spec/memory_redundancy.wast.js
+++ b/js/src/jit-test/tests/wasm/spec/memory_redundancy.wast.js
@@ -1,10 +1,8 @@
-// |jit-test| skip-if: getBuildConfiguration()['arm']
-// skip arm7 due to bug 1513231
 
 // memory_redundancy.wast:5
 let $1 = instance("\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x91\x80\x80\x80\x00\x04\x60\x00\x00\x60\x00\x01\x7f\x60\x00\x01\x7d\x60\x01\x7f\x01\x7f\x03\x87\x80\x80\x80\x00\x06\x00\x01\x01\x02\x03\x01\x05\x84\x80\x80\x80\x00\x01\x01\x01\x01\x07\xeb\x80\x80\x80\x00\x06\x0f\x7a\x65\x72\x6f\x5f\x65\x76\x65\x72\x79\x74\x68\x69\x6e\x67\x00\x00\x12\x74\x65\x73\x74\x5f\x73\x74\x6f\x72\x65\x5f\x74\x6f\x5f\x6c\x6f\x61\x64\x00\x01\x13\x74\x65\x73\x74\x5f\x72\x65\x64\x75\x6e\x64\x61\x6e\x74\x5f\x6c\x6f\x61\x64\x00\x02\x0f\x74\x65\x73\x74\x5f\x64\x65\x61\x64\x5f\x73\x74\x6f\x72\x65\x00\x03\x06\x6d\x61\x6c\x6c\x6f\x63\x00\x04\x0f\x6d\x61\x6c\x6c\x6f\x63\x5f\x61\x6c\x69\x61\x73\x69\x6e\x67\x00\x05\x0a\xbd\x81\x80\x80\x00\x06\x9e\x80\x80\x80\x00\x00\x41\x00\x41\x00\x36\x02\x00\x41\x04\x41\x00\x36\x02\x00\x41\x08\x41\x00\x36\x02\x00\x41\x0c\x41\x00\x36\x02\x00\x0b\x98\x80\x80\x80\x00\x00\x41\x08\x41\x00\x36\x02\x00\x41\x05\x43\x00\x00\x00\x80\x38\x02\x00\x41\x08\x28\x02\x00\x0b\xa2\x80\x80\x80\x00\x01\x02\x7f\x41\x08\x28\x02\x00\x21\x00\x41\x05\x41\x80\x80\x80\x80\x78\x36\x02\x00\x41\x08\x28\x02\x00\x21\x01\x20\x00\x20\x01\x6a\x0b\x9f\x80\x80\x80\x00\x01\x01\x7d\x41\x08\x41\xa3\xc6\x8c\x99\x02\x36\x02\x00\x41\x0b\x2a\x02\x00\x21\x00\x41\x08\x41\x00\x36\x02\x00\x20\x00\x0b\x84\x80\x80\x80\x00\x00\x41\x10\x0b\xa3\x80\x80\x80\x00\x01\x02\x7f\x41\x04\x10\x04\x21\x00\x41\x04\x10\x04\x21\x01\x20\x00\x41\x2a\x36\x02\x00\x20\x01\x41\x2b\x36\x02\x00\x20\x00\x28\x02\x00\x0b");
 
 // memory_redundancy.wast:59
 assert_return(() => call($1, "test_store_to_load", []), 128);
 
 // memory_redundancy.wast:60
--- a/js/src/jit/arm/MacroAssembler-arm.cpp
+++ b/js/src/jit/arm/MacroAssembler-arm.cpp
@@ -5902,16 +5902,18 @@ void MacroAssemblerARM::wasmLoadImpl(con
     }
   } else {
     bool isFloat = output.isFloat();
     if (isFloat) {
       MOZ_ASSERT((byteSize == 4) == output.fpu().isSingle());
       ScratchRegisterScope scratch(asMasm());
       ma_add(memoryBase, ptr, scratch);
 
+      // See HandleUnalignedTrap() in WasmSignalHandler.cpp.  We depend on this
+      // being a single, unconditional VLDR with a base pointer other than PC.
       load = ma_vldr(Operand(Address(scratch, 0)).toVFPAddr(), output.fpu());
       append(access, load.getOffset());
     } else {
       load = ma_dataTransferN(IsLoad, byteSize * 8, isSigned, memoryBase, ptr,
                               output.gpr());
       append(access, load.getOffset());
     }
   }
@@ -5956,16 +5958,18 @@ void MacroAssemblerARM::wasmStoreImpl(co
     append(access, store.getOffset());
   } else {
     if (value.isFloat()) {
       ScratchRegisterScope scratch(asMasm());
       FloatRegister val = value.fpu();
       MOZ_ASSERT((byteSize == 4) == val.isSingle());
       ma_add(memoryBase, ptr, scratch);
 
+      // See HandleUnalignedTrap() in WasmSignalHandler.cpp.  We depend on this
+      // being a single, unconditional VLDR with a base pointer other than PC.
       store = ma_vstr(val, Operand(Address(scratch, 0)).toVFPAddr());
       append(access, store.getOffset());
     } else {
       bool isSigned = type == Scalar::Uint32 ||
                       type == Scalar::Int32;  // see AsmJSStoreHeap;
       Register val = value.gpr();
 
       store = ma_dataTransferN(IsStore, 8 * byteSize /* bits */, isSigned,
--- a/js/src/wasm/WasmInstance.cpp
+++ b/js/src/wasm/WasmInstance.cpp
@@ -1138,16 +1138,46 @@ bool Instance::memoryAccessInGuardRegion
     return false;
   }
 
   size_t lastByteOffset = addr - base + (numBytes - 1);
   return lastByteOffset >= memory()->volatileMemoryLength() &&
          lastByteOffset < memoryMappedSize();
 }
 
+bool Instance::memoryAccessInBounds(uint8_t* addr,
+                                    unsigned numBytes) const {
+  MOZ_ASSERT(numBytes > 0 && numBytes <= sizeof(double));
+
+  if (!metadata().usesMemory()) {
+    return false;
+  }
+
+  uint8_t* base = memoryBase().unwrap(/* comparison */);
+  if (addr < base) {
+    return false;
+  }
+
+  uint32_t length = memory()->volatileMemoryLength();
+  if (addr >= base + length) {
+    return false;
+  }
+
+  // The pointer points into the memory.  Now check for partial OOB.
+  //
+  // This calculation can't wrap around because the access is small and there
+  // always is a guard page following the memory.
+  size_t lastByteOffset = addr - base + (numBytes - 1);
+  if (lastByteOffset >= length) {
+    return false;
+  }
+
+  return true;
+}
+
 void Instance::tracePrivate(JSTracer* trc) {
   // This method is only called from WasmInstanceObject so the only reason why
   // TraceEdge is called is so that the pointer can be updated during a moving
   // GC. TraceWeakEdge may sound better, but it is less efficient given that
   // we know object_ is already marked.
   MOZ_ASSERT(!gc::IsAboutToBeFinalized(&object_));
   TraceEdge(trc, &object_, "wasm instance object");
 
--- a/js/src/wasm/WasmInstance.h
+++ b/js/src/wasm/WasmInstance.h
@@ -108,16 +108,17 @@ class Instance {
   const Metadata& metadata() const { return code_->metadata(); }
   bool isAsmJS() const { return metadata().isAsmJS(); }
   const SharedTableVector& tables() const { return tables_; }
   SharedMem<uint8_t*> memoryBase() const;
   WasmMemoryObject* memory() const;
   size_t memoryMappedSize() const;
   SharedArrayRawBuffer* sharedMemoryBuffer() const;  // never null
   bool memoryAccessInGuardRegion(uint8_t* addr, unsigned numBytes) const;
+  bool memoryAccessInBounds(uint8_t* addr, unsigned numBytes) const;
   const StructTypeVector& structTypes() const { return code_->structTypes(); }
 
   static constexpr size_t offsetOfJSJitArgsRectifier() {
     return offsetof(Instance, jsJitArgsRectifier_);
   }
   static constexpr size_t offsetOfJSJitExceptionHandler() {
     return offsetof(Instance, jsJitExceptionHandler_);
   }
--- a/js/src/wasm/WasmSignalHandlers.cpp
+++ b/js/src/wasm/WasmSignalHandlers.cpp
@@ -208,16 +208,20 @@ using mozilla::DebugOnly;
 #define R11_sig(p) ((p)->thread.__r[11])
 #define R13_sig(p) ((p)->thread.__sp)
 #define R14_sig(p) ((p)->thread.__lr)
 #define R15_sig(p) ((p)->thread.__pc)
 #else
 #error "Don't know how to read/write to the thread state via the mcontext_t."
 #endif
 
+#if defined(__linux__) && defined(__arm__)
+#include <sys/user.h>
+#endif
+
 #if defined(ANDROID)
 // Not all versions of the Android NDK define ucontext_t or mcontext_t.
 // Detect this and provide custom but compatible definitions. Note that these
 // follow the GLibc naming convention to access register values from
 // mcontext_t.
 //
 // See: https://chromiumcodereview.appspot.com/10829122/
 // See: http://code.google.com/p/android/issues/detail?id=34784
@@ -432,17 +436,207 @@ struct AutoHandlingTrap {
   }
 
   ~AutoHandlingTrap() {
     MOZ_ASSERT(sAlreadyHandlingTrap.get());
     sAlreadyHandlingTrap.set(false);
   }
 };
 
+#if defined(__linux__) && defined(__arm__)
+
+// Code to handle SIGBUS for unaligned floating point accesses on 32-bit ARM.
+
+static uintptr_t ReadGPR(CONTEXT* context, uint32_t rn) {
+  switch (rn) {
+    case 0: return context->uc_mcontext.arm_r0;
+    case 1: return context->uc_mcontext.arm_r1;
+    case 2: return context->uc_mcontext.arm_r2;
+    case 3: return context->uc_mcontext.arm_r3;
+    case 4: return context->uc_mcontext.arm_r4;
+    case 5: return context->uc_mcontext.arm_r5;
+    case 6: return context->uc_mcontext.arm_r6;
+    case 7: return context->uc_mcontext.arm_r7;
+    case 8: return context->uc_mcontext.arm_r8;
+    case 9: return context->uc_mcontext.arm_r9;
+    case 10: return context->uc_mcontext.arm_r10;
+    case 11: return context->uc_mcontext.arm_fp;
+    case 12: return context->uc_mcontext.arm_ip;
+    case 13: return context->uc_mcontext.arm_sp;
+    case 14: return context->uc_mcontext.arm_lr;
+    case 15: return context->uc_mcontext.arm_pc;
+    default: MOZ_CRASH();
+  }
+}
+
+// Linux kernel data structures.
+//
+// The vfp_sigframe is a kernel type overlaid on the uc_regspace field of the
+// ucontext_t if the first word of the uc_regspace is VFP_MAGIC.  (user_vfp and
+// user_vfp_exc are defined in sys/user.h and are stable.)
+//
+// VFP_MAGIC appears to have been stable since a commit to Linux on 2010-04-11,
+// when it was changed from being 0x56465001 on ARMv6 and earlier and 0x56465002
+// on ARMv7 and later, to being 0x56465001 on all CPU versions.  This was in
+// Kernel 2.6.34-rc5.
+//
+// My best interpretation of the Android commit history is that Android has had
+// vfp_sigframe and VFP_MAGIC in this form since at least Android 3.4 / 2012;
+// Firefox requires Android 4.0 at least and we're probably safe here.
+
+struct vfp_sigframe
+{
+  unsigned long       magic;
+  unsigned long       size;
+  struct user_vfp     ufp;
+  struct user_vfp_exc ufp_exc;
+};
+
+#define VFP_MAGIC 0x56465001
+
+static vfp_sigframe* GetVFPFrame(CONTEXT* context) {
+  if (context->uc_regspace[0] != VFP_MAGIC) {
+    return nullptr;
+  }
+  return (vfp_sigframe*)&context->uc_regspace;
+}
+
+static bool ReadFPR64(CONTEXT* context, uint32_t vd, double* val) {
+  MOZ_ASSERT(vd < 32);
+  vfp_sigframe* frame = GetVFPFrame(context);
+  if (frame) {
+    *val = ((double*)frame->ufp.fpregs)[vd];
+    return true;
+  }
+  return false;
+}
+
+static bool WriteFPR64(CONTEXT* context, uint32_t vd, double val) {
+  MOZ_ASSERT(vd < 32);
+  vfp_sigframe* frame = GetVFPFrame(context);
+  if (frame) {
+    ((double*)frame->ufp.fpregs)[vd] = val;
+    return true;
+  }
+  return false;
+}
+
+static bool ReadFPR32(CONTEXT* context, uint32_t vd, float* val) {
+  MOZ_ASSERT(vd < 32);
+  vfp_sigframe* frame = GetVFPFrame(context);
+  if (frame) {
+    *val = ((float*)frame->ufp.fpregs)[vd];
+    return true;
+  }
+  return false;
+}
+
+static bool WriteFPR32(CONTEXT* context, uint32_t vd, float val) {
+  MOZ_ASSERT(vd < 32);
+  vfp_sigframe* frame = GetVFPFrame(context);
+  if (frame) {
+    ((float*)frame->ufp.fpregs)[vd] = val;
+    return true;
+  }
+  return false;
+}
+
+static bool HandleUnalignedTrap(CONTEXT* context, uint8_t* pc,
+                                Instance* instance) {
+  // ARM only, no Thumb.
+  MOZ_RELEASE_ASSERT(uintptr_t(pc) % 4 == 0);
+
+  // wasmLoadImpl() and wasmStoreImpl() in MacroAssembler-arm.cpp emit plain,
+  // unconditional VLDR and VSTR instructions that do not use the PC as the base
+  // register.
+  uint32_t instr = *(uint32_t*)pc;
+  uint32_t masked = instr & 0x0F300E00;
+  bool isVLDR = masked == 0x0D100A00;
+  bool isVSTR = masked == 0x0D000A00;
+
+  if (!isVLDR && !isVSTR) {
+    // Three obvious cases if we don't get our expected instructions:
+    // - masm is generating other FP access instructions than it should
+    // - we're encountering a device that traps on new kinds of accesses,
+    //   perhaps unaligned integer accesses
+    // - general code generation bugs that lead to SIGBUS
+#  ifdef ANDROID
+    __android_log_print(ANDROID_LOG_ERROR, "WASM", "Bad SIGBUS instr %08x", instr);
+#  endif
+#  ifdef DEBUG
+    MOZ_CRASH("Unexpected instruction");
+#  endif
+    return false;
+  }
+
+  bool isUnconditional = (instr >> 28) == 0xE;
+  bool isDouble = (instr & 0x00000100) != 0;
+  bool isAdd = (instr & 0x00800000) != 0;
+  uint32_t dBit = (instr >> 22) & 1;
+  uint32_t offs = (instr & 0xFF) << 2;
+  uint32_t rn = (instr >> 16) & 0xF;
+
+  MOZ_RELEASE_ASSERT(isUnconditional);
+  MOZ_RELEASE_ASSERT(rn != 15);
+
+  uint8_t* p = (uint8_t*)ReadGPR(context, rn) + (isAdd ? offs : -offs);
+
+  if (!instance->memoryAccessInBounds(p, isDouble ? sizeof(double)
+                                                  : sizeof(float))) {
+    return false;
+  }
+
+  if (isDouble) {
+    uint32_t vd = ((instr >> 12) & 0xF) | (dBit << 4);
+    double val;
+    if (isVLDR) {
+      memcpy(&val, p, sizeof(val));
+      if (WriteFPR64(context, vd, val)) {
+        SetContextPC(context, pc + 4);
+        return true;
+      }
+    } else {
+      if (ReadFPR64(context, vd, &val)) {
+        memcpy(p, &val, sizeof(val));
+        SetContextPC(context, pc + 4);
+        return true;
+      }
+    }
+  } else {
+    uint32_t vd = ((instr >> 11) & (0xF << 1)) | dBit;
+    float val;
+    if (isVLDR) {
+      memcpy(&val, p, sizeof(val));
+      if (WriteFPR32(context, vd, val)) {
+        SetContextPC(context, pc + 4);
+        return true;
+      }
+    } else {
+      if (ReadFPR32(context, vd, &val)) {
+        memcpy(p, &val, sizeof(val));
+        SetContextPC(context, pc + 4);
+        return true;
+      }
+    }
+  }
+
+#ifdef DEBUG
+  MOZ_CRASH("SIGBUS handler could not access FP register, incompatible kernel?");
+#endif
+  return false;
+}
+#else // __linux__ && __arm__
+static bool HandleUnalignedTrap(CONTEXT* context, uint8_t* pc,
+                                Instance* instance) {
+  return false;
+}
+#endif // __linux__ && __arm__
+
 static MOZ_MUST_USE bool HandleTrap(CONTEXT* context,
+                                    bool isUnalignedSignal = false,
                                     JSContext* assertCx = nullptr) {
   MOZ_ASSERT(sAlreadyHandlingTrap.get());
 
   uint8_t* pc = ContextToPC(context);
   const CodeSegment* codeSegment = LookupCodeSegment(pc);
   if (!codeSegment || !codeSegment->isModule()) {
     return false;
   }
@@ -458,16 +652,26 @@ static MOZ_MUST_USE bool HandleTrap(CONT
   // We have a safe, expected wasm trap, so fp is well-defined to be a Frame*.
   // For the first sanity check, the Trap::IndirectCallBadSig special case is
   // due to this trap occurring in the indirect call prologue, while fp points
   // to the caller's Frame which can be in a different Module. In any case,
   // though, the containing JSContext is the same.
   Instance* instance = ((Frame*)ContextToFP(context))->tls->instance;
   MOZ_RELEASE_ASSERT(&instance->code() == &segment.code() ||
                      trap == Trap::IndirectCallBadSig);
+
+  if (isUnalignedSignal) {
+    if (trap != Trap::OutOfBounds) {
+      return false;
+    }
+    if (HandleUnalignedTrap(context, pc, instance)) {
+      return true;
+    }
+  }
+
   JSContext* cx =
       instance->realm()->runtimeFromAnyThread()->mainContextFromAnyThread();
   MOZ_RELEASE_ASSERT(!assertCx || cx == assertCx);
 
   // JitActivation::startWasmTrap() stores enough register state from the
   // point of the trap to allow stack unwinding or resumption, both of which
   // will call finishWasmTrap().
   jit::JitActivation* activation = cx->activation()->asJit();
@@ -498,17 +702,17 @@ static LONG WINAPI WasmTrapHandler(LPEXC
   AutoHandlingTrap aht;
 
   EXCEPTION_RECORD* record = exception->ExceptionRecord;
   if (record->ExceptionCode != EXCEPTION_ACCESS_VIOLATION &&
       record->ExceptionCode != EXCEPTION_ILLEGAL_INSTRUCTION) {
     return EXCEPTION_CONTINUE_SEARCH;
   }
 
-  if (!HandleTrap(exception->ContextRecord, TlsContext.get())) {
+  if (!HandleTrap(exception->ContextRecord, false, TlsContext.get())) {
     return EXCEPTION_CONTINUE_SEARCH;
   }
 
   return EXCEPTION_CONTINUE_EXECUTION;
 }
 
 #elif defined(XP_DARWIN)
 // On OSX we are forced to use the lower-level Mach exception mechanism instead
@@ -666,17 +870,17 @@ static struct sigaction sPrevSEGVHandler
 static struct sigaction sPrevSIGBUSHandler;
 static struct sigaction sPrevWasmTrapHandler;
 
 static void WasmTrapHandler(int signum, siginfo_t* info, void* context) {
   if (!sAlreadyHandlingTrap.get()) {
     AutoHandlingTrap aht;
     MOZ_RELEASE_ASSERT(signum == SIGSEGV || signum == SIGBUS ||
                        signum == kWasmTrapSignal);
-    if (HandleTrap((CONTEXT*)context, TlsContext.get())) {
+    if (HandleTrap((CONTEXT*)context, signum == SIGBUS, TlsContext.get())) {
       return;
     }
   }
 
   struct sigaction* previousSignal = nullptr;
   switch (signum) {
     case SIGSEGV:
       previousSignal = &sPrevSEGVHandler;
--- a/layout/forms/nsImageControlFrame.cpp
+++ b/layout/forms/nsImageControlFrame.cpp
@@ -150,18 +150,18 @@ nsresult nsImageControlFrame::HandleEven
 void nsImageControlFrame::SetFocus(bool aOn, bool aRepaint) {}
 
 nsresult nsImageControlFrame::GetCursor(const nsPoint& aPoint,
                                         nsIFrame::Cursor& aCursor) {
   // Use style defined cursor if one is provided, otherwise when
   // the cursor style is "auto" we use the pointer cursor.
   FillCursorInformationFromStyle(StyleUI(), aCursor);
 
-  if (NS_STYLE_CURSOR_AUTO == aCursor.mCursor) {
-    aCursor.mCursor = NS_STYLE_CURSOR_POINTER;
+  if (StyleCursorKind::Auto == aCursor.mCursor) {
+    aCursor.mCursor = StyleCursorKind::Pointer;
   }
 
   return NS_OK;
 }
 
 nsresult nsImageControlFrame::SetFormProperty(nsAtom* aName,
                                               const nsAString& aValue) {
   return NS_OK;
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -5037,27 +5037,27 @@ void nsIFrame::AssociateImage(const nsSt
       aPresContext->Document()->StyleImageLoader();
 
   // If this fails there's not much we can do ...
   loader->AssociateRequestToFrame(req, this, aImageLoaderFlags);
 }
 
 nsresult nsFrame::GetCursor(const nsPoint& aPoint, nsIFrame::Cursor& aCursor) {
   FillCursorInformationFromStyle(StyleUI(), aCursor);
-  if (NS_STYLE_CURSOR_AUTO == aCursor.mCursor) {
+  if (StyleCursorKind::Auto == aCursor.mCursor) {
     // If this is editable, I-beam cursor is better for most elements.
     aCursor.mCursor = (mContent && mContent->IsEditable())
-                          ? NS_STYLE_CURSOR_TEXT
-                          : NS_STYLE_CURSOR_DEFAULT;
-  }
-  if (NS_STYLE_CURSOR_TEXT == aCursor.mCursor &&
+                          ? StyleCursorKind::Text
+                          : StyleCursorKind::Default;
+  }
+  if (StyleCursorKind::Text == aCursor.mCursor &&
       GetWritingMode().IsVertical()) {
     // Per CSS UI spec, UA may treat value 'text' as
     // 'vertical-text' for vertical text.
-    aCursor.mCursor = NS_STYLE_CURSOR_VERTICAL_TEXT;
+    aCursor.mCursor = StyleCursorKind::VerticalText;
   }
 
   return NS_OK;
 }
 
 // Resize and incremental reflow
 
 /* virtual */ void nsFrame::MarkIntrinsicISizesDirty() {
--- a/layout/generic/nsFrameSetFrame.cpp
+++ b/layout/generic/nsFrameSetFrame.cpp
@@ -627,20 +627,20 @@ nsresult nsHTMLFramesetFrame::HandleEven
   }
   return NS_OK;
 }
 
 nsresult nsHTMLFramesetFrame::GetCursor(const nsPoint& aPoint,
                                         nsIFrame::Cursor& aCursor) {
   aCursor.mLoading = false;
   if (mDragger) {
-    aCursor.mCursor = (mDragger->mVertical) ? NS_STYLE_CURSOR_EW_RESIZE
-                                            : NS_STYLE_CURSOR_NS_RESIZE;
+    aCursor.mCursor = (mDragger->mVertical) ? StyleCursorKind::EwResize
+                                            : StyleCursorKind::NsResize;
   } else {
-    aCursor.mCursor = NS_STYLE_CURSOR_DEFAULT;
+    aCursor.mCursor = StyleCursorKind::Default;
   }
   return NS_OK;
 }
 
 void nsHTMLFramesetFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
                                            const nsDisplayListSet& aLists) {
   BuildDisplayListForInline(aBuilder, aLists);
 
@@ -1463,20 +1463,20 @@ nsresult nsHTMLFramesetBorderFrame::Hand
   }
   return NS_OK;
 }
 
 nsresult nsHTMLFramesetBorderFrame::GetCursor(const nsPoint& aPoint,
                                               nsIFrame::Cursor& aCursor) {
   aCursor.mLoading = false;
   if (!mCanResize) {
-    aCursor.mCursor = NS_STYLE_CURSOR_DEFAULT;
+    aCursor.mCursor = StyleCursorKind::Default;
   } else {
     aCursor.mCursor =
-        (mVertical) ? NS_STYLE_CURSOR_EW_RESIZE : NS_STYLE_CURSOR_NS_RESIZE;
+        (mVertical) ? StyleCursorKind::EwResize: StyleCursorKind::NsResize;
   }
   return NS_OK;
 }
 
 #ifdef DEBUG_FRAME_DUMP
 nsresult nsHTMLFramesetBorderFrame::GetFrameName(nsAString& aResult) const {
   return MakeFrameName(NS_LITERAL_STRING("FramesetBorder"), aResult);
 }
--- a/layout/generic/nsIFrame.h
+++ b/layout/generic/nsIFrame.h
@@ -1981,17 +1981,17 @@ class nsIFrame : public nsQueryFrame {
 
   /**
    * This structure holds information about a cursor. mContainer represents a
    * loaded image that should be preferred. If it is not possible to use it, or
    * if it is null, mCursor should be used.
    */
   struct MOZ_STACK_CLASS Cursor {
     nsCOMPtr<imgIContainer> mContainer;
-    int32_t mCursor = NS_STYLE_CURSOR_AUTO;
+    mozilla::StyleCursorKind mCursor = mozilla::StyleCursorKind::Auto;
     bool mHaveHotspot = false;
     bool mLoading = false;
     float mHotspotX = 0.0f, mHotspotY = 0.0f;
   };
   /**
    * Get the cursor for a given frame.
    */
   virtual nsresult GetCursor(const nsPoint& aPoint, Cursor& aCursor) = 0;
--- a/layout/generic/nsImageFrame.cpp
+++ b/layout/generic/nsImageFrame.cpp
@@ -1613,18 +1613,17 @@ ImgDrawResult nsImageFrame::DisplayAltFe
       nsCOMPtr<imgIContainer> imgCon;
       request->GetImage(getter_AddRefs(imgCon));
       MOZ_ASSERT(imgCon, "Load complete, but no image container?");
 
       nsRect dest(flushRight ? inner.XMost() - size : inner.x, inner.y, size,
                   size);
 
       const int32_t factor = PresContext()->AppUnitsPerDevPixel();
-      LayoutDeviceRect destRect(
-          LayoutDeviceRect::FromAppUnits(dest, factor));
+      LayoutDeviceRect destRect(LayoutDeviceRect::FromAppUnits(dest, factor));
       destRect.Round();
 
       Maybe<SVGImageContext> svgContext;
       IntSize decodeSize =
           nsLayoutUtils::ComputeImageContainerDrawingParameters(
               imgCon, this, destRect, aSc, aFlags, svgContext);
       RefPtr<ImageContainer> container;
       result = imgCon->GetImageContainerAtSize(aManager->LayerManager(),
@@ -2307,18 +2306,18 @@ nsresult nsImageFrame::GetCursor(const n
       // XXX Using the image as the parent ComputedStyle isn't
       // technically correct, but it's probably the right thing to do
       // here, since it means that areas on which the cursor isn't
       // specified will inherit the style from the image.
       RefPtr<ComputedStyle> areaStyle =
           PresShell()->StyleSet()->ResolveStyleFor(area->AsElement(),
                                                    LazyComputeBehavior::Allow);
       FillCursorInformationFromStyle(areaStyle->StyleUI(), aCursor);
-      if (NS_STYLE_CURSOR_AUTO == aCursor.mCursor) {
-        aCursor.mCursor = NS_STYLE_CURSOR_DEFAULT;
+      if (StyleCursorKind::Auto == aCursor.mCursor) {
+        aCursor.mCursor = StyleCursorKind::Default;
       }
       return NS_OK;
     }
   }
   return nsFrame::GetCursor(aPoint, aCursor);
 }
 
 nsresult nsImageFrame::AttributeChanged(int32_t aNameSpaceID,
--- a/layout/generic/nsTextFrame.cpp
+++ b/layout/generic/nsTextFrame.cpp
@@ -4585,23 +4585,23 @@ nsIFrame* NS_NewContinuingTextFrame(nsIP
 
 NS_IMPL_FRAMEARENA_HELPERS(nsContinuingTextFrame)
 
 nsTextFrame::~nsTextFrame() {}
 
 nsresult nsTextFrame::GetCursor(const nsPoint& aPoint,
                                 nsIFrame::Cursor& aCursor) {
   FillCursorInformationFromStyle(StyleUI(), aCursor);
-  if (NS_STYLE_CURSOR_AUTO == aCursor.mCursor) {
+  if (StyleCursorKind::Auto == aCursor.mCursor) {
     if (!IsSelectable(nullptr)) {
-      aCursor.mCursor = NS_STYLE_CURSOR_DEFAULT;
+      aCursor.mCursor = StyleCursorKind::Default;
     } else {
       aCursor.mCursor = GetWritingMode().IsVertical()
-                            ? NS_STYLE_CURSOR_VERTICAL_TEXT
-                            : NS_STYLE_CURSOR_TEXT;
+                            ? StyleCursorKind::VerticalText
+                            : StyleCursorKind::Text;
     }
     return NS_OK;
   } else {
     return nsFrame::GetCursor(aPoint, aCursor);
   }
 }
 
 nsTextFrame* nsTextFrame::LastInFlow() const {
--- a/layout/style/ServoBindings.toml
+++ b/layout/style/ServoBindings.toml
@@ -384,16 +384,17 @@ opaque-types = [
 
 # All cbindgen-types are in mod "structs::root::mozilla".
 cbindgen-types = [
     { gecko = "StyleAppearance", servo = "values::specified::Appearance" },
     { gecko = "StyleComputedFontStretchRange", servo = "font_face::ComputedFontStretchRange" },
     { gecko = "StyleComputedFontStyleDescriptor", servo = "font_face::ComputedFontStyleDescriptor" },
     { gecko = "StyleComputedFontWeightRange", servo = "font_face::ComputedFontWeightRange" },
     { gecko = "StyleComputedTimingFunction", servo = "values::computed::easing::TimingFunction" },
+    { gecko = "StyleCursorKind", servo = "values::computed::ui::CursorKind" },
     { gecko = "StyleDisplay", servo = "values::specified::Display" },
     { gecko = "StyleDisplayMode", servo = "gecko::media_features::DisplayMode" },
     { gecko = "StyleExtremumLength", servo = "values::computed::length::ExtremumLength" },
     { gecko = "StyleFillRule", servo = "values::generics::basic_shape::FillRule" },
     { gecko = "StyleFontDisplay", servo = "font_face::FontDisplay" },
     { gecko = "StyleFontFaceSourceListComponent", servo = "font_face::FontFaceSourceListComponent" },
     { gecko = "StyleFontLanguageOverride", servo = "values::computed::font::FontLanguageOverride" },
     { gecko = "StylePathCommand", servo = "values::specified::svg_path::PathCommand" },
--- a/layout/style/ServoCSSPropList.mako.py
+++ b/layout/style/ServoCSSPropList.mako.py
@@ -77,16 +77,17 @@ SERIALIZED_PREDEFINED_TYPES = [
     "BreakBetween",
     "BreakWithin",
     "Clear",
     "ClipRectOrAuto",
     "Color",
     "Content",
     "CounterIncrement",
     "CounterReset",
+    "Cursor",
     "FillRule",
     "Float",
     "FontFamily",
     "FontFeatureSettings",
     "FontLanguageOverride",
     "FontSize",
     "FontSizeAdjust",
     "FontStretch",
--- a/layout/style/nsCSSProps.cpp
+++ b/layout/style/nsCSSProps.cpp
@@ -172,59 +172,59 @@ const nsCString& nsCSSProps::GetStringVa
 /***************************************************************************/
 
 const KTableEntry nsCSSProps::kBoxShadowTypeKTable[] = {
     {eCSSKeyword_inset, uint8_t(StyleBoxShadowType::Inset)},
     {eCSSKeyword_UNKNOWN, -1}};
 
 const KTableEntry nsCSSProps::kCursorKTable[] = {
     // CSS 2.0
-    {eCSSKeyword_auto, NS_STYLE_CURSOR_AUTO},
-    {eCSSKeyword_crosshair, NS_STYLE_CURSOR_CROSSHAIR},
-    {eCSSKeyword_default, NS_STYLE_CURSOR_DEFAULT},
-    {eCSSKeyword_pointer, NS_STYLE_CURSOR_POINTER},
-    {eCSSKeyword_move, NS_STYLE_CURSOR_MOVE},
-    {eCSSKeyword_e_resize, NS_STYLE_CURSOR_E_RESIZE},
-    {eCSSKeyword_ne_resize, NS_STYLE_CURSOR_NE_RESIZE},
-    {eCSSKeyword_nw_resize, NS_STYLE_CURSOR_NW_RESIZE},
-    {eCSSKeyword_n_resize, NS_STYLE_CURSOR_N_RESIZE},
-    {eCSSKeyword_se_resize, NS_STYLE_CURSOR_SE_RESIZE},
-    {eCSSKeyword_sw_resize, NS_STYLE_CURSOR_SW_RESIZE},
-    {eCSSKeyword_s_resize, NS_STYLE_CURSOR_S_RESIZE},
-    {eCSSKeyword_w_resize, NS_STYLE_CURSOR_W_RESIZE},
-    {eCSSKeyword_text, NS_STYLE_CURSOR_TEXT},
-    {eCSSKeyword_wait, NS_STYLE_CURSOR_WAIT},
-    {eCSSKeyword_help, NS_STYLE_CURSOR_HELP},
+    {eCSSKeyword_auto, StyleCursorKind::Auto},
+    {eCSSKeyword_crosshair, StyleCursorKind::Crosshair},
+    {eCSSKeyword_default, StyleCursorKind::Default},
+    {eCSSKeyword_pointer, StyleCursorKind::Pointer},
+    {eCSSKeyword_move, StyleCursorKind::Move},
+    {eCSSKeyword_e_resize, StyleCursorKind::EResize},
+    {eCSSKeyword_ne_resize, StyleCursorKind::NeResize},
+    {eCSSKeyword_nw_resize, StyleCursorKind::NwResize},
+    {eCSSKeyword_n_resize, StyleCursorKind::NResize},
+    {eCSSKeyword_se_resize, StyleCursorKind::SeResize},
+    {eCSSKeyword_sw_resize, StyleCursorKind::SwResize},
+    {eCSSKeyword_s_resize, StyleCursorKind::SResize},
+    {eCSSKeyword_w_resize, StyleCursorKind::WResize},
+    {eCSSKeyword_text, StyleCursorKind::Text},
+    {eCSSKeyword_wait, StyleCursorKind::Wait},
+    {eCSSKeyword_help, StyleCursorKind::Help},
     // CSS 2.1
-    {eCSSKeyword_progress, NS_STYLE_CURSOR_SPINNING},
+    {eCSSKeyword_progress, StyleCursorKind::Progress},
     // CSS3 basic user interface module
-    {eCSSKeyword_copy, NS_STYLE_CURSOR_COPY},
-    {eCSSKeyword_alias, NS_STYLE_CURSOR_ALIAS},
-    {eCSSKeyword_context_menu, NS_STYLE_CURSOR_CONTEXT_MENU},
-    {eCSSKeyword_cell, NS_STYLE_CURSOR_CELL},
-    {eCSSKeyword_not_allowed, NS_STYLE_CURSOR_NOT_ALLOWED},
-    {eCSSKeyword_col_resize, NS_STYLE_CURSOR_COL_RESIZE},
-    {eCSSKeyword_row_resize, NS_STYLE_CURSOR_ROW_RESIZE},
-    {eCSSKeyword_no_drop, NS_STYLE_CURSOR_NO_DROP},
-    {eCSSKeyword_vertical_text, NS_STYLE_CURSOR_VERTICAL_TEXT},
-    {eCSSKeyword_all_scroll, NS_STYLE_CURSOR_ALL_SCROLL},
-    {eCSSKeyword_nesw_resize, NS_STYLE_CURSOR_NESW_RESIZE},
-    {eCSSKeyword_nwse_resize, NS_STYLE_CURSOR_NWSE_RESIZE},
-    {eCSSKeyword_ns_resize, NS_STYLE_CURSOR_NS_RESIZE},
-    {eCSSKeyword_ew_resize, NS_STYLE_CURSOR_EW_RESIZE},
-    {eCSSKeyword_none, NS_STYLE_CURSOR_NONE},
-    {eCSSKeyword_grab, NS_STYLE_CURSOR_GRAB},
-    {eCSSKeyword_grabbing, NS_STYLE_CURSOR_GRABBING},
-    {eCSSKeyword_zoom_in, NS_STYLE_CURSOR_ZOOM_IN},
-    {eCSSKeyword_zoom_out, NS_STYLE_CURSOR_ZOOM_OUT},
+    {eCSSKeyword_copy, StyleCursorKind::Copy},
+    {eCSSKeyword_alias, StyleCursorKind::Alias},
+    {eCSSKeyword_context_menu, StyleCursorKind::ContextMenu},
+    {eCSSKeyword_cell, StyleCursorKind::Cell},
+    {eCSSKeyword_not_allowed, StyleCursorKind::NotAllowed},
+    {eCSSKeyword_col_resize, StyleCursorKind::ColResize},
+    {eCSSKeyword_row_resize, StyleCursorKind::RowResize},
+    {eCSSKeyword_no_drop, StyleCursorKind::NoDrop},
+    {eCSSKeyword_vertical_text, StyleCursorKind::VerticalText},
+    {eCSSKeyword_all_scroll, StyleCursorKind::AllScroll},
+    {eCSSKeyword_nesw_resize, StyleCursorKind::NeswResize},
+    {eCSSKeyword_nwse_resize, StyleCursorKind::NwseResize},
+    {eCSSKeyword_ns_resize, StyleCursorKind::NsResize},
+    {eCSSKeyword_ew_resize, StyleCursorKind::EwResize},
+    {eCSSKeyword_none, StyleCursorKind::None},
+    {eCSSKeyword_grab, StyleCursorKind::Grab},
+    {eCSSKeyword_grabbing, StyleCursorKind::Grabbing},
+    {eCSSKeyword_zoom_in, StyleCursorKind::ZoomIn},
+    {eCSSKeyword_zoom_out, StyleCursorKind::ZoomOut},
     // -moz- prefixed vendor specific
-    {eCSSKeyword__moz_grab, NS_STYLE_CURSOR_GRAB},
-    {eCSSKeyword__moz_grabbing, NS_STYLE_CURSOR_GRABBING},
-    {eCSSKeyword__moz_zoom_in, NS_STYLE_CURSOR_ZOOM_IN},
-    {eCSSKeyword__moz_zoom_out, NS_STYLE_CURSOR_ZOOM_OUT},
+    {eCSSKeyword__moz_grab, StyleCursorKind::Grab},
+    {eCSSKeyword__moz_grabbing, StyleCursorKind::Grabbing},
+    {eCSSKeyword__moz_zoom_in, StyleCursorKind::ZoomIn},
+    {eCSSKeyword__moz_zoom_out, StyleCursorKind::ZoomOut},
     {eCSSKeyword_UNKNOWN, -1}};
 
 KTableEntry nsCSSProps::kDisplayKTable[] = {
     {eCSSKeyword_none, StyleDisplay::None},
     {eCSSKeyword_inline, StyleDisplay::Inline},
     {eCSSKeyword_block, StyleDisplay::Block},
     {eCSSKeyword_inline_block, StyleDisplay::InlineBlock},
     {eCSSKeyword_list_item, StyleDisplay::ListItem},
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -2256,48 +2256,16 @@ static_assert(NS_STYLE_UNICODE_BIDI_NORM
               "unicode-bidi style constants not as expected");
 
 already_AddRefed<CSSValue> nsComputedDOMStyle::DoGetCaretColor() {
   RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   SetValueFromComplexColor(val, StyleUI()->mCaretColor);
   return val.forget();
 }
 
-already_AddRefed<CSSValue> nsComputedDOMStyle::DoGetCursor() {
-  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
-
-  const nsStyleUI* ui = StyleUI();
-
-  for (const nsCursorImage& item : ui->mCursorImages) {
-    RefPtr<nsDOMCSSValueList> itemList = GetROCSSValueList(false);
-
-    RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
-    SetValueToURLValue(item.mImage->GetImageValue(), val);
-    itemList->AppendCSSValue(val.forget());
-
-    if (item.mHaveHotspot) {
-      RefPtr<nsROCSSPrimitiveValue> valX = new nsROCSSPrimitiveValue;
-      RefPtr<nsROCSSPrimitiveValue> valY = new nsROCSSPrimitiveValue;
-
-      valX->SetNumber(item.mHotspotX);
-      valY->SetNumber(item.mHotspotY);
-
-      itemList->AppendCSSValue(valX.forget());
-      itemList->AppendCSSValue(valY.forget());
-    }
-    valueList->AppendCSSValue(itemList.forget());
-  }
-
-  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
-  val->SetIdent(
-      nsCSSProps::ValueToKeywordEnum(ui->mCursor, nsCSSProps::kCursorKTable));
-  valueList->AppendCSSValue(val.forget());
-  return valueList.forget();
-}
-
 already_AddRefed<CSSValue> nsComputedDOMStyle::DoGetBoxFlex() {
   RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetNumber(StyleXUL()->mBoxFlex);
   return val.forget();
 }
 
 /* Border image properties */
 
--- a/layout/style/nsComputedDOMStyle.h
+++ b/layout/style/nsComputedDOMStyle.h
@@ -339,17 +339,16 @@ class nsComputedDOMStyle final : public 
   already_AddRefed<CSSValue> DoGetPerspective();
   already_AddRefed<CSSValue> DoGetPerspectiveOrigin();
   already_AddRefed<CSSValue> DoGetScrollSnapPointsX();
   already_AddRefed<CSSValue> DoGetScrollSnapPointsY();
   already_AddRefed<CSSValue> DoGetScrollbarColor();
 
   /* User interface properties */
   already_AddRefed<CSSValue> DoGetCaretColor();
-  already_AddRefed<CSSValue> DoGetCursor();
   already_AddRefed<CSSValue> DoGetForceBrokenImageIcon();
 
   /* Column properties */
   already_AddRefed<CSSValue> DoGetColumnCount();
   already_AddRefed<CSSValue> DoGetColumnWidth();
   already_AddRefed<CSSValue> DoGetColumnRuleWidth();
 
   /* CSS Transitions */
--- a/layout/style/nsStyleConsts.h
+++ b/layout/style/nsStyleConsts.h
@@ -292,54 +292,16 @@ enum class StyleBorderImageRepeat : uint
 enum class StyleContent : uint8_t {
   OpenQuote,
   CloseQuote,
   NoOpenQuote,
   NoCloseQuote,
   AltContent
 };
 
-// See nsStyleUI
-#define NS_STYLE_CURSOR_AUTO 1
-#define NS_STYLE_CURSOR_CROSSHAIR 2
-#define NS_STYLE_CURSOR_DEFAULT 3  // ie: an arrow
-#define NS_STYLE_CURSOR_POINTER 4  // for links
-#define NS_STYLE_CURSOR_MOVE 5
-#define NS_STYLE_CURSOR_E_RESIZE 6
-#define NS_STYLE_CURSOR_NE_RESIZE 7
-#define NS_STYLE_CURSOR_NW_RESIZE 8
-#define NS_STYLE_CURSOR_N_RESIZE 9
-#define NS_STYLE_CURSOR_SE_RESIZE 10
-#define NS_STYLE_CURSOR_SW_RESIZE 11
-#define NS_STYLE_CURSOR_S_RESIZE 12
-#define NS_STYLE_CURSOR_W_RESIZE 13
-#define NS_STYLE_CURSOR_TEXT 14  // ie: i-beam
-#define NS_STYLE_CURSOR_WAIT 15
-#define NS_STYLE_CURSOR_HELP 16
-#define NS_STYLE_CURSOR_COPY 17  // CSS3
-#define NS_STYLE_CURSOR_ALIAS 18
-#define NS_STYLE_CURSOR_CONTEXT_MENU 19
-#define NS_STYLE_CURSOR_CELL 20
-#define NS_STYLE_CURSOR_GRAB 21
-#define NS_STYLE_CURSOR_GRABBING 22
-#define NS_STYLE_CURSOR_SPINNING 23
-#define NS_STYLE_CURSOR_ZOOM_IN 24
-#define NS_STYLE_CURSOR_ZOOM_OUT 25
-#define NS_STYLE_CURSOR_NOT_ALLOWED 26
-#define NS_STYLE_CURSOR_COL_RESIZE 27
-#define NS_STYLE_CURSOR_ROW_RESIZE 28
-#define NS_STYLE_CURSOR_NO_DROP 29
-#define NS_STYLE_CURSOR_VERTICAL_TEXT 30
-#define NS_STYLE_CURSOR_ALL_SCROLL 31
-#define NS_STYLE_CURSOR_NESW_RESIZE 32
-#define NS_STYLE_CURSOR_NWSE_RESIZE 33
-#define NS_STYLE_CURSOR_NS_RESIZE 34
-#define NS_STYLE_CURSOR_EW_RESIZE 35
-#define NS_STYLE_CURSOR_NONE 36
-
 // See nsStyleVisibility
 #define NS_STYLE_DIRECTION_LTR 0
 #define NS_STYLE_DIRECTION_RTL 1
 
 // See nsStyleVisibility
 // NOTE: WritingModes.h depends on the particular values used here.
 #define NS_STYLE_WRITING_MODE_HORIZONTAL_TB 0
 #define NS_STYLE_WRITING_MODE_VERTICAL_RL 1
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -3994,17 +3994,17 @@ bool nsCursorImage::operator==(const nsC
          DefinitelyEqualImages(mImage, aOther.mImage);
 }
 
 nsStyleUI::nsStyleUI(const nsPresContext* aContext)
     : mUserInput(StyleUserInput::Auto),
       mUserModify(StyleUserModify::ReadOnly),
       mUserFocus(StyleUserFocus::None),
       mPointerEvents(NS_STYLE_POINTER_EVENTS_AUTO),
-      mCursor(NS_STYLE_CURSOR_AUTO),
+      mCursor(StyleCursorKind::Auto),
       mCaretColor(StyleComplexColor::Auto()),
       mScrollbarFaceColor(StyleComplexColor::Auto()),
       mScrollbarTrackColor(StyleComplexColor::Auto()) {
   MOZ_COUNT_CTOR(nsStyleUI);
 }
 
 nsStyleUI::nsStyleUI(const nsStyleUI& aSource)
     : mUserInput(aSource.mUserInput),
--- a/layout/style/nsStyleStruct.h
+++ b/layout/style/nsStyleStruct.h
@@ -2569,17 +2569,17 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsSt
 
   nsChangeHint CalcDifference(const nsStyleUI& aNewData) const;
 
   mozilla::StyleUserInput mUserInput;
   mozilla::StyleUserModify mUserModify;  // (modify-content)
   mozilla::StyleUserFocus mUserFocus;    // (auto-select)
   uint8_t mPointerEvents;                // NS_STYLE_POINTER_EVENTS_*
 
-  uint8_t mCursor;                        // NS_STYLE_CURSOR_*
+  mozilla::StyleCursorKind mCursor;
   nsTArray<nsCursorImage> mCursorImages;  // images and coords
   mozilla::StyleComplexColor mCaretColor;
 
   mozilla::StyleComplexColor mScrollbarFaceColor;
   mozilla::StyleComplexColor mScrollbarTrackColor;
 
   inline uint8_t GetEffectivePointerEvents(nsIFrame* aFrame) const;
 
--- a/layout/xul/tree/nsTreeBodyFrame.cpp
+++ b/layout/xul/tree/nsTreeBodyFrame.cpp
@@ -2228,18 +2228,18 @@ nsresult nsTreeBodyFrame::GetCursor(cons
     nsCSSAnonBoxPseudoStaticAtom* child;
     GetCellAt(aPoint.x, aPoint.y, &row, &col, &child);
 
     if (child) {
       // Our scratch array is already prefilled.
       ComputedStyle* childContext = GetPseudoComputedStyle(child);
 
       FillCursorInformationFromStyle(childContext->StyleUI(), aCursor);
-      if (aCursor.mCursor == NS_STYLE_CURSOR_AUTO)
-        aCursor.mCursor = NS_STYLE_CURSOR_DEFAULT;
+      if (aCursor.mCursor == StyleCursorKind::Auto)
+        aCursor.mCursor = StyleCursorKind::Default;
 
       return NS_OK;
     }
   }
 
   return nsLeafBoxFrame::GetCursor(aPoint, aCursor);
 }
 
--- a/netwerk/protocol/http/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/nsHttpChannel.cpp
@@ -7494,30 +7494,16 @@ nsHttpChannel::OnStopRequest(nsIRequest 
         !mTransactionTimings.connectStart.IsNull() &&
         mDNSPrefetch->EndTimestamp() <= mTransactionTimings.connectStart) {
       // We only need the domainLookup timestamps when not using a
       // persistent connection, meaning if the endTimestamp < connectStart
       mTransactionTimings.domainLookupStart = mDNSPrefetch->StartTimestamp();
       mTransactionTimings.domainLookupEnd = mDNSPrefetch->EndTimestamp();
     }
     mDNSPrefetch = nullptr;
-#ifdef MOZ_GECKO_PROFILER
-    if (profiler_is_active() && !mRedirectURI) {
-      // Don't include this if we already redirected
-      // These do allocations/frees/etc; avoid if not active
-      nsCOMPtr<nsIURI> uri;
-      GetURI(getter_AddRefs(uri));
-      int32_t priority = PRIORITY_NORMAL;
-      GetPriority(&priority);
-      profiler_add_network_marker(
-          uri, priority, mChannelId, NetworkLoadType::LOAD_STOP,
-          mLastStatusReported, TimeStamp::Now(), mLogicalOffset,
-          mCacheDisposition, &mTransactionTimings, nullptr);
-    }
-#endif
 
     // handle auth retry...
     if (authRetry) {
       mAuthRetryPending = false;
       auto continueOSR = [authRetry, isFromNet, contentComplete,
                           stickyConn{std::move(stickyConn)}](auto *self,
                                                              nsresult aStatus) {
         return self->ContinueOnStopRequestAfterAuthRetry(
@@ -7738,16 +7724,31 @@ nsresult nsHttpChannel::ContinueOnStopRe
     }
   }
 
   ReportRcwnStats(aIsFromNet);
 
   // Register entry to the PerformanceStorage resource timing
   MaybeReportTimingData();
 
+#ifdef MOZ_GECKO_PROFILER
+  if (profiler_is_active() && !mRedirectURI) {
+    // Don't include this if we already redirected
+    // These do allocations/frees/etc; avoid if not active
+    nsCOMPtr<nsIURI> uri;
+    GetURI(getter_AddRefs(uri));
+    int32_t priority = PRIORITY_NORMAL;
+    GetPriority(&priority);
+    profiler_add_network_marker(
+        uri, priority, mChannelId, NetworkLoadType::LOAD_STOP,
+        mLastStatusReported, TimeStamp::Now(), mLogicalOffset,
+        mCacheDisposition, &mTransactionTimings, nullptr);
+  }
+#endif
+
   if (mListener) {
     LOG(("nsHttpChannel %p calling OnStopRequest\n", this));
     MOZ_ASSERT(mOnStartRequestCalled,
                "OnStartRequest should be called before OnStopRequest");
     MOZ_ASSERT(!mOnStopRequestCalled, "We should not call OnStopRequest twice");
     mListener->OnStopRequest(this, mListenerContext, aStatus);
     mOnStopRequestCalled = true;
   }
--- a/servo/components/style/cbindgen.toml
+++ b/servo/components/style/cbindgen.toml
@@ -43,16 +43,17 @@ include = [
   "BreakBetween",
   "BreakWithin",
   "BorderStyle",
   "OutlineStyle",
   "ComputedFontStretchRange",
   "ComputedFontStyleDescriptor",
   "ComputedFontWeightRange",
   "ComputedTimingFunction",
+  "CursorKind",
   "Display",
   "DisplayMode",
   "ExtremumLength",
   "FillRule",
   "FontDisplay",
   "FontFaceSourceListComponent",
   "FontLanguageOverride",
   "OverflowWrap",
--- a/servo/components/style/properties/gecko.mako.rs
+++ b/servo/components/style/properties/gecko.mako.rs
@@ -5157,62 +5157,17 @@ clip-path
         let color = ${get_gecko_property("mColor")} as u32;
         convert_nscolor_to_rgba(color)
     }
 </%self:impl_trait>
 
 <%self:impl_trait style_struct_name="InheritedUI"
                   skip_longhands="cursor scrollbar-color">
     pub fn set_cursor(&mut self, v: longhands::cursor::computed_value::T) {
-        use style_traits::cursor::CursorKind;
-
-        self.gecko.mCursor = match v.keyword {
-            CursorKind::Auto => structs::NS_STYLE_CURSOR_AUTO,
-            CursorKind::None => structs::NS_STYLE_CURSOR_NONE,
-            CursorKind::Default => structs::NS_STYLE_CURSOR_DEFAULT,
-            CursorKind::Pointer => structs::NS_STYLE_CURSOR_POINTER,
-            CursorKind::ContextMenu => structs::NS_STYLE_CURSOR_CONTEXT_MENU,
-            CursorKind::Help => structs::NS_STYLE_CURSOR_HELP,
-            CursorKind::Progress => structs::NS_STYLE_CURSOR_SPINNING,
-            CursorKind::Wait => structs::NS_STYLE_CURSOR_WAIT,
-            CursorKind::Cell => structs::NS_STYLE_CURSOR_CELL,
-            CursorKind::Crosshair => structs::NS_STYLE_CURSOR_CROSSHAIR,
-            CursorKind::Text => structs::NS_STYLE_CURSOR_TEXT,
-            CursorKind::VerticalText => structs::NS_STYLE_CURSOR_VERTICAL_TEXT,
-            CursorKind::Alias => structs::NS_STYLE_CURSOR_ALIAS,
-            CursorKind::Copy => structs::NS_STYLE_CURSOR_COPY,
-            CursorKind::Move => structs::NS_STYLE_CURSOR_MOVE,
-            CursorKind::NoDrop => structs::NS_STYLE_CURSOR_NO_DROP,
-            CursorKind::NotAllowed => structs::NS_STYLE_CURSOR_NOT_ALLOWED,
-            CursorKind::Grab => structs::NS_STYLE_CURSOR_GRAB,
-            CursorKind::Grabbing => structs::NS_STYLE_CURSOR_GRABBING,
-            CursorKind::EResize => structs::NS_STYLE_CURSOR_E_RESIZE,
-            CursorKind::NResize => structs::NS_STYLE_CURSOR_N_RESIZE,
-            CursorKind::NeResize => structs::NS_STYLE_CURSOR_NE_RESIZE,
-            CursorKind::NwResize => structs::NS_STYLE_CURSOR_NW_RESIZE,
-            CursorKind::SResize => structs::NS_STYLE_CURSOR_S_RESIZE,
-            CursorKind::SeResize => structs::NS_STYLE_CURSOR_SE_RESIZE,
-            CursorKind::SwResize => structs::NS_STYLE_CURSOR_SW_RESIZE,
-            CursorKind::WResize => structs::NS_STYLE_CURSOR_W_RESIZE,
-            CursorKind::EwResize => structs::NS_STYLE_CURSOR_EW_RESIZE,
-            CursorKind::NsResize => structs::NS_STYLE_CURSOR_NS_RESIZE,
-            CursorKind::NeswResize => structs::NS_STYLE_CURSOR_NESW_RESIZE,
-            CursorKind::NwseResize => structs::NS_STYLE_CURSOR_NWSE_RESIZE,
-            CursorKind::ColResize => structs::NS_STYLE_CURSOR_COL_RESIZE,
-            CursorKind::RowResize => structs::NS_STYLE_CURSOR_ROW_RESIZE,
-            CursorKind::AllScroll => structs::NS_STYLE_CURSOR_ALL_SCROLL,
-            CursorKind::ZoomIn => structs::NS_STYLE_CURSOR_ZOOM_IN,
-            CursorKind::ZoomOut => structs::NS_STYLE_CURSOR_ZOOM_OUT,
-            // note: the following properties are gecko-only.
-            CursorKind::MozGrab => structs::NS_STYLE_CURSOR_GRAB,
-            CursorKind::MozGrabbing => structs::NS_STYLE_CURSOR_GRABBING,
-            CursorKind::MozZoomIn => structs::NS_STYLE_CURSOR_ZOOM_IN,
-            CursorKind::MozZoomOut => structs::NS_STYLE_CURSOR_ZOOM_OUT,
-        } as u8;
-
+        self.gecko.mCursor = v.keyword;
         unsafe {
             Gecko_SetCursorArrayLength(&mut self.gecko, v.images.len());
         }
         for i in 0..v.images.len() {
             unsafe {
                 Gecko_SetCursorImageValue(
                     &mut self.gecko.mCursorImages[i],
                     v.images[i].url.url_value_ptr(),
@@ -5241,57 +5196,18 @@ clip-path
 
     pub fn reset_cursor(&mut self, other: &Self) {
         self.copy_cursor_from(other)
     }
 
     pub fn clone_cursor(&self) -> longhands::cursor::computed_value::T {
         use crate::values::computed::ui::CursorImage;
         use crate::values::computed::url::ComputedImageUrl;
-        use style_traits::cursor::CursorKind;
-
-        let keyword = match self.gecko.mCursor as u32 {
-            structs::NS_STYLE_CURSOR_AUTO => CursorKind::Auto,
-            structs::NS_STYLE_CURSOR_NONE => CursorKind::None,
-            structs::NS_STYLE_CURSOR_DEFAULT => CursorKind::Default,
-            structs::NS_STYLE_CURSOR_POINTER => CursorKind::Pointer,
-            structs::NS_STYLE_CURSOR_CONTEXT_MENU => CursorKind::ContextMenu,
-            structs::NS_STYLE_CURSOR_HELP => CursorKind::Help,
-            structs::NS_STYLE_CURSOR_SPINNING => CursorKind::Progress,
-            structs::NS_STYLE_CURSOR_WAIT => CursorKind::Wait,
-            structs::NS_STYLE_CURSOR_CELL => CursorKind::Cell,
-            structs::NS_STYLE_CURSOR_CROSSHAIR => CursorKind::Crosshair,
-            structs::NS_STYLE_CURSOR_TEXT => CursorKind::Text,
-            structs::NS_STYLE_CURSOR_VERTICAL_TEXT => CursorKind::VerticalText,
-            structs::NS_STYLE_CURSOR_ALIAS => CursorKind::Alias,
-            structs::NS_STYLE_CURSOR_COPY => CursorKind::Copy,
-            structs::NS_STYLE_CURSOR_MOVE => CursorKind::Move,
-            structs::NS_STYLE_CURSOR_NO_DROP => CursorKind::NoDrop,
-            structs::NS_STYLE_CURSOR_NOT_ALLOWED => CursorKind::NotAllowed,
-            structs::NS_STYLE_CURSOR_GRAB => CursorKind::Grab,
-            structs::NS_STYLE_CURSOR_GRABBING => CursorKind::Grabbing,
-            structs::NS_STYLE_CURSOR_E_RESIZE => CursorKind::EResize,
-            structs::NS_STYLE_CURSOR_N_RESIZE => CursorKind::NResize,
-            structs::NS_STYLE_CURSOR_NE_RESIZE => CursorKind::NeResize,
-            structs::NS_STYLE_CURSOR_NW_RESIZE => CursorKind::NwResize,
-            structs::NS_STYLE_CURSOR_S_RESIZE => CursorKind::SResize,
-            structs::NS_STYLE_CURSOR_SE_RESIZE => CursorKind::SeResize,
-            structs::NS_STYLE_CURSOR_SW_RESIZE => CursorKind::SwResize,
-            structs::NS_STYLE_CURSOR_W_RESIZE => CursorKind::WResize,
-            structs::NS_STYLE_CURSOR_EW_RESIZE => CursorKind::EwResize,
-            structs::NS_STYLE_CURSOR_NS_RESIZE => CursorKind::NsResize,
-            structs::NS_STYLE_CURSOR_NESW_RESIZE => CursorKind::NeswResize,
-            structs::NS_STYLE_CURSOR_NWSE_RESIZE => CursorKind::NwseResize,
-            structs::NS_STYLE_CURSOR_COL_RESIZE => CursorKind::ColResize,
-            structs::NS_STYLE_CURSOR_ROW_RESIZE => CursorKind::RowResize,
-            structs::NS_STYLE_CURSOR_ALL_SCROLL => CursorKind::AllScroll,
-            structs::NS_STYLE_CURSOR_ZOOM_IN => CursorKind::ZoomIn,
-            structs::NS_STYLE_CURSOR_ZOOM_OUT => CursorKind::ZoomOut,
-            _ => panic!("Found unexpected value in style struct for cursor property"),
-        };
+
+        let keyword = self.gecko.mCursor;
 
         let images = self.gecko.mCursorImages.iter().map(|gecko_cursor_image| {
             let url = unsafe {
                 let gecko_image_request = gecko_cursor_image.mImage.mRawPtr.as_ref().unwrap();
                 ComputedImageUrl::from_image_request(&gecko_image_request)
             };
 
             let hotspot =
--- a/servo/components/style/values/computed/mod.rs
+++ b/servo/components/style/values/computed/mod.rs
@@ -23,17 +23,16 @@ use crate::rule_cache::RuleCacheConditio
 use crate::Atom;
 #[cfg(feature = "servo")]
 use crate::Prefix;
 use euclid::Size2D;
 use std::cell::RefCell;
 use std::cmp;
 use std::f32;
 use std::fmt::{self, Write};
-use style_traits::cursor::CursorKind;
 use style_traits::{CssWriter, ToCss};
 
 #[cfg(feature = "gecko")]
 pub use self::align::{AlignContent, AlignItems, JustifyContent, JustifyItems, SelfAlignment};
 #[cfg(feature = "gecko")]
 pub use self::align::{AlignSelf, JustifySelf};
 pub use self::angle::Angle;
 pub use self::background::{BackgroundRepeat, BackgroundSize};
@@ -447,17 +446,16 @@ where
 trivial_to_computed_value!(());
 trivial_to_computed_value!(bool);
 trivial_to_computed_value!(f32);
 trivial_to_computed_value!(i32);
 trivial_to_computed_value!(u8);
 trivial_to_computed_value!(u16);
 trivial_to_computed_value!(u32);
 trivial_to_computed_value!(Atom);
-trivial_to_computed_value!(CursorKind);
 #[cfg(feature = "servo")]
 trivial_to_computed_value!(Prefix);
 trivial_to_computed_value!(String);
 trivial_to_computed_value!(Box<str>);
 
 /// A `<number>` value.
 pub type Number = CSSFloat;
 
--- a/servo/components/style/values/computed/ui.rs
+++ b/servo/components/style/values/computed/ui.rs
@@ -5,16 +5,17 @@
 //! Computed values for UI properties
 
 use crate::values::computed::color::Color;
 use crate::values::computed::url::ComputedImageUrl;
 use crate::values::computed::Number;
 use crate::values::generics::ui as generics;
 use crate::values::{Auto, Either};
 
+pub use crate::values::specified::ui::CursorKind;
 pub use crate::values::specified::ui::{MozForceBrokenImageIcon, UserSelect};
 
 /// auto | <color>
 pub type ColorOrAuto = Either<Color, Auto>;
 
 /// A computed value for the `cursor` property.
 pub type Cursor = generics::Cursor<CursorImage>;
 
--- a/servo/components/style/values/generics/ui.rs
+++ b/servo/components/style/values/generics/ui.rs
@@ -1,16 +1,16 @@
 /* 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 https://mozilla.org/MPL/2.0/. */
 
 //! Generic values for UI properties.
 
 use std::fmt::{self, Write};
-use style_traits::cursor::CursorKind;
+use values::specified::ui::CursorKind;
 use style_traits::{CssWriter, ToCss};
 
 /// A generic value for the `cursor` property.
 ///
 /// https://drafts.csswg.org/css-ui/#cursor
 #[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue)]
 pub struct Cursor<Image> {
     /// The parsed images for the cursor.
--- a/servo/components/style/values/specified/ui.rs
+++ b/servo/components/style/values/specified/ui.rs
@@ -7,17 +7,16 @@
 use crate::parser::{Parse, ParserContext};
 use crate::values::generics::ui as generics;
 use crate::values::specified::color::Color;
 use crate::values::specified::url::SpecifiedImageUrl;
 use crate::values::specified::Number;
 use crate::values::{Auto, Either};
 use cssparser::Parser;
 use std::fmt::{self, Write};
-use style_traits::cursor::CursorKind;
 use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss};
 
 /// auto | <color>
 pub type ColorOrAuto = Either<Color, Auto>;
 
 /// A specified value for the `cursor` property.
 pub type Cursor = generics::Cursor<CursorImage>;
 
@@ -35,33 +34,21 @@ impl Parse for Cursor {
             match input.try(|input| CursorImage::parse(context, input)) {
                 Ok(image) => images.push(image),
                 Err(_) => break,
             }
             input.expect_comma()?;
         }
         Ok(Self {
             images: images.into_boxed_slice(),
-            keyword: CursorKind::parse(context, input)?,
+            keyword: CursorKind::parse(input)?,
         })
     }
 }
 
-impl Parse for CursorKind {
-    fn parse<'i, 't>(
-        _context: &ParserContext,
-        input: &mut Parser<'i, 't>,
-    ) -> Result<Self, ParseError<'i>> {
-        let location = input.current_source_location();
-        let ident = input.expect_ident()?;
-        CursorKind::from_css_keyword(&ident)
-            .map_err(|_| location.new_custom_error(StyleParseErrorKind::UnspecifiedError))
-    }
-}
-
 impl Parse for CursorImage {
     fn parse<'i, 't>(
         context: &ParserContext,
         input: &mut Parser<'i, 't>,
     ) -> Result<Self, ParseError<'i>> {
         Ok(Self {
             url: SpecifiedImageUrl::parse(context, input)?,
             hotspot: match input.try(|input| Number::parse(context, input)) {
@@ -161,8 +148,68 @@ impl Parse for ScrollbarColor {
 pub enum UserSelect {
     Auto,
     Text,
     #[parse(aliases = "-moz-none")]
     None,
     /// Force selection of all children.
     All,
 }
+
+/// The keywords allowed in the Cursor property.
+///
+/// https://drafts.csswg.org/css-ui-4/#propdef-cursor
+#[allow(missing_docs)]
+#[derive(
+    Clone,
+    Copy,
+    Debug,
+    Eq,
+    MallocSizeOf,
+    Parse,
+    PartialEq,
+    SpecifiedValueInfo,
+    ToComputedValue,
+    ToCss,
+)]
+#[repr(u8)]
+pub enum CursorKind {
+    None,
+    Default,
+    Pointer,
+    ContextMenu,
+    Help,
+    Progress,
+    Wait,
+    Cell,
+    Crosshair,
+    Text,
+    VerticalText,
+    Alias,
+    Copy,
+    Move,
+    NoDrop,
+    NotAllowed,
+    Grab,
+    Grabbing,
+    EResize,
+    NResize,
+    NeResize,
+    NwResize,
+    SResize,
+    SeResize,
+    SwResize,
+    WResize,
+    EwResize,
+    NsResize,
+    NeswResize,
+    NwseResize,
+    ColResize,
+    RowResize,
+    AllScroll,
+    ZoomIn,
+    ZoomOut,
+    Auto,
+    MozGrab,
+    MozGrabbing,
+    MozZoomIn,
+    MozZoomOut,
+}
deleted file mode 100644
--- a/servo/components/style_traits/cursor.rs
+++ /dev/null
@@ -1,118 +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 https://mozilla.org/MPL/2.0/. */
-
-//! A list of common mouse cursors per CSS3-UI ยง 8.1.1.
-
-use super::{CssWriter, KeywordsCollectFn, SpecifiedValueInfo, ToCss};
-
-macro_rules! define_cursor {
-    (
-        common properties = [
-            $( $c_css: expr => $c_variant: ident = $c_value: expr, )+
-        ]
-        gecko properties = [
-            $( $g_css: expr => $g_variant: ident = $g_value: expr, )+
-        ]
-    ) => {
-        /// <https://drafts.csswg.org/css-ui/#cursor>
-        #[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq)]
-        #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
-        #[repr(u8)]
-        #[allow(missing_docs)]
-        pub enum CursorKind {
-            $( $c_variant = $c_value, )+
-            $( #[cfg(feature = "gecko")] $g_variant = $g_value, )+
-        }
-
-        impl CursorKind {
-            /// Given a CSS keyword, get the corresponding cursor enum.
-            pub fn from_css_keyword(keyword: &str) -> Result<Self, ()> {
-                match_ignore_ascii_case! { &keyword,
-                    $( $c_css => Ok(CursorKind::$c_variant), )+
-                    $( #[cfg(feature = "gecko")] $g_css => Ok(CursorKind::$g_variant), )+
-                    _ => Err(())
-                }
-            }
-
-            /// From the C u8 value, get the corresponding Cursor enum.
-            pub fn from_u8(value: u8) -> Result<Self, ()> {
-                match value {
-                    $( $c_value => Ok(CursorKind::$c_variant), )+
-                    $( #[cfg(feature = "gecko")] $g_value => Ok(CursorKind::$g_variant), )+
-                    _ => Err(())
-                }
-            }
-        }
-
-        impl ToCss for CursorKind {
-            fn to_css<W>(&self, dest: &mut CssWriter<W>) -> ::std::fmt::Result where W: ::std::fmt::Write {
-                match *self {
-                    $(CursorKind::$c_variant => {
-                        ::std::fmt::Write::write_str(dest, $c_css)
-                    })+
-                    $(#[cfg(feature = "gecko")] CursorKind::$g_variant => {
-                        ::std::fmt::Write::write_str(dest, $g_css)
-                    })+
-                }
-            }
-        }
-
-        impl SpecifiedValueInfo for CursorKind {
-            fn collect_completion_keywords(f: KeywordsCollectFn) {
-                f(&[
-                    $($c_css,)+
-                    $($g_css,)+
-                ]);
-            }
-        }
-    }
-}
-
-define_cursor! {
-    common properties = [
-        "none" => None = 0,
-        "default" => Default = 1,
-        "pointer" => Pointer = 2,
-        "context-menu" => ContextMenu = 3,
-        "help" => Help = 4,
-        "progress" => Progress = 5,
-        "wait" => Wait = 6,
-        "cell" => Cell = 7,
-        "crosshair" => Crosshair = 8,
-        "text" => Text = 9,
-        "vertical-text" => VerticalText = 10,
-        "alias" => Alias = 11,
-        "copy" => Copy = 12,
-        "move" => Move = 13,
-        "no-drop" => NoDrop = 14,
-        "not-allowed" => NotAllowed = 15,
-        "grab" => Grab = 16,
-        "grabbing" => Grabbing = 17,
-        "e-resize" => EResize = 18,
-        "n-resize" => NResize = 19,
-        "ne-resize" => NeResize = 20,
-        "nw-resize" => NwResize = 21,
-        "s-resize" => SResize = 22,
-        "se-resize" => SeResize = 23,
-        "sw-resize" => SwResize = 24,
-        "w-resize" => WResize = 25,
-        "ew-resize" => EwResize = 26,
-        "ns-resize" => NsResize = 27,
-        "nesw-resize" => NeswResize = 28,
-        "nwse-resize" => NwseResize = 29,
-        "col-resize" => ColResize = 30,
-        "row-resize" => RowResize = 31,
-        "all-scroll" => AllScroll = 32,
-        "zoom-in" => ZoomIn = 33,
-        "zoom-out" => ZoomOut = 34,
-        "auto" => Auto = 35,
-    ]
-    // gecko only properties
-    gecko properties = [
-        "-moz-grab" => MozGrab = 36,
-        "-moz-grabbing" => MozGrabbing = 37,
-        "-moz-zoom-in" => MozZoomIn = 38,
-        "-moz-zoom-out" => MozZoomOut = 39,
-    ]
-}
--- a/servo/components/style_traits/lib.rs
+++ b/servo/components/style_traits/lib.rs
@@ -76,17 +76,16 @@ impl PinchZoomFactor {
 pub enum CSSPixel {}
 
 // In summary, the hierarchy of pixel units and the factors to convert from one to the next:
 //
 // DevicePixel
 //   / hidpi_ratio => DeviceIndependentPixel
 //     / desktop_zoom => CSSPixel
 
-pub mod cursor;
 pub mod specified_value_info;
 #[macro_use]
 pub mod values;
 #[macro_use]
 pub mod viewport;
 
 pub use crate::specified_value_info::{CssType, KeywordsCollectFn, SpecifiedValueInfo};
 pub use crate::values::{