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

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-07-07 | 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        18837631 : PropertyCache::fill(JSContext *cx, JSObject *obj, unsigned scopeIndex, JSObject *pobj,
          52                 :                     const Shape *shape)
          53                 : {
          54        18837631 :     JS_ASSERT(this == &JS_PROPERTY_CACHE(cx));
          55        18837631 :     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        18837631 :     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        18837631 :     JS_ASSERT_IF(obj == pobj, scopeIndex == 0);
          78                 :
          79        18837631 :     JSObject *tmp = obj;
          80        20556567 :     for (unsigned i = 0; i < scopeIndex; i++)
          81         1718936 :         tmp = &tmp->asScope().enclosingScope();
          82                 :
          83        18837631 :     unsigned protoIndex = 0;
          84        39752076 :     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         2285811 :         if (tmp->hasUncacheableProto()) {
          90                 :             PCMETER(noprotos++);
          91          208948 :             return JS_NO_PROP_CACHE_FILL;
          92                 :         }
          93                 :
          94         2076863 :         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         2076863 :         if (!tmp || !tmp->isNative()) {
         102                 :             PCMETER(noprotos++);
         103              49 :             return JS_NO_PROP_CACHE_FILL;
         104                 :         }
         105         2076814 :         ++protoIndex;
         106                 :     }
         107                 :
         108                 :     typedef PropertyCacheEntry Entry;
         109        18628634 :     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        18628282 :     (void) cx->stack.currentScript(&pc);
         120        18628282 :     JSOp op = JSOp(*pc);
         121        18628282 :     const JSCodeSpec *cs = &js_CodeSpec[op];
         122                 :
         123        18628282 :     if ((cs->format & JOF_SET) && obj->watched())
         124            1253 :         return JS_NO_PROP_CACHE_FILL;
         125                 :
         126        18627029 :     if (obj == pobj) {
         127        15957899 :         JS_ASSERT(scopeIndex == 0 && protoIndex == 0);
         128                 :     } else {
         129                 : #ifdef DEBUG
         130         2669130 :         if (scopeIndex == 0) {
         131         1569696 :             JS_ASSERT(protoIndex != 0);
         132         1569696 :             JS_ASSERT((protoIndex == 1) == (obj->getProto() == pobj));
         133                 :         }
         134                 : #endif
         135                 :
         136         2669130 :         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         1429562 :             if (!obj->isDelegate())
         142         1374304 :                 return JS_NO_PROP_CACHE_FILL;
         143                 :         }
         144                 :     }
         145                 :
         146        17252725 :     PropertyCacheEntry *entry = &table[hash(pc, obj->lastProperty())];
         147                 :     PCMETER(entry->vword.isNull() || recycles++);
         148        17252725 :     entry->assign(pc, obj->lastProperty(), pobj->lastProperty(), shape, scopeIndex, protoIndex);
         149                 :
         150        17252725 :     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        17252725 :     return entry;
         160                 : }
         161                 :
         162                 : PropertyName *
         163        23915585 : PropertyCache::fullTest(JSContext *cx, jsbytecode *pc, JSObject **objp, JSObject **pobjp,
         164                 :                         PropertyCacheEntry *entry)
         165                 : {
         166                 :     JSObject *obj, *pobj, *tmp;
         167                 : #ifdef DEBUG
         168        23915585 :     JSScript *script = cx->stack.currentScript();
         169                 : #endif
         170                 :
         171        23915585 :     JS_ASSERT(this == &JS_PROPERTY_CACHE(cx));
         172        23915585 :     JS_ASSERT(uint32_t(pc - script->code) < script->length);
         173                 :
         174        23915585 :     JSOp op = JSOp(*pc);
         175        23915585 :     const JSCodeSpec &cs = js_CodeSpec[op];
         176                 :
         177        23915585 :     obj = *objp;
         178                 :
         179        23915585 :     if (entry->kpc != pc) {
         180                 :         PCMETER(kpcmisses++);
         181                 :
         182        23209998 :         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        23209998 :         return name;
         201                 :     }
         202                 :
         203          705587 :     if (entry->kshape != obj->lastProperty()) {
         204                 :         PCMETER(kshapemisses++);
         205          541113 :         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          164474 :     pobj = obj;
         213                 :
         214          164474 :     if (JOF_MODE(cs.format) == JOF_NAME) {
         215          151470 :         uint8_t scopeIndex = entry->scopeIndex;
         216          526984 :         while (scopeIndex > 0) {
         217          224044 :             tmp = pobj->enclosingScope();
         218          224044 :             if (!tmp || !tmp->isNative())
         219               0 :                 break;
         220          224044 :             pobj = tmp;
         221          224044 :             scopeIndex--;
         222                 :         }
         223                 :
         224          151470 :         *objp = pobj;
         225                 :     }
         226                 :
         227          164474 :     uint8_t protoIndex = entry->protoIndex;
         228          342044 :     while (protoIndex > 0) {
         229           13096 :         tmp = pobj->getProto();
         230           13096 :         if (!tmp || !tmp->isNative())
         231               0 :             break;
         232           13096 :         pobj = tmp;
         233           13096 :         protoIndex--;
         234                 :     }
         235                 :
         236          164474 :     if (pobj->lastProperty() == entry->pshape) {
         237                 : #ifdef DEBUG
         238          120518 :         PropertyName *name = GetNameFromBytecode(cx, pc, op, cs);
         239          120518 :         JS_ASSERT(pobj->nativeContains(cx, js_CheckForStringIndex(ATOM_TO_JSID(name))));
         240                 : #endif
         241          120518 :         *pobjp = pobj;
         242          120518 :         return NULL;
         243                 :     }
         244                 :
         245                 :     PCMETER(vcapmisses++);
         246           43956 :     return GetNameFromBytecode(cx, pc, op, cs);
         247                 : }
         248                 :
         249                 : #ifdef DEBUG
         250                 : void
         251           18742 : PropertyCache::assertEmpty()
         252                 : {
         253           18742 :     JS_ASSERT(empty);
         254        76785974 :     for (unsigned i = 0; i < SIZE; i++) {
         255        76767232 :         JS_ASSERT(!table[i].kpc);
         256        76767232 :         JS_ASSERT(!table[i].kshape);
         257        76767232 :         JS_ASSERT(!table[i].pshape);
         258        76767232 :         JS_ASSERT(!table[i].prop);
         259        76767232 :         JS_ASSERT(!table[i].scopeIndex);
         260        76767232 :         JS_ASSERT(!table[i].protoIndex);
         261                 :     }
         262           18742 : }
         263                 : #endif
         264                 :
         265                 : void
         266           52599 : PropertyCache::purge(JSRuntime *rt)
         267                 : {
         268           52599 :     if (empty) {
         269           18742 :         assertEmpty();
         270           18742 :         return;
         271                 :     }
         272                 :
         273           33857 :     PodArrayZero(table);
         274           33857 :     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