--- a/js/src/Makefile.in
+++ b/js/src/Makefile.in
@@ -115,16 +115,17 @@ CPPSRCS = \
jswrapper.cpp \
jsxml.cpp \
prmjtime.cpp \
sharkctl.cpp \
ArgumentsObject.cpp \
DateTime.cpp \
Debugger.cpp \
GlobalObject.cpp \
+ Object.cpp \
ObjectImpl.cpp \
ScopeObject.cpp \
Stack.cpp \
String.cpp \
BytecodeCompiler.cpp \
BytecodeEmitter.cpp \
FoldConstants.cpp \
Intl.cpp \
new file mode 100644
--- /dev/null
+++ b/js/src/builtin/Object.cpp
@@ -0,0 +1,988 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sw=4 et tw=99 ft=cpp:
+ *
+ * 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 "mozilla/Util.h"
+
+#include "jscntxt.h"
+#include "jsobj.h"
+
+#include "builtin/Object.h"
+#include "frontend/Parser.h"
+#include "vm/StringBuffer.h"
+
+#include "jsfuninlines.h"
+#include "jsobjinlines.h"
+
+using namespace js;
+using namespace js::types;
+
+using js::frontend::IsIdentifier;
+using mozilla::ArrayLength;
+
+
+static bool
+DefineProperties(JSContext *cx, HandleObject obj, HandleObject props)
+{
+ AutoIdVector ids(cx);
+ AutoPropDescArrayRooter descs(cx);
+ if (!ReadPropertyDescriptors(cx, props, true, &ids, &descs))
+ return false;
+
+ bool dummy;
+ for (size_t i = 0, len = ids.length(); i < len; i++) {
+ if (!DefineProperty(cx, obj, Handle<jsid>::fromMarkedLocation(&ids[i]), descs[i], true, &dummy))
+ return false;
+ }
+
+ return true;
+}
+
+
+JSBool
+js::obj_construct(JSContext *cx, unsigned argc, Value *vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+
+ RootedObject obj(cx, NULL);
+ if (args.length() > 0) {
+ /* If argv[0] is null or undefined, obj comes back null. */
+ if (!js_ValueToObjectOrNull(cx, args[0], &obj))
+ return false;
+ }
+ if (!obj) {
+ /* Make an object whether this was called with 'new' or not. */
+ JS_ASSERT(!args.length() || args[0].isNullOrUndefined());
+ if (!NewObjectScriptedCall(cx, &obj))
+ return false;
+ }
+
+ args.rval().setObject(*obj);
+ return true;
+}
+
+/* ES5 15.2.4.7. */
+static JSBool
+obj_propertyIsEnumerable(JSContext *cx, unsigned argc, Value *vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+
+ /* Step 1. */
+ RootedId id(cx);
+ if (!ValueToId(cx, args.length() ? args[0] : UndefinedValue(), id.address()))
+ return false;
+
+ /* Step 2. */
+ RootedObject obj(cx, ToObject(cx, args.thisv()));
+ if (!obj)
+ return false;
+
+ /* Steps 3. */
+ RootedObject pobj(cx);
+ RootedShape prop(cx);
+ if (!JSObject::lookupGeneric(cx, obj, id, &pobj, &prop))
+ return false;
+
+ /* Step 4. */
+ if (!prop) {
+ args.rval().setBoolean(false);
+ return true;
+ }
+
+ if (pobj != obj) {
+ vp->setBoolean(false);
+ return true;
+ }
+
+ /* Step 5. */
+ unsigned attrs;
+ if (!JSObject::getGenericAttributes(cx, pobj, id, &attrs))
+ return false;
+
+ args.rval().setBoolean((attrs & JSPROP_ENUMERATE) != 0);
+ return true;
+}
+
+#if JS_HAS_TOSOURCE
+static JSBool
+obj_toSource(JSContext *cx, unsigned argc, Value *vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ JS_CHECK_RECURSION(cx, return false);
+
+ RootedObject obj(cx, ToObject(cx, args.thisv()));
+ if (!obj)
+ return false;
+
+ /* If outermost, we need parentheses to be an expression, not a block. */
+ bool outermost = (cx->cycleDetectorSet.count() == 0);
+
+ AutoCycleDetector detector(cx, obj);
+ if (!detector.init())
+ return false;
+ if (detector.foundCycle()) {
+ JSString *str = js_NewStringCopyZ(cx, "{}");
+ if (!str)
+ return false;
+ args.rval().setString(str);
+ return true;
+ }
+
+ StringBuffer buf(cx);
+ if (outermost && !buf.append('('))
+ return false;
+ if (!buf.append('{'))
+ return false;
+
+ Value val[2];
+ PodArrayZero(val);
+ AutoArrayRooter tvr2(cx, ArrayLength(val), val);
+
+ JSString *gsop[2];
+ SkipRoot skipGsop(cx, &gsop, 2);
+
+ AutoIdVector idv(cx);
+ if (!GetPropertyNames(cx, obj, JSITER_OWNONLY, &idv))
+ return false;
+
+ bool comma = false;
+ for (size_t i = 0; i < idv.length(); ++i) {
+ RootedId id(cx, idv[i]);
+ RootedObject obj2(cx);
+ RootedShape shape(cx);
+ if (!JSObject::lookupGeneric(cx, obj, id, &obj2, &shape))
+ return false;
+
+ /* Decide early whether we prefer get/set or old getter/setter syntax. */
+ int valcnt = 0;
+ if (shape) {
+ bool doGet = true;
+ if (obj2->isNative()) {
+ unsigned attrs = shape->attributes();
+ if (attrs & JSPROP_GETTER) {
+ doGet = false;
+ val[valcnt] = shape->getterValue();
+ gsop[valcnt] = cx->names().get;
+ valcnt++;
+ }
+ if (attrs & JSPROP_SETTER) {
+ doGet = false;
+ val[valcnt] = shape->setterValue();
+ gsop[valcnt] = cx->names().set;
+ valcnt++;
+ }
+ }
+ if (doGet) {
+ valcnt = 1;
+ gsop[0] = NULL;
+ MutableHandleValue vp = MutableHandleValue::fromMarkedLocation(&val[0]);
+ if (!JSObject::getGeneric(cx, obj, obj, id, vp))
+ return false;
+ }
+ }
+
+ /* Convert id to a linear string. */
+ RawString s = ToString(cx, IdToValue(id));
+ if (!s)
+ return false;
+ Rooted<JSLinearString*> idstr(cx, s->ensureLinear(cx));
+ if (!idstr)
+ return false;
+
+ /*
+ * If id is a string that's not an identifier, or if it's a negative
+ * integer, then it must be quoted.
+ */
+ if (JSID_IS_ATOM(id)
+ ? !IsIdentifier(idstr)
+ : (!JSID_IS_INT(id) || JSID_TO_INT(id) < 0))
+ {
+ s = js_QuoteString(cx, idstr, jschar('\''));
+ if (!s || !(idstr = s->ensureLinear(cx)))
+ return false;
+ }
+
+ for (int j = 0; j < valcnt; j++) {
+ /*
+ * Censor an accessor descriptor getter or setter part if it's
+ * undefined.
+ */
+ if (gsop[j] && val[j].isUndefined())
+ continue;
+
+ /* Convert val[j] to its canonical source form. */
+ RootedString valstr(cx, js_ValueToSource(cx, val[j]));
+ if (!valstr)
+ return false;
+ const jschar *vchars = valstr->getChars(cx);
+ if (!vchars)
+ return false;
+ size_t vlength = valstr->length();
+
+ /*
+ * Remove '(function ' from the beginning of valstr and ')' from the
+ * end so that we can put "get" in front of the function definition.
+ */
+ if (gsop[j] && IsFunctionObject(val[j])) {
+ const jschar *start = vchars;
+ const jschar *end = vchars + vlength;
+
+ uint8_t parenChomp = 0;
+ if (vchars[0] == '(') {
+ vchars++;
+ parenChomp = 1;
+ }
+
+ /* Try to jump "function" keyword. */
+ if (vchars)
+ vchars = js_strchr_limit(vchars, ' ', end);
+
+ /*
+ * Jump over the function's name: it can't be encoded as part
+ * of an ECMA getter or setter.
+ */
+ if (vchars)
+ vchars = js_strchr_limit(vchars, '(', end);
+
+ if (vchars) {
+ if (*vchars == ' ')
+ vchars++;
+ vlength = end - vchars - parenChomp;
+ } else {
+ gsop[j] = NULL;
+ vchars = start;
+ }
+ }
+
+ if (comma && !buf.append(", "))
+ return false;
+ comma = true;
+
+ if (gsop[j])
+ if (!buf.append(gsop[j]) || !buf.append(' '))
+ return false;
+
+ if (!buf.append(idstr))
+ return false;
+ if (!buf.append(gsop[j] ? ' ' : ':'))
+ return false;
+
+ if (!buf.append(vchars, vlength))
+ return false;
+ }
+ }
+
+ if (!buf.append('}'))
+ return false;
+ if (outermost && !buf.append(')'))
+ return false;
+
+ RawString str = buf.finishString();
+ if (!str)
+ return false;
+ args.rval().setString(str);
+ return true;
+}
+#endif /* JS_HAS_TOSOURCE */
+
+JSString *
+js::obj_toStringHelper(JSContext *cx, JSObject *obj)
+{
+ if (obj->isProxy())
+ return Proxy::obj_toString(cx, obj);
+
+ StringBuffer sb(cx);
+ const char *className = obj->getClass()->name;
+ if (!sb.append("[object ") || !sb.appendInflated(className, strlen(className)) ||
+ !sb.append("]"))
+ {
+ return NULL;
+ }
+ return sb.finishString();
+}
+
+/* ES5 15.2.4.2. Note steps 1 and 2 are errata. */
+static JSBool
+obj_toString(JSContext *cx, unsigned argc, Value *vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+
+ /* Step 1. */
+ if (args.thisv().isUndefined()) {
+ args.rval().setString(cx->names().objectUndefined);
+ return true;
+ }
+
+ /* Step 2. */
+ if (args.thisv().isNull()) {
+ args.rval().setString(cx->names().objectNull);
+ return true;
+ }
+
+ /* Step 3. */
+ JSObject *obj = ToObject(cx, args.thisv());
+ if (!obj)
+ return false;
+
+ /* Steps 4-5. */
+ JSString *str = js::obj_toStringHelper(cx, obj);
+ if (!str)
+ return false;
+ args.rval().setString(str);
+ return true;
+}
+
+/* ES5 15.2.4.3. */
+static JSBool
+obj_toLocaleString(JSContext *cx, unsigned argc, Value *vp)
+{
+ JS_CHECK_RECURSION(cx, return false);
+
+ CallArgs args = CallArgsFromVp(argc, vp);
+
+ /* Step 1. */
+ JSObject *obj = ToObject(cx, args.thisv());
+ if (!obj)
+ return false;
+
+ /* Steps 2-4. */
+ RootedId id(cx, NameToId(cx->names().toString));
+ return obj->callMethod(cx, id, 0, NULL, args.rval());
+}
+
+static JSBool
+obj_valueOf(JSContext *cx, unsigned argc, Value *vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ JSObject *obj = ToObject(cx, args.thisv());
+ if (!obj)
+ return false;
+ args.rval().setObject(*obj);
+ return true;
+}
+
+#if OLD_GETTER_SETTER_METHODS
+
+enum DefineType { Getter, Setter };
+
+template<DefineType Type>
+static bool
+DefineAccessor(JSContext *cx, unsigned argc, Value *vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ if (!BoxNonStrictThis(cx, args))
+ return false;
+
+ if (args.length() < 2 || !js_IsCallable(args[1])) {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+ JSMSG_BAD_GETTER_OR_SETTER,
+ Type == Getter ? js_getter_str : js_setter_str);
+ return false;
+ }
+
+ RootedId id(cx);
+ if (!ValueToId(cx, args[0], id.address()))
+ return false;
+
+ RootedObject descObj(cx, NewBuiltinClassInstance(cx, &ObjectClass));
+ if (!descObj)
+ return false;
+
+ JSAtomState &names = cx->names();
+ RootedValue trueVal(cx, BooleanValue(true));
+
+ /* enumerable: true */
+ if (!JSObject::defineProperty(cx, descObj, names.enumerable, trueVal))
+ return false;
+
+ /* configurable: true */
+ if (!JSObject::defineProperty(cx, descObj, names.configurable, trueVal))
+ return false;
+
+ /* enumerable: true */
+ PropertyName *acc = (Type == Getter) ? names.get : names.set;
+ RootedValue accessorVal(cx, args[1]);
+ if (!JSObject::defineProperty(cx, descObj, acc, accessorVal))
+ return false;
+
+ RootedObject thisObj(cx, &args.thisv().toObject());
+
+ JSBool dummy;
+ if (!js_DefineOwnProperty(cx, thisObj, id, ObjectValue(*descObj), &dummy))
+ return false;
+
+ args.rval().setUndefined();
+ return true;
+}
+
+JS_FRIEND_API(JSBool)
+js::obj_defineGetter(JSContext *cx, unsigned argc, Value *vp)
+{
+ return DefineAccessor<Getter>(cx, argc, vp);
+}
+
+JS_FRIEND_API(JSBool)
+js::obj_defineSetter(JSContext *cx, unsigned argc, Value *vp)
+{
+ return DefineAccessor<Setter>(cx, argc, vp);
+}
+
+static JSBool
+obj_lookupGetter(JSContext *cx, unsigned argc, Value *vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+
+ RootedId id(cx);
+ if (!ValueToId(cx, args.length() ? args[0] : UndefinedValue(), id.address()))
+ return JS_FALSE;
+ RootedObject obj(cx, ToObject(cx, args.thisv()));
+ if (!obj)
+ return JS_FALSE;
+ if (obj->isProxy()) {
+ // The vanilla getter lookup code below requires that the object is
+ // native. Handle proxies separately.
+ args.rval().setUndefined();
+ AutoPropertyDescriptorRooter desc(cx);
+ if (!Proxy::getPropertyDescriptor(cx, obj, id, false, &desc))
+ return JS_FALSE;
+ if (desc.obj && (desc.attrs & JSPROP_GETTER) && desc.getter)
+ args.rval().set(CastAsObjectJsval(desc.getter));
+ return JS_TRUE;
+ }
+ RootedObject pobj(cx);
+ RootedShape shape(cx);
+ if (!JSObject::lookupGeneric(cx, obj, id, &pobj, &shape))
+ return JS_FALSE;
+ args.rval().setUndefined();
+ if (shape) {
+ if (pobj->isNative()) {
+ if (shape->hasGetterValue())
+ args.rval().set(shape->getterValue());
+ }
+ }
+ return JS_TRUE;
+}
+
+static JSBool
+obj_lookupSetter(JSContext *cx, unsigned argc, Value *vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+
+ RootedId id(cx);
+ if (!ValueToId(cx, args.length() ? args[0] : UndefinedValue(), id.address()))
+ return JS_FALSE;
+ RootedObject obj(cx, ToObject(cx, args.thisv()));
+ if (!obj)
+ return JS_FALSE;
+ if (obj->isProxy()) {
+ // The vanilla setter lookup code below requires that the object is
+ // native. Handle proxies separately.
+ args.rval().setUndefined();
+ AutoPropertyDescriptorRooter desc(cx);
+ if (!Proxy::getPropertyDescriptor(cx, obj, id, false, &desc))
+ return JS_FALSE;
+ if (desc.obj && (desc.attrs & JSPROP_SETTER) && desc.setter)
+ args.rval().set(CastAsObjectJsval(desc.setter));
+ return JS_TRUE;
+ }
+ RootedObject pobj(cx);
+ RootedShape shape(cx);
+ if (!JSObject::lookupGeneric(cx, obj, id, &pobj, &shape))
+ return JS_FALSE;
+ args.rval().setUndefined();
+ if (shape) {
+ if (pobj->isNative()) {
+ if (shape->hasSetterValue())
+ args.rval().set(shape->setterValue());
+ }
+ }
+ return JS_TRUE;
+}
+#endif /* OLD_GETTER_SETTER_METHODS */
+
+/* ES5 15.2.3.2. */
+JSBool
+obj_getPrototypeOf(JSContext *cx, unsigned argc, Value *vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+
+ /* Step 1. */
+ if (args.length() == 0) {
+ js_ReportMissingArg(cx, args.calleev(), 0);
+ return false;
+ }
+
+ if (args[0].isPrimitive()) {
+ RootedValue val(cx, args[0]);
+ char *bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, val, NullPtr());
+ if (!bytes)
+ return false;
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+ JSMSG_UNEXPECTED_TYPE, bytes, "not an object");
+ js_free(bytes);
+ return false;
+ }
+
+ /* Step 2. */
+
+ /*
+ * Implement [[Prototype]]-getting -- particularly across compartment
+ * boundaries -- by calling a cached __proto__ getter function.
+ */
+ InvokeArgsGuard nested;
+ if (!cx->stack.pushInvokeArgs(cx, 0, &nested))
+ return false;
+ nested.setCallee(cx->global()->protoGetter());
+ nested.setThis(args[0]);
+ if (!Invoke(cx, nested))
+ return false;
+ args.rval().set(nested.rval());
+ return true;
+}
+
+#if JS_HAS_OBJ_WATCHPOINT
+
+static JSBool
+obj_watch_handler(JSContext *cx, JSObject *obj_, jsid id_, jsval old,
+ jsval *nvp, void *closure)
+{
+ RootedObject obj(cx, obj_);
+ RootedId id(cx, id_);
+
+ /* Avoid recursion on (obj, id) already being watched on cx. */
+ AutoResolving resolving(cx, obj, id, AutoResolving::WATCH);
+ if (resolving.alreadyStarted())
+ return true;
+
+ JSObject *callable = (JSObject *)closure;
+ Value argv[] = { IdToValue(id), old, *nvp };
+ return Invoke(cx, ObjectValue(*obj), ObjectOrNullValue(callable), ArrayLength(argv), argv, nvp);
+}
+
+static JSBool
+obj_watch(JSContext *cx, unsigned argc, Value *vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+
+ if (args.length() <= 1) {
+ js_ReportMissingArg(cx, args.calleev(), 1);
+ return false;
+ }
+
+ RootedObject callable(cx, ValueToCallable(cx, &args[1]));
+ if (!callable)
+ return false;
+
+ RootedId propid(cx);
+ if (!ValueToId(cx, args[0], propid.address()))
+ return false;
+
+ RootedObject obj(cx, ToObject(cx, args.thisv()));
+ if (!obj)
+ return false;
+
+ RootedValue tmp(cx);
+ unsigned attrs;
+ if (!CheckAccess(cx, obj, propid, JSACC_WATCH, &tmp, &attrs))
+ return false;
+
+ args.rval().setUndefined();
+
+ if (obj->isDenseArray() && !JSObject::makeDenseArraySlow(cx, obj))
+ return false;
+ return JS_SetWatchPoint(cx, obj, propid, obj_watch_handler, callable);
+}
+
+static JSBool
+obj_unwatch(JSContext *cx, unsigned argc, Value *vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+
+ RootedObject obj(cx, ToObject(cx, args.thisv()));
+ if (!obj)
+ return false;
+ args.rval().setUndefined();
+ jsid id;
+ if (argc != 0) {
+ if (!ValueToId(cx, args[0], &id))
+ return false;
+ } else {
+ id = JSID_VOID;
+ }
+ return JS_ClearWatchPoint(cx, obj, id, NULL, NULL);
+}
+
+#endif /* JS_HAS_OBJ_WATCHPOINT */
+
+/* ECMA 15.2.4.5. */
+static JSBool
+obj_hasOwnProperty(JSContext *cx, unsigned argc, Value *vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+
+ /* Step 1. */
+ RootedId id(cx);
+ if (!ValueToId(cx, args.length() ? args[0] : UndefinedValue(), id.address()))
+ return false;
+
+ /* Step 2. */
+ RootedObject obj(cx, ToObject(cx, args.thisv()));
+ if (!obj)
+ return false;
+
+ /* Non-standard code for proxies. */
+ RootedObject obj2(cx);
+ RootedShape prop(cx);
+ if (obj->isProxy()) {
+ bool has;
+ if (!Proxy::hasOwn(cx, obj, id, &has))
+ return false;
+ args.rval().setBoolean(has);
+ return true;
+ }
+
+ /* Step 3. */
+ if (!js_HasOwnProperty(cx, obj->getOps()->lookupGeneric, obj, id, &obj2, &prop))
+ return false;
+ /* Step 4,5. */
+ args.rval().setBoolean(!!prop);
+ return true;
+}
+
+/* ES5 15.2.4.6. */
+static JSBool
+obj_isPrototypeOf(JSContext *cx, unsigned argc, Value *vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+
+ /* Step 1. */
+ if (args.length() < 1 || !args[0].isObject()) {
+ args.rval().setBoolean(false);
+ return true;
+ }
+
+ /* Step 2. */
+ RootedObject obj(cx, ToObject(cx, args.thisv()));
+ if (!obj)
+ return false;
+
+ /* Step 3. */
+ bool isDelegate;
+ if (!IsDelegate(cx, obj, args[0], &isDelegate))
+ return false;
+ args.rval().setBoolean(isDelegate);
+ return true;
+}
+
+/* ES5 15.2.3.5: Object.create(O [, Properties]) */
+static JSBool
+obj_create(JSContext *cx, unsigned argc, Value *vp)
+{
+ if (argc == 0) {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED,
+ "Object.create", "0", "s");
+ return false;
+ }
+
+ CallArgs args = CallArgsFromVp(argc, vp);
+ RootedValue v(cx, args[0]);
+ if (!v.isObjectOrNull()) {
+ char *bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, v, NullPtr());
+ if (!bytes)
+ return false;
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_UNEXPECTED_TYPE,
+ bytes, "not an object or null");
+ js_free(bytes);
+ return false;
+ }
+
+ JSObject *proto = v.toObjectOrNull();
+#if JS_HAS_XML_SUPPORT
+ if (proto && proto->isXML()) {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_XML_PROTO_FORBIDDEN);
+ return false;
+ }
+#endif
+
+ /*
+ * Use the callee's global as the parent of the new object to avoid dynamic
+ * scoping (i.e., using the caller's global).
+ */
+ RootedObject obj(cx, NewObjectWithGivenProto(cx, &ObjectClass, proto, &args.callee().global()));
+ if (!obj)
+ return false;
+
+ /* Don't track types or array-ness for objects created here. */
+ MarkTypeObjectUnknownProperties(cx, obj->type());
+
+ /* 15.2.3.5 step 4. */
+ if (args.hasDefined(1)) {
+ if (args[1].isPrimitive()) {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_NONNULL_OBJECT);
+ return false;
+ }
+
+ RootedObject props(cx, &args[1].toObject());
+ if (!DefineProperties(cx, obj, props))
+ return false;
+ }
+
+ /* 5. Return obj. */
+ args.rval().setObject(*obj);
+ return true;
+}
+
+static JSBool
+obj_getOwnPropertyDescriptor(JSContext *cx, unsigned argc, Value *vp)
+{
+ RootedObject obj(cx);
+ if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.getOwnPropertyDescriptor", &obj))
+ return JS_FALSE;
+ RootedId id(cx);
+ if (!ValueToId(cx, argc >= 2 ? vp[3] : UndefinedValue(), id.address()))
+ return JS_FALSE;
+ return GetOwnPropertyDescriptor(cx, obj, id, vp);
+}
+
+static JSBool
+obj_keys(JSContext *cx, unsigned argc, Value *vp)
+{
+ RootedObject obj(cx);
+ if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.keys", &obj))
+ return false;
+
+ AutoIdVector props(cx);
+ if (!GetPropertyNames(cx, obj, JSITER_OWNONLY, &props))
+ return false;
+
+ AutoValueVector vals(cx);
+ if (!vals.reserve(props.length()))
+ return false;
+ for (size_t i = 0, len = props.length(); i < len; i++) {
+ jsid id = props[i];
+ if (JSID_IS_STRING(id)) {
+ vals.infallibleAppend(StringValue(JSID_TO_STRING(id)));
+ } else if (JSID_IS_INT(id)) {
+ JSString *str = Int32ToString(cx, JSID_TO_INT(id));
+ if (!str)
+ return false;
+ vals.infallibleAppend(StringValue(str));
+ } else {
+ JS_ASSERT(JSID_IS_OBJECT(id));
+ }
+ }
+
+ JS_ASSERT(props.length() <= UINT32_MAX);
+ JSObject *aobj = NewDenseCopiedArray(cx, uint32_t(vals.length()), vals.begin());
+ if (!aobj)
+ return false;
+ vp->setObject(*aobj);
+
+ return true;
+}
+
+static JSBool
+obj_getOwnPropertyNames(JSContext *cx, unsigned argc, Value *vp)
+{
+ RootedObject obj(cx);
+ if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.getOwnPropertyNames", &obj))
+ return false;
+
+ AutoIdVector keys(cx);
+ if (!GetPropertyNames(cx, obj, JSITER_OWNONLY | JSITER_HIDDEN, &keys))
+ return false;
+
+ AutoValueVector vals(cx);
+ if (!vals.resize(keys.length()))
+ return false;
+
+ for (size_t i = 0, len = keys.length(); i < len; i++) {
+ jsid id = keys[i];
+ if (JSID_IS_INT(id)) {
+ JSString *str = Int32ToString(cx, JSID_TO_INT(id));
+ if (!str)
+ return false;
+ vals[i].setString(str);
+ } else if (JSID_IS_ATOM(id)) {
+ vals[i].setString(JSID_TO_STRING(id));
+ } else {
+ vals[i].setObject(*JSID_TO_OBJECT(id));
+ }
+ }
+
+ JSObject *aobj = NewDenseCopiedArray(cx, vals.length(), vals.begin());
+ if (!aobj)
+ return false;
+
+ vp->setObject(*aobj);
+ return true;
+}
+
+/* ES5 15.2.3.6: Object.defineProperty(O, P, Attributes) */
+static JSBool
+obj_defineProperty(JSContext *cx, unsigned argc, Value *vp)
+{
+ RootedObject obj(cx);
+ if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.defineProperty", &obj))
+ return false;
+
+ RootedId id(cx);
+ if (!ValueToId(cx, argc >= 2 ? vp[3] : UndefinedValue(), id.address()))
+ return JS_FALSE;
+
+ const Value descval = argc >= 3 ? vp[4] : UndefinedValue();
+
+ JSBool junk;
+ if (!js_DefineOwnProperty(cx, obj, id, descval, &junk))
+ return false;
+
+ vp->setObject(*obj);
+ return true;
+}
+
+/* ES5 15.2.3.7: Object.defineProperties(O, Properties) */
+static JSBool
+obj_defineProperties(JSContext *cx, unsigned argc, Value *vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+
+ /* Steps 1 and 7. */
+ RootedObject obj(cx);
+ if (!GetFirstArgumentAsObject(cx, args.length(), vp, "Object.defineProperties", &obj))
+ return false;
+ args.rval().setObject(*obj);
+
+ /* Step 2. */
+ if (args.length() < 2) {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED,
+ "Object.defineProperties", "0", "s");
+ return false;
+ }
+ RootedValue val(cx, args[1]);
+ RootedObject props(cx, ToObject(cx, val));
+ if (!props)
+ return false;
+
+ /* Steps 3-6. */
+ return DefineProperties(cx, obj, props);
+}
+
+static JSBool
+obj_isExtensible(JSContext *cx, unsigned argc, Value *vp)
+{
+ RootedObject obj(cx);
+ if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.isExtensible", &obj))
+ return false;
+
+ vp->setBoolean(obj->isExtensible());
+ return true;
+}
+
+static JSBool
+obj_preventExtensions(JSContext *cx, unsigned argc, Value *vp)
+{
+ RootedObject obj(cx);
+ if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.preventExtensions", &obj))
+ return false;
+
+ vp->setObject(*obj);
+ if (!obj->isExtensible())
+ return true;
+
+ return obj->preventExtensions(cx);
+}
+
+static JSBool
+obj_freeze(JSContext *cx, unsigned argc, Value *vp)
+{
+ RootedObject obj(cx);
+ if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.freeze", &obj))
+ return false;
+
+ vp->setObject(*obj);
+
+ return JSObject::freeze(cx, obj);
+}
+
+static JSBool
+obj_isFrozen(JSContext *cx, unsigned argc, Value *vp)
+{
+ RootedObject obj(cx);
+ if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.preventExtensions", &obj))
+ return false;
+
+ bool frozen;
+ if (!JSObject::isFrozen(cx, obj, &frozen))
+ return false;
+ vp->setBoolean(frozen);
+ return true;
+}
+
+static JSBool
+obj_seal(JSContext *cx, unsigned argc, Value *vp)
+{
+ RootedObject obj(cx);
+ if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.seal", &obj))
+ return false;
+
+ vp->setObject(*obj);
+
+ return JSObject::seal(cx, obj);
+}
+
+static JSBool
+obj_isSealed(JSContext *cx, unsigned argc, Value *vp)
+{
+ RootedObject obj(cx);
+ if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.isSealed", &obj))
+ return false;
+
+ bool sealed;
+ if (!JSObject::isSealed(cx, obj, &sealed))
+ return false;
+ vp->setBoolean(sealed);
+ return true;
+}
+
+JSFunctionSpec js::object_methods[] = {
+#if JS_HAS_TOSOURCE
+ JS_FN(js_toSource_str, obj_toSource, 0,0),
+#endif
+ JS_FN(js_toString_str, obj_toString, 0,0),
+ JS_FN(js_toLocaleString_str, obj_toLocaleString, 0,0),
+ JS_FN(js_valueOf_str, obj_valueOf, 0,0),
+#if JS_HAS_OBJ_WATCHPOINT
+ JS_FN(js_watch_str, obj_watch, 2,0),
+ JS_FN(js_unwatch_str, obj_unwatch, 1,0),
+#endif
+ JS_FN(js_hasOwnProperty_str, obj_hasOwnProperty, 1,0),
+ JS_FN(js_isPrototypeOf_str, obj_isPrototypeOf, 1,0),
+ JS_FN(js_propertyIsEnumerable_str, obj_propertyIsEnumerable, 1,0),
+#if OLD_GETTER_SETTER_METHODS
+ JS_FN(js_defineGetter_str, js::obj_defineGetter, 2,0),
+ JS_FN(js_defineSetter_str, js::obj_defineSetter, 2,0),
+ JS_FN(js_lookupGetter_str, obj_lookupGetter, 1,0),
+ JS_FN(js_lookupSetter_str, obj_lookupSetter, 1,0),
+#endif
+ JS_FS_END
+};
+
+JSFunctionSpec js::object_static_methods[] = {
+ JS_FN("getPrototypeOf", obj_getPrototypeOf, 1,0),
+ JS_FN("getOwnPropertyDescriptor", obj_getOwnPropertyDescriptor,2,0),
+ JS_FN("keys", obj_keys, 1,0),
+ JS_FN("defineProperty", obj_defineProperty, 3,0),
+ JS_FN("defineProperties", obj_defineProperties, 2,0),
+ JS_FN("create", obj_create, 2,0),
+ JS_FN("getOwnPropertyNames", obj_getOwnPropertyNames, 1,0),
+ JS_FN("isExtensible", obj_isExtensible, 1,0),
+ JS_FN("preventExtensions", obj_preventExtensions, 1,0),
+ JS_FN("freeze", obj_freeze, 1,0),
+ JS_FN("isFrozen", obj_isFrozen, 1,0),
+ JS_FN("seal", obj_seal, 1,0),
+ JS_FN("isSealed", obj_isSealed, 1,0),
+ JS_FS_END
+};
new file mode 100644
--- /dev/null
+++ b/js/src/builtin/Object.h
@@ -0,0 +1,27 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sw=4 et tw=99 ft=cpp:
+ *
+ * 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 Object_h___
+#define Object_h___
+
+#include "jsobj.h"
+
+namespace js {
+
+extern JSFunctionSpec object_methods[];
+extern JSFunctionSpec object_static_methods[];
+
+/* Object constructor native. Exposed only so the JIT can know its address. */
+extern JSBool
+obj_construct(JSContext *cx, unsigned argc, js::Value *vp);
+
+extern JSString *
+obj_toStringHelper(JSContext *cx, JSObject *obj);
+
+} /* namespace js */
+
+#endif
--- a/js/src/jscntxtinlines.h
+++ b/js/src/jscntxtinlines.h
@@ -11,16 +11,17 @@
#include "jscntxt.h"
#include "jscompartment.h"
#include "jsfriendapi.h"
#include "jsinterp.h"
#include "jsprobes.h"
#include "jsxml.h"
#include "jsgc.h"
+#include "builtin/Object.h" // For js::obj_construct
#include "frontend/ParseMaps.h"
#include "vm/RegExpObject.h"
#include "jsgcinlines.h"
namespace js {
inline void
@@ -423,17 +424,17 @@ CallJSNativeConstructor(JSContext *cx, N
* - new Iterator(x) is user-hookable; it returns x.__iterator__() which
* could be any object.
*
* - (new Object(Object)) returns the callee.
*/
JS_ASSERT_IF(native != FunctionProxyClass.construct &&
native != js::CallOrConstructBoundFunction &&
native != js::IteratorConstructor &&
- (!callee->isFunction() || callee->toFunction()->native() != js_Object),
+ (!callee->isFunction() || callee->toFunction()->native() != obj_construct),
!args.rval().isPrimitive() && callee != &args.rval().toObject());
return true;
}
JS_ALWAYS_INLINE bool
CallJSPropertyOp(JSContext *cx, PropertyOp op, HandleObject receiver, HandleId id, MutableHandleValue vp)
{
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -103,214 +103,16 @@ JS_ObjectToInnerObject(JSContext *cx, JS
JS_FRIEND_API(JSObject *)
JS_ObjectToOuterObject(JSContext *cx, JSObject *obj_)
{
Rooted<JSObject*> obj(cx, obj_);
return GetOuterObject(cx, obj);
}
-#if JS_HAS_TOSOURCE
-static JSBool
-obj_toSource(JSContext *cx, unsigned argc, Value *vp)
-{
- CallArgs args = CallArgsFromVp(argc, vp);
- JS_CHECK_RECURSION(cx, return JS_FALSE);
-
- RootedObject obj(cx, ToObject(cx, args.thisv()));
- if (!obj)
- return false;
-
- /* If outermost, we need parentheses to be an expression, not a block. */
- bool outermost = (cx->cycleDetectorSet.count() == 0);
-
- AutoCycleDetector detector(cx, obj);
- if (!detector.init())
- return false;
- if (detector.foundCycle()) {
- JSString *str = js_NewStringCopyZ(cx, "{}");
- if (!str)
- return false;
- args.rval().setString(str);
- return true;
- }
-
- StringBuffer buf(cx);
- if (outermost && !buf.append('('))
- return false;
- if (!buf.append('{'))
- return false;
-
- Value val[2];
- PodArrayZero(val);
- AutoArrayRooter tvr2(cx, ArrayLength(val), val);
-
- JSString *gsop[2];
- SkipRoot skipGsop(cx, &gsop, 2);
-
- AutoIdVector idv(cx);
- if (!GetPropertyNames(cx, obj, JSITER_OWNONLY, &idv))
- return false;
-
- bool comma = false;
- for (size_t i = 0; i < idv.length(); ++i) {
- RootedId id(cx, idv[i]);
- RootedObject obj2(cx);
- RootedShape shape(cx);
- if (!JSObject::lookupGeneric(cx, obj, id, &obj2, &shape))
- return false;
-
- /* Decide early whether we prefer get/set or old getter/setter syntax. */
- int valcnt = 0;
- if (shape) {
- bool doGet = true;
- if (obj2->isNative()) {
- unsigned attrs = shape->attributes();
- if (attrs & JSPROP_GETTER) {
- doGet = false;
- val[valcnt] = shape->getterValue();
- gsop[valcnt] = cx->names().get;
- valcnt++;
- }
- if (attrs & JSPROP_SETTER) {
- doGet = false;
- val[valcnt] = shape->setterValue();
- gsop[valcnt] = cx->names().set;
- valcnt++;
- }
- }
- if (doGet) {
- valcnt = 1;
- gsop[0] = NULL;
- MutableHandleValue vp = MutableHandleValue::fromMarkedLocation(&val[0]);
- if (!JSObject::getGeneric(cx, obj, obj, id, vp))
- return false;
- }
- }
-
- /* Convert id to a linear string. */
- RawString s = ToString(cx, IdToValue(id));
- if (!s)
- return false;
- Rooted<JSLinearString*> idstr(cx, s->ensureLinear(cx));
- if (!idstr)
- return false;
-
- /*
- * If id is a string that's not an identifier, or if it's a negative
- * integer, then it must be quoted.
- */
- if (JSID_IS_ATOM(id)
- ? !IsIdentifier(idstr)
- : (!JSID_IS_INT(id) || JSID_TO_INT(id) < 0))
- {
- s = js_QuoteString(cx, idstr, jschar('\''));
- if (!s || !(idstr = s->ensureLinear(cx)))
- return false;
- }
-
- for (int j = 0; j < valcnt; j++) {
- /*
- * Censor an accessor descriptor getter or setter part if it's
- * undefined.
- */
- if (gsop[j] && val[j].isUndefined())
- continue;
-
- /* Convert val[j] to its canonical source form. */
- RootedString valstr(cx, js_ValueToSource(cx, val[j]));
- if (!valstr)
- return false;
- const jschar *vchars = valstr->getChars(cx);
- if (!vchars)
- return false;
- size_t vlength = valstr->length();
-
- /*
- * Remove '(function ' from the beginning of valstr and ')' from the
- * end so that we can put "get" in front of the function definition.
- */
- if (gsop[j] && IsFunctionObject(val[j])) {
- const jschar *start = vchars;
- const jschar *end = vchars + vlength;
-
- uint8_t parenChomp = 0;
- if (vchars[0] == '(') {
- vchars++;
- parenChomp = 1;
- }
-
- /* Try to jump "function" keyword. */
- if (vchars)
- vchars = js_strchr_limit(vchars, ' ', end);
-
- /*
- * Jump over the function's name: it can't be encoded as part
- * of an ECMA getter or setter.
- */
- if (vchars)
- vchars = js_strchr_limit(vchars, '(', end);
-
- if (vchars) {
- if (*vchars == ' ')
- vchars++;
- vlength = end - vchars - parenChomp;
- } else {
- gsop[j] = NULL;
- vchars = start;
- }
- }
-
- if (comma && !buf.append(", "))
- return false;
- comma = true;
-
- if (gsop[j])
- if (!buf.append(gsop[j]) || !buf.append(' '))
- return false;
-
- if (!buf.append(idstr))
- return false;
- if (!buf.append(gsop[j] ? ' ' : ':'))
- return false;
-
- if (!buf.append(vchars, vlength))
- return false;
- }
- }
-
- if (!buf.append('}'))
- return false;
- if (outermost && !buf.append(')'))
- return false;
-
- RawString str = buf.finishString();
- if (!str)
- return false;
- args.rval().setString(str);
- return true;
-}
-#endif /* JS_HAS_TOSOURCE */
-
-JSString *
-js::obj_toStringHelper(JSContext *cx, JSObject *obj)
-{
- if (obj->isProxy())
- return Proxy::obj_toString(cx, obj);
-
- StringBuffer sb(cx);
- const char *className = obj->getClass()->name;
- if (!sb.append("[object ") || !sb.appendInflated(className, strlen(className)) ||
- !sb.append("]"))
- {
- return NULL;
- }
- return sb.finishString();
-}
-
JSObject *
js::NonNullObject(JSContext *cx, const Value &v)
{
if (v.isPrimitive()) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_NONNULL_OBJECT);
return NULL;
}
return &v.toObject();
@@ -329,196 +131,16 @@ js::InformalValueTypeName(const Value &v
return "boolean";
if (v.isNull())
return "null";
if (v.isUndefined())
return "undefined";
return "value";
}
-/* ES5 15.2.4.2. Note steps 1 and 2 are errata. */
-static JSBool
-obj_toString(JSContext *cx, unsigned argc, Value *vp)
-{
- CallArgs args = CallArgsFromVp(argc, vp);
-
- /* Step 1. */
- if (args.thisv().isUndefined()) {
- args.rval().setString(cx->names().objectUndefined);
- return true;
- }
-
- /* Step 2. */
- if (args.thisv().isNull()) {
- args.rval().setString(cx->names().objectNull);
- return true;
- }
-
- /* Step 3. */
- JSObject *obj = ToObject(cx, args.thisv());
- if (!obj)
- return false;
-
- /* Steps 4-5. */
- JSString *str = js::obj_toStringHelper(cx, obj);
- if (!str)
- return false;
- args.rval().setString(str);
- return true;
-}
-
-/* ES5 15.2.4.3. */
-static JSBool
-obj_toLocaleString(JSContext *cx, unsigned argc, Value *vp)
-{
- JS_CHECK_RECURSION(cx, return false);
-
- CallArgs args = CallArgsFromVp(argc, vp);
-
- /* Step 1. */
- JSObject *obj = ToObject(cx, args.thisv());
- if (!obj)
- return false;
-
- /* Steps 2-4. */
- RootedId id(cx, NameToId(cx->names().toString));
- return obj->callMethod(cx, id, 0, NULL, args.rval());
-}
-
-static JSBool
-obj_valueOf(JSContext *cx, unsigned argc, Value *vp)
-{
- CallArgs args = CallArgsFromVp(argc, vp);
- JSObject *obj = ToObject(cx, args.thisv());
- if (!obj)
- return false;
- args.rval().setObject(*obj);
- return true;
-}
-
-#if JS_HAS_OBJ_WATCHPOINT
-
-static JSBool
-obj_watch_handler(JSContext *cx, JSObject *obj_, jsid id_, jsval old,
- jsval *nvp, void *closure)
-{
- RootedObject obj(cx, obj_);
- RootedId id(cx, id_);
-
- /* Avoid recursion on (obj, id) already being watched on cx. */
- AutoResolving resolving(cx, obj, id, AutoResolving::WATCH);
- if (resolving.alreadyStarted())
- return true;
-
- JSObject *callable = (JSObject *)closure;
- Value argv[] = { IdToValue(id), old, *nvp };
- return Invoke(cx, ObjectValue(*obj), ObjectOrNullValue(callable), ArrayLength(argv), argv, nvp);
-}
-
-static JSBool
-obj_watch(JSContext *cx, unsigned argc, Value *vp)
-{
- CallArgs args = CallArgsFromVp(argc, vp);
-
- if (argc <= 1) {
- js_ReportMissingArg(cx, args.calleev(), 1);
- return false;
- }
-
- RootedObject callable(cx, ValueToCallable(cx, &args[1]));
- if (!callable)
- return false;
-
- RootedId propid(cx);
- if (!ValueToId(cx, args[0], propid.address()))
- return false;
-
- RootedObject obj(cx, ToObject(cx, args.thisv()));
- if (!obj)
- return false;
-
- RootedValue tmp(cx);
- unsigned attrs;
- if (!CheckAccess(cx, obj, propid, JSACC_WATCH, &tmp, &attrs))
- return false;
-
- args.rval().setUndefined();
-
- if (obj->isDenseArray() && !JSObject::makeDenseArraySlow(cx, obj))
- return false;
- return JS_SetWatchPoint(cx, obj, propid, obj_watch_handler, callable);
-}
-
-static JSBool
-obj_unwatch(JSContext *cx, unsigned argc, Value *vp)
-{
- CallArgs args = CallArgsFromVp(argc, vp);
-
- RootedObject obj(cx, ToObject(cx, args.thisv()));
- if (!obj)
- return false;
- args.rval().setUndefined();
- jsid id;
- if (argc != 0) {
- if (!ValueToId(cx, args[0], &id))
- return false;
- } else {
- id = JSID_VOID;
- }
- return JS_ClearWatchPoint(cx, obj, id, NULL, NULL);
-}
-
-#endif /* JS_HAS_OBJ_WATCHPOINT */
-
-/*
- * Prototype and property query methods, to complement the 'in' and
- * 'instanceof' operators.
- */
-
-/* ECMA 15.2.4.5. */
-static JSBool
-obj_hasOwnProperty(JSContext *cx, unsigned argc, Value *vp)
-{
- CallArgs args = CallArgsFromVp(argc, vp);
-
- /* Step 1. */
- RootedId id(cx);
- if (!ValueToId(cx, args.length() ? args[0] : UndefinedValue(), id.address()))
- return false;
-
- /* Step 2. */
- RootedObject obj(cx, ToObject(cx, args.thisv()));
- if (!obj)
- return false;
- return js_HasOwnPropertyHelper(cx, obj->getOps()->lookupGeneric, obj, id, args.rval());
-}
-
-JSBool
-js_HasOwnPropertyHelper(JSContext *cx, LookupGenericOp lookup, HandleObject obj,
- HandleId id, MutableHandleValue rval)
-{
- /* Non-standard code for proxies. */
- RootedObject obj2(cx);
- RootedShape prop(cx);
- if (obj->isProxy()) {
- bool has;
- if (!Proxy::hasOwn(cx, obj, id, &has))
- return false;
- rval.setBoolean(has);
- return true;
- }
-
- /* Step 3. */
- if (!js_HasOwnProperty(cx, lookup, obj, id, &obj2, &prop))
- return false;
- /* Step 4,5. */
- rval.setBoolean(!!prop);
- return true;
-}
-
JSBool
js_HasOwnProperty(JSContext *cx, LookupGenericOp lookup, HandleObject obj, HandleId id,
MutableHandleObject objp, MutableHandleShape propp)
{
JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
if (lookup) {
if (!lookup(cx, obj, id, objp, propp))
return false;
@@ -540,270 +162,16 @@ js_HasOwnProperty(JSContext *cx, LookupG
return false;
}
if (outer != objp)
propp.set(NULL);
return true;
}
-/* ES5 15.2.4.6. */
-static JSBool
-obj_isPrototypeOf(JSContext *cx, unsigned argc, Value *vp)
-{
- CallArgs args = CallArgsFromVp(argc, vp);
-
- /* Step 1. */
- if (args.length() < 1 || !args[0].isObject()) {
- args.rval().setBoolean(false);
- return true;
- }
-
- /* Step 2. */
- RootedObject obj(cx, ToObject(cx, args.thisv()));
- if (!obj)
- return false;
-
- /* Step 3. */
- bool isDelegate;
- if (!IsDelegate(cx, obj, args[0], &isDelegate))
- return false;
- args.rval().setBoolean(isDelegate);
- return true;
-}
-
-/* ES5 15.2.4.7. */
-static JSBool
-obj_propertyIsEnumerable(JSContext *cx, unsigned argc, Value *vp)
-{
- CallArgs args = CallArgsFromVp(argc, vp);
-
- /* Step 1. */
- RootedId id(cx);
- if (!ValueToId(cx, args.length() ? args[0] : UndefinedValue(), id.address()))
- return false;
-
- /* Step 2. */
- RootedObject obj(cx, ToObject(cx, args.thisv()));
- if (!obj)
- return false;
-
- /* Steps 3-5. */
- return js_PropertyIsEnumerable(cx, obj, id, args.rval().address());
-}
-
-JSBool
-js_PropertyIsEnumerable(JSContext *cx, HandleObject obj, HandleId id, Value *vp)
-{
- RootedObject pobj(cx);
- RootedShape prop(cx);
- if (!JSObject::lookupGeneric(cx, obj, id, &pobj, &prop))
- return false;
-
- if (!prop) {
- vp->setBoolean(false);
- return true;
- }
-
- /*
- * ECMA spec botch: return false unless hasOwnProperty. Leaving "own" out
- * of propertyIsEnumerable's name was a mistake.
- */
- if (pobj != obj) {
- vp->setBoolean(false);
- return true;
- }
-
- unsigned attrs;
- if (!JSObject::getGenericAttributes(cx, pobj, id, &attrs))
- return false;
-
- vp->setBoolean((attrs & JSPROP_ENUMERATE) != 0);
- return true;
-}
-
-#if OLD_GETTER_SETTER_METHODS
-
-enum DefineType { Getter, Setter };
-
-template<DefineType Type>
-static bool
-DefineAccessor(JSContext *cx, unsigned argc, Value *vp)
-{
- CallArgs args = CallArgsFromVp(argc, vp);
- if (!BoxNonStrictThis(cx, args))
- return false;
-
- if (args.length() < 2 || !js_IsCallable(args[1])) {
- JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
- JSMSG_BAD_GETTER_OR_SETTER,
- Type == Getter ? js_getter_str : js_setter_str);
- return false;
- }
-
- RootedId id(cx);
- if (!ValueToId(cx, args[0], id.address()))
- return false;
-
- RootedObject descObj(cx, NewBuiltinClassInstance(cx, &ObjectClass));
- if (!descObj)
- return false;
-
- JSAtomState &names = cx->names();
- RootedValue trueVal(cx, BooleanValue(true));
-
- /* enumerable: true */
- if (!JSObject::defineProperty(cx, descObj, names.enumerable, trueVal))
- return false;
-
- /* configurable: true */
- if (!JSObject::defineProperty(cx, descObj, names.configurable, trueVal))
- return false;
-
- /* enumerable: true */
- PropertyName *acc = (Type == Getter) ? names.get : names.set;
- RootedValue accessorVal(cx, args[1]);
- if (!JSObject::defineProperty(cx, descObj, acc, accessorVal))
- return false;
-
- RootedObject thisObj(cx, &args.thisv().toObject());
-
- JSBool dummy;
- if (!js_DefineOwnProperty(cx, thisObj, id, ObjectValue(*descObj), &dummy)) {
- return false;
- }
- args.rval().setUndefined();
- return true;
-}
-
-JS_FRIEND_API(JSBool)
-js::obj_defineGetter(JSContext *cx, unsigned argc, Value *vp)
-{
- return DefineAccessor<Getter>(cx, argc, vp);
-}
-
-JS_FRIEND_API(JSBool)
-js::obj_defineSetter(JSContext *cx, unsigned argc, Value *vp)
-{
- return DefineAccessor<Setter>(cx, argc, vp);
-}
-
-static JSBool
-obj_lookupGetter(JSContext *cx, unsigned argc, Value *vp)
-{
- CallArgs args = CallArgsFromVp(argc, vp);
-
- RootedId id(cx);
- if (!ValueToId(cx, args.length() ? args[0] : UndefinedValue(), id.address()))
- return JS_FALSE;
- RootedObject obj(cx, ToObject(cx, args.thisv()));
- if (!obj)
- return JS_FALSE;
- if (obj->isProxy()) {
- // The vanilla getter lookup code below requires that the object is
- // native. Handle proxies separately.
- args.rval().setUndefined();
- AutoPropertyDescriptorRooter desc(cx);
- if (!Proxy::getPropertyDescriptor(cx, obj, id, false, &desc))
- return JS_FALSE;
- if (desc.obj && (desc.attrs & JSPROP_GETTER) && desc.getter)
- args.rval().set(CastAsObjectJsval(desc.getter));
- return JS_TRUE;
- }
- RootedObject pobj(cx);
- RootedShape shape(cx);
- if (!JSObject::lookupGeneric(cx, obj, id, &pobj, &shape))
- return JS_FALSE;
- args.rval().setUndefined();
- if (shape) {
- if (pobj->isNative()) {
- if (shape->hasGetterValue())
- args.rval().set(shape->getterValue());
- }
- }
- return JS_TRUE;
-}
-
-static JSBool
-obj_lookupSetter(JSContext *cx, unsigned argc, Value *vp)
-{
- CallArgs args = CallArgsFromVp(argc, vp);
-
- RootedId id(cx);
- if (!ValueToId(cx, args.length() ? args[0] : UndefinedValue(), id.address()))
- return JS_FALSE;
- RootedObject obj(cx, ToObject(cx, args.thisv()));
- if (!obj)
- return JS_FALSE;
- if (obj->isProxy()) {
- // The vanilla setter lookup code below requires that the object is
- // native. Handle proxies separately.
- args.rval().setUndefined();
- AutoPropertyDescriptorRooter desc(cx);
- if (!Proxy::getPropertyDescriptor(cx, obj, id, false, &desc))
- return JS_FALSE;
- if (desc.obj && (desc.attrs & JSPROP_SETTER) && desc.setter)
- args.rval().set(CastAsObjectJsval(desc.setter));
- return JS_TRUE;
- }
- RootedObject pobj(cx);
- RootedShape shape(cx);
- if (!JSObject::lookupGeneric(cx, obj, id, &pobj, &shape))
- return JS_FALSE;
- args.rval().setUndefined();
- if (shape) {
- if (pobj->isNative()) {
- if (shape->hasSetterValue())
- args.rval().set(shape->setterValue());
- }
- }
- return JS_TRUE;
-}
-#endif /* OLD_GETTER_SETTER_METHODS */
-
-/* ES5 15.2.3.2. */
-JSBool
-obj_getPrototypeOf(JSContext *cx, unsigned argc, Value *vp)
-{
- CallArgs args = CallArgsFromVp(argc, vp);
-
- /* Step 1. */
- if (args.length() == 0) {
- js_ReportMissingArg(cx, args.calleev(), 0);
- return false;
- }
-
- if (args[0].isPrimitive()) {
- RootedValue val(cx, args[0]);
- char *bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, val, NullPtr());
- if (!bytes)
- return false;
- JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
- JSMSG_UNEXPECTED_TYPE, bytes, "not an object");
- js_free(bytes);
- return false;
- }
-
- /* Step 2. */
-
- /*
- * Implement [[Prototype]]-getting -- particularly across compartment
- * boundaries -- by calling a cached __proto__ getter function.
- */
- InvokeArgsGuard nested;
- if (!cx->stack.pushInvokeArgs(cx, 0, &nested))
- return false;
- nested.setCallee(cx->global()->protoGetter());
- nested.setThis(args[0]);
- if (!Invoke(cx, nested))
- return false;
- args.rval().set(nested.rval());
- return true;
-}
-
bool
js::NewPropertyDescriptorObject(JSContext *cx, const PropertyDescriptor *desc, Value *vp)
{
if (!desc->obj) {
vp->setUndefined();
return true;
}
@@ -952,65 +320,16 @@ js::GetFirstArgumentAsObject(JSContext *
js_free(bytes);
return false;
}
objp.set(&v.toObject());
return true;
}
-static JSBool
-obj_getOwnPropertyDescriptor(JSContext *cx, unsigned argc, Value *vp)
-{
- RootedObject obj(cx);
- if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.getOwnPropertyDescriptor", &obj))
- return JS_FALSE;
- RootedId id(cx);
- if (!ValueToId(cx, argc >= 2 ? vp[3] : UndefinedValue(), id.address()))
- return JS_FALSE;
- return GetOwnPropertyDescriptor(cx, obj, id, vp);
-}
-
-static JSBool
-obj_keys(JSContext *cx, unsigned argc, Value *vp)
-{
- RootedObject obj(cx);
- if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.keys", &obj))
- return false;
-
- AutoIdVector props(cx);
- if (!GetPropertyNames(cx, obj, JSITER_OWNONLY, &props))
- return false;
-
- AutoValueVector vals(cx);
- if (!vals.reserve(props.length()))
- return false;
- for (size_t i = 0, len = props.length(); i < len; i++) {
- jsid id = props[i];
- if (JSID_IS_STRING(id)) {
- vals.infallibleAppend(StringValue(JSID_TO_STRING(id)));
- } else if (JSID_IS_INT(id)) {
- JSString *str = Int32ToString(cx, JSID_TO_INT(id));
- if (!str)
- return false;
- vals.infallibleAppend(StringValue(str));
- } else {
- JS_ASSERT(JSID_IS_OBJECT(id));
- }
- }
-
- JS_ASSERT(props.length() <= UINT32_MAX);
- JSObject *aobj = NewDenseCopiedArray(cx, uint32_t(vals.length()), vals.begin());
- if (!aobj)
- return false;
- vp->setObject(*aobj);
-
- return true;
-}
-
static bool
HasProperty(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue vp, bool *foundp)
{
if (!JSObject::hasProperty(cx, obj, id, foundp, JSRESOLVE_QUALIFIED))
return false;
if (!*foundp) {
vp.setUndefined();
return true;
@@ -1629,37 +948,16 @@ js_DefineOwnProperty(JSContext *cx, Hand
bool rval;
if (!DefineProperty(cx, obj, id, *desc, true, &rval))
return false;
*bp = !!rval;
return true;
}
-/* ES5 15.2.3.6: Object.defineProperty(O, P, Attributes) */
-static JSBool
-obj_defineProperty(JSContext *cx, unsigned argc, Value *vp)
-{
- RootedObject obj(cx);
- if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.defineProperty", &obj))
- return false;
-
- RootedId id(cx);
- if (!ValueToId(cx, argc >= 2 ? vp[3] : UndefinedValue(), id.address()))
- return JS_FALSE;
-
- const Value descval = argc >= 3 ? vp[4] : UndefinedValue();
-
- JSBool junk;
- if (!js_DefineOwnProperty(cx, obj, id, descval, &junk))
- return false;
-
- vp->setObject(*obj);
- return true;
-}
bool
js::ReadPropertyDescriptors(JSContext *cx, HandleObject props, bool checkAccessors,
AutoIdVector *ids, AutoPropDescArrayRooter *descs)
{
if (!GetPropertyNames(cx, props, JSITER_OWNONLY, ids))
return false;
@@ -1696,163 +994,16 @@ DefineProperties(JSContext *cx, HandleOb
}
extern JSBool
js_PopulateObject(JSContext *cx, HandleObject newborn, HandleObject props)
{
return DefineProperties(cx, newborn, props);
}
-/* ES5 15.2.3.7: Object.defineProperties(O, Properties) */
-static JSBool
-obj_defineProperties(JSContext *cx, unsigned argc, Value *vp)
-{
- CallArgs args = CallArgsFromVp(argc, vp);
-
- /* Steps 1 and 7. */
- RootedObject obj(cx);
- if (!GetFirstArgumentAsObject(cx, args.length(), vp, "Object.defineProperties", &obj))
- return false;
- args.rval().setObject(*obj);
-
- /* Step 2. */
- if (args.length() < 2) {
- JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED,
- "Object.defineProperties", "0", "s");
- return false;
- }
- RootedValue val(cx, args[1]);
- RootedObject props(cx, ToObject(cx, val));
- if (!props)
- return false;
-
- /* Steps 3-6. */
- return DefineProperties(cx, obj, props);
-}
-
-/* ES5 15.2.3.5: Object.create(O [, Properties]) */
-static JSBool
-obj_create(JSContext *cx, unsigned argc, Value *vp)
-{
- if (argc == 0) {
- JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED,
- "Object.create", "0", "s");
- return false;
- }
-
- CallArgs args = CallArgsFromVp(argc, vp);
- RootedValue v(cx, args[0]);
- if (!v.isObjectOrNull()) {
- char *bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, v, NullPtr());
- if (!bytes)
- return false;
- JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_UNEXPECTED_TYPE,
- bytes, "not an object or null");
- js_free(bytes);
- return false;
- }
-
- JSObject *proto = v.toObjectOrNull();
-#if JS_HAS_XML_SUPPORT
- if (proto && proto->isXML()) {
- JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_XML_PROTO_FORBIDDEN);
- return false;
- }
-#endif
-
- /*
- * Use the callee's global as the parent of the new object to avoid dynamic
- * scoping (i.e., using the caller's global).
- */
- RootedObject obj(cx, NewObjectWithGivenProto(cx, &ObjectClass, proto, &args.callee().global()));
- if (!obj)
- return false;
-
- /* Don't track types or array-ness for objects created here. */
- MarkTypeObjectUnknownProperties(cx, obj->type());
-
- /* 15.2.3.5 step 4. */
- if (args.hasDefined(1)) {
- if (args[1].isPrimitive()) {
- JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_NONNULL_OBJECT);
- return false;
- }
-
- RootedObject props(cx, &args[1].toObject());
- if (!DefineProperties(cx, obj, props))
- return false;
- }
-
- /* 5. Return obj. */
- args.rval().setObject(*obj);
- return true;
-}
-
-static JSBool
-obj_getOwnPropertyNames(JSContext *cx, unsigned argc, Value *vp)
-{
- RootedObject obj(cx);
- if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.getOwnPropertyNames", &obj))
- return false;
-
- AutoIdVector keys(cx);
- if (!GetPropertyNames(cx, obj, JSITER_OWNONLY | JSITER_HIDDEN, &keys))
- return false;
-
- AutoValueVector vals(cx);
- if (!vals.resize(keys.length()))
- return false;
-
- for (size_t i = 0, len = keys.length(); i < len; i++) {
- jsid id = keys[i];
- if (JSID_IS_INT(id)) {
- JSString *str = Int32ToString(cx, JSID_TO_INT(id));
- if (!str)
- return false;
- vals[i].setString(str);
- } else if (JSID_IS_ATOM(id)) {
- vals[i].setString(JSID_TO_STRING(id));
- } else {
- vals[i].setObject(*JSID_TO_OBJECT(id));
- }
- }
-
- JSObject *aobj = NewDenseCopiedArray(cx, vals.length(), vals.begin());
- if (!aobj)
- return false;
-
- vp->setObject(*aobj);
- return true;
-}
-
-static JSBool
-obj_isExtensible(JSContext *cx, unsigned argc, Value *vp)
-{
- RootedObject obj(cx);
- if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.isExtensible", &obj))
- return false;
-
- vp->setBoolean(obj->isExtensible());
- return true;
-}
-
-static JSBool
-obj_preventExtensions(JSContext *cx, unsigned argc, Value *vp)
-{
- RootedObject obj(cx);
- if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.preventExtensions", &obj))
- return false;
-
- vp->setObject(*obj);
- if (!obj->isExtensible())
- return true;
-
- return obj->preventExtensions(cx);
-}
-
/* static */ inline unsigned
JSObject::getSealedOrFrozenAttributes(unsigned attrs, ImmutabilityType it)
{
/* Make all attributes permanent; if freezing, make data attributes read-only. */
if (it == FREEZE && !(attrs & (JSPROP_GETTER | JSPROP_SETTER)))
return JSPROP_PERMANENT | JSPROP_READONLY;
return JSPROP_PERMANENT;
}
@@ -1968,153 +1119,30 @@ JSObject::isSealedOrFrozen(JSContext *cx
}
}
/* All properties checked out. This object is sealed/frozen. */
*resultp = true;
return true;
}
-static JSBool
-obj_freeze(JSContext *cx, unsigned argc, Value *vp)
-{
- RootedObject obj(cx);
- if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.freeze", &obj))
- return false;
-
- vp->setObject(*obj);
-
- return JSObject::freeze(cx, obj);
-}
-
-static JSBool
-obj_isFrozen(JSContext *cx, unsigned argc, Value *vp)
-{
- RootedObject obj(cx);
- if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.preventExtensions", &obj))
- return false;
-
- bool frozen;
- if (!JSObject::isFrozen(cx, obj, &frozen))
- return false;
- vp->setBoolean(frozen);
- return true;
-}
-
-static JSBool
-obj_seal(JSContext *cx, unsigned argc, Value *vp)
-{
- RootedObject obj(cx);
- if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.seal", &obj))
- return false;
-
- vp->setObject(*obj);
-
- return JSObject::seal(cx, obj);
-}
-
-static JSBool
-obj_isSealed(JSContext *cx, unsigned argc, Value *vp)
-{
- RootedObject obj(cx);
- if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.isSealed", &obj))
- return false;
-
- bool sealed;
- if (!JSObject::isSealed(cx, obj, &sealed))
- return false;
- vp->setBoolean(sealed);
- return true;
-}
-
-JSFunctionSpec object_methods[] = {
-#if JS_HAS_TOSOURCE
- JS_FN(js_toSource_str, obj_toSource, 0,0),
-#endif
- JS_FN(js_toString_str, obj_toString, 0,0),
- JS_FN(js_toLocaleString_str, obj_toLocaleString, 0,0),
- JS_FN(js_valueOf_str, obj_valueOf, 0,0),
-#if JS_HAS_OBJ_WATCHPOINT
- JS_FN(js_watch_str, obj_watch, 2,0),
- JS_FN(js_unwatch_str, obj_unwatch, 1,0),
-#endif
- JS_FN(js_hasOwnProperty_str, obj_hasOwnProperty, 1,0),
- JS_FN(js_isPrototypeOf_str, obj_isPrototypeOf, 1,0),
- JS_FN(js_propertyIsEnumerable_str, obj_propertyIsEnumerable, 1,0),
-#if OLD_GETTER_SETTER_METHODS
- JS_FN(js_defineGetter_str, js::obj_defineGetter, 2,0),
- JS_FN(js_defineSetter_str, js::obj_defineSetter, 2,0),
- JS_FN(js_lookupGetter_str, obj_lookupGetter, 1,0),
- JS_FN(js_lookupSetter_str, obj_lookupSetter, 1,0),
-#endif
- JS_FS_END
-};
-
-JSFunctionSpec object_static_methods[] = {
- JS_FN("getPrototypeOf", obj_getPrototypeOf, 1,0),
- JS_FN("getOwnPropertyDescriptor", obj_getOwnPropertyDescriptor,2,0),
- JS_FN("keys", obj_keys, 1,0),
- JS_FN("defineProperty", obj_defineProperty, 3,0),
- JS_FN("defineProperties", obj_defineProperties, 2,0),
- JS_FN("create", obj_create, 2,0),
- JS_FN("getOwnPropertyNames", obj_getOwnPropertyNames, 1,0),
- JS_FN("isExtensible", obj_isExtensible, 1,0),
- JS_FN("preventExtensions", obj_preventExtensions, 1,0),
- JS_FN("freeze", obj_freeze, 1,0),
- JS_FN("isFrozen", obj_isFrozen, 1,0),
- JS_FN("seal", obj_seal, 1,0),
- JS_FN("isSealed", obj_isSealed, 1,0),
- JS_FS_END
-};
-
/*
* Get the GC kind to use for scripted 'new' on the given class.
* FIXME bug 547327: estimate the size from the allocation site.
*/
static inline gc::AllocKind
NewObjectGCKind(js::Class *clasp)
{
if (clasp == &ArrayClass || clasp == &SlowArrayClass)
return gc::FINALIZE_OBJECT8;
if (clasp == &FunctionClass)
return gc::FINALIZE_OBJECT2;
return gc::FINALIZE_OBJECT4;
}
-JSBool
-js_Object(JSContext *cx, unsigned argc, Value *vp)
-{
- RootedObject obj(cx);
- if (argc == 0) {
- /* Trigger logic below to construct a blank object. */
- obj = NULL;
- } else {
- /* If argv[0] is null or undefined, obj comes back null. */
- if (!js_ValueToObjectOrNull(cx, vp[2], &obj))
- return JS_FALSE;
- }
- if (!obj) {
- /* Make an object whether this was called with 'new' or not. */
- JS_ASSERT(!argc || vp[2].isNull() || vp[2].isUndefined());
- gc::AllocKind kind = NewObjectGCKind(&ObjectClass);
- obj = NewBuiltinClassInstance(cx, &ObjectClass, kind);
- if (!obj)
- return JS_FALSE;
- jsbytecode *pc;
- RootedScript script(cx, cx->stack.currentScript(&pc));
- if (script) {
- /* Try to specialize the type of the object to the scripted call site. */
- if (!types::SetInitializerObjectType(cx, script, pc, obj))
- return JS_FALSE;
- }
- }
- vp->setObject(*obj);
- return JS_TRUE;
-}
-
static inline JSObject *
NewObject(JSContext *cx, Class *clasp, types::TypeObject *type_, JSObject *parent,
gc::AllocKind kind)
{
AssertCanGC();
JS_ASSERT(clasp != &ArrayClass);
JS_ASSERT_IF(clasp == &FunctionClass,
kind == JSFunction::FinalizeKind || kind == JSFunction::ExtendedFinalizeKind);
@@ -2275,16 +1303,36 @@ js::NewObjectWithType(JSContext *cx, Han
return NULL;
if (entry != -1 && !obj->hasDynamicSlots())
cache.fillType(entry, &ObjectClass, type, kind, obj);
return obj;
}
+bool
+js::NewObjectScriptedCall(JSContext *cx, MutableHandleObject pobj)
+{
+ gc::AllocKind kind = NewObjectGCKind(&ObjectClass);
+ RootedObject obj(cx, NewBuiltinClassInstance(cx, &ObjectClass, kind));
+ if (!obj)
+ return false;
+
+ jsbytecode *pc;
+ RootedScript script(cx, cx->stack.currentScript(&pc));
+ if (script) {
+ /* Try to specialize the type of the object to the scripted call site. */
+ if (!types::SetInitializerObjectType(cx, script, pc, obj))
+ return false;
+ }
+
+ pobj.set(obj);
+ return true;
+}
+
JSObject *
js::NewReshapedObject(JSContext *cx, HandleTypeObject type, JSObject *parent,
gc::AllocKind kind, HandleShape shape)
{
RootedObject res(cx, NewObjectWithType(cx, type, parent, kind));
if (!res)
return NULL;
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -1097,28 +1097,19 @@ class ValueArray {
public:
js::Value *array;
size_t length;
ValueArray(js::Value *v, size_t c) : array(v), length(c) {}
};
extern JSBool
-js_HasOwnPropertyHelper(JSContext *cx, js::LookupGenericOp lookup, js::HandleObject obj,
- js::HandleId id, js::MutableHandleValue rval);
-
-extern JSBool
js_HasOwnProperty(JSContext *cx, js::LookupGenericOp lookup, js::HandleObject obj, js::HandleId id,
js::MutableHandleObject objp, js::MutableHandleShape propp);
-extern JSBool
-js_PropertyIsEnumerable(JSContext *cx, js::HandleObject obj, js::HandleId id, js::Value *vp);
-
-extern JSFunctionSpec object_methods[];
-extern JSFunctionSpec object_static_methods[];
namespace js {
bool
IsStandardClassResolved(JSObject *obj, js::Class *clasp);
void
MarkStandardClassInitializedNoProto(JSObject *obj, js::Class *clasp);
@@ -1409,19 +1400,16 @@ extern void
js_GetObjectSlotName(JSTracer *trc, char *buf, size_t bufsize);
extern JSBool
js_ReportGetterOnlyAssignment(JSContext *cx);
extern unsigned
js_InferFlags(JSContext *cx, unsigned defaultFlags);
-/* Object constructor native. Exposed only so the JIT can know its address. */
-JSBool
-js_Object(JSContext *cx, unsigned argc, js::Value *vp);
/*
* If protoKey is not JSProto_Null, then clasp is ignored. If protoKey is
* JSProto_Null, clasp must non-null.
*
* If protoKey is constant and scope is non-null, use GlobalObject's prototype
* methods instead.
*/
@@ -1429,19 +1417,16 @@ extern JS_FRIEND_API(bool)
js_GetClassPrototype(JSContext *cx, JSProtoKey protoKey, js::MutableHandleObject protop,
js::Class *clasp = NULL);
namespace js {
extern bool
SetProto(JSContext *cx, HandleObject obj, Handle<TaggedProto> proto, bool checkForCycles);
-extern JSString *
-obj_toStringHelper(JSContext *cx, JSObject *obj);
-
extern JSObject *
NonNullObject(JSContext *cx, const Value &v);
extern const char *
InformalValueTypeName(const Value &v);
inline void
DestroyIdArray(FreeOp *fop, JSIdArray *ida);
--- a/js/src/jsobjinlines.h
+++ b/js/src/jsobjinlines.h
@@ -1501,16 +1501,20 @@ FindClassPrototype(JSContext *cx, Handle
/*
* Create a plain object with the specified type. This bypasses getNewType to
* avoid losing creation site information for objects made by scripted 'new'.
*/
JSObject *
NewObjectWithType(JSContext *cx, HandleTypeObject type, JSObject *parent, gc::AllocKind kind);
+// Used to optimize calls to (new Object())
+bool
+NewObjectScriptedCall(JSContext *cx, MutableHandleObject obj);
+
/* Make an object with pregenerated shape from a NEWOBJECT bytecode. */
static inline JSObject *
CopyInitializerObject(JSContext *cx, HandleObject baseobj)
{
JS_ASSERT(baseobj->getClass() == &ObjectClass);
JS_ASSERT(!baseobj->inDictionaryMode());
gc::AllocKind kind = gc::GetGCObjectFixedSlotsKind(baseobj->numFixedSlots());
--- a/js/src/jsxml.cpp
+++ b/js/src/jsxml.cpp
@@ -5882,17 +5882,23 @@ xml_hasOwnProperty(JSContext *cx, unsign
if (found) {
args.rval().setBoolean(true);
return true;
}
RootedId id(cx);
if (!ValueToId(cx, name, id.address()))
return false;
- return js_HasOwnPropertyHelper(cx, baseops::LookupProperty, obj, id, args.rval());
+
+ RootedObject obj2(cx);
+ RootedShape prop(cx);
+ if (!js_HasOwnProperty(cx, baseops::LookupProperty, obj, id, &obj2, &prop))
+ return false;
+ args.rval().setBoolean(!!prop);
+ return true;
}
/* XML and XMLList */
static JSBool
xml_hasComplexContent(JSContext *cx, unsigned argc, jsval *vp)
{
JSXML *kid;
JSObject *kidobj;
--- a/js/src/vm/GlobalObject.cpp
+++ b/js/src/vm/GlobalObject.cpp
@@ -13,16 +13,17 @@
#include "jsfriendapi.h"
#include "jsmath.h"
#include "json.h"
#include "jsweakmap.h"
#include "builtin/Eval.h"
#include "builtin/Intl.h"
#include "builtin/MapObject.h"
+#include "builtin/Object.h"
#include "builtin/RegExp.h"
#include "frontend/BytecodeEmitter.h"
#include "jsobjinlines.h"
#include "vm/GlobalObject-inl.h"
#include "vm/RegExpObject-inl.h"
#include "vm/RegExpStatics-inl.h"
@@ -268,17 +269,17 @@ GlobalObject::initFunctionAndObjectClass
/* Create the Object function now that we have a [[Prototype]] for it. */
RootedFunction objectCtor(cx);
{
RootedObject ctor(cx, NewObjectWithGivenProto(cx, &FunctionClass, functionProto, self));
if (!ctor)
return NULL;
RootedAtom objectAtom(cx, cx->names().Object);
- objectCtor = js_NewFunction(cx, ctor, js_Object, 1, JSFunction::NATIVE_CTOR, self,
+ objectCtor = js_NewFunction(cx, ctor, obj_construct, 1, JSFunction::NATIVE_CTOR, self,
objectAtom);
if (!objectCtor)
return NULL;
}
/*
* Install |Object| and |Object.prototype| for the benefit of subsequent
* code that looks for them.