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