Merge mozilla-central to autoland. a=merge CLOSED TREE
authorGurzau Raul <rgurzau@mozilla.com>
Mon, 11 Mar 2019 11:39:53 +0200
changeset 521325 6e04cf2319d2c6513fc0d4e5df6cfd42e087d1fe
parent 521324 90de1c90ae69901ff38e5e1c95f9f09ac73313be (current diff)
parent 521309 cdb2110b85f32263e6213ee39e6cc9dc37945a03 (diff)
child 521326 cde32a9377303e91de8854649b704ae082c4cd5f
push id10866
push usernerli@mozilla.com
push dateTue, 12 Mar 2019 18:59:09 +0000
treeherdermozilla-beta@445c24a51727 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone67.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge mozilla-central to autoland. a=merge CLOSED TREE
--- a/js/src/builtin/TypedObject.cpp
+++ b/js/src/builtin/TypedObject.cpp
@@ -2312,17 +2312,17 @@ bool TypedObject::construct(JSContext* c
     JSContext* cx, js::gc::AllocKind kind, js::gc::InitialHeap heap,
     js::HandleShape shape, js::HandleObjectGroup group) {
   debugCheckNewObject(group, shape, kind, heap);
 
   const js::Class* clasp = group->clasp();
   MOZ_ASSERT(::IsTypedObjectClass(clasp));
 
   JSObject* obj =
-      js::AllocateObject(cx, kind, /* nDynamicSlots = */ 0, heap, clasp);
+      js::Allocate<JSObject>(cx, kind, /* nDynamicSlots = */ 0, heap, clasp);
   if (!obj) {
     return cx->alreadyReportedOOM();
   }
 
   TypedObject* tobj = static_cast<TypedObject*>(obj);
   tobj->initGroup(group);
   tobj->initShape(shape);
 
--- a/js/src/gc/Allocator.cpp
+++ b/js/src/gc/Allocator.cpp
@@ -20,19 +20,21 @@
 #include "gc/ArenaList-inl.h"
 #include "gc/Heap-inl.h"
 #include "gc/PrivateIterators-inl.h"
 #include "vm/JSObject-inl.h"
 
 using namespace js;
 using namespace gc;
 
-template <AllowGC allowGC /* = CanGC */>
-JSObject* js::AllocateObject(JSContext* cx, AllocKind kind, size_t nDynamicSlots,
-                             InitialHeap heap, const Class* clasp) {
+template <typename T, AllowGC allowGC /* = CanGC */>
+JSObject* js::Allocate(JSContext* cx, AllocKind kind, size_t nDynamicSlots,
+                       InitialHeap heap, const Class* clasp) {
+  static_assert(mozilla::IsConvertible<T*, JSObject*>::value,
+                "must be JSObject derived");
   MOZ_ASSERT(IsObjectAllocKind(kind));
   size_t thingSize = Arena::thingSize(kind);
 
   MOZ_ASSERT(thingSize == Arena::thingSize(kind));
   MOZ_ASSERT(thingSize >= sizeof(JSObject_Slots0));
   static_assert(
       sizeof(JSObject_Slots0) >= MinCellSize,
       "All allocations must be at least the allocator-imposed minimum size.");
@@ -70,26 +72,26 @@ JSObject* js::AllocateObject(JSContext* 
     if (!allowGC) {
       return nullptr;
     }
   }
 
   return GCRuntime::tryNewTenuredObject<allowGC>(cx, kind, thingSize,
                                                  nDynamicSlots);
 }
-template JSObject* js::AllocateObject<NoGC>(JSContext* cx,
-                                            gc::AllocKind kind,
-                                            size_t nDynamicSlots,
-                                            gc::InitialHeap heap,
-                                            const Class* clasp);
-template JSObject* js::AllocateObject<CanGC>(JSContext* cx,
-                                               gc::AllocKind kind,
-                                               size_t nDynamicSlots,
-                                               gc::InitialHeap heap,
-                                               const Class* clasp);
+template JSObject* js::Allocate<JSObject, NoGC>(JSContext* cx,
+                                                gc::AllocKind kind,
+                                                size_t nDynamicSlots,
+                                                gc::InitialHeap heap,
+                                                const Class* clasp);
+template JSObject* js::Allocate<JSObject, CanGC>(JSContext* cx,
+                                                 gc::AllocKind kind,
+                                                 size_t nDynamicSlots,
+                                                 gc::InitialHeap heap,
+                                                 const Class* clasp);
 
 // Attempt to allocate a new JSObject out of the nursery. If there is not
 // enough room in the nursery or there is an OOM, this method will return
 // nullptr.
 template <AllowGC allowGC>
 JSObject* GCRuntime::tryNewNurseryObject(JSContext* cx, size_t thingSize,
                                          size_t nDynamicSlots,
                                          const Class* clasp) {
@@ -170,17 +172,17 @@ JSString* GCRuntime::tryNewNurseryString
       return static_cast<JSString*>(
           cx->nursery().allocateString(cx->zone(), thingSize, kind));
     }
   }
   return nullptr;
 }
 
 template <typename StringAllocT, AllowGC allowGC /* = CanGC */>
-StringAllocT* js::AllocateStringImpl(JSContext* cx, InitialHeap heap) {
+StringAllocT* js::AllocateString(JSContext* cx, InitialHeap heap) {
   static_assert(mozilla::IsConvertible<StringAllocT*, JSString*>::value,
                 "must be JSString derived");
 
   AllocKind kind = MapTypeToFinalizeKind<StringAllocT>::kind;
   size_t size = sizeof(StringAllocT);
   MOZ_ASSERT(size == Arena::thingSize(kind));
   MOZ_ASSERT(size == sizeof(JSString) || size == sizeof(JSFatInlineString));
 
@@ -217,20 +219,20 @@ StringAllocT* js::AllocateStringImpl(JSC
     }
   }
 
   return GCRuntime::tryNewTenuredThing<StringAllocT, allowGC>(cx, kind, size);
 }
 
 #define DECL_ALLOCATOR_INSTANCES(allocKind, traceKind, type, sizedType, \
                                  bgfinal, nursery, compact)             \
-  template type* js::AllocateStringImpl<type, NoGC>(JSContext * cx,     \
-                                                    InitialHeap heap);  \
-  template type* js::AllocateStringImpl<type, CanGC>(JSContext * cx,    \
-                                                     InitialHeap heap);
+  template type* js::AllocateString<type, NoGC>(JSContext * cx,         \
+                                                InitialHeap heap);      \
+  template type* js::AllocateString<type, CanGC>(JSContext * cx,        \
+                                                 InitialHeap heap);
 FOR_EACH_NURSERY_STRING_ALLOCKIND(DECL_ALLOCATOR_INSTANCES)
 #undef DECL_ALLOCATOR_INSTANCES
 
 template <typename T, AllowGC allowGC /* = CanGC */>
 T* js::Allocate(JSContext* cx) {
   static_assert(!mozilla::IsConvertible<T*, JSObject*>::value,
                 "must not be JSObject derived");
   static_assert(
--- a/js/src/gc/Allocator.h
+++ b/js/src/gc/Allocator.h
@@ -12,59 +12,54 @@
 #include "js/RootingAPI.h"
 
 class JSFatInlineString;
 
 namespace js {
 
 struct Class;
 
-// Allocate a new GC thing that's not a JSObject or a string.
-//
-// After a successful allocation the caller must fully initialize the thing
-// before calling any function that can potentially trigger GC. This will ensure
-// that GC tracing never sees junk values stored in the partially initialized
-// thing.
+// Allocate a new GC thing. After a successful allocation the caller must
+// fully initialize the thing before calling any function that can potentially
+// trigger GC. This will ensure that GC tracing never sees junk values stored
+// in the partially initialized thing.
+
 template <typename T, AllowGC allowGC = CanGC>
 T* Allocate(JSContext* cx);
 
-// Allocate a JSObject.
-//
-// A longer signature that includes additional information in support of various
-// optimizations. If dynamic slots are requested they will be allocated and the
-// pointer stored directly in |NativeObject::slots_|.
-template <AllowGC allowGC = CanGC>
-JSObject* AllocateObject(JSContext* cx, gc::AllocKind kind, size_t nDynamicSlots,
-                         gc::InitialHeap heap, const Class* clasp);
+// Use for JSObject. A longer signature that includes additional information in
+// support of various optimizations. If dynamic slots are requested they will be
+// allocated and the pointer stored directly in |NativeObject::slots_|.
+template <typename, AllowGC allowGC = CanGC>
+JSObject* Allocate(JSContext* cx, gc::AllocKind kind, size_t nDynamicSlots,
+                   gc::InitialHeap heap, const Class* clasp);
 
 // Internal function used for nursery-allocatable strings.
 template <typename StringAllocT, AllowGC allowGC = CanGC>
-StringAllocT* AllocateStringImpl(JSContext* cx, gc::InitialHeap heap);
+StringAllocT* AllocateString(JSContext* cx, gc::InitialHeap heap);
 
-// Allocate a string.
-//
 // Use for nursery-allocatable strings. Returns a value cast to the correct
 // type.
 template <typename StringT, AllowGC allowGC = CanGC>
-StringT* AllocateString(JSContext* cx, gc::InitialHeap heap) {
-  return static_cast<StringT*>(AllocateStringImpl<JSString, allowGC>(cx, heap));
+StringT* Allocate(JSContext* cx, gc::InitialHeap heap) {
+  return static_cast<StringT*>(js::AllocateString<JSString, allowGC>(cx, heap));
 }
 
 // Specialization for JSFatInlineString that must use a different allocation
 // type. Note that we have to explicitly specialize for both values of AllowGC
 // because partial function specialization is not allowed.
 template <>
-inline JSFatInlineString* AllocateString<JSFatInlineString, CanGC>(
+inline JSFatInlineString* Allocate<JSFatInlineString, CanGC>(
     JSContext* cx, gc::InitialHeap heap) {
   return static_cast<JSFatInlineString*>(
-      js::AllocateStringImpl<JSFatInlineString, CanGC>(cx, heap));
+      js::AllocateString<JSFatInlineString, CanGC>(cx, heap));
 }
 
 template <>
-inline JSFatInlineString* AllocateString<JSFatInlineString, NoGC>(
+inline JSFatInlineString* Allocate<JSFatInlineString, NoGC>(
     JSContext* cx, gc::InitialHeap heap) {
   return static_cast<JSFatInlineString*>(
-      js::AllocateStringImpl<JSFatInlineString, NoGC>(cx, heap));
+      js::AllocateString<JSFatInlineString, NoGC>(cx, heap));
 }
 
 }  // namespace js
 
 #endif  // gc_Allocator_h
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -2397,22 +2397,22 @@ void CreateDependentString::generate(Mac
     masm.PopRegsInMask(regsToSave);
   }
 
   masm.bind(&done);
 }
 
 static void* AllocateString(JSContext* cx) {
   AutoUnsafeCallWithABI unsafe;
-  return js::AllocateString<JSString, NoGC>(cx, js::gc::TenuredHeap);
+  return js::Allocate<JSString, NoGC>(cx, js::gc::TenuredHeap);
 }
 
 static void* AllocateFatInlineString(JSContext* cx) {
   AutoUnsafeCallWithABI unsafe;
-  return js::AllocateString<JSFatInlineString, NoGC>(cx, js::gc::TenuredHeap);
+  return js::Allocate<JSFatInlineString, NoGC>(cx, js::gc::TenuredHeap);
 }
 
 void CreateDependentString::generateFallback(MacroAssembler& masm) {
   JitSpew(JitSpew_Codegen,
           "# Emitting CreateDependentString fallback (encoding=%s)",
           (encoding_ == CharEncoding::Latin1 ? "Latin-1" : "Two-Byte"));
 
   LiveRegisterSet regsToSave(RegisterSet::Volatile());
@@ -2438,18 +2438,18 @@ void CreateDependentString::generateFall
 
     masm.jump(&joins_[kind]);
   }
 }
 
 static void* CreateMatchResultFallbackFunc(JSContext* cx, gc::AllocKind kind,
                                            size_t nDynamicSlots) {
   AutoUnsafeCallWithABI unsafe;
-  return js::AllocateObject<NoGC>(cx, kind, nDynamicSlots, gc::DefaultHeap,
-                                  &ArrayObject::class_);
+  return js::Allocate<JSObject, NoGC>(cx, kind, nDynamicSlots, gc::DefaultHeap,
+                                      &ArrayObject::class_);
 }
 
 static void CreateMatchResultFallback(MacroAssembler& masm, Register object,
                                       Register temp1, Register temp2,
                                       const TemplateObject& templateObject,
                                       Label* fail) {
   JitSpew(JitSpew_Codegen, "# Emitting CreateMatchResult fallback");
 
--- a/js/src/vm/ArrayObject-inl.h
+++ b/js/src/vm/ArrayObject-inl.h
@@ -45,17 +45,17 @@ inline void ArrayObject::setLength(JSCon
   MOZ_ASSERT_IF(group->shouldPreTenureDontCheckGeneration(),
                 heap == gc::TenuredHeap);
 
   // Arrays can use their fixed slots to store elements, so can't have shapes
   // which allow named properties to be stored in the fixed slots.
   MOZ_ASSERT(shape->numFixedSlots() == 0);
 
   size_t nDynamicSlots = dynamicSlotsCount(0, shape->slotSpan(), clasp);
-  JSObject* obj = js::AllocateObject(cx, kind, nDynamicSlots, heap, clasp);
+  JSObject* obj = js::Allocate<JSObject>(cx, kind, nDynamicSlots, heap, clasp);
   if (!obj) {
     return nullptr;
   }
 
   ArrayObject* aobj = static_cast<ArrayObject*>(obj);
   aobj->initGroup(group);
   aobj->initShape(shape);
   // NOTE: Dynamic slots are created internally by Allocate<JSObject>.
--- a/js/src/vm/Caches-inl.h
+++ b/js/src/vm/Caches-inl.h
@@ -68,18 +68,18 @@ inline NativeObject* NewObjectCache::new
     }
   }
 
   if (cx->runtime()->gc.upcomingZealousGC()) {
     return nullptr;
   }
 
   NativeObject* obj = static_cast<NativeObject*>(
-      AllocateObject<NoGC>(cx, entry->kind, /* nDynamicSlots = */ 0,
-                           heap, group->clasp()));
+      Allocate<JSObject, NoGC>(cx, entry->kind,
+                               /* nDynamicSlots = */ 0, heap, group->clasp()));
   if (!obj) {
     return nullptr;
   }
 
   copyCachedToObject(obj, templateObj, entry->kind);
 
   if (group->clasp()->shouldDelayMetadataBuilder()) {
     cx->realm()->setObjectPendingMetadata(cx, obj);
--- a/js/src/vm/JSFunction-inl.h
+++ b/js/src/vm/JSFunction-inl.h
@@ -108,17 +108,18 @@ inline JSFunction* CloneFunctionObjectIf
 
   const js::Class* clasp = group->clasp();
   MOZ_ASSERT(clasp->isJSFunction());
 
   static constexpr size_t NumDynamicSlots = 0;
   MOZ_ASSERT(dynamicSlotsCount(shape->numFixedSlots(), shape->slotSpan(),
                                clasp) == NumDynamicSlots);
 
-  JSObject* obj = js::AllocateObject(cx, kind, NumDynamicSlots, heap, clasp);
+  JSObject* obj =
+      js::Allocate<JSObject>(cx, kind, NumDynamicSlots, heap, clasp);
   if (!obj) {
     return cx->alreadyReportedOOM();
   }
 
   NativeObject* nobj = static_cast<NativeObject*>(obj);
   nobj->initGroup(group);
   nobj->initShape(shape);
 
--- a/js/src/vm/NativeObject-inl.h
+++ b/js/src/vm/NativeObject-inl.h
@@ -483,17 +483,17 @@ inline bool NativeObject::isInWholeCellB
 
   const js::Class* clasp = group->clasp();
   MOZ_ASSERT(clasp->isNative());
   MOZ_ASSERT(!clasp->isJSFunction(), "should use JSFunction::create");
 
   size_t nDynamicSlots =
       dynamicSlotsCount(shape->numFixedSlots(), shape->slotSpan(), clasp);
 
-  JSObject* obj = js::AllocateObject(cx, kind, nDynamicSlots, heap, clasp);
+  JSObject* obj = js::Allocate<JSObject>(cx, kind, nDynamicSlots, heap, clasp);
   if (!obj) {
     return cx->alreadyReportedOOM();
   }
 
   NativeObject* nobj = static_cast<NativeObject*>(obj);
   nobj->initGroup(group);
   nobj->initShape(shape);
   // NOTE: Dynamic slots are created internally by Allocate<JSObject>.
--- a/js/src/vm/ProxyObject.cpp
+++ b/js/src/vm/ProxyObject.cpp
@@ -182,18 +182,18 @@ void ProxyObject::nuke() {
 
     MOZ_ASSERT(group->realm() == realm);
     realm->newProxyCache.add(group, shape);
   }
 
   gc::InitialHeap heap = GetInitialHeap(newKind, group);
   debugCheckNewObject(group, shape, allocKind, heap);
 
-  JSObject* obj = js::AllocateObject(cx, allocKind, /* nDynamicSlots = */ 0,
-                                     heap, clasp);
+  JSObject* obj = js::Allocate<JSObject>(cx, allocKind, /* nDynamicSlots = */ 0,
+                                         heap, clasp);
   if (!obj) {
     return cx->alreadyReportedOOM();
   }
 
   ProxyObject* pobj = static_cast<ProxyObject*>(obj);
   pobj->initGroup(group);
   pobj->initShape(shape);
 
--- a/js/src/vm/StringType-inl.h
+++ b/js/src/vm/StringType-inl.h
@@ -154,17 +154,17 @@ template <js::AllowGC allowGC>
 MOZ_ALWAYS_INLINE JSRope* JSRope::new_(
     JSContext* cx,
     typename js::MaybeRooted<JSString*, allowGC>::HandleType left,
     typename js::MaybeRooted<JSString*, allowGC>::HandleType right,
     size_t length, js::gc::InitialHeap heap) {
   if (!validateLength(cx, length)) {
     return nullptr;
   }
-  JSRope* str = js::AllocateString<JSRope, allowGC>(cx, heap);
+  JSRope* str = js::Allocate<JSRope, allowGC>(cx, heap);
   if (!str) {
     return nullptr;
   }
   str->init(cx, left, right, length);
   return str;
 }
 
 MOZ_ALWAYS_INLINE void JSDependentString::init(JSContext* cx,
@@ -215,25 +215,25 @@ MOZ_ALWAYS_INLINE JSLinearString* JSDepe
                : js::NewInlineString<char16_t>(cx, base, start, length);
   }
 
   if (baseArg->isExternal() && !baseArg->ensureFlat(cx)) {
     return nullptr;
   }
 
   JSDependentString* str =
-      js::AllocateString<JSDependentString, js::NoGC>(cx, js::gc::DefaultHeap);
+      js::Allocate<JSDependentString, js::NoGC>(cx, js::gc::DefaultHeap);
   if (str) {
     str->init(cx, baseArg, start, length);
     return str;
   }
 
   js::RootedLinearString base(cx, baseArg);
 
-  str = js::AllocateString<JSDependentString>(cx, js::gc::DefaultHeap);
+  str = js::Allocate<JSDependentString>(cx, js::gc::DefaultHeap);
   if (!str) {
     return nullptr;
   }
   str->init(cx, base, start, length);
   return str;
 }
 
 MOZ_ALWAYS_INLINE void JSFlatString::init(const char16_t* chars,
@@ -257,17 +257,17 @@ MOZ_ALWAYS_INLINE JSFlatString* JSFlatSt
   if (!validateLength(cx, length)) {
     return nullptr;
   }
 
   JSFlatString* str;
   if (cx->zone()->isAtomsZone()) {
     str = js::Allocate<js::NormalAtom, allowGC>(cx);
   } else {
-    str = js::AllocateString<JSFlatString, allowGC>(cx, js::gc::DefaultHeap);
+    str = js::Allocate<JSFlatString, allowGC>(cx, js::gc::DefaultHeap);
   }
   if (!str) {
     return nullptr;
   }
 
   if (!str->isTenured()) {
     // The chars pointer is only considered to be handed over to this
     // function on a successful return. If the following registration
@@ -303,26 +303,26 @@ inline js::PropertyName* JSFlatString::t
 }
 
 template <js::AllowGC allowGC>
 MOZ_ALWAYS_INLINE JSThinInlineString* JSThinInlineString::new_(JSContext* cx) {
   if (cx->zone()->isAtomsZone()) {
     return (JSThinInlineString*)(js::Allocate<js::NormalAtom, allowGC>(cx));
   }
 
-  return js::AllocateString<JSThinInlineString, allowGC>(cx, js::gc::DefaultHeap);
+  return js::Allocate<JSThinInlineString, allowGC>(cx, js::gc::DefaultHeap);
 }
 
 template <js::AllowGC allowGC>
 MOZ_ALWAYS_INLINE JSFatInlineString* JSFatInlineString::new_(JSContext* cx) {
   if (cx->zone()->isAtomsZone()) {
     return (JSFatInlineString*)(js::Allocate<js::FatInlineAtom, allowGC>(cx));
   }
 
-  return js::AllocateString<JSFatInlineString, allowGC>(cx, js::gc::DefaultHeap);
+  return js::Allocate<JSFatInlineString, allowGC>(cx, js::gc::DefaultHeap);
 }
 
 template <>
 MOZ_ALWAYS_INLINE JS::Latin1Char* JSThinInlineString::init<JS::Latin1Char>(
     size_t length) {
   MOZ_ASSERT(lengthFits<JS::Latin1Char>(length));
   setLengthAndFlags(length, INIT_THIN_INLINE_FLAGS | LATIN1_CHARS_BIT);
   return d.inlineStorageLatin1;
--- a/js/src/vm/UnboxedObject.cpp
+++ b/js/src/vm/UnboxedObject.cpp
@@ -841,17 +841,17 @@ NativeObject* UnboxedPlainObject::conver
   MOZ_ASSERT(clasp == &UnboxedPlainObject::class_);
 
   MOZ_ASSERT(CanBeFinalizedInBackground(kind, clasp));
   kind = GetBackgroundAllocKind(kind);
 
   debugCheckNewObject(group, /* shape = */ nullptr, kind, heap);
 
   JSObject* obj =
-      js::AllocateObject(cx, kind, /* nDynamicSlots = */ 0, heap, clasp);
+      js::Allocate<JSObject>(cx, kind, /* nDynamicSlots = */ 0, heap, clasp);
   if (!obj) {
     return cx->alreadyReportedOOM();
   }
 
   UnboxedObject* uobj = static_cast<UnboxedObject*>(obj);
   uobj->initGroup(group);
 
   MOZ_ASSERT(clasp->shouldDelayMetadataBuilder());
--- a/tools/profiler/lul/LulMain.cpp
+++ b/tools/profiler/lul/LulMain.cpp
@@ -1451,16 +1451,77 @@ void LUL::Unwind(/*OUT*/ uintptr_t* aFra
           regs.xbp = new_xbp;
           regs.xip = new_xip;
           regs.xsp = new_xsp;
           (*aFramePointerFramesAcquired)++;
           continue;
         }
       }
     }
+#elif defined(GP_ARCH_arm64)
+    // Here is an example of generated code for prologue and epilogue..
+    //
+    // stp     x29, x30, [sp, #-16]!
+    // mov     x29, sp
+    // ...
+    // ldp     x29, x30, [sp], #16
+    // ret
+    //
+    // Next is another example of generated code.
+    //
+    // stp     x20, x19, [sp, #-32]!
+    // stp     x29, x30, [sp, #16]
+    // add     x29, sp, #0x10
+    // ...
+    // ldp     x29, x30, [sp, #16]
+    // ldp     x20, x19, [sp], #32
+    // ret
+    //
+    // Previous x29 and x30 register are stored in the address of x29 register.
+    // But since sp register value depends on local variables, we cannot compute
+    // previous sp register from current sp/fp/lr register and there is no
+    // regular rule for sp register in prologue. But since return address is lr
+    // register, if x29 is valid, we will get return address without sp
+    // register.
+    //
+    // So we assume the following layout that if no rule set. x29 is frame
+    // pointer, so we will be able to compute x29 and x30 .
+    //
+    //   +----------+  <--- new_sp (cannot compute)
+    //   |   ....   |
+    //   +----------+
+    //   |  new_lr  |  (return address)
+    //   +----------+
+    //   |  new_fp  |  <--- old_fp
+    //   +----------+
+    //   |   ....   |
+    //   |   ....   |
+    //   +----------+  <---- old_sp (arbitrary, but unused)
+
+    TaggedUWord old_fp = regs.x29;
+    if (old_fp.Valid() && old_fp.IsAligned() && last_valid_sp.Valid() &&
+        last_valid_sp.Value() <= old_fp.Value()) {
+      TaggedUWord new_fp = DerefTUW(old_fp, aStackImg);
+      if (new_fp.Valid() && new_fp.IsAligned() &&
+          old_fp.Value() < new_fp.Value()) {
+        TaggedUWord old_fp_plus1 = old_fp + TaggedUWord(8);
+        TaggedUWord new_lr = DerefTUW(old_fp_plus1, aStackImg);
+        if (new_lr.Valid()) {
+          regs.x29 = new_fp;
+          regs.x30 = new_lr;
+          // When using frame pointer to walk stack, we cannot compute sp
+          // register since we cannot compute sp register from fp/lr/sp
+          // register, and there is no regular rule to compute previous sp
+          // register. So mark as invalid.
+          regs.sp = TaggedUWord();
+          (*aFramePointerFramesAcquired)++;
+          continue;
+        }
+      }
+    }
 #endif  // defined(GP_PLAT_amd64_linux) || defined(GP_PLAT_x86_linux)
 
     // We failed to recover a frame either using CFI or FP chasing, and we
     // have no other ways to recover the frame.  So we have to give up.
     break;
 
   }  // top level unwind loop