Merge mozilla-inbound to mozilla-central a=merge
authorRazvan Maries <rmaries@mozilla.com>
Wed, 16 Jan 2019 19:00:15 +0200
changeset 454091 1312db5d495953cc6e18b16d082d06d611a21166
parent 454083 6e8f0fdbe2e21fbf8db2bbfe1cefd5ba13ea665b (current diff)
parent 454090 036c3b7cde376187c8df91f7d764e528371adace (diff)
child 454112 fb629855a3bbed86fb68cb7d2e42f9486f7f81be
child 454206 3c6af4081f3a1494e47daed014cfc65d784cc208
push id35386
push userrmaries@mozilla.com
push dateWed, 16 Jan 2019 17:01:05 +0000
treeherdermozilla-central@1312db5d4959 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone66.0a1
first release with
nightly linux32
1312db5d4959 / 66.0a1 / 20190116170105 / files
nightly linux64
1312db5d4959 / 66.0a1 / 20190116170105 / files
nightly mac
1312db5d4959 / 66.0a1 / 20190116170105 / files
nightly win32
1312db5d4959 / 66.0a1 / 20190116170105 / files
nightly win64
1312db5d4959 / 66.0a1 / 20190116170105 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge mozilla-inbound to mozilla-central a=merge
dom/base/Document.cpp
dom/base/Document.h
layout/generic/nsIFrame.h
layout/generic/nsImageFrame.cpp
layout/generic/nsTextFrame.cpp
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::{