Bug 1491736 - Move the various meta-object operations into a new vm/ObjectOperations-inl.h header rather than sharding declaration and definition across separate headers, thereby risking used-before-definition problems. r=jandem
authorJeff Walden <jwalden@mit.edu>
Sat, 15 Sep 2018 20:24:31 -0700
changeset 436742 3ef024a29617c4e33765d0d9350101798fcee390
parent 436741 47d60f29b7cf1fc42621d1f68af36aa1e4e6901c
child 436743 5ecae696c54f6240e520e9a1517e7a5fc24069ed
child 436782 731089f123c6abf52f23d7ff7a52b2ca283ef0fa
push id34658
push userrgurzau@mozilla.com
push dateMon, 17 Sep 2018 16:46:41 +0000
treeherdermozilla-central@5ecae696c54f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjandem
bugs1491736
milestone64.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1491736 - Move the various meta-object operations into a new vm/ObjectOperations-inl.h header rather than sharding declaration and definition across separate headers, thereby risking used-before-definition problems. r=jandem
js/src/builtin/RegExp.cpp
js/src/vm/ArrayObject-inl.h
js/src/vm/GlobalObject-inl.h
js/src/vm/GlobalObject.h
js/src/vm/Interpreter-inl.h
js/src/vm/Interpreter.cpp
js/src/vm/JSObject-inl.h
js/src/vm/JSObject.h
js/src/vm/NativeObject.h
js/src/vm/ObjectOperations-inl.h
js/src/vm/ObjectOperations.h
js/src/vm/TypedArrayObject-inl.h
--- a/js/src/builtin/RegExp.cpp
+++ b/js/src/builtin/RegExp.cpp
@@ -15,16 +15,17 @@
 #include "util/StringBuffer.h"
 #include "util/Unicode.h"
 #include "vm/JSContext.h"
 #include "vm/RegExpStatics.h"
 #include "vm/SelfHosting.h"
 
 #include "vm/JSObject-inl.h"
 #include "vm/NativeObject-inl.h"
+#include "vm/ObjectOperations-inl.h"
 #include "vm/UnboxedObject-inl.h"
 
 using namespace js;
 
 using mozilla::CheckedInt;
 using mozilla::IsAsciiDigit;
 
 using JS::CompileOptions;
--- a/js/src/vm/ArrayObject-inl.h
+++ b/js/src/vm/ArrayObject-inl.h
@@ -9,16 +9,17 @@
 
 #include "vm/ArrayObject.h"
 
 #include "gc/GCTrace.h"
 #include "vm/StringType.h"
 
 #include "vm/JSObject-inl.h"
 #include "vm/ObjectGroup-inl.h"
+#include "vm/ObjectOperations-inl.h" // js::GetElement
 #include "vm/TypeInference-inl.h"
 
 namespace js {
 
 inline void
 ArrayObject::setLength(JSContext* cx, uint32_t length)
 {
     MOZ_ASSERT(lengthIsWritable());
new file mode 100644
--- /dev/null
+++ b/js/src/vm/GlobalObject-inl.h
@@ -0,0 +1,31 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_GlobalObject_inl_h
+#define vm_GlobalObject_inl_h
+
+#include "vm/GlobalObject.h"
+
+#include "mozilla/Assertions.h" // MOZ_ASSERT
+
+#include "vm/JSContext.h" // JSContext
+#include "vm/ObjectOperations-inl.h" // js::SetProperty
+
+/* static */ inline bool
+js::GlobalObject::setIntrinsicValue(JSContext* cx, Handle<GlobalObject*> global,
+                                    HandlePropertyName name, HandleValue value)
+{
+    MOZ_ASSERT(cx->runtime()->isSelfHostingGlobal(global));
+
+    RootedObject holder(cx, GlobalObject::getIntrinsicsHolder(cx, global));
+    if (!holder) {
+        return false;
+    }
+
+    return SetProperty(cx, holder, name, value);
+}
+
+#endif /* vm_GlobalObject_inl_h */
--- a/js/src/vm/GlobalObject.h
+++ b/js/src/vm/GlobalObject.h
@@ -733,26 +733,18 @@ class GlobalObject : public NativeObject
             return false;
         }
         return GlobalObject::addIntrinsicValue(cx, global, name, value);
     }
 
     static bool addIntrinsicValue(JSContext* cx, Handle<GlobalObject*> global,
                                   HandlePropertyName name, HandleValue value);
 
-    static bool setIntrinsicValue(JSContext* cx, Handle<GlobalObject*> global,
-                                  HandlePropertyName name, HandleValue value)
-    {
-        MOZ_ASSERT(cx->runtime()->isSelfHostingGlobal(global));
-        RootedObject holder(cx, GlobalObject::getIntrinsicsHolder(cx, global));
-        if (!holder) {
-            return false;
-        }
-        return SetProperty(cx, holder, name, value);
-    }
+    static inline bool setIntrinsicValue(JSContext* cx, Handle<GlobalObject*> global,
+                                         HandlePropertyName name, HandleValue value);
 
     static bool getSelfHostedFunction(JSContext* cx, Handle<GlobalObject*> global,
                                       HandlePropertyName selfHostedName, HandleAtom name,
                                       unsigned nargs, MutableHandleValue funVal);
 
     bool hasRegExpStatics() const;
     static RegExpStatics* getRegExpStatics(JSContext* cx,
                                            Handle<GlobalObject*> global);
--- a/js/src/vm/Interpreter-inl.h
+++ b/js/src/vm/Interpreter-inl.h
@@ -12,18 +12,20 @@
 #include "jsnum.h"
 
 #include "builtin/String.h"
 #include "jit/Ion.h"
 #include "vm/ArgumentsObject.h"
 #include "vm/Realm.h"
 
 #include "vm/EnvironmentObject-inl.h"
+#include "vm/GlobalObject-inl.h"
 #include "vm/JSAtom-inl.h"
 #include "vm/JSObject-inl.h"
+#include "vm/ObjectOperations-inl.h"
 #include "vm/Stack-inl.h"
 #include "vm/StringType-inl.h"
 #include "vm/UnboxedObject-inl.h"
 
 namespace js {
 
 /*
  * Every possible consumer of MagicValue(JS_OPTIMIZED_ARGUMENTS) (as determined
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -58,16 +58,17 @@
 #include "jit/JitFrames-inl.h"
 #include "vm/Debugger-inl.h"
 #include "vm/EnvironmentObject-inl.h"
 #include "vm/GeckoProfiler-inl.h"
 #include "vm/JSAtom-inl.h"
 #include "vm/JSFunction-inl.h"
 #include "vm/JSScript-inl.h"
 #include "vm/NativeObject-inl.h"
+#include "vm/ObjectOperations-inl.h"
 #include "vm/Probes-inl.h"
 #include "vm/Stack-inl.h"
 
 using namespace js;
 
 using mozilla::DebugOnly;
 using mozilla::NumberEqualsInt32;
 
--- a/js/src/vm/JSObject-inl.h
+++ b/js/src/vm/JSObject-inl.h
@@ -24,55 +24,33 @@
 #include "vm/NumberObject.h"
 #include "vm/Probes.h"
 #include "vm/StringObject.h"
 #include "vm/TypedArrayObject.h"
 
 #include "gc/Marking-inl.h"
 #include "gc/ObjectKind-inl.h"
 #include "vm/JSAtom-inl.h"
+#include "vm/ObjectOperations-inl.h" // js::MaybeHasInterestingSymbolProperty
 #include "vm/Realm-inl.h"
 #include "vm/ShapedObject-inl.h"
 #include "vm/TypeInference-inl.h"
 
 namespace js {
 
 // This is needed here for ensureShape() below.
 inline bool
 MaybeConvertUnboxedObjectToNative(JSContext* cx, JSObject* obj)
 {
     if (obj->is<UnboxedPlainObject>()) {
         return UnboxedPlainObject::convertToNative(cx, obj);
     }
     return true;
 }
 
-static MOZ_ALWAYS_INLINE bool
-ClassMayResolveId(const JSAtomState& names, const Class* clasp, jsid id, JSObject* maybeObj)
-{
-    MOZ_ASSERT_IF(maybeObj, maybeObj->getClass() == clasp);
-
-    if (!clasp->getResolve()) {
-        // Sanity check: we should only have a mayResolve hook if we have a
-        // resolve hook.
-        MOZ_ASSERT(!clasp->getMayResolve(), "Class with mayResolve hook but no resolve hook");
-        return false;
-    }
-
-    if (JSMayResolveOp mayResolve = clasp->getMayResolve()) {
-        // Tell the analysis our mayResolve hooks won't trigger GC.
-        JS::AutoSuppressGCAnalysis nogc;
-        if (!mayResolve(names, id, maybeObj)) {
-            return false;
-        }
-    }
-
-    return true;
-}
-
 } // namespace js
 
 inline js::Shape*
 JSObject::maybeShape() const
 {
     if (!is<js::ShapedObject>()) {
         return nullptr;
     }
@@ -194,154 +172,16 @@ JSObject::getGroup(JSContext* cx, js::Ha
 inline void
 JSObject::setGroup(js::ObjectGroup* group)
 {
     MOZ_RELEASE_ASSERT(group);
     MOZ_ASSERT(!isSingleton());
     group_ = group;
 }
 
-
-/*** Standard internal methods *******************************************************************/
-
-inline bool
-js::GetPrototype(JSContext* cx, js::HandleObject obj, js::MutableHandleObject protop)
-{
-    if (obj->hasDynamicPrototype()) {
-        MOZ_ASSERT(obj->is<js::ProxyObject>());
-        return js::Proxy::getPrototype(cx, obj, protop);
-    }
-
-    protop.set(obj->taggedProto().toObjectOrNull());
-    return true;
-}
-
-inline bool
-js::IsExtensible(JSContext* cx, HandleObject obj, bool* extensible)
-{
-    if (obj->is<ProxyObject>()) {
-        MOZ_ASSERT(!cx->helperThread());
-        return Proxy::isExtensible(cx, obj, extensible);
-    }
-
-    *extensible = obj->nonProxyIsExtensible();
-
-    // If the following assertion fails, there's somewhere else a missing
-    // call to shrinkCapacityToInitializedLength() which needs to be found and
-    // fixed.
-    MOZ_ASSERT_IF(obj->isNative() && !*extensible,
-                  obj->as<NativeObject>().getDenseInitializedLength() ==
-                  obj->as<NativeObject>().getDenseCapacity());
-    return true;
-}
-
-inline bool
-js::HasProperty(JSContext* cx, HandleObject obj, PropertyName* name, bool* found)
-{
-    RootedId id(cx, NameToId(name));
-    return HasProperty(cx, obj, id, found);
-}
-
-inline bool
-js::GetElement(JSContext* cx, HandleObject obj, HandleValue receiver, uint32_t index,
-               MutableHandleValue vp)
-{
-    RootedId id(cx);
-    if (!IndexToId(cx, index, &id)) {
-        return false;
-    }
-    return GetProperty(cx, obj, receiver, id, vp);
-}
-
-inline bool
-js::GetElement(JSContext* cx, HandleObject obj, HandleObject receiver, uint32_t index,
-               MutableHandleValue vp)
-{
-    RootedValue receiverValue(cx, ObjectValue(*receiver));
-    return GetElement(cx, obj, receiverValue, index, vp);
-}
-
-inline bool
-js::GetElementNoGC(JSContext* cx, JSObject* obj, const Value& receiver, uint32_t index, Value* vp)
-{
-    if (obj->getOpsGetProperty()) {
-        return false;
-    }
-
-    if (index > JSID_INT_MAX) {
-        return false;
-    }
-    return GetPropertyNoGC(cx, obj, receiver, INT_TO_JSID(index), vp);
-}
-
-inline bool
-js::DeleteProperty(JSContext* cx, HandleObject obj, HandleId id, ObjectOpResult& result)
-{
-    MarkTypePropertyNonData(cx, obj, id);
-    if (DeletePropertyOp op = obj->getOpsDeleteProperty()) {
-        return op(cx, obj, id, result);
-    }
-    return NativeDeleteProperty(cx, obj.as<NativeObject>(), id, result);
-}
-
-inline bool
-js::DeleteElement(JSContext* cx, HandleObject obj, uint32_t index, ObjectOpResult& result)
-{
-    RootedId id(cx);
-    if (!IndexToId(cx, index, &id)) {
-        return false;
-    }
-    return DeleteProperty(cx, obj, id, result);
-}
-
-MOZ_ALWAYS_INLINE bool
-js::MaybeHasInterestingSymbolProperty(JSContext* cx, JSObject* obj, Symbol* symbol,
-                                      JSObject** holder)
-{
-    MOZ_ASSERT(symbol->isInterestingSymbol());
-
-    jsid id = SYMBOL_TO_JSID(symbol);
-    do {
-        if (obj->maybeHasInterestingSymbolProperty() ||
-            MOZ_UNLIKELY(ClassMayResolveId(cx->names(), obj->getClass(), id, obj)))
-        {
-            if (holder) {
-                *holder = obj;
-            }
-            return true;
-        }
-        obj = obj->staticPrototype();
-    } while (obj);
-
-    return false;
-}
-
-MOZ_ALWAYS_INLINE bool
-js::GetInterestingSymbolProperty(JSContext* cx, HandleObject obj, Symbol* sym, MutableHandleValue vp)
-{
-    JSObject* holder;
-    if (!MaybeHasInterestingSymbolProperty(cx, obj, sym, &holder)) {
-#ifdef DEBUG
-        RootedValue receiver(cx, ObjectValue(*obj));
-        RootedId id(cx, SYMBOL_TO_JSID(sym));
-        if (!GetProperty(cx, obj, receiver, id, vp)) {
-            return false;
-        }
-        MOZ_ASSERT(vp.isUndefined());
-#endif
-        vp.setUndefined();
-        return true;
-    }
-
-    RootedObject holderRoot(cx, holder);
-    RootedValue receiver(cx, ObjectValue(*obj));
-    RootedId id(cx, SYMBOL_TO_JSID(sym));
-    return GetProperty(cx, holderRoot, receiver, id, vp);
-}
-
 /* * */
 
 inline bool
 JSObject::isQualifiedVarObj() const
 {
     if (is<js::DebugEnvironmentProxy>()) {
         return as<js::DebugEnvironmentProxy>().environment().isQualifiedVarObj();
     }
--- a/js/src/vm/JSObject.h
+++ b/js/src/vm/JSObject.h
@@ -647,319 +647,16 @@ JSObject::writeBarrierPost(void* cellp, 
     // be a prev entry if the prev value was in the nursery.
     if (prev && (buffer = prev->storeBuffer())) {
         buffer->unputCell(static_cast<js::gc::Cell**>(cellp));
     }
 }
 
 namespace js {
 
-/*** Standard internal methods ********************************************************************
- *
- * The functions below are the fundamental operations on objects. See the
- * comment about "Standard internal methods" in jsapi.h.
- */
-
-/*
- * ES6 [[GetPrototypeOf]]. Get obj's prototype, storing it in protop.
- *
- * If obj is definitely not a proxy, the infallible obj->getProto() can be used
- * instead. See the comment on JSObject::getTaggedProto().
- */
-inline bool
-GetPrototype(JSContext* cx, HandleObject obj, MutableHandleObject protop);
-
-/*
- * ES6 [[SetPrototypeOf]]. Change obj's prototype to proto.
- *
- * Returns false on error, success of operation in *result. For example, if
- * obj is not extensible, its prototype is fixed. js::SetPrototype will return
- * true, because no exception is thrown for this; but *result will be false.
- */
-extern bool
-SetPrototype(JSContext* cx, HandleObject obj, HandleObject proto,
-             ObjectOpResult& result);
-
-/* Convenience function: like the above, but throw on failure. */
-extern bool
-SetPrototype(JSContext* cx, HandleObject obj, HandleObject proto);
-
-/*
- * ES6 [[IsExtensible]]. Extensible objects can have new properties defined on
- * them. Inextensible objects can't, and their [[Prototype]] slot is fixed as
- * well.
- */
-inline bool
-IsExtensible(JSContext* cx, HandleObject obj, bool* extensible);
-
-/*
- * ES6 [[PreventExtensions]]. Attempt to change the [[Extensible]] bit on |obj|
- * to false.  Indicate success or failure through the |result| outparam, or
- * actual error through the return value.
- */
-extern bool
-PreventExtensions(JSContext* cx, HandleObject obj, ObjectOpResult& result);
-
-/* Convenience function. As above, but throw on failure. */
-extern bool
-PreventExtensions(JSContext* cx, HandleObject obj);
-
-/*
- * ES6 [[GetOwnProperty]]. Get a description of one of obj's own properties.
- *
- * If no such property exists on obj, return true with desc.object() set to
- * null.
- */
-extern bool
-GetOwnPropertyDescriptor(JSContext* cx, HandleObject obj, HandleId id,
-                         MutableHandle<JS::PropertyDescriptor> desc);
-
-/* ES6 [[DefineOwnProperty]]. Define a property on obj. */
-extern bool
-DefineProperty(JSContext* cx, HandleObject obj, HandleId id,
-               Handle<JS::PropertyDescriptor> desc, ObjectOpResult& result);
-
-extern bool
-DefineAccessorProperty(JSContext* cx, HandleObject obj, HandleId id,
-                       HandleObject getter, HandleObject setter, unsigned attrs,
-                       ObjectOpResult& result);
-
-extern bool
-DefineDataProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue value,
-                   unsigned attrs, ObjectOpResult& result);
-
-extern bool
-DefineDataProperty(JSContext* cx, HandleObject obj, PropertyName* name, HandleValue value,
-                   unsigned attrs, ObjectOpResult& result);
-
-extern bool
-DefineDataElement(JSContext* cx, HandleObject obj, uint32_t index, HandleValue value,
-                  unsigned attrs, ObjectOpResult& result);
-
-/*
- * When the 'result' out-param is omitted, the behavior is the same as above, except
- * that any failure results in a TypeError.
- */
-extern bool
-DefineProperty(JSContext* cx, HandleObject obj, HandleId id, Handle<JS::PropertyDescriptor> desc);
-
-extern bool
-DefineAccessorProperty(JSContext* cx, HandleObject obj, HandleId id,
-                       HandleObject getter, HandleObject setter,
-                       unsigned attrs = JSPROP_ENUMERATE);
-
-extern bool
-DefineDataProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue value,
-                   unsigned attrs = JSPROP_ENUMERATE);
-
-extern bool
-DefineDataProperty(JSContext* cx, HandleObject obj, PropertyName* name, HandleValue value,
-                   unsigned attrs = JSPROP_ENUMERATE);
-
-extern bool
-DefineDataElement(JSContext* cx, HandleObject obj, uint32_t index, HandleValue value,
-                  unsigned attrs = JSPROP_ENUMERATE);
-
-/*
- * ES6 [[Has]]. Set *foundp to true if `id in obj` (that is, if obj has an own
- * or inherited property obj[id]), false otherwise.
- */
-inline bool
-HasProperty(JSContext* cx, HandleObject obj, HandleId id, bool* foundp);
-
-inline bool
-HasProperty(JSContext* cx, HandleObject obj, PropertyName* name, bool* foundp);
-
-/*
- * ES6 [[Get]]. Get the value of the property `obj[id]`, or undefined if no
- * such property exists.
- *
- * Typically obj == receiver; if obj != receiver then the caller is most likely
- * a proxy using GetProperty to finish a property get that started out as
- * `receiver[id]`, and we've already searched the prototype chain up to `obj`.
- */
-inline bool
-GetProperty(JSContext* cx, HandleObject obj, HandleValue receiver, HandleId id,
-            MutableHandleValue vp);
-
-inline bool
-GetProperty(JSContext* cx, HandleObject obj, HandleValue receiver, PropertyName* name,
-            MutableHandleValue vp)
-{
-    RootedId id(cx, NameToId(name));
-    return GetProperty(cx, obj, receiver, id, vp);
-}
-
-inline bool
-GetProperty(JSContext* cx, HandleObject obj, HandleObject receiver, HandleId id,
-            MutableHandleValue vp)
-{
-    RootedValue receiverValue(cx, ObjectValue(*receiver));
-    return GetProperty(cx, obj, receiverValue, id, vp);
-}
-
-inline bool
-GetProperty(JSContext* cx, HandleObject obj, HandleObject receiver, PropertyName* name,
-            MutableHandleValue vp)
-{
-    RootedValue receiverValue(cx, ObjectValue(*receiver));
-    return GetProperty(cx, obj, receiverValue, name, vp);
-}
-
-inline bool
-GetElement(JSContext* cx, HandleObject obj, HandleValue receiver, uint32_t index,
-           MutableHandleValue vp);
-
-inline bool
-GetElement(JSContext* cx, HandleObject obj, HandleObject receiver, uint32_t index,
-           MutableHandleValue vp);
-
-inline bool
-GetPropertyNoGC(JSContext* cx, JSObject* obj, const Value& receiver, jsid id, Value* vp);
-
-inline bool
-GetPropertyNoGC(JSContext* cx, JSObject* obj, const Value& receiver, PropertyName* name, Value* vp)
-{
-    return GetPropertyNoGC(cx, obj, receiver, NameToId(name), vp);
-}
-
-inline bool
-GetElementNoGC(JSContext* cx, JSObject* obj, const Value& receiver, uint32_t index, Value* vp);
-
-// Returns whether |obj| or an object on its proto chain may have an interesting
-// symbol property (see JSObject::hasInterestingSymbolProperty). If it returns
-// true, *holder is set to the object that may have this property.
-MOZ_ALWAYS_INLINE bool
-MaybeHasInterestingSymbolProperty(JSContext* cx, JSObject* obj, Symbol* symbol,
-                                  JSObject** holder = nullptr);
-
-// Like GetProperty but optimized for interesting symbol properties like
-// @@toStringTag.
-MOZ_ALWAYS_INLINE bool
-GetInterestingSymbolProperty(JSContext* cx, HandleObject obj, Symbol* sym, MutableHandleValue vp);
-
-/*
- * ES6 [[Set]]. Carry out the assignment `obj[id] = v`.
- *
- * The `receiver` argument has to do with how [[Set]] interacts with the
- * prototype chain and proxies. It's hard to explain and ES6 doesn't really
- * try. Long story short, if you just want bog-standard assignment, pass
- * `ObjectValue(*obj)` as receiver. Or better, use one of the signatures that
- * doesn't have a receiver parameter.
- *
- * Callers pass obj != receiver e.g. when a proxy is involved, obj is the
- * proxy's target, and the proxy is using SetProperty to finish an assignment
- * that started out as `receiver[id] = v`, by delegating it to obj.
- */
-inline bool
-SetProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue v,
-            HandleValue receiver, ObjectOpResult& result);
-
-inline bool
-SetProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue v)
-{
-    RootedValue receiver(cx, ObjectValue(*obj));
-    ObjectOpResult result;
-    return SetProperty(cx, obj, id, v, receiver, result) &&
-           result.checkStrict(cx, obj, id);
-}
-
-inline bool
-SetProperty(JSContext* cx, HandleObject obj, PropertyName* name, HandleValue v,
-            HandleValue receiver, ObjectOpResult& result)
-{
-    RootedId id(cx, NameToId(name));
-    return SetProperty(cx, obj, id, v, receiver, result);
-}
-
-inline bool
-SetProperty(JSContext* cx, HandleObject obj, PropertyName* name, HandleValue v)
-{
-    RootedId id(cx, NameToId(name));
-    RootedValue receiver(cx, ObjectValue(*obj));
-    ObjectOpResult result;
-    return SetProperty(cx, obj, id, v, receiver, result) &&
-           result.checkStrict(cx, obj, id);
-}
-
-inline bool
-SetElement(JSContext* cx, HandleObject obj, uint32_t index, HandleValue v,
-           HandleValue receiver, ObjectOpResult& result);
-
-/*
- * ES6 draft rev 31 (15 Jan 2015) 7.3.3 Put (O, P, V, Throw), except that on
- * success, the spec says this is supposed to return a boolean value, which we
- * don't bother doing.
- */
-inline bool
-PutProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue v, bool strict)
-{
-    RootedValue receiver(cx, ObjectValue(*obj));
-    ObjectOpResult result;
-    return SetProperty(cx, obj, id, v, receiver, result) &&
-           result.checkStrictErrorOrWarning(cx, obj, id, strict);
-}
-
-/*
- * ES6 [[Delete]]. Equivalent to the JS code `delete obj[id]`.
- */
-inline bool
-DeleteProperty(JSContext* cx, HandleObject obj, HandleId id, ObjectOpResult& result);
-
-inline bool
-DeleteElement(JSContext* cx, HandleObject obj, uint32_t index, ObjectOpResult& result);
-
-
-/*** SpiderMonkey nonstandard internal methods ***************************************************/
-
-/**
- * If |obj| (underneath any functionally-transparent wrapper proxies) has as
- * its [[GetPrototypeOf]] trap the ordinary [[GetPrototypeOf]] behavior defined
- * for ordinary objects, set |*isOrdinary = true| and store |obj|'s prototype
- * in |result|.  Otherwise set |*isOrdinary = false|.  In case of error, both
- * outparams have unspecified value.
- */
-extern bool
-GetPrototypeIfOrdinary(JSContext* cx, HandleObject obj, bool* isOrdinary,
-                       MutableHandleObject protop);
-
-/*
- * Attempt to make |obj|'s [[Prototype]] immutable, such that subsequently
- * trying to change it will not work.  If an internal error occurred,
- * returns false.  Otherwise, |*succeeded| is set to true iff |obj|'s
- * [[Prototype]] is now immutable.
- */
-extern bool
-SetImmutablePrototype(JSContext* cx, JS::HandleObject obj, bool* succeeded);
-
-extern bool
-GetPropertyDescriptor(JSContext* cx, HandleObject obj, HandleId id,
-                      MutableHandle<JS::PropertyDescriptor> desc);
-
-/*
- * Deprecated. A version of HasProperty that also returns the object on which
- * the property was found (but that information is unreliable for proxies), and
- * the Shape of the property, if native.
- */
-extern bool
-LookupProperty(JSContext* cx, HandleObject obj, HandleId id,
-               MutableHandleObject objp, MutableHandle<PropertyResult> propp);
-
-inline bool
-LookupProperty(JSContext* cx, HandleObject obj, PropertyName* name,
-               MutableHandleObject objp, MutableHandle<PropertyResult> propp)
-{
-    RootedId id(cx, NameToId(name));
-    return LookupProperty(cx, obj, id, objp, propp);
-}
-
-/* Set *result to tell whether obj has an own property with the given id. */
-extern bool
-HasOwnProperty(JSContext* cx, HandleObject obj, HandleId id, bool* result);
-
 /**
  * This enum is used to select whether the defined functions should be marked as
  * builtin native instrinsics for self-hosted code.
  */
 enum DefineAsIntrinsic {
     NotIntrinsic,
     AsIntrinsic
 };
--- a/js/src/vm/NativeObject.h
+++ b/js/src/vm/NativeObject.h
@@ -1696,60 +1696,9 @@ CopyDataPropertiesNative(JSContext* cx, 
 
 extern bool
 CopyDataPropertiesNative(JSContext* cx, HandlePlainObject target,
                          Handle<UnboxedPlainObject*> from, HandlePlainObject excludedItems,
                          bool* optimized);
 
 } // namespace js
 
-
-/*** Inline functions declared in JSObject.h that use the native declarations above **************/
-
-inline bool
-js::HasProperty(JSContext* cx, HandleObject obj, HandleId id, bool* foundp)
-{
-    if (HasPropertyOp op = obj->getOpsHasProperty()) {
-        return op(cx, obj, id, foundp);
-    }
-    return NativeHasProperty(cx, obj.as<NativeObject>(), id, foundp);
-}
-
-inline bool
-js::GetProperty(JSContext* cx, HandleObject obj, HandleValue receiver, HandleId id,
-                MutableHandleValue vp)
-{
-    if (GetPropertyOp op = obj->getOpsGetProperty()) {
-        return op(cx, obj, receiver, id, vp);
-    }
-    return NativeGetProperty(cx, obj.as<NativeObject>(), receiver, id, vp);
-}
-
-inline bool
-js::GetPropertyNoGC(JSContext* cx, JSObject* obj, const Value& receiver, jsid id, Value* vp)
-{
-    if (obj->getOpsGetProperty()) {
-        return false;
-    }
-    return NativeGetPropertyNoGC(cx, &obj->as<NativeObject>(), receiver, id, vp);
-}
-
-inline bool
-js::SetProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue v,
-                HandleValue receiver, ObjectOpResult& result)
-{
-    if (obj->getOpsSetProperty()) {
-        return JSObject::nonNativeSetProperty(cx, obj, id, v, receiver, result);
-    }
-    return NativeSetProperty<Qualified>(cx, obj.as<NativeObject>(), id, v, receiver, result);
-}
-
-inline bool
-js::SetElement(JSContext* cx, HandleObject obj, uint32_t index, HandleValue v,
-               HandleValue receiver, ObjectOpResult& result)
-{
-    if (obj->getOpsSetProperty()) {
-        return JSObject::nonNativeSetElement(cx, obj, index, v, receiver, result);
-    }
-    return NativeSetElement(cx, obj.as<NativeObject>(), index, v, receiver, result);
-}
-
 #endif /* vm_NativeObject_h */
new file mode 100644
--- /dev/null
+++ b/js/src/vm/ObjectOperations-inl.h
@@ -0,0 +1,382 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* Fundamental operations on objects. */
+
+#ifndef vm_ObjectOperations_inl_h
+#define vm_ObjectOperations_inl_h
+
+#include "vm/ObjectOperations.h"
+
+#include "mozilla/Assertions.h" // MOZ_ASSERT
+#include "mozilla/Attributes.h" // MOZ_ALWAYS_INLINE
+#include "mozilla/Likely.h" // MOZ_UNLIKELY
+
+#include <stdint.h> // uint32_t
+
+#include "jsapi.h" // JSPROP_ENUMERATE, JS::PropertyDescriptor
+
+#include "js/Class.h" // js::{Delete,Get,Has}PropertyOp, JSMayResolveOp, JS::ObjectOpResult
+#include "js/GCAPI.h" // JS::AutoSuppressGCAnalysis
+#include "js/Id.h" // INT_TO_JSID, jsid, JSID_INT_MAX, SYMBOL_TO_JSID
+#include "js/RootingAPI.h" // JS::Handle, JS::MutableHandle, JS::Rooted
+#include "js/Value.h" // JS::ObjectValue, JS::Value
+#include "proxy/Proxy.h" // js::Proxy
+#include "vm/JSContext.h" // JSContext
+#include "vm/JSObject.h" // JSObject
+#include "vm/NativeObject.h" // js::NativeObject, js::Native{Get,Has,Set}Property, js::NativeGetPropertyNoGC, js::Qualified
+#include "vm/ProxyObject.h" // js::ProxyObject
+#include "vm/StringType.h" // js::NameToId
+#include "vm/SymbolType.h" // JS::Symbol
+
+#include "vm/JSAtom-inl.h" // js::IndexToId
+#include "vm/TypeInference-inl.h" // js::MarkTypePropertyNonData
+
+namespace js {
+
+// The functions below are the fundamental operations on objects. See the
+// comment about "Standard internal methods" in jsapi.h.
+
+/*
+ * ES6 [[GetPrototypeOf]]. Get obj's prototype, storing it in protop.
+ *
+ * If obj is definitely not a proxy, the infallible obj->getProto() can be used
+ * instead. See the comment on JSObject::getTaggedProto().
+ */
+inline bool
+GetPrototype(JSContext* cx, JS::Handle<JSObject*> obj, JS::MutableHandle<JSObject*> protop)
+{
+    if (obj->hasDynamicPrototype()) {
+        MOZ_ASSERT(obj->is<ProxyObject>());
+        return Proxy::getPrototype(cx, obj, protop);
+    }
+
+    protop.set(obj->taggedProto().toObjectOrNull());
+    return true;
+}
+
+/*
+ * ES6 [[IsExtensible]]. Extensible objects can have new properties defined on
+ * them. Inextensible objects can't, and their [[Prototype]] slot is fixed as
+ * well.
+ */
+inline bool
+IsExtensible(JSContext* cx, JS::Handle<JSObject*> obj, bool* extensible)
+{
+    if (obj->is<ProxyObject>()) {
+        MOZ_ASSERT(!cx->helperThread());
+        return Proxy::isExtensible(cx, obj, extensible);
+    }
+
+    *extensible = obj->nonProxyIsExtensible();
+
+    // If the following assertion fails, there's somewhere else a missing
+    // call to shrinkCapacityToInitializedLength() which needs to be found and
+    // fixed.
+    MOZ_ASSERT_IF(obj->isNative() && !*extensible,
+                  obj->as<NativeObject>().getDenseInitializedLength() ==
+                  obj->as<NativeObject>().getDenseCapacity());
+    return true;
+}
+
+/*
+ * ES6 [[Has]]. Set *foundp to true if `id in obj` (that is, if obj has an own
+ * or inherited property obj[id]), false otherwise.
+ */
+inline bool
+HasProperty(JSContext* cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id, bool* foundp)
+{
+    if (HasPropertyOp op = obj->getOpsHasProperty()) {
+        return op(cx, obj, id, foundp);
+    }
+
+    return NativeHasProperty(cx, obj.as<NativeObject>(), id, foundp);
+}
+
+inline bool
+HasProperty(JSContext* cx, JS::Handle<JSObject*> obj, PropertyName* name, bool* foundp)
+{
+    JS::Rooted<jsid> id(cx, NameToId(name));
+    return HasProperty(cx, obj, id, foundp);
+}
+
+/*
+ * ES6 [[Get]]. Get the value of the property `obj[id]`, or undefined if no
+ * such property exists.
+ *
+ * Typically obj == receiver; if obj != receiver then the caller is most likely
+ * a proxy using GetProperty to finish a property get that started out as
+ * `receiver[id]`, and we've already searched the prototype chain up to `obj`.
+ */
+inline bool
+GetProperty(JSContext* cx, JS::Handle<JSObject*> obj, JS::Handle<JS::Value> receiver,
+            JS::Handle<jsid> id, JS::MutableHandle<JS::Value> vp)
+{
+    if (GetPropertyOp op = obj->getOpsGetProperty()) {
+        return op(cx, obj, receiver, id, vp);
+    }
+
+    return NativeGetProperty(cx, obj.as<NativeObject>(), receiver, id, vp);
+}
+
+inline bool
+GetProperty(JSContext* cx, JS::Handle<JSObject*> obj, JS::Handle<JS::Value> receiver, PropertyName* name,
+            JS::MutableHandle<JS::Value> vp)
+{
+    JS::Rooted<jsid> id(cx, NameToId(name));
+    return GetProperty(cx, obj, receiver, id, vp);
+}
+
+inline bool
+GetProperty(JSContext* cx, JS::Handle<JSObject*> obj, JS::Handle<JSObject*> receiver,
+            JS::Handle<jsid> id, JS::MutableHandle<JS::Value> vp)
+{
+    JS::Rooted<JS::Value> receiverValue(cx, JS::ObjectValue(*receiver));
+    return GetProperty(cx, obj, receiverValue, id, vp);
+}
+
+inline bool
+GetProperty(JSContext* cx, JS::Handle<JSObject*> obj, JS::Handle<JSObject*> receiver,
+            PropertyName* name, JS::MutableHandle<JS::Value> vp)
+{
+    JS::Rooted<JS::Value> receiverValue(cx, JS::ObjectValue(*receiver));
+    return GetProperty(cx, obj, receiverValue, name, vp);
+}
+
+inline bool
+GetElement(JSContext* cx, JS::Handle<JSObject*> obj, JS::Handle<JS::Value> receiver,
+           uint32_t index, JS::MutableHandle<JS::Value> vp)
+{
+    JS::Rooted<jsid> id(cx);
+    if (!IndexToId(cx, index, &id)) {
+        return false;
+    }
+
+    return GetProperty(cx, obj, receiver, id, vp);
+}
+
+inline bool
+GetElement(JSContext* cx, JS::Handle<JSObject*> obj, JS::Handle<JSObject*> receiver,
+           uint32_t index, JS::MutableHandle<JS::Value> vp)
+{
+    JS::Rooted<JS::Value> receiverValue(cx, JS::ObjectValue(*receiver));
+    return GetElement(cx, obj, receiverValue, index, vp);
+}
+
+
+inline bool
+GetPropertyNoGC(JSContext* cx, JSObject* obj, const JS::Value& receiver, jsid id, JS::Value* vp)
+{
+    if (obj->getOpsGetProperty()) {
+        return false;
+    }
+
+    return NativeGetPropertyNoGC(cx, &obj->as<NativeObject>(), receiver, id, vp);
+}
+
+inline bool
+GetPropertyNoGC(JSContext* cx, JSObject* obj, const JS::Value& receiver, PropertyName* name,
+                JS::Value* vp)
+{
+    return GetPropertyNoGC(cx, obj, receiver, NameToId(name), vp);
+}
+
+inline bool
+GetElementNoGC(JSContext* cx, JSObject* obj, const JS::Value& receiver, uint32_t index,
+               JS::Value* vp)
+{
+    if (obj->getOpsGetProperty()) {
+        return false;
+    }
+
+    if (index > JSID_INT_MAX) {
+        return false;
+    }
+
+    return GetPropertyNoGC(cx, obj, receiver, INT_TO_JSID(index), vp);
+}
+
+static MOZ_ALWAYS_INLINE bool
+ClassMayResolveId(const JSAtomState& names, const Class* clasp, jsid id, JSObject* maybeObj)
+{
+    MOZ_ASSERT_IF(maybeObj, maybeObj->getClass() == clasp);
+
+    if (!clasp->getResolve()) {
+        // Sanity check: we should only have a mayResolve hook if we have a
+        // resolve hook.
+        MOZ_ASSERT(!clasp->getMayResolve(), "Class with mayResolve hook but no resolve hook");
+        return false;
+    }
+
+    if (JSMayResolveOp mayResolve = clasp->getMayResolve()) {
+        // Tell the analysis our mayResolve hooks won't trigger GC.
+        JS::AutoSuppressGCAnalysis nogc;
+        if (!mayResolve(names, id, maybeObj)) {
+            return false;
+        }
+    }
+
+    return true;
+}
+
+// Returns whether |obj| or an object on its proto chain may have an interesting
+// symbol property (see JSObject::hasInterestingSymbolProperty). If it returns
+// true, *holder is set to the object that may have this property.
+MOZ_ALWAYS_INLINE bool
+MaybeHasInterestingSymbolProperty(JSContext* cx, JSObject* obj, JS::Symbol* symbol,
+                                  JSObject** holder /* = nullptr */)
+{
+    MOZ_ASSERT(symbol->isInterestingSymbol());
+
+    jsid id = SYMBOL_TO_JSID(symbol);
+    do {
+        if (obj->maybeHasInterestingSymbolProperty() ||
+            MOZ_UNLIKELY(ClassMayResolveId(cx->names(), obj->getClass(), id, obj)))
+        {
+            if (holder) {
+                *holder = obj;
+            }
+            return true;
+        }
+        obj = obj->staticPrototype();
+    } while (obj);
+
+    return false;
+}
+
+// Like GetProperty but optimized for interesting symbol properties like
+// @@toStringTag.
+MOZ_ALWAYS_INLINE bool
+GetInterestingSymbolProperty(JSContext* cx, JS::Handle<JSObject*> obj, JS::Symbol* sym,
+                             JS::MutableHandle<JS::Value> vp)
+{
+    JSObject* holder;
+    if (!MaybeHasInterestingSymbolProperty(cx, obj, sym, &holder)) {
+#ifdef DEBUG
+        JS::Rooted<JS::Value> receiver(cx, JS::ObjectValue(*obj));
+        JS::Rooted<jsid> id(cx, SYMBOL_TO_JSID(sym));
+        if (!GetProperty(cx, obj, receiver, id, vp)) {
+            return false;
+        }
+        MOZ_ASSERT(vp.isUndefined());
+#endif
+
+        vp.setUndefined();
+        return true;
+    }
+
+    JS::Rooted<JSObject*> holderRoot(cx, holder);
+    JS::Rooted<JS::Value> receiver(cx, JS::ObjectValue(*obj));
+    JS::Rooted<jsid> id(cx, SYMBOL_TO_JSID(sym));
+    return GetProperty(cx, holderRoot, receiver, id, vp);
+}
+
+/*
+ * ES6 [[Set]]. Carry out the assignment `obj[id] = v`.
+ *
+ * The `receiver` argument has to do with how [[Set]] interacts with the
+ * prototype chain and proxies. It's hard to explain and ES6 doesn't really
+ * try. Long story short, if you just want bog-standard assignment, pass
+ * `ObjectValue(*obj)` as receiver. Or better, use one of the signatures that
+ * doesn't have a receiver parameter.
+ *
+ * Callers pass obj != receiver e.g. when a proxy is involved, obj is the
+ * proxy's target, and the proxy is using SetProperty to finish an assignment
+ * that started out as `receiver[id] = v`, by delegating it to obj.
+ */
+inline bool
+SetProperty(JSContext* cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id, JS::Handle<JS::Value> v,
+            JS::Handle<JS::Value> receiver, JS::ObjectOpResult& result)
+{
+    if (obj->getOpsSetProperty()) {
+        return JSObject::nonNativeSetProperty(cx, obj, id, v, receiver, result);
+    }
+
+    return NativeSetProperty<Qualified>(cx, obj.as<NativeObject>(), id, v, receiver, result);
+}
+
+inline bool
+SetProperty(JSContext* cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id, JS::Handle<JS::Value> v)
+{
+    JS::Rooted<JS::Value> receiver(cx, JS::ObjectValue(*obj));
+    JS::ObjectOpResult result;
+    return SetProperty(cx, obj, id, v, receiver, result) &&
+           result.checkStrict(cx, obj, id);
+}
+
+inline bool
+SetProperty(JSContext* cx, JS::Handle<JSObject*> obj, PropertyName* name, JS::Handle<JS::Value> v,
+            JS::Handle<JS::Value> receiver, JS::ObjectOpResult& result)
+{
+    JS::Rooted<jsid> id(cx, NameToId(name));
+    return SetProperty(cx, obj, id, v, receiver, result);
+}
+
+inline bool
+SetProperty(JSContext* cx, JS::Handle<JSObject*> obj, PropertyName* name, JS::Handle<JS::Value> v)
+{
+    JS::Rooted<jsid> id(cx, NameToId(name));
+    JS::Rooted<JS::Value> receiver(cx, JS::ObjectValue(*obj));
+    JS::ObjectOpResult result;
+    return SetProperty(cx, obj, id, v, receiver, result) &&
+           result.checkStrict(cx, obj, id);
+}
+
+inline bool
+SetElement(JSContext* cx, JS::Handle<JSObject*> obj, uint32_t index, JS::Handle<JS::Value> v,
+           JS::Handle<JS::Value> receiver, JS::ObjectOpResult& result)
+{
+    if (obj->getOpsSetProperty()) {
+        return JSObject::nonNativeSetElement(cx, obj, index, v, receiver, result);
+    }
+
+    return NativeSetElement(cx, obj.as<NativeObject>(), index, v, receiver, result);
+}
+
+/*
+ * ES6 draft rev 31 (15 Jan 2015) 7.3.3 Put (O, P, V, Throw), except that on
+ * success, the spec says this is supposed to return a boolean value, which we
+ * don't bother doing.
+ */
+inline bool
+PutProperty(JSContext* cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id, JS::Handle<JS::Value> v,
+            bool strict)
+{
+    JS::Rooted<JS::Value> receiver(cx, JS::ObjectValue(*obj));
+    JS::ObjectOpResult result;
+    return SetProperty(cx, obj, id, v, receiver, result) &&
+           result.checkStrictErrorOrWarning(cx, obj, id, strict);
+}
+
+/*
+ * ES6 [[Delete]]. Equivalent to the JS code `delete obj[id]`.
+ */
+inline bool
+DeleteProperty(JSContext* cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
+               JS::ObjectOpResult& result)
+{
+    MarkTypePropertyNonData(cx, obj, id);
+    if (DeletePropertyOp op = obj->getOpsDeleteProperty()) {
+        return op(cx, obj, id, result);
+    }
+
+    return NativeDeleteProperty(cx, obj.as<NativeObject>(), id, result);
+}
+
+inline bool
+DeleteElement(JSContext* cx, JS::Handle<JSObject*> obj, uint32_t index, JS::ObjectOpResult& result)
+{
+    JS::Rooted<jsid> id(cx);
+    if (!IndexToId(cx, index, &id)) {
+        return false;
+    }
+
+    return DeleteProperty(cx, obj, id, result);
+}
+
+} /* namespace js */
+
+#endif /* vm_ObjectOperations_inl_h */
new file mode 100644
--- /dev/null
+++ b/js/src/vm/ObjectOperations.h
@@ -0,0 +1,302 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* Fundamental operations on objects. */
+
+#ifndef vm_ObjectOperations_h
+#define vm_ObjectOperations_h
+
+#include "mozilla/Attributes.h" // MOZ_ALWAYS_INLINE
+
+#include <stdint.h> // uint32_t
+
+#include "jsapi.h" // JSPROP_ENUMERATE, JS::PropertyDescriptor
+
+#include "js/Class.h" // JS::ObjectOpResult
+#include "js/Id.h" // INT_TO_JSID, jsid, JSID_INT_MAX, SYMBOL_TO_JSID
+#include "js/RootingAPI.h" // JS::Handle, JS::MutableHandle, JS::Rooted
+#include "js/Value.h" // JS::Value
+#include "vm/JSContext.h" // JSContext
+#include "vm/JSObject.h" // JSObject
+#include "vm/StringType.h" // js::NameToId
+#include "vm/SymbolType.h" // JS::Symbol
+
+namespace js {
+
+class PropertyName;
+
+// The functions below are the fundamental operations on objects. See the
+// comment about "Standard internal methods" in jsapi.h.
+
+/*
+ * ES6 [[GetPrototypeOf]]. Get obj's prototype, storing it in protop.
+ *
+ * If obj is definitely not a proxy, the infallible obj->getProto() can be used
+ * instead. See the comment on JSObject::getTaggedProto().
+ */
+inline bool
+GetPrototype(JSContext* cx, JS::Handle<JSObject*> obj, JS::MutableHandle<JSObject*> protop);
+
+/*
+ * ES6 [[SetPrototypeOf]]. Change obj's prototype to proto.
+ *
+ * Returns false on error, success of operation in *result. For example, if
+ * obj is not extensible, its prototype is fixed. js::SetPrototype will return
+ * true, because no exception is thrown for this; but *result will be false.
+ */
+extern bool
+SetPrototype(JSContext* cx, JS::Handle<JSObject*> obj, JS::Handle<JSObject*> proto,
+             JS::ObjectOpResult& result);
+
+/* Convenience function: like the above, but throw on failure. */
+extern bool
+SetPrototype(JSContext* cx, JS::Handle<JSObject*> obj, JS::Handle<JSObject*> proto);
+
+/*
+ * ES6 [[IsExtensible]]. Extensible objects can have new properties defined on
+ * them. Inextensible objects can't, and their [[Prototype]] slot is fixed as
+ * well.
+ */
+inline bool
+IsExtensible(JSContext* cx, JS::Handle<JSObject*> obj, bool* extensible);
+
+/*
+ * ES6 [[PreventExtensions]]. Attempt to change the [[Extensible]] bit on |obj|
+ * to false.  Indicate success or failure through the |result| outparam, or
+ * actual error through the return value.
+ */
+extern bool
+PreventExtensions(JSContext* cx, JS::Handle<JSObject*> obj, JS::ObjectOpResult& result);
+
+/* Convenience function. As above, but throw on failure. */
+extern bool
+PreventExtensions(JSContext* cx, JS::Handle<JSObject*> obj);
+
+/*
+ * ES6 [[GetOwnProperty]]. Get a description of one of obj's own properties.
+ *
+ * If no such property exists on obj, return true with desc.object() set to
+ * null.
+ */
+extern bool
+GetOwnPropertyDescriptor(JSContext* cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
+                         JS::MutableHandle<JS::PropertyDescriptor> desc);
+
+/* ES6 [[DefineOwnProperty]]. Define a property on obj. */
+extern bool
+DefineProperty(JSContext* cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
+               Handle<JS::PropertyDescriptor> desc, JS::ObjectOpResult& result);
+
+/*
+ * When the 'result' out-param is omitted, the behavior is the same as above, except
+ * that any failure results in a TypeError.
+ */
+extern bool
+DefineProperty(JSContext* cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
+               JS::Handle<JS::PropertyDescriptor> desc);
+
+extern bool
+DefineAccessorProperty(JSContext* cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
+                       JS::Handle<JSObject*> getter, JS::Handle<JSObject*> setter, unsigned attrs,
+                       JS::ObjectOpResult& result);
+
+extern bool
+DefineDataProperty(JSContext* cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
+                   JS::Handle<JS::Value> value, unsigned attrs, JS::ObjectOpResult& result);
+
+extern bool
+DefineDataProperty(JSContext* cx, JS::Handle<JSObject*> obj, PropertyName* name, JS::Handle<JS::Value> value,
+                   unsigned attrs, JS::ObjectOpResult& result);
+
+extern bool
+DefineDataElement(JSContext* cx, JS::Handle<JSObject*> obj, uint32_t index, JS::Handle<JS::Value> value,
+                  unsigned attrs, JS::ObjectOpResult& result);
+
+extern bool
+DefineAccessorProperty(JSContext* cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
+                       JS::Handle<JSObject*> getter, JS::Handle<JSObject*> setter,
+                       unsigned attrs = JSPROP_ENUMERATE);
+
+extern bool
+DefineDataProperty(JSContext* cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id, JS::Handle<JS::Value> value,
+                   unsigned attrs = JSPROP_ENUMERATE);
+
+extern bool
+DefineDataProperty(JSContext* cx, JS::Handle<JSObject*> obj, PropertyName* name, JS::Handle<JS::Value> value,
+                   unsigned attrs = JSPROP_ENUMERATE);
+
+extern bool
+DefineDataElement(JSContext* cx, JS::Handle<JSObject*> obj, uint32_t index, JS::Handle<JS::Value> value,
+                  unsigned attrs = JSPROP_ENUMERATE);
+
+/*
+ * ES6 [[Has]]. Set *foundp to true if `id in obj` (that is, if obj has an own
+ * or inherited property obj[id]), false otherwise.
+ */
+inline bool
+HasProperty(JSContext* cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id, bool* foundp);
+
+inline bool
+HasProperty(JSContext* cx, JS::Handle<JSObject*> obj, PropertyName* name, bool* foundp);
+
+/*
+ * ES6 [[Get]]. Get the value of the property `obj[id]`, or undefined if no
+ * such property exists.
+ *
+ * Typically obj == receiver; if obj != receiver then the caller is most likely
+ * a proxy using GetProperty to finish a property get that started out as
+ * `receiver[id]`, and we've already searched the prototype chain up to `obj`.
+ */
+inline bool
+GetProperty(JSContext* cx, JS::Handle<JSObject*> obj, JS::Handle<JS::Value> receiver,
+            JS::Handle<jsid> id, JS::MutableHandle<JS::Value> vp);
+
+inline bool
+GetProperty(JSContext* cx, JS::Handle<JSObject*> obj, JS::Handle<JS::Value> receiver,
+            PropertyName* name, JS::MutableHandle<JS::Value> vp);
+
+inline bool
+GetProperty(JSContext* cx, JS::Handle<JSObject*> obj, JS::Handle<JSObject*> receiver,
+            JS::Handle<jsid> id, JS::MutableHandle<JS::Value> vp);
+
+inline bool
+GetProperty(JSContext* cx, JS::Handle<JSObject*> obj, JS::Handle<JSObject*> receiver,
+            PropertyName* name, JS::MutableHandle<JS::Value> vp);
+
+inline bool
+GetElement(JSContext* cx, JS::Handle<JSObject*> obj, JS::Handle<JS::Value> receiver,
+           uint32_t index, JS::MutableHandle<JS::Value> vp);
+
+inline bool
+GetElement(JSContext* cx, JS::Handle<JSObject*> obj, JS::Handle<JSObject*> receiver,
+           uint32_t index, JS::MutableHandle<JS::Value> vp);
+
+inline bool
+GetPropertyNoGC(JSContext* cx, JSObject* obj, const JS::Value& receiver, jsid id, JS::Value* vp);
+
+inline bool
+GetPropertyNoGC(JSContext* cx, JSObject* obj, const JS::Value& receiver, PropertyName* name,
+                JS::Value* vp);
+
+inline bool
+GetElementNoGC(JSContext* cx, JSObject* obj, const JS::Value& receiver, uint32_t index,
+               JS::Value* vp);
+
+// Returns whether |obj| or an object on its proto chain may have an interesting
+// symbol property (see JSObject::hasInterestingSymbolProperty). If it returns
+// true, *holder is set to the object that may have this property.
+MOZ_ALWAYS_INLINE bool
+MaybeHasInterestingSymbolProperty(JSContext* cx, JSObject* obj, JS::Symbol* symbol,
+                                  JSObject** holder = nullptr);
+
+// Like GetProperty but optimized for interesting symbol properties like
+// @@toStringTag.
+MOZ_ALWAYS_INLINE bool
+GetInterestingSymbolProperty(JSContext* cx, JS::Handle<JSObject*> obj, JS::Symbol* sym,
+                             JS::MutableHandle<JS::Value> vp);
+
+/*
+ * ES6 [[Set]]. Carry out the assignment `obj[id] = v`.
+ *
+ * The `receiver` argument has to do with how [[Set]] interacts with the
+ * prototype chain and proxies. It's hard to explain and ES6 doesn't really
+ * try. Long story short, if you just want bog-standard assignment, pass
+ * `ObjectValue(*obj)` as receiver. Or better, use one of the signatures that
+ * doesn't have a receiver parameter.
+ *
+ * Callers pass obj != receiver e.g. when a proxy is involved, obj is the
+ * proxy's target, and the proxy is using SetProperty to finish an assignment
+ * that started out as `receiver[id] = v`, by delegating it to obj.
+ */
+inline bool
+SetProperty(JSContext* cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id, JS::Handle<JS::Value> v,
+            JS::Handle<JS::Value> receiver, JS::ObjectOpResult& result);
+
+inline bool
+SetProperty(JSContext* cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
+            JS::Handle<JS::Value> v);
+
+inline bool
+SetProperty(JSContext* cx, JS::Handle<JSObject*> obj, PropertyName* name, JS::Handle<JS::Value> v,
+            JS::Handle<JS::Value> receiver, JS::ObjectOpResult& result);
+
+inline bool
+SetProperty(JSContext* cx, JS::Handle<JSObject*> obj, PropertyName* name, JS::Handle<JS::Value> v);
+
+inline bool
+SetElement(JSContext* cx, JS::Handle<JSObject*> obj, uint32_t index, JS::Handle<JS::Value> v,
+           JS::Handle<JS::Value> receiver, JS::ObjectOpResult& result);
+
+/*
+ * ES6 draft rev 31 (15 Jan 2015) 7.3.3 Put (O, P, V, Throw), except that on
+ * success, the spec says this is supposed to return a boolean value, which we
+ * don't bother doing.
+ */
+inline bool
+PutProperty(JSContext* cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id, JS::Handle<JS::Value> v,
+            bool strict);
+
+/*
+ * ES6 [[Delete]]. Equivalent to the JS code `delete obj[id]`.
+ */
+inline bool
+DeleteProperty(JSContext* cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
+               JS::ObjectOpResult& result);
+
+inline bool
+DeleteElement(JSContext* cx, JS::Handle<JSObject*> obj, uint32_t index,
+              JS::ObjectOpResult& result);
+
+/*** SpiderMonkey nonstandard internal methods ***************************************************/
+
+/**
+ * If |obj| (underneath any functionally-transparent wrapper proxies) has as
+ * its [[GetPrototypeOf]] trap the ordinary [[GetPrototypeOf]] behavior defined
+ * for ordinary objects, set |*isOrdinary = true| and store |obj|'s prototype
+ * in |result|.  Otherwise set |*isOrdinary = false|.  In case of error, both
+ * outparams have unspecified value.
+ */
+extern bool
+GetPrototypeIfOrdinary(JSContext* cx, JS::Handle<JSObject*> obj, bool* isOrdinary,
+                       JS::MutableHandle<JSObject*> protop);
+
+/*
+ * Attempt to make |obj|'s [[Prototype]] immutable, such that subsequently
+ * trying to change it will not work.  If an internal error occurred,
+ * returns false.  Otherwise, |*succeeded| is set to true iff |obj|'s
+ * [[Prototype]] is now immutable.
+ */
+extern bool
+SetImmutablePrototype(JSContext* cx, JS::Handle<JSObject*> obj, bool* succeeded);
+
+extern bool
+GetPropertyDescriptor(JSContext* cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
+                      MutableHandle<JS::PropertyDescriptor> desc);
+
+/*
+ * Deprecated. A version of HasProperty that also returns the object on which
+ * the property was found (but that information is unreliable for proxies), and
+ * the Shape of the property, if native.
+ */
+extern bool
+LookupProperty(JSContext* cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
+               JS::MutableHandle<JSObject*> objp, MutableHandle<PropertyResult> propp);
+
+inline bool
+LookupProperty(JSContext* cx, JS::Handle<JSObject*> obj, PropertyName* name,
+               JS::MutableHandle<JSObject*> objp, MutableHandle<PropertyResult> propp)
+{
+    JS::Rooted<jsid> id(cx, NameToId(name));
+    return LookupProperty(cx, obj, id, objp, propp);
+}
+
+/* Set *result to tell whether obj has an own property with the given id. */
+extern bool
+HasOwnProperty(JSContext* cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id, bool* result);
+
+} /* namespace js */
+
+#endif /* vm_ObjectOperations_h */
--- a/js/src/vm/TypedArrayObject-inl.h
+++ b/js/src/vm/TypedArrayObject-inl.h
@@ -23,16 +23,17 @@
 #include "gc/Zone.h"
 #include "jit/AtomicOperations.h"
 #include "js/Conversions.h"
 #include "js/Value.h"
 #include "vm/JSContext.h"
 #include "vm/NativeObject.h"
 
 #include "gc/ObjectKind-inl.h"
+#include "vm/ObjectOperations-inl.h"
 
 namespace js {
 
 template<typename To, typename From>
 inline To
 ConvertNumber(From src);
 
 template<>