js/src/jsobj.h

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 #ifndef jsobj_h
michael@0 8 #define jsobj_h
michael@0 9
michael@0 10 /*
michael@0 11 * JS object definitions.
michael@0 12 *
michael@0 13 * A JS object consists of a possibly-shared object descriptor containing
michael@0 14 * ordered property names, called the map; and a dense vector of property
michael@0 15 * values, called slots. The map/slot pointer pair is GC'ed, while the map
michael@0 16 * is reference counted and the slot vector is malloc'ed.
michael@0 17 */
michael@0 18
michael@0 19 #include "mozilla/MemoryReporting.h"
michael@0 20
michael@0 21 #include "gc/Barrier.h"
michael@0 22 #include "gc/Marking.h"
michael@0 23 #include "js/GCAPI.h"
michael@0 24 #include "vm/ObjectImpl.h"
michael@0 25 #include "vm/Shape.h"
michael@0 26 #include "vm/Xdr.h"
michael@0 27
michael@0 28 namespace JS {
michael@0 29 struct ObjectsExtraSizes;
michael@0 30 }
michael@0 31
michael@0 32 namespace js {
michael@0 33
michael@0 34 class AutoPropDescArrayRooter;
michael@0 35 struct GCMarker;
michael@0 36 struct NativeIterator;
michael@0 37 class Nursery;
michael@0 38 struct StackShape;
michael@0 39
michael@0 40 inline JSObject *
michael@0 41 CastAsObject(PropertyOp op)
michael@0 42 {
michael@0 43 return JS_FUNC_TO_DATA_PTR(JSObject *, op);
michael@0 44 }
michael@0 45
michael@0 46 inline JSObject *
michael@0 47 CastAsObject(StrictPropertyOp op)
michael@0 48 {
michael@0 49 return JS_FUNC_TO_DATA_PTR(JSObject *, op);
michael@0 50 }
michael@0 51
michael@0 52 inline Value
michael@0 53 CastAsObjectJsval(PropertyOp op)
michael@0 54 {
michael@0 55 return ObjectOrNullValue(CastAsObject(op));
michael@0 56 }
michael@0 57
michael@0 58 inline Value
michael@0 59 CastAsObjectJsval(StrictPropertyOp op)
michael@0 60 {
michael@0 61 return ObjectOrNullValue(CastAsObject(op));
michael@0 62 }
michael@0 63
michael@0 64 /******************************************************************************/
michael@0 65
michael@0 66 typedef Vector<PropDesc, 1> PropDescArray;
michael@0 67
michael@0 68 /*
michael@0 69 * The baseops namespace encapsulates the default behavior when performing
michael@0 70 * various operations on an object, irrespective of hooks installed in the
michael@0 71 * object's class. In general, instance methods on the object itself should be
michael@0 72 * called instead of calling these methods directly.
michael@0 73 */
michael@0 74 namespace baseops {
michael@0 75
michael@0 76 /*
michael@0 77 * On success, and if id was found, return true with *objp non-null and with a
michael@0 78 * property of *objp stored in *propp. If successful but id was not found,
michael@0 79 * return true with both *objp and *propp null.
michael@0 80 */
michael@0 81 template <AllowGC allowGC>
michael@0 82 extern bool
michael@0 83 LookupProperty(ExclusiveContext *cx,
michael@0 84 typename MaybeRooted<JSObject*, allowGC>::HandleType obj,
michael@0 85 typename MaybeRooted<jsid, allowGC>::HandleType id,
michael@0 86 typename MaybeRooted<JSObject*, allowGC>::MutableHandleType objp,
michael@0 87 typename MaybeRooted<Shape*, allowGC>::MutableHandleType propp);
michael@0 88
michael@0 89 extern bool
michael@0 90 LookupElement(JSContext *cx, HandleObject obj, uint32_t index,
michael@0 91 MutableHandleObject objp, MutableHandleShape propp);
michael@0 92
michael@0 93 extern bool
michael@0 94 DefineGeneric(ExclusiveContext *cx, HandleObject obj, HandleId id, HandleValue value,
michael@0 95 JSPropertyOp getter, JSStrictPropertyOp setter, unsigned attrs);
michael@0 96
michael@0 97 extern bool
michael@0 98 DefineElement(ExclusiveContext *cx, HandleObject obj, uint32_t index, HandleValue value,
michael@0 99 JSPropertyOp getter, JSStrictPropertyOp setter, unsigned attrs);
michael@0 100
michael@0 101 extern bool
michael@0 102 GetProperty(JSContext *cx, HandleObject obj, HandleObject receiver, HandleId id, MutableHandleValue vp);
michael@0 103
michael@0 104 extern bool
michael@0 105 GetPropertyNoGC(JSContext *cx, JSObject *obj, JSObject *receiver, jsid id, Value *vp);
michael@0 106
michael@0 107 extern bool
michael@0 108 GetElement(JSContext *cx, HandleObject obj, HandleObject receiver, uint32_t index, MutableHandleValue vp);
michael@0 109
michael@0 110 inline bool
michael@0 111 GetProperty(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue vp)
michael@0 112 {
michael@0 113 return GetProperty(cx, obj, obj, id, vp);
michael@0 114 }
michael@0 115
michael@0 116 inline bool
michael@0 117 GetElement(JSContext *cx, HandleObject obj, uint32_t index, MutableHandleValue vp)
michael@0 118 {
michael@0 119 return GetElement(cx, obj, obj, index, vp);
michael@0 120 }
michael@0 121
michael@0 122 /*
michael@0 123 * Indicates whether an assignment operation is qualified (`x.y = 0`) or
michael@0 124 * unqualified (`y = 0`). In strict mode, the latter is an error if no such
michael@0 125 * variable already exists.
michael@0 126 *
michael@0 127 * Used as an argument to baseops::SetPropertyHelper.
michael@0 128 */
michael@0 129 enum QualifiedBool {
michael@0 130 Unqualified = 0,
michael@0 131 Qualified = 1
michael@0 132 };
michael@0 133
michael@0 134 template <ExecutionMode mode>
michael@0 135 extern bool
michael@0 136 SetPropertyHelper(typename ExecutionModeTraits<mode>::ContextType cx, HandleObject obj,
michael@0 137 HandleObject receiver, HandleId id, QualifiedBool qualified,
michael@0 138 MutableHandleValue vp, bool strict);
michael@0 139
michael@0 140 extern bool
michael@0 141 SetElementHelper(JSContext *cx, HandleObject obj, HandleObject Receiver, uint32_t index,
michael@0 142 MutableHandleValue vp, bool strict);
michael@0 143
michael@0 144 extern bool
michael@0 145 GetAttributes(JSContext *cx, HandleObject obj, HandleId id, unsigned *attrsp);
michael@0 146
michael@0 147 extern bool
michael@0 148 SetAttributes(JSContext *cx, HandleObject obj, HandleId id, unsigned *attrsp);
michael@0 149
michael@0 150 extern bool
michael@0 151 DeleteProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, bool *succeeded);
michael@0 152
michael@0 153 extern bool
michael@0 154 DeleteElement(JSContext *cx, HandleObject obj, uint32_t index, bool *succeeded);
michael@0 155
michael@0 156 extern bool
michael@0 157 DeleteGeneric(JSContext *cx, HandleObject obj, HandleId id, bool *succeeded);
michael@0 158
michael@0 159 extern bool
michael@0 160 Watch(JSContext *cx, JS::HandleObject obj, JS::HandleId id, JS::HandleObject callable);
michael@0 161
michael@0 162 extern bool
michael@0 163 Unwatch(JSContext *cx, JS::HandleObject obj, JS::HandleId id);
michael@0 164
michael@0 165 } /* namespace js::baseops */
michael@0 166
michael@0 167 extern const Class IntlClass;
michael@0 168 extern const Class JSONClass;
michael@0 169 extern const Class MathClass;
michael@0 170
michael@0 171 class GlobalObject;
michael@0 172 class MapObject;
michael@0 173 class NewObjectCache;
michael@0 174 class NormalArgumentsObject;
michael@0 175 class SetObject;
michael@0 176 class StrictArgumentsObject;
michael@0 177
michael@0 178 /*
michael@0 179 * NOTE: This is a placeholder for bug 619558.
michael@0 180 *
michael@0 181 * Run a post write barrier that encompasses multiple contiguous slots in a
michael@0 182 * single step.
michael@0 183 */
michael@0 184 inline void
michael@0 185 DenseRangeWriteBarrierPost(JSRuntime *rt, JSObject *obj, uint32_t start, uint32_t count)
michael@0 186 {
michael@0 187 #ifdef JSGC_GENERATIONAL
michael@0 188 if (count > 0) {
michael@0 189 JS::shadow::Runtime *shadowRuntime = JS::shadow::Runtime::asShadowRuntime(rt);
michael@0 190 shadowRuntime->gcStoreBufferPtr()->putSlot(obj, HeapSlot::Element, start, count);
michael@0 191 }
michael@0 192 #endif
michael@0 193 }
michael@0 194
michael@0 195 } /* namespace js */
michael@0 196
michael@0 197 /*
michael@0 198 * The public interface for an object.
michael@0 199 *
michael@0 200 * Implementation of the underlying structure occurs in ObjectImpl, from which
michael@0 201 * this struct inherits. This inheritance is currently public, but it will
michael@0 202 * eventually be made protected. For full details, see vm/ObjectImpl.{h,cpp}.
michael@0 203 *
michael@0 204 * The JSFunction struct is an extension of this struct allocated from a larger
michael@0 205 * GC size-class.
michael@0 206 */
michael@0 207 class JSObject : public js::ObjectImpl
michael@0 208 {
michael@0 209 private:
michael@0 210 friend class js::Shape;
michael@0 211 friend struct js::GCMarker;
michael@0 212 friend class js::NewObjectCache;
michael@0 213 friend class js::Nursery;
michael@0 214
michael@0 215 /* Make the type object to use for LAZY_TYPE objects. */
michael@0 216 static js::types::TypeObject *makeLazyType(JSContext *cx, js::HandleObject obj);
michael@0 217
michael@0 218 public:
michael@0 219 static const js::Class class_;
michael@0 220
michael@0 221 /*
michael@0 222 * Update the last property, keeping the number of allocated slots in sync
michael@0 223 * with the object's new slot span.
michael@0 224 */
michael@0 225 static bool setLastProperty(js::ThreadSafeContext *cx,
michael@0 226 JS::HandleObject obj, js::HandleShape shape);
michael@0 227
michael@0 228 /* As above, but does not change the slot span. */
michael@0 229 inline void setLastPropertyInfallible(js::Shape *shape);
michael@0 230
michael@0 231 /*
michael@0 232 * Make a non-array object with the specified initial state. This method
michael@0 233 * takes ownership of any extantSlots it is passed.
michael@0 234 */
michael@0 235 static inline JSObject *create(js::ExclusiveContext *cx,
michael@0 236 js::gc::AllocKind kind,
michael@0 237 js::gc::InitialHeap heap,
michael@0 238 js::HandleShape shape,
michael@0 239 js::HandleTypeObject type,
michael@0 240 js::HeapSlot *extantSlots = nullptr);
michael@0 241
michael@0 242 /* Make an array object with the specified initial state. */
michael@0 243 static inline js::ArrayObject *createArray(js::ExclusiveContext *cx,
michael@0 244 js::gc::AllocKind kind,
michael@0 245 js::gc::InitialHeap heap,
michael@0 246 js::HandleShape shape,
michael@0 247 js::HandleTypeObject type,
michael@0 248 uint32_t length);
michael@0 249
michael@0 250 /*
michael@0 251 * Remove the last property of an object, provided that it is safe to do so
michael@0 252 * (the shape and previous shape do not carry conflicting information about
michael@0 253 * the object itself).
michael@0 254 */
michael@0 255 inline void removeLastProperty(js::ExclusiveContext *cx);
michael@0 256 inline bool canRemoveLastProperty();
michael@0 257
michael@0 258 /*
michael@0 259 * Update the slot span directly for a dictionary object, and allocate
michael@0 260 * slots to cover the new span if necessary.
michael@0 261 */
michael@0 262 static bool setSlotSpan(js::ThreadSafeContext *cx, JS::HandleObject obj, uint32_t span);
michael@0 263
michael@0 264 /* Upper bound on the number of elements in an object. */
michael@0 265 static const uint32_t NELEMENTS_LIMIT = JS_BIT(28);
michael@0 266
michael@0 267 public:
michael@0 268 bool setDelegate(js::ExclusiveContext *cx) {
michael@0 269 return setFlag(cx, js::BaseShape::DELEGATE, GENERATE_SHAPE);
michael@0 270 }
michael@0 271
michael@0 272 bool isBoundFunction() const {
michael@0 273 return lastProperty()->hasObjectFlag(js::BaseShape::BOUND_FUNCTION);
michael@0 274 }
michael@0 275
michael@0 276 inline bool hasSpecialEquality() const;
michael@0 277
michael@0 278 bool watched() const {
michael@0 279 return lastProperty()->hasObjectFlag(js::BaseShape::WATCHED);
michael@0 280 }
michael@0 281 bool setWatched(js::ExclusiveContext *cx) {
michael@0 282 return setFlag(cx, js::BaseShape::WATCHED, GENERATE_SHAPE);
michael@0 283 }
michael@0 284
michael@0 285 /* See InterpreterFrame::varObj. */
michael@0 286 inline bool isVarObj();
michael@0 287 bool setVarObj(js::ExclusiveContext *cx) {
michael@0 288 return setFlag(cx, js::BaseShape::VAROBJ);
michael@0 289 }
michael@0 290
michael@0 291 /*
michael@0 292 * Objects with an uncacheable proto can have their prototype mutated
michael@0 293 * without inducing a shape change on the object. Property cache entries
michael@0 294 * and JIT inline caches should not be filled for lookups across prototype
michael@0 295 * lookups on the object.
michael@0 296 */
michael@0 297 bool hasUncacheableProto() const {
michael@0 298 return lastProperty()->hasObjectFlag(js::BaseShape::UNCACHEABLE_PROTO);
michael@0 299 }
michael@0 300 bool setUncacheableProto(js::ExclusiveContext *cx) {
michael@0 301 return setFlag(cx, js::BaseShape::UNCACHEABLE_PROTO, GENERATE_SHAPE);
michael@0 302 }
michael@0 303
michael@0 304 /*
michael@0 305 * Whether SETLELEM was used to access this object. See also the comment near
michael@0 306 * PropertyTree::MAX_HEIGHT.
michael@0 307 */
michael@0 308 bool hadElementsAccess() const {
michael@0 309 return lastProperty()->hasObjectFlag(js::BaseShape::HAD_ELEMENTS_ACCESS);
michael@0 310 }
michael@0 311 bool setHadElementsAccess(js::ExclusiveContext *cx) {
michael@0 312 return setFlag(cx, js::BaseShape::HAD_ELEMENTS_ACCESS);
michael@0 313 }
michael@0 314
michael@0 315 public:
michael@0 316 bool nativeEmpty() const {
michael@0 317 return lastProperty()->isEmptyShape();
michael@0 318 }
michael@0 319
michael@0 320 bool shadowingShapeChange(js::ExclusiveContext *cx, const js::Shape &shape);
michael@0 321
michael@0 322 /*
michael@0 323 * Whether there may be indexed properties on this object, excluding any in
michael@0 324 * the object's elements.
michael@0 325 */
michael@0 326 bool isIndexed() const {
michael@0 327 return lastProperty()->hasObjectFlag(js::BaseShape::INDEXED);
michael@0 328 }
michael@0 329
michael@0 330 uint32_t propertyCount() const {
michael@0 331 return lastProperty()->entryCount();
michael@0 332 }
michael@0 333
michael@0 334 bool hasShapeTable() const {
michael@0 335 return lastProperty()->hasTable();
michael@0 336 }
michael@0 337
michael@0 338 void addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf, JS::ObjectsExtraSizes *sizes);
michael@0 339
michael@0 340 bool hasIdempotentProtoChain() const;
michael@0 341
michael@0 342 // MAX_FIXED_SLOTS is the biggest number of fixed slots our GC
michael@0 343 // size classes will give an object.
michael@0 344 static const uint32_t MAX_FIXED_SLOTS = 16;
michael@0 345
michael@0 346 public:
michael@0 347
michael@0 348 /* Accessors for properties. */
michael@0 349
michael@0 350 /* Whether a slot is at a fixed offset from this object. */
michael@0 351 bool isFixedSlot(size_t slot) {
michael@0 352 return slot < numFixedSlots();
michael@0 353 }
michael@0 354
michael@0 355 /* Index into the dynamic slots array to use for a dynamic slot. */
michael@0 356 size_t dynamicSlotIndex(size_t slot) {
michael@0 357 JS_ASSERT(slot >= numFixedSlots());
michael@0 358 return slot - numFixedSlots();
michael@0 359 }
michael@0 360
michael@0 361 /*
michael@0 362 * Grow or shrink slots immediately before changing the slot span.
michael@0 363 * The number of allocated slots is not stored explicitly, and changes to
michael@0 364 * the slots must track changes in the slot span.
michael@0 365 */
michael@0 366 static bool growSlots(js::ThreadSafeContext *cx, js::HandleObject obj, uint32_t oldCount,
michael@0 367 uint32_t newCount);
michael@0 368 static void shrinkSlots(js::ThreadSafeContext *cx, js::HandleObject obj, uint32_t oldCount,
michael@0 369 uint32_t newCount);
michael@0 370
michael@0 371 bool hasDynamicSlots() const { return !!slots; }
michael@0 372
michael@0 373 protected:
michael@0 374 static inline bool updateSlotsForSpan(js::ThreadSafeContext *cx,
michael@0 375 js::HandleObject obj, size_t oldSpan, size_t newSpan);
michael@0 376
michael@0 377 public:
michael@0 378 /*
michael@0 379 * Trigger the write barrier on a range of slots that will no longer be
michael@0 380 * reachable.
michael@0 381 */
michael@0 382 void prepareSlotRangeForOverwrite(size_t start, size_t end) {
michael@0 383 for (size_t i = start; i < end; i++)
michael@0 384 getSlotAddressUnchecked(i)->js::HeapSlot::~HeapSlot();
michael@0 385 }
michael@0 386
michael@0 387 void prepareElementRangeForOverwrite(size_t start, size_t end) {
michael@0 388 JS_ASSERT(end <= getDenseInitializedLength());
michael@0 389 for (size_t i = start; i < end; i++)
michael@0 390 elements[i].js::HeapSlot::~HeapSlot();
michael@0 391 }
michael@0 392
michael@0 393 static bool rollbackProperties(js::ExclusiveContext *cx, js::HandleObject obj,
michael@0 394 uint32_t slotSpan);
michael@0 395
michael@0 396 void nativeSetSlot(uint32_t slot, const js::Value &value) {
michael@0 397 JS_ASSERT(isNative());
michael@0 398 JS_ASSERT(slot < slotSpan());
michael@0 399 return setSlot(slot, value);
michael@0 400 }
michael@0 401
michael@0 402 inline bool nativeSetSlotIfHasType(js::Shape *shape, const js::Value &value);
michael@0 403 inline void nativeSetSlotWithType(js::ExclusiveContext *cx, js::Shape *shape,
michael@0 404 const js::Value &value);
michael@0 405
michael@0 406 inline const js::Value &getReservedSlot(uint32_t index) const {
michael@0 407 JS_ASSERT(index < JSSLOT_FREE(getClass()));
michael@0 408 return getSlot(index);
michael@0 409 }
michael@0 410
michael@0 411 const js::HeapSlot &getReservedSlotRef(uint32_t index) const {
michael@0 412 JS_ASSERT(index < JSSLOT_FREE(getClass()));
michael@0 413 return getSlotRef(index);
michael@0 414 }
michael@0 415
michael@0 416 js::HeapSlot &getReservedSlotRef(uint32_t index) {
michael@0 417 JS_ASSERT(index < JSSLOT_FREE(getClass()));
michael@0 418 return getSlotRef(index);
michael@0 419 }
michael@0 420
michael@0 421 void initReservedSlot(uint32_t index, const js::Value &v) {
michael@0 422 JS_ASSERT(index < JSSLOT_FREE(getClass()));
michael@0 423 initSlot(index, v);
michael@0 424 }
michael@0 425
michael@0 426 void setReservedSlot(uint32_t index, const js::Value &v) {
michael@0 427 JS_ASSERT(index < JSSLOT_FREE(getClass()));
michael@0 428 setSlot(index, v);
michael@0 429 }
michael@0 430
michael@0 431 /*
michael@0 432 * Marks this object as having a singleton type, and leave the type lazy.
michael@0 433 * Constructs a new, unique shape for the object.
michael@0 434 */
michael@0 435 static inline bool setSingletonType(js::ExclusiveContext *cx, js::HandleObject obj);
michael@0 436
michael@0 437 // uninlinedGetType() is the same as getType(), but not inlined.
michael@0 438 inline js::types::TypeObject* getType(JSContext *cx);
michael@0 439 js::types::TypeObject* uninlinedGetType(JSContext *cx);
michael@0 440
michael@0 441 const js::HeapPtr<js::types::TypeObject> &typeFromGC() const {
michael@0 442 /* Direct field access for use by GC. */
michael@0 443 return type_;
michael@0 444 }
michael@0 445
michael@0 446 /*
michael@0 447 * We allow the prototype of an object to be lazily computed if the object
michael@0 448 * is a proxy. In the lazy case, we store (JSObject *)0x1 in the proto field
michael@0 449 * of the object's TypeObject. We offer three ways of getting the prototype:
michael@0 450 *
michael@0 451 * 1. obj->getProto() returns the prototype, but asserts if obj is a proxy.
michael@0 452 * 2. obj->getTaggedProto() returns a TaggedProto, which can be tested to
michael@0 453 * check if the proto is an object, nullptr, or lazily computed.
michael@0 454 * 3. JSObject::getProto(cx, obj, &proto) computes the proto of an object.
michael@0 455 * If obj is a proxy and the proto is lazy, this code may allocate or
michael@0 456 * GC in order to compute the proto. Currently, it will not run JS code.
michael@0 457 */
michael@0 458 bool uninlinedIsProxy() const;
michael@0 459 JSObject *getProto() const {
michael@0 460 JS_ASSERT(!uninlinedIsProxy());
michael@0 461 return getTaggedProto().toObjectOrNull();
michael@0 462 }
michael@0 463 static inline bool getProto(JSContext *cx, js::HandleObject obj,
michael@0 464 js::MutableHandleObject protop);
michael@0 465 // Returns false on error, success of operation in outparam.
michael@0 466 static inline bool setProto(JSContext *cx, JS::HandleObject obj,
michael@0 467 JS::HandleObject proto, bool *succeeded);
michael@0 468
michael@0 469 // uninlinedSetType() is the same as setType(), but not inlined.
michael@0 470 inline void setType(js::types::TypeObject *newType);
michael@0 471 void uninlinedSetType(js::types::TypeObject *newType);
michael@0 472
michael@0 473 #ifdef DEBUG
michael@0 474 bool hasNewType(const js::Class *clasp, js::types::TypeObject *newType);
michael@0 475 #endif
michael@0 476
michael@0 477 /*
michael@0 478 * Mark an object that has been iterated over and is a singleton. We need
michael@0 479 * to recover this information in the object's type information after it
michael@0 480 * is purged on GC.
michael@0 481 */
michael@0 482 bool isIteratedSingleton() const {
michael@0 483 return lastProperty()->hasObjectFlag(js::BaseShape::ITERATED_SINGLETON);
michael@0 484 }
michael@0 485 bool setIteratedSingleton(js::ExclusiveContext *cx) {
michael@0 486 return setFlag(cx, js::BaseShape::ITERATED_SINGLETON);
michael@0 487 }
michael@0 488
michael@0 489 /*
michael@0 490 * Mark an object as requiring its default 'new' type to have unknown
michael@0 491 * properties.
michael@0 492 */
michael@0 493 bool isNewTypeUnknown() const {
michael@0 494 return lastProperty()->hasObjectFlag(js::BaseShape::NEW_TYPE_UNKNOWN);
michael@0 495 }
michael@0 496 static bool setNewTypeUnknown(JSContext *cx, const js::Class *clasp, JS::HandleObject obj);
michael@0 497
michael@0 498 /* Set a new prototype for an object with a singleton type. */
michael@0 499 bool splicePrototype(JSContext *cx, const js::Class *clasp, js::Handle<js::TaggedProto> proto);
michael@0 500
michael@0 501 /*
michael@0 502 * For bootstrapping, whether to splice a prototype for Function.prototype
michael@0 503 * or the global object.
michael@0 504 */
michael@0 505 bool shouldSplicePrototype(JSContext *cx);
michael@0 506
michael@0 507 /*
michael@0 508 * Parents and scope chains.
michael@0 509 *
michael@0 510 * All script-accessible objects with a nullptr parent are global objects,
michael@0 511 * and all global objects have a nullptr parent. Some builtin objects
michael@0 512 * which are not script-accessible also have a nullptr parent, such as
michael@0 513 * parser created functions for non-compileAndGo scripts.
michael@0 514 *
michael@0 515 * Except for the non-script-accessible builtins, the global with which an
michael@0 516 * object is associated can be reached by following parent links to that
michael@0 517 * global (see global()).
michael@0 518 *
michael@0 519 * The scope chain of an object is the link in the search path when a
michael@0 520 * script does a name lookup on a scope object. For JS internal scope
michael@0 521 * objects --- Call, DeclEnv and Block --- the chain is stored in
michael@0 522 * the first fixed slot of the object, and the object's parent is the
michael@0 523 * associated global. For other scope objects, the chain is stored in the
michael@0 524 * object's parent.
michael@0 525 *
michael@0 526 * In compileAndGo code, scope chains can contain only internal scope
michael@0 527 * objects with a global object at the root as the scope of the outermost
michael@0 528 * non-function script. In non-compileAndGo code, the scope of the
michael@0 529 * outermost non-function script might not be a global object, and can have
michael@0 530 * a mix of other objects above it before the global object is reached.
michael@0 531 */
michael@0 532
michael@0 533 /* Access the parent link of an object. */
michael@0 534 JSObject *getParent() const {
michael@0 535 return lastProperty()->getObjectParent();
michael@0 536 }
michael@0 537 static bool setParent(JSContext *cx, js::HandleObject obj, js::HandleObject newParent);
michael@0 538
michael@0 539 /*
michael@0 540 * Get the enclosing scope of an object. When called on non-scope object,
michael@0 541 * this will just be the global (the name "enclosing scope" still applies
michael@0 542 * in this situation because non-scope objects can be on the scope chain).
michael@0 543 */
michael@0 544 inline JSObject *enclosingScope();
michael@0 545
michael@0 546 /* Access the metadata on an object. */
michael@0 547 inline JSObject *getMetadata() const {
michael@0 548 return lastProperty()->getObjectMetadata();
michael@0 549 }
michael@0 550 static bool setMetadata(JSContext *cx, js::HandleObject obj, js::HandleObject newMetadata);
michael@0 551
michael@0 552 inline js::GlobalObject &global() const;
michael@0 553 inline bool isOwnGlobal() const;
michael@0 554
michael@0 555 /* Remove the type (and prototype) or parent from a new object. */
michael@0 556 static inline bool clearType(JSContext *cx, js::HandleObject obj);
michael@0 557 static bool clearParent(JSContext *cx, js::HandleObject obj);
michael@0 558
michael@0 559 /*
michael@0 560 * ES5 meta-object properties and operations.
michael@0 561 */
michael@0 562
michael@0 563 private:
michael@0 564 enum ImmutabilityType { SEAL, FREEZE };
michael@0 565
michael@0 566 /*
michael@0 567 * The guts of Object.seal (ES5 15.2.3.8) and Object.freeze (ES5 15.2.3.9): mark the
michael@0 568 * object as non-extensible, and adjust each property's attributes appropriately: each
michael@0 569 * property becomes non-configurable, and if |freeze|, data properties become
michael@0 570 * read-only as well.
michael@0 571 */
michael@0 572 static bool sealOrFreeze(JSContext *cx, js::HandleObject obj, ImmutabilityType it);
michael@0 573
michael@0 574 static bool isSealedOrFrozen(JSContext *cx, js::HandleObject obj, ImmutabilityType it, bool *resultp);
michael@0 575
michael@0 576 static inline unsigned getSealedOrFrozenAttributes(unsigned attrs, ImmutabilityType it);
michael@0 577
michael@0 578 public:
michael@0 579 /* ES5 15.2.3.8: non-extensible, all props non-configurable */
michael@0 580 static inline bool seal(JSContext *cx, js::HandleObject obj) { return sealOrFreeze(cx, obj, SEAL); }
michael@0 581 /* ES5 15.2.3.9: non-extensible, all properties non-configurable, all data props read-only */
michael@0 582 static inline bool freeze(JSContext *cx, js::HandleObject obj) { return sealOrFreeze(cx, obj, FREEZE); }
michael@0 583
michael@0 584 static inline bool isSealed(JSContext *cx, js::HandleObject obj, bool *resultp) {
michael@0 585 return isSealedOrFrozen(cx, obj, SEAL, resultp);
michael@0 586 }
michael@0 587 static inline bool isFrozen(JSContext *cx, js::HandleObject obj, bool *resultp) {
michael@0 588 return isSealedOrFrozen(cx, obj, FREEZE, resultp);
michael@0 589 }
michael@0 590
michael@0 591 /* toString support. */
michael@0 592 static const char *className(JSContext *cx, js::HandleObject obj);
michael@0 593
michael@0 594 /* Accessors for elements. */
michael@0 595 bool ensureElements(js::ThreadSafeContext *cx, uint32_t capacity) {
michael@0 596 if (capacity > getDenseCapacity())
michael@0 597 return growElements(cx, capacity);
michael@0 598 return true;
michael@0 599 }
michael@0 600
michael@0 601 bool growElements(js::ThreadSafeContext *cx, uint32_t newcap);
michael@0 602 void shrinkElements(js::ThreadSafeContext *cx, uint32_t cap);
michael@0 603 void setDynamicElements(js::ObjectElements *header) {
michael@0 604 JS_ASSERT(!hasDynamicElements());
michael@0 605 elements = header->elements();
michael@0 606 JS_ASSERT(hasDynamicElements());
michael@0 607 }
michael@0 608
michael@0 609 uint32_t getDenseCapacity() {
michael@0 610 JS_ASSERT(isNative());
michael@0 611 JS_ASSERT(getElementsHeader()->capacity >= getElementsHeader()->initializedLength);
michael@0 612 return getElementsHeader()->capacity;
michael@0 613 }
michael@0 614
michael@0 615 private:
michael@0 616 inline void ensureDenseInitializedLengthNoPackedCheck(js::ThreadSafeContext *cx,
michael@0 617 uint32_t index, uint32_t extra);
michael@0 618
michael@0 619 public:
michael@0 620 void setDenseInitializedLength(uint32_t length) {
michael@0 621 JS_ASSERT(isNative());
michael@0 622 JS_ASSERT(length <= getDenseCapacity());
michael@0 623 prepareElementRangeForOverwrite(length, getElementsHeader()->initializedLength);
michael@0 624 getElementsHeader()->initializedLength = length;
michael@0 625 }
michael@0 626
michael@0 627 inline void ensureDenseInitializedLength(js::ExclusiveContext *cx,
michael@0 628 uint32_t index, uint32_t extra);
michael@0 629 inline void ensureDenseInitializedLengthPreservePackedFlag(js::ThreadSafeContext *cx,
michael@0 630 uint32_t index, uint32_t extra);
michael@0 631 void setDenseElement(uint32_t index, const js::Value &val) {
michael@0 632 JS_ASSERT(isNative() && index < getDenseInitializedLength());
michael@0 633 elements[index].set(this, js::HeapSlot::Element, index, val);
michael@0 634 }
michael@0 635
michael@0 636 void initDenseElement(uint32_t index, const js::Value &val) {
michael@0 637 JS_ASSERT(isNative() && index < getDenseInitializedLength());
michael@0 638 elements[index].init(this, js::HeapSlot::Element, index, val);
michael@0 639 }
michael@0 640
michael@0 641 void setDenseElementMaybeConvertDouble(uint32_t index, const js::Value &val) {
michael@0 642 if (val.isInt32() && shouldConvertDoubleElements())
michael@0 643 setDenseElement(index, js::DoubleValue(val.toInt32()));
michael@0 644 else
michael@0 645 setDenseElement(index, val);
michael@0 646 }
michael@0 647
michael@0 648 inline bool setDenseElementIfHasType(uint32_t index, const js::Value &val);
michael@0 649 inline void setDenseElementWithType(js::ExclusiveContext *cx, uint32_t index,
michael@0 650 const js::Value &val);
michael@0 651 inline void initDenseElementWithType(js::ExclusiveContext *cx, uint32_t index,
michael@0 652 const js::Value &val);
michael@0 653 inline void setDenseElementHole(js::ExclusiveContext *cx, uint32_t index);
michael@0 654 static inline void removeDenseElementForSparseIndex(js::ExclusiveContext *cx,
michael@0 655 js::HandleObject obj, uint32_t index);
michael@0 656
michael@0 657 inline js::Value getDenseOrTypedArrayElement(uint32_t idx);
michael@0 658
michael@0 659 void copyDenseElements(uint32_t dstStart, const js::Value *src, uint32_t count) {
michael@0 660 JS_ASSERT(dstStart + count <= getDenseCapacity());
michael@0 661 JSRuntime *rt = runtimeFromMainThread();
michael@0 662 if (JS::IsIncrementalBarrierNeeded(rt)) {
michael@0 663 JS::Zone *zone = this->zone();
michael@0 664 for (uint32_t i = 0; i < count; ++i)
michael@0 665 elements[dstStart + i].set(zone, this, js::HeapSlot::Element, dstStart + i, src[i]);
michael@0 666 } else {
michael@0 667 memcpy(&elements[dstStart], src, count * sizeof(js::HeapSlot));
michael@0 668 DenseRangeWriteBarrierPost(rt, this, dstStart, count);
michael@0 669 }
michael@0 670 }
michael@0 671
michael@0 672 void initDenseElements(uint32_t dstStart, const js::Value *src, uint32_t count) {
michael@0 673 JS_ASSERT(dstStart + count <= getDenseCapacity());
michael@0 674 memcpy(&elements[dstStart], src, count * sizeof(js::HeapSlot));
michael@0 675 DenseRangeWriteBarrierPost(runtimeFromMainThread(), this, dstStart, count);
michael@0 676 }
michael@0 677
michael@0 678 void initDenseElementsUnbarriered(uint32_t dstStart, const js::Value *src, uint32_t count) {
michael@0 679 /*
michael@0 680 * For use by parallel threads, which since they cannot see nursery
michael@0 681 * things do not require a barrier.
michael@0 682 */
michael@0 683 JS_ASSERT(dstStart + count <= getDenseCapacity());
michael@0 684 #if defined(DEBUG) && defined(JSGC_GENERATIONAL)
michael@0 685 JS::shadow::Runtime *rt = JS::shadow::Runtime::asShadowRuntime(runtimeFromAnyThread());
michael@0 686 JS_ASSERT(!js::gc::IsInsideNursery(rt, this));
michael@0 687 for (uint32_t index = 0; index < count; ++index) {
michael@0 688 const JS::Value& value = src[index];
michael@0 689 if (value.isMarkable())
michael@0 690 JS_ASSERT(!js::gc::IsInsideNursery(rt, value.toGCThing()));
michael@0 691 }
michael@0 692 #endif
michael@0 693 memcpy(&elements[dstStart], src, count * sizeof(js::HeapSlot));
michael@0 694 }
michael@0 695
michael@0 696 void moveDenseElements(uint32_t dstStart, uint32_t srcStart, uint32_t count) {
michael@0 697 JS_ASSERT(dstStart + count <= getDenseCapacity());
michael@0 698 JS_ASSERT(srcStart + count <= getDenseInitializedLength());
michael@0 699
michael@0 700 /*
michael@0 701 * Using memmove here would skip write barriers. Also, we need to consider
michael@0 702 * an array containing [A, B, C], in the following situation:
michael@0 703 *
michael@0 704 * 1. Incremental GC marks slot 0 of array (i.e., A), then returns to JS code.
michael@0 705 * 2. JS code moves slots 1..2 into slots 0..1, so it contains [B, C, C].
michael@0 706 * 3. Incremental GC finishes by marking slots 1 and 2 (i.e., C).
michael@0 707 *
michael@0 708 * Since normal marking never happens on B, it is very important that the
michael@0 709 * write barrier is invoked here on B, despite the fact that it exists in
michael@0 710 * the array before and after the move.
michael@0 711 */
michael@0 712 JS::Zone *zone = this->zone();
michael@0 713 JS::shadow::Zone *shadowZone = JS::shadow::Zone::asShadowZone(zone);
michael@0 714 if (shadowZone->needsBarrier()) {
michael@0 715 if (dstStart < srcStart) {
michael@0 716 js::HeapSlot *dst = elements + dstStart;
michael@0 717 js::HeapSlot *src = elements + srcStart;
michael@0 718 for (uint32_t i = 0; i < count; i++, dst++, src++)
michael@0 719 dst->set(zone, this, js::HeapSlot::Element, dst - elements, *src);
michael@0 720 } else {
michael@0 721 js::HeapSlot *dst = elements + dstStart + count - 1;
michael@0 722 js::HeapSlot *src = elements + srcStart + count - 1;
michael@0 723 for (uint32_t i = 0; i < count; i++, dst--, src--)
michael@0 724 dst->set(zone, this, js::HeapSlot::Element, dst - elements, *src);
michael@0 725 }
michael@0 726 } else {
michael@0 727 memmove(elements + dstStart, elements + srcStart, count * sizeof(js::HeapSlot));
michael@0 728 DenseRangeWriteBarrierPost(runtimeFromMainThread(), this, dstStart, count);
michael@0 729 }
michael@0 730 }
michael@0 731
michael@0 732 void moveDenseElementsNoPreBarrier(uint32_t dstStart, uint32_t srcStart, uint32_t count) {
michael@0 733 JS_ASSERT(!shadowZone()->needsBarrier());
michael@0 734
michael@0 735 JS_ASSERT(dstStart + count <= getDenseCapacity());
michael@0 736 JS_ASSERT(srcStart + count <= getDenseCapacity());
michael@0 737
michael@0 738 memmove(elements + dstStart, elements + srcStart, count * sizeof(js::Value));
michael@0 739 DenseRangeWriteBarrierPost(runtimeFromMainThread(), this, dstStart, count);
michael@0 740 }
michael@0 741
michael@0 742 bool shouldConvertDoubleElements() {
michael@0 743 JS_ASSERT(getClass()->isNative());
michael@0 744 return getElementsHeader()->shouldConvertDoubleElements();
michael@0 745 }
michael@0 746
michael@0 747 inline void setShouldConvertDoubleElements();
michael@0 748 inline void clearShouldConvertDoubleElements();
michael@0 749
michael@0 750 /* Packed information for this object's elements. */
michael@0 751 inline bool writeToIndexWouldMarkNotPacked(uint32_t index);
michael@0 752 inline void markDenseElementsNotPacked(js::ExclusiveContext *cx);
michael@0 753
michael@0 754 /*
michael@0 755 * ensureDenseElements ensures that the object can hold at least
michael@0 756 * index + extra elements. It returns ED_OK on success, ED_FAILED on
michael@0 757 * failure to grow the array, ED_SPARSE when the object is too sparse to
michael@0 758 * grow (this includes the case of index + extra overflow). In the last
michael@0 759 * two cases the object is kept intact.
michael@0 760 */
michael@0 761 enum EnsureDenseResult { ED_OK, ED_FAILED, ED_SPARSE };
michael@0 762
michael@0 763 private:
michael@0 764 inline EnsureDenseResult ensureDenseElementsNoPackedCheck(js::ThreadSafeContext *cx,
michael@0 765 uint32_t index, uint32_t extra);
michael@0 766
michael@0 767 public:
michael@0 768 inline EnsureDenseResult ensureDenseElements(js::ExclusiveContext *cx,
michael@0 769 uint32_t index, uint32_t extra);
michael@0 770 inline EnsureDenseResult ensureDenseElementsPreservePackedFlag(js::ThreadSafeContext *cx,
michael@0 771 uint32_t index, uint32_t extra);
michael@0 772
michael@0 773 inline EnsureDenseResult extendDenseElements(js::ThreadSafeContext *cx,
michael@0 774 uint32_t requiredCapacity, uint32_t extra);
michael@0 775
michael@0 776 /* Convert a single dense element to a sparse property. */
michael@0 777 static bool sparsifyDenseElement(js::ExclusiveContext *cx,
michael@0 778 js::HandleObject obj, uint32_t index);
michael@0 779
michael@0 780 /* Convert all dense elements to sparse properties. */
michael@0 781 static bool sparsifyDenseElements(js::ExclusiveContext *cx, js::HandleObject obj);
michael@0 782
michael@0 783 /* Small objects are dense, no matter what. */
michael@0 784 static const uint32_t MIN_SPARSE_INDEX = 1000;
michael@0 785
michael@0 786 /*
michael@0 787 * Element storage for an object will be sparse if fewer than 1/8 indexes
michael@0 788 * are filled in.
michael@0 789 */
michael@0 790 static const unsigned SPARSE_DENSITY_RATIO = 8;
michael@0 791
michael@0 792 /*
michael@0 793 * Check if after growing the object's elements will be too sparse.
michael@0 794 * newElementsHint is an estimated number of elements to be added.
michael@0 795 */
michael@0 796 bool willBeSparseElements(uint32_t requiredCapacity, uint32_t newElementsHint);
michael@0 797
michael@0 798 /*
michael@0 799 * After adding a sparse index to obj, see if it should be converted to use
michael@0 800 * dense elements.
michael@0 801 */
michael@0 802 static EnsureDenseResult maybeDensifySparseElements(js::ExclusiveContext *cx, js::HandleObject obj);
michael@0 803
michael@0 804 public:
michael@0 805 /*
michael@0 806 * Iterator-specific getters and setters.
michael@0 807 */
michael@0 808
michael@0 809 static const uint32_t ITER_CLASS_NFIXED_SLOTS = 1;
michael@0 810
michael@0 811 /*
michael@0 812 * Back to generic stuff.
michael@0 813 */
michael@0 814 bool isCallable() {
michael@0 815 return getClass()->isCallable();
michael@0 816 }
michael@0 817
michael@0 818 inline void finish(js::FreeOp *fop);
michael@0 819 MOZ_ALWAYS_INLINE void finalize(js::FreeOp *fop);
michael@0 820
michael@0 821 static inline bool hasProperty(JSContext *cx, js::HandleObject obj,
michael@0 822 js::HandleId id, bool *foundp);
michael@0 823
michael@0 824 /*
michael@0 825 * Allocate and free an object slot.
michael@0 826 *
michael@0 827 * FIXME: bug 593129 -- slot allocation should be done by object methods
michael@0 828 * after calling object-parameter-free shape methods, avoiding coupling
michael@0 829 * logic across the object vs. shape module wall.
michael@0 830 */
michael@0 831 static bool allocSlot(js::ThreadSafeContext *cx, JS::HandleObject obj, uint32_t *slotp);
michael@0 832 void freeSlot(uint32_t slot);
michael@0 833
michael@0 834 public:
michael@0 835 static bool reportReadOnly(js::ThreadSafeContext *cx, jsid id, unsigned report = JSREPORT_ERROR);
michael@0 836 bool reportNotConfigurable(js::ThreadSafeContext *cx, jsid id, unsigned report = JSREPORT_ERROR);
michael@0 837 bool reportNotExtensible(js::ThreadSafeContext *cx, unsigned report = JSREPORT_ERROR);
michael@0 838
michael@0 839 /*
michael@0 840 * Get the property with the given id, then call it as a function with the
michael@0 841 * given arguments, providing this object as |this|. If the property isn't
michael@0 842 * callable a TypeError will be thrown. On success the value returned by
michael@0 843 * the call is stored in *vp.
michael@0 844 */
michael@0 845 bool callMethod(JSContext *cx, js::HandleId id, unsigned argc, js::Value *argv,
michael@0 846 js::MutableHandleValue vp);
michael@0 847
michael@0 848 private:
michael@0 849 static js::Shape *getChildPropertyOnDictionary(js::ThreadSafeContext *cx, JS::HandleObject obj,
michael@0 850 js::HandleShape parent, js::StackShape &child);
michael@0 851 static js::Shape *getChildProperty(js::ExclusiveContext *cx, JS::HandleObject obj,
michael@0 852 js::HandleShape parent, js::StackShape &child);
michael@0 853 template <js::ExecutionMode mode>
michael@0 854 static inline js::Shape *
michael@0 855 getOrLookupChildProperty(typename js::ExecutionModeTraits<mode>::ExclusiveContextType cx,
michael@0 856 JS::HandleObject obj, js::HandleShape parent, js::StackShape &child)
michael@0 857 {
michael@0 858 if (mode == js::ParallelExecution)
michael@0 859 return lookupChildProperty(cx, obj, parent, child);
michael@0 860 return getChildProperty(cx->asExclusiveContext(), obj, parent, child);
michael@0 861 }
michael@0 862
michael@0 863 public:
michael@0 864 /*
michael@0 865 * XXX: This should be private, but is public because it needs to be a
michael@0 866 * friend of ThreadSafeContext to get to the propertyTree on cx->compartment_.
michael@0 867 */
michael@0 868 static js::Shape *lookupChildProperty(js::ThreadSafeContext *cx, JS::HandleObject obj,
michael@0 869 js::HandleShape parent, js::StackShape &child);
michael@0 870
michael@0 871
michael@0 872 protected:
michael@0 873 /*
michael@0 874 * Internal helper that adds a shape not yet mapped by this object.
michael@0 875 *
michael@0 876 * Notes:
michael@0 877 * 1. getter and setter must be normalized based on flags (see jsscope.cpp).
michael@0 878 * 2. Checks for non-extensibility must be done by callers.
michael@0 879 */
michael@0 880 template <js::ExecutionMode mode>
michael@0 881 static js::Shape *
michael@0 882 addPropertyInternal(typename js::ExecutionModeTraits<mode>::ExclusiveContextType cx,
michael@0 883 JS::HandleObject obj, JS::HandleId id,
michael@0 884 JSPropertyOp getter, JSStrictPropertyOp setter,
michael@0 885 uint32_t slot, unsigned attrs, unsigned flags, js::Shape **spp,
michael@0 886 bool allowDictionary);
michael@0 887
michael@0 888 private:
michael@0 889 struct TradeGutsReserved;
michael@0 890 static bool ReserveForTradeGuts(JSContext *cx, JSObject *a, JSObject *b,
michael@0 891 TradeGutsReserved &reserved);
michael@0 892
michael@0 893 static void TradeGuts(JSContext *cx, JSObject *a, JSObject *b,
michael@0 894 TradeGutsReserved &reserved);
michael@0 895
michael@0 896 public:
michael@0 897 /* Add a property whose id is not yet in this scope. */
michael@0 898 static js::Shape *addProperty(js::ExclusiveContext *cx, JS::HandleObject, JS::HandleId id,
michael@0 899 JSPropertyOp getter, JSStrictPropertyOp setter,
michael@0 900 uint32_t slot, unsigned attrs, unsigned flags,
michael@0 901 bool allowDictionary = true);
michael@0 902
michael@0 903 /* Add a data property whose id is not yet in this scope. */
michael@0 904 js::Shape *addDataProperty(js::ExclusiveContext *cx,
michael@0 905 jsid id_, uint32_t slot, unsigned attrs);
michael@0 906 js::Shape *addDataProperty(js::ExclusiveContext *cx, js::HandlePropertyName name,
michael@0 907 uint32_t slot, unsigned attrs);
michael@0 908
michael@0 909 /* Add or overwrite a property for id in this scope. */
michael@0 910 template <js::ExecutionMode mode>
michael@0 911 static js::Shape *
michael@0 912 putProperty(typename js::ExecutionModeTraits<mode>::ExclusiveContextType cx,
michael@0 913 JS::HandleObject obj, JS::HandleId id,
michael@0 914 JSPropertyOp getter, JSStrictPropertyOp setter,
michael@0 915 uint32_t slot, unsigned attrs,
michael@0 916 unsigned flags);
michael@0 917 template <js::ExecutionMode mode>
michael@0 918 static inline js::Shape *
michael@0 919 putProperty(typename js::ExecutionModeTraits<mode>::ExclusiveContextType cx,
michael@0 920 JS::HandleObject obj, js::PropertyName *name,
michael@0 921 JSPropertyOp getter, JSStrictPropertyOp setter,
michael@0 922 uint32_t slot, unsigned attrs,
michael@0 923 unsigned flags);
michael@0 924
michael@0 925 /* Change the given property into a sibling with the same id in this scope. */
michael@0 926 template <js::ExecutionMode mode>
michael@0 927 static js::Shape *
michael@0 928 changeProperty(typename js::ExecutionModeTraits<mode>::ExclusiveContextType cx,
michael@0 929 js::HandleObject obj, js::HandleShape shape, unsigned attrs, unsigned mask,
michael@0 930 JSPropertyOp getter, JSStrictPropertyOp setter);
michael@0 931
michael@0 932 static inline bool changePropertyAttributes(JSContext *cx, js::HandleObject obj,
michael@0 933 js::HandleShape shape, unsigned attrs);
michael@0 934
michael@0 935 /* Remove the property named by id from this object. */
michael@0 936 bool removeProperty(js::ExclusiveContext *cx, jsid id);
michael@0 937
michael@0 938 /* Clear the scope, making it empty. */
michael@0 939 static void clear(JSContext *cx, js::HandleObject obj);
michael@0 940
michael@0 941 static bool lookupGeneric(JSContext *cx, js::HandleObject obj, js::HandleId id,
michael@0 942 js::MutableHandleObject objp, js::MutableHandleShape propp);
michael@0 943
michael@0 944 static bool lookupProperty(JSContext *cx, js::HandleObject obj, js::PropertyName *name,
michael@0 945 js::MutableHandleObject objp, js::MutableHandleShape propp)
michael@0 946 {
michael@0 947 JS::RootedId id(cx, js::NameToId(name));
michael@0 948 return lookupGeneric(cx, obj, id, objp, propp);
michael@0 949 }
michael@0 950
michael@0 951 static bool lookupElement(JSContext *cx, js::HandleObject obj, uint32_t index,
michael@0 952 js::MutableHandleObject objp, js::MutableHandleShape propp)
michael@0 953 {
michael@0 954 js::LookupElementOp op = obj->getOps()->lookupElement;
michael@0 955 return (op ? op : js::baseops::LookupElement)(cx, obj, index, objp, propp);
michael@0 956 }
michael@0 957
michael@0 958 static bool defineGeneric(js::ExclusiveContext *cx, js::HandleObject obj,
michael@0 959 js::HandleId id, js::HandleValue value,
michael@0 960 JSPropertyOp getter = JS_PropertyStub,
michael@0 961 JSStrictPropertyOp setter = JS_StrictPropertyStub,
michael@0 962 unsigned attrs = JSPROP_ENUMERATE);
michael@0 963
michael@0 964 static bool defineProperty(js::ExclusiveContext *cx, js::HandleObject obj,
michael@0 965 js::PropertyName *name, js::HandleValue value,
michael@0 966 JSPropertyOp getter = JS_PropertyStub,
michael@0 967 JSStrictPropertyOp setter = JS_StrictPropertyStub,
michael@0 968 unsigned attrs = JSPROP_ENUMERATE);
michael@0 969
michael@0 970 static bool defineElement(js::ExclusiveContext *cx, js::HandleObject obj,
michael@0 971 uint32_t index, js::HandleValue value,
michael@0 972 JSPropertyOp getter = JS_PropertyStub,
michael@0 973 JSStrictPropertyOp setter = JS_StrictPropertyStub,
michael@0 974 unsigned attrs = JSPROP_ENUMERATE);
michael@0 975
michael@0 976 static bool getGeneric(JSContext *cx, js::HandleObject obj, js::HandleObject receiver,
michael@0 977 js::HandleId id, js::MutableHandleValue vp)
michael@0 978 {
michael@0 979 JS_ASSERT(!!obj->getOps()->getGeneric == !!obj->getOps()->getProperty);
michael@0 980 js::GenericIdOp op = obj->getOps()->getGeneric;
michael@0 981 if (op) {
michael@0 982 if (!op(cx, obj, receiver, id, vp))
michael@0 983 return false;
michael@0 984 } else {
michael@0 985 if (!js::baseops::GetProperty(cx, obj, receiver, id, vp))
michael@0 986 return false;
michael@0 987 }
michael@0 988 return true;
michael@0 989 }
michael@0 990
michael@0 991 static bool getGenericNoGC(JSContext *cx, JSObject *obj, JSObject *receiver,
michael@0 992 jsid id, js::Value *vp)
michael@0 993 {
michael@0 994 js::GenericIdOp op = obj->getOps()->getGeneric;
michael@0 995 if (op)
michael@0 996 return false;
michael@0 997 return js::baseops::GetPropertyNoGC(cx, obj, receiver, id, vp);
michael@0 998 }
michael@0 999
michael@0 1000 static bool getProperty(JSContext *cx, js::HandleObject obj, js::HandleObject receiver,
michael@0 1001 js::PropertyName *name, js::MutableHandleValue vp)
michael@0 1002 {
michael@0 1003 JS::RootedId id(cx, js::NameToId(name));
michael@0 1004 return getGeneric(cx, obj, receiver, id, vp);
michael@0 1005 }
michael@0 1006
michael@0 1007 static bool getPropertyNoGC(JSContext *cx, JSObject *obj, JSObject *receiver,
michael@0 1008 js::PropertyName *name, js::Value *vp)
michael@0 1009 {
michael@0 1010 return getGenericNoGC(cx, obj, receiver, js::NameToId(name), vp);
michael@0 1011 }
michael@0 1012
michael@0 1013 static inline bool getElement(JSContext *cx, js::HandleObject obj, js::HandleObject receiver,
michael@0 1014 uint32_t index, js::MutableHandleValue vp);
michael@0 1015 static inline bool getElementNoGC(JSContext *cx, JSObject *obj, JSObject *receiver,
michael@0 1016 uint32_t index, js::Value *vp);
michael@0 1017
michael@0 1018 static bool setGeneric(JSContext *cx, js::HandleObject obj, js::HandleObject receiver,
michael@0 1019 js::HandleId id, js::MutableHandleValue vp, bool strict)
michael@0 1020 {
michael@0 1021 if (obj->getOps()->setGeneric)
michael@0 1022 return nonNativeSetProperty(cx, obj, id, vp, strict);
michael@0 1023 return js::baseops::SetPropertyHelper<js::SequentialExecution>(
michael@0 1024 cx, obj, receiver, id, js::baseops::Qualified, vp, strict);
michael@0 1025 }
michael@0 1026
michael@0 1027 static bool setProperty(JSContext *cx, js::HandleObject obj, js::HandleObject receiver,
michael@0 1028 js::PropertyName *name,
michael@0 1029 js::MutableHandleValue vp, bool strict)
michael@0 1030 {
michael@0 1031 JS::RootedId id(cx, js::NameToId(name));
michael@0 1032 return setGeneric(cx, obj, receiver, id, vp, strict);
michael@0 1033 }
michael@0 1034
michael@0 1035 static bool setElement(JSContext *cx, js::HandleObject obj, js::HandleObject receiver,
michael@0 1036 uint32_t index, js::MutableHandleValue vp, bool strict)
michael@0 1037 {
michael@0 1038 if (obj->getOps()->setElement)
michael@0 1039 return nonNativeSetElement(cx, obj, index, vp, strict);
michael@0 1040 return js::baseops::SetElementHelper(cx, obj, receiver, index, vp, strict);
michael@0 1041 }
michael@0 1042
michael@0 1043 static bool nonNativeSetProperty(JSContext *cx, js::HandleObject obj,
michael@0 1044 js::HandleId id, js::MutableHandleValue vp, bool strict);
michael@0 1045 static bool nonNativeSetElement(JSContext *cx, js::HandleObject obj,
michael@0 1046 uint32_t index, js::MutableHandleValue vp, bool strict);
michael@0 1047
michael@0 1048 static bool getGenericAttributes(JSContext *cx, js::HandleObject obj,
michael@0 1049 js::HandleId id, unsigned *attrsp)
michael@0 1050 {
michael@0 1051 js::GenericAttributesOp op = obj->getOps()->getGenericAttributes;
michael@0 1052 return (op ? op : js::baseops::GetAttributes)(cx, obj, id, attrsp);
michael@0 1053 }
michael@0 1054
michael@0 1055 static inline bool setGenericAttributes(JSContext *cx, js::HandleObject obj,
michael@0 1056 js::HandleId id, unsigned *attrsp);
michael@0 1057
michael@0 1058 static inline bool deleteProperty(JSContext *cx, js::HandleObject obj,
michael@0 1059 js::HandlePropertyName name,
michael@0 1060 bool *succeeded);
michael@0 1061 static inline bool deleteElement(JSContext *cx, js::HandleObject obj,
michael@0 1062 uint32_t index, bool *succeeded);
michael@0 1063 static bool deleteByValue(JSContext *cx, js::HandleObject obj,
michael@0 1064 const js::Value &property, bool *succeeded);
michael@0 1065
michael@0 1066 static inline bool watch(JSContext *cx, JS::HandleObject obj, JS::HandleId id,
michael@0 1067 JS::HandleObject callable);
michael@0 1068 static inline bool unwatch(JSContext *cx, JS::HandleObject obj, JS::HandleId id);
michael@0 1069
michael@0 1070 static bool enumerate(JSContext *cx, JS::HandleObject obj, JSIterateOp iterop,
michael@0 1071 JS::MutableHandleValue statep, JS::MutableHandleId idp)
michael@0 1072 {
michael@0 1073 JSNewEnumerateOp op = obj->getOps()->enumerate;
michael@0 1074 return (op ? op : JS_EnumerateState)(cx, obj, iterop, statep, idp);
michael@0 1075 }
michael@0 1076
michael@0 1077 static bool defaultValue(JSContext *cx, js::HandleObject obj, JSType hint,
michael@0 1078 js::MutableHandleValue vp)
michael@0 1079 {
michael@0 1080 JSConvertOp op = obj->getClass()->convert;
michael@0 1081 bool ok;
michael@0 1082 if (op == JS_ConvertStub)
michael@0 1083 ok = js::DefaultValue(cx, obj, hint, vp);
michael@0 1084 else
michael@0 1085 ok = op(cx, obj, hint, vp);
michael@0 1086 JS_ASSERT_IF(ok, vp.isPrimitive());
michael@0 1087 return ok;
michael@0 1088 }
michael@0 1089
michael@0 1090 static JSObject *thisObject(JSContext *cx, js::HandleObject obj)
michael@0 1091 {
michael@0 1092 JSObjectOp op = obj->getOps()->thisObject;
michael@0 1093 return op ? op(cx, obj) : obj;
michael@0 1094 }
michael@0 1095
michael@0 1096 static bool thisObject(JSContext *cx, const js::Value &v, js::Value *vp);
michael@0 1097
michael@0 1098 static bool swap(JSContext *cx, JS::HandleObject a, JS::HandleObject b);
michael@0 1099
michael@0 1100 inline void initArrayClass();
michael@0 1101
michael@0 1102 /*
michael@0 1103 * In addition to the generic object interface provided by JSObject,
michael@0 1104 * specific types of objects may provide additional operations. To access,
michael@0 1105 * these addition operations, callers should use the pattern:
michael@0 1106 *
michael@0 1107 * if (obj.is<XObject>()) {
michael@0 1108 * XObject &x = obj.as<XObject>();
michael@0 1109 * x.foo();
michael@0 1110 * }
michael@0 1111 *
michael@0 1112 * These XObject classes form a hierarchy. For example, for a cloned block
michael@0 1113 * object, the following predicates are true: is<ClonedBlockObject>,
michael@0 1114 * is<BlockObject>, is<NestedScopeObject> and is<ScopeObject>. Each of
michael@0 1115 * these has a respective class that derives and adds operations.
michael@0 1116 *
michael@0 1117 * A class XObject is defined in a vm/XObject{.h, .cpp, -inl.h} file
michael@0 1118 * triplet (along with any class YObject that derives XObject).
michael@0 1119 *
michael@0 1120 * Note that X represents a low-level representation and does not query the
michael@0 1121 * [[Class]] property of object defined by the spec (for this, see
michael@0 1122 * js::ObjectClassIs).
michael@0 1123 */
michael@0 1124
michael@0 1125 template <class T>
michael@0 1126 inline bool is() const { return getClass() == &T::class_; }
michael@0 1127
michael@0 1128 template <class T>
michael@0 1129 T &as() {
michael@0 1130 JS_ASSERT(is<T>());
michael@0 1131 return *static_cast<T *>(this);
michael@0 1132 }
michael@0 1133
michael@0 1134 template <class T>
michael@0 1135 const T &as() const {
michael@0 1136 JS_ASSERT(is<T>());
michael@0 1137 return *static_cast<const T *>(this);
michael@0 1138 }
michael@0 1139
michael@0 1140 static inline js::ThingRootKind rootKind() { return js::THING_ROOT_OBJECT; }
michael@0 1141
michael@0 1142 #ifdef DEBUG
michael@0 1143 void dump();
michael@0 1144 #endif
michael@0 1145
michael@0 1146 private:
michael@0 1147 static void staticAsserts() {
michael@0 1148 static_assert(sizeof(JSObject) == sizeof(js::shadow::Object),
michael@0 1149 "shadow interface must match actual interface");
michael@0 1150 static_assert(sizeof(JSObject) == sizeof(js::ObjectImpl),
michael@0 1151 "JSObject itself must not have any fields");
michael@0 1152 static_assert(sizeof(JSObject) % sizeof(js::Value) == 0,
michael@0 1153 "fixed slots after an object must be aligned");
michael@0 1154 static_assert(js::shadow::Object::MAX_FIXED_SLOTS == MAX_FIXED_SLOTS,
michael@0 1155 "We shouldn't be confused about our actual maximum "
michael@0 1156 "number of fixed slots");
michael@0 1157 }
michael@0 1158
michael@0 1159 JSObject() MOZ_DELETE;
michael@0 1160 JSObject(const JSObject &other) MOZ_DELETE;
michael@0 1161 void operator=(const JSObject &other) MOZ_DELETE;
michael@0 1162 };
michael@0 1163
michael@0 1164 template <class U>
michael@0 1165 MOZ_ALWAYS_INLINE JS::Handle<U*>
michael@0 1166 js::RootedBase<JSObject*>::as() const
michael@0 1167 {
michael@0 1168 const JS::Rooted<JSObject*> &self = *static_cast<const JS::Rooted<JSObject*>*>(this);
michael@0 1169 JS_ASSERT(self->is<U>());
michael@0 1170 return Handle<U*>::fromMarkedLocation(reinterpret_cast<U* const*>(self.address()));
michael@0 1171 }
michael@0 1172
michael@0 1173 /*
michael@0 1174 * The only sensible way to compare JSObject with == is by identity. We use
michael@0 1175 * const& instead of * as a syntactic way to assert non-null. This leads to an
michael@0 1176 * abundance of address-of operators to identity. Hence this overload.
michael@0 1177 */
michael@0 1178 static MOZ_ALWAYS_INLINE bool
michael@0 1179 operator==(const JSObject &lhs, const JSObject &rhs)
michael@0 1180 {
michael@0 1181 return &lhs == &rhs;
michael@0 1182 }
michael@0 1183
michael@0 1184 static MOZ_ALWAYS_INLINE bool
michael@0 1185 operator!=(const JSObject &lhs, const JSObject &rhs)
michael@0 1186 {
michael@0 1187 return &lhs != &rhs;
michael@0 1188 }
michael@0 1189
michael@0 1190 struct JSObject_Slots2 : JSObject { js::Value fslots[2]; };
michael@0 1191 struct JSObject_Slots4 : JSObject { js::Value fslots[4]; };
michael@0 1192 struct JSObject_Slots8 : JSObject { js::Value fslots[8]; };
michael@0 1193 struct JSObject_Slots12 : JSObject { js::Value fslots[12]; };
michael@0 1194 struct JSObject_Slots16 : JSObject { js::Value fslots[16]; };
michael@0 1195
michael@0 1196 static inline bool
michael@0 1197 js_IsCallable(const js::Value &v)
michael@0 1198 {
michael@0 1199 return v.isObject() && v.toObject().isCallable();
michael@0 1200 }
michael@0 1201
michael@0 1202 inline JSObject *
michael@0 1203 GetInnerObject(JSContext *cx, js::HandleObject obj)
michael@0 1204 {
michael@0 1205 if (JSObjectOp op = obj->getClass()->ext.innerObject)
michael@0 1206 return op(cx, obj);
michael@0 1207 return obj;
michael@0 1208 }
michael@0 1209
michael@0 1210 inline JSObject *
michael@0 1211 GetOuterObject(JSContext *cx, js::HandleObject obj)
michael@0 1212 {
michael@0 1213 if (JSObjectOp op = obj->getClass()->ext.outerObject)
michael@0 1214 return op(cx, obj);
michael@0 1215 return obj;
michael@0 1216 }
michael@0 1217
michael@0 1218 class JSValueArray {
michael@0 1219 public:
michael@0 1220 const jsval *array;
michael@0 1221 size_t length;
michael@0 1222
michael@0 1223 JSValueArray(const jsval *v, size_t c) : array(v), length(c) {}
michael@0 1224 };
michael@0 1225
michael@0 1226 class ValueArray {
michael@0 1227 public:
michael@0 1228 js::Value *array;
michael@0 1229 size_t length;
michael@0 1230
michael@0 1231 ValueArray(js::Value *v, size_t c) : array(v), length(c) {}
michael@0 1232 };
michael@0 1233
michael@0 1234 namespace js {
michael@0 1235
michael@0 1236 /* Set *resultp to tell whether obj has an own property with the given id. */
michael@0 1237 bool
michael@0 1238 HasOwnProperty(JSContext *cx, HandleObject obj, HandleId id, bool *resultp);
michael@0 1239
michael@0 1240 template <AllowGC allowGC>
michael@0 1241 extern bool
michael@0 1242 HasOwnProperty(JSContext *cx, LookupGenericOp lookup,
michael@0 1243 typename MaybeRooted<JSObject*, allowGC>::HandleType obj,
michael@0 1244 typename MaybeRooted<jsid, allowGC>::HandleType id,
michael@0 1245 typename MaybeRooted<JSObject*, allowGC>::MutableHandleType objp,
michael@0 1246 typename MaybeRooted<Shape*, allowGC>::MutableHandleType propp);
michael@0 1247
michael@0 1248 typedef JSObject *(*ClassInitializerOp)(JSContext *cx, JS::HandleObject obj);
michael@0 1249
michael@0 1250 /* Fast access to builtin constructors and prototypes. */
michael@0 1251 bool
michael@0 1252 GetBuiltinConstructor(ExclusiveContext *cx, JSProtoKey key, MutableHandleObject objp);
michael@0 1253
michael@0 1254 bool
michael@0 1255 GetBuiltinPrototype(ExclusiveContext *cx, JSProtoKey key, MutableHandleObject objp);
michael@0 1256
michael@0 1257 const Class *
michael@0 1258 ProtoKeyToClass(JSProtoKey key);
michael@0 1259
michael@0 1260 JSObject *
michael@0 1261 GetBuiltinPrototypePure(GlobalObject *global, JSProtoKey protoKey);
michael@0 1262
michael@0 1263 extern bool
michael@0 1264 SetClassAndProto(JSContext *cx, HandleObject obj,
michael@0 1265 const Class *clasp, Handle<TaggedProto> proto, bool *succeeded);
michael@0 1266
michael@0 1267 /*
michael@0 1268 * Property-lookup-based access to interface and prototype objects for classes.
michael@0 1269 * If the class is built-in (hhas a non-null JSProtoKey), these forward to
michael@0 1270 * GetClass{Object,Prototype}.
michael@0 1271 */
michael@0 1272
michael@0 1273 bool
michael@0 1274 FindClassObject(ExclusiveContext *cx, MutableHandleObject protop, const Class *clasp);
michael@0 1275
michael@0 1276 extern bool
michael@0 1277 FindClassPrototype(ExclusiveContext *cx, MutableHandleObject protop, const Class *clasp);
michael@0 1278
michael@0 1279 } /* namespace js */
michael@0 1280
michael@0 1281 /*
michael@0 1282 * Select Object.prototype method names shared between jsapi.cpp and jsobj.cpp.
michael@0 1283 */
michael@0 1284 extern const char js_watch_str[];
michael@0 1285 extern const char js_unwatch_str[];
michael@0 1286 extern const char js_hasOwnProperty_str[];
michael@0 1287 extern const char js_isPrototypeOf_str[];
michael@0 1288 extern const char js_propertyIsEnumerable_str[];
michael@0 1289
michael@0 1290 #ifdef JS_OLD_GETTER_SETTER_METHODS
michael@0 1291 extern const char js_defineGetter_str[];
michael@0 1292 extern const char js_defineSetter_str[];
michael@0 1293 extern const char js_lookupGetter_str[];
michael@0 1294 extern const char js_lookupSetter_str[];
michael@0 1295 #endif
michael@0 1296
michael@0 1297 extern bool
michael@0 1298 js_PopulateObject(JSContext *cx, js::HandleObject newborn, js::HandleObject props);
michael@0 1299
michael@0 1300
michael@0 1301 namespace js {
michael@0 1302
michael@0 1303 extern bool
michael@0 1304 DefineOwnProperty(JSContext *cx, JS::HandleObject obj, JS::HandleId id,
michael@0 1305 JS::HandleValue descriptor, bool *bp);
michael@0 1306
michael@0 1307 extern bool
michael@0 1308 DefineOwnProperty(JSContext *cx, JS::HandleObject obj, JS::HandleId id,
michael@0 1309 JS::Handle<js::PropertyDescriptor> descriptor, bool *bp);
michael@0 1310
michael@0 1311 /*
michael@0 1312 * The NewObjectKind allows an allocation site to specify the type properties
michael@0 1313 * and lifetime requirements that must be fixed at allocation time.
michael@0 1314 */
michael@0 1315 enum NewObjectKind {
michael@0 1316 /* This is the default. Most objects are generic. */
michael@0 1317 GenericObject,
michael@0 1318
michael@0 1319 /*
michael@0 1320 * Singleton objects are treated specially by the type system. This flag
michael@0 1321 * ensures that the new object is automatically set up correctly as a
michael@0 1322 * singleton and is allocated in the correct heap.
michael@0 1323 */
michael@0 1324 SingletonObject,
michael@0 1325
michael@0 1326 /*
michael@0 1327 * Objects which may be marked as a singleton after allocation must still
michael@0 1328 * be allocated on the correct heap, but are not automatically setup as a
michael@0 1329 * singleton after allocation.
michael@0 1330 */
michael@0 1331 MaybeSingletonObject,
michael@0 1332
michael@0 1333 /*
michael@0 1334 * Objects which will not benefit from being allocated in the nursery
michael@0 1335 * (e.g. because they are known to have a long lifetime) may be allocated
michael@0 1336 * with this kind to place them immediately into the tenured generation.
michael@0 1337 */
michael@0 1338 TenuredObject
michael@0 1339 };
michael@0 1340
michael@0 1341 inline gc::InitialHeap
michael@0 1342 GetInitialHeap(NewObjectKind newKind, const Class *clasp)
michael@0 1343 {
michael@0 1344 if (clasp->finalize || newKind != GenericObject)
michael@0 1345 return gc::TenuredHeap;
michael@0 1346 return gc::DefaultHeap;
michael@0 1347 }
michael@0 1348
michael@0 1349 // Specialized call for constructing |this| with a known function callee,
michael@0 1350 // and a known prototype.
michael@0 1351 extern JSObject *
michael@0 1352 CreateThisForFunctionWithProto(JSContext *cx, js::HandleObject callee, JSObject *proto,
michael@0 1353 NewObjectKind newKind = GenericObject);
michael@0 1354
michael@0 1355 // Specialized call for constructing |this| with a known function callee.
michael@0 1356 extern JSObject *
michael@0 1357 CreateThisForFunction(JSContext *cx, js::HandleObject callee, NewObjectKind newKind);
michael@0 1358
michael@0 1359 // Generic call for constructing |this|.
michael@0 1360 extern JSObject *
michael@0 1361 CreateThis(JSContext *cx, const js::Class *clasp, js::HandleObject callee);
michael@0 1362
michael@0 1363 extern JSObject *
michael@0 1364 CloneObject(JSContext *cx, HandleObject obj, Handle<js::TaggedProto> proto, HandleObject parent);
michael@0 1365
michael@0 1366 extern JSObject *
michael@0 1367 DeepCloneObjectLiteral(JSContext *cx, HandleObject obj, NewObjectKind newKind = GenericObject);
michael@0 1368
michael@0 1369 /*
michael@0 1370 * Return successfully added or changed shape or nullptr on error.
michael@0 1371 */
michael@0 1372 extern bool
michael@0 1373 DefineNativeProperty(ExclusiveContext *cx, HandleObject obj, HandleId id, HandleValue value,
michael@0 1374 PropertyOp getter, StrictPropertyOp setter, unsigned attrs);
michael@0 1375
michael@0 1376 extern bool
michael@0 1377 LookupNativeProperty(ExclusiveContext *cx, HandleObject obj, HandleId id,
michael@0 1378 js::MutableHandleObject objp, js::MutableHandleShape propp);
michael@0 1379
michael@0 1380 /*
michael@0 1381 * Call the [[DefineOwnProperty]] internal method of obj.
michael@0 1382 *
michael@0 1383 * If obj is an array, this follows ES5 15.4.5.1.
michael@0 1384 * If obj is any other native object, this follows ES5 8.12.9.
michael@0 1385 * If obj is a proxy, this calls the proxy handler's defineProperty method.
michael@0 1386 * Otherwise, this reports an error and returns false.
michael@0 1387 */
michael@0 1388 extern bool
michael@0 1389 DefineProperty(JSContext *cx, js::HandleObject obj,
michael@0 1390 js::HandleId id, const PropDesc &desc, bool throwError,
michael@0 1391 bool *rval);
michael@0 1392
michael@0 1393 bool
michael@0 1394 DefineProperties(JSContext *cx, HandleObject obj, HandleObject props);
michael@0 1395
michael@0 1396 /*
michael@0 1397 * Read property descriptors from props, as for Object.defineProperties. See
michael@0 1398 * ES5 15.2.3.7 steps 3-5.
michael@0 1399 */
michael@0 1400 extern bool
michael@0 1401 ReadPropertyDescriptors(JSContext *cx, HandleObject props, bool checkAccessors,
michael@0 1402 AutoIdVector *ids, AutoPropDescArrayRooter *descs);
michael@0 1403
michael@0 1404 /* Read the name using a dynamic lookup on the scopeChain. */
michael@0 1405 extern bool
michael@0 1406 LookupName(JSContext *cx, HandlePropertyName name, HandleObject scopeChain,
michael@0 1407 MutableHandleObject objp, MutableHandleObject pobjp, MutableHandleShape propp);
michael@0 1408
michael@0 1409 extern bool
michael@0 1410 LookupNameNoGC(JSContext *cx, PropertyName *name, JSObject *scopeChain,
michael@0 1411 JSObject **objp, JSObject **pobjp, Shape **propp);
michael@0 1412
michael@0 1413 /*
michael@0 1414 * Like LookupName except returns the global object if 'name' is not found in
michael@0 1415 * any preceding non-global scope.
michael@0 1416 *
michael@0 1417 * Additionally, pobjp and propp are not needed by callers so they are not
michael@0 1418 * returned.
michael@0 1419 */
michael@0 1420 extern bool
michael@0 1421 LookupNameWithGlobalDefault(JSContext *cx, HandlePropertyName name, HandleObject scopeChain,
michael@0 1422 MutableHandleObject objp);
michael@0 1423
michael@0 1424 }
michael@0 1425
michael@0 1426 extern JSObject *
michael@0 1427 js_FindVariableScope(JSContext *cx, JSFunction **funp);
michael@0 1428
michael@0 1429
michael@0 1430 namespace js {
michael@0 1431
michael@0 1432 bool
michael@0 1433 NativeGet(JSContext *cx, js::Handle<JSObject*> obj, js::Handle<JSObject*> pobj,
michael@0 1434 js::Handle<js::Shape*> shape, js::MutableHandle<js::Value> vp);
michael@0 1435
michael@0 1436 template <js::ExecutionMode mode>
michael@0 1437 bool
michael@0 1438 NativeSet(typename js::ExecutionModeTraits<mode>::ContextType cx,
michael@0 1439 js::Handle<JSObject*> obj, js::Handle<JSObject*> receiver,
michael@0 1440 js::Handle<js::Shape*> shape, bool strict, js::MutableHandleValue vp);
michael@0 1441
michael@0 1442 bool
michael@0 1443 LookupPropertyPure(JSObject *obj, jsid id, JSObject **objp, Shape **propp);
michael@0 1444
michael@0 1445 bool
michael@0 1446 GetPropertyPure(ThreadSafeContext *cx, JSObject *obj, jsid id, Value *vp);
michael@0 1447
michael@0 1448 inline bool
michael@0 1449 GetPropertyPure(ThreadSafeContext *cx, JSObject *obj, PropertyName *name, Value *vp)
michael@0 1450 {
michael@0 1451 return GetPropertyPure(cx, obj, NameToId(name), vp);
michael@0 1452 }
michael@0 1453
michael@0 1454 bool
michael@0 1455 GetOwnPropertyDescriptor(JSContext *cx, HandleObject obj, HandleId id,
michael@0 1456 MutableHandle<PropertyDescriptor> desc);
michael@0 1457
michael@0 1458 bool
michael@0 1459 GetOwnPropertyDescriptor(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue vp);
michael@0 1460
michael@0 1461 bool
michael@0 1462 NewPropertyDescriptorObject(JSContext *cx, Handle<PropertyDescriptor> desc, MutableHandleValue vp);
michael@0 1463
michael@0 1464 /*
michael@0 1465 * If obj has an already-resolved data property for id, return true and
michael@0 1466 * store the property value in *vp.
michael@0 1467 */
michael@0 1468 extern bool
michael@0 1469 HasDataProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp);
michael@0 1470
michael@0 1471 inline bool
michael@0 1472 HasDataProperty(JSContext *cx, JSObject *obj, PropertyName *name, Value *vp)
michael@0 1473 {
michael@0 1474 return HasDataProperty(cx, obj, NameToId(name), vp);
michael@0 1475 }
michael@0 1476
michael@0 1477 extern bool
michael@0 1478 IsDelegate(JSContext *cx, HandleObject obj, const Value &v, bool *result);
michael@0 1479
michael@0 1480 // obj is a JSObject*, but we root it immediately up front. We do it
michael@0 1481 // that way because we need a Rooted temporary in this method anyway.
michael@0 1482 extern bool
michael@0 1483 IsDelegateOfObject(JSContext *cx, HandleObject protoObj, JSObject* obj, bool *result);
michael@0 1484
michael@0 1485 bool
michael@0 1486 GetObjectElementOperationPure(ThreadSafeContext *cx, JSObject *obj, const Value &prop, Value *vp);
michael@0 1487
michael@0 1488 /* Wrap boolean, number or string as Boolean, Number or String object. */
michael@0 1489 extern JSObject *
michael@0 1490 PrimitiveToObject(JSContext *cx, const Value &v);
michael@0 1491
michael@0 1492 } /* namespace js */
michael@0 1493
michael@0 1494 namespace js {
michael@0 1495
michael@0 1496 /*
michael@0 1497 * Invokes the ES5 ToObject algorithm on vp, returning the result. If vp might
michael@0 1498 * already be an object, use ToObject. reportCantConvert controls how null and
michael@0 1499 * undefined errors are reported.
michael@0 1500 */
michael@0 1501 extern JSObject *
michael@0 1502 ToObjectSlow(JSContext *cx, HandleValue vp, bool reportScanStack);
michael@0 1503
michael@0 1504 /* For object conversion in e.g. native functions. */
michael@0 1505 MOZ_ALWAYS_INLINE JSObject *
michael@0 1506 ToObject(JSContext *cx, HandleValue vp)
michael@0 1507 {
michael@0 1508 if (vp.isObject())
michael@0 1509 return &vp.toObject();
michael@0 1510 return ToObjectSlow(cx, vp, false);
michael@0 1511 }
michael@0 1512
michael@0 1513 /* For converting stack values to objects. */
michael@0 1514 MOZ_ALWAYS_INLINE JSObject *
michael@0 1515 ToObjectFromStack(JSContext *cx, HandleValue vp)
michael@0 1516 {
michael@0 1517 if (vp.isObject())
michael@0 1518 return &vp.toObject();
michael@0 1519 return ToObjectSlow(cx, vp, true);
michael@0 1520 }
michael@0 1521
michael@0 1522 template<XDRMode mode>
michael@0 1523 bool
michael@0 1524 XDRObjectLiteral(XDRState<mode> *xdr, MutableHandleObject obj);
michael@0 1525
michael@0 1526 extern JSObject *
michael@0 1527 CloneObjectLiteral(JSContext *cx, HandleObject parent, HandleObject srcObj);
michael@0 1528
michael@0 1529 } /* namespace js */
michael@0 1530
michael@0 1531 extern void
michael@0 1532 js_GetObjectSlotName(JSTracer *trc, char *buf, size_t bufsize);
michael@0 1533
michael@0 1534 extern bool
michael@0 1535 js_ReportGetterOnlyAssignment(JSContext *cx, bool strict);
michael@0 1536
michael@0 1537
michael@0 1538 namespace js {
michael@0 1539
michael@0 1540 extern JSObject *
michael@0 1541 NonNullObject(JSContext *cx, const Value &v);
michael@0 1542
michael@0 1543 extern const char *
michael@0 1544 InformalValueTypeName(const Value &v);
michael@0 1545
michael@0 1546 extern bool
michael@0 1547 GetFirstArgumentAsObject(JSContext *cx, const CallArgs &args, const char *method,
michael@0 1548 MutableHandleObject objp);
michael@0 1549
michael@0 1550 /* Helpers for throwing. These always return false. */
michael@0 1551 extern bool
michael@0 1552 Throw(JSContext *cx, jsid id, unsigned errorNumber);
michael@0 1553
michael@0 1554 extern bool
michael@0 1555 Throw(JSContext *cx, JSObject *obj, unsigned errorNumber);
michael@0 1556
michael@0 1557 } /* namespace js */
michael@0 1558
michael@0 1559 #endif /* jsobj_h */

mercurial