LCOV - code coverage report
Current view: directory - js/src - jsscope.h (source / functions) Found Hit Coverage
Test: app.info Lines: 235 232 98.7 %
Date: 2012-06-02 Functions: 105 103 98.1 %

       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___ */

Generated by: LCOV version 1.7