LCOV - app.info - js/src/jspropertytree.cpp

LCOV - code coverage report
| Current view: | directory - js/src - jspropertytree.cpp (source / functions) |  | Found | Hit | Coverage |
| Test: | app.info | Lines: | 172 | 93 | 54.1 %
| Date: | 2012-04-07 | Functions: | 13 | 10 | 76.9 %

           1                 : /* -*- Mode: c++; c-basic-offset: 4; tab-width: 40; indent-tabs-mode: nil -*- */
           2                 : /* vim: set ts=40 sw=4 et tw=99: */
           3                 : /* ***** BEGIN LICENSE BLOCK *****
           4                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
           5                 :  *
           6                 :  * The contents of this file are subject to the Mozilla Public License Version
           7                 :  * 1.1 (the "License"); you may not use this file except in compliance with
           8                 :  * the License. You may obtain a copy of the License at
           9                 :  * http://www.mozilla.org/MPL/
          10                 :  *
          11                 :  * Software distributed under the License is distributed on an "AS IS" basis,
          12                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
          13                 :  * for the specific language governing rights and limitations under the
          14                 :  * License.
          15                 :  *
          16                 :  * The Original Code is the Mozilla SpiderMonkey property tree implementation
          17                 :  *
          18                 :  * The Initial Developer of the Original Code is
          19                 :  *   Mozilla Foundation
          20                 :  * Portions created by the Initial Developer are Copyright (C) 2002-2010
          21                 :  * the Initial Developer. All Rights Reserved.
          22                 :  *
          23                 :  * Contributor(s):
          24                 :  *   Brendan Eich <brendan@mozilla.org>
          25                 :  *
          26                 :  * Alternatively, the contents of this file may be used under the terms of
          27                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
          28                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
          29                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
          30                 :  * of those above. If you wish to allow use of your version of this file only
          31                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
          32                 :  * use your version of this file under the terms of the MPL, indicate your
          33                 :  * decision by deleting the provisions above and replace them with the notice
          34                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
          35                 :  * the provisions above, a recipient may use your version of this file under
          36                 :  * the terms of any one of the MPL, the GPL or the LGPL.
          37                 :  *
          38                 :  * ***** END LICENSE BLOCK ***** */
          39                 :
          40                 : #include <new>
          41                 :
          42                 : #include "jstypes.h"
          43                 : #include "jsprf.h"
          44                 : #include "jsapi.h"
          45                 : #include "jscntxt.h"
          46                 : #include "jsgc.h"
          47                 : #include "jspropertytree.h"
          48                 : #include "jsscope.h"
          49                 :
          50                 : #include "jsgcinlines.h"
          51                 : #include "jsobjinlines.h"
          52                 : #include "jsscopeinlines.h"
          53                 :
          54                 : using namespace js;
          55                 :
          56                 : inline HashNumber
          57         6236301 : ShapeHasher::hash(const Lookup &l)
          58                 : {
          59         6236301 :     return l.hash();
          60                 : }
          61                 :
          62                 : inline bool
          63         4136813 : ShapeHasher::match(const Key k, const Lookup &l)
          64                 : {
          65         4136813 :     return k->matches(l);
          66                 : }
          67                 :
          68                 : Shape *
          69        15359492 : PropertyTree::newShape(JSContext *cx)
          70                 : {
          71        15359492 :     Shape *shape = js_NewGCShape(cx);
          72        15359492 :     if (!shape) {
          73               0 :         JS_ReportOutOfMemory(cx);
          74               0 :         return NULL;
          75                 :     }
          76        15359492 :     return shape;
          77                 : }
          78                 :
          79                 : static KidsHash *
          80          708487 : HashChildren(Shape *kid1, Shape *kid2)
          81                 : {
          82          708487 :     KidsHash *hash = OffTheBooks::new_<KidsHash>();
          83          708487 :     if (!hash || !hash->init(2)) {
          84               0 :         Foreground::delete_(hash);
          85               0 :         return NULL;
          86                 :     }
          87                 :
          88          708487 :     JS_ALWAYS_TRUE(hash->putNew(kid1, kid1));
          89          708487 :     JS_ALWAYS_TRUE(hash->putNew(kid2, kid2));
          90          708487 :     return hash;
          91                 : }
          92                 :
          93                 : bool
          94        13499442 : PropertyTree::insertChild(JSContext *cx, Shape *parent, Shape *child)
          95                 : {
          96        13499442 :     JS_ASSERT(!parent->inDictionary());
          97        13499442 :     JS_ASSERT(!child->parent);
          98        13499442 :     JS_ASSERT(!child->inDictionary());
          99        13499442 :     JS_ASSERT(cx->compartment == compartment);
         100        13499442 :     JS_ASSERT(child->compartment() == parent->compartment());
         101                 :
         102        13499442 :     KidsPointer *kidp = &parent->kids;
         103                 :
         104        13499442 :     if (kidp->isNull()) {
         105        12449698 :         child->setParent(parent);
         106        12449698 :         kidp->setShape(child);
         107        12449698 :         return true;
         108                 :     }
         109                 :
         110         1049744 :     if (kidp->isShape()) {
         111          708487 :         Shape *shape = kidp->toShape();
         112          708487 :         JS_ASSERT(shape != child);
         113          708487 :         JS_ASSERT(!shape->matches(child));
         114                 :
         115          708487 :         KidsHash *hash = HashChildren(shape, child);
         116          708487 :         if (!hash) {
         117               0 :             JS_ReportOutOfMemory(cx);
         118               0 :             return false;
         119                 :         }
         120          708487 :         kidp->setHash(hash);
         121          708487 :         child->setParent(parent);
         122          708487 :         return true;
         123                 :     }
         124                 :
         125          341257 :     if (!kidp->toHash()->putNew(child, child)) {
         126               0 :         JS_ReportOutOfMemory(cx);
         127               0 :         return false;
         128                 :     }
         129                 :
         130          341257 :     child->setParent(parent);
         131          341257 :     return true;
         132                 : }
         133                 :
         134                 : void
         135           44584 : Shape::removeChild(Shape *child)
         136                 : {
         137           44584 :     JS_ASSERT(!child->inDictionary());
         138                 :
         139           44584 :     KidsPointer *kidp = &kids;
         140                 :
         141           44584 :     if (kidp->isShape()) {
         142            3372 :         JS_ASSERT(kidp->toShape() == child);
         143            3372 :         kidp->setNull();
         144            3372 :         return;
         145                 :     }
         146                 :
         147           41212 :     KidsHash *hash = kidp->toHash();
         148           41212 :     JS_ASSERT(hash->count() >= 2);      /* otherwise kidp->isShape() should be true */
         149                 :
         150           41212 :     hash->remove(child);
         151                 :
         152           41212 :     if (hash->count() == 1) {
         153                 :         /* Convert from HASH form back to SHAPE form. */
         154           26111 :         KidsHash::Range r = hash->all();
         155           26111 :         Shape *otherChild = r.front();
         156           26111 :         JS_ASSERT((r.popFront(), r.empty()));    /* No more elements! */
         157           26111 :         kidp->setShape(otherChild);
         158           26111 :         js::UnwantedForeground::delete_(hash);
         159                 :     }
         160                 : }
         161                 :
         162                 : /*
         163                 :  * We need a read barrier for the shape tree, since these are weak pointers.
         164                 :  */
         165                 : static Shape *
         166        19719003 : ReadBarrier(Shape *shape)
         167                 : {
         168                 : #ifdef JSGC_INCREMENTAL
         169        19719003 :     JSCompartment *comp = shape->compartment();
         170        19719003 :     if (comp->needsBarrier()) {
         171            1059 :         Shape *tmp = shape;
         172            1059 :         MarkShapeUnbarriered(comp->barrierTracer(), &tmp, "read barrier");
         173            1059 :         JS_ASSERT(tmp == shape);
         174                 :     }
         175                 : #endif
         176        19719003 :     return shape;
         177                 : }
         178                 :
         179                 : Shape *
         180        33218445 : PropertyTree::getChild(JSContext *cx, Shape *parent, uint32_t nfixed, const StackShape &child)
         181                 : {
         182                 :     Shape *shape;
         183                 :
         184        33218445 :     JS_ASSERT(parent);
         185                 :
         186                 :     /*
         187                 :      * The property tree has extremely low fan-out below its root in
         188                 :      * popular embeddings with real-world workloads. Patterns such as
         189                 :      * defining closures that capture a constructor's environment as
         190                 :      * getters or setters on the new object that is passed in as
         191                 :      * |this| can significantly increase fan-out below the property
         192                 :      * tree root -- see bug 335700 for details.
         193                 :      */
         194        33218445 :     KidsPointer *kidp = &parent->kids;
         195        33218445 :     if (kidp->isShape()) {
         196        16331889 :         shape = kidp->toShape();
         197        16331889 :         if (shape->matches(child))
         198        15623402 :             return ReadBarrier(shape);
         199        16886556 :     } else if (kidp->isHash()) {
         200         4436858 :         shape = *kidp->toHash()->lookup(child);
         201         4436858 :         if (shape)
         202         4095601 :             return ReadBarrier(shape);
         203                 :     } else {
         204                 :         /* If kidp->isNull(), we always insert. */
         205                 :     }
         206                 :
         207        26998884 :     RootStackShape childRoot(cx, &child);
         208        26998884 :     RootShape parentRoot(cx, &parent);
         209                 :
         210        13499442 :     shape = newShape(cx);
         211        13499442 :     if (!shape)
         212               0 :         return NULL;
         213                 :
         214        13499442 :     new (shape) Shape(child, nfixed);
         215                 :
         216        13499442 :     if (!insertChild(cx, parent, shape))
         217               0 :         return NULL;
         218                 :
         219        13499442 :     return shape;
         220                 : }
         221                 :
         222                 : void
         223        20149251 : Shape::finalize(FreeOp *fop)
         224                 : {
         225        20149251 :     if (!inDictionary()) {
         226        15359492 :         if (parent && parent->isMarked())
         227           44584 :             parent->removeChild(this);
         228                 :
         229        15359492 :         if (kids.isHash())
         230          682376 :             fop->delete_(kids.toHash());
         231                 :     }
         232        20149251 : }
         233                 :
         234                 : #ifdef DEBUG
         235                 :
         236                 : void
         237               0 : KidsPointer::checkConsistency(const Shape *aKid) const
         238                 : {
         239               0 :     if (isShape()) {
         240               0 :         JS_ASSERT(toShape() == aKid);
         241                 :     } else {
         242               0 :         JS_ASSERT(isHash());
         243               0 :         KidsHash *hash = toHash();
         244               0 :         KidsHash::Ptr ptr = hash->lookup(aKid);
         245               0 :         JS_ASSERT(*ptr == aKid);
         246                 :     }
         247               0 : }
         248                 :
         249                 : void
         250               0 : Shape::dump(JSContext *cx, FILE *fp) const
         251                 : {
         252               0 :     jsid propid = this->propid();
         253                 :
         254               0 :     JS_ASSERT(!JSID_IS_VOID(propid));
         255                 :
         256               0 :     if (JSID_IS_INT(propid)) {
         257               0 :         fprintf(fp, "[%ld]", (long) JSID_TO_INT(propid));
         258               0 :     } else if (JSID_IS_DEFAULT_XML_NAMESPACE(propid)) {
         259               0 :         fprintf(fp, "<default XML namespace>");
         260                 :     } else {
         261                 :         JSLinearString *str;
         262               0 :         if (JSID_IS_ATOM(propid)) {
         263               0 :             str = JSID_TO_ATOM(propid);
         264                 :         } else {
         265               0 :             JS_ASSERT(JSID_IS_OBJECT(propid));
         266               0 :             JSString *s = ToStringSlow(cx, IdToValue(propid));
         267               0 :             fputs("object ", fp);
         268               0 :             str = s ? s->ensureLinear(cx) : NULL;
         269                 :         }
         270               0 :         if (!str)
         271               0 :             fputs("<error>", fp);
         272                 :         else
         273               0 :             FileEscapedString(fp, str, '"');
         274                 :     }
         275                 :
         276                 :     fprintf(fp, " g/s %p/%p slot %d attrs %x ",
         277               0 :             JS_FUNC_TO_DATA_PTR(void *, base()->rawGetter),
         278               0 :             JS_FUNC_TO_DATA_PTR(void *, base()->rawSetter),
         279               0 :             hasSlot() ? slot() : -1, attrs);
         280                 :
         281               0 :     if (attrs) {
         282               0 :         int first = 1;
         283               0 :         fputs("(", fp);
         284                 : #define DUMP_ATTR(name, display) if (attrs & JSPROP_##name) fputs(&(" " #display)[first], fp), first = 0
         285               0 :         DUMP_ATTR(ENUMERATE, enumerate);
         286               0 :         DUMP_ATTR(READONLY, readonly);
         287               0 :         DUMP_ATTR(PERMANENT, permanent);
         288               0 :         DUMP_ATTR(GETTER, getter);
         289               0 :         DUMP_ATTR(SETTER, setter);
         290               0 :         DUMP_ATTR(SHARED, shared);
         291                 : #undef  DUMP_ATTR
         292               0 :         fputs(") ", fp);
         293                 :     }
         294                 :
         295               0 :     fprintf(fp, "flags %x ", flags);
         296               0 :     if (flags) {
         297               0 :         int first = 1;
         298               0 :         fputs("(", fp);
         299                 : #define DUMP_FLAG(name, display) if (flags & name) fputs(&(" " #display)[first], fp), first = 0
         300               0 :         DUMP_FLAG(HAS_SHORTID, has_shortid);
         301               0 :         DUMP_FLAG(IN_DICTIONARY, in_dictionary);
         302                 : #undef  DUMP_FLAG
         303               0 :         fputs(") ", fp);
         304                 :     }
         305                 :
         306               0 :     fprintf(fp, "shortid %d\n", shortid());
         307               0 : }
         308                 :
         309                 : void
         310               0 : Shape::dumpSubtree(JSContext *cx, int level, FILE *fp) const
         311                 : {
         312               0 :     if (!parent) {
         313               0 :         JS_ASSERT(level == 0);
         314               0 :         JS_ASSERT(JSID_IS_EMPTY(propid_));
         315               0 :         fprintf(fp, "class %s emptyShape\n", getObjectClass()->name);
         316                 :     } else {
         317               0 :         fprintf(fp, "%*sid ", level, "");
         318               0 :         dump(cx, fp);
         319                 :     }
         320                 :
         321               0 :     if (!kids.isNull()) {
         322               0 :         ++level;
         323               0 :         if (kids.isShape()) {
         324               0 :             Shape *kid = kids.toShape();
         325               0 :             JS_ASSERT(kid->parent == this);
         326               0 :             kid->dumpSubtree(cx, level, fp);
         327                 :         } else {
         328               0 :             const KidsHash &hash = *kids.toHash();
         329               0 :             for (KidsHash::Range range = hash.all(); !range.empty(); range.popFront()) {
         330               0 :                 Shape *kid = range.front();
         331                 :
         332               0 :                 JS_ASSERT(kid->parent == this);
         333               0 :                 kid->dumpSubtree(cx, level, fp);
         334                 :             }
         335                 :         }
         336                 :     }
         337               0 : }
         338                 :
         339                 : void
         340           38427 : js::PropertyTree::dumpShapes(JSRuntime *rt)
         341                 : {
         342                 :     static bool init = false;
         343                 :     static FILE *dumpfp = NULL;
         344           38427 :     if (!init) {
         345           18667 :         init = true;
         346           18667 :         const char *name = getenv("JS_DUMP_SHAPES_FILE");
         347           18667 :         if (!name)
         348           18667 :             return;
         349               0 :         dumpfp = fopen(name, "a");
         350                 :     }
         351                 :
         352           19760 :     if (!dumpfp)
         353           19760 :         return;
         354                 :
         355               0 :     fprintf(dumpfp, "rt->gcNumber = %lu", (unsigned long)rt->gcNumber);
         356                 :
         357               0 :     for (gc::GCCompartmentsIter c(rt); !c.done(); c.next()) {
         358               0 :         fprintf(dumpfp, "*** Compartment %p ***\n", (void *)c.get());
         359                 :
         360                 :         /*
         361                 :         typedef JSCompartment::EmptyShapeSet HS;
         362                 :         HS &h = c->emptyShapes;
         363                 :         for (HS::Range r = h.all(); !r.empty(); r.popFront()) {
         364                 :             Shape *empty = r.front();
         365                 :             empty->dumpSubtree(rt, 0, dumpfp);
         366                 :             putc('\n', dumpfp);
         367                 :         }
         368                 :         */
         369                 :     }
         370                 : }
         371                 : #endif

Generated by: LCOV version 1.7