LCOV - app.info - js/src/jsscope.h

LCOV - code coverage report
| Current view: | directory - js/src - jsscope.h (source / functions) |  | Found | Hit | Coverage |
| Test: | app.info | Lines: | 223 | 220 | 98.7 %
| Date: | 2012-04-07 | Functions: | 101 | 99 | 98.0 %

           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 "jsobj.h"
          52                 : #include "jspropertytree.h"
          53                 : #include "jstypes.h"
          54                 :
          55                 : #include "js/HashTable.h"
          56                 : #include "gc/Root.h"
          57                 : #include "mozilla/Attributes.h"
          58                 :
          59                 : #ifdef _MSC_VER
          60                 : #pragma warning(push)
          61                 : #pragma warning(disable:4800)
          62                 : #pragma warning(push)
          63                 : #pragma warning(disable:4100) /* Silence unreferenced formal parameter warnings */
          64                 : #endif
          65                 :
          66                 : /*
          67                 :  * In isolation, a Shape represents a property that exists in one or more
          68                 :  * objects; it has an id, flags, etc. (But it doesn't represent the property's
          69                 :  * value.)  However, Shapes are always stored in linked linear sequence of
          70                 :  * Shapes, called "shape lineages". Each shape lineage represents the layout of
          71                 :  * an entire object.
          72                 :  *
          73                 :  * Every JSObject has a pointer, |shape_|, accessible via lastProperty(), to
          74                 :  * the last Shape in a shape lineage, which identifies the property most
          75                 :  * recently added to the object.  This pointer permits fast object layout
          76                 :  * tests. The shape lineage order also dictates the enumeration order for the
          77                 :  * object; ECMA requires no particular order but this implementation has
          78                 :  * promised and delivered property definition order.
          79                 :  *
          80                 :  * Shape lineages occur in two kinds of data structure.
          81                 :  *
          82                 :  * 1. N-ary property trees. Each path from a non-root node to the root node in
          83                 :  *    a property tree is a shape lineage. Property trees permit full (or
          84                 :  *    partial) sharing of Shapes between objects that have fully (or partly)
          85                 :  *    identical layouts. The root is an EmptyShape whose identity is determined
          86                 :  *    by the object's class, compartment and prototype. These Shapes are shared
          87                 :  *    and immutable.
          88                 :  *
          89                 :  * 2. Dictionary mode lists. Shapes in such lists are said to be "in
          90                 :  *    dictionary mode", as are objects that point to such Shapes. These Shapes
          91                 :  *    are unshared, private to a single object, and immutable except for their
          92                 :  *    links in the dictionary list.
          93                 :  *
          94                 :  * All shape lineages are bi-directionally linked, via the |parent| and
          95                 :  * |kids|/|listp| members.
          96                 :  *
          97                 :  * Shape lineages start out life in the property tree. They can be converted
          98                 :  * (by copying) to dictionary mode lists in the following circumstances.
          99                 :  *
         100                 :  * 1. The shape lineage's size reaches MAX_HEIGHT. This reasonable limit avoids
         101                 :  *    potential worst cases involving shape lineage mutations.
         102                 :  *
         103                 :  * 2. A property represented by a non-last Shape in a shape lineage is removed
         104                 :  *    from an object. (In the last Shape case, obj->shape_ can be easily
         105                 :  *    adjusted to point to obj->shape_->parent.)  We originally tried lazy
         106                 :  *    forking of the property tree, but this blows up for delete/add
         107                 :  *    repetitions.
         108                 :  *
         109                 :  * 3. A property represented by a non-last Shape in a shape lineage has its
         110                 :  *    attributes modified.
         111                 :  *
         112                 :  * To find the Shape for a particular property of an object initially requires
         113                 :  * a linear search. But if the number of searches starting at any particular
         114                 :  * Shape in the property tree exceeds MAX_LINEAR_SEARCHES and the Shape's
         115                 :  * lineage has (excluding the EmptyShape) at least MIN_ENTRIES, we create an
         116                 :  * auxiliary hash table -- the PropertyTable -- that allows faster lookup.
         117                 :  * Furthermore, a PropertyTable is always created for dictionary mode lists,
         118                 :  * and it is attached to the last Shape in the lineage. Property tables for
         119                 :  * property tree Shapes never change, but property tables for dictionary mode
         120                 :  * Shapes can grow and shrink.
         121                 :  *
         122                 :  * There used to be a long, math-heavy comment here explaining why property
         123                 :  * trees are more space-efficient than alternatives.  This was removed in bug
         124                 :  * 631138; see that bug for the full details.
         125                 :  *
         126                 :  * Because many Shapes have similar data, there is actually a secondary type
         127                 :  * called a BaseShape that holds some of a Shape's data.  Many shapes can share
         128                 :  * a single BaseShape.
         129                 :  */
         130                 :
         131                 : namespace js {
         132                 :
         133                 : /* Limit on the number of slotful properties in an object. */
         134                 : static const uint32_t SHAPE_INVALID_SLOT = JS_BIT(24) - 1;
         135                 : static const uint32_t SHAPE_MAXIMUM_SLOT = JS_BIT(24) - 2;
         136                 :
         137                 : /*
         138                 :  * Shapes use multiplicative hashing, but specialized to
         139                 :  * minimize footprint.
         140                 :  */
         141                 : struct PropertyTable {
         142                 :     static const uint32_t HASH_BITS     = tl::BitSize<HashNumber>::result;
         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          127390 :     PropertyTable(uint32_t nentries)
         157                 :       : hashShift(HASH_BITS - MIN_SIZE_LOG2),
         158                 :         entryCount(nentries),
         159                 :         removedCount(0),
         160          127390 :         freelist(SHAPE_INVALID_SLOT)
         161                 :     {
         162                 :         /* NB: entries is set by init, which must be called. */
         163          127390 :     }
         164                 :
         165          127390 :     ~PropertyTable() {
         166          127390 :         js::UnwantedForeground::free_(entries);
         167          127390 :     }
         168                 :
         169                 :     /* By definition, hashShift = HASH_BITS - log2(capacity). */
         170         1654145 :     uint32_t capacity() const { return JS_BIT(HASH_BITS - hashShift); }
         171                 :
         172                 :     /* Computes the size of the entries array for a given capacity. */
         173          132187 :     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                 :     size_t sizeOfIncludingThis(JSMallocSizeOfFun mallocSizeOf) const {
         180                 :         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         1646936 :     bool needsToGrow() const {
         185         1646936 :         uint32_t size = capacity();
         186         1646936 :         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          127390 : {
         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(FreeOp *fop);
         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       470833332 :     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        10812663 :     JSObject *getObjectParent() const { return parent; }
         352        27372082 :     uint32_t getObjectFlags() const { return flags & OBJECT_FLAG_MASK; }
         353                 :
         354        16717511 :     bool hasGetterObject() const { return !!(flags & HAS_GETTER_OBJECT); }
         355         2385992 :     JSObject *getterObject() const { JS_ASSERT(hasGetterObject()); return getterObj; }
         356                 :
         357        14639127 :     bool hasSetterObject() const { return !!(flags & HAS_SETTER_OBJECT); }
         358          307608 :     JSObject *setterObject() const { JS_ASSERT(hasSetterObject()); return setterObj; }
         359                 :
         360       158781828 :     bool hasTable() const { JS_ASSERT_IF(table_, isOwned()); return table_ != NULL; }
         361        57771371 :     PropertyTable &table() const { JS_ASSERT(table_ && isOwned()); return *table_; }
         362         2143271 :     void setTable(PropertyTable *table) { JS_ASSERT(isOwned()); table_ = table; }
         363                 :
         364       224789549 :     uint32_t slotSpan() const { JS_ASSERT(isOwned()); return slotSpan_; }
         365         3431432 :     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          113046 :     static inline size_t offsetOfClass() { return offsetof(BaseShape, clasp); }
         384            3075 :     static inline size_t offsetOfParent() { return offsetof(BaseShape, parent); }
         385            1615 :     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        72237867 : BaseShape::unowned()
         405                 : {
         406        72237867 :     return isOwned() ? baseUnowned() : toUnowned();
         407                 : }
         408                 :
         409                 : UnownedBaseShape *
         410        71823533 : BaseShape::toUnowned()
         411                 : {
         412        71823533 :     JS_ASSERT(!isOwned() && !unowned_); return static_cast<UnownedBaseShape *>(this);
         413                 : }
         414                 :
         415                 : UnownedBaseShape *
         416         7237667 : BaseShape::baseUnowned()
         417                 : {
         418         7237667 :     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        15910736 :     StackBaseShape(BaseShape *base)
         433                 :       : flags(base->flags & BaseShape::OBJECT_FLAG_MASK),
         434                 :         clasp(base->clasp),
         435                 :         parent(base->parent),
         436                 :         rawGetter(NULL),
         437        15910736 :         rawSetter(NULL)
         438        15910736 :     {}
         439                 :
         440         2215383 :     StackBaseShape(Class *clasp, JSObject *parent, uint32_t objectFlags)
         441                 :       : flags(objectFlags),
         442                 :         clasp(clasp),
         443                 :         parent(parent),
         444                 :         rawGetter(NULL),
         445         2215383 :         rawSetter(NULL)
         446         2215383 :     {}
         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          127390 :     bool ensureOwnBaseShape(JSContext *cx) {
         540          127390 :         if (base()->isOwned())
         541               0 :             return true;
         542          127390 :         return makeOwnBaseShape(cx);
         543                 :     }
         544                 :
         545                 :     bool makeOwnBaseShape(JSContext *cx);
         546                 :
         547                 :   public:
         548       158781828 :     bool hasTable() const { return base()->hasTable(); }
         549        55755490 :     js::PropertyTable &table() const { return base()->table(); }
         550                 :
         551                 :     void sizeOfExcludingThis(JSMallocSizeOfFun mallocSizeOf,
         552                 :                              size_t *propTableSize, size_t *kidsSize) const {
         553                 :         *propTableSize = hasTable() ? table().sizeOfIncludingThis(mallocSizeOf) : 0;
         554                 :         *kidsSize = !inDictionary() && kids.isHash()
         555                 :                   ? kids.toHash()->sizeOfIncludingThis(mallocSizeOf)
         556                 :                   : 0;
         557                 :     }
         558                 :
         559       312729946 :     bool isNative() const {
         560       312729946 :         JS_ASSERT(!(flags & NON_NATIVE) == getObjectClass()->isNative());
         561       312729946 :         return !(flags & NON_NATIVE);
         562                 :     }
         563                 :
         564        26270450 :     const HeapPtrShape &previous() const {
         565        26270450 :         return parent;
         566                 :     }
         567                 :
         568                 :     class Range {
         569                 :       protected:
         570                 :         friend struct Shape;
         571                 :         const Shape *cursor;
         572                 :
         573                 :       public:
         574        67587088 :         Range(const Shape *shape) : cursor(shape) { }
         575                 :
         576     -1618075960 :         bool empty() const {
         577     -1618075960 :             return cursor->isEmptyShape();
         578                 :         }
         579                 :
         580        41981912 :         const Shape &front() const {
         581        41981912 :             JS_ASSERT(!empty());
         582        41981912 :             return *cursor;
         583                 :         }
         584                 :
         585      1283651952 :         void popFront() {
         586      1283651952 :             JS_ASSERT(!empty());
         587      1283651952 :             cursor = cursor->parent;
         588      1283651952 :         }
         589                 :
         590         2069854 :         class Root {
         591                 :             js::Root<const Shape*> cursorRoot;
         592                 :           public:
         593         2069854 :             Root(JSContext *cx, Range *range)
         594         2069854 :               : cursorRoot(cx, &range->cursor)
         595         2069854 :             {}
         596                 :         };
         597                 :     };
         598                 :
         599        66839310 :     Range all() const {
         600        66839310 :         return Range(this);
         601                 :     }
         602                 :
         603     -1698948099 :     Class *getObjectClass() const { return base()->clasp; }
         604      1054888195 :     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        18555462 :     uint32_t getObjectFlags() const { return base()->getObjectFlags(); }
         610        79120927 :     bool hasObjectFlag(BaseShape::Flag flag) const {
         611        79120927 :         JS_ASSERT(!(flag & ~BaseShape::OBJECT_FLAG_MASK));
         612        79120927 :         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       785484062 :     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                 :         PUBLIC_FLAGS    = HAS_SHORTID
         653                 :     };
         654                 :
         655      1607752915 :     bool inDictionary() const   { return (flags & IN_DICTIONARY) != 0; }
         656               0 :     unsigned getFlags() const  { return flags & PUBLIC_FLAGS; }
         657         1881089 :     bool hasShortID() const { return (flags & HAS_SHORTID) != 0; }
         658                 :
         659         1979030 :     PropertyOp getter() const { return base()->rawGetter; }
         660       111199759 :     bool hasDefaultGetter() const  { return !base()->rawGetter; }
         661          850304 :     PropertyOp getterOp() const { JS_ASSERT(!hasGetterValue()); return base()->rawGetter; }
         662             234 :     JSObject *getterObject() const { JS_ASSERT(hasGetterValue()); return base()->getterObj; }
         663                 :
         664                 :     // Per ES5, decode null getterObj as the undefined value, which encodes as null.
         665          336897 :     Value getterValue() const {
         666          336897 :         JS_ASSERT(hasGetterValue());
         667          336897 :         return base()->getterObj ? js::ObjectValue(*base()->getterObj) : js::UndefinedValue();
         668                 :     }
         669                 :
         670               9 :     Value getterOrUndefined() const {
         671              18 :         return (hasGetterValue() && base()->getterObj)
         672               9 :                ? ObjectValue(*base()->getterObj)
         673              27 :                : UndefinedValue();
         674                 :     }
         675                 :
         676         1915226 :     StrictPropertyOp setter() const { return base()->rawSetter; }
         677        17416613 :     bool hasDefaultSetter() const  { return !base()->rawSetter; }
         678           24591 :     StrictPropertyOp setterOp() const { JS_ASSERT(!hasSetterValue()); return base()->rawSetter; }
         679              63 :     JSObject *setterObject() const { JS_ASSERT(hasSetterValue()); return base()->setterObj; }
         680                 :
         681                 :     // Per ES5, decode null setterObj as the undefined value, which encodes as null.
         682            9469 :     Value setterValue() const {
         683            9469 :         JS_ASSERT(hasSetterValue());
         684            9469 :         return base()->setterObj ? js::ObjectValue(*base()->setterObj) : js::UndefinedValue();
         685                 :     }
         686                 :
         687             153 :     Value setterOrUndefined() const {
         688             297 :         return (hasSetterValue() && base()->setterObj)
         689             144 :                ? ObjectValue(*base()->setterObj)
         690             441 :                : UndefinedValue();
         691                 :     }
         692                 :
         693                 :     void update(js::PropertyOp getter, js::StrictPropertyOp setter, uint8_t attrs);
         694                 :
         695                 :     inline bool matches(const Shape *other) const;
         696                 :     inline bool matches(const StackShape &other) const;
         697                 :     inline bool matchesParamsAfterId(BaseShape *base,
         698                 :                                      uint32_t aslot, unsigned aattrs, unsigned aflags,
         699                 :                                      int ashortid) const;
         700                 :
         701                 :     bool get(JSContext* cx, JSObject *receiver, JSObject *obj, JSObject *pobj, js::Value* vp) const;
         702                 :     bool set(JSContext* cx, JSObject *obj, bool strict, js::Value* vp) const;
         703                 :
         704              -1 :     BaseShape *base() const { return base_; }
         705                 :
         706       334287180 :     bool hasSlot() const { return (attrs & JSPROP_SHARED) == 0; }
         707       146260846 :     uint32_t slot() const { JS_ASSERT(hasSlot() && !hasMissingSlot()); return maybeSlot(); }
         708      1376441725 :     uint32_t maybeSlot() const { return slotInfo & SLOT_MASK; }
         709                 :
         710     -1431668387 :     bool isEmptyShape() const {
         711     -1431668387 :         JS_ASSERT_IF(JSID_IS_EMPTY(propid_), hasMissingSlot());
         712     -1431668387 :         return JSID_IS_EMPTY(propid_);
         713                 :     }
         714                 :
         715       555732078 :     uint32_t slotSpan() const {
         716       555732078 :         JS_ASSERT(!inDictionary());
         717       555732078 :         uint32_t free = JSSLOT_FREE(getObjectClass());
         718       555732078 :         return hasMissingSlot() ? free : Max(free, maybeSlot() + 1);
         719                 :     }
         720                 :
         721           78790 :     void setSlot(uint32_t slot) {
         722           78790 :         JS_ASSERT(slot <= SHAPE_INVALID_SLOT);
         723           78790 :         slotInfo = slotInfo & ~Shape::SLOT_MASK;
         724           78790 :         slotInfo = slotInfo | slot;
         725           78790 :     }
         726                 :
         727        65728214 :     uint32_t numFixedSlots() const {
         728        65728214 :         return (slotInfo >> FIXED_SLOTS_SHIFT);
         729                 :     }
         730                 :
         731          355342 :     void setNumFixedSlots(uint32_t nfixed) {
         732          355342 :         JS_ASSERT(nfixed < FIXED_SLOTS_MAX);
         733          355342 :         slotInfo = slotInfo & ~FIXED_SLOTS_MASK;
         734          355342 :         slotInfo = slotInfo | (nfixed << FIXED_SLOTS_SHIFT);
         735          355342 :     }
         736                 :
         737        62610341 :     uint32_t numLinearSearches() const {
         738        62610341 :         return (slotInfo & LINEAR_SEARCHES_MASK) >> LINEAR_SEARCHES_SHIFT;
         739                 :     }
         740                 :
         741        14201164 :     void incrementNumLinearSearches() {
         742        14201164 :         uint32_t count = numLinearSearches();
         743        14201164 :         JS_ASSERT(count < LINEAR_SEARCHES_MAX);
         744        14201164 :         slotInfo = slotInfo & ~LINEAR_SEARCHES_MASK;
         745        14201164 :         slotInfo = slotInfo | ((count + 1) << LINEAR_SEARCHES_SHIFT);
         746        14201164 :     }
         747                 :
         748       182917276 :     const HeapId &propid() const {
         749       182917276 :         JS_ASSERT(!isEmptyShape());
         750       182917276 :         JS_ASSERT(!JSID_IS_VOID(propid_));
         751       182917276 :         return propid_;
         752                 :     }
         753       901648177 :     HeapId &propidRef() { JS_ASSERT(!JSID_IS_VOID(propid_)); return propid_; }
         754                 :
         755          969161 :     int16_t shortid() const { JS_ASSERT(hasShortID()); return maybeShortid(); }
         756         1001283 :     int16_t maybeShortid() const { return shortid_; }
         757                 :
         758                 :     /*
         759                 :      * If SHORTID is set in shape->flags, we use shape->shortid rather
         760                 :      * than id when calling shape's getter or setter.
         761                 :      */
         762          861692 :     jsid getUserId() const {
         763          861692 :         return hasShortID() ? INT_TO_JSID(shortid()) : propid();
         764                 :     }
         765                 :
         766          862795 :     uint8_t attributes() const { return attrs; }
         767         2246098 :     bool configurable() const { return (attrs & JSPROP_PERMANENT) == 0; }
         768        34360340 :     bool enumerable() const { return (attrs & JSPROP_ENUMERATE) != 0; }
         769        16218453 :     bool writable() const {
         770                 :         // JS_ASSERT(isDataDescriptor());
         771        16218453 :         return (attrs & JSPROP_READONLY) == 0;
         772                 :     }
         773         2425493 :     bool hasGetterValue() const { return attrs & JSPROP_GETTER; }
         774           90922 :     bool hasSetterValue() const { return attrs & JSPROP_SETTER; }
         775                 :
         776        93332318 :     bool isDataDescriptor() const {
         777        93332318 :         return (attrs & (JSPROP_SETTER | JSPROP_GETTER)) == 0;
         778                 :     }
         779          766167 :     bool isAccessorDescriptor() const {
         780          766167 :         return (attrs & (JSPROP_SETTER | JSPROP_GETTER)) != 0;
         781                 :     }
         782                 :
         783                 :     /*
         784                 :      * For ES5 compatibility, we allow properties with PropertyOp-flavored
         785                 :      * setters to be shadowed when set. The "own" property thereby created in
         786                 :      * the directly referenced object will have the same getter and setter as
         787                 :      * the prototype property. See bug 552432.
         788                 :      */
         789          503601 :     bool shadowable() const {
         790          503601 :         JS_ASSERT_IF(isDataDescriptor(), writable());
         791          503601 :         return hasSlot() || (attrs & JSPROP_SHADOWABLE);
         792                 :     }
         793                 :
         794                 :     /*
         795                 :      * Sometimes call objects and run-time block objects need unique shapes, but
         796                 :      * sometimes they don't.
         797                 :      *
         798                 :      * Property cache entries only record the shapes of the first and last
         799                 :      * objects along the search path, so if the search traverses more than those
         800                 :      * two objects, then those first and last shapes must determine the shapes
         801                 :      * of everything else along the path. The js_PurgeScopeChain stuff takes
         802                 :      * care of making this work, but that suffices only because we require that
         803                 :      * start points with the same shape have the same successor object in the
         804                 :      * search path --- a cache hit means the starting shapes were equal, which
         805                 :      * means the seach path tail (everything but the first object in the path)
         806                 :      * was shared, which in turn means the effects of a purge will be seen by
         807                 :      * all affected starting search points.
         808                 :      *
         809                 :      * For call and run-time block objects, the "successor object" is the scope
         810                 :      * chain parent. Unlike prototype objects (of which there are usually few),
         811                 :      * scope chain parents are created frequently (possibly on every call), so
         812                 :      * following the shape-implies-parent rule blindly would lead one to give
         813                 :      * every call and block its own shape.
         814                 :      *
         815                 :      * In many cases, however, it's not actually necessary to give call and
         816                 :      * block objects their own shapes, and we can do better. If the code will
         817                 :      * always be used with the same global object, and none of the enclosing
         818                 :      * call objects could have bindings added to them at runtime (by direct eval
         819                 :      * calls or function statements), then we can use a fixed set of shapes for
         820                 :      * those objects. You could think of the shapes in the functions' bindings
         821                 :      * and compile-time blocks as uniquely identifying the global object(s) at
         822                 :      * the end of the scope chain.
         823                 :      *
         824                 :      * (In fact, some JSScripts we do use against multiple global objects (see
         825                 :      * bug 618497), and using the fixed shapes isn't sound there.)
         826                 :      *
         827                 :      * In deciding whether a call or block has any extensible parents, we
         828                 :      * actually only need to consider enclosing calls; blocks are never
         829                 :      * extensible, and the other sorts of objects that appear in the scope
         830                 :      * chains ('with' blocks, say) are not CacheableNonGlobalScopes.
         831                 :      *
         832                 :      * If the hasExtensibleParents flag is set for the last property in a
         833                 :      * script's bindings or a compiler-generated Block object, then created
         834                 :      * Call or Block objects need unique shapes. If the flag is clear, then we
         835                 :      * can use lastBinding's shape.
         836                 :      */
         837                 :     static Shape *setExtensibleParents(JSContext *cx, Shape *shape);
         838          818526 :     bool extensibleParents() const { return !!(base()->flags & BaseShape::EXTENSIBLE_PARENTS); }
         839                 :
         840        29833330 :     uint32_t entryCount() const {
         841        29833330 :         if (hasTable())
         842          760476 :             return table().entryCount;
         843                 :
         844        29072854 :         const js::Shape *shape = this;
         845        29072854 :         uint32_t count = 0;
         846      1217439101 :         for (js::Shape::Range r = shape->all(); !r.empty(); r.popFront())
         847      1188366247 :             ++count;
         848        29072854 :         return count;
         849                 :     }
         850                 :
         851        34208013 :     bool isBigEnoughForAPropertyTable() const {
         852        34208013 :         JS_ASSERT(!hasTable());
         853        34208013 :         const js::Shape *shape = this;
         854        34208013 :         uint32_t count = 0;
         855        88017809 :         for (js::Shape::Range r = shape->all(); !r.empty(); r.popFront()) {
         856        53817291 :             ++count;
         857        53817291 :             if (count >= PropertyTable::MIN_ENTRIES)
         858            7495 :                 return true;
         859                 :         }
         860        34200518 :         return false;
         861                 :     }
         862                 :
         863                 : #ifdef DEBUG
         864                 :     void dump(JSContext *cx, FILE *fp) const;
         865                 :     void dumpSubtree(JSContext *cx, int level, FILE *fp) const;
         866                 : #endif
         867                 :
         868                 :     void finalize(FreeOp *fop);
         869                 :     void removeChild(js::Shape *child);
         870                 :
         871                 :     static inline void writeBarrierPre(const Shape *shape);
         872                 :     static inline void writeBarrierPost(const Shape *shape, void *addr);
         873                 :
         874                 :     /*
         875                 :      * All weak references need a read barrier for incremental GC. This getter
         876                 :      * method implements the read barrier. It's used to obtain initial shapes
         877                 :      * from the compartment.
         878                 :      */
         879                 :     static inline void readBarrier(const Shape *shape);
         880                 :
         881                 :     static inline ThingRootKind rootKind() { return THING_ROOT_SHAPE; }
         882                 :
         883                 :     inline void markChildren(JSTracer *trc);
         884                 :
         885                 :     /* For JIT usage */
         886          116121 :     static inline size_t offsetOfBase() { return offsetof(Shape, base_); }
         887                 :
         888                 :   private:
         889                 :     static void staticAsserts() {
         890                 :         JS_STATIC_ASSERT(offsetof(Shape, base_) == offsetof(js::shadow::Shape, base));
         891                 :         JS_STATIC_ASSERT(offsetof(Shape, slotInfo) == offsetof(js::shadow::Shape, slotInfo));
         892                 :         JS_STATIC_ASSERT(FIXED_SLOTS_SHIFT == js::shadow::Shape::FIXED_SLOTS_SHIFT);
         893                 :     }
         894                 : };
         895                 :
         896                 : struct EmptyShape : public js::Shape
         897                 : {
         898                 :     EmptyShape(UnownedBaseShape *base, uint32_t nfixed);
         899                 :
         900                 :     /*
         901                 :      * Lookup an initial shape matching the given parameters, creating an empty
         902                 :      * shape if none was found.
         903                 :      */
         904                 :     static Shape *getInitialShape(JSContext *cx, Class *clasp, JSObject *proto,
         905                 :                                   JSObject *parent, gc::AllocKind kind, uint32_t objectFlags = 0);
         906                 :
         907                 :     /*
         908                 :      * Reinsert an alternate initial shape, to be returned by future
         909                 :      * getInitialShape calls, until the new shape becomes unreachable in a GC
         910                 :      * and the table entry is purged.
         911                 :      */
         912                 :     static void insertInitialShape(JSContext *cx, Shape *shape, JSObject *proto);
         913                 : };
         914                 :
         915                 : /*
         916                 :  * Entries for the per-compartment initialShapes set indexing initial shapes
         917                 :  * for objects in the compartment and the associated types.
         918                 :  */
         919                 : struct InitialShapeEntry
         920        10782720 : {
         921                 :     /*
         922                 :      * Initial shape to give to the object. This is an empty shape, except for
         923                 :      * certain classes (e.g. String, RegExp) which may add certain baked-in
         924                 :      * properties.
         925                 :      */
         926                 :     ReadBarriered<Shape> shape;
         927                 :
         928                 :     /*
         929                 :      * Matching prototype for the entry. The shape of an object determines its
         930                 :      * prototype, but the prototype cannot be determined from the shape itself.
         931                 :      */
         932                 :     JSObject *proto;
         933                 :
         934                 :     /* State used to determine a match on an initial shape. */
         935                 :     struct Lookup {
         936                 :         Class *clasp;
         937                 :         JSObject *proto;
         938                 :         JSObject *parent;
         939                 :         uint32_t nfixed;
         940                 :         uint32_t baseFlags;
         941         8611900 :         Lookup(Class *clasp, JSObject *proto, JSObject *parent, uint32_t nfixed,
         942                 :                uint32_t baseFlags)
         943                 :             : clasp(clasp), proto(proto), parent(parent),
         944         8611900 :               nfixed(nfixed), baseFlags(baseFlags)
         945         8611900 :         {}
         946                 :     };
         947                 :
         948                 :     static inline HashNumber hash(const Lookup &lookup);
         949                 :     static inline bool match(const InitialShapeEntry &key, const Lookup &lookup);
         950                 : };
         951                 :
         952                 : typedef HashSet<InitialShapeEntry, InitialShapeEntry, SystemAllocPolicy> InitialShapeSet;
         953                 :
         954                 : struct StackShape
         955                 : {
         956                 :     UnownedBaseShape *base;
         957                 :     jsid             propid;
         958                 :     uint32_t         slot_;
         959                 :     uint8_t          attrs;
         960                 :     uint8_t          flags;
         961                 :     int16_t          shortid;
         962                 :
         963        30465010 :     StackShape(UnownedBaseShape *base, jsid propid, uint32_t slot,
         964                 :                uint32_t nfixed, unsigned attrs, unsigned flags, int shortid)
         965                 :       : base(base),
         966                 :         propid(propid),
         967                 :         slot_(slot),
         968                 :         attrs(uint8_t(attrs)),
         969                 :         flags(uint8_t(flags)),
         970        30465010 :         shortid(int16_t(shortid))
         971                 :     {
         972        30465010 :         JS_ASSERT(base);
         973        30465010 :         JS_ASSERT(!JSID_IS_VOID(propid));
         974        30465010 :         JS_ASSERT(slot <= SHAPE_INVALID_SLOT);
         975        30465010 :     }
         976                 :
         977         9342637 :     StackShape(const Shape *shape)
         978         9342637 :       : base(shape->base()->unowned()),
         979         9342637 :         propid(const_cast<Shape *>(shape)->propidRef()),
         980                 :         slot_(shape->slotInfo & Shape::SLOT_MASK),
         981                 :         attrs(shape->attrs),
         982                 :         flags(shape->flags),
         983        18685274 :         shortid(shape->shortid_)
         984         9342637 :     {}
         985                 :
         986        33407705 :     bool hasSlot() const { return (attrs & JSPROP_SHARED) == 0; }
         987        20594627 :     bool hasMissingSlot() const { return maybeSlot() == SHAPE_INVALID_SLOT; }
         988                 :
         989         1634797 :     uint32_t slot() const { JS_ASSERT(hasSlot() && !hasMissingSlot()); return slot_; }
         990        39239170 :     uint32_t maybeSlot() const { return slot_; }
         991                 :
         992          355342 :     uint32_t slotSpan() const {
         993          355342 :         uint32_t free = JSSLOT_FREE(base->clasp);
         994          355342 :         return hasMissingSlot() ? free : (maybeSlot() + 1);
         995                 :     }
         996                 :
         997        29635563 :     void setSlot(uint32_t slot) {
         998        29635563 :         JS_ASSERT(slot <= SHAPE_INVALID_SLOT);
         999        29635563 :         slot_ = slot;
        1000        29635563 :     }
        1001                 :
        1002                 :     inline HashNumber hash() const;
        1003                 : };
        1004                 :
        1005                 : /* Rooter for stack allocated shapes. */
        1006                 : class RootStackShape
        1007        15162673 : {
        1008                 :     Root<const UnownedBaseShape*> baseShapeRoot;
        1009                 :     Root<const jsid> propidRoot;
        1010                 :
        1011                 :   public:
        1012        15162673 :     RootStackShape(JSContext *cx, const StackShape *shape)
        1013                 :       : baseShapeRoot(cx, &shape->base),
        1014        15162673 :         propidRoot(cx, &shape->propid)
        1015        15162673 :     {}
        1016                 : };
        1017                 :
        1018                 : } /* namespace js */
        1019                 :
        1020                 : /* js::Shape pointer tag bit indicating a collision. */
        1021                 : #define SHAPE_COLLISION                 (uintptr_t(1))
        1022                 : #define SHAPE_REMOVED                   ((js::Shape *) SHAPE_COLLISION)
        1023                 :
        1024                 : /* Macros to get and set shape pointer values and collision flags. */
        1025                 : #define SHAPE_IS_FREE(shape)            ((shape) == NULL)
        1026                 : #define SHAPE_IS_REMOVED(shape)         ((shape) == SHAPE_REMOVED)
        1027                 : #define SHAPE_IS_LIVE(shape)            ((shape) > SHAPE_REMOVED)
        1028                 : #define SHAPE_FLAG_COLLISION(spp,shape) (*(spp) = (js::Shape *)               \
        1029                 :                                          (uintptr_t(shape) | SHAPE_COLLISION))
        1030                 : #define SHAPE_HAD_COLLISION(shape)      (uintptr_t(shape) & SHAPE_COLLISION)
        1031                 : #define SHAPE_FETCH(spp)                SHAPE_CLEAR_COLLISION(*(spp))
        1032                 :
        1033                 : #define SHAPE_CLEAR_COLLISION(shape)                                          \
        1034                 :     ((js::Shape *) (uintptr_t(shape) & ~SHAPE_COLLISION))
        1035                 :
        1036                 : #define SHAPE_STORE_PRESERVING_COLLISION(spp, shape)                          \
        1037                 :     (*(spp) = (js::Shape *) (uintptr_t(shape) | SHAPE_HAD_COLLISION(*(spp))))
        1038                 :
        1039                 : namespace js {
        1040                 :
        1041                 : inline Shape *
        1042        98304497 : Shape::search(JSContext *cx, Shape *start, jsid id, Shape ***pspp, bool adding)
        1043                 : {
        1044        98304497 :     if (start->inDictionary()) {
        1045        40652699 :         *pspp = start->table().search(id, adding);
        1046        40652699 :         return SHAPE_FETCH(*pspp);
        1047                 :     }
        1048                 :
        1049        57651798 :     *pspp = NULL;
        1050                 :
        1051        57651798 :     if (start->hasTable()) {
        1052         9242621 :         Shape **spp = start->table().search(id, adding);
        1053         9242621 :         return SHAPE_FETCH(spp);
        1054                 :     }
        1055                 :
        1056        48409177 :     if (start->numLinearSearches() == LINEAR_SEARCHES_MAX) {
        1057        34208013 :         if (start->isBigEnoughForAPropertyTable()) {
        1058           14990 :             RootShape startRoot(cx, &start);
        1059           14990 :             RootId idRoot(cx, &id);
        1060            7495 :             if (start->hashify(cx)) {
        1061            7495 :                 Shape **spp = start->table().search(id, adding);
        1062            7495 :                 return SHAPE_FETCH(spp);
        1063                 :             }
        1064                 :         }
        1065                 :         /*
        1066                 :          * No table built -- there weren't enough entries, or OOM occurred.
        1067                 :          * Don't increment numLinearSearches, to keep hasTable() false.
        1068                 :          */
        1069        34200518 :         JS_ASSERT(!start->hasTable());
        1070                 :     } else {
        1071        14201164 :         start->incrementNumLinearSearches();
        1072                 :     }
        1073                 :
        1074       905401775 :     for (Shape *shape = start; shape; shape = shape->parent) {
        1075       869602028 :         if (shape->propidRef() == id)
        1076        12601935 :             return shape;
        1077                 :     }
        1078                 :
        1079        35799747 :     return NULL;
        1080                 : }
        1081                 :
        1082                 : } // namespace js
        1083                 :
        1084                 : #ifdef _MSC_VER
        1085                 : #pragma warning(pop)
        1086                 : #pragma warning(pop)
        1087                 : #endif
        1088                 :
        1089                 : namespace JS {
        1090                 :     template<> class AnchorPermitted<js::Shape *> { };
        1091                 :     template<> class AnchorPermitted<const js::Shape *> { };
        1092                 : }
        1093                 :
        1094                 : #endif /* jsscope_h___ */

Generated by: LCOV version 1.7