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.

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

mercurial