/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- * vim: set ts=8 sts=2 et sw=2 tw=80: * 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/. */ #include "js/PropertyAndElement.h" #include "mozilla/Assertions.h" // MOZ_ASSERT #include // size_t #include // uint32_t #include "jsfriendapi.h" // js::GetPropertyKeys, JSITER_OWNONLY #include "jstypes.h" // JS_PUBLIC_API #include "js/CallArgs.h" // JSNative #include "js/Class.h" // JS::ObjectOpResult #include "js/Context.h" // AssertHeapIsIdle #include "js/GCVector.h" // JS::GCVector, JS::RootedVector #include "js/Id.h" // JS::PropertyKey, jsid #include "js/PropertyDescriptor.h" // JS::PropertyDescriptor, JSPROP_READONLY #include "js/PropertySpec.h" // JSNativeWrapper #include "js/RootingAPI.h" // JS::Rooted, JS::Handle, JS::MutableHandle #include "js/Value.h" // JS::Value, JS::*Value #include "vm/FunctionPrefixKind.h" // js::FunctionPrefixKind #include "vm/GlobalObject.h" // js::GlobalObject #include "vm/JSAtom.h" // JSAtom, js::Atomize, js::AtomizeChars #include "vm/JSContext.h" // JSContext, CHECK_THREAD #include "vm/JSFunction.h" // js::IdToFunctionName, js::DefineFunction #include "vm/JSObject.h" // JSObject, js::DefineFunctions #include "vm/ObjectOperations.h" // js::DefineProperty, js::DefineDataProperty, js::HasOwnProperty #include "vm/PropertyResult.h" // js::PropertyResult #include "vm/StringType.h" // js::PropertyName #include "vm/JSAtom-inl.h" // js::AtomToId, js::IndexToId #include "vm/JSContext-inl.h" // JSContext::check #include "vm/JSObject-inl.h" // js::NewBuiltinClassInstance #include "vm/NativeObject-inl.h" // js::NativeLookupOwnPropertyNoResolve #include "vm/ObjectOperations-inl.h" // js::GetProperty, js::GetElement, js::SetProperty, js::HasProperty, js::DeleteProperty, js::DeleteElement using namespace js; static bool DefinePropertyByDescriptor(JSContext* cx, JS::Handle obj, JS::Handle id, JS::Handle desc, JS::ObjectOpResult& result) { AssertHeapIsIdle(); CHECK_THREAD(cx); cx->check(obj, id, desc); return js::DefineProperty(cx, obj, id, desc, result); } JS_PUBLIC_API bool JS_DefinePropertyById( JSContext* cx, JS::Handle obj, JS::Handle id, JS::Handle desc, JS::ObjectOpResult& result) { return ::DefinePropertyByDescriptor(cx, obj, id, desc, result); } JS_PUBLIC_API bool JS_DefinePropertyById( JSContext* cx, JS::Handle obj, JS::Handle id, JS::Handle desc) { JS::ObjectOpResult result; return ::DefinePropertyByDescriptor(cx, obj, id, desc, result) && result.checkStrict(cx, obj, id); } static bool DefineDataPropertyById(JSContext* cx, JS::Handle obj, JS::Handle id, JS::Handle value, unsigned attrs) { AssertHeapIsIdle(); CHECK_THREAD(cx); cx->check(obj, id, value); return js::DefineDataProperty(cx, obj, id, value, attrs); } JS_PUBLIC_API bool JS_DefinePropertyById(JSContext* cx, JS::Handle obj, JS::Handle id, JS::Handle value, unsigned attrs) { return ::DefineDataPropertyById(cx, obj, id, value, attrs); } static bool DefineAccessorPropertyById(JSContext* cx, JS::Handle obj, JS::Handle id, JS::Handle getter, JS::Handle setter, unsigned attrs) { // JSPROP_READONLY has no meaning when accessors are involved. Ideally we'd // throw if this happens, but we've accepted it for long enough that it's // not worth trying to make callers change their ways. Just flip it off on // its way through the API layer so that we can enforce this internally. attrs &= ~JSPROP_READONLY; AssertHeapIsIdle(); CHECK_THREAD(cx); cx->check(obj, id, getter, setter); return js::DefineAccessorProperty(cx, obj, id, getter, setter, attrs); } static bool DefineAccessorPropertyById(JSContext* cx, JS::Handle obj, JS::Handle id, const JSNativeWrapper& get, const JSNativeWrapper& set, unsigned attrs) { // Getter/setter are both possibly-null JSNatives. Wrap them in JSFunctions. JS::Rooted getter(cx); if (get.op) { JS::Rooted atom(cx, IdToFunctionName(cx, id, FunctionPrefixKind::Get)); if (!atom) { return false; } getter = NewNativeFunction(cx, get.op, 0, atom); if (!getter) { return false; } if (get.info) { getter->setJitInfo(get.info); } } JS::Rooted setter(cx); if (set.op) { JS::Rooted atom(cx, IdToFunctionName(cx, id, FunctionPrefixKind::Set)); if (!atom) { return false; } setter = NewNativeFunction(cx, set.op, 1, atom); if (!setter) { return false; } if (set.info) { setter->setJitInfo(set.info); } } return ::DefineAccessorPropertyById(cx, obj, id, getter, setter, attrs); } /* * Wrapper functions to create wrappers with no corresponding JSJitInfo from API * function arguments. */ static JSNativeWrapper NativeOpWrapper(Native native) { JSNativeWrapper ret; ret.op = native; ret.info = nullptr; return ret; } JS_PUBLIC_API bool JS_DefinePropertyById(JSContext* cx, JS::Handle obj, JS::Handle id, JSNative getter, JSNative setter, unsigned attrs) { return ::DefineAccessorPropertyById(cx, obj, id, ::NativeOpWrapper(getter), ::NativeOpWrapper(setter), attrs); } JS_PUBLIC_API bool JS_DefinePropertyById(JSContext* cx, JS::Handle obj, JS::Handle id, JS::Handle getter, JS::Handle setter, unsigned attrs) { return ::DefineAccessorPropertyById(cx, obj, id, getter, setter, attrs); } JS_PUBLIC_API bool JS_DefinePropertyById(JSContext* cx, JS::Handle obj, JS::Handle id, JS::Handle valueArg, unsigned attrs) { JS::Rooted value(cx, JS::ObjectValue(*valueArg)); return ::DefineDataPropertyById(cx, obj, id, value, attrs); } JS_PUBLIC_API bool JS_DefinePropertyById(JSContext* cx, JS::Handle obj, JS::Handle id, HandleString valueArg, unsigned attrs) { JS::Rooted value(cx, JS::StringValue(valueArg)); return ::DefineDataPropertyById(cx, obj, id, value, attrs); } JS_PUBLIC_API bool JS_DefinePropertyById(JSContext* cx, JS::Handle obj, JS::Handle id, int32_t valueArg, unsigned attrs) { JS::Value value = JS::Int32Value(valueArg); return ::DefineDataPropertyById( cx, obj, id, JS::Handle::fromMarkedLocation(&value), attrs); } JS_PUBLIC_API bool JS_DefinePropertyById(JSContext* cx, JS::Handle obj, JS::Handle id, uint32_t valueArg, unsigned attrs) { JS::Value value = JS::NumberValue(valueArg); return ::DefineDataPropertyById( cx, obj, id, JS::Handle::fromMarkedLocation(&value), attrs); } JS_PUBLIC_API bool JS_DefinePropertyById(JSContext* cx, JS::Handle obj, JS::Handle id, double valueArg, unsigned attrs) { JS::Value value = JS::NumberValue(valueArg); return ::DefineDataPropertyById( cx, obj, id, JS::Handle::fromMarkedLocation(&value), attrs); } static bool DefineDataProperty(JSContext* cx, JS::Handle obj, const char* name, JS::Handle value, unsigned attrs) { JSAtom* atom = Atomize(cx, name, strlen(name)); if (!atom) { return false; } JS::Rooted id(cx, AtomToId(atom)); return ::DefineDataPropertyById(cx, obj, id, value, attrs); } JS_PUBLIC_API bool JS_DefineProperty(JSContext* cx, JS::Handle obj, const char* name, JS::Handle value, unsigned attrs) { return ::DefineDataProperty(cx, obj, name, value, attrs); } JS_PUBLIC_API bool JS_DefineProperty(JSContext* cx, JS::Handle obj, const char* name, JSNative getter, JSNative setter, unsigned attrs) { JSAtom* atom = Atomize(cx, name, strlen(name)); if (!atom) { return false; } JS::Rooted id(cx, AtomToId(atom)); return ::DefineAccessorPropertyById(cx, obj, id, ::NativeOpWrapper(getter), ::NativeOpWrapper(setter), attrs); } JS_PUBLIC_API bool JS_DefineProperty(JSContext* cx, JS::Handle obj, const char* name, JS::Handle getter, JS::Handle setter, unsigned attrs) { JSAtom* atom = Atomize(cx, name, strlen(name)); if (!atom) { return false; } JS::Rooted id(cx, AtomToId(atom)); return ::DefineAccessorPropertyById(cx, obj, id, getter, setter, attrs); } JS_PUBLIC_API bool JS_DefineProperty(JSContext* cx, JS::Handle obj, const char* name, JS::Handle valueArg, unsigned attrs) { JS::Rooted value(cx, JS::ObjectValue(*valueArg)); return ::DefineDataProperty(cx, obj, name, value, attrs); } JS_PUBLIC_API bool JS_DefineProperty(JSContext* cx, JS::Handle obj, const char* name, HandleString valueArg, unsigned attrs) { JS::Rooted value(cx, JS::StringValue(valueArg)); return ::DefineDataProperty(cx, obj, name, value, attrs); } JS_PUBLIC_API bool JS_DefineProperty(JSContext* cx, JS::Handle obj, const char* name, int32_t valueArg, unsigned attrs) { JS::Value value = JS::Int32Value(valueArg); return ::DefineDataProperty( cx, obj, name, JS::Handle::fromMarkedLocation(&value), attrs); } JS_PUBLIC_API bool JS_DefineProperty(JSContext* cx, JS::Handle obj, const char* name, uint32_t valueArg, unsigned attrs) { JS::Value value = JS::NumberValue(valueArg); return ::DefineDataProperty( cx, obj, name, JS::Handle::fromMarkedLocation(&value), attrs); } JS_PUBLIC_API bool JS_DefineProperty(JSContext* cx, JS::Handle obj, const char* name, double valueArg, unsigned attrs) { JS::Value value = JS::NumberValue(valueArg); return ::DefineDataProperty( cx, obj, name, JS::Handle::fromMarkedLocation(&value), attrs); } #define AUTO_NAMELEN(s, n) (((n) == (size_t)-1) ? js_strlen(s) : (n)) JS_PUBLIC_API bool JS_DefineUCProperty(JSContext* cx, JS::Handle obj, const char16_t* name, size_t namelen, JS::Handle desc, JS::ObjectOpResult& result) { JSAtom* atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen)); if (!atom) { return false; } JS::Rooted id(cx, AtomToId(atom)); return ::DefinePropertyByDescriptor(cx, obj, id, desc, result); } JS_PUBLIC_API bool JS_DefineUCProperty( JSContext* cx, JS::Handle obj, const char16_t* name, size_t namelen, JS::Handle desc) { JSAtom* atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen)); if (!atom) { return false; } JS::Rooted id(cx, AtomToId(atom)); JS::ObjectOpResult result; return ::DefinePropertyByDescriptor(cx, obj, id, desc, result) && result.checkStrict(cx, obj, id); } static bool DefineUCDataProperty(JSContext* cx, JS::Handle obj, const char16_t* name, size_t namelen, JS::Handle value, unsigned attrs) { JSAtom* atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen)); if (!atom) { return false; } JS::Rooted id(cx, AtomToId(atom)); return ::DefineDataPropertyById(cx, obj, id, value, attrs); } JS_PUBLIC_API bool JS_DefineUCProperty(JSContext* cx, JS::Handle obj, const char16_t* name, size_t namelen, JS::Handle value, unsigned attrs) { return ::DefineUCDataProperty(cx, obj, name, namelen, value, attrs); } JS_PUBLIC_API bool JS_DefineUCProperty(JSContext* cx, JS::Handle obj, const char16_t* name, size_t namelen, JS::Handle getter, JS::Handle setter, unsigned attrs) { JSAtom* atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen)); if (!atom) { return false; } JS::Rooted id(cx, AtomToId(atom)); return ::DefineAccessorPropertyById(cx, obj, id, getter, setter, attrs); } JS_PUBLIC_API bool JS_DefineUCProperty(JSContext* cx, JS::Handle obj, const char16_t* name, size_t namelen, JS::Handle valueArg, unsigned attrs) { JS::Rooted value(cx, JS::ObjectValue(*valueArg)); return ::DefineUCDataProperty(cx, obj, name, namelen, value, attrs); } JS_PUBLIC_API bool JS_DefineUCProperty(JSContext* cx, JS::Handle obj, const char16_t* name, size_t namelen, HandleString valueArg, unsigned attrs) { JS::Rooted value(cx, JS::StringValue(valueArg)); return ::DefineUCDataProperty(cx, obj, name, namelen, value, attrs); } JS_PUBLIC_API bool JS_DefineUCProperty(JSContext* cx, JS::Handle obj, const char16_t* name, size_t namelen, int32_t valueArg, unsigned attrs) { JS::Value value = JS::Int32Value(valueArg); return ::DefineUCDataProperty( cx, obj, name, namelen, JS::Handle::fromMarkedLocation(&value), attrs); } JS_PUBLIC_API bool JS_DefineUCProperty(JSContext* cx, JS::Handle obj, const char16_t* name, size_t namelen, uint32_t valueArg, unsigned attrs) { JS::Value value = JS::NumberValue(valueArg); return ::DefineUCDataProperty( cx, obj, name, namelen, JS::Handle::fromMarkedLocation(&value), attrs); } JS_PUBLIC_API bool JS_DefineUCProperty(JSContext* cx, JS::Handle obj, const char16_t* name, size_t namelen, double valueArg, unsigned attrs) { JS::Value value = JS::NumberValue(valueArg); return ::DefineUCDataProperty( cx, obj, name, namelen, JS::Handle::fromMarkedLocation(&value), attrs); } extern bool PropertySpecNameToId(JSContext* cx, JSPropertySpec::Name name, MutableHandleId id); static bool DefineSelfHostedProperty(JSContext* cx, JS::Handle obj, JS::Handle id, const char* getterName, const char* setterName, unsigned attrs) { JSAtom* getterNameAtom = Atomize(cx, getterName, strlen(getterName)); if (!getterNameAtom) { return false; } JS::Rooted getterNameName(cx, getterNameAtom->asPropertyName()); JS::Rooted name(cx, IdToFunctionName(cx, id)); if (!name) { return false; } JS::Rooted getterValue(cx); if (!GlobalObject::getSelfHostedFunction(cx, cx->global(), getterNameName, name, 0, &getterValue)) { return false; } MOZ_ASSERT(getterValue.isObject() && getterValue.toObject().is()); JS::Rooted getterFunc(cx, &getterValue.toObject().as()); JS::Rooted setterFunc(cx); if (setterName) { JSAtom* setterNameAtom = Atomize(cx, setterName, strlen(setterName)); if (!setterNameAtom) { return false; } JS::Rooted setterNameName(cx, setterNameAtom->asPropertyName()); JS::Rooted setterValue(cx); if (!GlobalObject::getSelfHostedFunction(cx, cx->global(), setterNameName, name, 1, &setterValue)) { return false; } MOZ_ASSERT(setterValue.isObject() && setterValue.toObject().is()); setterFunc = &setterValue.toObject().as(); } return ::DefineAccessorPropertyById(cx, obj, id, getterFunc, setterFunc, attrs); } static bool DefineDataElement(JSContext* cx, JS::Handle obj, uint32_t index, JS::Handle value, unsigned attrs) { cx->check(obj, value); AssertHeapIsIdle(); CHECK_THREAD(cx); JS::Rooted id(cx); if (!IndexToId(cx, index, &id)) { return false; } return ::DefineDataPropertyById(cx, obj, id, value, attrs); } JS_PUBLIC_API bool JS_DefineElement(JSContext* cx, JS::Handle obj, uint32_t index, JS::Handle value, unsigned attrs) { return ::DefineDataElement(cx, obj, index, value, attrs); } JS_PUBLIC_API bool JS_DefineElement(JSContext* cx, JS::Handle obj, uint32_t index, JS::Handle getter, JS::Handle setter, unsigned attrs) { JS::Rooted id(cx); if (!IndexToId(cx, index, &id)) { return false; } return ::DefineAccessorPropertyById(cx, obj, id, getter, setter, attrs); } JS_PUBLIC_API bool JS_DefineElement(JSContext* cx, JS::Handle obj, uint32_t index, JS::Handle valueArg, unsigned attrs) { JS::Rooted value(cx, JS::ObjectValue(*valueArg)); return ::DefineDataElement(cx, obj, index, value, attrs); } JS_PUBLIC_API bool JS_DefineElement(JSContext* cx, JS::Handle obj, uint32_t index, HandleString valueArg, unsigned attrs) { JS::Rooted value(cx, JS::StringValue(valueArg)); return ::DefineDataElement(cx, obj, index, value, attrs); } JS_PUBLIC_API bool JS_DefineElement(JSContext* cx, JS::Handle obj, uint32_t index, int32_t valueArg, unsigned attrs) { JS::Value value = JS::Int32Value(valueArg); return ::DefineDataElement( cx, obj, index, JS::Handle::fromMarkedLocation(&value), attrs); } JS_PUBLIC_API bool JS_DefineElement(JSContext* cx, JS::Handle obj, uint32_t index, uint32_t valueArg, unsigned attrs) { JS::Value value = JS::NumberValue(valueArg); return ::DefineDataElement( cx, obj, index, JS::Handle::fromMarkedLocation(&value), attrs); } JS_PUBLIC_API bool JS_DefineElement(JSContext* cx, JS::Handle obj, uint32_t index, double valueArg, unsigned attrs) { JS::Value value = JS::NumberValue(valueArg); return ::DefineDataElement( cx, obj, index, JS::Handle::fromMarkedLocation(&value), attrs); } JS_PUBLIC_API bool JS_HasPropertyById(JSContext* cx, JS::Handle obj, JS::Handle id, bool* foundp) { AssertHeapIsIdle(); CHECK_THREAD(cx); cx->check(obj, id); return js::HasProperty(cx, obj, id, foundp); } JS_PUBLIC_API bool JS_HasProperty(JSContext* cx, JS::Handle obj, const char* name, bool* foundp) { JSAtom* atom = Atomize(cx, name, strlen(name)); if (!atom) { return false; } JS::Rooted id(cx, AtomToId(atom)); return JS_HasPropertyById(cx, obj, id, foundp); } JS_PUBLIC_API bool JS_HasUCProperty(JSContext* cx, JS::Handle obj, const char16_t* name, size_t namelen, bool* foundp) { JSAtom* atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen)); if (!atom) { return false; } JS::Rooted id(cx, AtomToId(atom)); return JS_HasPropertyById(cx, obj, id, foundp); } JS_PUBLIC_API bool JS_HasElement(JSContext* cx, JS::Handle obj, uint32_t index, bool* foundp) { AssertHeapIsIdle(); CHECK_THREAD(cx); JS::Rooted id(cx); if (!IndexToId(cx, index, &id)) { return false; } return JS_HasPropertyById(cx, obj, id, foundp); } JS_PUBLIC_API bool JS_HasOwnPropertyById(JSContext* cx, JS::Handle obj, JS::Handle id, bool* foundp) { AssertHeapIsIdle(); CHECK_THREAD(cx); cx->check(obj, id); return js::HasOwnProperty(cx, obj, id, foundp); } JS_PUBLIC_API bool JS_HasOwnProperty(JSContext* cx, JS::Handle obj, const char* name, bool* foundp) { JSAtom* atom = Atomize(cx, name, strlen(name)); if (!atom) { return false; } JS::Rooted id(cx, AtomToId(atom)); return JS_HasOwnPropertyById(cx, obj, id, foundp); } JS_PUBLIC_API bool JS_ForwardGetPropertyTo(JSContext* cx, JS::Handle obj, JS::Handle id, JS::Handle receiver, JS::MutableHandle vp) { AssertHeapIsIdle(); CHECK_THREAD(cx); cx->check(obj, id, receiver); return js::GetProperty(cx, obj, receiver, id, vp); } JS_PUBLIC_API bool JS_ForwardGetElementTo(JSContext* cx, JS::Handle obj, uint32_t index, JS::Handle receiver, JS::MutableHandle vp) { AssertHeapIsIdle(); CHECK_THREAD(cx); cx->check(obj); return js::GetElement(cx, obj, receiver, index, vp); } JS_PUBLIC_API bool JS_GetPropertyById(JSContext* cx, JS::Handle obj, JS::Handle id, JS::MutableHandle vp) { JS::Rooted receiver(cx, JS::ObjectValue(*obj)); return JS_ForwardGetPropertyTo(cx, obj, id, receiver, vp); } JS_PUBLIC_API bool JS_GetProperty(JSContext* cx, JS::Handle obj, const char* name, JS::MutableHandle vp) { JSAtom* atom = Atomize(cx, name, strlen(name)); if (!atom) { return false; } JS::Rooted id(cx, AtomToId(atom)); return JS_GetPropertyById(cx, obj, id, vp); } JS_PUBLIC_API bool JS_GetUCProperty(JSContext* cx, JS::Handle obj, const char16_t* name, size_t namelen, JS::MutableHandle vp) { JSAtom* atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen)); if (!atom) { return false; } JS::Rooted id(cx, AtomToId(atom)); return JS_GetPropertyById(cx, obj, id, vp); } JS_PUBLIC_API bool JS_GetElement(JSContext* cx, JS::Handle objArg, uint32_t index, JS::MutableHandle vp) { return JS_ForwardGetElementTo(cx, objArg, index, objArg, vp); } JS_PUBLIC_API bool JS_ForwardSetPropertyTo(JSContext* cx, JS::Handle obj, JS::Handle id, JS::Handle v, JS::Handle receiver, JS::ObjectOpResult& result) { AssertHeapIsIdle(); CHECK_THREAD(cx); cx->check(obj, id, v, receiver); return js::SetProperty(cx, obj, id, v, receiver, result); } JS_PUBLIC_API bool JS_SetPropertyById(JSContext* cx, JS::Handle obj, JS::Handle id, JS::Handle v) { AssertHeapIsIdle(); CHECK_THREAD(cx); cx->check(obj, id, v); JS::Rooted receiver(cx, JS::ObjectValue(*obj)); JS::ObjectOpResult ignored; return js::SetProperty(cx, obj, id, v, receiver, ignored); } JS_PUBLIC_API bool JS_SetProperty(JSContext* cx, JS::Handle obj, const char* name, JS::Handle v) { JSAtom* atom = Atomize(cx, name, strlen(name)); if (!atom) { return false; } JS::Rooted id(cx, AtomToId(atom)); return JS_SetPropertyById(cx, obj, id, v); } JS_PUBLIC_API bool JS_SetUCProperty(JSContext* cx, JS::Handle obj, const char16_t* name, size_t namelen, JS::Handle v) { JSAtom* atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen)); if (!atom) { return false; } JS::Rooted id(cx, AtomToId(atom)); return JS_SetPropertyById(cx, obj, id, v); } static bool SetElement(JSContext* cx, JS::Handle obj, uint32_t index, JS::Handle v) { AssertHeapIsIdle(); CHECK_THREAD(cx); cx->check(obj, v); JS::Rooted receiver(cx, JS::ObjectValue(*obj)); JS::ObjectOpResult ignored; return js::SetElement(cx, obj, index, v, receiver, ignored); } JS_PUBLIC_API bool JS_SetElement(JSContext* cx, JS::Handle obj, uint32_t index, JS::Handle v) { return ::SetElement(cx, obj, index, v); } JS_PUBLIC_API bool JS_SetElement(JSContext* cx, JS::Handle obj, uint32_t index, JS::Handle v) { JS::Rooted value(cx, JS::ObjectOrNullValue(v)); return ::SetElement(cx, obj, index, value); } JS_PUBLIC_API bool JS_SetElement(JSContext* cx, JS::Handle obj, uint32_t index, HandleString v) { JS::Rooted value(cx, JS::StringValue(v)); return ::SetElement(cx, obj, index, value); } JS_PUBLIC_API bool JS_SetElement(JSContext* cx, JS::Handle obj, uint32_t index, int32_t v) { JS::Rooted value(cx, JS::NumberValue(v)); return ::SetElement(cx, obj, index, value); } JS_PUBLIC_API bool JS_SetElement(JSContext* cx, JS::Handle obj, uint32_t index, uint32_t v) { JS::Rooted value(cx, JS::NumberValue(v)); return ::SetElement(cx, obj, index, value); } JS_PUBLIC_API bool JS_SetElement(JSContext* cx, JS::Handle obj, uint32_t index, double v) { JS::Rooted value(cx, JS::NumberValue(v)); return ::SetElement(cx, obj, index, value); } JS_PUBLIC_API bool JS_DeletePropertyById(JSContext* cx, JS::Handle obj, JS::Handle id, JS::ObjectOpResult& result) { AssertHeapIsIdle(); CHECK_THREAD(cx); cx->check(obj, id); return js::DeleteProperty(cx, obj, id, result); } JS_PUBLIC_API bool JS_DeleteProperty(JSContext* cx, JS::Handle obj, const char* name, JS::ObjectOpResult& result) { CHECK_THREAD(cx); cx->check(obj); JSAtom* atom = Atomize(cx, name, strlen(name)); if (!atom) { return false; } JS::Rooted id(cx, AtomToId(atom)); return js::DeleteProperty(cx, obj, id, result); } JS_PUBLIC_API bool JS_DeleteUCProperty(JSContext* cx, JS::Handle obj, const char16_t* name, size_t namelen, JS::ObjectOpResult& result) { CHECK_THREAD(cx); cx->check(obj); JSAtom* atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen)); if (!atom) { return false; } JS::Rooted id(cx, AtomToId(atom)); return js::DeleteProperty(cx, obj, id, result); } JS_PUBLIC_API bool JS_DeleteElement(JSContext* cx, JS::Handle obj, uint32_t index, JS::ObjectOpResult& result) { AssertHeapIsIdle(); CHECK_THREAD(cx); cx->check(obj); return js::DeleteElement(cx, obj, index, result); } JS_PUBLIC_API bool JS_DeletePropertyById(JSContext* cx, JS::Handle obj, JS::Handle id) { JS::ObjectOpResult ignored; return JS_DeletePropertyById(cx, obj, id, ignored); } JS_PUBLIC_API bool JS_DeleteProperty(JSContext* cx, JS::Handle obj, const char* name) { JS::ObjectOpResult ignored; return JS_DeleteProperty(cx, obj, name, ignored); } JS_PUBLIC_API bool JS_DeleteElement(JSContext* cx, JS::Handle obj, uint32_t index) { JS::ObjectOpResult ignored; return JS_DeleteElement(cx, obj, index, ignored); } JS_PUBLIC_API bool JS_Enumerate(JSContext* cx, JS::Handle obj, JS::MutableHandle props) { AssertHeapIsIdle(); CHECK_THREAD(cx); cx->check(obj, props); MOZ_ASSERT(props.empty()); JS::RootedVector ids(cx); if (!js::GetPropertyKeys(cx, obj, JSITER_OWNONLY, &ids)) { return false; } return props.append(ids.begin(), ids.end()); } JS_PUBLIC_API JSObject* JS_DefineObject(JSContext* cx, JS::Handle obj, const char* name, const JSClass* clasp, unsigned attrs) { AssertHeapIsIdle(); CHECK_THREAD(cx); cx->check(obj); JS::Rooted nobj(cx); if (!clasp) { // Default class is Object. nobj = NewPlainObject(cx); } else { nobj = NewBuiltinClassInstance(cx, clasp); } if (!nobj) { return nullptr; } JS::Rooted nobjValue(cx, JS::ObjectValue(*nobj)); if (!::DefineDataProperty(cx, obj, name, nobjValue, attrs)) { return nullptr; } return nobj; } JS_PUBLIC_API bool JS_DefineProperties(JSContext* cx, JS::Handle obj, const JSPropertySpec* ps) { JS::Rooted id(cx); for (; ps->name; ps++) { if (!PropertySpecNameToId(cx, ps->name, &id)) { return false; } if (ps->isAccessor()) { if (ps->isSelfHosted()) { if (!::DefineSelfHostedProperty( cx, obj, id, ps->u.accessors.getter.selfHosted.funname, ps->u.accessors.setter.selfHosted.funname, ps->attributes())) { return false; } } else { if (!::DefineAccessorPropertyById( cx, obj, id, ps->u.accessors.getter.native, ps->u.accessors.setter.native, ps->attributes())) { return false; } } } else { JS::Rooted v(cx); if (!ps->getValue(cx, &v)) { return false; } if (!::DefineDataPropertyById(cx, obj, id, v, ps->attributes())) { return false; } } } return true; } JS_PUBLIC_API bool JS_AlreadyHasOwnPropertyById(JSContext* cx, JS::Handle obj, JS::Handle id, bool* foundp) { AssertHeapIsIdle(); CHECK_THREAD(cx); cx->check(obj, id); if (!obj->is()) { return js::HasOwnProperty(cx, obj, id, foundp); } PropertyResult prop; if (!NativeLookupOwnPropertyNoResolve(cx, &obj->as(), id, &prop)) { return false; } *foundp = prop.isFound(); return true; } JS_PUBLIC_API bool JS_AlreadyHasOwnProperty(JSContext* cx, JS::Handle obj, const char* name, bool* foundp) { JSAtom* atom = Atomize(cx, name, strlen(name)); if (!atom) { return false; } JS::Rooted id(cx, AtomToId(atom)); return JS_AlreadyHasOwnPropertyById(cx, obj, id, foundp); } JS_PUBLIC_API bool JS_AlreadyHasOwnUCProperty(JSContext* cx, JS::Handle obj, const char16_t* name, size_t namelen, bool* foundp) { JSAtom* atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen)); if (!atom) { return false; } JS::Rooted id(cx, AtomToId(atom)); return JS_AlreadyHasOwnPropertyById(cx, obj, id, foundp); } JS_PUBLIC_API bool JS_AlreadyHasOwnElement(JSContext* cx, JS::Handle obj, uint32_t index, bool* foundp) { AssertHeapIsIdle(); CHECK_THREAD(cx); JS::Rooted id(cx); if (!IndexToId(cx, index, &id)) { return false; } return JS_AlreadyHasOwnPropertyById(cx, obj, id, foundp); } JS_PUBLIC_API bool JS_DefineFunctions(JSContext* cx, JS::Handle obj, const JSFunctionSpec* fs) { MOZ_ASSERT(!cx->zone()->isAtomsZone()); AssertHeapIsIdle(); CHECK_THREAD(cx); cx->check(obj); return js::DefineFunctions(cx, obj, fs); } JS_PUBLIC_API JSFunction* JS_DefineFunction(JSContext* cx, JS::Handle obj, const char* name, JSNative call, unsigned nargs, unsigned attrs) { MOZ_ASSERT(!cx->zone()->isAtomsZone()); AssertHeapIsIdle(); CHECK_THREAD(cx); cx->check(obj); JSAtom* atom = Atomize(cx, name, strlen(name)); if (!atom) { return nullptr; } Rooted id(cx, AtomToId(atom)); return js::DefineFunction(cx, obj, id, call, nargs, attrs); } JS_PUBLIC_API JSFunction* JS_DefineUCFunction(JSContext* cx, JS::Handle obj, const char16_t* name, size_t namelen, JSNative call, unsigned nargs, unsigned attrs) { MOZ_ASSERT(!cx->zone()->isAtomsZone()); AssertHeapIsIdle(); CHECK_THREAD(cx); cx->check(obj); JSAtom* atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen)); if (!atom) { return nullptr; } Rooted id(cx, AtomToId(atom)); return js::DefineFunction(cx, obj, id, call, nargs, attrs); } JS_PUBLIC_API JSFunction* JS_DefineFunctionById(JSContext* cx, JS::Handle obj, JS::Handle id, JSNative call, unsigned nargs, unsigned attrs) { MOZ_ASSERT(!cx->zone()->isAtomsZone()); AssertHeapIsIdle(); CHECK_THREAD(cx); cx->check(obj, id); return js::DefineFunction(cx, obj, id, call, nargs, attrs); }