home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / js / src / jsatom.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  16.4 KB  |  650 lines

  1. /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19. /*
  20.  * JS atom table.
  21.  */
  22. #include <stddef.h>
  23. #include <stdlib.h>
  24. #include <string.h>
  25. #include "prtypes.h"
  26. #include "prlog.h"
  27. #ifndef NSPR20
  28. #include "prhash.h"
  29. #else
  30. #include "plhash.h"
  31. #endif
  32. #include "jsapi.h"
  33. #include "jsatom.h"
  34. #include "jscntxt.h"
  35. #include "jsgc.h"
  36. #include "jslock.h"
  37. #include "jsnum.h"
  38. #include "jsopcode.h"
  39. #include "jsstr.h"
  40.  
  41. /*
  42.  * Keep this in sync with jspubtd.h -- an assertion below will insist that
  43.  * its length match the JSType enum's JSTYPE_LIMIT limit value.
  44.  */
  45. char *js_type_str[] = {
  46.     "undefined",
  47.     "object",
  48.     "function",
  49.     "string",
  50.     "number",
  51.     "boolean",
  52. };
  53.  
  54. char   js_Array_str[]             = "Array";
  55. char   js_Object_str[]            = "Object";
  56. char   js_anonymous_str[]         = "anonymous";
  57. char   js_assign_str[]            = "assign";
  58. char   js_class_prototype_str[]   = "prototype";
  59. char   js_constructor_str[]       = "constructor";
  60. char   js_count_str[]             = "__count__";
  61. char   js_eval_str[]              = "eval";
  62. char   js_index_str[]             = "index";
  63. char   js_input_str[]             = "input";
  64. char   js_length_str[]            = "length";
  65. char   js_parent_str[]            = "__parent__";
  66. char   js_proto_str[]             = "__proto__";
  67. char   js_toString_str[]          = "toString";
  68. char   js_valueOf_str[]           = "valueOf";
  69.  
  70. #define HASH_OBJECT(o)  ((PRHashNumber)(o) >> JSVAL_TAGBITS)
  71. #define HASH_INT(i)     ((PRHashNumber)(i))
  72. #define HASH_DOUBLE(dp) ((PRHashNumber)(((uint32*)(dp))[0] ^ ((uint32*)(dp))[1]))
  73. #define HASH_BOOLEAN(b) ((PRHashNumber)(b))
  74.  
  75. PR_STATIC_CALLBACK(PRHashNumber)
  76. js_hash_atom_key(const void *key)
  77. {
  78.     jsval v;
  79.     jsdouble *dp;
  80.  
  81.     /* Order JSVAL_IS_* tests by likelihood of success. */
  82.     v = (jsval)key;
  83.     if (JSVAL_IS_STRING(v))
  84.     return js_HashString(JSVAL_TO_STRING(v));
  85.     if (JSVAL_IS_INT(v))
  86.     return HASH_INT(JSVAL_TO_INT(v));
  87.     if (JSVAL_IS_DOUBLE(v)) {
  88.     dp = JSVAL_TO_DOUBLE(v);
  89.     return HASH_DOUBLE(dp);
  90.     }
  91.     if (JSVAL_IS_OBJECT(v))
  92.     return HASH_OBJECT(JSVAL_TO_OBJECT(v));
  93.     if (JSVAL_IS_BOOLEAN(v))
  94.     return HASH_BOOLEAN(JSVAL_TO_BOOLEAN(v));
  95.     return (PRHashNumber)v;
  96. }
  97.  
  98. PR_STATIC_CALLBACK(intN)
  99. js_compare_atom_keys(const void *k1, const void *k2)
  100. {
  101.     jsval v1, v2;
  102.  
  103.     v1 = (jsval)k1, v2 = (jsval)k2;
  104.     if (JSVAL_IS_STRING(v1) && JSVAL_IS_STRING(v2))
  105.     return !js_CompareStrings(JSVAL_TO_STRING(v1), JSVAL_TO_STRING(v2));
  106.     if (JSVAL_IS_DOUBLE(v1) && JSVAL_IS_DOUBLE(v2))
  107.     return *JSVAL_TO_DOUBLE(v1) == *JSVAL_TO_DOUBLE(v2);
  108.     return v1 == v2;
  109. }
  110.  
  111. PR_STATIC_CALLBACK(int)
  112. js_compare_stub(const void *v1, const void *v2)
  113. {
  114.     return 1;
  115. }
  116.  
  117. PR_STATIC_CALLBACK(void *)
  118. js_alloc_atom_space(void *priv, size_t size)
  119. {
  120.     return malloc(size);
  121. }
  122.  
  123. PR_STATIC_CALLBACK(void)
  124. js_free_atom_space(void *priv, void *item)
  125. {
  126.     free(item);
  127. }
  128.  
  129. PR_STATIC_CALLBACK(PRHashEntry *)
  130. js_alloc_atom(void *priv, const void *key)
  131. {
  132.     JSAtomState *state = priv;
  133.     JSAtom *atom;
  134.  
  135.     atom = malloc(sizeof(JSAtom));
  136.     if (!atom)
  137.     return NULL;
  138.     atom->entry.key = key;
  139.     atom->entry.value = NULL;
  140.     atom->nrefs = 0;
  141.     atom->flags = 0;
  142.     atom->kwindex = -1;
  143.     atom->index = 0;
  144.     atom->number = state->number++;
  145.     return &atom->entry;
  146. }
  147.  
  148. PR_STATIC_CALLBACK(void)
  149. js_free_atom(void *priv, PRHashEntry *he, uintN flag)
  150. {
  151.     if (flag == HT_FREE_ENTRY)
  152.     free(he);
  153. }
  154.  
  155. static PRHashAllocOps atomAllocOps = {
  156.     js_alloc_atom_space,    js_free_atom_space,
  157.     js_alloc_atom,          js_free_atom
  158. };
  159.  
  160. #define JS_ATOM_HASH_SIZE   1024
  161.  
  162. JSBool
  163. js_InitAtomState(JSContext *cx, JSAtomState *state)
  164. {
  165.     uintN i;
  166.  
  167.     state->number = 0;
  168.     state->table = PR_NewHashTable(JS_ATOM_HASH_SIZE, js_hash_atom_key,
  169.                    js_compare_atom_keys, js_compare_stub,
  170.                    &atomAllocOps, state);
  171.     if (!state->table) {
  172.     JS_ReportOutOfMemory(cx);
  173.     return JS_FALSE;
  174.     }
  175.  
  176. #define FROB(lval,str) {                                                      \
  177.     if (!(state->lval = js_Atomize(cx, str, strlen(str), 0))) {               \
  178.     js_FreeAtomState(cx, state);                                          \
  179.     return JS_FALSE;                                                      \
  180.     }                                                                         \
  181. }
  182.  
  183.     PR_ASSERT(sizeof js_type_str / sizeof js_type_str[0] == JSTYPE_LIMIT);
  184.     for (i = 0; i < JSTYPE_LIMIT; i++)
  185.     FROB(typeAtoms[i],        js_type_str[i]);
  186.  
  187.     FROB(booleanAtoms[0],         js_false_str);
  188.     FROB(booleanAtoms[1],         js_true_str);
  189.     FROB(nullAtom,                js_null_str);
  190.  
  191.     FROB(ArrayAtom,               js_Array_str);
  192.     FROB(ObjectAtom,              js_Object_str);
  193.     FROB(anonymousAtom,           js_anonymous_str);
  194.     FROB(assignAtom,              js_assign_str);
  195.     FROB(classPrototypeAtom,      js_class_prototype_str);
  196.     FROB(constructorAtom,         js_constructor_str);
  197.     FROB(countAtom,               js_count_str);
  198.     FROB(indexAtom,               js_index_str);
  199.     FROB(inputAtom,               js_input_str);
  200.     FROB(lengthAtom,              js_length_str);
  201.     FROB(parentAtom,              js_parent_str);
  202.     FROB(protoAtom,               js_proto_str);
  203.     FROB(toStringAtom,            js_toString_str);
  204.     FROB(valueOfAtom,             js_valueOf_str);
  205.  
  206. #undef FROB
  207.  
  208.     return JS_TRUE;
  209. }
  210.  
  211. PR_STATIC_CALLBACK(intN)
  212. js_atom_key_zapper(PRHashEntry *he, intN i, void *arg)
  213. {
  214.     JSAtom *atom;
  215.  
  216.     atom = (JSAtom *)he;
  217.     if (atom->nrefs == 0)
  218.     return HT_ENUMERATE_REMOVE;
  219.     he->key = NULL;
  220.     return HT_ENUMERATE_NEXT;
  221. }
  222.  
  223. void
  224. js_FreeAtomState(JSContext *cx, JSAtomState *state)
  225. {
  226.     PRHashTable *table;
  227.  
  228.     js_ForceGC(cx);
  229.     table = state->table;
  230.     PR_HashTableEnumerateEntries(table, js_atom_key_zapper, NULL);
  231.     js_ForceGC(cx);
  232.     PR_HashTableDestroy(table);
  233.     state->table = NULL;
  234.     state->number = 0;
  235. }
  236.  
  237. typedef struct MarkAtomArgs {
  238.     JSRuntime       *runtime;
  239.     JSAtomMarker    mark;
  240. } MarkAtomArgs;
  241.  
  242. PR_STATIC_CALLBACK(intN)
  243. js_atom_key_marker(PRHashEntry *he, intN i, void *arg)
  244. {
  245.     JSAtom *atom;
  246.     jsval key;
  247.     MarkAtomArgs *args;
  248.  
  249.     atom = (JSAtom *)he;
  250.     if (atom->nrefs == 0) {
  251.     /*
  252.      * Unreferenced atom, probably from the scanner atomizing a name,
  253.      * number, or string that the parser did not save in an atom map
  254.      * (because it was a syntax error, e.g.).
  255.      */
  256.     return HT_ENUMERATE_REMOVE;
  257.     }
  258.     key = ATOM_KEY(atom);
  259.     if (JSVAL_IS_GCTHING(key)) {
  260.     args = arg;
  261.     args->mark(args->runtime, JSVAL_TO_GCTHING(key));
  262.     }
  263.     return HT_ENUMERATE_NEXT;
  264. }
  265.  
  266. void
  267. js_MarkAtomState(JSRuntime *rt, JSAtomMarker mark)
  268. {
  269.     PRHashTable *table;
  270.     MarkAtomArgs args;
  271.  
  272.     table = rt->atomState.table;
  273.     if (!table)
  274.     return;
  275.     args.runtime = rt;
  276.     args.mark = mark;
  277.     PR_HashTableEnumerateEntries(table, js_atom_key_marker, &args);
  278. }
  279.  
  280. static JSAtom *
  281. js_AtomizeHashedKey(JSContext *cx, jsval key, PRHashNumber keyHash, uintN flags)
  282. {
  283.     PRHashTable *table;
  284.     PRHashEntry *he, **hep;
  285.     JSAtom *atom;
  286.  
  287.     PR_ASSERT(JS_IS_LOCKED(cx));
  288.     table = cx->runtime->atomState.table;
  289.     hep = PR_HashTableRawLookup(table, keyHash, (void *)key);
  290.     if ((he = *hep) == NULL) {
  291.     he = PR_HashTableRawAdd(table, hep, keyHash, (void *)key, NULL);
  292.     if (!he) {
  293.         JS_ReportOutOfMemory(cx);
  294.         return NULL;
  295.     }
  296.     }
  297.  
  298.     atom = (JSAtom *)he;
  299. #ifdef DEBUG_DUPLICATE_ATOMS
  300.     hep = PR_HashTableRawLookup(table, keyHash, (void *)key);
  301.     he = *hep;
  302.     PR_ASSERT(atom == (JSAtom *)he);
  303. #endif
  304.  
  305.     if (flags & ATOM_NOHOLD)
  306.     return atom;
  307.     return js_HoldAtom(cx, atom);
  308. }
  309.  
  310. JSAtom *
  311. js_AtomizeObject(JSContext *cx, JSObject *obj, uintN flags)
  312. {
  313.     jsval key;
  314.     PRHashNumber keyHash;
  315.  
  316.     /* XXX must be set in the following order or MSVC1.52 will crash */
  317.     keyHash = HASH_OBJECT(obj);
  318.     key = OBJECT_TO_JSVAL(obj);
  319.     return js_AtomizeHashedKey(cx, key, keyHash, flags);
  320. }
  321.  
  322. JSAtom *
  323. js_AtomizeBoolean(JSContext *cx, JSBool b, uintN flags)
  324. {
  325.     jsval key;
  326.     PRHashNumber keyHash;
  327.  
  328.     key = BOOLEAN_TO_JSVAL(b);
  329.     keyHash = HASH_BOOLEAN(b);
  330.     return js_AtomizeHashedKey(cx, key, keyHash, flags);
  331. }
  332.  
  333. JSAtom *
  334. js_AtomizeInt(JSContext *cx, jsint i, uintN flags)
  335. {
  336.     jsval key;
  337.     PRHashNumber keyHash;
  338.  
  339.     key = INT_TO_JSVAL(i);
  340.     keyHash = HASH_INT(i);
  341.     return js_AtomizeHashedKey(cx, key, keyHash, flags);
  342. }
  343.  
  344. JSAtom *
  345. js_AtomizeDouble(JSContext *cx, jsdouble d, uintN flags)
  346. {
  347.     jsdouble *dp;
  348.     PRHashTable *table;
  349.     PRHashNumber keyHash;
  350.     jsval key;
  351.     PRHashEntry *he, **hep;
  352.     JSAtom *atom;
  353.  
  354. #if PR_ALIGN_OF_DOUBLE == 8
  355.     dp = &d;
  356. #else
  357.     char alignbuf[16];
  358.  
  359.     dp = (jsdouble *)&alignbuf[8 - ((pruword)&alignbuf & 7)];
  360.     *dp = d;
  361. #endif
  362.  
  363.     PR_ASSERT(JS_IS_LOCKED(cx));
  364.     table = cx->runtime->atomState.table;
  365.     keyHash = HASH_DOUBLE(dp);
  366.     key = DOUBLE_TO_JSVAL(dp);
  367.     hep = PR_HashTableRawLookup(table, keyHash, (void *)key);
  368.     if ((he = *hep) == NULL) {
  369.     if (!js_NewDoubleValue(cx, d, &key))
  370.         return NULL;
  371.     he = PR_HashTableRawAdd(table, hep, keyHash, (void *)key, NULL);
  372.     if (!he) {
  373.         JS_ReportOutOfMemory(cx);
  374.         return NULL;
  375.     }
  376.     }
  377.  
  378.     atom = (JSAtom *)he;
  379. #ifdef DEBUG_DUPLICATE_ATOMS
  380.     hep = PR_HashTableRawLookup(table, keyHash, (void *)key);
  381.     he = *hep;
  382.     PR_ASSERT(atom == (JSAtom *)he);
  383. #endif
  384.  
  385.     if (flags & ATOM_NOHOLD)
  386.     return atom;
  387.     return js_HoldAtom(cx, atom);
  388. }
  389.  
  390. JSAtom *
  391. js_AtomizeString(JSContext *cx, JSString *str, uintN flags)
  392. {
  393.     PRHashTable *table;
  394.     PRHashNumber keyHash;
  395.     jsval key;
  396.     PRHashEntry *he, **hep;
  397.     JSAtom *atom;
  398.  
  399.     PR_ASSERT(JS_IS_LOCKED(cx));
  400.     table = cx->runtime->atomState.table;
  401.     keyHash = js_HashString(str);
  402.     key = STRING_TO_JSVAL(str);
  403.     hep = PR_HashTableRawLookup(table, keyHash, (void *)key);
  404.     if ((he = *hep) == NULL) {
  405.     if (flags & ATOM_TMPSTR) {
  406.         if (flags & ATOM_NOCOPY)
  407.         str = js_NewString(cx, str->chars, str->length, 0);
  408.         else
  409.         str = js_NewStringCopyN(cx, str->chars, str->length, 0);
  410.         if (!str)
  411.         return NULL;
  412.         key = STRING_TO_JSVAL(str);
  413.     }
  414.     he = PR_HashTableRawAdd(table, hep, keyHash, (void *)key, NULL);
  415.     if (!he) {
  416.         JS_ReportOutOfMemory(cx);
  417.         return NULL;
  418.     }
  419.     }
  420.  
  421.     atom = (JSAtom *)he;
  422. #ifdef DEBUG_DUPLICATE_ATOMS
  423.     hep = PR_HashTableRawLookup(table, keyHash, (void *)key);
  424.     he = *hep;
  425.     PR_ASSERT(atom == (JSAtom *)he);
  426. #endif
  427.  
  428.     if (flags & ATOM_NOHOLD)
  429.     return atom;
  430.     return js_HoldAtom(cx, atom);
  431. }
  432.  
  433. JS_FRIEND_API(JSAtom *)
  434. js_Atomize(JSContext *cx, const char *bytes, size_t length, uintN flags)
  435. {
  436.     jschar *chars;
  437.     JSString *str;
  438.     JSAtom *atom;
  439. #if PR_ALIGN_OF_DOUBLE == 8
  440.     union { jsdouble d; JSString s; } u;
  441.  
  442.     str = &u.s;
  443. #else
  444.     char alignbuf[16];
  445.  
  446.     str = (JSString *)&alignbuf[8 - ((pruword)&alignbuf & 7)];
  447. #endif
  448.  
  449.     chars = js_InflateString(cx, bytes, length);
  450.     if (!chars)
  451.     return NULL;
  452.     str->chars = chars;
  453.     str->length = length;
  454.     atom = js_AtomizeString(cx, str, ATOM_TMPSTR | ATOM_NOCOPY | flags);
  455.     if (!atom || ATOM_TO_STRING(atom)->chars != chars)
  456.     JS_free(cx, chars);
  457.     return atom;
  458. }
  459.  
  460. JS_FRIEND_API(JSAtom *)
  461. js_AtomizeChars(JSContext *cx, const jschar *chars, size_t length, uintN flags)
  462. {
  463.     JSString *str;
  464. #if PR_ALIGN_OF_DOUBLE == 8
  465.     union { jsdouble d; JSString s; } u;
  466.  
  467.     str = &u.s;
  468. #else
  469.     char alignbuf[16];
  470.  
  471.     str = (JSString *)&alignbuf[8 - ((pruword)&alignbuf & 7)];
  472. #endif
  473.  
  474.     str->chars = (jschar *)chars;
  475.     str->length = length;
  476.     return js_AtomizeString(cx, str, ATOM_TMPSTR | flags);
  477. }
  478.  
  479. JSAtom *
  480. js_AtomizeValue(JSContext *cx, jsval value, uintN flags)
  481. {
  482.     if (JSVAL_IS_STRING(value))
  483.     return js_AtomizeString(cx, JSVAL_TO_STRING(value), flags);
  484.     if (JSVAL_IS_INT(value))
  485.     return js_AtomizeInt(cx, JSVAL_TO_INT(value), flags);
  486.     if (JSVAL_IS_DOUBLE(value))
  487.     return js_AtomizeDouble(cx, *JSVAL_TO_DOUBLE(value), flags);
  488.     if (JSVAL_IS_OBJECT(value))
  489.     return js_AtomizeObject(cx, JSVAL_TO_OBJECT(value), flags);
  490.     if (JSVAL_IS_BOOLEAN(value))
  491.     return js_AtomizeBoolean(cx, JSVAL_TO_BOOLEAN(value), flags);
  492.     return js_AtomizeHashedKey(cx, value, (PRHashNumber)value, flags);
  493. }
  494.  
  495. JSAtom *
  496. js_ValueToStringAtom(JSContext *cx, jsval v)
  497. {
  498.     JSString *str;
  499.  
  500.     str = js_ValueToString(cx, v);
  501.     if (!str)
  502.     return NULL;
  503.     return js_AtomizeString(cx, str, 0);
  504. }
  505.  
  506. jsatomid
  507. js_IndexAtom(JSContext *cx, JSAtom *atom, JSAtomList *al)
  508. {
  509.     if (!(atom->flags & ATOM_INDEXED)) {
  510.     atom->flags |= ATOM_INDEXED;
  511.     atom->index = (jsatomid) al->count++;
  512.     ATOM_SET_NEXT(atom, al->list);
  513.     al->list = js_HoldAtom(cx, atom);
  514.     }
  515.     return atom->index;
  516. }
  517.  
  518. JSAtom *
  519. js_HoldAtom(JSContext *cx, JSAtom *atom)
  520. {
  521. #ifdef DEBUG_DUPLICATE_ATOMS
  522.     jsval key;
  523.     PRHashNumber keyHash;
  524.     PRHashEntry *he, **hep;
  525.  
  526.     key = ATOM_KEY(atom);
  527.     keyHash = js_hash_atom_key((void *)key);
  528.     hep = PR_HashTableRawLookup(cx->runtime->atomState.table, keyHash,
  529.                 (void*)key);
  530.     he = *hep;
  531.     PR_ASSERT(atom == (JSAtom *)he);
  532. #endif
  533.     PR_ASSERT(JS_IS_LOCKED(cx));
  534.     atom->nrefs++;
  535.     PR_ASSERT(atom->nrefs > 0);
  536.     return atom;
  537. }
  538.  
  539. JS_FRIEND_API(JSAtom *)
  540. js_DropAtom(JSContext *cx, JSAtom *atom)
  541. {
  542. #ifdef DEBUG_DUPLICATE_ATOMS
  543.     jsval key;
  544.     PRHashNumber keyHash;
  545.     PRHashEntry *he, **hep;
  546.  
  547.     key = ATOM_KEY(atom);
  548.     keyHash = js_hash_atom_key((void *)key);
  549.     hep = PR_HashTableRawLookup(cx->runtime->atomState.table, keyHash,
  550.                 (void*)key);
  551.     he = *hep;
  552.     PR_ASSERT(atom == (JSAtom *)he);
  553. #endif
  554.     PR_ASSERT(JS_IS_LOCKED(cx));
  555.     PR_ASSERT(atom->nrefs > 0);
  556.     if (atom->nrefs <= 0)
  557.     return NULL;
  558.     if (--atom->nrefs == 0) {
  559.     PR_HashTableRemove(cx->runtime->atomState.table, atom->entry.key);
  560. #ifdef DEBUG_DUPLICATE_ATOMS
  561.     hep = PR_HashTableRawLookup(cx->runtime->atomState.table, keyHash,
  562.                     (void *)key);
  563.     he = *hep;
  564.     PR_ASSERT(he == NULL);
  565. #endif
  566.     atom = NULL;
  567.     }
  568.     return atom;
  569. }
  570.  
  571. JSAtom *
  572. js_GetAtom(JSContext *cx, JSAtomMap *map, jsatomid i)
  573. {
  574.     JSAtom *atom;
  575.  
  576.     PR_ASSERT(map->vector && i < map->length);
  577.     if (!map->vector || i >= map->length) {
  578.     JS_ReportError(cx, "internal error: no index for atom %ld", (long)i);
  579.     return NULL;
  580.     }
  581.     atom = map->vector[i];
  582.     PR_ASSERT(atom);
  583.     return atom;
  584. }
  585.  
  586. JS_FRIEND_API(JSBool)
  587. js_InitAtomMap(JSContext *cx, JSAtomMap *map, JSAtomList *al)
  588. {
  589.     JSAtom *atom, *next, **vector;
  590.     uint32 count;
  591.  
  592.     atom = al->list;
  593.     if (!atom) {
  594.     map->vector = NULL;
  595.     map->length = 0;
  596.     return JS_TRUE;
  597.     }
  598.  
  599.     count = al->count;
  600.     if (count >= ATOM_INDEX_LIMIT) {
  601.     JS_ReportError(cx, "too many literals");
  602.     return JS_FALSE;
  603.     }
  604.     vector = JS_malloc(cx, (size_t) count * sizeof *vector);
  605.     if (!vector)
  606.     return JS_FALSE;
  607.  
  608.     do {
  609.         vector[atom->index] = atom;
  610.     atom->flags &= ~ATOM_INDEXED;
  611.     next = ATOM_NEXT(atom);
  612.     ATOM_SET_NEXT(atom, NULL);
  613.     } while ((atom = next) != NULL);
  614.     al->list = NULL;
  615.     al->count = 0;
  616.  
  617.     map->vector = vector;
  618.     map->length = (jsatomid)count;
  619.     return JS_TRUE;
  620. }
  621.  
  622. JS_FRIEND_API(void)
  623. js_FreeAtomMap(JSContext *cx, JSAtomMap *map)
  624. {
  625.     uintN i;
  626.  
  627.     if (map->vector) {
  628.         for (i = 0; i < map->length; i++)
  629.         js_DropAtom(cx, map->vector[i]);
  630.     free(map->vector);
  631.     map->vector = NULL;
  632.     }
  633.     map->length = 0;
  634. }
  635.  
  636. void
  637. js_DropUnmappedAtoms(JSContext *cx, JSAtomList *al)
  638. {
  639.     JSAtom *atom, *next;
  640.  
  641.     for (atom = al->list; atom; atom = next) {
  642.     atom->flags &= ~ATOM_INDEXED;
  643.     next = ATOM_NEXT(atom);
  644.     ATOM_SET_NEXT(atom, NULL);
  645.     js_DropAtom(cx, atom);
  646.     }
  647.     al->list = NULL;
  648.     al->count = 0;
  649. }
  650.