summaryrefslogtreecommitdiffstats
path: root/js/src/vm/PropertyAndElement.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--js/src/vm/PropertyAndElement.cpp995
1 files changed, 995 insertions, 0 deletions
diff --git a/js/src/vm/PropertyAndElement.cpp b/js/src/vm/PropertyAndElement.cpp
new file mode 100644
index 0000000000..05adbd44a6
--- /dev/null
+++ b/js/src/vm/PropertyAndElement.cpp
@@ -0,0 +1,995 @@
+/* -*- 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 <stddef.h> // size_t
+#include <stdint.h> // 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<JSObject*> obj,
+ JS::Handle<jsid> id,
+ JS::Handle<JS::PropertyDescriptor> 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<JSObject*> obj, JS::Handle<jsid> id,
+ JS::Handle<JS::PropertyDescriptor> desc, JS::ObjectOpResult& result) {
+ return ::DefinePropertyByDescriptor(cx, obj, id, desc, result);
+}
+
+JS_PUBLIC_API bool JS_DefinePropertyById(
+ JSContext* cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
+ JS::Handle<JS::PropertyDescriptor> desc) {
+ JS::ObjectOpResult result;
+ return ::DefinePropertyByDescriptor(cx, obj, id, desc, result) &&
+ result.checkStrict(cx, obj, id);
+}
+
+static bool DefineDataPropertyById(JSContext* cx, JS::Handle<JSObject*> obj,
+ JS::Handle<jsid> id,
+ JS::Handle<JS::Value> 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<JSObject*> obj,
+ JS::Handle<jsid> id,
+ JS::Handle<JS::Value> value,
+ unsigned attrs) {
+ return ::DefineDataPropertyById(cx, obj, id, value, attrs);
+}
+
+static bool DefineAccessorPropertyById(JSContext* cx, JS::Handle<JSObject*> obj,
+ JS::Handle<jsid> id,
+ JS::Handle<JSObject*> getter,
+ JS::Handle<JSObject*> 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<JSObject*> obj,
+ JS::Handle<jsid> id,
+ const JSNativeWrapper& get,
+ const JSNativeWrapper& set,
+ unsigned attrs) {
+ // Getter/setter are both possibly-null JSNatives. Wrap them in JSFunctions.
+
+ JS::Rooted<JSFunction*> getter(cx);
+ if (get.op) {
+ JS::Rooted<JSAtom*> 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<JSFunction*> setter(cx);
+ if (set.op) {
+ JS::Rooted<JSAtom*> 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<JSObject*> obj,
+ JS::Handle<jsid> 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<JSObject*> obj,
+ JS::Handle<jsid> id,
+ JS::Handle<JSObject*> getter,
+ JS::Handle<JSObject*> setter,
+ unsigned attrs) {
+ return ::DefineAccessorPropertyById(cx, obj, id, getter, setter, attrs);
+}
+
+JS_PUBLIC_API bool JS_DefinePropertyById(JSContext* cx,
+ JS::Handle<JSObject*> obj,
+ JS::Handle<jsid> id,
+ JS::Handle<JSObject*> valueArg,
+ unsigned attrs) {
+ JS::Rooted<JS::Value> value(cx, JS::ObjectValue(*valueArg));
+ return ::DefineDataPropertyById(cx, obj, id, value, attrs);
+}
+
+JS_PUBLIC_API bool JS_DefinePropertyById(JSContext* cx,
+ JS::Handle<JSObject*> obj,
+ JS::Handle<jsid> id,
+ HandleString valueArg,
+ unsigned attrs) {
+ JS::Rooted<JS::Value> value(cx, JS::StringValue(valueArg));
+ return ::DefineDataPropertyById(cx, obj, id, value, attrs);
+}
+
+JS_PUBLIC_API bool JS_DefinePropertyById(JSContext* cx,
+ JS::Handle<JSObject*> obj,
+ JS::Handle<jsid> id, int32_t valueArg,
+ unsigned attrs) {
+ JS::Value value = JS::Int32Value(valueArg);
+ return ::DefineDataPropertyById(
+ cx, obj, id, JS::Handle<JS::Value>::fromMarkedLocation(&value), attrs);
+}
+
+JS_PUBLIC_API bool JS_DefinePropertyById(JSContext* cx,
+ JS::Handle<JSObject*> obj,
+ JS::Handle<jsid> id, uint32_t valueArg,
+ unsigned attrs) {
+ JS::Value value = JS::NumberValue(valueArg);
+ return ::DefineDataPropertyById(
+ cx, obj, id, JS::Handle<JS::Value>::fromMarkedLocation(&value), attrs);
+}
+
+JS_PUBLIC_API bool JS_DefinePropertyById(JSContext* cx,
+ JS::Handle<JSObject*> obj,
+ JS::Handle<jsid> id, double valueArg,
+ unsigned attrs) {
+ JS::Value value = JS::NumberValue(valueArg);
+ return ::DefineDataPropertyById(
+ cx, obj, id, JS::Handle<JS::Value>::fromMarkedLocation(&value), attrs);
+}
+
+static bool DefineDataProperty(JSContext* cx, JS::Handle<JSObject*> obj,
+ const char* name, JS::Handle<JS::Value> value,
+ unsigned attrs) {
+ JSAtom* atom = Atomize(cx, name, strlen(name));
+ if (!atom) {
+ return false;
+ }
+ JS::Rooted<jsid> id(cx, AtomToId(atom));
+
+ return ::DefineDataPropertyById(cx, obj, id, value, attrs);
+}
+
+JS_PUBLIC_API bool JS_DefineProperty(JSContext* cx, JS::Handle<JSObject*> obj,
+ const char* name,
+ JS::Handle<JS::Value> value,
+ unsigned attrs) {
+ return ::DefineDataProperty(cx, obj, name, value, attrs);
+}
+
+JS_PUBLIC_API bool JS_DefineProperty(JSContext* cx, JS::Handle<JSObject*> obj,
+ const char* name, JSNative getter,
+ JSNative setter, unsigned attrs) {
+ JSAtom* atom = Atomize(cx, name, strlen(name));
+ if (!atom) {
+ return false;
+ }
+ JS::Rooted<jsid> id(cx, AtomToId(atom));
+ return ::DefineAccessorPropertyById(cx, obj, id, ::NativeOpWrapper(getter),
+ ::NativeOpWrapper(setter), attrs);
+}
+
+JS_PUBLIC_API bool JS_DefineProperty(JSContext* cx, JS::Handle<JSObject*> obj,
+ const char* name,
+ JS::Handle<JSObject*> getter,
+ JS::Handle<JSObject*> setter,
+ unsigned attrs) {
+ JSAtom* atom = Atomize(cx, name, strlen(name));
+ if (!atom) {
+ return false;
+ }
+ JS::Rooted<jsid> id(cx, AtomToId(atom));
+
+ return ::DefineAccessorPropertyById(cx, obj, id, getter, setter, attrs);
+}
+
+JS_PUBLIC_API bool JS_DefineProperty(JSContext* cx, JS::Handle<JSObject*> obj,
+ const char* name,
+ JS::Handle<JSObject*> valueArg,
+ unsigned attrs) {
+ JS::Rooted<JS::Value> value(cx, JS::ObjectValue(*valueArg));
+ return ::DefineDataProperty(cx, obj, name, value, attrs);
+}
+
+JS_PUBLIC_API bool JS_DefineProperty(JSContext* cx, JS::Handle<JSObject*> obj,
+ const char* name, HandleString valueArg,
+ unsigned attrs) {
+ JS::Rooted<JS::Value> value(cx, JS::StringValue(valueArg));
+ return ::DefineDataProperty(cx, obj, name, value, attrs);
+}
+
+JS_PUBLIC_API bool JS_DefineProperty(JSContext* cx, JS::Handle<JSObject*> obj,
+ const char* name, int32_t valueArg,
+ unsigned attrs) {
+ JS::Value value = JS::Int32Value(valueArg);
+ return ::DefineDataProperty(
+ cx, obj, name, JS::Handle<JS::Value>::fromMarkedLocation(&value), attrs);
+}
+
+JS_PUBLIC_API bool JS_DefineProperty(JSContext* cx, JS::Handle<JSObject*> obj,
+ const char* name, uint32_t valueArg,
+ unsigned attrs) {
+ JS::Value value = JS::NumberValue(valueArg);
+ return ::DefineDataProperty(
+ cx, obj, name, JS::Handle<JS::Value>::fromMarkedLocation(&value), attrs);
+}
+
+JS_PUBLIC_API bool JS_DefineProperty(JSContext* cx, JS::Handle<JSObject*> obj,
+ const char* name, double valueArg,
+ unsigned attrs) {
+ JS::Value value = JS::NumberValue(valueArg);
+ return ::DefineDataProperty(
+ cx, obj, name, JS::Handle<JS::Value>::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<JSObject*> obj,
+ const char16_t* name, size_t namelen,
+ JS::Handle<JS::PropertyDescriptor> desc,
+ JS::ObjectOpResult& result) {
+ JSAtom* atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen));
+ if (!atom) {
+ return false;
+ }
+ JS::Rooted<jsid> id(cx, AtomToId(atom));
+ return ::DefinePropertyByDescriptor(cx, obj, id, desc, result);
+}
+
+JS_PUBLIC_API bool JS_DefineUCProperty(
+ JSContext* cx, JS::Handle<JSObject*> obj, const char16_t* name,
+ size_t namelen, JS::Handle<JS::PropertyDescriptor> desc) {
+ JSAtom* atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen));
+ if (!atom) {
+ return false;
+ }
+ JS::Rooted<jsid> 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<JSObject*> obj,
+ const char16_t* name, size_t namelen,
+ JS::Handle<JS::Value> value, unsigned attrs) {
+ JSAtom* atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen));
+ if (!atom) {
+ return false;
+ }
+ JS::Rooted<jsid> id(cx, AtomToId(atom));
+ return ::DefineDataPropertyById(cx, obj, id, value, attrs);
+}
+
+JS_PUBLIC_API bool JS_DefineUCProperty(JSContext* cx, JS::Handle<JSObject*> obj,
+ const char16_t* name, size_t namelen,
+ JS::Handle<JS::Value> value,
+ unsigned attrs) {
+ return ::DefineUCDataProperty(cx, obj, name, namelen, value, attrs);
+}
+
+JS_PUBLIC_API bool JS_DefineUCProperty(JSContext* cx, JS::Handle<JSObject*> obj,
+ const char16_t* name, size_t namelen,
+ JS::Handle<JSObject*> getter,
+ JS::Handle<JSObject*> setter,
+ unsigned attrs) {
+ JSAtom* atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen));
+ if (!atom) {
+ return false;
+ }
+ JS::Rooted<jsid> id(cx, AtomToId(atom));
+ return ::DefineAccessorPropertyById(cx, obj, id, getter, setter, attrs);
+}
+
+JS_PUBLIC_API bool JS_DefineUCProperty(JSContext* cx, JS::Handle<JSObject*> obj,
+ const char16_t* name, size_t namelen,
+ JS::Handle<JSObject*> valueArg,
+ unsigned attrs) {
+ JS::Rooted<JS::Value> value(cx, JS::ObjectValue(*valueArg));
+ return ::DefineUCDataProperty(cx, obj, name, namelen, value, attrs);
+}
+
+JS_PUBLIC_API bool JS_DefineUCProperty(JSContext* cx, JS::Handle<JSObject*> obj,
+ const char16_t* name, size_t namelen,
+ HandleString valueArg, unsigned attrs) {
+ JS::Rooted<JS::Value> value(cx, JS::StringValue(valueArg));
+ return ::DefineUCDataProperty(cx, obj, name, namelen, value, attrs);
+}
+
+JS_PUBLIC_API bool JS_DefineUCProperty(JSContext* cx, JS::Handle<JSObject*> 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<JS::Value>::fromMarkedLocation(&value),
+ attrs);
+}
+
+JS_PUBLIC_API bool JS_DefineUCProperty(JSContext* cx, JS::Handle<JSObject*> 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<JS::Value>::fromMarkedLocation(&value),
+ attrs);
+}
+
+JS_PUBLIC_API bool JS_DefineUCProperty(JSContext* cx, JS::Handle<JSObject*> 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<JS::Value>::fromMarkedLocation(&value),
+ attrs);
+}
+
+extern bool PropertySpecNameToId(JSContext* cx, JSPropertySpec::Name name,
+ MutableHandleId id);
+
+static bool DefineSelfHostedProperty(JSContext* cx, JS::Handle<JSObject*> obj,
+ JS::Handle<jsid> id,
+ const char* getterName,
+ const char* setterName, unsigned attrs) {
+ JSAtom* getterNameAtom = Atomize(cx, getterName, strlen(getterName));
+ if (!getterNameAtom) {
+ return false;
+ }
+ JS::Rooted<PropertyName*> getterNameName(cx,
+ getterNameAtom->asPropertyName());
+
+ JS::Rooted<JSAtom*> name(cx, IdToFunctionName(cx, id));
+ if (!name) {
+ return false;
+ }
+
+ JS::Rooted<JS::Value> getterValue(cx);
+ if (!GlobalObject::getSelfHostedFunction(cx, cx->global(), getterNameName,
+ name, 0, &getterValue)) {
+ return false;
+ }
+ MOZ_ASSERT(getterValue.isObject() && getterValue.toObject().is<JSFunction>());
+ JS::Rooted<JSFunction*> getterFunc(cx,
+ &getterValue.toObject().as<JSFunction>());
+
+ JS::Rooted<JSFunction*> setterFunc(cx);
+ if (setterName) {
+ JSAtom* setterNameAtom = Atomize(cx, setterName, strlen(setterName));
+ if (!setterNameAtom) {
+ return false;
+ }
+ JS::Rooted<PropertyName*> setterNameName(cx,
+ setterNameAtom->asPropertyName());
+
+ JS::Rooted<JS::Value> setterValue(cx);
+ if (!GlobalObject::getSelfHostedFunction(cx, cx->global(), setterNameName,
+ name, 1, &setterValue)) {
+ return false;
+ }
+ MOZ_ASSERT(setterValue.isObject() &&
+ setterValue.toObject().is<JSFunction>());
+ setterFunc = &setterValue.toObject().as<JSFunction>();
+ }
+
+ return ::DefineAccessorPropertyById(cx, obj, id, getterFunc, setterFunc,
+ attrs);
+}
+
+static bool DefineDataElement(JSContext* cx, JS::Handle<JSObject*> obj,
+ uint32_t index, JS::Handle<JS::Value> value,
+ unsigned attrs) {
+ cx->check(obj, value);
+ AssertHeapIsIdle();
+ CHECK_THREAD(cx);
+ JS::Rooted<jsid> 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<JSObject*> obj,
+ uint32_t index, JS::Handle<JS::Value> value,
+ unsigned attrs) {
+ return ::DefineDataElement(cx, obj, index, value, attrs);
+}
+
+JS_PUBLIC_API bool JS_DefineElement(JSContext* cx, JS::Handle<JSObject*> obj,
+ uint32_t index,
+ JS::Handle<JSObject*> getter,
+ JS::Handle<JSObject*> setter,
+ unsigned attrs) {
+ JS::Rooted<jsid> 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<JSObject*> obj,
+ uint32_t index,
+ JS::Handle<JSObject*> valueArg,
+ unsigned attrs) {
+ JS::Rooted<JS::Value> value(cx, JS::ObjectValue(*valueArg));
+ return ::DefineDataElement(cx, obj, index, value, attrs);
+}
+
+JS_PUBLIC_API bool JS_DefineElement(JSContext* cx, JS::Handle<JSObject*> obj,
+ uint32_t index, HandleString valueArg,
+ unsigned attrs) {
+ JS::Rooted<JS::Value> value(cx, JS::StringValue(valueArg));
+ return ::DefineDataElement(cx, obj, index, value, attrs);
+}
+
+JS_PUBLIC_API bool JS_DefineElement(JSContext* cx, JS::Handle<JSObject*> obj,
+ uint32_t index, int32_t valueArg,
+ unsigned attrs) {
+ JS::Value value = JS::Int32Value(valueArg);
+ return ::DefineDataElement(
+ cx, obj, index, JS::Handle<JS::Value>::fromMarkedLocation(&value), attrs);
+}
+
+JS_PUBLIC_API bool JS_DefineElement(JSContext* cx, JS::Handle<JSObject*> obj,
+ uint32_t index, uint32_t valueArg,
+ unsigned attrs) {
+ JS::Value value = JS::NumberValue(valueArg);
+ return ::DefineDataElement(
+ cx, obj, index, JS::Handle<JS::Value>::fromMarkedLocation(&value), attrs);
+}
+
+JS_PUBLIC_API bool JS_DefineElement(JSContext* cx, JS::Handle<JSObject*> obj,
+ uint32_t index, double valueArg,
+ unsigned attrs) {
+ JS::Value value = JS::NumberValue(valueArg);
+ return ::DefineDataElement(
+ cx, obj, index, JS::Handle<JS::Value>::fromMarkedLocation(&value), attrs);
+}
+
+JS_PUBLIC_API bool JS_HasPropertyById(JSContext* cx, JS::Handle<JSObject*> obj,
+ JS::Handle<jsid> 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<JSObject*> obj,
+ const char* name, bool* foundp) {
+ JSAtom* atom = Atomize(cx, name, strlen(name));
+ if (!atom) {
+ return false;
+ }
+ JS::Rooted<jsid> id(cx, AtomToId(atom));
+ return JS_HasPropertyById(cx, obj, id, foundp);
+}
+
+JS_PUBLIC_API bool JS_HasUCProperty(JSContext* cx, JS::Handle<JSObject*> 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<jsid> id(cx, AtomToId(atom));
+ return JS_HasPropertyById(cx, obj, id, foundp);
+}
+
+JS_PUBLIC_API bool JS_HasElement(JSContext* cx, JS::Handle<JSObject*> obj,
+ uint32_t index, bool* foundp) {
+ AssertHeapIsIdle();
+ CHECK_THREAD(cx);
+ JS::Rooted<jsid> 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<JSObject*> obj,
+ JS::Handle<jsid> 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<JSObject*> obj,
+ const char* name, bool* foundp) {
+ JSAtom* atom = Atomize(cx, name, strlen(name));
+ if (!atom) {
+ return false;
+ }
+ JS::Rooted<jsid> id(cx, AtomToId(atom));
+ return JS_HasOwnPropertyById(cx, obj, id, foundp);
+}
+
+JS_PUBLIC_API bool JS_ForwardGetPropertyTo(JSContext* cx,
+ JS::Handle<JSObject*> obj,
+ JS::Handle<jsid> id,
+ JS::Handle<JS::Value> receiver,
+ JS::MutableHandle<JS::Value> 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<JSObject*> obj,
+ uint32_t index,
+ JS::Handle<JSObject*> receiver,
+ JS::MutableHandle<JS::Value> 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<JSObject*> obj,
+ JS::Handle<jsid> id,
+ JS::MutableHandle<JS::Value> vp) {
+ JS::Rooted<JS::Value> receiver(cx, JS::ObjectValue(*obj));
+ return JS_ForwardGetPropertyTo(cx, obj, id, receiver, vp);
+}
+
+JS_PUBLIC_API bool JS_GetProperty(JSContext* cx, JS::Handle<JSObject*> obj,
+ const char* name,
+ JS::MutableHandle<JS::Value> vp) {
+ JSAtom* atom = Atomize(cx, name, strlen(name));
+ if (!atom) {
+ return false;
+ }
+ JS::Rooted<jsid> id(cx, AtomToId(atom));
+ return JS_GetPropertyById(cx, obj, id, vp);
+}
+
+JS_PUBLIC_API bool JS_GetUCProperty(JSContext* cx, JS::Handle<JSObject*> obj,
+ const char16_t* name, size_t namelen,
+ JS::MutableHandle<JS::Value> vp) {
+ JSAtom* atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen));
+ if (!atom) {
+ return false;
+ }
+ JS::Rooted<jsid> id(cx, AtomToId(atom));
+ return JS_GetPropertyById(cx, obj, id, vp);
+}
+
+JS_PUBLIC_API bool JS_GetElement(JSContext* cx, JS::Handle<JSObject*> objArg,
+ uint32_t index,
+ JS::MutableHandle<JS::Value> vp) {
+ return JS_ForwardGetElementTo(cx, objArg, index, objArg, vp);
+}
+
+JS_PUBLIC_API bool JS_ForwardSetPropertyTo(JSContext* cx,
+ JS::Handle<JSObject*> obj,
+ JS::Handle<jsid> id,
+ JS::Handle<JS::Value> v,
+ JS::Handle<JS::Value> 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<JSObject*> obj,
+ JS::Handle<jsid> id,
+ JS::Handle<JS::Value> v) {
+ AssertHeapIsIdle();
+ CHECK_THREAD(cx);
+ cx->check(obj, id, v);
+
+ JS::Rooted<JS::Value> 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<JSObject*> obj,
+ const char* name, JS::Handle<JS::Value> v) {
+ JSAtom* atom = Atomize(cx, name, strlen(name));
+ if (!atom) {
+ return false;
+ }
+ JS::Rooted<jsid> id(cx, AtomToId(atom));
+ return JS_SetPropertyById(cx, obj, id, v);
+}
+
+JS_PUBLIC_API bool JS_SetUCProperty(JSContext* cx, JS::Handle<JSObject*> obj,
+ const char16_t* name, size_t namelen,
+ JS::Handle<JS::Value> v) {
+ JSAtom* atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen));
+ if (!atom) {
+ return false;
+ }
+ JS::Rooted<jsid> id(cx, AtomToId(atom));
+ return JS_SetPropertyById(cx, obj, id, v);
+}
+
+static bool SetElement(JSContext* cx, JS::Handle<JSObject*> obj, uint32_t index,
+ JS::Handle<JS::Value> v) {
+ AssertHeapIsIdle();
+ CHECK_THREAD(cx);
+ cx->check(obj, v);
+
+ JS::Rooted<JS::Value> 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<JSObject*> obj,
+ uint32_t index, JS::Handle<JS::Value> v) {
+ return ::SetElement(cx, obj, index, v);
+}
+
+JS_PUBLIC_API bool JS_SetElement(JSContext* cx, JS::Handle<JSObject*> obj,
+ uint32_t index, JS::Handle<JSObject*> v) {
+ JS::Rooted<JS::Value> value(cx, JS::ObjectOrNullValue(v));
+ return ::SetElement(cx, obj, index, value);
+}
+
+JS_PUBLIC_API bool JS_SetElement(JSContext* cx, JS::Handle<JSObject*> obj,
+ uint32_t index, HandleString v) {
+ JS::Rooted<JS::Value> value(cx, JS::StringValue(v));
+ return ::SetElement(cx, obj, index, value);
+}
+
+JS_PUBLIC_API bool JS_SetElement(JSContext* cx, JS::Handle<JSObject*> obj,
+ uint32_t index, int32_t v) {
+ JS::Rooted<JS::Value> value(cx, JS::NumberValue(v));
+ return ::SetElement(cx, obj, index, value);
+}
+
+JS_PUBLIC_API bool JS_SetElement(JSContext* cx, JS::Handle<JSObject*> obj,
+ uint32_t index, uint32_t v) {
+ JS::Rooted<JS::Value> value(cx, JS::NumberValue(v));
+ return ::SetElement(cx, obj, index, value);
+}
+
+JS_PUBLIC_API bool JS_SetElement(JSContext* cx, JS::Handle<JSObject*> obj,
+ uint32_t index, double v) {
+ JS::Rooted<JS::Value> value(cx, JS::NumberValue(v));
+ return ::SetElement(cx, obj, index, value);
+}
+
+JS_PUBLIC_API bool JS_DeletePropertyById(JSContext* cx,
+ JS::Handle<JSObject*> obj,
+ JS::Handle<jsid> 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<JSObject*> 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<jsid> id(cx, AtomToId(atom));
+ return js::DeleteProperty(cx, obj, id, result);
+}
+
+JS_PUBLIC_API bool JS_DeleteUCProperty(JSContext* cx, JS::Handle<JSObject*> 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<jsid> id(cx, AtomToId(atom));
+ return js::DeleteProperty(cx, obj, id, result);
+}
+
+JS_PUBLIC_API bool JS_DeleteElement(JSContext* cx, JS::Handle<JSObject*> 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<JSObject*> obj,
+ JS::Handle<jsid> id) {
+ JS::ObjectOpResult ignored;
+ return JS_DeletePropertyById(cx, obj, id, ignored);
+}
+
+JS_PUBLIC_API bool JS_DeleteProperty(JSContext* cx, JS::Handle<JSObject*> obj,
+ const char* name) {
+ JS::ObjectOpResult ignored;
+ return JS_DeleteProperty(cx, obj, name, ignored);
+}
+
+JS_PUBLIC_API bool JS_DeleteElement(JSContext* cx, JS::Handle<JSObject*> obj,
+ uint32_t index) {
+ JS::ObjectOpResult ignored;
+ return JS_DeleteElement(cx, obj, index, ignored);
+}
+
+JS_PUBLIC_API bool JS_Enumerate(JSContext* cx, JS::Handle<JSObject*> obj,
+ JS::MutableHandle<IdVector> props) {
+ AssertHeapIsIdle();
+ CHECK_THREAD(cx);
+ cx->check(obj, props);
+ MOZ_ASSERT(props.empty());
+
+ JS::RootedVector<JS::PropertyKey> 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<JSObject*> obj,
+ const char* name, const JSClass* clasp,
+ unsigned attrs) {
+ AssertHeapIsIdle();
+ CHECK_THREAD(cx);
+ cx->check(obj);
+
+ JS::Rooted<JSObject*> nobj(cx);
+ if (!clasp) {
+ // Default class is Object.
+ nobj = NewPlainObject(cx);
+ } else {
+ nobj = NewBuiltinClassInstance(cx, clasp);
+ }
+ if (!nobj) {
+ return nullptr;
+ }
+
+ JS::Rooted<JS::Value> 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<JSObject*> obj,
+ const JSPropertySpec* ps) {
+ JS::Rooted<jsid> 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<JS::Value> 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<JSObject*> obj,
+ JS::Handle<jsid> id,
+ bool* foundp) {
+ AssertHeapIsIdle();
+ CHECK_THREAD(cx);
+ cx->check(obj, id);
+
+ if (!obj->is<NativeObject>()) {
+ return js::HasOwnProperty(cx, obj, id, foundp);
+ }
+
+ PropertyResult prop;
+ if (!NativeLookupOwnPropertyNoResolve(cx, &obj->as<NativeObject>(), id,
+ &prop)) {
+ return false;
+ }
+ *foundp = prop.isFound();
+ return true;
+}
+
+JS_PUBLIC_API bool JS_AlreadyHasOwnProperty(JSContext* cx,
+ JS::Handle<JSObject*> obj,
+ const char* name, bool* foundp) {
+ JSAtom* atom = Atomize(cx, name, strlen(name));
+ if (!atom) {
+ return false;
+ }
+ JS::Rooted<jsid> id(cx, AtomToId(atom));
+ return JS_AlreadyHasOwnPropertyById(cx, obj, id, foundp);
+}
+
+JS_PUBLIC_API bool JS_AlreadyHasOwnUCProperty(JSContext* cx,
+ JS::Handle<JSObject*> 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<jsid> id(cx, AtomToId(atom));
+ return JS_AlreadyHasOwnPropertyById(cx, obj, id, foundp);
+}
+
+JS_PUBLIC_API bool JS_AlreadyHasOwnElement(JSContext* cx,
+ JS::Handle<JSObject*> obj,
+ uint32_t index, bool* foundp) {
+ AssertHeapIsIdle();
+ CHECK_THREAD(cx);
+ JS::Rooted<jsid> 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<JSObject*> 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<JSObject*> 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<jsid> id(cx, AtomToId(atom));
+ return js::DefineFunction(cx, obj, id, call, nargs, attrs);
+}
+
+JS_PUBLIC_API JSFunction* JS_DefineUCFunction(JSContext* cx,
+ JS::Handle<JSObject*> 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<jsid> id(cx, AtomToId(atom));
+ return js::DefineFunction(cx, obj, id, call, nargs, attrs);
+}
+
+JS_PUBLIC_API JSFunction* JS_DefineFunctionById(JSContext* cx,
+ JS::Handle<JSObject*> obj,
+ JS::Handle<jsid> 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);
+}