author | Jeff 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 id | 34658 |
push user | rgurzau@mozilla.com |
push date | Mon, 17 Sep 2018 16:46:41 +0000 |
treeherder | mozilla-central@5ecae696c54f [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | jandem |
bugs | 1491736 |
milestone | 64.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
|
--- 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<>