LCOV - code coverage report
Current view: directory - js/src - jspropertycache.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 92 84 91.3 %
Date: 2012-06-02 Functions: 5 4 80.0 %

       1                 : /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2                 :  * vim: set ts=8 sw=4 et tw=98:
       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 the GNU General Public License Version 2 or later (the "GPL"), or
      29                 :  * 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                 : #include "jspropertycache.h"
      42                 : #include "jscntxt.h"
      43                 : #include "jsnum.h"
      44                 : #include "jsobjinlines.h"
      45                 : #include "jsopcodeinlines.h"
      46                 : #include "jspropertycacheinlines.h"
      47                 : 
      48                 : using namespace js;
      49                 : 
      50                 : PropertyCacheEntry *
      51        18783779 : PropertyCache::fill(JSContext *cx, JSObject *obj, unsigned scopeIndex, JSObject *pobj,
      52                 :                     const Shape *shape)
      53                 : {
      54        18783779 :     JS_ASSERT(this == &JS_PROPERTY_CACHE(cx));
      55        18783779 :     JS_ASSERT(!cx->runtime->gcRunning);
      56                 : 
      57                 :     /*
      58                 :      * Check for fill from js_SetPropertyHelper where the setter removed shape
      59                 :      * from pobj (via unwatch or delete, e.g.).
      60                 :      */
      61        18783779 :     if (!pobj->nativeContains(cx, *shape)) {
      62                 :         PCMETER(oddfills++);
      63               0 :         return JS_NO_PROP_CACHE_FILL;
      64                 :     }
      65                 : 
      66                 :     /*
      67                 :      * Check for overdeep scope and prototype chain. Because resolve, getter,
      68                 :      * and setter hooks can change the prototype chain using JS_SetPrototype
      69                 :      * after LookupPropertyWithFlags has returned, we calculate the protoIndex
      70                 :      * here and not in LookupPropertyWithFlags.
      71                 :      *
      72                 :      * The scopeIndex can't be wrong. We require JS_SetParent calls to happen
      73                 :      * before any running script might consult a parent-linked scope chain. If
      74                 :      * this requirement is not satisfied, the fill in progress will never hit,
      75                 :      * but scope shape tests ensure nothing malfunctions.
      76                 :      */
      77        18783779 :     JS_ASSERT_IF(obj == pobj, scopeIndex == 0);
      78                 : 
      79        18783779 :     JSObject *tmp = obj;
      80        20502726 :     for (unsigned i = 0; i < scopeIndex; i++)
      81         1718947 :         tmp = &tmp->asScope().enclosingScope();
      82                 : 
      83        18783779 :     unsigned protoIndex = 0;
      84        39646913 :     while (tmp != pobj) {
      85                 :         /*
      86                 :          * Don't cache entries across prototype lookups which can mutate in
      87                 :          * arbitrary ways without a shape change.
      88                 :          */
      89         2288364 :         if (tmp->hasUncacheableProto()) {
      90                 :             PCMETER(noprotos++);
      91          208960 :             return JS_NO_PROP_CACHE_FILL;
      92                 :         }
      93                 : 
      94         2079404 :         tmp = tmp->getProto();
      95                 : 
      96                 :         /*
      97                 :          * We cannot cache properties coming from native objects behind
      98                 :          * non-native ones on the prototype chain. The non-natives can
      99                 :          * mutate in arbitrary way without changing any shapes.
     100                 :          */
     101         2079404 :         if (!tmp || !tmp->isNative()) {
     102                 :             PCMETER(noprotos++);
     103              49 :             return JS_NO_PROP_CACHE_FILL;
     104                 :         }
     105         2079355 :         ++protoIndex;
     106                 :     }
     107                 : 
     108                 :     typedef PropertyCacheEntry Entry;
     109        18574770 :     if (scopeIndex > Entry::MaxScopeIndex || protoIndex > Entry::MaxProtoIndex) {
     110                 :         PCMETER(longchains++);
     111             352 :         return JS_NO_PROP_CACHE_FILL;
     112                 :     }
     113                 : 
     114                 :     /*
     115                 :      * Optimize the cached vword based on our parameters and the current pc's
     116                 :      * opcode format flags.
     117                 :      */
     118                 :     jsbytecode *pc;
     119        18574418 :     (void) cx->stack.currentScript(&pc);
     120        18574418 :     JSOp op = JSOp(*pc);
     121        18574418 :     const JSCodeSpec *cs = &js_CodeSpec[op];
     122                 : 
     123        18574418 :     if ((cs->format & JOF_SET) && obj->watched())
     124            1253 :         return JS_NO_PROP_CACHE_FILL;
     125                 : 
     126        18573165 :     if (obj == pobj) {
     127        15901152 :         JS_ASSERT(scopeIndex == 0 && protoIndex == 0);
     128                 :     } else {
     129                 : #ifdef DEBUG
     130         2672013 :         if (scopeIndex == 0) {
     131         1572611 :             JS_ASSERT(protoIndex != 0);
     132         1572611 :             JS_ASSERT((protoIndex == 1) == (obj->getProto() == pobj));
     133                 :         }
     134                 : #endif
     135                 : 
     136         2672013 :         if (scopeIndex != 0 || protoIndex != 1) {
     137                 :             /*
     138                 :              * Make sure that a later shadowing assignment will enter
     139                 :              * PurgeProtoChain and invalidate this entry, bug 479198.
     140                 :              */
     141         1429170 :             if (!obj->isDelegate())
     142         1373935 :                 return JS_NO_PROP_CACHE_FILL;
     143                 :         }
     144                 :     }
     145                 : 
     146        17199230 :     PropertyCacheEntry *entry = &table[hash(pc, obj->lastProperty())];
     147                 :     PCMETER(entry->vword.isNull() || recycles++);
     148        17199230 :     entry->assign(pc, obj->lastProperty(), pobj->lastProperty(), shape, scopeIndex, protoIndex);
     149                 : 
     150        17199230 :     empty = false;
     151                 :     PCMETER(fills++);
     152                 : 
     153                 :     /*
     154                 :      * The modfills counter is not exact. It increases if a getter or setter
     155                 :      * recurse into the interpreter.
     156                 :      */
     157                 :     PCMETER(entry == pctestentry || modfills++);
     158                 :     PCMETER(pctestentry = NULL);
     159        17199230 :     return entry;
     160                 : }
     161                 : 
     162                 : PropertyName *
     163        23861499 : PropertyCache::fullTest(JSContext *cx, jsbytecode *pc, JSObject **objp, JSObject **pobjp,
     164                 :                         PropertyCacheEntry *entry)
     165                 : {
     166                 :     JSObject *obj, *pobj, *tmp;
     167                 : #ifdef DEBUG
     168        23861499 :     JSScript *script = cx->stack.currentScript();
     169                 : #endif
     170                 : 
     171        23861499 :     JS_ASSERT(this == &JS_PROPERTY_CACHE(cx));
     172        23861499 :     JS_ASSERT(uint32_t(pc - script->code) < script->length);
     173                 : 
     174        23861499 :     JSOp op = JSOp(*pc);
     175        23861499 :     const JSCodeSpec &cs = js_CodeSpec[op];
     176                 : 
     177        23861499 :     obj = *objp;
     178                 : 
     179        23861499 :     if (entry->kpc != pc) {
     180                 :         PCMETER(kpcmisses++);
     181                 : 
     182        23143772 :         PropertyName *name = GetNameFromBytecode(cx, pc, op, cs);
     183                 : #ifdef DEBUG_notme
     184                 :         JSAutoByteString printable;
     185                 :         fprintf(stderr,
     186                 :                 "id miss for %s from %s:%u"
     187                 :                 " (pc %u, kpc %u, kshape %p, shape %p)\n",
     188                 :                 js_AtomToPrintableString(cx, name, &printable),
     189                 :                 script->filename,
     190                 :                 js_PCToLineNumber(cx, script, pc),
     191                 :                 pc - script->code,
     192                 :                 entry->kpc - script->code,
     193                 :                 entry->kshape,
     194                 :                 obj->lastProperty());
     195                 :                 js_Disassemble1(cx, script, pc,
     196                 :                                 pc - script->code,
     197                 :                                 JS_FALSE, stderr);
     198                 : #endif
     199                 : 
     200        23143772 :         return name;
     201                 :     }
     202                 : 
     203          717727 :     if (entry->kshape != obj->lastProperty()) {
     204                 :         PCMETER(kshapemisses++);
     205          553406 :         return GetNameFromBytecode(cx, pc, op, cs);
     206                 :     }
     207                 : 
     208                 :     /*
     209                 :      * PropertyCache::test handles only the direct and immediate-prototype hit
     210                 :      * cases. All others go here.
     211                 :      */
     212          164321 :     pobj = obj;
     213                 : 
     214          164321 :     if (JOF_MODE(cs.format) == JOF_NAME) {
     215          151458 :         uint8_t scopeIndex = entry->scopeIndex;
     216          526853 :         while (scopeIndex > 0) {
     217          223937 :             tmp = pobj->enclosingScope();
     218          223937 :             if (!tmp || !tmp->isNative())
     219               0 :                 break;
     220          223937 :             pobj = tmp;
     221          223937 :             scopeIndex--;
     222                 :         }
     223                 : 
     224          151458 :         *objp = pobj;
     225                 :     }
     226                 : 
     227          164321 :     uint8_t protoIndex = entry->protoIndex;
     228          341597 :     while (protoIndex > 0) {
     229           12955 :         tmp = pobj->getProto();
     230           12955 :         if (!tmp || !tmp->isNative())
     231               0 :             break;
     232           12955 :         pobj = tmp;
     233           12955 :         protoIndex--;
     234                 :     }
     235                 : 
     236          164321 :     if (pobj->lastProperty() == entry->pshape) {
     237                 : #ifdef DEBUG
     238          120733 :         PropertyName *name = GetNameFromBytecode(cx, pc, op, cs);
     239          120733 :         JS_ASSERT(pobj->nativeContains(cx, js_CheckForStringIndex(ATOM_TO_JSID(name))));
     240                 : #endif
     241          120733 :         *pobjp = pobj;
     242          120733 :         return NULL;
     243                 :     }
     244                 : 
     245                 :     PCMETER(vcapmisses++);
     246           43588 :     return GetNameFromBytecode(cx, pc, op, cs);
     247                 : }
     248                 : 
     249                 : #ifdef DEBUG
     250                 : void
     251           18726 : PropertyCache::assertEmpty()
     252                 : {
     253           18726 :     JS_ASSERT(empty);
     254        76720422 :     for (unsigned i = 0; i < SIZE; i++) {
     255        76701696 :         JS_ASSERT(!table[i].kpc);
     256        76701696 :         JS_ASSERT(!table[i].kshape);
     257        76701696 :         JS_ASSERT(!table[i].pshape);
     258        76701696 :         JS_ASSERT(!table[i].prop);
     259        76701696 :         JS_ASSERT(!table[i].scopeIndex);
     260        76701696 :         JS_ASSERT(!table[i].protoIndex);
     261                 :     }
     262           18726 : }
     263                 : #endif
     264                 : 
     265                 : void
     266           52591 : PropertyCache::purge(JSRuntime *rt)
     267                 : {
     268           52591 :     if (empty) {
     269           18726 :         assertEmpty();
     270           18726 :         return;
     271                 :     }
     272                 : 
     273           33865 :     PodArrayZero(table);
     274           33865 :     empty = true;
     275                 : 
     276                 : #ifdef JS_PROPERTY_CACHE_METERING
     277                 :   { static FILE *fp;
     278                 :     if (!fp)
     279                 :         fp = fopen("/tmp/propcache.stats", "w");
     280                 :     if (fp) {
     281                 :         fputs("Property cache stats for ", fp);
     282                 :         fprintf(fp, "GC %lu\n", (unsigned long)rt->gcNumber);
     283                 : 
     284                 : # define P(mem) fprintf(fp, "%11s %10lu\n", #mem, (unsigned long)mem)
     285                 :         P(fills);
     286                 :         P(nofills);
     287                 :         P(rofills);
     288                 :         P(disfills);
     289                 :         P(oddfills);
     290                 :         P(add2dictfills);
     291                 :         P(modfills);
     292                 :         P(brandfills);
     293                 :         P(noprotos);
     294                 :         P(longchains);
     295                 :         P(recycles);
     296                 :         P(tests);
     297                 :         P(pchits);
     298                 :         P(protopchits);
     299                 :         P(initests);
     300                 :         P(inipchits);
     301                 :         P(inipcmisses);
     302                 :         P(settests);
     303                 :         P(addpchits);
     304                 :         P(setpchits);
     305                 :         P(setpcmisses);
     306                 :         P(setmisses);
     307                 :         P(kpcmisses);
     308                 :         P(kshapemisses);
     309                 :         P(vcapmisses);
     310                 :         P(misses);
     311                 :         P(flushes);
     312                 :         P(pcpurges);
     313                 : # undef P
     314                 : 
     315                 :         fprintf(fp, "hit rates: pc %g%% (proto %g%%), set %g%%, ini %g%%, full %g%%\n",
     316                 :                 (100. * pchits) / tests,
     317                 :                 (100. * protopchits) / tests,
     318                 :                 (100. * (addpchits + setpchits))
     319                 :                 / settests,
     320                 :                 (100. * inipchits) / initests,
     321                 :                 (100. * (tests - misses)) / tests);
     322                 :         fflush(fp);
     323                 :     }
     324                 :   }
     325                 : #endif
     326                 : 
     327                 :     PCMETER(flushes++);
     328                 : }
     329                 : 
     330                 : void
     331               0 : PropertyCache::restore(PropertyCacheEntry *entry)
     332                 : {
     333                 :     PropertyCacheEntry *entry2;
     334                 : 
     335               0 :     empty = false;
     336                 : 
     337               0 :     entry2 = &table[hash(entry->kpc, entry->kshape)];
     338               0 :     *entry2 = *entry;
     339               0 : }

Generated by: LCOV version 1.7