Backed out changesets 22770b30545b, 0809370fabdb, 4ef4764c1b55, and bfe768b87464 (bug 697343) due to Gaia UI test bustage.
authorRyan VanderMeulen <ryanvm@gmail.com>
Thu, 05 Dec 2013 16:19:47 -0500
changeset 174752 fbc0b4c30fd0fb53e5613e747ab5b9263170919a
parent 174751 53a630e3ed5e6181a55b63ff15ff7573db018d44
child 174753 2b398758366ce3cae904394dc9d79c35c75f5e89
push id445
push userffxbld
push dateMon, 10 Mar 2014 22:05:19 +0000
treeherdermozilla-release@dc38b741b04e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs697343
milestone28.0a1
backs out22770b30545b26ee7280f94c6126e59c1f49d16c
0809370fabdb4261b6025efe3cba71af06470edf
4ef4764c1b559115664fbd4534629e48d45e3cf0
bfe768b8746466df23f9f141b8ed32ba991bc5ff
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Backed out changesets 22770b30545b, 0809370fabdb, 4ef4764c1b55, and bfe768b87464 (bug 697343) due to Gaia UI test bustage. CLOSED TREE
dom/bindings/Codegen.py
dom/permission/tests/file_framework.js
js/public/Class.h
js/src/builtin/TypedObject.cpp
js/src/builtin/TypedObject.h
js/src/jit-test/tests/arrays/slice.js
js/src/jsapi.cpp
js/src/jsapi.h
js/src/jsarray.cpp
js/src/jsfriendapi.cpp
js/src/jsfriendapi.h
js/src/jsobj.h
js/src/jsobjinlines.h
js/src/jsproxy.cpp
js/src/jsproxy.h
js/src/jswrapper.cpp
js/src/jswrapper.h
js/src/vm/ScopeObject.cpp
js/src/vm/TypedArrayObject.cpp
js/src/vm/TypedArrayObject.h
js/xpconnect/src/XPCWrappedNativeJSOps.cpp
js/xpconnect/src/xpcprivate.h
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -7567,23 +7567,18 @@ class CGClassForwardDeclare(CGThing):
         return ''
     def deps(self):
         return set()
 
 class CGProxySpecialOperation(CGPerSignatureCall):
     """
     Base class for classes for calling an indexed or named special operation
     (don't use this directly, use the derived classes below).
-
-    If checkFound is False, will just assert that the prop is found instead of
-    checking that it is before wrapping the value.
-    """
-    def __init__(self, descriptor, operation, checkFound=True):
-        self.checkFound = checkFound;
-
+    """
+    def __init__(self, descriptor, operation):
         nativeName = MakeNativeName(descriptor.binaryNames.get(operation, operation))
         operation = descriptor.operations[operation]
         assert len(operation.signatures()) == 1
         signature = operation.signatures()[0]
 
         (returnType, arguments) = signature
 
         # We pass len(arguments) as the final argument so that the
@@ -7619,68 +7614,45 @@ class CGProxySpecialOperation(CGPerSigna
                          "found"))
         return args
 
     def wrap_return_value(self):
         if not self.idlNode.isGetter() or self.templateValues is None:
             return ""
 
         wrap = CGGeneric(wrapForType(self.returnType, self.descriptor, self.templateValues))
-        if self.checkFound:
-            wrap = CGIfWrapper(wrap, "found")
-        else:
-            wrap = CGList([CGGeneric("MOZ_ASSERT(found);"), wrap], "\n")
+        wrap = CGIfWrapper(wrap, "found")
         return "\n" + wrap.define()
 
 class CGProxyIndexedOperation(CGProxySpecialOperation):
     """
     Class to generate a call to an indexed operation.
-
-    If doUnwrap is False, the caller is responsible for making sure a variable
-    named 'self' holds the C++ object somewhere where the code we generate
-    will see it.
-
-    If checkFound is False, will just assert that the prop is found instead of
-    checking that it is before wrapping the value.
-    """
-    def __init__(self, descriptor, name, doUnwrap=True, checkFound=True):
-        self.doUnwrap = doUnwrap
-        CGProxySpecialOperation.__init__(self, descriptor, name, checkFound)
+    """
+    def __init__(self, descriptor, name):
+        CGProxySpecialOperation.__init__(self, descriptor, name)
     def define(self):
         # Our first argument is the id we're getting.
         argName = self.arguments[0].identifier.name
         if argName == "index":
             # We already have our index in a variable with that name
             setIndex = ""
         else:
             setIndex = "uint32_t %s = index;\n" % argName
-        if self.doUnwrap:
-            unwrap = "%s* self = UnwrapProxy(proxy);\n"
-        else:
-            unwrap = ""
-        return (setIndex + unwrap +
+        return (setIndex +
+                "%s* self = UnwrapProxy(proxy);\n" +
                 CGProxySpecialOperation.define(self))
 
 class CGProxyIndexedGetter(CGProxyIndexedOperation):
     """
     Class to generate a call to an indexed getter. If templateValues is not None
     the returned value will be wrapped with wrapForType using templateValues.
-
-    If doUnwrap is False, the caller is responsible for making sure a variable
-    named 'self' holds the C++ object somewhere where the code we generate
-    will see it.
-
-    If checkFound is False, will just assert that the prop is found instead of
-    checking that it is before wrapping the value.
-    """
-    def __init__(self, descriptor, templateValues=None, doUnwrap=True,
-                 checkFound=True):
+    """
+    def __init__(self, descriptor, templateValues=None):
         self.templateValues = templateValues
-        CGProxyIndexedOperation.__init__(self, descriptor, 'IndexedGetter',
-                                         doUnwrap, checkFound)
+        CGProxyIndexedOperation.__init__(self, descriptor, 'IndexedGetter')
 
 class CGProxyIndexedPresenceChecker(CGProxyIndexedGetter):
     """
     Class to generate a call that checks whether an indexed property exists.
 
     For now, we just delegate to CGProxyIndexedGetter
     """
     def __init__(self, descriptor):
@@ -8307,65 +8279,75 @@ class CGDOMJSProxyHandler_finalize(Class
     def __init__(self, descriptor):
         args = [Argument('JSFreeOp*', 'fop'), Argument('JSObject*', 'proxy')]
         ClassMethod.__init__(self, "finalize", "void", args)
         self.descriptor = descriptor
     def getBody(self):
         return ("%s self = UnwrapProxy(proxy);\n\n" % (self.descriptor.nativeType + "*") +
                 finalizeHook(self.descriptor, FINALIZE_HOOK_NAME, self.args[0].name).define())
 
-class CGDOMJSProxyHandler_slice(ClassMethod):
+class CGDOMJSProxyHandler_getElementIfPresent(ClassMethod):
     def __init__(self, descriptor):
-        assert descriptor.supportsIndexedProperties()
-
         args = [Argument('JSContext*', 'cx'),
                 Argument('JS::Handle<JSObject*>', 'proxy'),
-                Argument('uint32_t', 'begin'),
-                Argument('uint32_t', 'end'),
-                Argument('JS::Handle<JSObject*>', 'array')]
-        ClassMethod.__init__(self, "slice", "bool", args)
+                Argument('JS::Handle<JSObject*>', 'receiver'),
+                Argument('uint32_t', 'index'),
+                Argument('JS::MutableHandle<JS::Value>', 'vp'),
+                Argument('bool*', 'present')]
+        ClassMethod.__init__(self, "getElementIfPresent", "bool", args)
         self.descriptor = descriptor
-
     def getBody(self):
-        # Just like getOwnPropertyNames we'll assume that we have no holes, so
-        # we have all properties from 0 to length.  If that ever changes
-        # (unlikely), we'll need to do something a bit more clever with how we
-        # forward on to our ancestor.
-        header = CGGeneric(
-            'JS::Rooted<JS::Value> temp(cx);\n'
-            'MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy),\n'
-            '           "Should not have a XrayWrapper here");\n'
-            '\n'
-            '%s* self = UnwrapProxy(proxy);\n'
-            'uint32_t length = self->Length();\n'
-            "// Compute the end of the indices we'll get ourselves\n"
-            'uint32_t ourEnd = std::max(begin, std::min(end, length));' %
-            self.descriptor.nativeType)
-
-        successCode = ("js::UnsafeDefineElement(cx, array, index - begin, temp);\n"
-                       "continue;")
-        templateValues = {'jsvalRef': 'temp', 'jsvalHandle': '&temp',
+        successCode = ("*present = found;\n"
+                       "return true;")
+        templateValues = {'jsvalRef': 'vp', 'jsvalHandle': 'vp',
                           'obj': 'proxy', 'successCode': successCode}
-        get = CGProxyIndexedGetter(self.descriptor, templateValues, False, False)
-
-        getOurElements = CGWrapper(
-            CGIndenter(get),
-            pre="for (uint32_t index = begin; index < ourEnd; ++index) {\n",
-            post="\n}")
-
-        getProtoElements = CGIfWrapper(
-            CGGeneric("JS::Rooted<JSObject*> proto(cx);\n"
-                      "if (!js::GetObjectProto(cx, proxy, &proto)) {\n"
-                      "  return false;\n"
-                      "}\n"
-                      "return js::SliceSlowly(cx, proto, proxy, ourEnd, end, array);"),
-            "end > ourEnd")
-
-        return CGList([header, getOurElements, getProtoElements,
-                       CGGeneric("return true;")], "\n\n").define();
+        if self.descriptor.supportsIndexedProperties():
+            get = (CGProxyIndexedGetter(self.descriptor, templateValues).define() + "\n"
+                   "// We skip the expando object and any named getters if\n"
+                   "// there is an indexed getter.\n" +
+                   "\n") % (self.descriptor.nativeType)
+        else:
+            if self.descriptor.supportsNamedProperties():
+                get = CGProxyNamedGetter(self.descriptor, templateValues,
+                                         "UINT_TO_JSVAL(index)").define()
+            get += """
+
+JS::Rooted<JSObject*> expando(cx, GetExpandoObject(proxy));
+if (expando) {
+  bool isPresent;
+  if (!JS_GetElementIfPresent(cx, expando, index, expando, vp, &isPresent)) {
+    return false;
+  }
+  if (isPresent) {
+    *present = true;
+    return true;
+  }
+}
+"""
+
+        return """MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy),
+             "Should not have a XrayWrapper here");
+
+""" + get + """
+JS::Rooted<JSObject*> proto(cx);
+if (!js::GetObjectProto(cx, proxy, &proto)) {
+  return false;
+}
+if (proto) {
+  bool isPresent;
+  if (!JS_GetElementIfPresent(cx, proto, index, proxy, vp, &isPresent)) {
+    return false;
+  }
+  *present = isPresent;
+  return true;
+}
+
+*present = false;
+// Can't Debug_SetValueRangeToCrashOnTouch because it's not public
+return true;"""
 
 class CGDOMJSProxyHandler_getInstance(ClassMethod):
     def __init__(self):
         ClassMethod.__init__(self, "getInstance", "DOMProxyHandler*", [], static=True)
     def getBody(self):
         return """static DOMProxyHandler instance;
 return &instance;"""
 
@@ -8379,21 +8361,19 @@ class CGDOMJSProxyHandler(CGClass):
                    ClassUsingDeclaration("mozilla::dom::DOMProxyHandler",
                                          "defineProperty"),
                    CGDOMJSProxyHandler_getOwnPropertyNames(descriptor),
                    CGDOMJSProxyHandler_hasOwn(descriptor),
                    CGDOMJSProxyHandler_get(descriptor),
                    CGDOMJSProxyHandler_className(descriptor),
                    CGDOMJSProxyHandler_finalizeInBackground(descriptor),
                    CGDOMJSProxyHandler_finalize(descriptor),
+                   CGDOMJSProxyHandler_getElementIfPresent(descriptor),
                    CGDOMJSProxyHandler_getInstance(),
                    CGDOMJSProxyHandler_delete(descriptor)]
-        if descriptor.supportsIndexedProperties():
-            methods.append(CGDOMJSProxyHandler_slice(descriptor))
-
         CGClass.__init__(self, 'DOMProxyHandler',
                          bases=[ClassBase('mozilla::dom::DOMProxyHandler')],
                          constructors=constructors,
                          methods=methods)
 
 class CGDOMJSProxyHandlerDeclarer(CGThing):
     """
     A class for declaring a DOMProxyHandler.
--- a/dom/permission/tests/file_framework.js
+++ b/dom/permission/tests/file_framework.js
@@ -164,21 +164,17 @@ function addPermissions(aPerms, aDoc, aC
   SpecialPowers.pushPermissions(permList, aCallback);
 }
 
 function expandPermissions(aPerms) {
   var perms = [];
   aPerms.forEach(function(el) {
     var access = permTable[el].access ? "readwrite" : null;
     var expanded = SpecialPowers.unwrap(expand(el, access));
-    // COW arrays don't behave array-like enough, to allow
-    // using expanded.slice(0) here.
-    for (let i = 0; i < expanded.length; i++) {
-      perms.push(expanded[i]);
-    }
+    perms = perms.concat(expanded.slice(0));
   });
 
   return perms;
 }
 
 function msgHandler(evt) {
   var data = evt.data;
   var test = pendingTests[data.id];
--- a/js/public/Class.h
+++ b/js/public/Class.h
@@ -342,16 +342,19 @@ typedef bool
                 JS::MutableHandleValue vp);
 typedef bool
 (* PropertyIdOp)(JSContext *cx, JS::HandleObject obj, JS::HandleObject receiver,
                  JS::Handle<PropertyName*> name, JS::MutableHandleValue vp);
 typedef bool
 (* ElementIdOp)(JSContext *cx, JS::HandleObject obj, JS::HandleObject receiver, uint32_t index,
                 JS::MutableHandleValue vp);
 typedef bool
+(* ElementIfPresentOp)(JSContext *cx, JS::HandleObject obj, JS::HandleObject receiver,
+                       uint32_t index, JS::MutableHandleValue vp, bool* present);
+typedef bool
 (* SpecialIdOp)(JSContext *cx, JS::HandleObject obj, JS::HandleObject receiver,
                 HandleSpecialId sid, JS::MutableHandleValue vp);
 typedef bool
 (* StrictGenericIdOp)(JSContext *cx, JS::HandleObject obj, JS::HandleId id,
                       JS::MutableHandleValue vp, bool strict);
 typedef bool
 (* StrictPropertyIdOp)(JSContext *cx, JS::HandleObject obj, JS::Handle<PropertyName*> name,
                        JS::MutableHandleValue vp, bool strict);
@@ -375,20 +378,16 @@ typedef bool
 (* DeleteSpecialOp)(JSContext *cx, JS::HandleObject obj, HandleSpecialId sid, bool *succeeded);
 
 typedef bool
 (* WatchOp)(JSContext *cx, JS::HandleObject obj, JS::HandleId id, JS::HandleObject callable);
 
 typedef bool
 (* UnwatchOp)(JSContext *cx, JS::HandleObject obj, JS::HandleId id);
 
-typedef bool
-(* SliceOp)(JSContext *cx, JS::HandleObject obj, uint32_t begin, uint32_t end,
-            JS::HandleObject result); // result is actually preallocted.
-
 typedef JSObject *
 (* ObjectOp)(JSContext *cx, JS::HandleObject obj);
 typedef void
 (* FinalizeOp)(FreeOp *fop, JSObject *obj);
 
 #define JS_CLASS_MEMBERS                                                      \
     const char          *name;                                                \
     uint32_t            flags;                                                \
@@ -455,38 +454,38 @@ struct ObjectOps
     LookupSpecialOp     lookupSpecial;
     DefineGenericOp     defineGeneric;
     DefinePropOp        defineProperty;
     DefineElementOp     defineElement;
     DefineSpecialOp     defineSpecial;
     GenericIdOp         getGeneric;
     PropertyIdOp        getProperty;
     ElementIdOp         getElement;
+    ElementIfPresentOp  getElementIfPresent; /* can be null */
     SpecialIdOp         getSpecial;
     StrictGenericIdOp   setGeneric;
     StrictPropertyIdOp  setProperty;
     StrictElementIdOp   setElement;
     StrictSpecialIdOp   setSpecial;
     GenericAttributesOp getGenericAttributes;
     GenericAttributesOp setGenericAttributes;
     DeletePropertyOp    deleteProperty;
     DeleteElementOp     deleteElement;
     DeleteSpecialOp     deleteSpecial;
     WatchOp             watch;
     UnwatchOp           unwatch;
-    SliceOp             slice; // Optimized slice, can be null.
 
     JSNewEnumerateOp    enumerate;
     ObjectOp            thisObject;
 };
 
 #define JS_NULL_OBJECT_OPS                                                    \
     {nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr, \
      nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr, \
-     nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr}
+     nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr}
 
 } // namespace js
 
 // Classes, objects, and properties.
 
 typedef void (*JSClassInternal)();
 
 struct JSClass {
--- a/js/src/builtin/TypedObject.cpp
+++ b/js/src/builtin/TypedObject.cpp
@@ -2050,47 +2050,58 @@ TypedDatum::obj_getProperty(JSContext *c
     RootedId id(cx, NameToId(name));
     return obj_getGeneric(cx, obj, receiver, id, vp);
 }
 
 bool
 TypedDatum::obj_getElement(JSContext *cx, HandleObject obj, HandleObject receiver,
                              uint32_t index, MutableHandleValue vp)
 {
+    bool present;
+    return obj_getElementIfPresent(cx, obj, receiver, index, vp, &present);
+}
+
+bool
+TypedDatum::obj_getElementIfPresent(JSContext *cx, HandleObject obj,
+                                    HandleObject receiver, uint32_t index,
+                                    MutableHandleValue vp, bool *present)
+{
     RootedObject type(cx, GetType(*obj));
     TypeRepresentation *typeRepr = typeRepresentation(*type);
 
     switch (typeRepr->kind()) {
       case TypeRepresentation::Scalar:
       case TypeRepresentation::Reference:
       case TypeRepresentation::X4:
       case TypeRepresentation::Struct:
         break;
 
       case TypeRepresentation::Array: {
+        *present = true;
         ArrayTypeRepresentation *arrayTypeRepr = typeRepr->asArray();
 
         if (index >= arrayTypeRepr->length()) {
             vp.setUndefined();
             return true;
         }
 
         RootedObject elementType(cx, ArrayElementType(type));
         size_t offset = arrayTypeRepr->element()->size() * index;
         return Reify(cx, arrayTypeRepr->element(), elementType, obj, offset, vp);
       }
     }
 
     RootedObject proto(cx, obj->getProto());
     if (!proto) {
+        *present = false;
         vp.setUndefined();
         return true;
     }
 
-    return JSObject::getElement(cx, proto, receiver, index, vp);
+    return JSObject::getElementIfPresent(cx, proto, receiver, index, vp, present);
 }
 
 bool
 TypedDatum::obj_getSpecial(JSContext *cx, HandleObject obj,
                             HandleObject receiver, HandleSpecialId sid,
                             MutableHandleValue vp)
 {
     RootedId id(cx, SPECIALID_TO_JSID(sid));
@@ -2445,28 +2456,28 @@ const Class TypedObject::class_ = {
         TypedDatum::obj_lookupSpecial,
         TypedDatum::obj_defineGeneric,
         TypedDatum::obj_defineProperty,
         TypedDatum::obj_defineElement,
         TypedDatum::obj_defineSpecial,
         TypedDatum::obj_getGeneric,
         TypedDatum::obj_getProperty,
         TypedDatum::obj_getElement,
+        TypedDatum::obj_getElementIfPresent,
         TypedDatum::obj_getSpecial,
         TypedDatum::obj_setGeneric,
         TypedDatum::obj_setProperty,
         TypedDatum::obj_setElement,
         TypedDatum::obj_setSpecial,
         TypedDatum::obj_getGenericAttributes,
         TypedDatum::obj_setGenericAttributes,
         TypedDatum::obj_deleteProperty,
         TypedDatum::obj_deleteElement,
         TypedDatum::obj_deleteSpecial,
         nullptr, nullptr, // watch/unwatch
-        nullptr, // slice
         TypedDatum::obj_enumerate,
         nullptr, /* thisObject */
     }
 };
 
 /*static*/ JSObject *
 TypedObject::createZeroed(JSContext *cx, HandleObject type)
 {
@@ -2537,28 +2548,28 @@ const Class TypedHandle::class_ = {
         TypedDatum::obj_lookupSpecial,
         TypedDatum::obj_defineGeneric,
         TypedDatum::obj_defineProperty,
         TypedDatum::obj_defineElement,
         TypedDatum::obj_defineSpecial,
         TypedDatum::obj_getGeneric,
         TypedDatum::obj_getProperty,
         TypedDatum::obj_getElement,
+        TypedDatum::obj_getElementIfPresent,
         TypedDatum::obj_getSpecial,
         TypedDatum::obj_setGeneric,
         TypedDatum::obj_setProperty,
         TypedDatum::obj_setElement,
         TypedDatum::obj_setSpecial,
         TypedDatum::obj_getGenericAttributes,
         TypedDatum::obj_setGenericAttributes,
         TypedDatum::obj_deleteProperty,
         TypedDatum::obj_deleteElement,
         TypedDatum::obj_deleteSpecial,
         nullptr, nullptr, // watch/unwatch
-        nullptr, // slice
         TypedDatum::obj_enumerate,
         nullptr, /* thisObject */
     }
 };
 
 const JSFunctionSpec TypedHandle::handleStaticMethods[] = {
     {"move", {nullptr, nullptr}, 3, 0, "HandleMove"},
     {"get", {nullptr, nullptr}, 1, 0, "HandleGet"},
--- a/js/src/builtin/TypedObject.h
+++ b/js/src/builtin/TypedObject.h
@@ -263,16 +263,19 @@ class TypedDatum : public JSObject
                                 HandlePropertyName name, MutableHandleValue vp);
 
     static bool obj_getElement(JSContext *cx, HandleObject obj, HandleObject receiver,
                                uint32_t index, MutableHandleValue vp);
 
     static bool obj_getSpecial(JSContext *cx, HandleObject obj, HandleObject receiver,
                                HandleSpecialId sid, MutableHandleValue vp);
 
+    static bool obj_getElementIfPresent(JSContext *cx, HandleObject obj,
+                                        HandleObject receiver, uint32_t index,
+                                        MutableHandleValue vp, bool *present);
     static bool obj_setGeneric(JSContext *cx, HandleObject obj, HandleId id,
                                MutableHandleValue vp, bool strict);
     static bool obj_setProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
                                 MutableHandleValue vp, bool strict);
     static bool obj_setElement(JSContext *cx, HandleObject obj, uint32_t index,
                                MutableHandleValue vp, bool strict);
     static bool obj_setSpecial(JSContext *cx, HandleObject obj,
                                HandleSpecialId sid, MutableHandleValue vp, bool strict);
deleted file mode 100644
--- a/js/src/jit-test/tests/arrays/slice.js
+++ /dev/null
@@ -1,37 +0,0 @@
-let invoked = false;
-Object.defineProperty(Array.prototype, '0', {set: function () {
-    invoked = true;
-}});
-
-let result = [1, 2, 3].slice(1);
-assertEq(invoked, false);
-
-let proxy = new Proxy({}, {
-    get: function (target, name, proxy) {
-        switch (name) {
-          case "length":
-            return 2;
-          case "0":
-            return 15;
-          case "1":
-            // Should not invoke [[Get]] for this hole.
-          default:
-            assertEq(false, true);
-        }
-    },
-    has: function (target, name) {
-        switch (name) {
-          case "0":
-            return true;
-          case "1":
-            return false;
-          default:
-            assertEq(false, true);
-        }
-    }
-})
-result = Array.prototype.slice.call(proxy, 0);
-assertEq(result.length, 2);
-assertEq(0 in result, true);
-assertEq(1 in result, false);
-assertEq(result[0], 15);
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -3389,16 +3389,35 @@ JS_ForwardGetElementTo(JSContext *cx, JS
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj);
     JSAutoResolveFlags rf(cx, 0);
 
     return JSObject::getElement(cx, obj, onBehalfOf, index, vp);
 }
 
 JS_PUBLIC_API(bool)
+JS_GetElementIfPresent(JSContext *cx, JSObject *objArg, uint32_t index, JSObject *onBehalfOfArg,
+                       MutableHandleValue vp, bool* present)
+{
+    RootedObject obj(cx, objArg);
+    RootedObject onBehalfOf(cx, onBehalfOfArg);
+    AssertHeapIsIdle(cx);
+    CHECK_REQUEST(cx);
+    assertSameCompartment(cx, obj);
+    JSAutoResolveFlags rf(cx, 0);
+
+    bool isPresent;
+    if (!JSObject::getElementIfPresent(cx, obj, onBehalfOf, index, vp, &isPresent))
+        return false;
+
+    *present = isPresent;
+    return true;
+}
+
+JS_PUBLIC_API(bool)
 JS_GetProperty(JSContext *cx, JSObject *objArg, const char *name, MutableHandleValue vp)
 {
     RootedObject obj(cx, objArg);
     JSAtom *atom = Atomize(cx, name, strlen(name));
     return atom && JS_GetPropertyById(cx, obj, AtomToId(atom), vp);
 }
 
 JS_PUBLIC_API(bool)
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -3035,16 +3035,25 @@ JS_LookupElement(JSContext *cx, JSObject
 
 extern JS_PUBLIC_API(bool)
 JS_GetElement(JSContext *cx, JSObject *obj, uint32_t index, JS::MutableHandle<JS::Value> vp);
 
 extern JS_PUBLIC_API(bool)
 JS_ForwardGetElementTo(JSContext *cx, JSObject *obj, uint32_t index, JSObject *onBehalfOf,
                        JS::MutableHandle<JS::Value> vp);
 
+/*
+ * Get the property with name given by |index|, if it has one.  If
+ * not, |*present| will be set to false and the value of |vp| must not
+ * be relied on.
+ */
+extern JS_PUBLIC_API(bool)
+JS_GetElementIfPresent(JSContext *cx, JSObject *obj, uint32_t index, JSObject *onBehalfOf,
+                       JS::MutableHandle<JS::Value> vp, bool* present);
+
 extern JS_PUBLIC_API(bool)
 JS_SetElement(JSContext *cx, JSObject *obj, uint32_t index, JS::MutableHandle<JS::Value> vp);
 
 extern JS_PUBLIC_API(bool)
 JS_DeleteElement(JSContext *cx, JSObject *obj, uint32_t index);
 
 extern JS_PUBLIC_API(bool)
 JS_DeleteElement2(JSContext *cx, JSObject *obj, uint32_t index, bool *succeeded);
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -129,105 +129,103 @@ js::StringIsArrayIndex(JSLinearString *s
         *indexp = index;
         return true;
     }
 
     return false;
 }
 
 static bool
-ToId(JSContext *cx, double index, MutableHandleId id)
+DoubleIndexToId(JSContext *cx, double index, MutableHandleId id)
 {
     if (index == uint32_t(index))
         return IndexToId(cx, uint32_t(index), id.address());
 
     Value tmp = DoubleValue(index);
     return ValueToId<CanGC>(cx, HandleValue::fromMarkedLocation(&tmp), id);
 }
 
-static bool
-ToId(JSContext *cx, uint32_t index, MutableHandleId id)
-{
-    return IndexToId(cx, index, id.address());
-}
-
 /*
  * If the property at the given index exists, get its value into location
  * pointed by vp and set *hole to false. Otherwise set *hole to true and *vp
  * to JSVAL_VOID. This function assumes that the location pointed by vp is
  * properly rooted and can be used as GC-protected storage for temporaries.
  */
-template<typename IndexType>
 static inline bool
-DoGetElement(JSContext *cx, HandleObject obj, HandleObject receiver,
-             IndexType index, bool *hole, MutableHandleValue vp)
+DoGetElement(JSContext *cx, HandleObject obj, double index, bool *hole, MutableHandleValue vp)
 {
     RootedId id(cx);
 
-    if (!ToId(cx, index, &id))
+    if (!DoubleIndexToId(cx, index, &id))
         return false;
 
     RootedObject obj2(cx);
     RootedShape prop(cx);
     if (!JSObject::lookupGeneric(cx, obj, id, &obj2, &prop))
         return false;
 
     if (!prop) {
         vp.setUndefined();
         *hole = true;
     } else {
-        if (!JSObject::getGeneric(cx, obj, receiver, id, vp))
+        if (!JSObject::getGeneric(cx, obj, obj, id, vp))
             return false;
         *hole = false;
     }
     return true;
 }
 
+static inline bool
+DoGetElement(JSContext *cx, HandleObject obj, uint32_t index, bool *hole, MutableHandleValue vp)
+{
+    bool present;
+    if (!JSObject::getElementIfPresent(cx, obj, obj, index, vp, &present))
+        return false;
+
+    *hole = !present;
+    if (*hole)
+        vp.setUndefined();
+
+    return true;
+}
+
 template<typename IndexType>
 static void
 AssertGreaterThanZero(IndexType index)
 {
     JS_ASSERT(index >= 0);
     JS_ASSERT(index == floor(index));
 }
 
 template<>
 void
 AssertGreaterThanZero(uint32_t index)
 {
 }
 
 template<typename IndexType>
 static bool
-GetElement(JSContext *cx, HandleObject obj, HandleObject receiver,
-           IndexType index, bool *hole, MutableHandleValue vp)
+GetElement(JSContext *cx, HandleObject obj, IndexType index, bool *hole, MutableHandleValue vp)
 {
     AssertGreaterThanZero(index);
     if (obj->isNative() && index < obj->getDenseInitializedLength()) {
         vp.set(obj->getDenseElement(uint32_t(index)));
         if (!vp.isMagic(JS_ELEMENTS_HOLE)) {
             *hole = false;
             return true;
         }
     }
     if (obj->is<ArgumentsObject>()) {
         if (obj->as<ArgumentsObject>().maybeGetElement(uint32_t(index), vp)) {
             *hole = false;
             return true;
         }
     }
 
-    return DoGetElement(cx, obj, receiver, index, hole, vp);
-}
-
-template<typename IndexType>
-static inline bool
-GetElement(JSContext *cx, HandleObject obj, IndexType index, bool *hole, MutableHandleValue vp)
-{
-    return GetElement(cx, obj, obj, index, hole, vp);
+    return DoGetElement(cx, obj, index, hole, vp);
 }
 
 static bool
 GetElementsSlow(JSContext *cx, HandleObject aobj, uint32_t length, Value *vp)
 {
     for (uint32_t i = 0; i < length; i++) {
         if (!JSObject::getElement(cx, aobj, aobj, i, MutableHandleValue::fromMarkedLocation(&vp[i])))
             return false;
@@ -293,17 +291,17 @@ SetArrayElement(JSContext *cx, HandleObj
         } while (false);
 
         if (result == JSObject::ED_FAILED)
             return false;
         JS_ASSERT(result == JSObject::ED_SPARSE);
     }
 
     RootedId id(cx);
-    if (!ToId(cx, index, &id))
+    if (!DoubleIndexToId(cx, index, &id))
         return false;
 
     RootedValue tmp(cx, v);
     return JSObject::setGeneric(cx, obj, obj, id, &tmp, true);
 }
 
 /*
  * Attempt to delete the element |index| from |obj| as if by
@@ -2677,28 +2675,30 @@ js::array_concat(JSContext *cx, unsigned
     }
 
     return SetLengthProperty(cx, narr, length);
 }
 
 static bool
 array_slice(JSContext *cx, unsigned argc, Value *vp)
 {
+    uint32_t length, begin, end, slot;
+    bool hole;
+
     CallArgs args = CallArgsFromVp(argc, vp);
 
     RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return false;
 
-    uint32_t length;
     if (!GetLengthProperty(cx, obj, &length))
         return false;
-
-    uint32_t begin = 0;
-    uint32_t end = length;
+    begin = 0;
+    end = length;
+
     if (args.length() > 0) {
         double d;
         if (!ToInteger(cx, args[0], &d))
             return false;
         if (d < 0) {
             d += length;
             if (d < 0)
                 d = 0;
@@ -2736,60 +2736,30 @@ array_slice(JSContext *cx, unsigned argc
             uint32_t initLength = Min(numSourceElements, end - begin);
             narr->setDenseInitializedLength(initLength);
             narr->initDenseElements(0, &obj->getDenseElement(begin), initLength);
         }
         args.rval().setObject(*narr);
         return true;
     }
 
-    if (js::SliceOp op = obj->getOps()->slice) {
-        // Ensure that we have dense elements, so that DOM can use js::UnsafeDefineElement.
-        JSObject::EnsureDenseResult result = narr->ensureDenseElements(cx, 0, end - begin);
-        if (result == JSObject::ED_FAILED)
-             return false;
-
-        if (result == JSObject::ED_OK) {
-            if (!op(cx, obj, begin, end, narr))
-                return false;
-
-            args.rval().setObject(*narr);
-            return true;
+    RootedValue value(cx);
+    for (slot = begin; slot < end; slot++) {
+        if (!JS_CHECK_OPERATION_LIMIT(cx) ||
+            !GetElement(cx, obj, slot, &hole, &value)) {
+            return false;
         }
-
-        // Fallthrough
-        JS_ASSERT(result == JSObject::ED_SPARSE);
+        if (!hole && !SetArrayElement(cx, narr, slot - begin, value))
+            return false;
     }
 
-
-    if (!SliceSlowly(cx, obj, obj, begin, end, narr))
-        return false;
-
     args.rval().setObject(*narr);
     return true;
 }
 
-JS_FRIEND_API(bool)
-js::SliceSlowly(JSContext* cx, HandleObject obj, HandleObject receiver,
-                uint32_t begin, uint32_t end, HandleObject result)
-{
-    RootedValue value(cx);
-    for (uint32_t slot = begin; slot < end; slot++) {
-        bool hole;
-        if (!JS_CHECK_OPERATION_LIMIT(cx) ||
-            !GetElement(cx, obj, receiver, slot, &hole, &value))
-        {
-            return false;
-        }
-        if (!hole && !JSObject::defineElement(cx, result, slot - begin, value))
-            return false;
-    }
-    return true;
-}
-
 /* ES5 15.4.4.20. */
 static bool
 array_filter(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     /* Step 1. */
     RootedObject obj(cx, ToObject(cx, args.thisv()));
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -1160,24 +1160,16 @@ js::SetObjectMetadata(JSContext *cx, Han
 }
 
 JS_FRIEND_API(JSObject *)
 js::GetObjectMetadata(JSObject *obj)
 {
     return obj->getMetadata();
 }
 
-JS_FRIEND_API(void)
-js::UnsafeDefineElement(JSContext *cx, JS::HandleObject obj, uint32_t index, JS::HandleValue value)
-{
-    JS_ASSERT(obj->isNative());
-    JS_ASSERT(index < obj->getDenseInitializedLength());
-    obj->setDenseElementWithType(cx, index, value);
-}
-
 JS_FRIEND_API(bool)
 js_DefineOwnProperty(JSContext *cx, JSObject *objArg, jsid idArg,
                      JS::Handle<js::PropertyDescriptor> descriptor, bool *bp)
 {
     RootedObject obj(cx, objArg);
     RootedId id(cx, idArg);
     JS_ASSERT(cx->runtime()->heapState == js::Idle);
     CHECK_REQUEST(cx);
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -1734,23 +1734,16 @@ SetObjectMetadataCallback(JSContext *cx,
 /* Manipulate the metadata associated with an object. */
 
 JS_FRIEND_API(bool)
 SetObjectMetadata(JSContext *cx, JS::HandleObject obj, JS::HandleObject metadata);
 
 JS_FRIEND_API(JSObject *)
 GetObjectMetadata(JSObject *obj);
 
-JS_FRIEND_API(void)
-UnsafeDefineElement(JSContext *cx, JS::HandleObject obj, uint32_t index, JS::HandleValue value);
-
-JS_FRIEND_API(bool)
-SliceSlowly(JSContext* cx, JS::HandleObject obj, JS::HandleObject receiver,
-            uint32_t begin, uint32_t end, JS::HandleObject result);
-
 /* ES5 8.12.8. */
 extern JS_FRIEND_API(bool)
 DefaultValue(JSContext *cx, JS::HandleObject obj, JSType hint, JS::MutableHandleValue vp);
 
 /*
  * Helper function. To approximate a call to the [[DefineOwnProperty]] internal
  * method described in ES5, first call this, then call JS_DefinePropertyById.
  *
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -1025,16 +1025,22 @@ class JSObject : public js::ObjectImpl
         return getGenericNoGC(cx, obj, receiver, js::NameToId(name), vp);
     }
 
     static inline bool getElement(JSContext *cx, js::HandleObject obj, js::HandleObject receiver,
                                   uint32_t index, js::MutableHandleValue vp);
     static inline bool getElementNoGC(JSContext *cx, JSObject *obj, JSObject *receiver,
                                       uint32_t index, js::Value *vp);
 
+    /* If element is not present (e.g. array hole) *present is set to
+       false and the contents of *vp are unusable garbage. */
+    static inline bool getElementIfPresent(JSContext *cx, js::HandleObject obj,
+                                           js::HandleObject receiver, uint32_t index,
+                                           js::MutableHandleValue vp, bool *present);
+
     static bool getSpecial(JSContext *cx, js::HandleObject obj,
                            js::HandleObject receiver, js::SpecialId sid,
                            js::MutableHandleValue vp)
     {
         JS::RootedId id(cx, SPECIALID_TO_JSID(sid));
         return getGeneric(cx, obj, receiver, id, vp);
     }
 
--- a/js/src/jsobjinlines.h
+++ b/js/src/jsobjinlines.h
@@ -578,16 +578,48 @@ JSObject::getElementNoGC(JSContext *cx, 
         return false;
 
     jsid id;
     if (!js::IndexToId(cx, index, &id))
         return false;
     return getGenericNoGC(cx, obj, receiver, id, vp);
 }
 
+/* static */ inline bool
+JSObject::getElementIfPresent(JSContext *cx, js::HandleObject obj, js::HandleObject receiver,
+                              uint32_t index, js::MutableHandleValue vp,
+                              bool *present)
+{
+    js::ElementIfPresentOp op = obj->getOps()->getElementIfPresent;
+    if (op)
+        return op(cx, obj, receiver, index, vp, present);
+
+    /*
+     * For now, do the index-to-id conversion just once, then use
+     * lookupGeneric/getGeneric.  Once lookupElement and getElement stop both
+     * doing index-to-id conversions, we can use those here.
+     */
+    JS::RootedId id(cx);
+    if (!js::IndexToId(cx, index, id.address()))
+        return false;
+
+    JS::RootedObject obj2(cx);
+    js::RootedShape prop(cx);
+    if (!lookupGeneric(cx, obj, id, &obj2, &prop))
+        return false;
+
+    if (!prop) {
+        *present = false;
+        return true;
+    }
+
+    *present = true;
+    return getGeneric(cx, obj, receiver, id, vp);
+}
+
 inline js::GlobalObject &
 JSObject::global() const
 {
 #ifdef DEBUG
     JSObject *obj = const_cast<JSObject *>(this);
     while (JSObject *parent = obj->getParent())
         obj = parent;
 #endif
--- a/js/src/jsproxy.cpp
+++ b/js/src/jsproxy.cpp
@@ -147,16 +147,37 @@ BaseProxyHandler::get(JSContext *cx, Han
     if (desc.hasShortId()) {
         RootedId id(cx, INT_TO_JSID(desc.shortid()));
         return CallJSPropertyOp(cx, desc.getter(), receiver, id, vp);
     }
     return CallJSPropertyOp(cx, desc.getter(), receiver, id, vp);
 }
 
 bool
+BaseProxyHandler::getElementIfPresent(JSContext *cx, HandleObject proxy, HandleObject receiver,
+                                      uint32_t index, MutableHandleValue vp, bool *present)
+{
+    RootedId id(cx);
+    if (!IndexToId(cx, index, id.address()))
+        return false;
+
+    assertEnteredPolicy(cx, proxy, id);
+
+    if (!has(cx, proxy, id, present))
+        return false;
+
+    if (!*present) {
+        Debug_SetValueRangeToCrashOnTouch(vp.address(), 1);
+        return true;
+    }
+
+    return get(cx, proxy, receiver, id, vp);
+}
+
+bool
 BaseProxyHandler::set(JSContext *cx, HandleObject proxy, HandleObject receiver,
                       HandleId id, bool strict, MutableHandleValue vp)
 {
     assertEnteredPolicy(cx, proxy, id);
 
     Rooted<PropertyDescriptor> desc(cx);
     if (!getOwnPropertyDescriptor(cx, proxy, id, &desc, JSRESOLVE_ASSIGNING))
         return false;
@@ -360,44 +381,16 @@ BaseProxyHandler::watch(JSContext *cx, H
 
 bool
 BaseProxyHandler::unwatch(JSContext *cx, HandleObject proxy, HandleId id)
 {
     return true;
 }
 
 bool
-BaseProxyHandler::slice(JSContext *cx, HandleObject proxy, uint32_t begin, uint32_t end,
-                        HandleObject result)
-{
-    assertEnteredPolicy(cx, proxy, JSID_VOID);
-
-    RootedId id(cx);
-    RootedValue value(cx);
-    for (uint32_t index = begin; index < end; index++) {
-        if (!IndexToId(cx, index, id.address()))
-            return false;
-
-        bool present;
-        if (!Proxy::has(cx, proxy, id, &present))
-            return false;
-
-        if (present) {
-            if (!Proxy::get(cx, proxy, proxy, id, &value))
-                return false;
-
-            if (!JSObject::defineElement(cx, result, index - begin, value))
-                return false;
-        }
-    }
-
-    return true;
-}
-
-bool
 DirectProxyHandler::getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
                                           MutableHandle<PropertyDescriptor> desc, unsigned flags)
 {
     assertEnteredPolicy(cx, proxy, id);
     JS_ASSERT(!hasPrototype()); // Should never be called if there's a prototype.
     RootedObject target(cx, proxy->as<ProxyObject>().target());
     return JS_GetPropertyDescriptorById(cx, target, id, 0, desc);
 }
@@ -2521,16 +2514,51 @@ Proxy::callProp(JSContext *cx, HandleObj
         if (!OnUnknownMethod(cx, proxy, IdToValue(id), vp))
             return false;
     }
 #endif
 
     return true;
 }
 
+
+bool
+Proxy::getElementIfPresent(JSContext *cx, HandleObject proxy, HandleObject receiver, uint32_t index,
+                           MutableHandleValue vp, bool *present)
+{
+    JS_CHECK_RECURSION(cx, return false);
+
+    RootedId id(cx);
+    if (!IndexToId(cx, index, id.address()))
+        return false;
+
+    BaseProxyHandler *handler = proxy->as<ProxyObject>().handler();
+    AutoEnterPolicy policy(cx, handler, proxy, id, BaseProxyHandler::GET, true);
+    if (!policy.allowed())
+        return policy.returnValue();
+
+    if (!handler->hasPrototype()) {
+        return handler->getElementIfPresent(cx, proxy, receiver, index,
+                                            vp, present);
+    }
+
+    bool hasOwn;
+    if (!handler->hasOwn(cx, proxy, id, &hasOwn))
+        return false;
+
+    if (hasOwn) {
+        *present = true;
+        return proxy->as<ProxyObject>().handler()->get(cx, proxy, receiver, id, vp);
+    }
+
+    *present = false;
+    INVOKE_ON_PROTOTYPE(cx, handler, proxy,
+                        JSObject::getElementIfPresent(cx, proto, receiver, index, vp, present));
+}
+
 bool
 Proxy::set(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id, bool strict,
            MutableHandleValue vp)
 {
     JS_CHECK_RECURSION(cx, return false);
     BaseProxyHandler *handler = proxy->as<ProxyObject>().handler();
     AutoEnterPolicy policy(cx, handler, proxy, id, BaseProxyHandler::SET, true);
     if (!policy.allowed())
@@ -2743,28 +2771,16 @@ Proxy::watch(JSContext *cx, JS::HandleOb
 
 /* static */ bool
 Proxy::unwatch(JSContext *cx, JS::HandleObject proxy, JS::HandleId id)
 {
     JS_CHECK_RECURSION(cx, return false);
     return proxy->as<ProxyObject>().handler()->unwatch(cx, proxy, id);
 }
 
-/* static */ bool
-Proxy::slice(JSContext *cx, HandleObject proxy, uint32_t begin, uint32_t end,
-             HandleObject result)
-{
-    JS_CHECK_RECURSION(cx, return false);
-    BaseProxyHandler *handler = proxy->as<ProxyObject>().handler();
-    AutoEnterPolicy policy(cx, handler, proxy, JSID_VOIDHANDLE, BaseProxyHandler::GET, true);
-    if (!policy.allowed())
-        return policy.returnValue();
-    return handler->slice(cx, proxy, begin, end, result);
-}
-
 static JSObject *
 proxy_innerObject(JSContext *cx, HandleObject obj)
 {
     return obj->as<ProxyObject>().private_().toObjectOrNull();
 }
 
 static bool
 proxy_LookupGeneric(JSContext *cx, HandleObject obj, HandleId id,
@@ -2871,16 +2887,23 @@ proxy_GetElement(JSContext *cx, HandleOb
 {
     RootedId id(cx);
     if (!IndexToId(cx, index, id.address()))
         return false;
     return proxy_GetGeneric(cx, obj, receiver, id, vp);
 }
 
 static bool
+proxy_GetElementIfPresent(JSContext *cx, HandleObject obj, HandleObject receiver, uint32_t index,
+                          MutableHandleValue vp, bool *present)
+{
+    return Proxy::getElementIfPresent(cx, obj, receiver, index, vp, present);
+}
+
+static bool
 proxy_GetSpecial(JSContext *cx, HandleObject obj, HandleObject receiver, HandleSpecialId sid,
                  MutableHandleValue vp)
 {
     Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
     return proxy_GetGeneric(cx, obj, receiver, id, vp);
 }
 
 static bool
@@ -3048,34 +3071,27 @@ proxy_Construct(JSContext *cx, unsigned 
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     RootedObject proxy(cx, &args.callee());
     JS_ASSERT(proxy->is<ProxyObject>());
     return Proxy::construct(cx, proxy, args);
 }
 
 static bool
-proxy_Watch(JSContext *cx, HandleObject obj, HandleId id, HandleObject callable)
+proxy_Watch(JSContext *cx, JS::HandleObject obj, JS::HandleId id, JS::HandleObject callable)
 {
     return Proxy::watch(cx, obj, id, callable);
 }
 
 static bool
-proxy_Unwatch(JSContext *cx, HandleObject obj, HandleId id)
+proxy_Unwatch(JSContext *cx, JS::HandleObject obj, JS::HandleId id)
 {
     return Proxy::unwatch(cx, obj, id);
 }
 
-static bool
-proxy_Slice(JSContext *cx, HandleObject proxy, uint32_t begin, uint32_t end,
-            HandleObject result)
-{
-    return Proxy::slice(cx, proxy, begin, end, result);
-}
-
 #define PROXY_CLASS_EXT                             \
     {                                               \
         nullptr,             /* outerObject */      \
         nullptr,             /* innerObject */      \
         nullptr,             /* iteratorObject */   \
         false,               /* isWrappedNative */  \
         proxy_WeakmapKeyDelegate                    \
     }
@@ -3107,28 +3123,28 @@ proxy_Slice(JSContext *cx, HandleObject 
         proxy_LookupSpecial,                        \
         proxy_DefineGeneric,                        \
         proxy_DefineProperty,                       \
         proxy_DefineElement,                        \
         proxy_DefineSpecial,                        \
         proxy_GetGeneric,                           \
         proxy_GetProperty,                          \
         proxy_GetElement,                           \
+        proxy_GetElementIfPresent,                  \
         proxy_GetSpecial,                           \
         proxy_SetGeneric,                           \
         proxy_SetProperty,                          \
         proxy_SetElement,                           \
         proxy_SetSpecial,                           \
         proxy_GetGenericAttributes,                 \
         proxy_SetGenericAttributes,                 \
         proxy_DeleteProperty,                       \
         proxy_DeleteElement,                        \
         proxy_DeleteSpecial,                        \
         proxy_Watch, proxy_Unwatch,                 \
-        proxy_Slice,                                \
         nullptr,             /* enumerate       */  \
         nullptr,             /* thisObject      */  \
     }                                               \
 }
 
 const Class js::ProxyObject::uncallableClass_ = PROXY_CLASS(nullptr, nullptr);
 const Class js::ProxyObject::callableClass_ = PROXY_CLASS(proxy_Call, proxy_Construct);
 
@@ -3165,28 +3181,28 @@ const Class js::OuterWindowProxyObject::
         proxy_LookupSpecial,
         proxy_DefineGeneric,
         proxy_DefineProperty,
         proxy_DefineElement,
         proxy_DefineSpecial,
         proxy_GetGeneric,
         proxy_GetProperty,
         proxy_GetElement,
+        proxy_GetElementIfPresent,
         proxy_GetSpecial,
         proxy_SetGeneric,
         proxy_SetProperty,
         proxy_SetElement,
         proxy_SetSpecial,
         proxy_GetGenericAttributes,
         proxy_SetGenericAttributes,
         proxy_DeleteProperty,
         proxy_DeleteElement,
         proxy_DeleteSpecial,
         proxy_Watch, proxy_Unwatch,
-        proxy_Slice,
         nullptr,             /* enumerate       */
         nullptr,             /* thisObject      */
     }
 };
 
 const Class* const js::OuterWindowProxyClassPtr = &OuterWindowProxyObject::class_;
 
 JS_FRIEND_API(JSObject *)
--- a/js/src/jsproxy.h
+++ b/js/src/jsproxy.h
@@ -161,27 +161,26 @@ class JS_FRIEND_API(BaseProxyHandler)
     virtual bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl, CallArgs args);
     virtual bool hasInstance(JSContext *cx, HandleObject proxy, MutableHandleValue v, bool *bp);
     virtual bool objectClassIs(HandleObject obj, ESClassValue classValue, JSContext *cx);
     virtual const char *className(JSContext *cx, HandleObject proxy);
     virtual JSString *fun_toString(JSContext *cx, HandleObject proxy, unsigned indent);
     virtual bool regexp_toShared(JSContext *cx, HandleObject proxy, RegExpGuard *g);
     virtual bool defaultValue(JSContext *cx, HandleObject obj, JSType hint, MutableHandleValue vp);
     virtual void finalize(JSFreeOp *fop, JSObject *proxy);
+    virtual bool getElementIfPresent(JSContext *cx, HandleObject obj, HandleObject receiver,
+                                     uint32_t index, MutableHandleValue vp, bool *present);
     virtual bool getPrototypeOf(JSContext *cx, HandleObject proxy, MutableHandleObject protop);
 
     // These two hooks must be overridden, or not overridden, in tandem -- no
     // overriding just one!
     virtual bool watch(JSContext *cx, JS::HandleObject proxy, JS::HandleId id,
                        JS::HandleObject callable);
     virtual bool unwatch(JSContext *cx, JS::HandleObject proxy, JS::HandleId id);
 
-    virtual bool slice(JSContext *cx, HandleObject proxy, uint32_t begin, uint32_t end,
-                       HandleObject result);
-
     /* See comment for weakmapKeyDelegateOp in js/Class.h. */
     virtual JSObject *weakmapKeyDelegate(JSObject *proxy);
     virtual bool isScripted() { return false; }
 };
 
 /*
  * DirectProxyHandler includes a notion of a target object. All traps are
  * reimplemented such that they forward their behavior to the target. This
@@ -272,16 +271,18 @@ class Proxy
     static bool delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp);
     static bool enumerate(JSContext *cx, HandleObject proxy, AutoIdVector &props);
 
     /* ES5 Harmony derived proxy traps. */
     static bool has(JSContext *cx, HandleObject proxy, HandleId id, bool *bp);
     static bool hasOwn(JSContext *cx, HandleObject proxy, HandleId id, bool *bp);
     static bool get(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id,
                     MutableHandleValue vp);
+    static bool getElementIfPresent(JSContext *cx, HandleObject proxy, HandleObject receiver,
+                                    uint32_t index, MutableHandleValue vp, bool *present);
     static bool set(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id,
                     bool strict, MutableHandleValue vp);
     static bool keys(JSContext *cx, HandleObject proxy, AutoIdVector &props);
     static bool iterate(JSContext *cx, HandleObject proxy, unsigned flags, MutableHandleValue vp);
 
     /* Spidermonkey extensions. */
     static bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible);
     static bool call(JSContext *cx, HandleObject proxy, const CallArgs &args);
@@ -290,21 +291,19 @@ class Proxy
     static bool hasInstance(JSContext *cx, HandleObject proxy, MutableHandleValue v, bool *bp);
     static bool objectClassIs(HandleObject obj, ESClassValue classValue, JSContext *cx);
     static const char *className(JSContext *cx, HandleObject proxy);
     static JSString *fun_toString(JSContext *cx, HandleObject proxy, unsigned indent);
     static bool regexp_toShared(JSContext *cx, HandleObject proxy, RegExpGuard *g);
     static bool defaultValue(JSContext *cx, HandleObject obj, JSType hint, MutableHandleValue vp);
     static bool getPrototypeOf(JSContext *cx, HandleObject proxy, MutableHandleObject protop);
 
-    static bool watch(JSContext *cx, HandleObject proxy, HandleId id, HandleObject callable);
-    static bool unwatch(JSContext *cx, HandleObject proxy, HandleId id);
-
-    static bool slice(JSContext *cx, HandleObject obj, uint32_t begin, uint32_t end,
-                      HandleObject result);
+    static bool watch(JSContext *cx, JS::HandleObject proxy, JS::HandleId id,
+                      JS::HandleObject callable);
+    static bool unwatch(JSContext *cx, JS::HandleObject proxy, JS::HandleId id);
 
     /* IC entry path for handling __noSuchMethod__ on access. */
     static bool callProp(JSContext *cx, HandleObject proxy, HandleObject reveiver, HandleId id,
                          MutableHandleValue vp);
 
     static JSObject * const LazyProto;
 };
 
--- a/js/src/jswrapper.cpp
+++ b/js/src/jswrapper.cpp
@@ -835,16 +835,24 @@ DeadObjectProxy::regexp_toShared(JSConte
 bool
 DeadObjectProxy::defaultValue(JSContext *cx, HandleObject obj, JSType hint, MutableHandleValue vp)
 {
     JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT);
     return false;
 }
 
 bool
+DeadObjectProxy::getElementIfPresent(JSContext *cx, HandleObject obj, HandleObject receiver,
+                                     uint32_t index, MutableHandleValue vp, bool *present)
+{
+    JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT);
+    return false;
+}
+
+bool
 DeadObjectProxy::getPrototypeOf(JSContext *cx, HandleObject proxy, MutableHandleObject protop)
 {
     protop.set(nullptr);
     return true;
 }
 
 DeadObjectProxy DeadObjectProxy::singleton;
 const char DeadObjectProxy::sDeadObjectFamily = 0;
--- a/js/src/jswrapper.h
+++ b/js/src/jswrapper.h
@@ -203,16 +203,19 @@ class JS_FRIEND_API(DeadObjectProxy) : p
                              bool *bp) MOZ_OVERRIDE;
     virtual bool objectClassIs(HandleObject obj, ESClassValue classValue,
                                JSContext *cx) MOZ_OVERRIDE;
     virtual const char *className(JSContext *cx, HandleObject proxy) MOZ_OVERRIDE;
     virtual JSString *fun_toString(JSContext *cx, HandleObject proxy, unsigned indent) MOZ_OVERRIDE;
     virtual bool regexp_toShared(JSContext *cx, HandleObject proxy, RegExpGuard *g) MOZ_OVERRIDE;
     virtual bool defaultValue(JSContext *cx, HandleObject obj, JSType hint,
                               MutableHandleValue vp) MOZ_OVERRIDE;
+    virtual bool getElementIfPresent(JSContext *cx, HandleObject obj, HandleObject receiver,
+                                     uint32_t index, MutableHandleValue vp,
+                                     bool *present) MOZ_OVERRIDE;
     virtual bool getPrototypeOf(JSContext *cx, HandleObject proxy,
                                 MutableHandleObject protop) MOZ_OVERRIDE;
 
     static DeadObjectProxy singleton;
 };
 
 extern JSObject *
 TransparentObjectWrapper(JSContext *cx, HandleObject existing, HandleObject obj,
--- a/js/src/vm/ScopeObject.cpp
+++ b/js/src/vm/ScopeObject.cpp
@@ -552,28 +552,28 @@ const Class WithObject::class_ = {
         with_LookupSpecial,
         nullptr,             /* defineGeneric */
         nullptr,             /* defineProperty */
         nullptr,             /* defineElement */
         nullptr,             /* defineSpecial */
         with_GetGeneric,
         with_GetProperty,
         with_GetElement,
+        nullptr,             /* getElementIfPresent */
         with_GetSpecial,
         with_SetGeneric,
         with_SetProperty,
         with_SetElement,
         with_SetSpecial,
         with_GetGenericAttributes,
         with_SetGenericAttributes,
         with_DeleteProperty,
         with_DeleteElement,
         with_DeleteSpecial,
-        nullptr, nullptr,    /* watch/unwatch */
-        nullptr,             /* slice */
+        nullptr, nullptr, /* watch/unwatch */
         with_Enumerate,
         with_ThisObject,
     }
 };
 
 /*****************************************************************************/
 
 ClonedBlockObject *
--- a/js/src/vm/TypedArrayObject.cpp
+++ b/js/src/vm/TypedArrayObject.cpp
@@ -1033,16 +1033,26 @@ ArrayBufferObject::obj_getElement(JSCont
 {
     RootedObject delegate(cx, ArrayBufferDelegate(cx, obj));
     if (!delegate)
         return false;
     return baseops::GetElement(cx, delegate, receiver, index, vp);
 }
 
 bool
+ArrayBufferObject::obj_getElementIfPresent(JSContext *cx, HandleObject obj, HandleObject receiver,
+                                           uint32_t index, MutableHandleValue vp, bool *present)
+{
+    RootedObject delegate(cx, ArrayBufferDelegate(cx, obj));
+    if (!delegate)
+        return false;
+    return JSObject::getElementIfPresent(cx, delegate, receiver, index, vp, present);
+}
+
+bool
 ArrayBufferObject::obj_getSpecial(JSContext *cx, HandleObject obj,
                                   HandleObject receiver, HandleSpecialId sid,
                                   MutableHandleValue vp)
 {
     Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
     return obj_getGeneric(cx, obj, receiver, id, vp);
 }
 
@@ -1480,16 +1490,37 @@ class TypedArrayObjectTemplate : public 
         if (atom->isIndex(&index))
             return obj_getElement(cx, obj, receiver, index, vp);
 
         Rooted<PropertyName*> name(cx, atom->asPropertyName());
         return obj_getProperty(cx, obj, receiver, name, vp);
     }
 
     static bool
+    obj_getElementIfPresent(JSContext *cx, HandleObject tarray, HandleObject receiver, uint32_t index,
+                            MutableHandleValue vp, bool *present)
+    {
+        // Fast-path the common case of index < length
+        if (index < tarray->as<TypedArrayObject>().length()) {
+            // this inline function is specialized for each type
+            copyIndexToValue(tarray, index, vp);
+            *present = true;
+            return true;
+        }
+
+        RootedObject proto(cx, tarray->getProto());
+        if (!proto) {
+            vp.setUndefined();
+            return true;
+        }
+
+        return JSObject::getElementIfPresent(cx, proto, receiver, index, vp, present);
+    }
+
+    static bool
     setElementTail(JSContext *cx, HandleObject tarray, uint32_t index,
                    MutableHandleValue vp, bool strict)
     {
         JS_ASSERT(tarray);
         JS_ASSERT(index < tarray->as<TypedArrayObject>().length());
 
         if (vp.isInt32()) {
             setIndex(tarray, index, NativeType(vp.toInt32()));
@@ -3444,30 +3475,30 @@ const Class ArrayBufferObject::class_ = 
         ArrayBufferObject::obj_lookupSpecial,
         ArrayBufferObject::obj_defineGeneric,
         ArrayBufferObject::obj_defineProperty,
         ArrayBufferObject::obj_defineElement,
         ArrayBufferObject::obj_defineSpecial,
         ArrayBufferObject::obj_getGeneric,
         ArrayBufferObject::obj_getProperty,
         ArrayBufferObject::obj_getElement,
+        ArrayBufferObject::obj_getElementIfPresent,
         ArrayBufferObject::obj_getSpecial,
         ArrayBufferObject::obj_setGeneric,
         ArrayBufferObject::obj_setProperty,
         ArrayBufferObject::obj_setElement,
         ArrayBufferObject::obj_setSpecial,
         ArrayBufferObject::obj_getGenericAttributes,
         ArrayBufferObject::obj_setGenericAttributes,
         ArrayBufferObject::obj_deleteProperty,
         ArrayBufferObject::obj_deleteElement,
         ArrayBufferObject::obj_deleteSpecial,
         nullptr, nullptr, /* watch/unwatch */
-        nullptr,          /* slice */
         ArrayBufferObject::obj_enumerate,
-        nullptr,          /* thisObject      */
+        nullptr,       /* thisObject      */
     }
 };
 
 const JSFunctionSpec ArrayBufferObject::jsfuncs[] = {
     JS_FN("slice", ArrayBufferObject::fun_slice, 2, JSFUN_GENERIC_NATIVE),
     JS_FS_END
 };
 
@@ -3607,30 +3638,30 @@ IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Flo
         _typedArray##Object::obj_lookupSpecial,                                \
         _typedArray##Object::obj_defineGeneric,                                \
         _typedArray##Object::obj_defineProperty,                               \
         _typedArray##Object::obj_defineElement,                                \
         _typedArray##Object::obj_defineSpecial,                                \
         _typedArray##Object::obj_getGeneric,                                   \
         _typedArray##Object::obj_getProperty,                                  \
         _typedArray##Object::obj_getElement,                                   \
+        _typedArray##Object::obj_getElementIfPresent,                          \
         _typedArray##Object::obj_getSpecial,                                   \
         _typedArray##Object::obj_setGeneric,                                   \
         _typedArray##Object::obj_setProperty,                                  \
         _typedArray##Object::obj_setElement,                                   \
         _typedArray##Object::obj_setSpecial,                                   \
         _typedArray##Object::obj_getGenericAttributes,                         \
         _typedArray##Object::obj_setGenericAttributes,                         \
         _typedArray##Object::obj_deleteProperty,                               \
         _typedArray##Object::obj_deleteElement,                                \
         _typedArray##Object::obj_deleteSpecial,                                \
         nullptr, nullptr, /* watch/unwatch */                                  \
-        nullptr,          /* slice */                                          \
         _typedArray##Object::obj_enumerate,                                    \
-        nullptr,          /* thisObject  */                                    \
+        nullptr,             /* thisObject  */                                 \
     }                                                                          \
 }
 
 template<class ArrayType>
 static inline JSObject *
 InitTypedArrayClass(JSContext *cx)
 {
     Rooted<GlobalObject*> global(cx, cx->compartment()->maybeGlobal());
--- a/js/src/vm/TypedArrayObject.h
+++ b/js/src/vm/TypedArrayObject.h
@@ -102,16 +102,18 @@ class ArrayBufferObject : public JSObjec
     static bool obj_getGeneric(JSContext *cx, HandleObject obj, HandleObject receiver,
                                HandleId id, MutableHandleValue vp);
 
     static bool obj_getProperty(JSContext *cx, HandleObject obj, HandleObject receiver,
                                 HandlePropertyName name, MutableHandleValue vp);
 
     static bool obj_getElement(JSContext *cx, HandleObject obj, HandleObject receiver,
                                uint32_t index, MutableHandleValue vp);
+    static bool obj_getElementIfPresent(JSContext *cx, HandleObject obj, HandleObject receiver,
+                                        uint32_t index, MutableHandleValue vp, bool *present);
 
     static bool obj_getSpecial(JSContext *cx, HandleObject obj, HandleObject receiver,
                                HandleSpecialId sid, MutableHandleValue vp);
 
     static bool obj_setGeneric(JSContext *cx, HandleObject obj, HandleId id,
                                MutableHandleValue vp, bool strict);
     static bool obj_setProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
                                 MutableHandleValue vp, bool strict);
--- a/js/xpconnect/src/XPCWrappedNativeJSOps.cpp
+++ b/js/xpconnect/src/XPCWrappedNativeJSOps.cpp
@@ -715,28 +715,28 @@ const XPCWrappedNativeJSClass XPC_WN_NoH
         nullptr, // lookupSpecial
         nullptr, // defineGeneric
         nullptr, // defineProperty
         nullptr, // defineElement
         nullptr, // defineSpecial
         nullptr, // getGeneric
         nullptr, // getProperty
         nullptr, // getElement
+        nullptr, // getElementIfPresent
         nullptr, // getSpecial
         nullptr, // setGeneric
         nullptr, // setProperty
         nullptr, // setElement
         nullptr, // setSpecial
         nullptr, // getGenericAttributes
         nullptr, // setGenericAttributes
         nullptr, // deleteProperty
         nullptr, // deleteElement
         nullptr, // deleteSpecial
         nullptr, nullptr, // watch/unwatch
-        nullptr, // slice
         XPC_WN_JSOp_Enumerate,
         XPC_WN_JSOp_ThisObject,
     }
   },
   0 // interfacesBitmap
 };
 
 
--- a/js/xpconnect/src/xpcprivate.h
+++ b/js/xpconnect/src/xpcprivate.h
@@ -977,28 +977,28 @@ XPC_WN_JSOp_ThisObject(JSContext *cx, JS
         nullptr, /* lookupSpecial */                                          \
         nullptr, /* defineGeneric */                                          \
         nullptr, /* defineProperty */                                         \
         nullptr, /* defineElement */                                          \
         nullptr, /* defineSpecial */                                          \
         nullptr, /* getGeneric    */                                          \
         nullptr, /* getProperty    */                                         \
         nullptr, /* getElement    */                                          \
+        nullptr, /* getElementIfPresent */                                    \
         nullptr, /* getSpecial    */                                          \
         nullptr, /* setGeneric    */                                          \
         nullptr, /* setProperty    */                                         \
         nullptr, /* setElement    */                                          \
         nullptr, /* setSpecial    */                                          \
         nullptr, /* getGenericAttributes  */                                  \
         nullptr, /* setGenericAttributes  */                                  \
         nullptr, /* deleteProperty */                                         \
         nullptr, /* deleteElement */                                          \
         nullptr, /* deleteSpecial */                                          \
         nullptr, nullptr, /* watch/unwatch */                                 \
-        nullptr, /* slice */                                                  \
         XPC_WN_JSOp_Enumerate,                                                \
         XPC_WN_JSOp_ThisObject,                                               \
     }
 
 #define XPC_WN_NoCall_ObjectOps                                               \
     {                                                                         \
         nullptr, /* lookupGeneric */                                          \
         nullptr, /* lookupProperty */                                         \
@@ -1006,28 +1006,28 @@ XPC_WN_JSOp_ThisObject(JSContext *cx, JS
         nullptr, /* lookupSpecial */                                          \
         nullptr, /* defineGeneric */                                          \
         nullptr, /* defineProperty */                                         \
         nullptr, /* defineElement */                                          \
         nullptr, /* defineSpecial */                                          \
         nullptr, /* getGeneric    */                                          \
         nullptr, /* getProperty    */                                         \
         nullptr, /* getElement    */                                          \
+        nullptr, /* getElementIfPresent */                                    \
         nullptr, /* getSpecial    */                                          \
         nullptr, /* setGeneric    */                                          \
         nullptr, /* setProperty    */                                         \
         nullptr, /* setElement    */                                          \
         nullptr, /* setSpecial    */                                          \
         nullptr, /* getGenericAttributes  */                                  \
         nullptr, /* setGenericAttributes  */                                  \
         nullptr, /* deleteProperty */                                         \
         nullptr, /* deleteElement */                                          \
         nullptr, /* deleteSpecial */                                          \
         nullptr, nullptr, /* watch/unwatch */                                 \
-        nullptr, /* slice */                                                  \
         XPC_WN_JSOp_Enumerate,                                                \
         XPC_WN_JSOp_ThisObject,                                               \
     }
 
 // Maybe this macro should check for class->enumerate ==
 // XPC_WN_Shared_Proto_Enumerate or something rather than checking for
 // 4 classes?
 static inline bool IS_PROTO_CLASS(const js::Class *clazz)