js/src/builtin/Object.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     2  * vim: set ts=8 sts=4 et sw=4 tw=99:
     3  * This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 #include "builtin/Object.h"
     9 #include "mozilla/ArrayUtils.h"
    11 #include "jscntxt.h"
    13 #include "frontend/BytecodeCompiler.h"
    14 #include "vm/StringBuffer.h"
    16 #include "jsobjinlines.h"
    18 #include "vm/ObjectImpl-inl.h"
    20 using namespace js;
    21 using namespace js::types;
    23 using js::frontend::IsIdentifier;
    24 using mozilla::ArrayLength;
    27 bool
    28 js::obj_construct(JSContext *cx, unsigned argc, Value *vp)
    29 {
    30     CallArgs args = CallArgsFromVp(argc, vp);
    32     RootedObject obj(cx, nullptr);
    33     if (args.length() > 0 && !args[0].isNullOrUndefined()) {
    34         obj = ToObject(cx, args[0]);
    35         if (!obj)
    36             return false;
    37     } else {
    38         /* Make an object whether this was called with 'new' or not. */
    39         if (!NewObjectScriptedCall(cx, &obj))
    40             return false;
    41     }
    43     args.rval().setObject(*obj);
    44     return true;
    45 }
    47 /* ES5 15.2.4.7. */
    48 static bool
    49 obj_propertyIsEnumerable(JSContext *cx, unsigned argc, Value *vp)
    50 {
    51     CallArgs args = CallArgsFromVp(argc, vp);
    53     /* Step 1. */
    54     RootedId id(cx);
    55     if (!ValueToId<CanGC>(cx, args.get(0), &id))
    56         return false;
    58     /* Step 2. */
    59     RootedObject obj(cx, ToObject(cx, args.thisv()));
    60     if (!obj)
    61         return false;
    63     /* Steps 3. */
    64     RootedObject pobj(cx);
    65     RootedShape prop(cx);
    66     if (!JSObject::lookupGeneric(cx, obj, id, &pobj, &prop))
    67         return false;
    69     /* Step 4. */
    70     if (!prop) {
    71         args.rval().setBoolean(false);
    72         return true;
    73     }
    75     if (pobj != obj) {
    76         args.rval().setBoolean(false);
    77         return true;
    78     }
    80     /* Step 5. */
    81     unsigned attrs;
    82     if (!JSObject::getGenericAttributes(cx, pobj, id, &attrs))
    83         return false;
    85     args.rval().setBoolean((attrs & JSPROP_ENUMERATE) != 0);
    86     return true;
    87 }
    89 #if JS_HAS_TOSOURCE
    90 static bool
    91 obj_toSource(JSContext *cx, unsigned argc, Value *vp)
    92 {
    93     CallArgs args = CallArgsFromVp(argc, vp);
    94     JS_CHECK_RECURSION(cx, return false);
    96     RootedObject obj(cx, ToObject(cx, args.thisv()));
    97     if (!obj)
    98         return false;
   100     JSString *str = ObjectToSource(cx, obj);
   101     if (!str)
   102         return false;
   104     args.rval().setString(str);
   105     return true;
   106 }
   108 JSString *
   109 js::ObjectToSource(JSContext *cx, HandleObject obj)
   110 {
   111     /* If outermost, we need parentheses to be an expression, not a block. */
   112     bool outermost = (cx->cycleDetectorSet.count() == 0);
   114     AutoCycleDetector detector(cx, obj);
   115     if (!detector.init())
   116         return nullptr;
   117     if (detector.foundCycle())
   118         return js_NewStringCopyZ<CanGC>(cx, "{}");
   120     StringBuffer buf(cx);
   121     if (outermost && !buf.append('('))
   122         return nullptr;
   123     if (!buf.append('{'))
   124         return nullptr;
   126     RootedValue v0(cx), v1(cx);
   127     MutableHandleValue val[2] = {&v0, &v1};
   129     RootedString str0(cx), str1(cx);
   130     MutableHandleString gsop[2] = {&str0, &str1};
   132     AutoIdVector idv(cx);
   133     if (!GetPropertyNames(cx, obj, JSITER_OWNONLY, &idv))
   134         return nullptr;
   136     bool comma = false;
   137     for (size_t i = 0; i < idv.length(); ++i) {
   138         RootedId id(cx, idv[i]);
   139         RootedObject obj2(cx);
   140         RootedShape shape(cx);
   141         if (!JSObject::lookupGeneric(cx, obj, id, &obj2, &shape))
   142             return nullptr;
   144         /*  Decide early whether we prefer get/set or old getter/setter syntax. */
   145         int valcnt = 0;
   146         if (shape) {
   147             bool doGet = true;
   148             if (obj2->isNative() && !IsImplicitDenseOrTypedArrayElement(shape)) {
   149                 unsigned attrs = shape->attributes();
   150                 if (attrs & JSPROP_GETTER) {
   151                     doGet = false;
   152                     val[valcnt].set(shape->getterValue());
   153                     gsop[valcnt].set(cx->names().get);
   154                     valcnt++;
   155                 }
   156                 if (attrs & JSPROP_SETTER) {
   157                     doGet = false;
   158                     val[valcnt].set(shape->setterValue());
   159                     gsop[valcnt].set(cx->names().set);
   160                     valcnt++;
   161                 }
   162             }
   163             if (doGet) {
   164                 valcnt = 1;
   165                 gsop[0].set(nullptr);
   166                 if (!JSObject::getGeneric(cx, obj, obj, id, val[0]))
   167                     return nullptr;
   168             }
   169         }
   171         /* Convert id to a linear string. */
   172         RootedValue idv(cx, IdToValue(id));
   173         JSString *s = ToString<CanGC>(cx, idv);
   174         if (!s)
   175             return nullptr;
   176         Rooted<JSLinearString*> idstr(cx, s->ensureLinear(cx));
   177         if (!idstr)
   178             return nullptr;
   180         /*
   181          * If id is a string that's not an identifier, or if it's a negative
   182          * integer, then it must be quoted.
   183          */
   184         if (JSID_IS_ATOM(id)
   185             ? !IsIdentifier(idstr)
   186             : (!JSID_IS_INT(id) || JSID_TO_INT(id) < 0))
   187         {
   188             s = js_QuoteString(cx, idstr, jschar('\''));
   189             if (!s || !(idstr = s->ensureLinear(cx)))
   190                 return nullptr;
   191         }
   193         for (int j = 0; j < valcnt; j++) {
   194             /*
   195              * Censor an accessor descriptor getter or setter part if it's
   196              * undefined.
   197              */
   198             if (gsop[j] && val[j].isUndefined())
   199                 continue;
   201             /* Convert val[j] to its canonical source form. */
   202             RootedString valstr(cx, ValueToSource(cx, val[j]));
   203             if (!valstr)
   204                 return nullptr;
   205             const jschar *vchars = valstr->getChars(cx);
   206             if (!vchars)
   207                 return nullptr;
   208             size_t vlength = valstr->length();
   210             /*
   211              * Remove '(function ' from the beginning of valstr and ')' from the
   212              * end so that we can put "get" in front of the function definition.
   213              */
   214             if (gsop[j] && IsFunctionObject(val[j])) {
   215                 const jschar *start = vchars;
   216                 const jschar *end = vchars + vlength;
   218                 uint8_t parenChomp = 0;
   219                 if (vchars[0] == '(') {
   220                     vchars++;
   221                     parenChomp = 1;
   222                 }
   224                 /* Try to jump "function" keyword. */
   225                 if (vchars)
   226                     vchars = js_strchr_limit(vchars, ' ', end);
   228                 /*
   229                  * Jump over the function's name: it can't be encoded as part
   230                  * of an ECMA getter or setter.
   231                  */
   232                 if (vchars)
   233                     vchars = js_strchr_limit(vchars, '(', end);
   235                 if (vchars) {
   236                     if (*vchars == ' ')
   237                         vchars++;
   238                     vlength = end - vchars - parenChomp;
   239                 } else {
   240                     gsop[j].set(nullptr);
   241                     vchars = start;
   242                 }
   243             }
   245             if (comma && !buf.append(", "))
   246                 return nullptr;
   247             comma = true;
   249             if (gsop[j])
   250                 if (!buf.append(gsop[j]) || !buf.append(' '))
   251                     return nullptr;
   253             if (!buf.append(idstr))
   254                 return nullptr;
   255             if (!buf.append(gsop[j] ? ' ' : ':'))
   256                 return nullptr;
   258             if (!buf.append(vchars, vlength))
   259                 return nullptr;
   260         }
   261     }
   263     if (!buf.append('}'))
   264         return nullptr;
   265     if (outermost && !buf.append(')'))
   266         return nullptr;
   268     return buf.finishString();
   269 }
   270 #endif /* JS_HAS_TOSOURCE */
   272 JSString *
   273 JS_BasicObjectToString(JSContext *cx, HandleObject obj)
   274 {
   275     // Some classes are really common, don't allocate new strings for them.
   276     // The ordering below is based on the measurements in bug 966264.
   277     if (obj->is<JSObject>())
   278         return cx->names().objectObject;
   279     if (obj->is<StringObject>())
   280         return cx->names().objectString;
   281     if (obj->is<ArrayObject>())
   282         return cx->names().objectArray;
   283     if (obj->is<JSFunction>())
   284         return cx->names().objectFunction;
   285     if (obj->is<NumberObject>())
   286         return cx->names().objectNumber;
   288     const char *className = JSObject::className(cx, obj);
   290     if (strcmp(className, "Window") == 0)
   291         return cx->names().objectWindow;
   293     StringBuffer sb(cx);
   294     if (!sb.append("[object ") || !sb.appendInflated(className, strlen(className)) ||
   295         !sb.append("]"))
   296     {
   297         return nullptr;
   298     }
   299     return sb.finishString();
   300 }
   302 /* ES5 15.2.4.2.  Note steps 1 and 2 are errata. */
   303 static bool
   304 obj_toString(JSContext *cx, unsigned argc, Value *vp)
   305 {
   306     CallArgs args = CallArgsFromVp(argc, vp);
   308     /* Step 1. */
   309     if (args.thisv().isUndefined()) {
   310         args.rval().setString(cx->names().objectUndefined);
   311         return true;
   312     }
   314     /* Step 2. */
   315     if (args.thisv().isNull()) {
   316         args.rval().setString(cx->names().objectNull);
   317         return true;
   318     }
   320     /* Step 3. */
   321     RootedObject obj(cx, ToObject(cx, args.thisv()));
   322     if (!obj)
   323         return false;
   325     /* Steps 4-5. */
   326     JSString *str = JS_BasicObjectToString(cx, obj);
   327     if (!str)
   328         return false;
   329     args.rval().setString(str);
   330     return true;
   331 }
   333 /* ES5 15.2.4.3. */
   334 static bool
   335 obj_toLocaleString(JSContext *cx, unsigned argc, Value *vp)
   336 {
   337     JS_CHECK_RECURSION(cx, return false);
   339     CallArgs args = CallArgsFromVp(argc, vp);
   341     /* Step 1. */
   342     RootedObject obj(cx, ToObject(cx, args.thisv()));
   343     if (!obj)
   344         return false;
   346     /* Steps 2-4. */
   347     RootedId id(cx, NameToId(cx->names().toString));
   348     return obj->callMethod(cx, id, 0, nullptr, args.rval());
   349 }
   351 static bool
   352 obj_valueOf(JSContext *cx, unsigned argc, Value *vp)
   353 {
   354     CallArgs args = CallArgsFromVp(argc, vp);
   355     RootedObject obj(cx, ToObject(cx, args.thisv()));
   356     if (!obj)
   357         return false;
   358     args.rval().setObject(*obj);
   359     return true;
   360 }
   362 #if JS_OLD_GETTER_SETTER_METHODS
   364 enum DefineType { GetterAccessor, SetterAccessor };
   366 template<DefineType Type>
   367 static bool
   368 DefineAccessor(JSContext *cx, unsigned argc, Value *vp)
   369 {
   370     CallArgs args = CallArgsFromVp(argc, vp);
   371     if (!BoxNonStrictThis(cx, args))
   372         return false;
   374     if (args.length() < 2 || !js_IsCallable(args[1])) {
   375         JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr,
   376                              JSMSG_BAD_GETTER_OR_SETTER,
   377                              Type == GetterAccessor ? js_getter_str : js_setter_str);
   378         return false;
   379     }
   381     RootedId id(cx);
   382     if (!ValueToId<CanGC>(cx, args[0], &id))
   383         return false;
   385     RootedObject descObj(cx, NewBuiltinClassInstance(cx, &JSObject::class_));
   386     if (!descObj)
   387         return false;
   389     JSAtomState &names = cx->names();
   390     RootedValue trueVal(cx, BooleanValue(true));
   392     /* enumerable: true */
   393     if (!JSObject::defineProperty(cx, descObj, names.enumerable, trueVal))
   394         return false;
   396     /* configurable: true */
   397     if (!JSObject::defineProperty(cx, descObj, names.configurable, trueVal))
   398         return false;
   400     /* enumerable: true */
   401     PropertyName *acc = (Type == GetterAccessor) ? names.get : names.set;
   402     RootedValue accessorVal(cx, args[1]);
   403     if (!JSObject::defineProperty(cx, descObj, acc, accessorVal))
   404         return false;
   406     RootedObject thisObj(cx, &args.thisv().toObject());
   408     bool dummy;
   409     RootedValue descObjValue(cx, ObjectValue(*descObj));
   410     if (!DefineOwnProperty(cx, thisObj, id, descObjValue, &dummy))
   411         return false;
   413     args.rval().setUndefined();
   414     return true;
   415 }
   417 JS_FRIEND_API(bool)
   418 js::obj_defineGetter(JSContext *cx, unsigned argc, Value *vp)
   419 {
   420     return DefineAccessor<GetterAccessor>(cx, argc, vp);
   421 }
   423 JS_FRIEND_API(bool)
   424 js::obj_defineSetter(JSContext *cx, unsigned argc, Value *vp)
   425 {
   426     return DefineAccessor<SetterAccessor>(cx, argc, vp);
   427 }
   429 static bool
   430 obj_lookupGetter(JSContext *cx, unsigned argc, Value *vp)
   431 {
   432     CallArgs args = CallArgsFromVp(argc, vp);
   434     RootedId id(cx);
   435     if (!ValueToId<CanGC>(cx, args.get(0), &id))
   436         return false;
   437     RootedObject obj(cx, ToObject(cx, args.thisv()));
   438     if (!obj)
   439         return false;
   440     if (obj->is<ProxyObject>()) {
   441         // The vanilla getter lookup code below requires that the object is
   442         // native. Handle proxies separately.
   443         args.rval().setUndefined();
   444         Rooted<PropertyDescriptor> desc(cx);
   445         if (!Proxy::getPropertyDescriptor(cx, obj, id, &desc))
   446             return false;
   447         if (desc.object() && desc.hasGetterObject() && desc.getterObject())
   448             args.rval().setObject(*desc.getterObject());
   449         return true;
   450     }
   451     RootedObject pobj(cx);
   452     RootedShape shape(cx);
   453     if (!JSObject::lookupGeneric(cx, obj, id, &pobj, &shape))
   454         return false;
   455     args.rval().setUndefined();
   456     if (shape) {
   457         if (pobj->isNative() && !IsImplicitDenseOrTypedArrayElement(shape)) {
   458             if (shape->hasGetterValue())
   459                 args.rval().set(shape->getterValue());
   460         }
   461     }
   462     return true;
   463 }
   465 static bool
   466 obj_lookupSetter(JSContext *cx, unsigned argc, Value *vp)
   467 {
   468     CallArgs args = CallArgsFromVp(argc, vp);
   470     RootedId id(cx);
   471     if (!ValueToId<CanGC>(cx, args.get(0), &id))
   472         return false;
   473     RootedObject obj(cx, ToObject(cx, args.thisv()));
   474     if (!obj)
   475         return false;
   476     if (obj->is<ProxyObject>()) {
   477         // The vanilla setter lookup code below requires that the object is
   478         // native. Handle proxies separately.
   479         args.rval().setUndefined();
   480         Rooted<PropertyDescriptor> desc(cx);
   481         if (!Proxy::getPropertyDescriptor(cx, obj, id, &desc))
   482             return false;
   483         if (desc.object() && desc.hasSetterObject() && desc.setterObject())
   484             args.rval().setObject(*desc.setterObject());
   485         return true;
   486     }
   487     RootedObject pobj(cx);
   488     RootedShape shape(cx);
   489     if (!JSObject::lookupGeneric(cx, obj, id, &pobj, &shape))
   490         return false;
   491     args.rval().setUndefined();
   492     if (shape) {
   493         if (pobj->isNative() && !IsImplicitDenseOrTypedArrayElement(shape)) {
   494             if (shape->hasSetterValue())
   495                 args.rval().set(shape->setterValue());
   496         }
   497     }
   498     return true;
   499 }
   500 #endif /* JS_OLD_GETTER_SETTER_METHODS */
   502 /* ES5 15.2.3.2. */
   503 static bool
   504 obj_getPrototypeOf(JSContext *cx, unsigned argc, Value *vp)
   505 {
   506     CallArgs args = CallArgsFromVp(argc, vp);
   508     /* Step 1. */
   509     if (args.length() == 0) {
   510         js_ReportMissingArg(cx, args.calleev(), 0);
   511         return false;
   512     }
   514     if (args[0].isPrimitive()) {
   515         RootedValue val(cx, args[0]);
   516         char *bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, val, NullPtr());
   517         if (!bytes)
   518             return false;
   519         JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr,
   520                              JSMSG_UNEXPECTED_TYPE, bytes, "not an object");
   521         js_free(bytes);
   522         return false;
   523     }
   525     /* Step 2. */
   527     /*
   528      * Implement [[Prototype]]-getting -- particularly across compartment
   529      * boundaries -- by calling a cached __proto__ getter function.
   530      */
   531     InvokeArgs args2(cx);
   532     if (!args2.init(0))
   533         return false;
   534     args2.setCallee(cx->global()->protoGetter());
   535     args2.setThis(args[0]);
   536     if (!Invoke(cx, args2))
   537         return false;
   538     args.rval().set(args2.rval());
   539     return true;
   540 }
   542 static bool
   543 obj_setPrototypeOf(JSContext *cx, unsigned argc, Value *vp)
   544 {
   545     CallArgs args = CallArgsFromVp(argc, vp);
   547     RootedObject setPrototypeOf(cx, &args.callee());
   548     if (!GlobalObject::warnOnceAboutPrototypeMutation(cx, setPrototypeOf))
   549         return false;
   551     if (args.length() < 2) {
   552         JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_MORE_ARGS_NEEDED,
   553                              "Object.setPrototypeOf", "1", "");
   554         return false;
   555     }
   557     /* Step 1-2. */
   558     if (args[0].isNullOrUndefined()) {
   559         JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_CANT_CONVERT_TO,
   560                              args[0].isNull() ? "null" : "undefined", "object");
   561         return false;
   562     }
   564     /* Step 3. */
   565     if (!args[1].isObjectOrNull()) {
   566         JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_NOT_EXPECTED_TYPE,
   567                              "Object.setPrototypeOf", "an object or null", InformalValueTypeName(args[1]));
   568         return false;
   569     }
   571     /* Step 4. */
   572     if (!args[0].isObject()) {
   573         args.rval().set(args[0]);
   574         return true;
   575     }
   577     /* Step 5-6. */
   578     RootedObject obj(cx, &args[0].toObject());
   579     RootedObject newProto(cx, args[1].toObjectOrNull());
   581     bool success;
   582     if (!JSObject::setProto(cx, obj, newProto, &success))
   583         return false;
   585     /* Step 7. */
   586     if (!success) {
   587         JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_OBJECT_NOT_EXTENSIBLE, "object");
   588         return false;
   589     }
   591     /* Step 8. */
   592     args.rval().set(args[0]);
   593     return true;
   594 }
   596 #if JS_HAS_OBJ_WATCHPOINT
   598 bool
   599 js::WatchHandler(JSContext *cx, JSObject *obj_, jsid id_, JS::Value old,
   600                  JS::Value *nvp, void *closure)
   601 {
   602     RootedObject obj(cx, obj_);
   603     RootedId id(cx, id_);
   605     /* Avoid recursion on (obj, id) already being watched on cx. */
   606     AutoResolving resolving(cx, obj, id, AutoResolving::WATCH);
   607     if (resolving.alreadyStarted())
   608         return true;
   610     JSObject *callable = (JSObject *)closure;
   611     Value argv[] = { IdToValue(id), old, *nvp };
   612     RootedValue rv(cx);
   613     if (!Invoke(cx, ObjectValue(*obj), ObjectOrNullValue(callable), ArrayLength(argv), argv, &rv))
   614         return false;
   616     *nvp = rv;
   617     return true;
   618 }
   620 static bool
   621 obj_watch(JSContext *cx, unsigned argc, Value *vp)
   622 {
   623     CallArgs args = CallArgsFromVp(argc, vp);
   625     RootedObject obj(cx, ToObject(cx, args.thisv()));
   626     if (!obj)
   627         return false;
   629     if (!GlobalObject::warnOnceAboutWatch(cx, obj))
   630         return false;
   632     if (args.length() <= 1) {
   633         js_ReportMissingArg(cx, args.calleev(), 1);
   634         return false;
   635     }
   637     RootedObject callable(cx, ValueToCallable(cx, args[1], args.length() - 2));
   638     if (!callable)
   639         return false;
   641     RootedId propid(cx);
   642     if (!ValueToId<CanGC>(cx, args[0], &propid))
   643         return false;
   645     if (!JSObject::watch(cx, obj, propid, callable))
   646         return false;
   648     args.rval().setUndefined();
   649     return true;
   650 }
   652 static bool
   653 obj_unwatch(JSContext *cx, unsigned argc, Value *vp)
   654 {
   655     CallArgs args = CallArgsFromVp(argc, vp);
   657     RootedObject obj(cx, ToObject(cx, args.thisv()));
   658     if (!obj)
   659         return false;
   661     if (!GlobalObject::warnOnceAboutWatch(cx, obj))
   662         return false;
   664     RootedId id(cx);
   665     if (args.length() != 0) {
   666         if (!ValueToId<CanGC>(cx, args[0], &id))
   667             return false;
   668     } else {
   669         id = JSID_VOID;
   670     }
   672     if (!JSObject::unwatch(cx, obj, id))
   673         return false;
   675     args.rval().setUndefined();
   676     return true;
   677 }
   679 #endif /* JS_HAS_OBJ_WATCHPOINT */
   681 /* ECMA 15.2.4.5. */
   682 static bool
   683 obj_hasOwnProperty(JSContext *cx, unsigned argc, Value *vp)
   684 {
   685     CallArgs args = CallArgsFromVp(argc, vp);
   687     HandleValue idValue = args.get(0);
   689     /* Step 1, 2. */
   690     jsid id;
   691     if (args.thisv().isObject() && ValueToId<NoGC>(cx, idValue, &id)) {
   692         JSObject *obj = &args.thisv().toObject(), *obj2;
   693         Shape *prop;
   694         if (!obj->is<ProxyObject>() &&
   695             HasOwnProperty<NoGC>(cx, obj->getOps()->lookupGeneric, obj, id, &obj2, &prop))
   696         {
   697             args.rval().setBoolean(!!prop);
   698             return true;
   699         }
   700     }
   702     /* Step 1. */
   703     RootedId idRoot(cx);
   704     if (!ValueToId<CanGC>(cx, idValue, &idRoot))
   705         return false;
   707     /* Step 2. */
   708     RootedObject obj(cx, ToObject(cx, args.thisv()));
   709     if (!obj)
   710         return false;
   712     /* Non-standard code for proxies. */
   713     if (obj->is<ProxyObject>()) {
   714         bool has;
   715         if (!Proxy::hasOwn(cx, obj, idRoot, &has))
   716             return false;
   717         args.rval().setBoolean(has);
   718         return true;
   719     }
   721     /* Step 3. */
   722     bool found;
   723     if (!HasOwnProperty(cx, obj, idRoot, &found))
   724         return false;
   726     /* Step 4,5. */
   727     args.rval().setBoolean(found);
   728     return true;
   729 }
   731 /* ES5 15.2.4.6. */
   732 static bool
   733 obj_isPrototypeOf(JSContext *cx, unsigned argc, Value *vp)
   734 {
   735     CallArgs args = CallArgsFromVp(argc, vp);
   737     /* Step 1. */
   738     if (args.length() < 1 || !args[0].isObject()) {
   739         args.rval().setBoolean(false);
   740         return true;
   741     }
   743     /* Step 2. */
   744     RootedObject obj(cx, ToObject(cx, args.thisv()));
   745     if (!obj)
   746         return false;
   748     /* Step 3. */
   749     bool isDelegate;
   750     if (!IsDelegate(cx, obj, args[0], &isDelegate))
   751         return false;
   752     args.rval().setBoolean(isDelegate);
   753     return true;
   754 }
   756 /* ES5 15.2.3.5: Object.create(O [, Properties]) */
   757 static bool
   758 obj_create(JSContext *cx, unsigned argc, Value *vp)
   759 {
   760     CallArgs args = CallArgsFromVp(argc, vp);
   761     if (args.length() == 0) {
   762         JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_MORE_ARGS_NEEDED,
   763                              "Object.create", "0", "s");
   764         return false;
   765     }
   767     RootedValue v(cx, args[0]);
   768     if (!v.isObjectOrNull()) {
   769         char *bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, v, NullPtr());
   770         if (!bytes)
   771             return false;
   772         JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_UNEXPECTED_TYPE,
   773                              bytes, "not an object or null");
   774         js_free(bytes);
   775         return false;
   776     }
   778     RootedObject proto(cx, v.toObjectOrNull());
   780     /*
   781      * Use the callee's global as the parent of the new object to avoid dynamic
   782      * scoping (i.e., using the caller's global).
   783      */
   784     RootedObject obj(cx, NewObjectWithGivenProto(cx, &JSObject::class_, proto, &args.callee().global()));
   785     if (!obj)
   786         return false;
   788     /* 15.2.3.5 step 4. */
   789     if (args.hasDefined(1)) {
   790         if (args[1].isPrimitive()) {
   791             JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT);
   792             return false;
   793         }
   795         RootedObject props(cx, &args[1].toObject());
   796         if (!DefineProperties(cx, obj, props))
   797             return false;
   798     }
   800     /* 5. Return obj. */
   801     args.rval().setObject(*obj);
   802     return true;
   803 }
   805 static bool
   806 obj_getOwnPropertyDescriptor(JSContext *cx, unsigned argc, Value *vp)
   807 {
   808     CallArgs args = CallArgsFromVp(argc, vp);
   809     RootedObject obj(cx);
   810     if (!GetFirstArgumentAsObject(cx, args, "Object.getOwnPropertyDescriptor", &obj))
   811         return false;
   812     RootedId id(cx);
   813     if (!ValueToId<CanGC>(cx, args.get(1), &id))
   814         return false;
   815     return GetOwnPropertyDescriptor(cx, obj, id, args.rval());
   816 }
   818 static bool
   819 obj_keys(JSContext *cx, unsigned argc, Value *vp)
   820 {
   821     CallArgs args = CallArgsFromVp(argc, vp);
   822     RootedObject obj(cx);
   823     if (!GetFirstArgumentAsObject(cx, args, "Object.keys", &obj))
   824         return false;
   826     AutoIdVector props(cx);
   827     if (!GetPropertyNames(cx, obj, JSITER_OWNONLY, &props))
   828         return false;
   830     AutoValueVector vals(cx);
   831     if (!vals.reserve(props.length()))
   832         return false;
   833     for (size_t i = 0, len = props.length(); i < len; i++) {
   834         jsid id = props[i];
   835         if (JSID_IS_STRING(id)) {
   836             vals.infallibleAppend(StringValue(JSID_TO_STRING(id)));
   837         } else if (JSID_IS_INT(id)) {
   838             JSString *str = Int32ToString<CanGC>(cx, JSID_TO_INT(id));
   839             if (!str)
   840                 return false;
   841             vals.infallibleAppend(StringValue(str));
   842         } else {
   843             JS_ASSERT(JSID_IS_OBJECT(id));
   844         }
   845     }
   847     JS_ASSERT(props.length() <= UINT32_MAX);
   848     JSObject *aobj = NewDenseCopiedArray(cx, uint32_t(vals.length()), vals.begin());
   849     if (!aobj)
   850         return false;
   852     args.rval().setObject(*aobj);
   853     return true;
   854 }
   856 /* ES6 draft 15.2.3.16 */
   857 static bool
   858 obj_is(JSContext *cx, unsigned argc, Value *vp)
   859 {
   860     CallArgs args = CallArgsFromVp(argc, vp);
   862     bool same;
   863     if (!SameValue(cx, args.get(0), args.get(1), &same))
   864         return false;
   866     args.rval().setBoolean(same);
   867     return true;
   868 }
   870 static bool
   871 obj_getOwnPropertyNames(JSContext *cx, unsigned argc, Value *vp)
   872 {
   873     CallArgs args = CallArgsFromVp(argc, vp);
   874     RootedObject obj(cx);
   875     if (!GetFirstArgumentAsObject(cx, args, "Object.getOwnPropertyNames", &obj))
   876         return false;
   878     AutoIdVector keys(cx);
   879     if (!GetPropertyNames(cx, obj, JSITER_OWNONLY | JSITER_HIDDEN, &keys))
   880         return false;
   882     AutoValueVector vals(cx);
   883     if (!vals.resize(keys.length()))
   884         return false;
   886     for (size_t i = 0, len = keys.length(); i < len; i++) {
   887          jsid id = keys[i];
   888          if (JSID_IS_INT(id)) {
   889              JSString *str = Int32ToString<CanGC>(cx, JSID_TO_INT(id));
   890              if (!str)
   891                  return false;
   892              vals[i].setString(str);
   893          } else if (JSID_IS_ATOM(id)) {
   894              vals[i].setString(JSID_TO_STRING(id));
   895          } else {
   896              vals[i].setObject(*JSID_TO_OBJECT(id));
   897          }
   898     }
   900     JSObject *aobj = NewDenseCopiedArray(cx, vals.length(), vals.begin());
   901     if (!aobj)
   902         return false;
   904     args.rval().setObject(*aobj);
   905     return true;
   906 }
   908 /* ES5 15.2.3.6: Object.defineProperty(O, P, Attributes) */
   909 static bool
   910 obj_defineProperty(JSContext *cx, unsigned argc, Value *vp)
   911 {
   912     CallArgs args = CallArgsFromVp(argc, vp);
   913     RootedObject obj(cx);
   914     if (!GetFirstArgumentAsObject(cx, args, "Object.defineProperty", &obj))
   915         return false;
   917     RootedId id(cx);
   918     if (!ValueToId<CanGC>(cx, args.get(1), &id))
   919         return false;
   921     bool junk;
   922     if (!DefineOwnProperty(cx, obj, id, args.get(2), &junk))
   923         return false;
   925     args.rval().setObject(*obj);
   926     return true;
   927 }
   929 /* ES5 15.2.3.7: Object.defineProperties(O, Properties) */
   930 static bool
   931 obj_defineProperties(JSContext *cx, unsigned argc, Value *vp)
   932 {
   933     CallArgs args = CallArgsFromVp(argc, vp);
   935     /* Steps 1 and 7. */
   936     RootedObject obj(cx);
   937     if (!GetFirstArgumentAsObject(cx, args, "Object.defineProperties", &obj))
   938         return false;
   939     args.rval().setObject(*obj);
   941     /* Step 2. */
   942     if (args.length() < 2) {
   943         JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_MORE_ARGS_NEEDED,
   944                              "Object.defineProperties", "0", "s");
   945         return false;
   946     }
   947     RootedValue val(cx, args[1]);
   948     RootedObject props(cx, ToObject(cx, val));
   949     if (!props)
   950         return false;
   952     /* Steps 3-6. */
   953     return DefineProperties(cx, obj, props);
   954 }
   956 static bool
   957 obj_isExtensible(JSContext *cx, unsigned argc, Value *vp)
   958 {
   959     CallArgs args = CallArgsFromVp(argc, vp);
   960     RootedObject obj(cx);
   961     if (!GetFirstArgumentAsObject(cx, args, "Object.isExtensible", &obj))
   962         return false;
   964     bool extensible;
   965     if (!JSObject::isExtensible(cx, obj, &extensible))
   966         return false;
   967     args.rval().setBoolean(extensible);
   968     return true;
   969 }
   971 static bool
   972 obj_preventExtensions(JSContext *cx, unsigned argc, Value *vp)
   973 {
   974     CallArgs args = CallArgsFromVp(argc, vp);
   975     RootedObject obj(cx);
   976     if (!GetFirstArgumentAsObject(cx, args, "Object.preventExtensions", &obj))
   977         return false;
   979     args.rval().setObject(*obj);
   981     bool extensible;
   982     if (!JSObject::isExtensible(cx, obj, &extensible))
   983         return false;
   984     if (!extensible)
   985         return true;
   987     return JSObject::preventExtensions(cx, obj);
   988 }
   990 static bool
   991 obj_freeze(JSContext *cx, unsigned argc, Value *vp)
   992 {
   993     CallArgs args = CallArgsFromVp(argc, vp);
   994     RootedObject obj(cx);
   995     if (!GetFirstArgumentAsObject(cx, args, "Object.freeze", &obj))
   996         return false;
   998     args.rval().setObject(*obj);
  1000     return JSObject::freeze(cx, obj);
  1003 static bool
  1004 obj_isFrozen(JSContext *cx, unsigned argc, Value *vp)
  1006     CallArgs args = CallArgsFromVp(argc, vp);
  1007     RootedObject obj(cx);
  1008     if (!GetFirstArgumentAsObject(cx, args, "Object.preventExtensions", &obj))
  1009         return false;
  1011     bool frozen;
  1012     if (!JSObject::isFrozen(cx, obj, &frozen))
  1013         return false;
  1014     args.rval().setBoolean(frozen);
  1015     return true;
  1018 static bool
  1019 obj_seal(JSContext *cx, unsigned argc, Value *vp)
  1021     CallArgs args = CallArgsFromVp(argc, vp);
  1022     RootedObject obj(cx);
  1023     if (!GetFirstArgumentAsObject(cx, args, "Object.seal", &obj))
  1024         return false;
  1026     args.rval().setObject(*obj);
  1028     return JSObject::seal(cx, obj);
  1031 static bool
  1032 obj_isSealed(JSContext *cx, unsigned argc, Value *vp)
  1034     CallArgs args = CallArgsFromVp(argc, vp);
  1035     RootedObject obj(cx);
  1036     if (!GetFirstArgumentAsObject(cx, args, "Object.isSealed", &obj))
  1037         return false;
  1039     bool sealed;
  1040     if (!JSObject::isSealed(cx, obj, &sealed))
  1041         return false;
  1042     args.rval().setBoolean(sealed);
  1043     return true;
  1046 const JSFunctionSpec js::object_methods[] = {
  1047 #if JS_HAS_TOSOURCE
  1048     JS_FN(js_toSource_str,             obj_toSource,                0,0),
  1049 #endif
  1050     JS_FN(js_toString_str,             obj_toString,                0,0),
  1051     JS_FN(js_toLocaleString_str,       obj_toLocaleString,          0,0),
  1052     JS_FN(js_valueOf_str,              obj_valueOf,                 0,0),
  1053 #if JS_HAS_OBJ_WATCHPOINT
  1054     JS_FN(js_watch_str,                obj_watch,                   2,0),
  1055     JS_FN(js_unwatch_str,              obj_unwatch,                 1,0),
  1056 #endif
  1057     JS_FN(js_hasOwnProperty_str,       obj_hasOwnProperty,          1,0),
  1058     JS_FN(js_isPrototypeOf_str,        obj_isPrototypeOf,           1,0),
  1059     JS_FN(js_propertyIsEnumerable_str, obj_propertyIsEnumerable,    1,0),
  1060 #if JS_OLD_GETTER_SETTER_METHODS
  1061     JS_FN(js_defineGetter_str,         js::obj_defineGetter,        2,0),
  1062     JS_FN(js_defineSetter_str,         js::obj_defineSetter,        2,0),
  1063     JS_FN(js_lookupGetter_str,         obj_lookupGetter,            1,0),
  1064     JS_FN(js_lookupSetter_str,         obj_lookupSetter,            1,0),
  1065 #endif
  1066     JS_FS_END
  1067 };
  1069 const JSFunctionSpec js::object_static_methods[] = {
  1070     JS_FN("getPrototypeOf",            obj_getPrototypeOf,          1,0),
  1071     JS_FN("setPrototypeOf",            obj_setPrototypeOf,          2,0),
  1072     JS_FN("getOwnPropertyDescriptor",  obj_getOwnPropertyDescriptor,2,0),
  1073     JS_FN("keys",                      obj_keys,                    1,0),
  1074     JS_FN("is",                        obj_is,                      2,0),
  1075     JS_FN("defineProperty",            obj_defineProperty,          3,0),
  1076     JS_FN("defineProperties",          obj_defineProperties,        2,0),
  1077     JS_FN("create",                    obj_create,                  2,0),
  1078     JS_FN("getOwnPropertyNames",       obj_getOwnPropertyNames,     1,0),
  1079     JS_FN("isExtensible",              obj_isExtensible,            1,0),
  1080     JS_FN("preventExtensions",         obj_preventExtensions,       1,0),
  1081     JS_FN("freeze",                    obj_freeze,                  1,0),
  1082     JS_FN("isFrozen",                  obj_isFrozen,                1,0),
  1083     JS_FN("seal",                      obj_seal,                    1,0),
  1084     JS_FN("isSealed",                  obj_isSealed,                1,0),
  1085     JS_FS_END
  1086 };

mercurial