1 : /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: set ts=8 sw=4 et tw=99:
3 : *
4 : * ***** BEGIN LICENSE BLOCK *****
5 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 : *
7 : * The contents of this file are subject to the Mozilla Public License Version
8 : * 1.1 (the "License"); you may not use this file except in compliance with
9 : * the License. You may obtain a copy of the License at
10 : * http://www.mozilla.org/MPL/
11 : *
12 : * Software distributed under the License is distributed on an "AS IS" basis,
13 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 : * for the specific language governing rights and limitations under the
15 : * License.
16 : *
17 : * The Original Code is Mozilla Communicator client code, released
18 : * March 31, 1998.
19 : *
20 : * The Initial Developer of the Original Code is
21 : * Netscape Communications Corporation.
22 : * Portions created by the Initial Developer are Copyright (C) 1998
23 : * the Initial Developer. All Rights Reserved.
24 : *
25 : * Contributor(s):
26 : *
27 : * Alternatively, the contents of this file may be used under the terms of
28 : * either of the GNU General Public License Version 2 or later (the "GPL"),
29 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 : * in which case the provisions of the GPL or the LGPL are applicable instead
31 : * of those above. If you wish to allow use of your version of this file only
32 : * under the terms of either the GPL or the LGPL, and not to allow others to
33 : * use your version of this file under the terms of the MPL, indicate your
34 : * decision by deleting the provisions above and replace them with the notice
35 : * and other provisions required by the GPL or the LGPL. If you do not delete
36 : * the provisions above, a recipient may use your version of this file under
37 : * the terms of any one of the MPL, the GPL or the LGPL.
38 : *
39 : * ***** END LICENSE BLOCK ***** */
40 :
41 : #ifndef jsscope_h___
42 : #define jsscope_h___
43 : /*
44 : * JS symbol tables.
45 : */
46 : #include <new>
47 : #ifdef DEBUG
48 : #include <stdio.h>
49 : #endif
50 :
51 : #include "jsdhash.h"
52 : #include "jsobj.h"
53 : #include "jspropertytree.h"
54 : #include "jstypes.h"
55 :
56 : #include "js/HashTable.h"
57 : #include "gc/Root.h"
58 : #include "mozilla/Attributes.h"
59 :
60 : #ifdef _MSC_VER
61 : #pragma warning(push)
62 : #pragma warning(disable:4800)
63 : #pragma warning(push)
64 : #pragma warning(disable:4100) /* Silence unreferenced formal parameter warnings */
65 : #endif
66 :
67 : /*
68 : * In isolation, a Shape represents a property that exists in one or more
69 : * objects; it has an id, flags, etc. (But it doesn't represent the property's
70 : * value.) However, Shapes are always stored in linked linear sequence of
71 : * Shapes, called "shape lineages". Each shape lineage represents the layout of
72 : * an entire object.
73 : *
74 : * Every JSObject has a pointer, |shape_|, accessible via lastProperty(), to
75 : * the last Shape in a shape lineage, which identifies the property most
76 : * recently added to the object. This pointer permits fast object layout
77 : * tests. The shape lineage order also dictates the enumeration order for the
78 : * object; ECMA requires no particular order but this implementation has
79 : * promised and delivered property definition order.
80 : *
81 : * Shape lineages occur in two kinds of data structure.
82 : *
83 : * 1. N-ary property trees. Each path from a non-root node to the root node in
84 : * a property tree is a shape lineage. Property trees permit full (or
85 : * partial) sharing of Shapes between objects that have fully (or partly)
86 : * identical layouts. The root is an EmptyShape whose identity is determined
87 : * by the object's class, compartment and prototype. These Shapes are shared
88 : * and immutable.
89 : *
90 : * 2. Dictionary mode lists. Shapes in such lists are said to be "in
91 : * dictionary mode", as are objects that point to such Shapes. These Shapes
92 : * are unshared, private to a single object, and immutable except for their
93 : * links in the dictionary list.
94 : *
95 : * All shape lineages are bi-directionally linked, via the |parent| and
96 : * |kids|/|listp| members.
97 : *
98 : * Shape lineages start out life in the property tree. They can be converted
99 : * (by copying) to dictionary mode lists in the following circumstances.
100 : *
101 : * 1. The shape lineage's size reaches MAX_HEIGHT. This reasonable limit avoids
102 : * potential worst cases involving shape lineage mutations.
103 : *
104 : * 2. A property represented by a non-last Shape in a shape lineage is removed
105 : * from an object. (In the last Shape case, obj->shape_ can be easily
106 : * adjusted to point to obj->shape_->parent.) We originally tried lazy
107 : * forking of the property tree, but this blows up for delete/add
108 : * repetitions.
109 : *
110 : * 3. A property represented by a non-last Shape in a shape lineage has its
111 : * attributes modified.
112 : *
113 : * To find the Shape for a particular property of an object initially requires
114 : * a linear search. But if the number of searches starting at any particular
115 : * Shape in the property tree exceeds MAX_LINEAR_SEARCHES and the Shape's
116 : * lineage has (excluding the EmptyShape) at least MIN_ENTRIES, we create an
117 : * auxiliary hash table -- the PropertyTable -- that allows faster lookup.
118 : * Furthermore, a PropertyTable is always created for dictionary mode lists,
119 : * and it is attached to the last Shape in the lineage. Property tables for
120 : * property tree Shapes never change, but property tables for dictionary mode
121 : * Shapes can grow and shrink.
122 : *
123 : * There used to be a long, math-heavy comment here explaining why property
124 : * trees are more space-efficient than alternatives. This was removed in bug
125 : * 631138; see that bug for the full details.
126 : *
127 : * Because many Shapes have similar data, there is actually a secondary type
128 : * called a BaseShape that holds some of a Shape's data. Many shapes can share
129 : * a single BaseShape.
130 : */
131 :
132 : namespace js {
133 :
134 : /* Limit on the number of slotful properties in an object. */
135 : static const uint32_t SHAPE_INVALID_SLOT = JS_BIT(24) - 1;
136 : static const uint32_t SHAPE_MAXIMUM_SLOT = JS_BIT(24) - 2;
137 :
138 : /*
139 : * Shapes use multiplicative hashing, _a la_ jsdhash.[ch], but specialized to
140 : * minimize footprint.
141 : */
142 : struct PropertyTable {
143 : static const uint32_t MIN_ENTRIES = 7;
144 : static const uint32_t MIN_SIZE_LOG2 = 4;
145 : static const uint32_t MIN_SIZE = JS_BIT(MIN_SIZE_LOG2);
146 :
147 : int hashShift; /* multiplicative hash shift */
148 :
149 : uint32_t entryCount; /* number of entries in table */
150 : uint32_t removedCount; /* removed entry sentinels in table */
151 : uint32_t freelist; /* SHAPE_INVALID_SLOT or head of slot
152 : freelist in owning dictionary-mode
153 : object */
154 : js::Shape **entries; /* table of ptrs to shared tree nodes */
155 :
156 351675 : PropertyTable(uint32_t nentries)
157 : : hashShift(JS_DHASH_BITS - MIN_SIZE_LOG2),
158 : entryCount(nentries),
159 : removedCount(0),
160 351675 : freelist(SHAPE_INVALID_SLOT)
161 : {
162 : /* NB: entries is set by init, which must be called. */
163 351675 : }
164 :
165 351514 : ~PropertyTable() {
166 351514 : js::UnwantedForeground::free_(entries);
167 351514 : }
168 :
169 : /* By definition, hashShift = JS_DHASH_BITS - log2(capacity). */
170 4088275 : uint32_t capacity() const { return JS_BIT(JS_DHASH_BITS - hashShift); }
171 :
172 : /* Computes the size of the entries array for a given capacity. */
173 386524 : static size_t sizeOfEntries(size_t cap) { return cap * sizeof(Shape *); }
174 :
175 : /*
176 : * This counts the PropertyTable object itself (which must be
177 : * heap-allocated) and its |entries| array.
178 : */
179 616 : size_t sizeOfIncludingThis(JSMallocSizeOfFun mallocSizeOf) const {
180 616 : return mallocSizeOf(this) + mallocSizeOf(entries);
181 : }
182 :
183 : /* Whether we need to grow. We want to do this if the load factor is >= 0.75 */
184 3583038 : bool needsToGrow() const {
185 3583038 : uint32_t size = capacity();
186 3583038 : return entryCount + removedCount >= size - (size >> 2);
187 : }
188 :
189 : /*
190 : * Try to grow the table. On failure, reports out of memory on cx
191 : * and returns false. This will make any extant pointers into the
192 : * table invalid. Don't call this unless needsToGrow() is true.
193 : */
194 : bool grow(JSContext *cx);
195 :
196 : /*
197 : * NB: init and change are fallible but do not report OOM, so callers can
198 : * cope or ignore. They do however use JSRuntime's calloc_ method in order
199 : * to update the malloc counter on success.
200 : */
201 : bool init(JSRuntime *rt, js::Shape *lastProp);
202 : bool change(int log2Delta, JSContext *cx);
203 : js::Shape **search(jsid id, bool adding);
204 : };
205 :
206 : } /* namespace js */
207 :
208 : struct JSObject;
209 :
210 : namespace js {
211 :
212 : class PropertyTree;
213 :
214 : /*
215 : * Reuse the API-only JSPROP_INDEX attribute to mean shadowability.
216 : */
217 : #define JSPROP_SHADOWABLE JSPROP_INDEX
218 :
219 : /*
220 : * Shapes encode information about both a property lineage *and* a particular
221 : * property. This information is split across the Shape and the BaseShape
222 : * at shape->base(). Both Shape and BaseShape can be either owned or unowned
223 : * by, respectively, the Object or Shape referring to them.
224 : *
225 : * Owned Shapes are used in dictionary objects, and form a doubly linked list
226 : * whose entries are all owned by that dictionary. Unowned Shapes are all in
227 : * the property tree.
228 : *
229 : * Owned BaseShapes are used for shapes which have property tables, including
230 : * the last properties in all dictionaries. Unowned BaseShapes compactly store
231 : * information common to many shapes. In a given compartment there is a single
232 : * BaseShape for each combination of BaseShape information. This information
233 : * is cloned in owned BaseShapes so that information can be quickly looked up
234 : * for a given object or shape without regard to whether the base shape is
235 : * owned or not.
236 : *
237 : * All combinations of owned/unowned Shapes/BaseShapes are possible:
238 : *
239 : * Owned Shape, Owned BaseShape:
240 : *
241 : * Last property in a dictionary object. The BaseShape is transferred from
242 : * property to property as the object's last property changes.
243 : *
244 : * Owned Shape, Unowned BaseShape:
245 : *
246 : * Property in a dictionary object other than the last one.
247 : *
248 : * Unowned Shape, Owned BaseShape:
249 : *
250 : * Property in the property tree which has a property table.
251 : *
252 : * Unowned Shape, Unowned BaseShape:
253 : *
254 : * Property in the property tree which does not have a property table.
255 : *
256 : * BaseShapes additionally encode some information about the referring object
257 : * itself. This includes the object's class, parent and various flags that may
258 : * be set for the object. Except for the class, this information is mutable and
259 : * may change when the object has an established property lineage. On such
260 : * changes the entire property lineage is not updated, but rather only the
261 : * last property (and its base shape). This works because only the object's
262 : * last property is used to query information about the object. Care must be
263 : * taken to call JSObject::canRemoveLastProperty when unwinding an object to
264 : * an earlier property, however.
265 : */
266 :
267 : class UnownedBaseShape;
268 :
269 : class BaseShape : public js::gc::Cell
270 351675 : {
271 : public:
272 : friend struct Shape;
273 : friend struct StackBaseShape;
274 : friend struct StackShape;
275 :
276 : enum Flag {
277 : /* Owned by the referring shape. */
278 : OWNED_SHAPE = 0x1,
279 :
280 : /* getterObj/setterObj are active in unions below. */
281 : HAS_GETTER_OBJECT = 0x2,
282 : HAS_SETTER_OBJECT = 0x4,
283 :
284 : /*
285 : * Flags set which describe the referring object. Once set these cannot
286 : * be unset, and are transferred from shape to shape as the object's
287 : * last property changes.
288 : */
289 :
290 : EXTENSIBLE_PARENTS = 0x8,
291 : DELEGATE = 0x10,
292 : SYSTEM = 0x20,
293 : NOT_EXTENSIBLE = 0x40,
294 : INDEXED = 0x80,
295 : BOUND_FUNCTION = 0x100,
296 : VAROBJ = 0x200,
297 : WATCHED = 0x400,
298 : ITERATED_SINGLETON = 0x800,
299 : NEW_TYPE_UNKNOWN = 0x1000,
300 : UNCACHEABLE_PROTO = 0x2000,
301 :
302 : OBJECT_FLAG_MASK = 0x3ff8
303 : };
304 :
305 : private:
306 : Class *clasp; /* Class of referring object. */
307 : HeapPtrObject parent; /* Parent of referring object. */
308 : uint32_t flags; /* Vector of above flags. */
309 : uint32_t slotSpan_; /* Object slot span for BaseShapes at
310 : * dictionary last properties. */
311 :
312 : union {
313 : js::PropertyOp rawGetter; /* getter hook for shape */
314 : JSObject *getterObj; /* user-defined callable "get" object or
315 : null if shape->hasGetterValue() */
316 : };
317 :
318 : union {
319 : js::StrictPropertyOp rawSetter; /* setter hook for shape */
320 : JSObject *setterObj; /* user-defined callable "set" object or
321 : null if shape->hasSetterValue() */
322 : };
323 :
324 : /* For owned BaseShapes, the canonical unowned BaseShape. */
325 : HeapPtr<UnownedBaseShape> unowned_;
326 :
327 : /* For owned BaseShapes, the shape's property table. */
328 : PropertyTable *table_;
329 :
330 : public:
331 : void finalize(JSContext *cx, bool background);
332 :
333 : inline BaseShape(Class *clasp, JSObject *parent, uint32_t objectFlags);
334 : inline BaseShape(Class *clasp, JSObject *parent, uint32_t objectFlags,
335 : uint8_t attrs, PropertyOp rawGetter, StrictPropertyOp rawSetter);
336 : inline BaseShape(const StackBaseShape &base);
337 :
338 : /* Not defined: BaseShapes must not be stack allocated. */
339 : ~BaseShape();
340 :
341 : inline BaseShape &operator=(const BaseShape &other);
342 :
343 836075560 : bool isOwned() const { return !!(flags & OWNED_SHAPE); }
344 :
345 : inline bool matchesGetterSetter(PropertyOp rawGetter,
346 : StrictPropertyOp rawSetter) const;
347 :
348 : inline void adoptUnowned(UnownedBaseShape *other);
349 : inline void setOwned(UnownedBaseShape *unowned);
350 :
351 28754677 : JSObject *getObjectParent() const { return parent; }
352 61073657 : uint32_t getObjectFlags() const { return flags & OBJECT_FLAG_MASK; }
353 :
354 40190796 : bool hasGetterObject() const { return !!(flags & HAS_GETTER_OBJECT); }
355 4233536 : JSObject *getterObject() const { JS_ASSERT(hasGetterObject()); return getterObj; }
356 :
357 36545322 : bool hasSetterObject() const { return !!(flags & HAS_SETTER_OBJECT); }
358 588062 : JSObject *setterObject() const { JS_ASSERT(hasSetterObject()); return setterObj; }
359 :
360 402167399 : bool hasTable() const { JS_ASSERT_IF(table_, isOwned()); return table_ != NULL; }
361 151604563 : PropertyTable &table() const { JS_ASSERT(table_ && isOwned()); return *table_; }
362 5146686 : void setTable(PropertyTable *table) { JS_ASSERT(isOwned()); table_ = table; }
363 :
364 378971873 : uint32_t slotSpan() const { JS_ASSERT(isOwned()); return slotSpan_; }
365 8098212 : void setSlotSpan(uint32_t slotSpan) { JS_ASSERT(isOwned()); slotSpan_ = slotSpan; }
366 :
367 : /* Lookup base shapes from the compartment's baseShapes table. */
368 : static UnownedBaseShape *getUnowned(JSContext *cx, const StackBaseShape &base);
369 :
370 : /* Get the canonical base shape. */
371 : inline UnownedBaseShape *unowned();
372 :
373 : /* Get the canonical base shape for an owned one. */
374 : inline UnownedBaseShape *baseUnowned();
375 :
376 : /* Get the canonical base shape for an unowned one (i.e. identity). */
377 : inline UnownedBaseShape *toUnowned();
378 :
379 : /* Check that an owned base shape is consistent with its unowned base. */
380 : inline void assertConsistency();
381 :
382 : /* For JIT usage */
383 175022 : static inline size_t offsetOfClass() { return offsetof(BaseShape, clasp); }
384 7111 : static inline size_t offsetOfParent() { return offsetof(BaseShape, parent); }
385 2413 : static inline size_t offsetOfFlags() { return offsetof(BaseShape, flags); }
386 :
387 : static inline void writeBarrierPre(BaseShape *shape);
388 : static inline void writeBarrierPost(BaseShape *shape, void *addr);
389 : static inline void readBarrier(BaseShape *shape);
390 :
391 : static inline ThingRootKind rootKind() { return THING_ROOT_BASE_SHAPE; }
392 :
393 : inline void markChildren(JSTracer *trc);
394 :
395 : private:
396 : static void staticAsserts() {
397 : JS_STATIC_ASSERT(offsetof(BaseShape, clasp) == offsetof(js::shadow::BaseShape, clasp));
398 : }
399 : };
400 :
401 : class UnownedBaseShape : public BaseShape {};
402 :
403 : UnownedBaseShape *
404 96761074 : BaseShape::unowned()
405 : {
406 96761074 : return isOwned() ? baseUnowned() : toUnowned();
407 : }
408 :
409 : UnownedBaseShape *
410 96634819 : BaseShape::toUnowned()
411 : {
412 96634819 : JS_ASSERT(!isOwned() && !unowned_); return static_cast<UnownedBaseShape *>(this);
413 : }
414 :
415 : UnownedBaseShape *
416 17840419 : BaseShape::baseUnowned()
417 : {
418 17840419 : JS_ASSERT(isOwned() && unowned_); return unowned_;
419 : }
420 :
421 : /* Entries for the per-compartment baseShapes set of unowned base shapes. */
422 : struct StackBaseShape
423 : {
424 : typedef const StackBaseShape *Lookup;
425 :
426 : uint32_t flags;
427 : Class *clasp;
428 : JSObject *parent;
429 : PropertyOp rawGetter;
430 : StrictPropertyOp rawSetter;
431 :
432 21099317 : StackBaseShape(BaseShape *base)
433 : : flags(base->flags & BaseShape::OBJECT_FLAG_MASK),
434 : clasp(base->clasp),
435 : parent(base->parent),
436 : rawGetter(NULL),
437 21099317 : rawSetter(NULL)
438 21099317 : {}
439 :
440 6286238 : StackBaseShape(Class *clasp, JSObject *parent, uint32_t objectFlags)
441 : : flags(objectFlags),
442 : clasp(clasp),
443 : parent(parent),
444 : rawGetter(NULL),
445 6286238 : rawSetter(NULL)
446 6286238 : {}
447 :
448 : inline StackBaseShape(Shape *shape);
449 :
450 : inline void updateGetterSetter(uint8_t attrs,
451 : PropertyOp rawGetter,
452 : StrictPropertyOp rawSetter);
453 :
454 : static inline HashNumber hash(const StackBaseShape *lookup);
455 : static inline bool match(UnownedBaseShape *key, const StackBaseShape *lookup);
456 : };
457 :
458 : typedef HashSet<ReadBarriered<UnownedBaseShape>,
459 : StackBaseShape,
460 : SystemAllocPolicy> BaseShapeSet;
461 :
462 : struct Shape : public js::gc::Cell
463 0 : {
464 : friend struct ::JSObject;
465 : friend struct ::JSFunction;
466 : friend class js::Bindings;
467 : friend class js::ObjectImpl;
468 : friend class js::PropertyTree;
469 : friend class js::StaticBlockObject;
470 : friend struct js::StackShape;
471 : friend struct js::StackBaseShape;
472 :
473 : protected:
474 : HeapPtrBaseShape base_;
475 : HeapId propid_;
476 :
477 : JS_ENUM_HEADER(SlotInfo, uint32_t)
478 : {
479 : /* Number of fixed slots in objects with this shape. */
480 : FIXED_SLOTS_MAX = 0x1f,
481 : FIXED_SLOTS_SHIFT = 27,
482 : FIXED_SLOTS_MASK = uint32_t(FIXED_SLOTS_MAX << FIXED_SLOTS_SHIFT),
483 :
484 : /*
485 : * numLinearSearches starts at zero and is incremented initially on
486 : * search() calls. Once numLinearSearches reaches LINEAR_SEARCHES_MAX,
487 : * the table is created on the next search() call. The table can also
488 : * be created when hashifying for dictionary mode.
489 : */
490 : LINEAR_SEARCHES_MAX = 0x7,
491 : LINEAR_SEARCHES_SHIFT = 24,
492 : LINEAR_SEARCHES_MASK = LINEAR_SEARCHES_MAX << LINEAR_SEARCHES_SHIFT,
493 :
494 : /*
495 : * Mask to get the index in object slots for shapes which hasSlot().
496 : * For !hasSlot() shapes in the property tree with a parent, stores the
497 : * parent's slot index (which may be invalid), and invalid for all
498 : * other shapes.
499 : */
500 : SLOT_MASK = JS_BIT(24) - 1
501 : } JS_ENUM_FOOTER(SlotInfo);
502 :
503 : uint32_t slotInfo; /* mask of above info */
504 : uint8_t attrs; /* attributes, see jsapi.h JSPROP_* */
505 : uint8_t flags; /* flags, see below for defines */
506 : int16_t shortid_; /* tinyid, or local arg/var index */
507 :
508 : HeapPtrShape parent; /* parent node, reverse for..in order */
509 : /* kids is valid when !inDictionary(), listp is valid when inDictionary(). */
510 : union {
511 : KidsPointer kids; /* null, single child, or a tagged ptr
512 : to many-kids data structure */
513 : HeapPtrShape *listp; /* dictionary list starting at shape_
514 : has a double-indirect back pointer,
515 : either to the next shape's parent if not
516 : last, else to obj->shape_ */
517 : };
518 :
519 : static inline Shape *search(JSContext *cx, Shape *start, jsid id,
520 : Shape ***pspp, bool adding = false);
521 :
522 : inline void removeFromDictionary(JSObject *obj);
523 : inline void insertIntoDictionary(HeapPtrShape *dictp);
524 :
525 : inline void initDictionaryShape(const StackShape &child, uint32_t nfixed,
526 : HeapPtrShape *dictp);
527 :
528 : Shape *getChildBinding(JSContext *cx, const StackShape &child);
529 :
530 : /* Replace the base shape of the last shape in a non-dictionary lineage with base. */
531 : static Shape *replaceLastProperty(JSContext *cx, const StackBaseShape &base,
532 : JSObject *proto, Shape *shape);
533 :
534 : bool hashify(JSContext *cx);
535 : void handoffTableTo(Shape *newShape);
536 :
537 : inline void setParent(js::Shape *p);
538 :
539 351675 : bool ensureOwnBaseShape(JSContext *cx) {
540 351675 : if (base()->isOwned())
541 0 : return true;
542 351675 : return makeOwnBaseShape(cx);
543 : }
544 :
545 : bool makeOwnBaseShape(JSContext *cx);
546 :
547 : public:
548 402167399 : bool hasTable() const { return base()->hasTable(); }
549 146809552 : js::PropertyTable &table() const { return base()->table(); }
550 :
551 43133 : void sizeOfExcludingThis(JSMallocSizeOfFun mallocSizeOf,
552 : size_t *propTableSize, size_t *kidsSize) const {
553 43133 : *propTableSize = hasTable() ? table().sizeOfIncludingThis(mallocSizeOf) : 0;
554 72154 : *kidsSize = !inDictionary() && kids.isHash()
555 1206 : ? kids.toHash()->sizeOfIncludingThis(mallocSizeOf)
556 73360 : : 0;
557 43133 : }
558 :
559 745816410 : bool isNative() const {
560 745816410 : JS_ASSERT(!(flags & NON_NATIVE) == getObjectClass()->isNative());
561 745816410 : return !(flags & NON_NATIVE);
562 : }
563 :
564 105293640 : const HeapPtrShape &previous() const {
565 105293640 : return parent;
566 : }
567 :
568 : class Range {
569 : protected:
570 : friend struct Shape;
571 : const Shape *cursor;
572 :
573 : public:
574 143103880 : Range(const Shape *shape) : cursor(shape) { }
575 :
576 -1106831585 : bool empty() const {
577 -1106831585 : return cursor->isEmptyShape();
578 : }
579 :
580 64837223 : const Shape &front() const {
581 64837223 : JS_ASSERT(!empty());
582 64837223 : return *cursor;
583 : }
584 :
585 1490088092 : void popFront() {
586 1490088092 : JS_ASSERT(!empty());
587 1490088093 : cursor = cursor->parent;
588 1490088093 : }
589 :
590 2455835 : class Root {
591 : js::Root<const Shape*> cursorRoot;
592 : public:
593 2455835 : Root(JSContext *cx, Range *range)
594 2455835 : : cursorRoot(cx, &range->cursor)
595 2455835 : {}
596 : };
597 : };
598 :
599 141733962 : Range all() const {
600 141733962 : return Range(this);
601 : }
602 :
603 -1 : Class *getObjectClass() const { return base()->clasp; }
604 1128997338 : JSObject *getObjectParent() const { return base()->parent; }
605 :
606 : static Shape *setObjectParent(JSContext *cx, JSObject *obj, JSObject *proto, Shape *last);
607 : static Shape *setObjectFlag(JSContext *cx, BaseShape::Flag flag, JSObject *proto, Shape *last);
608 :
609 38740743 : uint32_t getObjectFlags() const { return base()->getObjectFlags(); }
610 169309713 : bool hasObjectFlag(BaseShape::Flag flag) const {
611 169309713 : JS_ASSERT(!(flag & ~BaseShape::OBJECT_FLAG_MASK));
612 169309713 : return !!(base()->flags & flag);
613 : }
614 :
615 : protected:
616 : /*
617 : * Implementation-private bits stored in shape->flags. See public: enum {}
618 : * flags further below, which were allocated FCFS over time, so interleave
619 : * with these bits.
620 : */
621 : enum {
622 : /* Property is placeholder for a non-native class. */
623 : NON_NATIVE = 0x01,
624 :
625 : /* Property stored in per-object dictionary, not shared property tree. */
626 : IN_DICTIONARY = 0x02,
627 :
628 : UNUSED_BITS = 0x3C
629 : };
630 :
631 : /* Get a shape identical to this one, without parent/kids information. */
632 : Shape(const StackShape &other, uint32_t nfixed);
633 :
634 : /* Used by EmptyShape (see jsscopeinlines.h). */
635 : Shape(UnownedBaseShape *base, uint32_t nfixed);
636 :
637 : /* Copy constructor disabled, to avoid misuse of the above form. */
638 : Shape(const Shape &other) MOZ_DELETE;
639 :
640 : /*
641 : * Whether this shape has a valid slot value. This may be true even if
642 : * !hasSlot() (see SlotInfo comment above), and may be false even if
643 : * hasSlot() if the shape is being constructed and has not had a slot
644 : * assigned yet. After construction, hasSlot() implies !hasMissingSlot().
645 : */
646 1212747330 : bool hasMissingSlot() const { return maybeSlot() == SHAPE_INVALID_SLOT; }
647 :
648 : public:
649 : /* Public bits stored in shape->flags. */
650 : enum {
651 : HAS_SHORTID = 0x40,
652 : METHOD = 0x80,
653 : PUBLIC_FLAGS = HAS_SHORTID | METHOD
654 : };
655 :
656 -1764798822 : bool inDictionary() const { return (flags & IN_DICTIONARY) != 0; }
657 0 : unsigned getFlags() const { return flags & PUBLIC_FLAGS; }
658 7048673 : bool hasShortID() const { return (flags & HAS_SHORTID) != 0; }
659 :
660 : /*
661 : * A shape has a method barrier when some compiler-created "null closure"
662 : * function objects (functions that do not use lexical bindings above their
663 : * scope, only free variable names) that have a correct JSSLOT_PARENT value
664 : * thanks to the COMPILE_N_GO optimization are stored in objects without
665 : * cloning.
666 : *
667 : * The de-facto standard JS language requires each evaluation of such a
668 : * closure to result in a unique (according to === and observable effects)
669 : * function object. When storing a function to a property, we use method
670 : * shapes to speculate that these effects will never be observed: the
671 : * property will only be used in calls, and f.callee will not be used
672 : * to get a handle on the object.
673 : *
674 : * If either a non-call use or callee access occurs, then the function is
675 : * cloned and the object is reshaped with a non-method property.
676 : *
677 : * Note that method shapes do not imply the object has a particular
678 : * uncloned function, just that the object has *some* uncloned function
679 : * in the shape's slot.
680 : */
681 194634335 : bool isMethod() const {
682 194634335 : JS_ASSERT_IF(flags & METHOD, !base()->rawGetter);
683 194634335 : return (flags & METHOD) != 0;
684 : }
685 :
686 7592848 : PropertyOp getter() const { return base()->rawGetter; }
687 39230058 : bool hasDefaultGetterOrIsMethod() const { return !base()->rawGetter; }
688 163269369 : bool hasDefaultGetter() const { return !base()->rawGetter && !isMethod(); }
689 2120723 : PropertyOp getterOp() const { JS_ASSERT(!hasGetterValue()); return base()->rawGetter; }
690 574 : JSObject *getterObject() const { JS_ASSERT(hasGetterValue()); return base()->getterObj; }
691 :
692 : // Per ES5, decode null getterObj as the undefined value, which encodes as null.
693 3226563 : Value getterValue() const {
694 3226563 : JS_ASSERT(hasGetterValue());
695 3226563 : return base()->getterObj ? js::ObjectValue(*base()->getterObj) : js::UndefinedValue();
696 : }
697 :
698 35 : Value getterOrUndefined() const {
699 69 : return (hasGetterValue() && base()->getterObj)
700 34 : ? ObjectValue(*base()->getterObj)
701 103 : : UndefinedValue();
702 : }
703 :
704 5673514 : StrictPropertyOp setter() const { return base()->rawSetter; }
705 33650663 : bool hasDefaultSetter() const { return !base()->rawSetter; }
706 206702 : StrictPropertyOp setterOp() const { JS_ASSERT(!hasSetterValue()); return base()->rawSetter; }
707 63 : JSObject *setterObject() const { JS_ASSERT(hasSetterValue()); return base()->setterObj; }
708 :
709 : // Per ES5, decode null setterObj as the undefined value, which encodes as null.
710 157126 : Value setterValue() const {
711 157126 : JS_ASSERT(hasSetterValue());
712 157126 : return base()->setterObj ? js::ObjectValue(*base()->setterObj) : js::UndefinedValue();
713 : }
714 :
715 16244 : Value setterOrUndefined() const {
716 16388 : return (hasSetterValue() && base()->setterObj)
717 144 : ? ObjectValue(*base()->setterObj)
718 16532 : : UndefinedValue();
719 : }
720 :
721 : void update(js::PropertyOp getter, js::StrictPropertyOp setter, uint8_t attrs);
722 :
723 : inline bool matches(const Shape *other) const;
724 : inline bool matches(const StackShape &other) const;
725 : inline bool matchesParamsAfterId(BaseShape *base,
726 : uint32_t aslot, unsigned aattrs, unsigned aflags,
727 : int ashortid) const;
728 :
729 : bool get(JSContext* cx, JSObject *receiver, JSObject *obj, JSObject *pobj, js::Value* vp) const;
730 : bool set(JSContext* cx, JSObject *obj, bool strict, js::Value* vp) const;
731 :
732 -1 : BaseShape *base() const { return base_; }
733 :
734 522236482 : bool hasSlot() const { return (attrs & JSPROP_SHARED) == 0; }
735 236155379 : uint32_t slot() const { JS_ASSERT(hasSlot() && !hasMissingSlot()); return maybeSlot(); }
736 2118125888 : uint32_t maybeSlot() const { return slotInfo & SLOT_MASK; }
737 :
738 -692996070 : bool isEmptyShape() const {
739 -692996070 : JS_ASSERT_IF(JSID_IS_EMPTY(propid_), hasMissingSlot());
740 -692996069 : return JSID_IS_EMPTY(propid_);
741 : }
742 :
743 805378681 : uint32_t slotSpan() const {
744 805378681 : JS_ASSERT(!inDictionary());
745 805378681 : uint32_t free = JSSLOT_FREE(getObjectClass());
746 805378679 : return hasMissingSlot() ? free : Max(free, maybeSlot() + 1);
747 : }
748 :
749 117918 : void setSlot(uint32_t slot) {
750 117918 : JS_ASSERT(slot <= SHAPE_INVALID_SLOT);
751 117918 : slotInfo = slotInfo & ~Shape::SLOT_MASK;
752 117918 : slotInfo = slotInfo | slot;
753 117918 : }
754 :
755 105738040 : uint32_t numFixedSlots() const {
756 105738040 : return (slotInfo >> FIXED_SLOTS_SHIFT);
757 : }
758 :
759 2573523 : void setNumFixedSlots(uint32_t nfixed) {
760 2573523 : JS_ASSERT(nfixed < FIXED_SLOTS_MAX);
761 2573523 : slotInfo = slotInfo & ~FIXED_SLOTS_MASK;
762 2573523 : slotInfo = slotInfo | (nfixed << FIXED_SLOTS_SHIFT);
763 2573523 : }
764 :
765 180547676 : uint32_t numLinearSearches() const {
766 180547676 : return (slotInfo & LINEAR_SEARCHES_MASK) >> LINEAR_SEARCHES_SHIFT;
767 : }
768 :
769 43067434 : void incrementNumLinearSearches() {
770 43067434 : uint32_t count = numLinearSearches();
771 43067434 : JS_ASSERT(count < LINEAR_SEARCHES_MAX);
772 43067434 : slotInfo = slotInfo & ~LINEAR_SEARCHES_MASK;
773 43067434 : slotInfo = slotInfo | ((count + 1) << LINEAR_SEARCHES_SHIFT);
774 43067434 : }
775 :
776 397628365 : const HeapId &propid() const {
777 397628365 : JS_ASSERT(!isEmptyShape());
778 397628365 : JS_ASSERT(!JSID_IS_VOID(propid_));
779 397628365 : return propid_;
780 : }
781 1431642688 : HeapId &propidRef() { JS_ASSERT(!JSID_IS_VOID(propid_)); return propid_; }
782 :
783 3768618 : int16_t shortid() const { JS_ASSERT(hasShortID()); return maybeShortid(); }
784 3838905 : int16_t maybeShortid() const { return shortid_; }
785 :
786 : /*
787 : * If SHORTID is set in shape->flags, we use shape->shortid rather
788 : * than id when calling shape's getter or setter.
789 : */
790 2355400 : jsid getUserId() const {
791 2355400 : return hasShortID() ? INT_TO_JSID(shortid()) : propid();
792 : }
793 :
794 14895455 : uint8_t attributes() const { return attrs; }
795 12083759 : bool configurable() const { return (attrs & JSPROP_PERMANENT) == 0; }
796 40617681 : bool enumerable() const { return (attrs & JSPROP_ENUMERATE) != 0; }
797 30937276 : bool writable() const {
798 : // JS_ASSERT(isDataDescriptor());
799 30937276 : return (attrs & JSPROP_READONLY) == 0;
800 : }
801 10860514 : bool hasGetterValue() const { return attrs & JSPROP_GETTER; }
802 446572 : bool hasSetterValue() const { return attrs & JSPROP_SETTER; }
803 :
804 138290827 : bool isDataDescriptor() const {
805 138290827 : return (attrs & (JSPROP_SETTER | JSPROP_GETTER)) == 0;
806 : }
807 14787299 : bool isAccessorDescriptor() const {
808 14787299 : return (attrs & (JSPROP_SETTER | JSPROP_GETTER)) != 0;
809 : }
810 :
811 : /*
812 : * For ES5 compatibility, we allow properties with PropertyOp-flavored
813 : * setters to be shadowed when set. The "own" property thereby created in
814 : * the directly referenced object will have the same getter and setter as
815 : * the prototype property. See bug 552432.
816 : */
817 692530 : bool shadowable() const {
818 692530 : JS_ASSERT_IF(isDataDescriptor(), writable());
819 692530 : return hasSlot() || (attrs & JSPROP_SHADOWABLE);
820 : }
821 :
822 : /*
823 : * Sometimes call objects and run-time block objects need unique shapes, but
824 : * sometimes they don't.
825 : *
826 : * Property cache entries only record the shapes of the first and last
827 : * objects along the search path, so if the search traverses more than those
828 : * two objects, then those first and last shapes must determine the shapes
829 : * of everything else along the path. The js_PurgeScopeChain stuff takes
830 : * care of making this work, but that suffices only because we require that
831 : * start points with the same shape have the same successor object in the
832 : * search path --- a cache hit means the starting shapes were equal, which
833 : * means the seach path tail (everything but the first object in the path)
834 : * was shared, which in turn means the effects of a purge will be seen by
835 : * all affected starting search points.
836 : *
837 : * For call and run-time block objects, the "successor object" is the scope
838 : * chain parent. Unlike prototype objects (of which there are usually few),
839 : * scope chain parents are created frequently (possibly on every call), so
840 : * following the shape-implies-parent rule blindly would lead one to give
841 : * every call and block its own shape.
842 : *
843 : * In many cases, however, it's not actually necessary to give call and
844 : * block objects their own shapes, and we can do better. If the code will
845 : * always be used with the same global object, and none of the enclosing
846 : * call objects could have bindings added to them at runtime (by direct eval
847 : * calls or function statements), then we can use a fixed set of shapes for
848 : * those objects. You could think of the shapes in the functions' bindings
849 : * and compile-time blocks as uniquely identifying the global object(s) at
850 : * the end of the scope chain.
851 : *
852 : * (In fact, some JSScripts we do use against multiple global objects (see
853 : * bug 618497), and using the fixed shapes isn't sound there.)
854 : *
855 : * In deciding whether a call or block has any extensible parents, we
856 : * actually only need to consider enclosing calls; blocks are never
857 : * extensible, and the other sorts of objects that appear in the scope
858 : * chains ('with' blocks, say) are not CacheableNonGlobalScopes.
859 : *
860 : * If the hasExtensibleParents flag is set for the last property in a
861 : * script's bindings or a compiler-generated Block object, then created
862 : * Call or Block objects need unique shapes. If the flag is clear, then we
863 : * can use lastBinding's shape.
864 : */
865 : static Shape *setExtensibleParents(JSContext *cx, Shape *shape);
866 1771664 : bool extensibleParents() const { return !!(base()->flags & BaseShape::EXTENSIBLE_PARENTS); }
867 :
868 43256223 : uint32_t entryCount() const {
869 43256223 : if (hasTable())
870 1348416 : return table().entryCount;
871 :
872 41907807 : const js::Shape *shape = this;
873 41907807 : uint32_t count = 0;
874 1316236733 : for (js::Shape::Range r = shape->all(); !r.empty(); r.popFront())
875 1274328926 : ++count;
876 41907807 : return count;
877 : }
878 :
879 94412808 : bool isBigEnoughForAPropertyTable() const {
880 94412808 : JS_ASSERT(!hasTable());
881 94412808 : const js::Shape *shape = this;
882 94412808 : uint32_t count = 0;
883 246233628 : for (js::Shape::Range r = shape->all(); !r.empty(); r.popFront()) {
884 152005209 : ++count;
885 152005209 : if (count >= PropertyTable::MIN_ENTRIES)
886 184389 : return true;
887 : }
888 94228419 : return false;
889 : }
890 :
891 : #ifdef DEBUG
892 : void dump(JSContext *cx, FILE *fp) const;
893 : void dumpSubtree(JSContext *cx, int level, FILE *fp) const;
894 : #endif
895 :
896 : void finalize(JSContext *cx, bool background);
897 : void removeChild(js::Shape *child);
898 :
899 : static inline void writeBarrierPre(const Shape *shape);
900 : static inline void writeBarrierPost(const Shape *shape, void *addr);
901 :
902 : /*
903 : * All weak references need a read barrier for incremental GC. This getter
904 : * method implements the read barrier. It's used to obtain initial shapes
905 : * from the compartment.
906 : */
907 : static inline void readBarrier(const Shape *shape);
908 :
909 : static inline ThingRootKind rootKind() { return THING_ROOT_SHAPE; }
910 :
911 : inline void markChildren(JSTracer *trc);
912 :
913 : /* For JIT usage */
914 182133 : static inline size_t offsetOfBase() { return offsetof(Shape, base_); }
915 :
916 : private:
917 : static void staticAsserts() {
918 : JS_STATIC_ASSERT(offsetof(Shape, base_) == offsetof(js::shadow::Shape, base));
919 : JS_STATIC_ASSERT(offsetof(Shape, slotInfo) == offsetof(js::shadow::Shape, slotInfo));
920 : JS_STATIC_ASSERT(FIXED_SLOTS_SHIFT == js::shadow::Shape::FIXED_SLOTS_SHIFT);
921 : }
922 : };
923 :
924 : struct EmptyShape : public js::Shape
925 : {
926 : EmptyShape(UnownedBaseShape *base, uint32_t nfixed);
927 :
928 : /*
929 : * Lookup an initial shape matching the given parameters, creating an empty
930 : * shape if none was found.
931 : */
932 : static Shape *getInitialShape(JSContext *cx, Class *clasp, JSObject *proto,
933 : JSObject *parent, gc::AllocKind kind, uint32_t objectFlags = 0);
934 :
935 : /*
936 : * Reinsert an alternate initial shape, to be returned by future
937 : * getInitialShape calls, until the new shape becomes unreachable in a GC
938 : * and the table entry is purged.
939 : */
940 : static void insertInitialShape(JSContext *cx, Shape *shape, JSObject *proto);
941 : };
942 :
943 : /*
944 : * Entries for the per-compartment initialShapes set indexing initial shapes
945 : * for objects in the compartment and the associated types.
946 : */
947 : struct InitialShapeEntry
948 22516807 : {
949 : /*
950 : * Initial shape to give to the object. This is an empty shape, except for
951 : * certain classes (e.g. String, RegExp) which may add certain baked-in
952 : * properties.
953 : */
954 : ReadBarriered<Shape> shape;
955 :
956 : /*
957 : * Matching prototype for the entry. The shape of an object determines its
958 : * prototype, but the prototype cannot be determined from the shape itself.
959 : */
960 : JSObject *proto;
961 :
962 : /* State used to determine a match on an initial shape. */
963 : struct Lookup {
964 : Class *clasp;
965 : JSObject *proto;
966 : JSObject *parent;
967 : uint32_t nfixed;
968 : uint32_t baseFlags;
969 17387944 : Lookup(Class *clasp, JSObject *proto, JSObject *parent, uint32_t nfixed,
970 : uint32_t baseFlags)
971 : : clasp(clasp), proto(proto), parent(parent),
972 17387944 : nfixed(nfixed), baseFlags(baseFlags)
973 17387944 : {}
974 : };
975 :
976 : static inline HashNumber hash(const Lookup &lookup);
977 : static inline bool match(const InitialShapeEntry &key, const Lookup &lookup);
978 : };
979 :
980 : typedef HashSet<InitialShapeEntry, InitialShapeEntry, SystemAllocPolicy> InitialShapeSet;
981 :
982 : struct StackShape
983 : {
984 : UnownedBaseShape *base;
985 : jsid propid;
986 : uint32_t slot_;
987 : uint8_t attrs;
988 : uint8_t flags;
989 : int16_t shortid;
990 :
991 43656177 : StackShape(UnownedBaseShape *base, jsid propid, uint32_t slot,
992 : uint32_t nfixed, unsigned attrs, unsigned flags, int shortid)
993 : : base(base),
994 : propid(propid),
995 : slot_(slot),
996 : attrs(uint8_t(attrs)),
997 : flags(uint8_t(flags)),
998 43656177 : shortid(int16_t(shortid))
999 : {
1000 43656177 : JS_ASSERT(base);
1001 43656177 : JS_ASSERT(!JSID_IS_VOID(propid));
1002 43656177 : JS_ASSERT(slot <= SHAPE_INVALID_SLOT);
1003 43656177 : }
1004 :
1005 14323800 : StackShape(const Shape *shape)
1006 14323800 : : base(shape->base()->unowned()),
1007 14323800 : propid(const_cast<Shape *>(shape)->propidRef()),
1008 : slot_(shape->slotInfo & Shape::SLOT_MASK),
1009 : attrs(shape->attrs),
1010 : flags(shape->flags),
1011 28647600 : shortid(shape->shortid_)
1012 14323800 : {}
1013 :
1014 49884113 : bool hasSlot() const { return (attrs & JSPROP_SHARED) == 0; }
1015 35789180 : bool hasMissingSlot() const { return maybeSlot() == SHAPE_INVALID_SLOT; }
1016 :
1017 5204090 : uint32_t slot() const { JS_ASSERT(hasSlot() && !hasMissingSlot()); return slot_; }
1018 67327157 : uint32_t maybeSlot() const { return slot_; }
1019 :
1020 2573523 : uint32_t slotSpan() const {
1021 2573523 : uint32_t free = JSSLOT_FREE(base->clasp);
1022 2573523 : return hasMissingSlot() ? free : (maybeSlot() + 1);
1023 : }
1024 :
1025 38377828 : void setSlot(uint32_t slot) {
1026 38377828 : JS_ASSERT(slot <= SHAPE_INVALID_SLOT);
1027 38377828 : slot_ = slot;
1028 38377828 : }
1029 :
1030 : inline JSDHashNumber hash() const;
1031 : };
1032 :
1033 : /* Rooter for stack allocated shapes. */
1034 : class RootStackShape
1035 23896995 : {
1036 : Root<const UnownedBaseShape*> baseShapeRoot;
1037 : Root<const jsid> propidRoot;
1038 :
1039 : public:
1040 23896995 : RootStackShape(JSContext *cx, const StackShape *shape)
1041 : : baseShapeRoot(cx, &shape->base),
1042 23896995 : propidRoot(cx, &shape->propid)
1043 23896995 : {}
1044 : };
1045 :
1046 : } /* namespace js */
1047 :
1048 : /* js::Shape pointer tag bit indicating a collision. */
1049 : #define SHAPE_COLLISION (uintptr_t(1))
1050 : #define SHAPE_REMOVED ((js::Shape *) SHAPE_COLLISION)
1051 :
1052 : /* Macros to get and set shape pointer values and collision flags. */
1053 : #define SHAPE_IS_FREE(shape) ((shape) == NULL)
1054 : #define SHAPE_IS_REMOVED(shape) ((shape) == SHAPE_REMOVED)
1055 : #define SHAPE_IS_LIVE(shape) ((shape) > SHAPE_REMOVED)
1056 : #define SHAPE_FLAG_COLLISION(spp,shape) (*(spp) = (js::Shape *) \
1057 : (uintptr_t(shape) | SHAPE_COLLISION))
1058 : #define SHAPE_HAD_COLLISION(shape) (uintptr_t(shape) & SHAPE_COLLISION)
1059 : #define SHAPE_FETCH(spp) SHAPE_CLEAR_COLLISION(*(spp))
1060 :
1061 : #define SHAPE_CLEAR_COLLISION(shape) \
1062 : ((js::Shape *) (uintptr_t(shape) & ~SHAPE_COLLISION))
1063 :
1064 : #define SHAPE_STORE_PRESERVING_COLLISION(spp, shape) \
1065 : (*(spp) = (js::Shape *) (uintptr_t(shape) | SHAPE_HAD_COLLISION(*(spp))))
1066 :
1067 : namespace js {
1068 :
1069 : inline Shape *
1070 270325701 : Shape::search(JSContext *cx, Shape *start, jsid id, Shape ***pspp, bool adding)
1071 : {
1072 270325701 : if (start->inDictionary()) {
1073 104526957 : *pspp = start->table().search(id, adding);
1074 104526957 : return SHAPE_FETCH(*pspp);
1075 : }
1076 :
1077 165798744 : *pspp = NULL;
1078 :
1079 165798744 : if (start->hasTable()) {
1080 28318502 : Shape **spp = start->table().search(id, adding);
1081 28318502 : return SHAPE_FETCH(spp);
1082 : }
1083 :
1084 137480242 : if (start->numLinearSearches() == LINEAR_SEARCHES_MAX) {
1085 94412808 : if (start->isBigEnoughForAPropertyTable()) {
1086 368778 : RootShape startRoot(cx, &start);
1087 368778 : RootId idRoot(cx, &id);
1088 184389 : if (start->hashify(cx)) {
1089 184389 : Shape **spp = start->table().search(id, adding);
1090 184389 : return SHAPE_FETCH(spp);
1091 : }
1092 : }
1093 : /*
1094 : * No table built -- there weren't enough entries, or OOM occurred.
1095 : * Don't increment numLinearSearches, to keep hasTable() false.
1096 : */
1097 94228419 : JS_ASSERT(!start->hasTable());
1098 : } else {
1099 43067434 : start->incrementNumLinearSearches();
1100 : }
1101 :
1102 1419105538 : for (Shape *shape = start; shape; shape = shape->parent) {
1103 1320065424 : if (shape->propidRef() == id)
1104 38255738 : return shape;
1105 : }
1106 :
1107 99040115 : return NULL;
1108 : }
1109 :
1110 : } // namespace js
1111 :
1112 : #ifdef _MSC_VER
1113 : #pragma warning(pop)
1114 : #pragma warning(pop)
1115 : #endif
1116 :
1117 : namespace JS {
1118 : template<> class AnchorPermitted<js::Shape *> { };
1119 : template<> class AnchorPermitted<const js::Shape *> { };
1120 : }
1121 :
1122 : #endif /* jsscope_h___ */
|