Bug 1320670 part 2 - Use GetPropIRGenerator for GETELEM stubs in Baseline. r=h4writer
authorJan de Mooij <jdemooij@mozilla.com>
Mon, 05 Dec 2016 15:44:35 -1000
changeset 325300 17f5bc695acc81a98f34c95eef31454c1706aa56
parent 325299 6b75807ac2e04eb448ed0f6c1b27b526e17a0669
child 325301 93d785448a69cd60c7105bfe722cfd94b6d59b37
push id24
push usermaklebus@msu.edu
push dateTue, 20 Dec 2016 03:11:33 +0000
reviewersh4writer
bugs1320670
milestone53.0a1
Bug 1320670 part 2 - Use GetPropIRGenerator for GETELEM stubs in Baseline. r=h4writer
js/src/jit/BaselineCacheIR.cpp
js/src/jit/BaselineDebugModeOSR.cpp
js/src/jit/BaselineIC.cpp
js/src/jit/BaselineIC.h
js/src/jit/BaselineICList.h
js/src/jit/BaselineInspector.cpp
js/src/jit/CacheIR.cpp
js/src/jit/CacheIR.h
js/src/jit/IonCaches.cpp
js/src/jit/IonCaches.h
js/src/jit/SharedIC.cpp
js/src/jit/VMFunctions.cpp
js/src/jit/VMFunctions.h
--- a/js/src/jit/BaselineCacheIR.cpp
+++ b/js/src/jit/BaselineCacheIR.cpp
@@ -929,16 +929,27 @@ BaselineCacheIRCompiler::emitGuardIsStri
     FailurePath* failure;
     if (!addFailurePath(&failure))
         return false;
     masm.branchTestString(Assembler::NotEqual, input, failure->label());
     return true;
 }
 
 bool
+BaselineCacheIRCompiler::emitGuardIsSymbol()
+{
+    ValueOperand input = allocator.useValueRegister(masm, reader.valOperandId());
+    FailurePath* failure;
+    if (!addFailurePath(&failure))
+        return false;
+    masm.branchTestSymbol(Assembler::NotEqual, input, failure->label());
+    return true;
+}
+
+bool
 BaselineCacheIRCompiler::emitGuardType()
 {
     ValueOperand input = allocator.useValueRegister(masm, reader.valOperandId());
     JSValueType type = reader.valueType();
 
     FailurePath* failure;
     if (!addFailurePath(&failure))
         return false;
@@ -1087,16 +1098,77 @@ BaselineCacheIRCompiler::emitGuardSpecif
         return false;
 
     Address addr(stubAddress(reader.stubOffset()));
     masm.branchPtr(Assembler::NotEqual, addr, obj, failure->label());
     return true;
 }
 
 bool
+BaselineCacheIRCompiler::emitGuardSpecificAtom()
+{
+    Register str = allocator.useRegister(masm, reader.stringOperandId());
+    AutoScratchRegister scratch(allocator, masm);
+
+    FailurePath* failure;
+    if (!addFailurePath(&failure))
+        return false;
+
+    Address atomAddr(stubAddress(reader.stubOffset()));
+
+    Label done;
+    masm.branchPtr(Assembler::Equal, atomAddr, str, &done);
+
+    // The pointers are not equal, so if the input string is also an atom it
+    // must be a different string.
+    masm.branchTest32(Assembler::NonZero, Address(str, JSString::offsetOfFlags()),
+                      Imm32(JSString::ATOM_BIT), failure->label());
+
+    // Check the length.
+    masm.loadPtr(atomAddr, scratch);
+    masm.loadStringLength(scratch, scratch);
+    masm.branch32(Assembler::NotEqual, Address(str, JSString::offsetOfLength()),
+                  scratch, failure->label());
+
+    // We have a non-atomized string with the same length. Call a helper
+    // function to do the comparison.
+    LiveRegisterSet volatileRegs(RegisterSet::Volatile());
+    masm.PushRegsInMask(volatileRegs);
+
+    masm.setupUnalignedABICall(scratch);
+    masm.loadPtr(atomAddr, scratch);
+    masm.passABIArg(scratch);
+    masm.passABIArg(str);
+    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, EqualStringsHelper));
+    masm.mov(ReturnReg, scratch);
+
+    LiveRegisterSet ignore;
+    ignore.add(scratch);
+    masm.PopRegsInMaskIgnore(volatileRegs, ignore);
+    masm.branchIfFalseBool(scratch, failure->label());
+
+    masm.bind(&done);
+    return true;
+}
+
+bool
+BaselineCacheIRCompiler::emitGuardSpecificSymbol()
+{
+    Register sym = allocator.useRegister(masm, reader.symbolOperandId());
+
+    FailurePath* failure;
+    if (!addFailurePath(&failure))
+        return false;
+
+    Address addr(stubAddress(reader.stubOffset()));
+    masm.branchPtr(Assembler::NotEqual, addr, sym, failure->label());
+    return true;
+}
+
+bool
 BaselineCacheIRCompiler::emitGuardMagicValue()
 {
     ValueOperand val = allocator.useValueRegister(masm, reader.valOperandId());
     JSWhyMagic magic = reader.whyMagic();
 
     FailurePath* failure;
     if (!addFailurePath(&failure))
         return false;
@@ -1281,16 +1353,44 @@ BaselineCacheIRCompiler::emitCallProxyGe
 
     if (!callVM(masm, ProxyGetPropertyInfo))
         return false;
 
     stubFrame.leave(masm);
     return true;
 }
 
+typedef bool (*ProxyGetPropertyByValueFn)(JSContext*, HandleObject, HandleValue, MutableHandleValue);
+static const VMFunction ProxyGetPropertyByValueInfo =
+    FunctionInfo<ProxyGetPropertyByValueFn>(ProxyGetPropertyByValue, "ProxyGetPropertyByValue");
+
+bool
+BaselineCacheIRCompiler::emitCallProxyGetByValueResult()
+{
+    AutoStubFrame stubFrame(*this);
+
+    Register obj = allocator.useRegister(masm, reader.objOperandId());
+    ValueOperand idVal = allocator.useValueRegister(masm, reader.valOperandId());
+
+    AutoScratchRegister scratch(allocator, masm);
+
+    allocator.discardStack(masm);
+
+    stubFrame.enter(masm, scratch);
+
+    masm.Push(idVal);
+    masm.Push(obj);
+
+    if (!callVM(masm, ProxyGetPropertyByValueInfo))
+        return false;
+
+    stubFrame.leave(masm);
+    return true;
+}
+
 bool
 BaselineCacheIRCompiler::emitLoadUnboxedPropertyResult()
 {
     Register obj = allocator.useRegister(masm, reader.objOperandId());
     AutoScratchRegister scratch(allocator, masm);
 
     JSValueType fieldType = reader.valueType();
     Address fieldOffset(stubAddress(reader.stubOffset()));
@@ -1572,18 +1672,21 @@ BaselineCacheIRCompiler::emitGuardDOMExp
 
 bool
 BaselineCacheIRCompiler::init(CacheKind kind)
 {
     size_t numInputs = writer_.numInputOperands();
     if (!allocator.init(ICStubCompiler::availableGeneralRegs(numInputs)))
         return false;
 
-    MOZ_ASSERT(numInputs == 1);
-    allocator.initInputLocation(0, R0);
+    if (numInputs >= 1) {
+        allocator.initInputLocation(0, R0);
+        if (numInputs >= 2)
+            allocator.initInputLocation(1, R1);
+    }
 
     return true;
 }
 
 template <typename T>
 static GCPtr<T>*
 AsGCPtr(uintptr_t* ptr)
 {
@@ -1626,16 +1729,22 @@ CacheIRWriter::copyStubData(uint8_t* des
             InitGCPtr<Shape*>(destWords, stubFields_[i].asWord());
             break;
           case StubField::Type::JSObject:
             InitGCPtr<JSObject*>(destWords, stubFields_[i].asWord());
             break;
           case StubField::Type::ObjectGroup:
             InitGCPtr<ObjectGroup*>(destWords, stubFields_[i].asWord());
             break;
+          case StubField::Type::Symbol:
+            InitGCPtr<JS::Symbol*>(destWords, stubFields_[i].asWord());
+            break;
+          case StubField::Type::String:
+            InitGCPtr<JSString*>(destWords, stubFields_[i].asWord());
+            break;
           case StubField::Type::Id:
             InitGCPtr<jsid>(destWords, stubFields_[i].asWord());
             break;
           case StubField::Type::RawInt64:
             *reinterpret_cast<uint64_t*>(destWords) = stubFields_[i].asInt64();
             break;
           case StubField::Type::Value:
             InitGCPtr<JS::Value>(destWords, stubFields_[i].asInt64());
@@ -1720,17 +1829,17 @@ jit::AttachBaselineCacheIRStub(JSContext
 
     if (writer.failed())
         return nullptr;
 
     // Just a sanity check: the caller should ensure we don't attach an
     // unlimited number of stubs.
     MOZ_ASSERT(stub->numOptimizedStubs() < MaxOptimizedCacheIRStubs);
 
-    MOZ_ASSERT(kind == CacheKind::GetProp);
+    MOZ_ASSERT(kind == CacheKind::GetProp || kind == CacheKind::GetElem);
     uint32_t stubDataOffset = sizeof(ICCacheIR_Monitored);
 
     JitCompartment* jitCompartment = cx->compartment()->jitCompartment();
 
     // Check if we already have JitCode for this stub.
     CacheIRStubInfo* stubInfo;
     CacheIRStubKey::Lookup lookup(kind, engine, writer.codeStart(), writer.codeLength());
     JitCode* code = jitCompartment->getCacheIRStubCode(lookup, &stubInfo);
@@ -1800,16 +1909,24 @@ jit::TraceBaselineCacheIRStub(JSTracer* 
           case StubField::Type::ObjectGroup:
             TraceNullableEdge(trc, &stubInfo->getStubField<ObjectGroup*>(stub, offset),
                               "baseline-cacheir-group");
             break;
           case StubField::Type::JSObject:
             TraceNullableEdge(trc, &stubInfo->getStubField<JSObject*>(stub, offset),
                               "baseline-cacheir-object");
             break;
+          case StubField::Type::Symbol:
+            TraceNullableEdge(trc, &stubInfo->getStubField<JS::Symbol*>(stub, offset),
+                              "baseline-cacheir-symbol");
+            break;
+          case StubField::Type::String:
+            TraceNullableEdge(trc, &stubInfo->getStubField<JSString*>(stub, offset),
+                              "baseline-cacheir-string");
+            break;
           case StubField::Type::Id:
             TraceEdge(trc, &stubInfo->getStubField<jsid>(stub, offset), "baseline-cacheir-id");
             break;
           case StubField::Type::Value:
             TraceEdge(trc, &stubInfo->getStubField<JS::Value>(stub, offset),
                       "baseline-cacheir-value");
             break;
           case StubField::Type::Limit:
@@ -1856,16 +1973,22 @@ CacheIRStubInfo::copyStubData(ICStub* sr
             getStubField<Shape*>(dest, offset).init(getStubField<Shape*>(src, offset));
             break;
           case StubField::Type::JSObject:
             getStubField<JSObject*>(dest, offset).init(getStubField<JSObject*>(src, offset));
             break;
           case StubField::Type::ObjectGroup:
             getStubField<ObjectGroup*>(dest, offset).init(getStubField<ObjectGroup*>(src, offset));
             break;
+          case StubField::Type::Symbol:
+            getStubField<JS::Symbol*>(dest, offset).init(getStubField<JS::Symbol*>(src, offset));
+            break;
+          case StubField::Type::String:
+            getStubField<JSString*>(dest, offset).init(getStubField<JSString*>(src, offset));
+            break;
           case StubField::Type::Id:
             getStubField<jsid>(dest, offset).init(getStubField<jsid>(src, offset));
             break;
           case StubField::Type::Value:
             getStubField<Value>(dest, offset).init(getStubField<Value>(src, offset));
             break;
           case StubField::Type::Limit:
             return; // Done.
--- a/js/src/jit/BaselineDebugModeOSR.cpp
+++ b/js/src/jit/BaselineDebugModeOSR.cpp
@@ -693,20 +693,16 @@ RecompileBaselineScriptForDebugMode(JSCo
     _(CacheIR_Monitored)                        \
     _(Call_Scripted)                            \
     _(Call_AnyScripted)                         \
     _(Call_Native)                              \
     _(Call_ClassHook)                           \
     _(Call_ScriptedApplyArray)                  \
     _(Call_ScriptedApplyArguments)              \
     _(Call_ScriptedFunCall)                     \
-    _(GetElem_NativePrototypeCallNativeName)    \
-    _(GetElem_NativePrototypeCallNativeSymbol)  \
-    _(GetElem_NativePrototypeCallScriptedName)  \
-    _(GetElem_NativePrototypeCallScriptedSymbol) \
     _(GetProp_CallNativeGlobal)                 \
     _(GetProp_Generic)                          \
     _(SetProp_CallScripted)                     \
     _(SetProp_CallNative)
 
 static bool
 CloneOldBaselineStub(JSContext* cx, DebugModeOSREntryVector& entries, size_t entryIndex)
 {
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -11,16 +11,17 @@
 #include "mozilla/TemplateLib.h"
 
 #include "jslibmath.h"
 #include "jstypes.h"
 
 #include "builtin/Eval.h"
 #include "builtin/SIMD.h"
 #include "gc/Policy.h"
+#include "jit/BaselineCacheIR.h"
 #include "jit/BaselineDebugModeOSR.h"
 #include "jit/BaselineJIT.h"
 #include "jit/InlinableNatives.h"
 #include "jit/JitSpewer.h"
 #include "jit/Linker.h"
 #include "jit/Lowering.h"
 #ifdef JS_ION_PERF
 # include "jit/PerfSpewer.h"
@@ -847,189 +848,16 @@ IsCacheableSetPropCall(JSContext* cx, JS
         *isTemporarilyUnoptimizable = true;
         return false;
     }
 
     *isScripted = true;
     return true;
 }
 
-template <class T>
-static bool
-GetElemNativeStubExists(ICGetElem_Fallback* stub, HandleObject obj, HandleObject holder,
-                        Handle<T> key, bool needsAtomize)
-{
-    bool indirect = (obj.get() != holder.get());
-    MOZ_ASSERT_IF(indirect, holder->isNative());
-
-    for (ICStubConstIterator iter = stub->beginChainConst(); !iter.atEnd(); iter++) {
-        if (iter->kind() != ICStub::GetElem_NativeSlotName &&
-            iter->kind() != ICStub::GetElem_NativeSlotSymbol &&
-            iter->kind() != ICStub::GetElem_NativePrototypeSlotName &&
-            iter->kind() != ICStub::GetElem_NativePrototypeSlotSymbol &&
-            iter->kind() != ICStub::GetElem_NativePrototypeCallNativeName &&
-            iter->kind() != ICStub::GetElem_NativePrototypeCallNativeSymbol &&
-            iter->kind() != ICStub::GetElem_NativePrototypeCallScriptedName &&
-            iter->kind() != ICStub::GetElem_NativePrototypeCallScriptedSymbol)
-        {
-            continue;
-        }
-
-        if (indirect && (iter->kind() != ICStub::GetElem_NativePrototypeSlotName &&
-                         iter->kind() != ICStub::GetElem_NativePrototypeSlotSymbol &&
-                         iter->kind() != ICStub::GetElem_NativePrototypeCallNativeName &&
-                         iter->kind() != ICStub::GetElem_NativePrototypeCallNativeSymbol &&
-                         iter->kind() != ICStub::GetElem_NativePrototypeCallScriptedName &&
-                         iter->kind() != ICStub::GetElem_NativePrototypeCallScriptedSymbol))
-        {
-            continue;
-        }
-
-        if(mozilla::IsSame<T, JS::Symbol*>::value !=
-           static_cast<ICGetElemNativeStub*>(*iter)->isSymbol())
-        {
-            continue;
-        }
-
-        ICGetElemNativeStubImpl<T>* getElemNativeStub =
-            reinterpret_cast<ICGetElemNativeStubImpl<T>*>(*iter);
-        if (key != getElemNativeStub->key())
-            continue;
-
-        if (ReceiverGuard(obj) != getElemNativeStub->receiverGuard())
-            continue;
-
-        // If the new stub needs atomization, and the old stub doesn't atomize, then
-        // an appropriate stub doesn't exist.
-        if (needsAtomize && !getElemNativeStub->needsAtomize())
-            continue;
-
-        // For prototype gets, check the holder and holder shape.
-        if (indirect) {
-            if (iter->isGetElem_NativePrototypeSlotName() ||
-                iter->isGetElem_NativePrototypeSlotSymbol()) {
-                ICGetElem_NativePrototypeSlot<T>* protoStub =
-                    reinterpret_cast<ICGetElem_NativePrototypeSlot<T>*>(*iter);
-
-                if (holder != protoStub->holder())
-                    continue;
-
-                if (holder->as<NativeObject>().lastProperty() != protoStub->holderShape())
-                    continue;
-            } else {
-                MOZ_ASSERT(iter->isGetElem_NativePrototypeCallNativeName() ||
-                           iter->isGetElem_NativePrototypeCallNativeSymbol() ||
-                           iter->isGetElem_NativePrototypeCallScriptedName() ||
-                           iter->isGetElem_NativePrototypeCallScriptedSymbol());
-
-                ICGetElemNativePrototypeCallStub<T>* protoStub =
-                    reinterpret_cast<ICGetElemNativePrototypeCallStub<T>*>(*iter);
-
-                if (holder != protoStub->holder())
-                    continue;
-
-                if (holder->as<NativeObject>().lastProperty() != protoStub->holderShape())
-                    continue;
-            }
-        }
-
-        return true;
-    }
-    return false;
-}
-
-template <class T>
-static void
-RemoveExistingGetElemNativeStubs(JSContext* cx, ICGetElem_Fallback* stub, HandleObject obj,
-                                 HandleObject holder, Handle<T> key, bool needsAtomize)
-{
-    bool indirect = (obj.get() != holder.get());
-    MOZ_ASSERT_IF(indirect, holder->isNative());
-
-    for (ICStubIterator iter = stub->beginChain(); !iter.atEnd(); iter++) {
-        switch (iter->kind()) {
-          case ICStub::GetElem_NativeSlotName:
-          case ICStub::GetElem_NativeSlotSymbol:
-            if (indirect)
-                continue;
-            MOZ_FALLTHROUGH;
-          case ICStub::GetElem_NativePrototypeSlotName:
-          case ICStub::GetElem_NativePrototypeSlotSymbol:
-          case ICStub::GetElem_NativePrototypeCallNativeName:
-          case ICStub::GetElem_NativePrototypeCallNativeSymbol:
-          case ICStub::GetElem_NativePrototypeCallScriptedName:
-          case ICStub::GetElem_NativePrototypeCallScriptedSymbol:
-            break;
-          default:
-            continue;
-        }
-
-        if(mozilla::IsSame<T, JS::Symbol*>::value !=
-           static_cast<ICGetElemNativeStub*>(*iter)->isSymbol())
-        {
-            continue;
-        }
-
-        ICGetElemNativeStubImpl<T>* getElemNativeStub =
-            reinterpret_cast<ICGetElemNativeStubImpl<T>*>(*iter);
-        if (key != getElemNativeStub->key())
-            continue;
-
-        if (ReceiverGuard(obj) != getElemNativeStub->receiverGuard())
-            continue;
-
-        // For prototype gets, check the holder and holder shape.
-        if (indirect) {
-            if (iter->isGetElem_NativePrototypeSlotName() ||
-                iter->isGetElem_NativePrototypeSlotSymbol()) {
-                ICGetElem_NativePrototypeSlot<T>* protoStub =
-                    reinterpret_cast<ICGetElem_NativePrototypeSlot<T>*>(*iter);
-
-                if (holder != protoStub->holder())
-                    continue;
-
-                // If the holder matches, but the holder's lastProperty doesn't match, then
-                // this stub is invalid anyway.  Unlink it.
-                if (holder->as<NativeObject>().lastProperty() != protoStub->holderShape()) {
-                    iter.unlink(cx);
-                    continue;
-                }
-            } else {
-                MOZ_ASSERT(iter->isGetElem_NativePrototypeCallNativeName() ||
-                           iter->isGetElem_NativePrototypeCallNativeSymbol() ||
-                           iter->isGetElem_NativePrototypeCallScriptedName() ||
-                           iter->isGetElem_NativePrototypeCallScriptedSymbol());
-                ICGetElemNativePrototypeCallStub<T>* protoStub =
-                    reinterpret_cast<ICGetElemNativePrototypeCallStub<T>*>(*iter);
-
-                if (holder != protoStub->holder())
-                    continue;
-
-                // If the holder matches, but the holder's lastProperty doesn't match, then
-                // this stub is invalid anyway.  Unlink it.
-                if (holder->as<NativeObject>().lastProperty() != protoStub->holderShape()) {
-                    iter.unlink(cx);
-                    continue;
-                }
-            }
-        }
-
-        // If the new stub needs atomization, and the old stub doesn't atomize, then
-        // remove the old stub.
-        if (needsAtomize && !getElemNativeStub->needsAtomize()) {
-            iter.unlink(cx);
-            continue;
-        }
-
-        // Should never get here, because this means a matching stub exists, and if
-        // a matching stub exists, this procedure should never have been called.
-        MOZ_CRASH("Procedure should never have been called.");
-    }
-}
-
 static bool
 TypedArrayGetElemStubExists(ICGetElem_Fallback* stub, HandleObject obj)
 {
     for (ICStubConstIterator iter = stub->beginChainConst(); !iter.atEnd(); iter++) {
         if (!iter->isGetElem_TypedArray())
             continue;
         if (obj->maybeShape() == iter->toGetElem_TypedArray()->shape())
             return true;
@@ -1044,41 +872,16 @@ ArgumentsGetElemStubExists(ICGetElem_Fal
         if (!iter->isGetElem_Arguments())
             continue;
         if (iter->toGetElem_Arguments()->which() == which)
             return true;
     }
     return false;
 }
 
-template <class T>
-static T
-getKey(jsid id)
-{
-    MOZ_ASSERT_UNREACHABLE("Key has to be PropertyName or Symbol");
-    return false;
-}
-
-template <>
-JS::Symbol* getKey<JS::Symbol*>(jsid id)
-{
-    if (!JSID_IS_SYMBOL(id))
-        return nullptr;
-    return JSID_TO_SYMBOL(id);
-}
-
-template <>
-PropertyName* getKey<PropertyName*>(jsid id)
-{
-    uint32_t dummy;
-    if (!JSID_IS_ATOM(id) || JSID_TO_ATOM(id)->isIndex(&dummy))
-        return nullptr;
-    return JSID_TO_ATOM(id)->asPropertyName();
-}
-
 static bool
 IsOptimizableElementPropertyName(JSContext* cx, HandleValue key, MutableHandleId idp)
 {
     if (!key.isString())
         return false;
 
     // Convert to interned property name.
     if (!ValueToId<CanGC>(cx, key, idp))
@@ -1086,237 +889,16 @@ IsOptimizableElementPropertyName(JSConte
 
     uint32_t dummy;
     if (!JSID_IS_ATOM(idp) || JSID_TO_ATOM(idp)->isIndex(&dummy))
         return false;
 
     return true;
 }
 
-template <class T>
-static bool
-checkAtomize(HandleValue key)
-{
-    MOZ_ASSERT_UNREACHABLE("Key has to be PropertyName or Symbol");
-    return false;
-}
-
-template <>
-bool checkAtomize<JS::Symbol*>(HandleValue key)
-{
-    return false;
-}
-
-template <>
-bool checkAtomize<PropertyName*>(HandleValue key)
-{
-    return !key.toString()->isAtom();
-}
-
-template <class T>
-static bool
-TryAttachNativeOrUnboxedGetValueElemStub(JSContext* cx, HandleScript script, jsbytecode* pc,
-                                         ICGetElem_Fallback* stub, HandleObject obj,
-                                         HandleValue keyVal, bool* attached)
-{
-    MOZ_ASSERT(keyVal.isString() || keyVal.isSymbol());
-
-    // Convert to id.
-    RootedId id(cx);
-    if (!ValueToId<CanGC>(cx, keyVal, &id))
-        return false;
-
-    Rooted<T> key(cx, getKey<T>(id));
-    if (!key)
-        return true;
-    bool needsAtomize = checkAtomize<T>(keyVal);
-
-    RootedShape shape(cx);
-    RootedObject holder(cx);
-    if (!EffectlesslyLookupProperty(cx, obj, id, &holder, &shape))
-        return false;
-    if (!holder || (holder != obj && !holder->isNative()))
-        return true;
-
-    // If a suitable stub already exists, nothing else to do.
-    if (GetElemNativeStubExists<T>(stub, obj, holder, key, needsAtomize))
-        return true;
-
-    // Remove any existing stubs that may interfere with the new stub being added.
-    RemoveExistingGetElemNativeStubs<T>(cx, stub, obj, holder, key, needsAtomize);
-
-    ICStub* monitorStub = stub->fallbackMonitorStub()->firstMonitorStub();
-
-    if (obj->is<UnboxedPlainObject>() && holder == obj) {
-        const UnboxedLayout::Property* property = obj->as<UnboxedPlainObject>().layout().lookup(id);
-
-        // Once unboxed objects support symbol-keys, we need to change the following accordingly
-        MOZ_ASSERT_IF(!keyVal.isString(), !property);
-
-        if (property) {
-            if (!cx->runtime()->jitSupportsFloatingPoint)
-                return true;
-
-            RootedPropertyName name(cx, JSID_TO_ATOM(id)->asPropertyName());
-            ICGetElemNativeCompiler<PropertyName*> compiler(cx, ICStub::GetElem_UnboxedPropertyName,
-                                                            monitorStub, obj, holder,
-                                                            name,
-                                                            ICGetElemNativeStub::UnboxedProperty,
-                                                            needsAtomize, property->offset +
-                                                            UnboxedPlainObject::offsetOfData(),
-                                                            property->type);
-            ICStub* newStub = compiler.getStub(compiler.getStubSpace(script));
-            if (!newStub)
-                return false;
-
-            stub->addNewStub(newStub);
-            *attached = true;
-            return true;
-        }
-
-        Shape* shape = obj->as<UnboxedPlainObject>().maybeExpando()->lookup(cx, id);
-        if (!shape->hasDefaultGetter() || !shape->hasSlot())
-            return true;
-
-        bool isFixedSlot;
-        uint32_t offset;
-        GetFixedOrDynamicSlotOffset(shape, &isFixedSlot, &offset);
-
-        ICGetElemNativeStub::AccessType acctype =
-            isFixedSlot ? ICGetElemNativeStub::FixedSlot
-                        : ICGetElemNativeStub::DynamicSlot;
-        ICGetElemNativeCompiler<T> compiler(cx, getGetElemStubKind<T>(ICStub::GetElem_NativeSlotName),
-                                            monitorStub, obj, holder, key,
-                                            acctype, needsAtomize, offset);
-        ICStub* newStub = compiler.getStub(compiler.getStubSpace(script));
-        if (!newStub)
-            return false;
-
-        stub->addNewStub(newStub);
-        *attached = true;
-        return true;
-    }
-
-    if (!holder->isNative())
-        return true;
-
-    if (IsCacheableGetPropReadSlot(obj, holder, shape)) {
-        bool isFixedSlot;
-        uint32_t offset;
-        GetFixedOrDynamicSlotOffset(shape, &isFixedSlot, &offset);
-
-        ICStub::Kind kind = (obj == holder) ? ICStub::GetElem_NativeSlotName
-                                            : ICStub::GetElem_NativePrototypeSlotName;
-        kind = getGetElemStubKind<T>(kind);
-
-        JitSpew(JitSpew_BaselineIC, "  Generating GetElem(Native %s%s slot) stub "
-                                    "(obj=%p, holder=%p, holderShape=%p)",
-                    (obj == holder) ? "direct" : "prototype",
-                    needsAtomize ? " atomizing" : "",
-                obj.get(), holder.get(), holder->as<NativeObject>().lastProperty());
-
-        AccType acctype = isFixedSlot ? ICGetElemNativeStub::FixedSlot
-                                      : ICGetElemNativeStub::DynamicSlot;
-        ICGetElemNativeCompiler<T> compiler(cx, kind, monitorStub, obj, holder, key,
-                                            acctype, needsAtomize, offset);
-        ICStub* newStub = compiler.getStub(compiler.getStubSpace(script));
-        if (!newStub)
-            return false;
-
-        stub->addNewStub(newStub);
-        *attached = true;
-        return true;
-    }
-
-    return true;
-}
-
-template <class T>
-static bool
-TryAttachNativeGetAccessorElemStub(JSContext* cx, HandleScript script, jsbytecode* pc,
-                                   ICGetElem_Fallback* stub, HandleNativeObject obj,
-                                   HandleValue keyVal, bool* attached,
-                                   bool* isTemporarilyUnoptimizable)
-{
-    MOZ_ASSERT(!*attached);
-    MOZ_ASSERT(keyVal.isString() || keyVal.isSymbol());
-
-    RootedId id(cx);
-    if (!ValueToId<CanGC>(cx, keyVal, &id))
-        return false;
-
-    Rooted<T> key(cx, getKey<T>(id));
-    if (!key)
-        return true;
-    bool needsAtomize = checkAtomize<T>(keyVal);
-
-    RootedShape shape(cx);
-    RootedObject baseHolder(cx);
-    if (!EffectlesslyLookupProperty(cx, obj, id, &baseHolder, &shape))
-        return false;
-    if (!baseHolder || !baseHolder->isNative())
-        return true;
-
-    HandleNativeObject holder = baseHolder.as<NativeObject>();
-
-    bool getterIsScripted = false;
-    if (IsCacheableGetPropCall(cx, obj, baseHolder, shape, &getterIsScripted,
-                               isTemporarilyUnoptimizable, /*isDOMProxy=*/false))
-    {
-        RootedFunction getter(cx, &shape->getterObject()->as<JSFunction>());
-
-        // For now, we do not handle own property getters
-        if (obj == holder)
-            return true;
-
-        // If a suitable stub already exists, nothing else to do.
-        if (GetElemNativeStubExists<T>(stub, obj, holder, key, needsAtomize))
-            return true;
-
-        // Remove any existing stubs that may interfere with the new stub being added.
-        RemoveExistingGetElemNativeStubs<T>(cx, stub, obj, holder, key, needsAtomize);
-
-        ICStub* monitorStub = stub->fallbackMonitorStub()->firstMonitorStub();
-        ICStub::Kind kind = getterIsScripted ? ICStub::GetElem_NativePrototypeCallScriptedName
-                                             : ICStub::GetElem_NativePrototypeCallNativeName;
-        kind = getGetElemStubKind<T>(kind);
-
-        if (getterIsScripted) {
-            JitSpew(JitSpew_BaselineIC,
-                    "  Generating GetElem(Native %s%s call scripted %s:%" PRIuSIZE ") stub "
-                    "(obj=%p, shape=%p, holder=%p, holderShape=%p)",
-                        (obj == holder) ? "direct" : "prototype",
-                        needsAtomize ? " atomizing" : "",
-                        getter->nonLazyScript()->filename(), getter->nonLazyScript()->lineno(),
-                        obj.get(), obj->lastProperty(), holder.get(), holder->lastProperty());
-        } else {
-            JitSpew(JitSpew_BaselineIC,
-                    "  Generating GetElem(Native %s%s call native) stub "
-                    "(obj=%p, shape=%p, holder=%p, holderShape=%p)",
-                        (obj == holder) ? "direct" : "prototype",
-                        needsAtomize ? " atomizing" : "",
-                        obj.get(), obj->lastProperty(), holder.get(), holder->lastProperty());
-        }
-
-        AccType acctype = getterIsScripted ? ICGetElemNativeStub::ScriptedGetter
-                                           : ICGetElemNativeStub::NativeGetter;
-        ICGetElemNativeCompiler<T> compiler(cx, kind, monitorStub, obj, holder, key, acctype,
-                                            needsAtomize, getter, script->pcToOffset(pc));
-        ICStub* newStub = compiler.getStub(compiler.getStubSpace(script));
-        if (!newStub)
-            return false;
-
-        stub->addNewStub(newStub);
-        *attached = true;
-        return true;
-    }
-
-    return true;
-}
-
 static bool
 IsPrimitiveArrayTypedObject(JSObject* obj)
 {
     if (!obj->is<TypedObject>())
         return false;
     TypeDescr& descr = obj->as<TypedObject>().typeDescr();
     return descr.is<ArrayTypeDescr>() &&
            descr.as<ArrayTypeDescr>().elementType().is<ScalarTypeDescr>();
@@ -1436,37 +1018,16 @@ TryAttachGetElemStub(JSContext* cx, JSSc
         if (!denseStub)
             return false;
 
         stub->addNewStub(denseStub);
         *attached = true;
         return true;
     }
 
-    // Check for NativeObject[id] and UnboxedPlainObject[id] shape-optimizable accesses.
-    if (obj->isNative() || obj->is<UnboxedPlainObject>()) {
-        RootedScript rootedScript(cx, script);
-        if (rhs.isString()) {
-            if (!TryAttachNativeOrUnboxedGetValueElemStub<PropertyName*>(cx, rootedScript, pc, stub,
-                                                                         obj, rhs, attached))
-            {
-                return false;
-            }
-        } else if (rhs.isSymbol()) {
-            if (!TryAttachNativeOrUnboxedGetValueElemStub<JS::Symbol*>(cx, rootedScript, pc, stub,
-                                                                       obj, rhs, attached))
-            {
-                return false;
-            }
-        }
-        if (*attached)
-            return true;
-        script = rootedScript;
-    }
-
     // Check for UnboxedArray[int] accesses.
     if (obj->is<UnboxedArrayObject>() && rhs.isInt32() && rhs.toInt32() >= 0) {
         JitSpew(JitSpew_BaselineIC, "  Generating GetElem(UnboxedArray[Int32]) stub");
         ICGetElem_UnboxedArray::Compiler compiler(cx, stub->fallbackMonitorStub()->firstMonitorStub(),
                                                   obj->group());
         ICStub* unboxedStub = compiler.getStub(compiler.getStubSpace(script));
         if (!unboxedStub)
             return false;
@@ -1550,39 +1111,32 @@ DoGetElemFallback(JSContext* cx, Baselin
     bool attached = false;
     if (stub->numOptimizedStubs() >= ICGetElem_Fallback::MAX_OPTIMIZED_STUBS) {
         // TODO: Discard all stubs in this IC and replace with inert megamorphic stub.
         // But for now we just bail.
         stub->noteUnoptimizableAccess();
         attached = true;
     }
 
-    // Try to attach an optimized getter stub.
     bool isTemporarilyUnoptimizable = false;
-    if (!attached && lhs.isObject() && lhs.toObject().isNative()){
-        if (rhs.isString()) {
-            RootedScript rootedScript(cx, frame->script());
-            RootedNativeObject obj(cx, &lhs.toObject().as<NativeObject>());
-            if (!TryAttachNativeGetAccessorElemStub<PropertyName*>(cx, rootedScript, pc, stub,
-                                                                   obj, rhs, &attached,
-                                                                   &isTemporarilyUnoptimizable))
-            {
-                return false;
+    if (!attached && !JitOptions.disableCacheIR) {
+        ICStubEngine engine = ICStubEngine::Baseline;
+        GetPropIRGenerator gen(cx, pc, engine, CacheKind::GetElem, &isTemporarilyUnoptimizable,
+                               lhs, rhs, res);
+        if (gen.tryAttachStub()) {
+            ICStub* newStub = AttachBaselineCacheIRStub(cx, gen.writerRef(), gen.cacheKind(),
+                                                        engine, info.outerScript(cx), stub);
+            if (newStub) {
+                JitSpew(JitSpew_BaselineIC, "  Attached CacheIR stub");
+                attached = true;
+                if (gen.shouldNotePreliminaryObjectStub())
+                    newStub->toCacheIR_Monitored()->notePreliminaryObject();
+                else if (gen.shouldUnlinkPreliminaryObjectStubs())
+                    StripPreliminaryObjectStubs(cx, stub);
             }
-            script = rootedScript;
-        } else if (rhs.isSymbol()) {
-            RootedScript rootedScript(cx, frame->script());
-            RootedNativeObject obj(cx, &lhs.toObject().as<NativeObject>());
-            if (!TryAttachNativeGetAccessorElemStub<JS::Symbol*>(cx, rootedScript, pc, stub,
-                                                                 obj, rhs, &attached,
-                                                                 &isTemporarilyUnoptimizable))
-            {
-                return false;
-            }
-            script = rootedScript;
         }
     }
 
     if (!isOptimizedArgs) {
         if (!GetElementOperation(cx, op, &lhsCopy, rhs, res))
             return false;
         TypeScript::Monitor(cx, frame->script(), pc, res);
     }
@@ -1634,362 +1188,16 @@ ICGetElem_Fallback::Compiler::generateSt
     masm.pushValue(R0);
     masm.push(ICStubReg);
     pushStubPayload(masm, R0.scratchReg());
 
     return tailCallVM(DoGetElemFallbackInfo, masm);
 }
 
 //
-// GetElem_NativeSlot
-//
-
-static bool
-DoAtomizeString(JSContext* cx, HandleString string, MutableHandleValue result)
-{
-    JitSpew(JitSpew_BaselineIC, "  AtomizeString called");
-
-    RootedValue key(cx, StringValue(string));
-
-    // Convert to interned property name.
-    RootedId id(cx);
-    if (!ValueToId<CanGC>(cx, key, &id))
-        return false;
-
-    if (!JSID_IS_ATOM(id)) {
-        result.set(key);
-        return true;
-    }
-
-    result.set(StringValue(JSID_TO_ATOM(id)));
-    return true;
-}
-
-typedef bool (*DoAtomizeStringFn)(JSContext*, HandleString, MutableHandleValue);
-static const VMFunction DoAtomizeStringInfo = FunctionInfo<DoAtomizeStringFn>(DoAtomizeString,
-                                                                              "DoAtomizeString");
-
-template <class T>
-bool
-ICGetElemNativeCompiler<T>::emitCallNative(MacroAssembler& masm, Register objReg)
-{
-    AllocatableGeneralRegisterSet regs(availableGeneralRegs(0));
-    regs.takeUnchecked(objReg);
-    regs.takeUnchecked(ICTailCallReg);
-
-    enterStubFrame(masm, regs.getAny());
-
-    // Push object.
-    masm.push(objReg);
-
-    // Push native callee.
-    masm.loadPtr(Address(ICStubReg, ICGetElemNativeGetterStub<T>::offsetOfGetter()), objReg);
-    masm.push(objReg);
-
-    regs.add(objReg);
-
-    // Call helper.
-    if (!callVM(DoCallNativeGetterInfo, masm))
-        return false;
-
-    leaveStubFrame(masm);
-
-    return true;
-}
-
-template <class T>
-bool
-ICGetElemNativeCompiler<T>::emitCallScripted(MacroAssembler& masm, Register objReg)
-{
-    AllocatableGeneralRegisterSet regs(availableGeneralRegs(0));
-    regs.takeUnchecked(objReg);
-    regs.takeUnchecked(ICTailCallReg);
-
-    // Enter stub frame.
-    enterStubFrame(masm, regs.getAny());
-
-    // Align the stack such that the JitFrameLayout is aligned on
-    // JitStackAlignment.
-    masm.alignJitStackBasedOnNArgs(0);
-
-    // Push |this| for getter (target object).
-    {
-        ValueOperand val = regs.takeAnyValue();
-        masm.tagValue(JSVAL_TYPE_OBJECT, objReg, val);
-        masm.Push(val);
-        regs.add(val);
-    }
-
-    regs.add(objReg);
-
-    Register callee = regs.takeAny();
-    masm.loadPtr(Address(ICStubReg, ICGetElemNativeGetterStub<T>::offsetOfGetter()), callee);
-
-    // Push argc, callee, and descriptor.
-    {
-        Register callScratch = regs.takeAny();
-        EmitBaselineCreateStubFrameDescriptor(masm, callScratch, JitFrameLayout::Size());
-        masm.Push(Imm32(0));  // ActualArgc is 0
-        masm.Push(callee);
-        masm.Push(callScratch);
-        regs.add(callScratch);
-    }
-
-    Register code = regs.takeAnyExcluding(ArgumentsRectifierReg);
-    masm.loadPtr(Address(callee, JSFunction::offsetOfNativeOrScript()), code);
-    masm.loadBaselineOrIonRaw(code, code, nullptr);
-
-    Register scratch = regs.takeAny();
-
-    // Handle arguments underflow.
-    Label noUnderflow;
-    masm.load16ZeroExtend(Address(callee, JSFunction::offsetOfNargs()), scratch);
-    masm.branch32(Assembler::Equal, scratch, Imm32(0), &noUnderflow);
-    {
-        // Call the arguments rectifier.
-        MOZ_ASSERT(ArgumentsRectifierReg != code);
-
-        JitCode* argumentsRectifier =
-            cx->runtime()->jitRuntime()->getArgumentsRectifier();
-
-        masm.movePtr(ImmGCPtr(argumentsRectifier), code);
-        masm.loadPtr(Address(code, JitCode::offsetOfCode()), code);
-        masm.movePtr(ImmWord(0), ArgumentsRectifierReg);
-    }
-
-    masm.bind(&noUnderflow);
-    masm.callJit(code);
-
-    leaveStubFrame(masm, true);
-
-    return true;
-}
-
-template <class T>
-bool
-ICGetElemNativeCompiler<T>::emitCheckKey(MacroAssembler& masm, Label& failure)
-{
-    MOZ_ASSERT_UNREACHABLE("Key has to be PropertyName or Symbol");
-    return false;
-}
-
-template <>
-bool
-ICGetElemNativeCompiler<JS::Symbol*>::emitCheckKey(MacroAssembler& masm, Label& failure)
-{
-    MOZ_ASSERT(!needsAtomize_);
-    masm.branchTestSymbol(Assembler::NotEqual, R1, &failure);
-    Address symbolAddr(ICStubReg, ICGetElemNativeStubImpl<JS::Symbol*>::offsetOfKey());
-    Register symExtract = masm.extractObject(R1, ExtractTemp1);
-    masm.branchPtr(Assembler::NotEqual, symbolAddr, symExtract, &failure);
-    return true;
-}
-
-template <>
-bool
-ICGetElemNativeCompiler<PropertyName*>::emitCheckKey(MacroAssembler& masm, Label& failure)
-{
-    masm.branchTestString(Assembler::NotEqual, R1, &failure);
-    // Check key identity.  Don't automatically fail if this fails, since the incoming
-    // key maybe a non-interned string.  Switch to a slowpath vm-call based check.
-    Address nameAddr(ICStubReg, ICGetElemNativeStubImpl<PropertyName*>::offsetOfKey());
-    Register strExtract = masm.extractString(R1, ExtractTemp1);
-
-    // If needsAtomize_ is true, and the string is not already an atom, then atomize the
-    // string before proceeding.
-    if (needsAtomize_) {
-        Label skipAtomize;
-
-        // If string is already an atom, skip the atomize.
-        masm.branchTest32(Assembler::NonZero,
-                          Address(strExtract, JSString::offsetOfFlags()),
-                          Imm32(JSString::ATOM_BIT),
-                          &skipAtomize);
-
-        // Stow R0.
-        EmitStowICValues(masm, 1);
-
-        enterStubFrame(masm, R0.scratchReg());
-
-        // Atomize the string into a new value.
-        masm.push(strExtract);
-        if (!callVM(DoAtomizeStringInfo, masm))
-            return false;
-
-        // Atomized string is now in JSReturnOperand (R0).
-        // Leave stub frame, move atomized string into R1.
-        MOZ_ASSERT(R0 == JSReturnOperand);
-        leaveStubFrame(masm);
-        masm.moveValue(JSReturnOperand, R1);
-
-        // Unstow R0
-        EmitUnstowICValues(masm, 1);
-
-        // Extract string from R1 again.
-        DebugOnly<Register> strExtract2 = masm.extractString(R1, ExtractTemp1);
-        MOZ_ASSERT(Register(strExtract2) == strExtract);
-
-        masm.bind(&skipAtomize);
-    }
-
-    // Key has been atomized if necessary.  Do identity check on string pointer.
-    masm.branchPtr(Assembler::NotEqual, nameAddr, strExtract, &failure);
-    return true;
-}
-
-template <class T>
-bool
-ICGetElemNativeCompiler<T>::generateStubCode(MacroAssembler& masm)
-{
-    MOZ_ASSERT(engine_ == Engine::Baseline);
-
-    Label failure;
-    Label failurePopR1;
-    bool popR1 = false;
-
-    masm.branchTestObject(Assembler::NotEqual, R0, &failure);
-
-    AllocatableGeneralRegisterSet regs(availableGeneralRegs(2));
-    Register scratchReg = regs.takeAny();
-
-    // Unbox object.
-    Register objReg = masm.extractObject(R0, ExtractTemp0);
-
-    // Check object shape/group.
-    GuardReceiverObject(masm, ReceiverGuard(obj_), objReg, scratchReg,
-                        ICGetElemNativeStub::offsetOfReceiverGuard(), &failure);
-
-    // Since this stub sometimes enters a stub frame, we manually set this to true (lie).
-#ifdef DEBUG
-    entersStubFrame_ = true;
-#endif
-
-    if (!emitCheckKey(masm, failure))
-        return false;
-
-    Register holderReg;
-    if (obj_ == holder_) {
-        holderReg = objReg;
-
-        if (obj_->is<UnboxedPlainObject>() && acctype_ != ICGetElemNativeStub::UnboxedProperty) {
-            // The property will be loaded off the unboxed expando.
-            masm.push(R1.scratchReg());
-            popR1 = true;
-            holderReg = R1.scratchReg();
-            masm.loadPtr(Address(objReg, UnboxedPlainObject::offsetOfExpando()), holderReg);
-        }
-    } else {
-        // Shape guard holder.
-        if (regs.empty()) {
-            masm.push(R1.scratchReg());
-            popR1 = true;
-            holderReg = R1.scratchReg();
-        } else {
-            holderReg = regs.takeAny();
-        }
-
-        if (kind == ICStub::GetElem_NativePrototypeCallNativeName ||
-            kind == ICStub::GetElem_NativePrototypeCallNativeSymbol ||
-            kind == ICStub::GetElem_NativePrototypeCallScriptedName ||
-            kind == ICStub::GetElem_NativePrototypeCallScriptedSymbol)
-        {
-            masm.loadPtr(Address(ICStubReg,
-                                 ICGetElemNativePrototypeCallStub<T>::offsetOfHolder()),
-                         holderReg);
-            masm.loadPtr(Address(ICStubReg,
-                                 ICGetElemNativePrototypeCallStub<T>::offsetOfHolderShape()),
-                         scratchReg);
-        } else {
-            masm.loadPtr(Address(ICStubReg,
-                                 ICGetElem_NativePrototypeSlot<T>::offsetOfHolder()),
-                         holderReg);
-            masm.loadPtr(Address(ICStubReg,
-                                 ICGetElem_NativePrototypeSlot<T>::offsetOfHolderShape()),
-                         scratchReg);
-        }
-        masm.branchTestObjShape(Assembler::NotEqual, holderReg, scratchReg,
-                                popR1 ? &failurePopR1 : &failure);
-    }
-
-    if (acctype_ == ICGetElemNativeStub::DynamicSlot ||
-        acctype_ == ICGetElemNativeStub::FixedSlot)
-    {
-        masm.load32(Address(ICStubReg, ICGetElemNativeSlotStub<T>::offsetOfOffset()),
-                    scratchReg);
-
-        // Load from object.
-        if (acctype_ == ICGetElemNativeStub::DynamicSlot)
-            masm.addPtr(Address(holderReg, NativeObject::offsetOfSlots()), scratchReg);
-        else
-            masm.addPtr(holderReg, scratchReg);
-
-        Address valAddr(scratchReg, 0);
-        masm.loadValue(valAddr, R0);
-        if (popR1)
-            masm.addToStackPtr(ImmWord(sizeof(size_t)));
-
-    } else if (acctype_ == ICGetElemNativeStub::UnboxedProperty) {
-        masm.load32(Address(ICStubReg, ICGetElemNativeSlotStub<T>::offsetOfOffset()),
-                    scratchReg);
-        masm.loadUnboxedProperty(BaseIndex(objReg, scratchReg, TimesOne), unboxedType_,
-                                 TypedOrValueRegister(R0));
-        if (popR1)
-            masm.addToStackPtr(ImmWord(sizeof(size_t)));
-    } else {
-        MOZ_ASSERT(acctype_ == ICGetElemNativeStub::NativeGetter ||
-                   acctype_ == ICGetElemNativeStub::ScriptedGetter);
-        MOZ_ASSERT(kind == ICStub::GetElem_NativePrototypeCallNativeName ||
-                   kind == ICStub::GetElem_NativePrototypeCallNativeSymbol ||
-                   kind == ICStub::GetElem_NativePrototypeCallScriptedName ||
-                   kind == ICStub::GetElem_NativePrototypeCallScriptedSymbol);
-
-        if (acctype_ == ICGetElemNativeStub::NativeGetter) {
-            // If calling a native getter, there is no chance of failure now.
-
-            // GetElem key (R1) is no longer needed.
-            if (popR1)
-                masm.addToStackPtr(ImmWord(sizeof(size_t)));
-
-            if (!emitCallNative(masm, objReg))
-                return false;
-
-        } else {
-            MOZ_ASSERT(acctype_ == ICGetElemNativeStub::ScriptedGetter);
-
-            // Load function in scratchReg and ensure that it has a jit script.
-            masm.loadPtr(Address(ICStubReg, ICGetElemNativeGetterStub<T>::offsetOfGetter()),
-                         scratchReg);
-            masm.branchIfFunctionHasNoScript(scratchReg, popR1 ? &failurePopR1 : &failure);
-            masm.loadPtr(Address(scratchReg, JSFunction::offsetOfNativeOrScript()), scratchReg);
-            masm.loadBaselineOrIonRaw(scratchReg, scratchReg, popR1 ? &failurePopR1 : &failure);
-
-            // At this point, we are guaranteed to successfully complete.
-            if (popR1)
-                masm.addToStackPtr(Imm32(sizeof(size_t)));
-
-            if (!emitCallScripted(masm, objReg))
-                return false;
-        }
-    }
-
-    // Enter type monitor IC to type-check result.
-    EmitEnterTypeMonitorIC(masm);
-
-    // Failure case - jump to next stub
-    if (popR1) {
-        masm.bind(&failurePopR1);
-        masm.pop(R1.scratchReg());
-    }
-    masm.bind(&failure);
-    EmitStubGuardFailure(masm);
-
-    return true;
-}
-
-//
 // GetElem_String
 //
 
 bool
 ICGetElem_String::Compiler::generateStubCode(MacroAssembler& masm)
 {
     MOZ_ASSERT(engine_ == Engine::Baseline);
 
@@ -8174,111 +7382,16 @@ ICTypeUpdate_SingleObject::ICTypeUpdate_
     obj_(obj)
 { }
 
 ICTypeUpdate_ObjectGroup::ICTypeUpdate_ObjectGroup(JitCode* stubCode, ObjectGroup* group)
   : ICStub(TypeUpdate_ObjectGroup, stubCode),
     group_(group)
 { }
 
-ICGetElemNativeStub::ICGetElemNativeStub(ICStub::Kind kind, JitCode* stubCode,
-                                         ICStub* firstMonitorStub,
-                                         ReceiverGuard guard, AccessType acctype,
-                                         bool needsAtomize, bool isSymbol)
-  : ICMonitoredStub(kind, stubCode, firstMonitorStub),
-    receiverGuard_(guard)
-{
-    extra_ = (static_cast<uint16_t>(acctype) << ACCESSTYPE_SHIFT) |
-             (static_cast<uint16_t>(needsAtomize) << NEEDS_ATOMIZE_SHIFT) |
-             (static_cast<uint16_t>(isSymbol) << ISSYMBOL_SHIFT);
-}
-
-ICGetElemNativeStub::~ICGetElemNativeStub()
-{ }
-
-template <class T>
-ICGetElemNativeGetterStub<T>::ICGetElemNativeGetterStub(
-                           ICStub::Kind kind, JitCode* stubCode, ICStub* firstMonitorStub,
-                           ReceiverGuard guard, const T* key, AccType acctype, bool needsAtomize,
-                           JSFunction* getter, uint32_t pcOffset)
-  : ICGetElemNativeStubImpl<T>(kind, stubCode, firstMonitorStub, guard, key, acctype, needsAtomize),
-    getter_(getter),
-    pcOffset_(pcOffset)
-{
-    MOZ_ASSERT(kind == ICStub::GetElem_NativePrototypeCallNativeName ||
-               kind == ICStub::GetElem_NativePrototypeCallNativeSymbol ||
-               kind == ICStub::GetElem_NativePrototypeCallScriptedName ||
-               kind == ICStub::GetElem_NativePrototypeCallScriptedSymbol);
-    MOZ_ASSERT(acctype == ICGetElemNativeStub::NativeGetter ||
-               acctype == ICGetElemNativeStub::ScriptedGetter);
-}
-
-template <class T>
-ICGetElem_NativePrototypeSlot<T>::ICGetElem_NativePrototypeSlot(
-                               JitCode* stubCode, ICStub* firstMonitorStub, ReceiverGuard guard,
-                               const T* key, AccType acctype, bool needsAtomize, uint32_t offset,
-                               JSObject* holder, Shape* holderShape)
-  : ICGetElemNativeSlotStub<T>(getGetElemStubKind<T>(ICStub::GetElem_NativePrototypeSlotName),
-                               stubCode, firstMonitorStub, guard, key, acctype, needsAtomize, offset),
-    holder_(holder),
-    holderShape_(holderShape)
-{ }
-
-template <class T>
-ICGetElemNativePrototypeCallStub<T>::ICGetElemNativePrototypeCallStub(
-                                  ICStub::Kind kind, JitCode* stubCode, ICStub* firstMonitorStub,
-                                  ReceiverGuard guard, const T* key, AccType acctype,
-                                  bool needsAtomize, JSFunction* getter, uint32_t pcOffset,
-                                  JSObject* holder, Shape* holderShape)
-  : ICGetElemNativeGetterStub<T>(kind, stubCode, firstMonitorStub, guard, key, acctype, needsAtomize,
-                                 getter, pcOffset),
-    holder_(holder),
-    holderShape_(holderShape)
-{}
-
-template <class T>
-/* static */ ICGetElem_NativePrototypeCallNative<T>*
-ICGetElem_NativePrototypeCallNative<T>::Clone(JSContext* cx,
-                                              ICStubSpace* space,
-                                              ICStub* firstMonitorStub,
-                                              ICGetElem_NativePrototypeCallNative<T>& other)
-{
-    return ICStub::New<ICGetElem_NativePrototypeCallNative<T>>(cx, space, other.jitCode(),
-                firstMonitorStub, other.receiverGuard(), &other.key().get(), other.accessType(),
-                other.needsAtomize(), other.getter(), other.pcOffset_, other.holder(),
-                other.holderShape());
-}
-
-template ICGetElem_NativePrototypeCallNative<JS::Symbol*>*
-ICGetElem_NativePrototypeCallNative<JS::Symbol*>::Clone(JSContext*, ICStubSpace*, ICStub*,
-                                          ICGetElem_NativePrototypeCallNative<JS::Symbol*>&);
-template ICGetElem_NativePrototypeCallNative<js::PropertyName*>*
-ICGetElem_NativePrototypeCallNative<js::PropertyName*>::Clone(JSContext*, ICStubSpace*, ICStub*,
-                                          ICGetElem_NativePrototypeCallNative<js::PropertyName*>&);
-
-template <class T>
-/* static */ ICGetElem_NativePrototypeCallScripted<T>*
-ICGetElem_NativePrototypeCallScripted<T>::Clone(JSContext* cx,
-                                                ICStubSpace* space,
-                                                ICStub* firstMonitorStub,
-                                                ICGetElem_NativePrototypeCallScripted<T>& other)
-{
-    return ICStub::New<ICGetElem_NativePrototypeCallScripted<T>>(cx, space, other.jitCode(),
-                firstMonitorStub, other.receiverGuard(), &other.key().get(), other.accessType(),
-                other.needsAtomize(), other.getter(), other.pcOffset_, other.holder(),
-                other.holderShape());
-}
-
-template ICGetElem_NativePrototypeCallScripted<JS::Symbol*>*
-ICGetElem_NativePrototypeCallScripted<JS::Symbol*>::Clone(JSContext*, ICStubSpace*, ICStub*,
-                                        ICGetElem_NativePrototypeCallScripted<JS::Symbol*>&);
-template ICGetElem_NativePrototypeCallScripted<js::PropertyName*>*
-ICGetElem_NativePrototypeCallScripted<js::PropertyName*>::Clone(JSContext*, ICStubSpace*, ICStub*,
-                                        ICGetElem_NativePrototypeCallScripted<js::PropertyName*>&);
-
 ICGetElem_Dense::ICGetElem_Dense(JitCode* stubCode, ICStub* firstMonitorStub, Shape* shape)
     : ICMonitoredStub(GetElem_Dense, stubCode, firstMonitorStub),
       shape_(shape)
 { }
 
 /* static */ ICGetElem_Dense*
 ICGetElem_Dense::Clone(JSContext* cx, ICStubSpace* space, ICStub* firstMonitorStub,
                        ICGetElem_Dense& other)
--- a/js/src/jit/BaselineIC.h
+++ b/js/src/jit/BaselineIC.h
@@ -414,421 +414,16 @@ class ICGetElem_Fallback : public ICMoni
                 return nullptr;
             if (!stub->initMonitoringChain(cx, space, engine_))
                 return nullptr;
             return stub;
         }
     };
 };
 
-class ICGetElemNativeStub : public ICMonitoredStub
-{
-  public:
-    enum AccessType { FixedSlot = 0, DynamicSlot, UnboxedProperty, NativeGetter, ScriptedGetter, NumAccessTypes };
-
-  protected:
-    HeapReceiverGuard receiverGuard_;
-
-    static const unsigned NEEDS_ATOMIZE_SHIFT = 0;
-    static const uint16_t NEEDS_ATOMIZE_MASK = 0x1;
-
-    static const unsigned ACCESSTYPE_SHIFT = 1;
-    static const uint16_t ACCESSTYPE_MASK = 0x7;
-
-    static const unsigned ISSYMBOL_SHIFT = 4;
-    static const uint16_t ISSYMBOL_MASK = 0x1;
-
-    static_assert(ACCESSTYPE_MASK >= NumAccessTypes, "ACCESSTYPE_MASK must cover all possible AccessType values");
-
-    ICGetElemNativeStub(ICStub::Kind kind, JitCode* stubCode, ICStub* firstMonitorStub,
-                        ReceiverGuard guard, AccessType acctype, bool needsAtomize, bool isSymbol);
-
-    ~ICGetElemNativeStub();
-
-  public:
-    HeapReceiverGuard& receiverGuard() {
-        return receiverGuard_;
-    }
-    static size_t offsetOfReceiverGuard() {
-        return offsetof(ICGetElemNativeStub, receiverGuard_);
-    }
-
-    AccessType accessType() const {
-        return static_cast<AccessType>((extra_ >> ACCESSTYPE_SHIFT) & ACCESSTYPE_MASK);
-    }
-
-    bool needsAtomize() const {
-        return (extra_ >> NEEDS_ATOMIZE_SHIFT) & NEEDS_ATOMIZE_MASK;
-    }
-
-    bool isSymbol() const {
-        return (extra_ >> ISSYMBOL_SHIFT) & ISSYMBOL_MASK;
-    }
-};
-
-template <class T>
-class ICGetElemNativeStubImpl : public ICGetElemNativeStub
-{
-  protected:
-    GCPtr<T> key_;
-
-    ICGetElemNativeStubImpl(ICStub::Kind kind, JitCode* stubCode, ICStub* firstMonitorStub,
-                            ReceiverGuard guard, const T* key, AccessType acctype, bool needsAtomize)
-      : ICGetElemNativeStub(kind, stubCode, firstMonitorStub, guard, acctype, needsAtomize,
-                            mozilla::IsSame<T, JS::Symbol*>::value),
-        key_(*key)
-    {}
-
-  public:
-    GCPtr<T>& key() {
-        return key_;
-    }
-    static size_t offsetOfKey() {
-        return offsetof(ICGetElemNativeStubImpl, key_);
-    }
-};
-
-typedef ICGetElemNativeStub::AccessType AccType;
-
-template <class T>
-class ICGetElemNativeSlotStub : public ICGetElemNativeStubImpl<T>
-{
-  protected:
-    uint32_t offset_;
-
-    ICGetElemNativeSlotStub(ICStub::Kind kind, JitCode* stubCode, ICStub* firstMonitorStub,
-                            ReceiverGuard guard, const T* key, AccType acctype, bool needsAtomize,
-                            uint32_t offset)
-      : ICGetElemNativeStubImpl<T>(kind, stubCode, firstMonitorStub, guard, key, acctype, needsAtomize),
-        offset_(offset)
-    {
-        MOZ_ASSERT(kind == ICStub::GetElem_NativeSlotName ||
-                   kind == ICStub::GetElem_NativeSlotSymbol ||
-                   kind == ICStub::GetElem_NativePrototypeSlotName ||
-                   kind == ICStub::GetElem_NativePrototypeSlotSymbol ||
-                   kind == ICStub::GetElem_UnboxedPropertyName);
-        MOZ_ASSERT(acctype == ICGetElemNativeStub::FixedSlot ||
-                   acctype == ICGetElemNativeStub::DynamicSlot ||
-                   acctype == ICGetElemNativeStub::UnboxedProperty);
-    }
-
-  public:
-    uint32_t offset() const {
-        return offset_;
-    }
-
-    static size_t offsetOfOffset() {
-        return offsetof(ICGetElemNativeSlotStub, offset_);
-    }
-};
-
-template <class T>
-class ICGetElemNativeGetterStub : public ICGetElemNativeStubImpl<T>
-{
-  protected:
-    GCPtrFunction getter_;
-    uint32_t pcOffset_;
-
-    ICGetElemNativeGetterStub(ICStub::Kind kind, JitCode* stubCode, ICStub* firstMonitorStub,
-                              ReceiverGuard guard, const T* key, AccType acctype, bool needsAtomize,
-                              JSFunction* getter, uint32_t pcOffset);
-
-  public:
-    GCPtrFunction& getter() {
-        return getter_;
-    }
-    static size_t offsetOfGetter() {
-        return offsetof(ICGetElemNativeGetterStub, getter_);
-    }
-
-    static size_t offsetOfPCOffset() {
-        return offsetof(ICGetElemNativeGetterStub, pcOffset_);
-    }
-};
-
-template <class T>
-ICStub::Kind
-getGetElemStubKind(ICStub::Kind kind)
-{
-    MOZ_ASSERT(kind == ICStub::GetElem_NativeSlotName ||
-               kind == ICStub::GetElem_NativePrototypeSlotName ||
-               kind == ICStub::GetElem_NativePrototypeCallNativeName ||
-               kind == ICStub::GetElem_NativePrototypeCallScriptedName);
-    return static_cast<ICStub::Kind>(kind + mozilla::IsSame<T, JS::Symbol*>::value);
-}
-
-template <class T>
-class ICGetElem_NativeSlot : public ICGetElemNativeSlotStub<T>
-{
-    friend class ICStubSpace;
-    ICGetElem_NativeSlot(JitCode* stubCode, ICStub* firstMonitorStub, ReceiverGuard guard,
-                         const T* key, AccType acctype, bool needsAtomize, uint32_t offset)
-      : ICGetElemNativeSlotStub<T>(getGetElemStubKind<T>(ICStub::GetElem_NativeSlotName),
-                                   stubCode, firstMonitorStub, guard,
-                                   key, acctype, needsAtomize, offset)
-    {}
-};
-
-class ICGetElem_NativeSlotName :
-      public ICGetElem_NativeSlot<PropertyName*>
-{};
-class ICGetElem_NativeSlotSymbol :
-      public ICGetElem_NativeSlot<JS::Symbol*>
-{};
-
-template <class T>
-class ICGetElem_UnboxedProperty : public ICGetElemNativeSlotStub<T>
-{
-    friend class ICStubSpace;
-    ICGetElem_UnboxedProperty(JitCode* stubCode, ICStub* firstMonitorStub,
-                              ReceiverGuard guard, const T* key, AccType acctype,
-                              bool needsAtomize, uint32_t offset)
-      : ICGetElemNativeSlotStub<T>(ICStub::GetElem_UnboxedPropertyName, stubCode, firstMonitorStub,
-                                   guard, key, acctype, needsAtomize, offset)
-     {}
-};
-
-class ICGetElem_UnboxedPropertyName :
-      public ICGetElem_UnboxedProperty<PropertyName*>
-{};
-
-template <class T>
-class ICGetElem_NativePrototypeSlot : public ICGetElemNativeSlotStub<T>
-{
-    friend class ICStubSpace;
-    GCPtrObject holder_;
-    GCPtrShape holderShape_;
-
-    ICGetElem_NativePrototypeSlot(JitCode* stubCode, ICStub* firstMonitorStub, ReceiverGuard guard,
-                                  const T* key, AccType acctype, bool needsAtomize, uint32_t offset,
-                                  JSObject* holder, Shape* holderShape);
-
-  public:
-    GCPtrObject& holder() {
-        return holder_;
-    }
-    static size_t offsetOfHolder() {
-        return offsetof(ICGetElem_NativePrototypeSlot, holder_);
-    }
-
-    GCPtrShape& holderShape() {
-        return holderShape_;
-    }
-    static size_t offsetOfHolderShape() {
-        return offsetof(ICGetElem_NativePrototypeSlot, holderShape_);
-    }
-};
-
-class ICGetElem_NativePrototypeSlotName :
-      public ICGetElem_NativePrototypeSlot<PropertyName*>
-{};
-class ICGetElem_NativePrototypeSlotSymbol :
-      public ICGetElem_NativePrototypeSlot<JS::Symbol*>
-{};
-
-template <class T>
-class ICGetElemNativePrototypeCallStub : public ICGetElemNativeGetterStub<T>
-{
-    friend class ICStubSpace;
-    GCPtrObject holder_;
-    GCPtrShape holderShape_;
-
-  protected:
-    ICGetElemNativePrototypeCallStub(ICStub::Kind kind, JitCode* stubCode, ICStub* firstMonitorStub,
-                                     ReceiverGuard guard, const T* key, AccType acctype,
-                                     bool needsAtomize, JSFunction* getter, uint32_t pcOffset,
-                                     JSObject* holder, Shape* holderShape);
-
-  public:
-    GCPtrObject& holder() {
-        return holder_;
-    }
-    static size_t offsetOfHolder() {
-        return offsetof(ICGetElemNativePrototypeCallStub, holder_);
-    }
-
-    GCPtrShape& holderShape() {
-        return holderShape_;
-    }
-    static size_t offsetOfHolderShape() {
-        return offsetof(ICGetElemNativePrototypeCallStub, holderShape_);
-    }
-};
-
-template <class T>
-class ICGetElem_NativePrototypeCallNative : public ICGetElemNativePrototypeCallStub<T>
-{
-    friend class ICStubSpace;
-
-    ICGetElem_NativePrototypeCallNative(JitCode* stubCode, ICStub* firstMonitorStub,
-                                        ReceiverGuard guard, const T* key, AccType acctype,
-                                        bool needsAtomize, JSFunction* getter, uint32_t pcOffset,
-                                        JSObject* holder, Shape* holderShape)
-      : ICGetElemNativePrototypeCallStub<T>(getGetElemStubKind<T>(
-                                            ICStub::GetElem_NativePrototypeCallNativeName),
-                                            stubCode, firstMonitorStub, guard, key,
-                                            acctype, needsAtomize, getter, pcOffset, holder,
-                                            holderShape)
-    {}
-
-  public:
-    static ICGetElem_NativePrototypeCallNative<T>* Clone(JSContext* cx, ICStubSpace* space,
-                                                         ICStub* firstMonitorStub,
-                                                         ICGetElem_NativePrototypeCallNative<T>& other);
-};
-
-class ICGetElem_NativePrototypeCallNativeName :
-      public ICGetElem_NativePrototypeCallNative<PropertyName*>
-{};
-class ICGetElem_NativePrototypeCallNativeSymbol :
-      public ICGetElem_NativePrototypeCallNative<JS::Symbol*>
-{};
-
-template <class T>
-class ICGetElem_NativePrototypeCallScripted : public ICGetElemNativePrototypeCallStub<T>
-{
-    friend class ICStubSpace;
-
-    ICGetElem_NativePrototypeCallScripted(JitCode* stubCode, ICStub* firstMonitorStub,
-                                          ReceiverGuard guard, const T* key, AccType acctype,
-                                          bool needsAtomize, JSFunction* getter, uint32_t pcOffset,
-                                          JSObject* holder, Shape* holderShape)
-      : ICGetElemNativePrototypeCallStub<T>(getGetElemStubKind<T>(
-                                            ICStub::GetElem_NativePrototypeCallScriptedName),
-                                            stubCode, firstMonitorStub, guard, key, acctype,
-                                            needsAtomize, getter, pcOffset, holder, holderShape)
-    {}
-
-  public:
-    static ICGetElem_NativePrototypeCallScripted<T>*
-    Clone(JSContext* cx, ICStubSpace* space,
-          ICStub* firstMonitorStub,
-          ICGetElem_NativePrototypeCallScripted<T>& other);
-};
-
-class ICGetElem_NativePrototypeCallScriptedName :
-      public ICGetElem_NativePrototypeCallScripted<PropertyName*>
-{};
-class ICGetElem_NativePrototypeCallScriptedSymbol :
-      public ICGetElem_NativePrototypeCallScripted<JS::Symbol*>
-{};
-
-// Compiler for GetElem_NativeSlot and GetElem_NativePrototypeSlot stubs.
-template <class T>
-class ICGetElemNativeCompiler : public ICStubCompiler
-{
-    ICStub* firstMonitorStub_;
-    HandleObject obj_;
-    HandleObject holder_;
-    Handle<T> key_;
-    AccType acctype_;
-    bool needsAtomize_;
-    uint32_t offset_;
-    JSValueType unboxedType_;
-    HandleFunction getter_;
-    uint32_t pcOffset_;
-
-    MOZ_MUST_USE bool emitCheckKey(MacroAssembler& masm, Label& failure);
-    MOZ_MUST_USE bool emitCallNative(MacroAssembler& masm, Register objReg);
-    MOZ_MUST_USE bool emitCallScripted(MacroAssembler& masm, Register objReg);
-    MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
-
-  protected:
-    virtual int32_t getKey() const {
-        MOZ_ASSERT(static_cast<int32_t>(acctype_) <= 7);
-        MOZ_ASSERT(static_cast<int32_t>(unboxedType_) <= 15);
-        return static_cast<int32_t>(engine_) |
-              (static_cast<int32_t>(kind) << 1) |
-              (static_cast<int32_t>(needsAtomize_) << 17) |
-              (static_cast<int32_t>(acctype_) << 18) |
-              (static_cast<int32_t>(unboxedType_) << 21) |
-              (static_cast<int32_t>(mozilla::IsSame<JS::Symbol*, T>::value) << 25) |
-              (HeapReceiverGuard::keyBits(obj_) << 26);
-    }
-
-  public:
-    ICGetElemNativeCompiler(JSContext* cx, ICStub::Kind kind, ICStub* firstMonitorStub,
-                            HandleObject obj, HandleObject holder, Handle<T> key, AccType acctype,
-                            bool needsAtomize, uint32_t offset,
-                            JSValueType unboxedType = JSVAL_TYPE_MAGIC)
-      : ICStubCompiler(cx, kind, Engine::Baseline),
-        firstMonitorStub_(firstMonitorStub),
-        obj_(obj),
-        holder_(holder),
-        key_(key),
-        acctype_(acctype),
-        needsAtomize_(needsAtomize),
-        offset_(offset),
-        unboxedType_(unboxedType),
-        getter_(nullptr),
-        pcOffset_(0)
-    {}
-
-    ICGetElemNativeCompiler(JSContext* cx, ICStub::Kind kind, ICStub* firstMonitorStub,
-                            HandleObject obj, HandleObject holder, Handle<T> key, AccType acctype,
-                            bool needsAtomize, HandleFunction getter, uint32_t pcOffset)
-      : ICStubCompiler(cx, kind, Engine::Baseline),
-        firstMonitorStub_(firstMonitorStub),
-        obj_(obj),
-        holder_(holder),
-        key_(key),
-        acctype_(acctype),
-        needsAtomize_(needsAtomize),
-        offset_(0),
-        unboxedType_(JSVAL_TYPE_MAGIC),
-        getter_(getter),
-        pcOffset_(pcOffset)
-    {}
-
-    ICStub* getStub(ICStubSpace* space) {
-        RootedReceiverGuard guard(cx, ReceiverGuard(obj_));
-        if (kind == ICStub::GetElem_NativeSlotName || kind == ICStub::GetElem_NativeSlotSymbol) {
-            MOZ_ASSERT(obj_ == holder_);
-            return newStub<ICGetElem_NativeSlot<T>>(
-                    space, getStubCode(), firstMonitorStub_, guard, key_.address(), acctype_,
-                    needsAtomize_, offset_);
-        }
-
-	if (kind == ICStub::GetElem_UnboxedPropertyName) {
-            MOZ_ASSERT(obj_ == holder_);
-            return newStub<ICGetElem_UnboxedProperty<T>>(
-                    space, getStubCode(), firstMonitorStub_, guard, key_.address(), acctype_,
-                    needsAtomize_, offset_);
-        }
-
-        MOZ_ASSERT(obj_ != holder_);
-        RootedShape holderShape(cx, holder_->as<NativeObject>().lastProperty());
-        if (kind == ICStub::GetElem_NativePrototypeSlotName ||
-            kind == ICStub::GetElem_NativePrototypeSlotSymbol)
-        {
-            return newStub<ICGetElem_NativePrototypeSlot<T>>(
-                    space, getStubCode(), firstMonitorStub_, guard, key_.address(), acctype_,
-                    needsAtomize_, offset_, holder_, holderShape);
-        }
-
-        if (kind == ICStub::GetElem_NativePrototypeCallNativeSymbol ||
-            kind == ICStub::GetElem_NativePrototypeCallNativeName) {
-            return newStub<ICGetElem_NativePrototypeCallNative<T>>(
-                    space, getStubCode(), firstMonitorStub_, guard, key_.address(), acctype_,
-                    needsAtomize_, getter_, pcOffset_, holder_, holderShape);
-        }
-
-        MOZ_ASSERT(kind == ICStub::GetElem_NativePrototypeCallScriptedName ||
-                   kind == ICStub::GetElem_NativePrototypeCallScriptedSymbol);
-        if (kind == ICStub::GetElem_NativePrototypeCallScriptedName ||
-            kind == ICStub::GetElem_NativePrototypeCallScriptedSymbol) {
-            return newStub<ICGetElem_NativePrototypeCallScripted<T>>(
-                    space, getStubCode(), firstMonitorStub_, guard, key_.address(), acctype_,
-                    needsAtomize_, getter_, pcOffset_, holder_, holderShape);
-        }
-
-        MOZ_CRASH("Invalid kind.");
-    }
-};
-
 class ICGetElem_String : public ICStub
 {
     friend class ICStubSpace;
 
     explicit ICGetElem_String(JitCode* stubCode)
       : ICStub(ICStub::GetElem_String, stubCode) {}
 
   public:
--- a/js/src/jit/BaselineICList.h
+++ b/js/src/jit/BaselineICList.h
@@ -44,25 +44,16 @@ namespace jit {
     _(Call_ClassHook)                            \
     _(Call_ScriptedApplyArray)                   \
     _(Call_ScriptedApplyArguments)               \
     _(Call_ScriptedFunCall)                      \
     _(Call_StringSplit)                          \
     _(Call_IsSuspendedStarGenerator)             \
                                                  \
     _(GetElem_Fallback)                          \
-    _(GetElem_NativeSlotName)                    \
-    _(GetElem_NativeSlotSymbol)                  \
-    _(GetElem_NativePrototypeSlotName)           \
-    _(GetElem_NativePrototypeSlotSymbol)         \
-    _(GetElem_NativePrototypeCallNativeName)     \
-    _(GetElem_NativePrototypeCallNativeSymbol)   \
-    _(GetElem_NativePrototypeCallScriptedName)   \
-    _(GetElem_NativePrototypeCallScriptedSymbol) \
-    _(GetElem_UnboxedPropertyName)               \
     _(GetElem_String)                            \
     _(GetElem_Dense)                             \
     _(GetElem_UnboxedArray)                      \
     _(GetElem_TypedArray)                        \
     _(GetElem_Arguments)                         \
                                                  \
     _(SetElem_Fallback)                          \
     _(SetElem_DenseOrUnboxedArray)               \
--- a/js/src/jit/BaselineInspector.cpp
+++ b/js/src/jit/BaselineInspector.cpp
@@ -1015,25 +1015,16 @@ BaselineInspector::expectedPropertyAcces
 
           case ICStub::GetProp_Generic:
             return MIRType::Value;
 
           case ICStub::GetElem_Arguments:
             // Either an object or magic arguments.
             return MIRType::Value;
 
-          case ICStub::GetElem_NativeSlotName:
-          case ICStub::GetElem_NativeSlotSymbol:
-          case ICStub::GetElem_NativePrototypeSlotName:
-          case ICStub::GetElem_NativePrototypeSlotSymbol:
-          case ICStub::GetElem_NativePrototypeCallNativeName:
-          case ICStub::GetElem_NativePrototypeCallNativeSymbol:
-          case ICStub::GetElem_NativePrototypeCallScriptedName:
-          case ICStub::GetElem_NativePrototypeCallScriptedSymbol:
-          case ICStub::GetElem_UnboxedPropertyName:
           case ICStub::GetElem_String:
           case ICStub::GetElem_Dense:
           case ICStub::GetElem_TypedArray:
           case ICStub::GetElem_UnboxedArray:
             stubType = MIRType::Object;
             break;
 
           case ICStub::CacheIR_Monitored:
--- a/js/src/jit/CacheIR.cpp
+++ b/js/src/jit/CacheIR.cpp
@@ -14,26 +14,28 @@
 #include "vm/UnboxedObject-inl.h"
 
 using namespace js;
 using namespace js::jit;
 
 using mozilla::Maybe;
 
 GetPropIRGenerator::GetPropIRGenerator(JSContext* cx, jsbytecode* pc, ICStubEngine engine,
+                                       CacheKind cacheKind,
                                        bool* isTemporarilyUnoptimizable,
                                        HandleValue val, HandleValue idVal,
                                        MutableHandleValue res)
   : writer(cx),
     cx_(cx),
     pc_(pc),
     val_(val),
     idVal_(idVal),
     res_(res),
     engine_(engine),
+    cacheKind_(cacheKind),
     isTemporarilyUnoptimizable_(isTemporarilyUnoptimizable),
     preliminaryObjectAction_(PreliminaryObjectAction::None)
 {}
 
 static void
 EmitLoadSlotResult(CacheIRWriter& writer, ObjOperandId holderOp, NativeObject* holder,
                    Shape* shape)
 {
@@ -46,48 +48,60 @@ EmitLoadSlotResult(CacheIRWriter& writer
 }
 
 bool
 GetPropIRGenerator::tryAttachStub()
 {
     AutoAssertNoPendingException aanpe(cx_);
 
     ValOperandId valId(writer.setInputOperandId(0));
+    if (cacheKind_ == CacheKind::GetElem) {
+        MOZ_ASSERT(getElemKeyValueId().id() == 1);
+        writer.setInputOperandId(1);
+    }
 
-    RootedId id(cx_, INTERNED_STRING_TO_JSID(cx_, idVal_.toString())); //XXX
+    RootedId id(cx_);
+    bool nameOrSymbol;
+    if (!ValueToNameOrSymbolId(cx_, idVal_, &id, &nameOrSymbol)) {
+        cx_->clearPendingException();
+        return false;
+    }
 
     if (val_.isObject()) {
         RootedObject obj(cx_, &val_.toObject());
         ObjOperandId objId = writer.guardIsObject(valId);
-
-        if (tryAttachObjectLength(obj, objId, id))
-            return true;
-        if (tryAttachNative(obj, objId, id))
-            return true;
-        if (tryAttachUnboxed(obj, objId, id))
-            return true;
-        if (tryAttachUnboxedExpando(obj, objId, id))
-            return true;
-        if (tryAttachTypedObject(obj, objId, id))
-            return true;
-        if (tryAttachModuleNamespace(obj, objId, id))
-            return true;
-        if (tryAttachWindowProxy(obj, objId, id))
-            return true;
-        if (tryAttachProxy(obj, objId, id))
-            return true;
+        if (nameOrSymbol) {
+            if (tryAttachObjectLength(obj, objId, id))
+                return true;
+            if (tryAttachNative(obj, objId, id))
+                return true;
+            if (tryAttachUnboxed(obj, objId, id))
+                return true;
+            if (tryAttachUnboxedExpando(obj, objId, id))
+                return true;
+            if (tryAttachTypedObject(obj, objId, id))
+                return true;
+            if (tryAttachModuleNamespace(obj, objId, id))
+                return true;
+            if (tryAttachWindowProxy(obj, objId, id))
+                return true;
+            if (tryAttachProxy(obj, objId, id))
+                return true;
+        }
         return false;
     }
 
-    if (tryAttachPrimitive(valId, id))
-        return true;
-    if (tryAttachStringLength(valId, id))
-        return true;
-    if (tryAttachMagicArguments(valId, id))
-        return true;
+    if (nameOrSymbol) {
+        if (tryAttachPrimitive(valId, id))
+            return true;
+        if (tryAttachStringLength(valId, id))
+            return true;
+        if (tryAttachMagicArguments(valId, id))
+            return true;
+    }
 
     return false;
 }
 
 static bool
 IsCacheableNoProperty(JSContext* cx, JSObject* obj, JSObject* holder, Shape* shape, jsid id,
                       jsbytecode* pc)
 {
@@ -309,30 +323,32 @@ GetPropIRGenerator::tryAttachNative(Hand
     RootedNativeObject holder(cx_);
 
     NativeGetPropCacheability type = CanAttachNativeGetProp(cx_, obj, id, &holder, &shape, pc_,
                                                             engine_, isTemporarilyUnoptimizable_);
     switch (type) {
       case CanAttachNone:
         return false;
       case CanAttachReadSlot:
+        maybeEmitIdGuard(id);
         if (holder) {
             EnsureTrackPropertyTypes(cx_, holder, id);
             if (obj == holder) {
                 // See the comment in StripPreliminaryObjectStubs.
                 if (IsPreliminaryObject(obj))
                     preliminaryObjectAction_ = PreliminaryObjectAction::NotePreliminary;
                 else
                     preliminaryObjectAction_ = PreliminaryObjectAction::Unlink;
             }
         }
         EmitReadSlotResult(writer, obj, holder, shape, objId);
         EmitReadSlotReturn(writer, obj, holder, shape);
         return true;
       case CanAttachCallGetter:
+        maybeEmitIdGuard(id);
         EmitCallGetterResult(writer, obj, holder, shape, objId);
         return true;
     }
 
     MOZ_CRASH("Bad NativeGetPropCacheability");
 }
 
 bool
@@ -367,16 +383,17 @@ GetPropIRGenerator::tryAttachWindowProxy
     // instead of the WindowProxy as |this| value.
     JSFunction* callee = &shape->getterObject()->as<JSFunction>();
     MOZ_ASSERT(callee->isNative());
     if (!callee->jitInfo() || callee->jitInfo()->needsOuterizedThisObject())
         return false;
 
     // Guard the incoming object is a WindowProxy and inline a getter call based
     // on the Window object.
+    maybeEmitIdGuard(id);
     writer.guardClass(objId, GuardClassKind::WindowProxy);
     ObjOperandId windowObjId = writer.loadObject(windowObj);
     EmitCallGetterResult(writer, windowObj, holder, shape, windowObjId);
     return true;
 }
 
 bool
 GetPropIRGenerator::tryAttachGenericProxy(HandleObject obj, ObjOperandId objId, HandleId id)
@@ -384,26 +401,36 @@ GetPropIRGenerator::tryAttachGenericProx
     MOZ_ASSERT(obj->is<ProxyObject>());
 
     writer.guardIsProxy(objId);
 
     // Ensure that the incoming object is not a DOM proxy, so that we can get to
     // the specialized stubs
     writer.guardNotDOMProxy(objId);
 
-    writer.callProxyGetResult(objId, id);
+    if (cacheKind_ == CacheKind::GetProp) {
+        writer.callProxyGetResult(objId, id);
+    } else {
+        // We could call maybeEmitIdGuard here and then emit CallProxyGetResult,
+        // but for GetElem we prefer to attach a stub that can handle any Value
+        // so we don't attach a new stub for every id.
+        MOZ_ASSERT(cacheKind_ == CacheKind::GetElem);
+        writer.callProxyGetByValueResult(objId, getElemKeyValueId());
+    }
+
     writer.typeMonitorResult();
     return true;
 }
 
 bool
 GetPropIRGenerator::tryAttachDOMProxyShadowed(HandleObject obj, ObjOperandId objId, HandleId id)
 {
     MOZ_ASSERT(IsCacheableDOMProxy(obj));
 
+    maybeEmitIdGuard(id);
     writer.guardShape(objId, obj->maybeShape());
 
     // No need for more guards: we know this is a DOM proxy, since the shape
     // guard enforces a given JSClass, so just go ahead and emit the call to
     // ProxyGet.
     writer.callProxyGetResult(objId, id);
     writer.typeMonitorResult();
     return true;
@@ -453,16 +480,17 @@ GetPropIRGenerator::tryAttachDOMProxyUns
     RootedShape shape(cx_);
 
     NativeGetPropCacheability canCache = CanAttachNativeGetProp(cx_, checkObj, id, &holder, &shape,
                                                                 pc_, engine_,
                                                                 isTemporarilyUnoptimizable_);
     if (canCache == CanAttachNone)
         return false;
 
+    maybeEmitIdGuard(id);
     writer.guardShape(objId, obj->maybeShape());
 
     // Guard that our expando object hasn't started shadowing this property.
     CheckDOMProxyExpandoDoesNotShadow(writer, obj, id, objId);
 
     if (holder) {
         // Found the property on the prototype chain. Treat it like a native
         // getprop.
@@ -524,16 +552,17 @@ GetPropIRGenerator::tryAttachUnboxed(Han
 
     const UnboxedLayout::Property* property = obj->as<UnboxedPlainObject>().layout().lookup(id);
     if (!property)
         return false;
 
     if (!cx_->runtime()->jitSupportsFloatingPoint)
         return false;
 
+    maybeEmitIdGuard(id);
     writer.guardGroup(objId, obj->group());
     writer.loadUnboxedPropertyResult(objId, property->type,
                                      UnboxedPlainObject::offsetOfData() + property->offset);
     if (property->type == JSVAL_TYPE_OBJECT)
         writer.typeMonitorResult();
     else
         writer.returnFromIC();
 
@@ -550,16 +579,17 @@ GetPropIRGenerator::tryAttachUnboxedExpa
     UnboxedExpandoObject* expando = obj->as<UnboxedPlainObject>().maybeExpando();
     if (!expando)
         return false;
 
     Shape* shape = expando->lookup(cx_, id);
     if (!shape || !shape->hasDefaultGetter() || !shape->hasSlot())
         return false;
 
+    maybeEmitIdGuard(id);
     EmitReadSlotResult(writer, obj, obj, shape, objId);
     EmitReadSlotReturn(writer, obj, obj, shape);
     return true;
 }
 
 bool
 GetPropIRGenerator::tryAttachTypedObject(HandleObject obj, ObjOperandId objId, HandleId id)
 {
@@ -584,16 +614,17 @@ GetPropIRGenerator::tryAttachTypedObject
         return false;
 
     Shape* shape = typedObj->maybeShape();
     TypedThingLayout layout = GetTypedThingLayout(shape->getObjectClass());
 
     uint32_t fieldOffset = structDescr->fieldOffset(fieldIndex);
     uint32_t typeDescr = SimpleTypeDescrKey(&fieldDescr->as<SimpleTypeDescr>());
 
+    maybeEmitIdGuard(id);
     writer.guardNoDetachedTypedObjects();
     writer.guardShape(objId, shape);
     writer.loadTypedObjectResult(objId, fieldOffset, layout, typeDescr);
 
     // Only monitor the result if the type produced by this stub might vary.
     bool monitorLoad = false;
     if (SimpleTypeDescrKeyIsScalar(typeDescr)) {
         Scalar::Type type = ScalarTypeFromSimpleTypeDescrKey(typeDescr);
@@ -618,30 +649,33 @@ GetPropIRGenerator::tryAttachObjectLengt
         return false;
 
     if (obj->is<ArrayObject>()) {
         // Make sure int32 is added to the TypeSet before we attach a stub, so
         // the stub can return int32 values without monitoring the result.
         if (obj->as<ArrayObject>().length() > INT32_MAX)
             return false;
 
+        maybeEmitIdGuard(id);
         writer.guardClass(objId, GuardClassKind::Array);
         writer.loadInt32ArrayLengthResult(objId);
         writer.returnFromIC();
         return true;
     }
 
     if (obj->is<UnboxedArrayObject>()) {
+        maybeEmitIdGuard(id);
         writer.guardClass(objId, GuardClassKind::UnboxedArray);
         writer.loadUnboxedArrayLengthResult(objId);
         writer.returnFromIC();
         return true;
     }
 
     if (obj->is<ArgumentsObject>() && !obj->as<ArgumentsObject>().hasOverriddenLength()) {
+        maybeEmitIdGuard(id);
         if (obj->is<MappedArgumentsObject>()) {
             writer.guardClass(objId, GuardClassKind::MappedArguments);
         } else {
             MOZ_ASSERT(obj->is<UnmappedArgumentsObject>());
             writer.guardClass(objId, GuardClassKind::UnmappedArguments);
         }
         writer.loadArgumentsObjectLengthResult(objId);
         writer.returnFromIC();
@@ -666,16 +700,17 @@ GetPropIRGenerator::tryAttachModuleNames
     // Don't emit a stub until the target binding has been initialized.
     if (env->getSlot(shape->slot()).isMagic(JS_UNINITIALIZED_LEXICAL))
         return false;
 
     if (IsIonEnabled(cx_))
         EnsureTrackPropertyTypes(cx_, env, shape->propid());
 
     // Check for the specific namespace object.
+    maybeEmitIdGuard(id);
     writer.guardSpecificObject(objId, ns);
 
     ObjOperandId envId = writer.loadObject(env);
     EmitLoadSlotResult(writer, envId, env, shape);
     writer.typeMonitorResult();
     return true;
 }
 
@@ -712,51 +747,76 @@ GetPropIRGenerator::tryAttachPrimitive(V
         EnsureTrackPropertyTypes(cx_, proto, id);
 
     // For now, only look for properties directly set on the prototype.
     Shape* shape = proto->lookup(cx_, id);
     if (!shape || !shape->hasSlot() || !shape->hasDefaultGetter())
         return false;
 
     writer.guardType(valId, primitiveType);
+    maybeEmitIdGuard(id);
 
     ObjOperandId protoId = writer.loadObject(proto);
     writer.guardShape(protoId, proto->lastProperty());
     EmitLoadSlotResult(writer, protoId, proto, shape);
     writer.typeMonitorResult();
     return true;
 }
 
 bool
 GetPropIRGenerator::tryAttachStringLength(ValOperandId valId, HandleId id)
 {
     if (!val_.isString() || !JSID_IS_ATOM(id, cx_->names().length))
         return false;
 
     StringOperandId strId = writer.guardIsString(valId);
+    maybeEmitIdGuard(id);
     writer.loadStringLengthResult(strId);
     writer.returnFromIC();
     return true;
 }
 
 bool
 GetPropIRGenerator::tryAttachMagicArguments(ValOperandId valId, HandleId id)
 {
     if (!val_.isMagic(JS_OPTIMIZED_ARGUMENTS))
         return false;
 
     if (!JSID_IS_ATOM(id, cx_->names().length) && !JSID_IS_ATOM(id, cx_->names().callee))
         return false;
 
+    maybeEmitIdGuard(id);
     writer.guardMagicValue(valId, JS_OPTIMIZED_ARGUMENTS);
     writer.guardFrameHasNoArgumentsObject();
 
     if (JSID_IS_ATOM(id, cx_->names().length)) {
         writer.loadFrameNumActualArgsResult();
         writer.returnFromIC();
     } else {
         MOZ_ASSERT(JSID_IS_ATOM(id, cx_->names().callee));
         writer.loadFrameCalleeResult();
         writer.typeMonitorResult();
     }
 
     return true;
 }
+
+void
+GetPropIRGenerator::maybeEmitIdGuard(jsid id)
+{
+    if (cacheKind_ == CacheKind::GetProp) {
+        // Constant PropertyName, no guards necessary.
+        MOZ_ASSERT(&idVal_.toString()->asAtom() == JSID_TO_ATOM(id));
+        return;
+    }
+
+    MOZ_ASSERT(cacheKind_ == CacheKind::GetElem);
+
+    ValOperandId valId = getElemKeyValueId();
+    if (JSID_IS_SYMBOL(id)) {
+        SymbolOperandId symId = writer.guardIsSymbol(valId);
+        writer.guardSpecificSymbol(symId, JSID_TO_SYMBOL(id));
+    } else {
+        MOZ_ASSERT(JSID_IS_ATOM(id));
+        StringOperandId strId = writer.guardIsString(valId);
+        writer.guardSpecificAtom(strId, JSID_TO_ATOM(id));
+    }
+}
--- a/js/src/jit/CacheIR.h
+++ b/js/src/jit/CacheIR.h
@@ -81,42 +81,61 @@ class ObjOperandId : public OperandId
 
 class StringOperandId : public OperandId
 {
   public:
     StringOperandId() = default;
     explicit StringOperandId(uint16_t id) : OperandId(id) {}
 };
 
+class SymbolOperandId : public OperandId
+{
+  public:
+    SymbolOperandId() = default;
+    explicit SymbolOperandId(uint16_t id) : OperandId(id) {}
+};
+
 class TypedOperandId : public OperandId
 {
     JSValueType type_;
 
   public:
     MOZ_IMPLICIT TypedOperandId(ObjOperandId id)
       : OperandId(id.id()), type_(JSVAL_TYPE_OBJECT)
     {}
     MOZ_IMPLICIT TypedOperandId(StringOperandId id)
       : OperandId(id.id()), type_(JSVAL_TYPE_STRING)
     {}
+    MOZ_IMPLICIT TypedOperandId(SymbolOperandId id)
+      : OperandId(id.id()), type_(JSVAL_TYPE_SYMBOL)
+    {}
 
     JSValueType type() const { return type_; }
 };
 
+enum class CacheKind : uint8_t
+{
+    GetProp,
+    GetElem,
+};
+
 #define CACHE_IR_OPS(_)                   \
     _(GuardIsObject)                      \
     _(GuardIsString)                      \
+    _(GuardIsSymbol)                      \
     _(GuardType)                          \
     _(GuardShape)                         \
     _(GuardGroup)                         \
     _(GuardProto)                         \
     _(GuardClass)                         \
     _(GuardIsProxy)                       \
     _(GuardNotDOMProxy)                   \
     _(GuardSpecificObject)                \
+    _(GuardSpecificAtom)                  \
+    _(GuardSpecificSymbol)                \
     _(GuardNoDetachedTypedObjects)        \
     _(GuardMagicValue)                    \
     _(GuardFrameHasNoArgumentsObject)     \
     _(GuardNoUnboxedExpando)              \
     _(GuardAndLoadUnboxedExpando)         \
     _(LoadObject)                         \
     _(LoadProto)                          \
                                           \
@@ -133,16 +152,17 @@ class TypedOperandId : public OperandId
     _(LoadUnboxedArrayLengthResult)       \
     _(LoadArgumentsObjectLengthResult)    \
     _(LoadStringLengthResult)             \
     _(LoadFrameCalleeResult)              \
     _(LoadFrameNumActualArgsResult)       \
     _(CallScriptedGetterResult)           \
     _(CallNativeGetterResult)             \
     _(CallProxyGetResult)                 \
+    _(CallProxyGetByValueResult)          \
     _(LoadUndefinedResult)                \
                                           \
     _(TypeMonitorResult)                  \
     _(ReturnFromIC)
 
 enum class CacheOp {
 #define DEFINE_OP(op) op,
     CACHE_IR_OPS(DEFINE_OP)
@@ -153,16 +173,18 @@ class StubField
 {
   public:
     enum class Type : uint8_t {
         // These fields take up a single word.
         RawWord,
         Shape,
         ObjectGroup,
         JSObject,
+        Symbol,
+        String,
         Id,
 
         // These fields take up 64 bits on all platforms.
         RawInt64,
         First64BitType = RawInt64,
         Value,
 
         Limit
@@ -337,16 +359,20 @@ class MOZ_RAII CacheIRWriter : public JS
     ObjOperandId guardIsObject(ValOperandId val) {
         writeOpWithOperandId(CacheOp::GuardIsObject, val);
         return ObjOperandId(val.id());
     }
     StringOperandId guardIsString(ValOperandId val) {
         writeOpWithOperandId(CacheOp::GuardIsString, val);
         return StringOperandId(val.id());
     }
+    SymbolOperandId guardIsSymbol(ValOperandId val) {
+        writeOpWithOperandId(CacheOp::GuardIsSymbol, val);
+        return SymbolOperandId(val.id());
+    }
     void guardType(ValOperandId val, JSValueType type) {
         writeOpWithOperandId(CacheOp::GuardType, val);
         static_assert(sizeof(type) == sizeof(uint8_t), "JSValueType should fit in a byte");
         buffer_.writeByte(uint32_t(type));
     }
     void guardShape(ObjOperandId obj, Shape* shape) {
         writeOpWithOperandId(CacheOp::GuardShape, obj);
         addStubField(uintptr_t(shape), StubField::Type::Shape);
@@ -370,16 +396,24 @@ class MOZ_RAII CacheIRWriter : public JS
     }
     void guardNotDOMProxy(ObjOperandId obj) {
         writeOpWithOperandId(CacheOp::GuardNotDOMProxy, obj);
     }
     void guardSpecificObject(ObjOperandId obj, JSObject* expected) {
         writeOpWithOperandId(CacheOp::GuardSpecificObject, obj);
         addStubField(uintptr_t(expected), StubField::Type::JSObject);
     }
+    void guardSpecificAtom(StringOperandId str, JSAtom* expected) {
+        writeOpWithOperandId(CacheOp::GuardSpecificAtom, str);
+        addStubField(uintptr_t(expected), StubField::Type::String);
+    }
+    void guardSpecificSymbol(SymbolOperandId sym, JS::Symbol* expected) {
+        writeOpWithOperandId(CacheOp::GuardSpecificSymbol, sym);
+        addStubField(uintptr_t(expected), StubField::Type::Symbol);
+    }
     void guardMagicValue(ValOperandId val, JSWhyMagic magic) {
         writeOpWithOperandId(CacheOp::GuardMagicValue, val);
         buffer_.writeByte(uint32_t(magic));
     }
     void guardNoDetachedTypedObjects() {
         writeOp(CacheOp::GuardNoDetachedTypedObjects);
     }
     void guardFrameHasNoArgumentsObject() {
@@ -480,16 +514,20 @@ class MOZ_RAII CacheIRWriter : public JS
     void callNativeGetterResult(ObjOperandId obj, JSFunction* getter) {
         writeOpWithOperandId(CacheOp::CallNativeGetterResult, obj);
         addStubField(uintptr_t(getter), StubField::Type::JSObject);
     }
     void callProxyGetResult(ObjOperandId obj, jsid id) {
         writeOpWithOperandId(CacheOp::CallProxyGetResult, obj);
         addStubField(uintptr_t(JSID_BITS(id)), StubField::Type::Id);
     }
+    void callProxyGetByValueResult(ObjOperandId obj, ValOperandId idVal) {
+        writeOpWithOperandId(CacheOp::CallProxyGetByValueResult, obj);
+        writeOperandId(idVal);
+    }
 
     void typeMonitorResult() {
         writeOp(CacheOp::TypeMonitorResult);
     }
     void returnFromIC() {
         writeOp(CacheOp::ReturnFromIC);
     }
 };
@@ -517,16 +555,17 @@ class MOZ_RAII CacheIRReader
 
     CacheOp readOp() {
         return CacheOp(buffer_.readByte());
     }
 
     ValOperandId valOperandId() { return ValOperandId(buffer_.readByte()); }
     ObjOperandId objOperandId() { return ObjOperandId(buffer_.readByte()); }
     StringOperandId stringOperandId() { return StringOperandId(buffer_.readByte()); }
+    SymbolOperandId symbolOperandId() { return SymbolOperandId(buffer_.readByte()); }
 
     uint32_t stubOffset() { return buffer_.readByte() * sizeof(uintptr_t); }
     GuardClassKind guardClassKind() { return GuardClassKind(buffer_.readByte()); }
     JSValueType valueType() { return JSValueType(buffer_.readByte()); }
     TypedThingLayout typedThingLayout() { return TypedThingLayout(buffer_.readByte()); }
     uint32_t typeDescrKey() { return buffer_.readByte(); }
     JSWhyMagic whyMagic() { return JSWhyMagic(buffer_.readByte()); }
 
@@ -559,16 +598,17 @@ class MOZ_RAII GetPropIRGenerator
 {
     CacheIRWriter writer;
     JSContext* cx_;
     jsbytecode* pc_;
     HandleValue val_;
     HandleValue idVal_;
     MutableHandleValue res_;
     ICStubEngine engine_;
+    CacheKind cacheKind_;
     bool* isTemporarilyUnoptimizable_;
 
     enum class PreliminaryObjectAction { None, Unlink, NotePreliminary };
     PreliminaryObjectAction preliminaryObjectAction_;
 
     bool tryAttachNative(HandleObject obj, ObjOperandId objId, HandleId id);
     bool tryAttachUnboxed(HandleObject obj, ObjOperandId objId, HandleId id);
     bool tryAttachUnboxedExpando(HandleObject obj, ObjOperandId objId, HandleId id);
@@ -581,38 +621,42 @@ class MOZ_RAII GetPropIRGenerator
     bool tryAttachDOMProxyShadowed(HandleObject obj, ObjOperandId objId, HandleId id);
     bool tryAttachDOMProxyUnshadowed(HandleObject obj, ObjOperandId objId, HandleId id);
     bool tryAttachProxy(HandleObject obj, ObjOperandId objId, HandleId id);
 
     bool tryAttachPrimitive(ValOperandId valId, HandleId id);
     bool tryAttachStringLength(ValOperandId valId, HandleId id);
     bool tryAttachMagicArguments(ValOperandId valId, HandleId id);
 
+    ValOperandId getElemKeyValueId() const {
+        MOZ_ASSERT(cacheKind_ == CacheKind::GetElem);
+        return ValOperandId(1);
+    }
+
+    // If this is a GetElem cache, emit instructions to guard the incoming Value
+    // matches |id|.
+    void maybeEmitIdGuard(jsid id);
+
     GetPropIRGenerator(const GetPropIRGenerator&) = delete;
     GetPropIRGenerator& operator=(const GetPropIRGenerator&) = delete;
 
   public:
-    GetPropIRGenerator(JSContext* cx, jsbytecode* pc, ICStubEngine engine,
+    GetPropIRGenerator(JSContext* cx, jsbytecode* pc, ICStubEngine engine, CacheKind cacheKind,
                        bool* isTemporarilyUnoptimizable,
                        HandleValue val, HandleValue idVal, MutableHandleValue res);
 
     bool tryAttachStub();
 
     bool shouldUnlinkPreliminaryObjectStubs() const {
         return preliminaryObjectAction_ == PreliminaryObjectAction::Unlink;
     }
     bool shouldNotePreliminaryObjectStub() const {
         return preliminaryObjectAction_ == PreliminaryObjectAction::NotePreliminary;
     }
-    const CacheIRWriter& writerRef() const {
-        return writer;
-    }
-};
 
-enum class CacheKind : uint8_t
-{
-    GetProp
+    const CacheIRWriter& writerRef() const { return writer; }
+    CacheKind cacheKind() const { return cacheKind_; }
 };
 
 } // namespace jit
 } // namespace js
 
 #endif /* jit_CacheIR_h */
--- a/js/src/jit/IonCaches.cpp
+++ b/js/src/jit/IonCaches.cpp
@@ -1353,30 +1353,16 @@ CanAttachNativeGetProp(JSContext* cx, co
         // Don't enable getter call if cache is idempotent, since they can be
         // effectful. This is handled by allowGetters()
         return GetPropertyIC::CanAttachCallGetter;
     }
 
     return GetPropertyIC::CanAttachNone;
 }
 
-static bool
-EqualStringsHelper(JSString* str1, JSString* str2)
-{
-    MOZ_ASSERT(str1->isAtom());
-    MOZ_ASSERT(!str2->isAtom());
-    MOZ_ASSERT(str1->length() == str2->length());
-
-    JSLinearString* str2Linear = str2->ensureLinear(nullptr);
-    if (!str2Linear)
-        return false;
-
-    return EqualChars(&str1->asLinear(), str2Linear);
-}
-
 static void
 EmitIdGuard(MacroAssembler& masm, jsid id, TypedOrValueRegister idReg, Register objReg,
             Register scratchReg, Label* failures)
 {
     MOZ_ASSERT(JSID_IS_STRING(id) || JSID_IS_SYMBOL(id));
 
     MOZ_ASSERT(idReg.type() == MIRType::String ||
                idReg.type() == MIRType::Symbol ||
@@ -2139,18 +2125,19 @@ GetPropertyIC::tryAttachModuleNamespace(
     Label* maybeFailures = failures.used() ? &failures : nullptr;
 
     GenerateReadModuleNamespace(cx, ion, masm, attacher, ns, env,
                                 shape, object(), output(), maybeFailures);
     return linkAndAttachStub(cx, masm, attacher, ion, "module namespace",
                              JS::TrackedOutcome::ICGetPropStub_ReadSlot);
 }
 
-static bool
-ValueToNameOrSymbolId(JSContext* cx, HandleValue idval, MutableHandleId id, bool* nameOrSymbol)
+bool
+jit::ValueToNameOrSymbolId(JSContext* cx, HandleValue idval, MutableHandleId id,
+                           bool* nameOrSymbol)
 {
     *nameOrSymbol = false;
 
     if (!idval.isString() && !idval.isSymbol())
         return true;
 
     if (!ValueToId<CanGC>(cx, idval, id))
         return false;
--- a/js/src/jit/IonCaches.h
+++ b/js/src/jit/IonCaches.h
@@ -841,12 +841,15 @@ IONCACHE_KIND_LIST(CACHE_CASTS)
 
 bool IsCacheableProtoChainForIonOrCacheIR(JSObject* obj, JSObject* holder);
 bool IsCacheableGetPropReadSlotForIonOrCacheIR(JSObject* obj, JSObject* holder, Shape* shape);
 
 bool IsCacheableGetPropCallScripted(JSObject* obj, JSObject* holder, Shape* shape,
                                     bool* isTemporarilyUnoptimizable = nullptr);
 bool IsCacheableGetPropCallNative(JSObject* obj, JSObject* holder, Shape* shape);
 
+bool ValueToNameOrSymbolId(JSContext* cx, HandleValue idval, MutableHandleId id,
+                           bool* nameOrSymbol);
+
 } // namespace jit
 } // namespace js
 
 #endif /* jit_IonCaches_h */
--- a/js/src/jit/SharedIC.cpp
+++ b/js/src/jit/SharedIC.cpp
@@ -170,25 +170,16 @@ ICStub::NonCacheIRStubMakesGCCalls(Kind 
       case Call_AnyScripted:
       case Call_Native:
       case Call_ClassHook:
       case Call_ScriptedApplyArray:
       case Call_ScriptedApplyArguments:
       case Call_ScriptedFunCall:
       case Call_StringSplit:
       case WarmUpCounter_Fallback:
-      case GetElem_NativeSlotName:
-      case GetElem_NativeSlotSymbol:
-      case GetElem_NativePrototypeSlotName:
-      case GetElem_NativePrototypeSlotSymbol:
-      case GetElem_NativePrototypeCallNativeName:
-      case GetElem_NativePrototypeCallNativeSymbol:
-      case GetElem_NativePrototypeCallScriptedName:
-      case GetElem_NativePrototypeCallScriptedSymbol:
-      case GetElem_UnboxedPropertyName:
       case GetProp_CallNativeGlobal:
       case GetProp_Generic:
       case SetProp_CallScripted:
       case SetProp_CallNative:
       case RetSub_Fallback:
       // These two fallback stubs don't actually make non-tail calls,
       // but the fallback code for the bailout path needs to pop the stub frame
       // pushed during the bailout.
@@ -267,73 +258,16 @@ ICStub::trace(JSTracer* trc)
       }
       case ICStub::Call_StringSplit: {
         ICCall_StringSplit* callStub = toCall_StringSplit();
         TraceEdge(trc, &callStub->templateObject(), "baseline-callstringsplit-template");
         TraceEdge(trc, &callStub->expectedSep(), "baseline-callstringsplit-sep");
         TraceEdge(trc, &callStub->expectedStr(), "baseline-callstringsplit-str");
         break;
       }
-      case ICStub::GetElem_NativeSlotName:
-      case ICStub::GetElem_NativeSlotSymbol:
-      case ICStub::GetElem_UnboxedPropertyName: {
-        ICGetElemNativeStub* getElemStub = static_cast<ICGetElemNativeStub*>(this);
-        getElemStub->receiverGuard().trace(trc);
-        if (getElemStub->isSymbol()) {
-            ICGetElem_NativeSlot<JS::Symbol*>* typedGetElemStub = toGetElem_NativeSlotSymbol();
-            TraceEdge(trc, &typedGetElemStub->key(), "baseline-getelem-native-key");
-        } else {
-            ICGetElemNativeSlotStub<PropertyName*>* typedGetElemStub =
-                reinterpret_cast<ICGetElemNativeSlotStub<PropertyName*>*>(this);
-            TraceEdge(trc, &typedGetElemStub->key(), "baseline-getelem-native-key");
-        }
-        break;
-      }
-      case ICStub::GetElem_NativePrototypeSlotName:
-      case ICStub::GetElem_NativePrototypeSlotSymbol: {
-        ICGetElemNativeStub* getElemStub = static_cast<ICGetElemNativeStub*>(this);
-        getElemStub->receiverGuard().trace(trc);
-        if (getElemStub->isSymbol()) {
-            ICGetElem_NativePrototypeSlot<JS::Symbol*>* typedGetElemStub
-                = toGetElem_NativePrototypeSlotSymbol();
-            TraceEdge(trc, &typedGetElemStub->key(), "baseline-getelem-nativeproto-key");
-            TraceEdge(trc, &typedGetElemStub->holder(), "baseline-getelem-nativeproto-holder");
-            TraceEdge(trc, &typedGetElemStub->holderShape(), "baseline-getelem-nativeproto-holdershape");
-        } else {
-            ICGetElem_NativePrototypeSlot<PropertyName*>* typedGetElemStub
-                = toGetElem_NativePrototypeSlotName();
-            TraceEdge(trc, &typedGetElemStub->key(), "baseline-getelem-nativeproto-key");
-            TraceEdge(trc, &typedGetElemStub->holder(), "baseline-getelem-nativeproto-holder");
-            TraceEdge(trc, &typedGetElemStub->holderShape(), "baseline-getelem-nativeproto-holdershape");
-        }
-        break;
-      }
-      case ICStub::GetElem_NativePrototypeCallNativeName:
-      case ICStub::GetElem_NativePrototypeCallNativeSymbol:
-      case ICStub::GetElem_NativePrototypeCallScriptedName:
-      case ICStub::GetElem_NativePrototypeCallScriptedSymbol: {
-        ICGetElemNativeStub* getElemStub = static_cast<ICGetElemNativeStub*>(this);
-        getElemStub->receiverGuard().trace(trc);
-        if (getElemStub->isSymbol()) {
-            ICGetElemNativePrototypeCallStub<JS::Symbol*>* callStub =
-                reinterpret_cast<ICGetElemNativePrototypeCallStub<JS::Symbol*>*>(this);
-            TraceEdge(trc, &callStub->key(), "baseline-getelem-nativeprotocall-key");
-            TraceEdge(trc, &callStub->getter(), "baseline-getelem-nativeprotocall-getter");
-            TraceEdge(trc, &callStub->holder(), "baseline-getelem-nativeprotocall-holder");
-            TraceEdge(trc, &callStub->holderShape(), "baseline-getelem-nativeprotocall-holdershape");
-        } else {
-            ICGetElemNativePrototypeCallStub<PropertyName*>* callStub =
-                reinterpret_cast<ICGetElemNativePrototypeCallStub<PropertyName*>*>(this);
-            TraceEdge(trc, &callStub->key(), "baseline-getelem-nativeprotocall-key");
-            TraceEdge(trc, &callStub->getter(), "baseline-getelem-nativeprotocall-getter");
-            TraceEdge(trc, &callStub->holder(), "baseline-getelem-nativeprotocall-holder");
-            TraceEdge(trc, &callStub->holderShape(), "baseline-getelem-nativeprotocall-holdershape");
-        }
-        break;
-      }
       case ICStub::GetElem_Dense: {
         ICGetElem_Dense* getElemStub = toGetElem_Dense();
         TraceEdge(trc, &getElemStub->shape(), "baseline-getelem-dense-shape");
         break;
       }
       case ICStub::GetElem_UnboxedArray: {
         ICGetElem_UnboxedArray* getElemStub = toGetElem_UnboxedArray();
         TraceEdge(trc, &getElemStub->group(), "baseline-getelem-unboxed-array-group");
@@ -2400,19 +2334,20 @@ DoGetPropFallback(JSContext* cx, void* p
         if (!newStub)
             return false;
         stub->addNewStub(newStub);
         attached = true;
     }
 
     if (!attached && !JitOptions.disableCacheIR) {
         RootedValue idVal(cx, StringValue(name));
-        GetPropIRGenerator gen(cx, pc, engine, &isTemporarilyUnoptimizable, val, idVal, res);
+        GetPropIRGenerator gen(cx, pc, engine, CacheKind::GetProp, &isTemporarilyUnoptimizable,
+                               val, idVal, res);
         if (gen.tryAttachStub()) {
-            ICStub* newStub = AttachBaselineCacheIRStub(cx, gen.writerRef(), CacheKind::GetProp,
+            ICStub* newStub = AttachBaselineCacheIRStub(cx, gen.writerRef(), gen.cacheKind(),
                                                         engine, info.outerScript(cx), stub);
             if (newStub) {
                 JitSpew(JitSpew_BaselineIC, "  Attached CacheIR stub");
                 attached = true;
                 if (gen.shouldNotePreliminaryObjectStub())
                     newStub->toCacheIR_Monitored()->notePreliminaryObject();
                 else if (gen.shouldUnlinkPreliminaryObjectStubs())
                     StripPreliminaryObjectStubs(cx, stub);
--- a/js/src/jit/VMFunctions.cpp
+++ b/js/src/jit/VMFunctions.cpp
@@ -1357,10 +1357,36 @@ BaselineGetFunctionThis(JSContext* cx, B
 
 bool
 ProxyGetProperty(JSContext* cx, HandleObject proxy, HandleId id, MutableHandleValue vp)
 {
     RootedValue receiver(cx, ObjectValue(*proxy));
     return Proxy::get(cx, proxy, receiver, id, vp);
 }
 
+bool
+ProxyGetPropertyByValue(JSContext* cx, HandleObject proxy, HandleValue idVal,
+                        MutableHandleValue vp)
+{
+    RootedId id(cx);
+    if (!ValueToId<CanGC>(cx, idVal, &id))
+        return false;
+
+    RootedValue receiver(cx, ObjectValue(*proxy));
+    return Proxy::get(cx, proxy, receiver, id, vp);
+}
+
+bool
+EqualStringsHelper(JSString* str1, JSString* str2)
+{
+    MOZ_ASSERT(str1->isAtom());
+    MOZ_ASSERT(!str2->isAtom());
+    MOZ_ASSERT(str1->length() == str2->length());
+
+    JSLinearString* str2Linear = str2->ensureLinear(nullptr);
+    if (!str2Linear)
+        return false;
+
+    return EqualChars(&str1->asLinear(), str2Linear);
+}
+
 } // namespace jit
 } // namespace js
--- a/js/src/jit/VMFunctions.h
+++ b/js/src/jit/VMFunctions.h
@@ -807,12 +807,19 @@ MOZ_MUST_USE bool
 ThrowObjectCoercible(JSContext* cx, HandleValue v);
 
 MOZ_MUST_USE bool
 BaselineGetFunctionThis(JSContext* cx, BaselineFrame* frame, MutableHandleValue res);
 
 MOZ_MUST_USE bool
 ProxyGetProperty(JSContext* cx, HandleObject proxy, HandleId id, MutableHandleValue vp);
 
+MOZ_MUST_USE bool
+ProxyGetPropertyByValue(JSContext* cx, HandleObject proxy, HandleValue idVal,
+                        MutableHandleValue vp);
+
+MOZ_MUST_USE bool
+EqualStringsHelper(JSString* str1, JSString* str2);
+
 } // namespace jit
 } // namespace js
 
 #endif /* jit_VMFunctions_h */