LCOV - code coverage report
Current view: directory - js/src - jsatom.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 238 192 80.7 %
Date: 2012-06-02 Functions: 21 18 85.7 %

       1                 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2                 :  *
       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 Mozilla Communicator client code, released
      17                 :  * March 31, 1998.
      18                 :  *
      19                 :  * The Initial Developer of the Original Code is
      20                 :  * Netscape Communications Corporation.
      21                 :  * Portions created by the Initial Developer are Copyright (C) 1998
      22                 :  * the Initial Developer. All Rights Reserved.
      23                 :  *
      24                 :  * Contributor(s):
      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                 : /*
      41                 :  * JS atom table.
      42                 :  */
      43                 : #include <stdlib.h>
      44                 : #include <string.h>
      45                 : 
      46                 : #include "mozilla/RangedPtr.h"
      47                 : #include "mozilla/Util.h"
      48                 : 
      49                 : #include "jstypes.h"
      50                 : #include "jsutil.h"
      51                 : #include "jshash.h"
      52                 : #include "jsprf.h"
      53                 : #include "jsapi.h"
      54                 : #include "jsatom.h"
      55                 : #include "jscntxt.h"
      56                 : #include "jsgc.h"
      57                 : #include "jsgcmark.h"
      58                 : #include "jslock.h"
      59                 : #include "jsnum.h"
      60                 : #include "jsstr.h"
      61                 : #include "jsversion.h"
      62                 : #include "jsxml.h"
      63                 : 
      64                 : #include "frontend/Parser.h"
      65                 : 
      66                 : #include "jsstrinlines.h"
      67                 : #include "jsatominlines.h"
      68                 : #include "jsobjinlines.h"
      69                 : 
      70                 : #include "vm/String-inl.h"
      71                 : 
      72                 : using namespace mozilla;
      73                 : using namespace js;
      74                 : using namespace js::gc;
      75                 : 
      76                 : const size_t JSAtomState::commonAtomsOffset = offsetof(JSAtomState, emptyAtom);
      77                 : const size_t JSAtomState::lazyAtomsOffset = offsetof(JSAtomState, lazy);
      78                 : 
      79                 : /*
      80                 :  * ATOM_HASH assumes that JSHashNumber is 32-bit even on 64-bit systems.
      81                 :  */
      82                 : JS_STATIC_ASSERT(sizeof(JSHashNumber) == 4);
      83                 : JS_STATIC_ASSERT(sizeof(JSAtom *) == JS_BYTES_PER_WORD);
      84                 : 
      85                 : const char *
      86           21994 : js_AtomToPrintableString(JSContext *cx, JSAtom *atom, JSAutoByteString *bytes)
      87                 : {
      88           21994 :     return js_ValueToPrintable(cx, StringValue(atom), bytes);
      89                 : }
      90                 : 
      91                 : #define JS_PROTO(name,code,init) const char js_##name##_str[] = #name;
      92                 : #include "jsproto.tbl"
      93                 : #undef JS_PROTO
      94                 : 
      95                 : /*
      96                 :  * String constants for common atoms defined in JSAtomState starting from
      97                 :  * JSAtomState.emptyAtom until JSAtomState.lazy.
      98                 :  *
      99                 :  * The elements of the array after the first empty string define strings
     100                 :  * corresponding to the two boolean literals, false and true, followed by the
     101                 :  * JSType enumerators from jspubtd.h starting with "undefined" for JSTYPE_VOID
     102                 :  * (which is special-value 2) and continuing as initialized below. The static
     103                 :  * asserts check these relations.
     104                 :  */
     105                 : JS_STATIC_ASSERT(JSTYPE_LIMIT == 8);
     106                 : JS_STATIC_ASSERT(JSTYPE_VOID == 0);
     107                 : 
     108                 : const char *const js_common_atom_names[] = {
     109                 :     "",                         /* emptyAtom                    */
     110                 :     js_false_str,               /* booleanAtoms[0]              */
     111                 :     js_true_str,                /* booleanAtoms[1]              */
     112                 :     js_undefined_str,           /* typeAtoms[JSTYPE_VOID]       */
     113                 :     js_object_str,              /* typeAtoms[JSTYPE_OBJECT]     */
     114                 :     js_function_str,            /* typeAtoms[JSTYPE_FUNCTION]   */
     115                 :     "string",                   /* typeAtoms[JSTYPE_STRING]     */
     116                 :     "number",                   /* typeAtoms[JSTYPE_NUMBER]     */
     117                 :     "boolean",                  /* typeAtoms[JSTYPE_BOOLEAN]    */
     118                 :     js_null_str,                /* typeAtoms[JSTYPE_NULL]       */
     119                 :     "xml",                      /* typeAtoms[JSTYPE_XML]        */
     120                 :     js_null_str,                /* nullAtom                     */
     121                 : 
     122                 : #define JS_PROTO(name,code,init) js_##name##_str,
     123                 : #include "jsproto.tbl"
     124                 : #undef JS_PROTO
     125                 : 
     126                 :     js_anonymous_str,           /* anonymousAtom                */
     127                 :     js_apply_str,               /* applyAtom                    */
     128                 :     js_arguments_str,           /* argumentsAtom                */
     129                 :     js_arity_str,               /* arityAtom                    */
     130                 :     js_BYTES_PER_ELEMENT_str,   /* BYTES_PER_ELEMENTAtom        */
     131                 :     js_call_str,                /* callAtom                     */
     132                 :     js_callee_str,              /* calleeAtom                   */
     133                 :     js_caller_str,              /* callerAtom                   */
     134                 :     js_class_prototype_str,     /* classPrototypeAtom           */
     135                 :     js_constructor_str,         /* constructorAtom              */
     136                 :     js_each_str,                /* eachAtom                     */
     137                 :     js_eval_str,                /* evalAtom                     */
     138                 :     js_fileName_str,            /* fileNameAtom                 */
     139                 :     js_get_str,                 /* getAtom                      */
     140                 :     js_global_str,              /* globalAtom                   */
     141                 :     js_ignoreCase_str,          /* ignoreCaseAtom               */
     142                 :     js_index_str,               /* indexAtom                    */
     143                 :     js_input_str,               /* inputAtom                    */
     144                 :     "toISOString",              /* toISOStringAtom              */
     145                 :     js_iterator_str,            /* iteratorAtom                 */
     146                 :     js_join_str,                /* joinAtom                     */
     147                 :     js_lastIndex_str,           /* lastIndexAtom                */
     148                 :     js_length_str,              /* lengthAtom                   */
     149                 :     js_lineNumber_str,          /* lineNumberAtom               */
     150                 :     js_message_str,             /* messageAtom                  */
     151                 :     js_multiline_str,           /* multilineAtom                */
     152                 :     js_name_str,                /* nameAtom                     */
     153                 :     js_next_str,                /* nextAtom                     */
     154                 :     js_noSuchMethod_str,        /* noSuchMethodAtom             */
     155                 :     "[object Null]",            /* objectNullAtom               */
     156                 :     "[object Undefined]",       /* objectUndefinedAtom          */
     157                 :     "of",                       /* ofAtom                       */
     158                 :     js_proto_str,               /* protoAtom                    */
     159                 :     js_set_str,                 /* setAtom                      */
     160                 :     js_source_str,              /* sourceAtom                   */
     161                 :     js_stack_str,               /* stackAtom                    */
     162                 :     js_sticky_str,              /* stickyAtom                   */
     163                 :     js_toGMTString_str,         /* toGMTStringAtom              */
     164                 :     js_toLocaleString_str,      /* toLocaleStringAtom           */
     165                 :     js_toSource_str,            /* toSourceAtom                 */
     166                 :     js_toString_str,            /* toStringAtom                 */
     167                 :     js_toUTCString_str,         /* toUTCStringAtom              */
     168                 :     js_valueOf_str,             /* valueOfAtom                  */
     169                 :     js_toJSON_str,              /* toJSONAtom                   */
     170                 :     "(void 0)",                 /* void0Atom                    */
     171                 :     js_enumerable_str,          /* enumerableAtom               */
     172                 :     js_configurable_str,        /* configurableAtom             */
     173                 :     js_writable_str,            /* writableAtom                 */
     174                 :     js_value_str,               /* valueAtom                    */
     175                 :     js_test_str,                /* testAtom                     */
     176                 :     "use strict",               /* useStrictAtom                */
     177                 :     "loc",                      /* locAtom                      */
     178                 :     "line",                     /* lineAtom                     */
     179                 :     "Infinity",                 /* InfinityAtom                 */
     180                 :     "NaN",                      /* NaNAtom                      */
     181                 :     "builder",                  /* builderAtom                  */
     182                 : 
     183                 : #if JS_HAS_XML_SUPPORT
     184                 :     js_etago_str,               /* etagoAtom                    */
     185                 :     js_namespace_str,           /* namespaceAtom                */
     186                 :     js_ptagc_str,               /* ptagcAtom                    */
     187                 :     js_qualifier_str,           /* qualifierAtom                */
     188                 :     js_space_str,               /* spaceAtom                    */
     189                 :     js_stago_str,               /* stagoAtom                    */
     190                 :     js_star_str,                /* starAtom                     */
     191                 :     js_starQualifier_str,       /* starQualifierAtom            */
     192                 :     js_tagc_str,                /* tagcAtom                     */
     193                 :     js_xml_str,                 /* xmlAtom                      */
     194                 :     "@mozilla.org/js/function", /* functionNamespaceURIAtom     */
     195                 : #endif
     196                 : 
     197                 :     "Proxy",                    /* ProxyAtom                    */
     198                 : 
     199                 :     "getOwnPropertyDescriptor", /* getOwnPropertyDescriptorAtom */
     200                 :     "getPropertyDescriptor",    /* getPropertyDescriptorAtom    */
     201                 :     "defineProperty",           /* definePropertyAtom           */
     202                 :     "delete",                   /* deleteAtom                   */
     203                 :     "getOwnPropertyNames",      /* getOwnPropertyNames          */
     204                 :     "enumerate",                /* enumerateAtom                */
     205                 :     "fix",                      /* fixAtom                      */
     206                 : 
     207                 :     "has",                      /* hasAtom                      */
     208                 :     "hasOwn",                   /* hasOwnAtom                   */
     209                 :     "keys",                     /* keysAtom                     */
     210                 :     "iterate",                  /* iterateAtom                  */
     211                 : 
     212                 :     "WeakMap",                  /* WeakMapAtom                  */
     213                 : 
     214                 :     "byteLength",               /* byteLengthAtom               */
     215                 : 
     216                 :     "return",                   /* returnAtom                   */
     217                 :     "throw"                     /* throwAtom                    */
     218                 : };
     219                 : 
     220                 : void
     221               0 : JSAtomState::checkStaticInvariants()
     222                 : {
     223                 :     /*
     224                 :      * Start and limit offsets for atom pointers in JSAtomState must be aligned
     225                 :      * on the word boundary.
     226                 :      */
     227                 :     JS_STATIC_ASSERT(commonAtomsOffset % sizeof(JSAtom *) == 0);
     228                 :     JS_STATIC_ASSERT(sizeof(*this) % sizeof(JSAtom *) == 0);
     229                 : 
     230                 :     /*
     231                 :      * JS_BOOLEAN_STR and JS_TYPE_STR assume that boolean names starts from the
     232                 :      * index 1 and type name starts from the index 1+2 atoms in JSAtomState.
     233                 :      */
     234                 :     JS_STATIC_ASSERT(1 * sizeof(JSAtom *) ==
     235                 :                      offsetof(JSAtomState, booleanAtoms) - commonAtomsOffset);
     236                 :     JS_STATIC_ASSERT((1 + 2) * sizeof(JSAtom *) ==
     237                 :                      offsetof(JSAtomState, typeAtoms) - commonAtomsOffset);
     238                 : 
     239                 :     JS_STATIC_ASSERT(JS_ARRAY_LENGTH(js_common_atom_names) * sizeof(JSAtom *) ==
     240                 :                      lazyAtomsOffset - commonAtomsOffset);
     241               0 : }
     242                 : 
     243                 : /*
     244                 :  * Interpreter macros called by the trace recorder assume common atom indexes
     245                 :  * fit in one byte of immediate operand.
     246                 :  */
     247                 : JS_STATIC_ASSERT(JS_ARRAY_LENGTH(js_common_atom_names) < 256);
     248                 : 
     249                 : const size_t js_common_atom_count = JS_ARRAY_LENGTH(js_common_atom_names);
     250                 : 
     251                 : const char js_anonymous_str[]       = "anonymous";
     252                 : const char js_apply_str[]           = "apply";
     253                 : const char js_arguments_str[]       = "arguments";
     254                 : const char js_arity_str[]           = "arity";
     255                 : const char js_BYTES_PER_ELEMENT_str[] = "BYTES_PER_ELEMENT";
     256                 : const char js_call_str[]            = "call";
     257                 : const char js_callee_str[]          = "callee";
     258                 : const char js_caller_str[]          = "caller";
     259                 : const char js_class_prototype_str[] = "prototype";
     260                 : const char js_constructor_str[]     = "constructor";
     261                 : const char js_each_str[]            = "each";
     262                 : const char js_eval_str[]            = "eval";
     263                 : const char js_fileName_str[]        = "fileName";
     264                 : const char js_get_str[]             = "get";
     265                 : const char js_getter_str[]          = "getter";
     266                 : const char js_global_str[]          = "global";
     267                 : const char js_ignoreCase_str[]      = "ignoreCase";
     268                 : const char js_index_str[]           = "index";
     269                 : const char js_input_str[]           = "input";
     270                 : const char js_iterator_str[]        = "__iterator__";
     271                 : const char js_join_str[]            = "join";
     272                 : const char js_lastIndex_str[]       = "lastIndex";
     273                 : const char js_length_str[]          = "length";
     274                 : const char js_lineNumber_str[]      = "lineNumber";
     275                 : const char js_message_str[]         = "message";
     276                 : const char js_multiline_str[]       = "multiline";
     277                 : const char js_name_str[]            = "name";
     278                 : const char js_next_str[]            = "next";
     279                 : const char js_noSuchMethod_str[]    = "__noSuchMethod__";
     280                 : const char js_object_str[]          = "object";
     281                 : const char js_proto_str[]           = "__proto__";
     282                 : const char js_setter_str[]          = "setter";
     283                 : const char js_set_str[]             = "set";
     284                 : const char js_source_str[]          = "source";
     285                 : const char js_stack_str[]           = "stack";
     286                 : const char js_sticky_str[]          = "sticky";
     287                 : const char js_toGMTString_str[]     = "toGMTString";
     288                 : const char js_toLocaleString_str[]  = "toLocaleString";
     289                 : const char js_toSource_str[]        = "toSource";
     290                 : const char js_toString_str[]        = "toString";
     291                 : const char js_toUTCString_str[]     = "toUTCString";
     292                 : const char js_undefined_str[]       = "undefined";
     293                 : const char js_valueOf_str[]         = "valueOf";
     294                 : const char js_toJSON_str[]          = "toJSON";
     295                 : const char js_enumerable_str[]      = "enumerable";
     296                 : const char js_configurable_str[]    = "configurable";
     297                 : const char js_writable_str[]        = "writable";
     298                 : const char js_value_str[]           = "value";
     299                 : const char js_test_str[]            = "test";
     300                 : 
     301                 : #if JS_HAS_XML_SUPPORT
     302                 : const char js_etago_str[]           = "</";
     303                 : const char js_namespace_str[]       = "namespace";
     304                 : const char js_ptagc_str[]           = "/>";
     305                 : const char js_qualifier_str[]       = "::";
     306                 : const char js_space_str[]           = " ";
     307                 : const char js_stago_str[]           = "<";
     308                 : const char js_star_str[]            = "*";
     309                 : const char js_starQualifier_str[]   = "*::";
     310                 : const char js_tagc_str[]            = ">";
     311                 : const char js_xml_str[]             = "xml";
     312                 : #endif
     313                 : 
     314                 : #if JS_HAS_GENERATORS
     315                 : const char js_close_str[]           = "close";
     316                 : const char js_send_str[]            = "send";
     317                 : #endif
     318                 : 
     319                 : /*
     320                 :  * For a browser build from 2007-08-09 after the browser starts up there are
     321                 :  * just 55 double atoms, but over 15000 string atoms. Not to penalize more
     322                 :  * economical embeddings allocating too much memory initially we initialize
     323                 :  * atomized strings with just 1K entries.
     324                 :  */
     325                 : #define JS_STRING_HASH_COUNT   1024
     326                 : 
     327                 : JSBool
     328           19910 : js_InitAtomState(JSRuntime *rt)
     329                 : {
     330           19910 :     JSAtomState *state = &rt->atomState;
     331                 : 
     332           19910 :     JS_ASSERT(!state->atoms.initialized());
     333           19910 :     if (!state->atoms.init(JS_STRING_HASH_COUNT))
     334               0 :         return false;
     335                 : 
     336           19910 :     JS_ASSERT(state->atoms.initialized());
     337           19910 :     return true;
     338                 : }
     339                 : 
     340                 : void
     341           19908 : js_FinishAtomState(JSRuntime *rt)
     342                 : {
     343           19908 :     JSAtomState *state = &rt->atomState;
     344                 : 
     345           19908 :     if (!state->atoms.initialized()) {
     346                 :         /*
     347                 :          * We are called with uninitialized state when JS_NewRuntime fails and
     348                 :          * calls JS_DestroyRuntime on a partially initialized runtime.
     349                 :          */
     350               0 :         return;
     351                 :     }
     352                 : 
     353         3678177 :     for (AtomSet::Range r = state->atoms.all(); !r.empty(); r.popFront())
     354         3658269 :         r.front().asPtr()->finalize(rt);
     355                 : }
     356                 : 
     357                 : bool
     358           19910 : js_InitCommonAtoms(JSContext *cx)
     359                 : {
     360           19910 :     JSAtomState *state = &cx->runtime->atomState;
     361           19910 :     JSAtom **atoms = state->commonAtomsStart();
     362         2687850 :     for (size_t i = 0; i < ArrayLength(js_common_atom_names); i++, atoms++) {
     363                 :         JSAtom *atom = js_Atomize(cx, js_common_atom_names[i], strlen(js_common_atom_names[i]),
     364         2667940 :                                   InternAtom);
     365         2667940 :         if (!atom)
     366               0 :             return false;
     367         2667940 :         *atoms = atom->asPropertyName();
     368                 :     }
     369                 : 
     370           19910 :     state->clearLazyAtoms();
     371           19910 :     cx->runtime->emptyString = state->emptyAtom;
     372           19910 :     return true;
     373                 : }
     374                 : 
     375                 : void
     376           19908 : js_FinishCommonAtoms(JSContext *cx)
     377                 : {
     378           19908 :     cx->runtime->emptyString = NULL;
     379           19908 :     cx->runtime->atomState.junkAtoms();
     380           19908 : }
     381                 : 
     382                 : void
     383           54466 : js_TraceAtomState(JSTracer *trc)
     384                 : {
     385           54466 :     JSRuntime *rt = trc->runtime;
     386           54466 :     JSAtomState *state = &rt->atomState;
     387                 : 
     388           54466 :     if (rt->gcKeepAtoms) {
     389         5465720 :         for (AtomSet::Range r = state->atoms.all(); !r.empty(); r.popFront()) {
     390         5456668 :             JSAtom *tmp = r.front().asPtr();
     391         5456668 :             MarkStringRoot(trc, &tmp, "locked_atom");
     392         5456668 :             JS_ASSERT(tmp == r.front().asPtr());
     393                 :         }
     394                 :     } else {
     395        95187791 :         for (AtomSet::Range r = state->atoms.all(); !r.empty(); r.popFront()) {
     396        95142377 :             AtomStateEntry entry = r.front();
     397        95142377 :             if (!entry.isTagged())
     398        79872540 :                 continue;
     399                 : 
     400        15269837 :             JSAtom *tmp = entry.asPtr();
     401        15269837 :             MarkStringRoot(trc, &tmp, "interned_atom");
     402        15269837 :             JS_ASSERT(tmp == entry.asPtr());
     403                 :         }
     404                 :     }
     405           54466 : }
     406                 : 
     407                 : void
     408           51092 : js_SweepAtomState(JSRuntime *rt)
     409                 : {
     410           51092 :     JSAtomState *state = &rt->atomState;
     411                 : 
     412        98722146 :     for (AtomSet::Enum e(state->atoms); !e.empty(); e.popFront()) {
     413        98671054 :         AtomStateEntry entry = e.front();
     414                 : 
     415        98671054 :         if (entry.isTagged()) {
     416                 :             /* Pinned or interned key cannot be finalized. */
     417        16118769 :             JS_ASSERT(!IsAboutToBeFinalized(entry.asPtr()));
     418        16118769 :             continue;
     419                 :         }
     420                 : 
     421        82552285 :         if (IsAboutToBeFinalized(entry.asPtr()))
     422        15377535 :             e.removeFront();
     423                 :     }
     424           51092 : }
     425                 : 
     426                 : bool
     427         4237985 : AtomIsInterned(JSContext *cx, JSAtom *atom)
     428                 : {
     429                 :     /* We treat static strings as interned because they're never collected. */
     430         4237985 :     if (StaticStrings::isStatic(atom))
     431            6752 :         return true;
     432                 : 
     433         4231233 :     AtomSet::Ptr p = cx->runtime->atomState.atoms.lookup(atom);
     434         4231233 :     if (!p)
     435               0 :         return false;
     436                 : 
     437         4231233 :     return p->isTagged();
     438                 : }
     439                 : 
     440                 : enum OwnCharsBehavior
     441                 : {
     442                 :     CopyChars, /* in other words, do not take ownership */
     443                 :     TakeCharOwnership
     444                 : };
     445                 : 
     446                 : /*
     447                 :  * Callers passing OwnChars have freshly allocated *pchars and thus this
     448                 :  * memory can be used as a new JSAtom's buffer without copying. When this flag
     449                 :  * is set, the contract is that callers will free *pchars iff *pchars == NULL.
     450                 :  */
     451                 : JS_ALWAYS_INLINE
     452                 : static JSAtom *
     453        77119232 : AtomizeInline(JSContext *cx, const jschar **pchars, size_t length,
     454                 :               InternBehavior ib, OwnCharsBehavior ocb = CopyChars)
     455                 : {
     456        77119232 :     const jschar *chars = *pchars;
     457                 : 
     458        77119232 :     if (JSAtom *s = cx->runtime->staticStrings.lookup(chars, length))
     459         4646743 :         return s;
     460                 : 
     461        72472489 :     AtomSet &atoms = cx->runtime->atomState.atoms;
     462        72472489 :     AtomSet::AddPtr p = atoms.lookupForAdd(AtomHasher::Lookup(chars, length));
     463                 : 
     464        72472489 :     if (p) {
     465        53435395 :         JSAtom *atom = p->asPtr();
     466        53435395 :         p->setTagged(bool(ib));
     467        53435395 :         return atom;
     468                 :     }
     469                 : 
     470        38074188 :     SwitchToCompartment sc(cx, cx->runtime->atomsCompartment);
     471                 : 
     472                 :     JSFixedString *key;
     473                 : 
     474        19037094 :     if (ocb == TakeCharOwnership) {
     475         1273643 :         key = js_NewString(cx, const_cast<jschar *>(chars), length);
     476         1273643 :         if (!key)
     477               0 :             return NULL;
     478         1273643 :         *pchars = NULL; /* Called should not free *pchars. */
     479                 :     } else {
     480        17763451 :         JS_ASSERT(ocb == CopyChars);
     481        17763451 :         key = js_NewStringCopyN(cx, chars, length);
     482        17763451 :         if (!key)
     483               0 :             return NULL;
     484                 :     }
     485                 : 
     486                 :     /*
     487                 :      * We have to relookup the key as the last ditch GC invoked from the
     488                 :      * string allocation or OOM handling unlocks the atomsCompartment.
     489                 :      *
     490                 :      * N.B. this avoids recomputing the hash but still has a potential
     491                 :      * (# collisions * # chars) comparison cost in the case of a hash
     492                 :      * collision!
     493                 :      */
     494        19037094 :     AtomHasher::Lookup lookup(chars, length);
     495        19037094 :     if (!atoms.relookupOrAdd(p, lookup, AtomStateEntry((JSAtom *) key, bool(ib)))) {
     496               0 :         JS_ReportOutOfMemory(cx); /* SystemAllocPolicy does not report */
     497               0 :         return NULL;
     498                 :     }
     499                 : 
     500        19037094 :     return key->morphAtomizedStringIntoAtom();
     501                 : }
     502                 : 
     503                 : static JSAtom *
     504        38723396 : Atomize(JSContext *cx, const jschar **pchars, size_t length,
     505                 :         InternBehavior ib, OwnCharsBehavior ocb = CopyChars)
     506                 : {
     507        38723396 :     return AtomizeInline(cx, pchars, length, ib, ocb);
     508                 : }
     509                 : 
     510                 : JSAtom *
     511         5315630 : js_AtomizeString(JSContext *cx, JSString *str, InternBehavior ib)
     512                 : {
     513         5315630 :     if (str->isAtom()) {
     514         1267657 :         JSAtom &atom = str->asAtom();
     515                 :         /* N.B. static atoms are effectively always interned. */
     516         1267657 :         if (ib != InternAtom || js::StaticStrings::isStatic(&atom))
     517         1267656 :             return &atom;
     518                 : 
     519               1 :         AtomSet &atoms = cx->runtime->atomState.atoms;
     520               1 :         AtomSet::Ptr p = atoms.lookup(AtomHasher::Lookup(&atom));
     521               1 :         JS_ASSERT(p); /* Non-static atom must exist in atom state set. */
     522               1 :         JS_ASSERT(p->asPtr() == &atom);
     523               1 :         JS_ASSERT(ib == InternAtom);
     524               1 :         p->setTagged(bool(ib));
     525               1 :         return &atom;
     526                 :     }
     527                 : 
     528         4047973 :     if (str->isAtom())
     529               0 :         return &str->asAtom();
     530                 : 
     531         4047973 :     size_t length = str->length();
     532         4047973 :     const jschar *chars = str->getChars(cx);
     533         4047973 :     if (!chars)
     534               0 :         return NULL;
     535                 : 
     536         4047973 :     JS_ASSERT(length <= JSString::MAX_LENGTH);
     537         4047973 :     return Atomize(cx, &chars, length, ib);
     538                 : }
     539                 : 
     540                 : JSAtom *
     541        34675423 : js_Atomize(JSContext *cx, const char *bytes, size_t length, InternBehavior ib, FlationCoding fc)
     542                 : {
     543        69350846 :     CHECK_REQUEST(cx);
     544                 : 
     545        34675423 :     if (!JSString::validateLength(cx, length))
     546               0 :         return NULL;
     547                 : 
     548                 :     /*
     549                 :      * Avoiding the malloc in InflateString on shorter strings saves us
     550                 :      * over 20,000 malloc calls on mozilla browser startup. This compares to
     551                 :      * only 131 calls where the string is longer than a 31 char (net) buffer.
     552                 :      * The vast majority of atomized strings are already in the hashtable. So
     553                 :      * js_AtomizeString rarely has to copy the temp string we make.
     554                 :      */
     555                 :     static const unsigned ATOMIZE_BUF_MAX = 32;
     556                 :     jschar inflated[ATOMIZE_BUF_MAX];
     557        34675423 :     size_t inflatedLength = ATOMIZE_BUF_MAX - 1;
     558                 : 
     559                 :     const jschar *chars;
     560        34675423 :     OwnCharsBehavior ocb = CopyChars;
     561        34675423 :     if (length < ATOMIZE_BUF_MAX) {
     562        33091883 :         if (fc == CESU8Encoding)
     563               0 :             InflateUTF8StringToBuffer(cx, bytes, length, inflated, &inflatedLength, fc);
     564                 :         else
     565        33091883 :             InflateStringToBuffer(cx, bytes, length, inflated, &inflatedLength);
     566        33091883 :         inflated[inflatedLength] = 0;
     567        33091883 :         chars = inflated;
     568                 :     } else {
     569         1583540 :         inflatedLength = length;
     570         1583540 :         chars = InflateString(cx, bytes, &inflatedLength, fc);
     571         1583540 :         if (!chars)
     572               0 :             return NULL;
     573         1583540 :         ocb = TakeCharOwnership;
     574                 :     }
     575                 : 
     576        34675423 :     JSAtom *atom = Atomize(cx, &chars, inflatedLength, ib, ocb);
     577        34675423 :     if (ocb == TakeCharOwnership && chars)
     578          309897 :         cx->free_((void *)chars);
     579        34675423 :     return atom;
     580                 : }
     581                 : 
     582                 : JSAtom *
     583        38395836 : js_AtomizeChars(JSContext *cx, const jschar *chars, size_t length, InternBehavior ib)
     584                 : {
     585        76791672 :     CHECK_REQUEST(cx);
     586                 : 
     587        38395836 :     if (!JSString::validateLength(cx, length))
     588               0 :         return NULL;
     589                 : 
     590        38395836 :     return AtomizeInline(cx, &chars, length, ib);
     591                 : }
     592                 : 
     593                 : JSAtom *
     594               0 : js_GetExistingStringAtom(JSContext *cx, const jschar *chars, size_t length)
     595                 : {
     596               0 :     if (JSAtom *atom = cx->runtime->staticStrings.lookup(chars, length))
     597               0 :         return atom;
     598               0 :     if (AtomSet::Ptr p = cx->runtime->atomState.atoms.lookup(AtomHasher::Lookup(chars, length)))
     599               0 :         return p->asPtr();
     600               0 :     return NULL;
     601                 : }
     602                 : 
     603                 : #ifdef DEBUG
     604                 : JS_FRIEND_API(void)
     605               0 : js_DumpAtoms(JSContext *cx, FILE *fp)
     606                 : {
     607               0 :     JSAtomState *state = &cx->runtime->atomState;
     608                 : 
     609               0 :     fprintf(fp, "atoms table contents:\n");
     610               0 :     unsigned number = 0;
     611               0 :     for (AtomSet::Range r = state->atoms.all(); !r.empty(); r.popFront()) {
     612               0 :         AtomStateEntry entry = r.front();
     613               0 :         fprintf(fp, "%3u ", number++);
     614               0 :         JSAtom *key = entry.asPtr();
     615               0 :         FileEscapedString(fp, key, '"');
     616               0 :         if (entry.isTagged())
     617               0 :             fputs(" interned", fp);
     618               0 :         putc('\n', fp);
     619                 :     }
     620               0 :     putc('\n', fp);
     621               0 : }
     622                 : #endif
     623                 : 
     624                 : #if JS_BITS_PER_WORD == 32
     625                 : # define TEMP_SIZE_START_LOG2   5
     626                 : #else
     627                 : # define TEMP_SIZE_START_LOG2   6
     628                 : #endif
     629                 : #define TEMP_SIZE_LIMIT_LOG2    (TEMP_SIZE_START_LOG2 + NUM_TEMP_FREELISTS)
     630                 : 
     631                 : #define TEMP_SIZE_START         JS_BIT(TEMP_SIZE_START_LOG2)
     632                 : #define TEMP_SIZE_LIMIT         JS_BIT(TEMP_SIZE_LIMIT_LOG2)
     633                 : 
     634                 : JS_STATIC_ASSERT(TEMP_SIZE_START >= sizeof(JSHashTable));
     635                 : 
     636                 : void
     637         1109121 : js_InitAtomMap(JSContext *cx, AtomIndexMap *indices, JSAtom **atoms)
     638                 : {
     639         1109121 :     if (indices->isMap()) {
     640                 :         typedef AtomIndexMap::WordMap WordMap;
     641           73192 :         const WordMap &wm = indices->asMap();
     642         6927467 :         for (WordMap::Range r = wm.all(); !r.empty(); r.popFront()) {
     643         6854275 :             JSAtom *atom = r.front().key;
     644         6854275 :             jsatomid index = r.front().value;
     645         6854275 :             JS_ASSERT(index < indices->count());
     646         6854275 :             atoms[index] = atom;
     647                 :         }
     648                 :     } else {
     649         7008566 :         for (const AtomIndexMap::InlineElem *it = indices->asInline(), *end = indices->inlineEnd();
     650                 :              it != end; ++it) {
     651         5972637 :             JSAtom *atom = it->key;
     652         5972637 :             if (!atom)
     653               0 :                 continue;
     654         5972637 :             JS_ASSERT(it->value < indices->count());
     655         5972637 :             atoms[it->value] = atom;
     656                 :         }
     657                 :     }
     658         1109121 : }
     659                 : 
     660                 : namespace js {
     661                 : 
     662                 : bool
     663             233 : IndexToIdSlow(JSContext *cx, uint32_t index, jsid *idp)
     664                 : {
     665             233 :     JS_ASSERT(index > JSID_INT_MAX);
     666                 : 
     667                 :     jschar buf[UINT32_CHAR_BUFFER_LENGTH];
     668             233 :     RangedPtr<jschar> end(ArrayEnd(buf), buf, ArrayEnd(buf));
     669             233 :     RangedPtr<jschar> start = BackfillIndexInCharBuffer(index, end);
     670                 : 
     671             233 :     JSAtom *atom = js_AtomizeChars(cx, start.get(), end - start);
     672             233 :     if (!atom)
     673               0 :         return false;
     674                 : 
     675             233 :     *idp = ATOM_TO_JSID(atom);
     676             233 :     JS_ASSERT(js_CheckForStringIndex(*idp) == *idp);
     677             233 :     return true;
     678                 : }
     679                 : 
     680                 : } /* namespace js */
     681                 : 
     682                 : /* JSBOXEDWORD_INT_MAX as a string */
     683                 : #define JSBOXEDWORD_INT_MAX_STRING "1073741823"
     684                 : 
     685                 : /*
     686                 :  * Convert string indexes that convert to int jsvals as ints to save memory.
     687                 :  * Care must be taken to use this macro every time a property name is used, or
     688                 :  * else double-sets, incorrect property cache misses, or other mistakes could
     689                 :  * occur.
     690                 :  */
     691                 : jsid
     692       399935245 : js_CheckForStringIndex(jsid id)
     693                 : {
     694       399935245 :     if (!JSID_IS_ATOM(id))
     695       118001644 :         return id;
     696                 : 
     697       281933601 :     JSAtom *atom = JSID_TO_ATOM(id);
     698       281933601 :     const jschar *s = atom->chars();
     699       281933602 :     jschar ch = *s;
     700                 : 
     701       281933602 :     JSBool negative = (ch == '-');
     702       281933602 :     if (negative)
     703           28352 :         ch = *++s;
     704                 : 
     705       281933602 :     if (!JS7_ISDEC(ch))
     706       279875898 :         return id;
     707                 : 
     708         2057704 :     size_t n = atom->length() - negative;
     709         2057704 :     if (n > sizeof(JSBOXEDWORD_INT_MAX_STRING) - 1)
     710            3471 :         return id;
     711                 : 
     712         2054233 :     const jschar *cp = s;
     713         2054233 :     const jschar *end = s + n;
     714                 : 
     715         2054233 :     uint32_t index = JS7_UNDEC(*cp++);
     716         2054233 :     uint32_t oldIndex = 0;
     717         2054233 :     uint32_t c = 0;
     718                 : 
     719         2054233 :     if (index != 0) {
     720         4320279 :         while (JS7_ISDEC(*cp)) {
     721          513489 :             oldIndex = index;
     722          513489 :             c = JS7_UNDEC(*cp);
     723          513489 :             index = 10 * index + c;
     724          513489 :             cp++;
     725                 :         }
     726                 :     }
     727                 : 
     728                 :     /*
     729                 :      * Non-integer indexes can't be represented as integers.  Also, distinguish
     730                 :      * index "-0" from "0", because JSBOXEDWORD_INT cannot.
     731                 :      */
     732         2054233 :     if (cp != end || (negative && index == 0))
     733          887041 :         return id;
     734                 : 
     735         1167192 :     if (negative) {
     736            3321 :         if (oldIndex < -(JSID_INT_MIN / 10) ||
     737                 :             (oldIndex == -(JSID_INT_MIN / 10) && c <= (-JSID_INT_MIN % 10)))
     738                 :         {
     739            2574 :             id = INT_TO_JSID(-int32_t(index));
     740                 :         }
     741                 :     } else {
     742         1163871 :         if (oldIndex < JSID_INT_MAX / 10 ||
     743                 :             (oldIndex == JSID_INT_MAX / 10 && c <= (JSID_INT_MAX % 10)))
     744                 :         {
     745         1162936 :             id = INT_TO_JSID(int32_t(index));
     746                 :         }
     747                 :     }
     748                 : 
     749         1167192 :     return id;
     750                 : }
     751                 : 
     752                 : #if JS_HAS_XML_SUPPORT
     753                 : bool
     754               6 : js_InternNonIntElementIdSlow(JSContext *cx, JSObject *obj, const Value &idval,
     755                 :                              jsid *idp)
     756                 : {
     757               6 :     JS_ASSERT(idval.isObject());
     758               6 :     if (obj->isXML()) {
     759               0 :         *idp = OBJECT_TO_JSID(&idval.toObject());
     760               0 :         return true;
     761                 :     }
     762                 : 
     763               6 :     if (js_GetLocalNameFromFunctionQName(&idval.toObject(), idp, cx))
     764               0 :         return true;
     765                 : 
     766               6 :     return js_ValueToStringId(cx, idval, idp);
     767                 : }
     768                 : 
     769                 : bool
     770            3479 : js_InternNonIntElementIdSlow(JSContext *cx, JSObject *obj, const Value &idval,
     771                 :                              jsid *idp, Value *vp)
     772                 : {
     773            3479 :     JS_ASSERT(idval.isObject());
     774            3479 :     if (obj->isXML()) {
     775               0 :         JSObject &idobj = idval.toObject();
     776               0 :         *idp = OBJECT_TO_JSID(&idobj);
     777               0 :         vp->setObject(idobj);
     778               0 :         return true;
     779                 :     }
     780                 : 
     781            3479 :     if (js_GetLocalNameFromFunctionQName(&idval.toObject(), idp, cx)) {
     782               9 :         *vp = IdToValue(*idp);
     783               9 :         return true;
     784                 :     }
     785                 : 
     786            3470 :     if (js_ValueToStringId(cx, idval, idp)) {
     787            3470 :         vp->setString(JSID_TO_STRING(*idp));
     788            3470 :         return true;
     789                 :     }
     790               0 :     return false;
     791                 : }
     792                 : #endif

Generated by: LCOV version 1.7