1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
3
* ***** BEGIN LICENSE BLOCK *****
4
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
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/
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
16
* The Original Code is Mozilla Communicator client code, released
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.
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.
38
* ***** END LICENSE BLOCK ***** */
47
#include "jsutil.h" /* Added by JSIFY */
48
#include "jshash.h" /* Added by JSIFY */
60
JS_FRIEND_API(const char *)
61
js_AtomToPrintableString(JSContext *cx, JSAtom *atom)
63
return js_ValueToPrintableString(cx, ATOM_KEY(atom));
66
#if JS_HAS_ERROR_EXCEPTIONS
67
extern const char js_Error_str[]; /* trivial, from jsexn.h */
71
* Keep this in sync with jspubtd.h -- an assertion below will insist that
72
* its length match the JSType enum's JSTYPE_LIMIT limit value.
74
const char *js_type_str[] = {
85
const char *js_boolean_str[] = {
90
const char js_Arguments_str[] = "Arguments";
91
const char js_Array_str[] = "Array";
92
const char js_Boolean_str[] = "Boolean";
93
const char js_Call_str[] = "Call";
94
const char js_Date_str[] = "Date";
95
const char js_Function_str[] = "Function";
96
const char js_Math_str[] = "Math";
97
const char js_Namespace_str[] = "Namespace";
98
const char js_Number_str[] = "Number";
99
const char js_Object_str[] = "Object";
100
const char js_QName_str[] = "QName";
101
const char js_RegExp_str[] = "RegExp";
102
const char js_Script_str[] = "Script";
103
const char js_String_str[] = "String";
104
const char js_XML_str[] = "XML";
105
const char js_File_str[] = "File";
106
const char js_anonymous_str[] = "anonymous";
107
const char js_arguments_str[] = "arguments";
108
const char js_arity_str[] = "arity";
109
const char js_callee_str[] = "callee";
110
const char js_caller_str[] = "caller";
111
const char js_class_prototype_str[] = "prototype";
112
const char js_constructor_str[] = "constructor";
113
const char js_count_str[] = "__count__";
114
const char js_each_str[] = "each";
115
const char js_eval_str[] = "eval";
116
const char js_getter_str[] = "getter";
117
const char js_get_str[] = "get";
118
const char js_index_str[] = "index";
119
const char js_input_str[] = "input";
120
const char js_length_str[] = "length";
121
const char js_name_str[] = "name";
122
const char js_noSuchMethod_str[] = "__noSuchMethod__";
123
const char js_object_str[] = "object";
124
const char js_parent_str[] = "__parent__";
125
const char js_private_str[] = "private";
126
const char js_proto_str[] = "__proto__";
127
const char js_setter_str[] = "setter";
128
const char js_set_str[] = "set";
129
const char js_toSource_str[] = "toSource";
130
const char js_toString_str[] = "toString";
131
const char js_toLocaleString_str[] = "toLocaleString";
132
const char js_valueOf_str[] = "valueOf";
134
#if JS_HAS_XML_SUPPORT
135
const char js_etago_str[] = "</";
136
const char js_namespace_str[] = "namespace";
137
const char js_ptagc_str[] = "/>";
138
const char js_qualifier_str[] = "::";
139
const char js_space_str[] = " ";
140
const char js_stago_str[] = "<";
141
const char js_star_str[] = "*";
142
const char js_starQualifier_str[] = "*::";
143
const char js_tagc_str[] = ">";
144
const char js_xml_str[] = "xml";
148
const char js_call_str[] = "__call__";
149
const char js_construct_str[] = "__construct__";
150
const char js_hasInstance_str[] = "__hasInstance__";
151
const char js_ExecutionContext_str[] = "ExecutionContext";
152
const char js_current_str[] = "current";
155
#define HASH_OBJECT(o) (JS_PTR_TO_UINT32(o) >> JSVAL_TAGBITS)
156
#define HASH_INT(i) ((JSHashNumber)(i))
157
#define HASH_DOUBLE(dp) ((JSDOUBLE_HI32(*dp) ^ JSDOUBLE_LO32(*dp)))
158
#define HASH_BOOLEAN(b) ((JSHashNumber)(b))
160
JS_STATIC_DLL_CALLBACK(JSHashNumber)
161
js_hash_atom_key(const void *key)
166
/* Order JSVAL_IS_* tests by likelihood of success. */
168
if (JSVAL_IS_STRING(v))
169
return js_HashString(JSVAL_TO_STRING(v));
171
return HASH_INT(JSVAL_TO_INT(v));
172
if (JSVAL_IS_DOUBLE(v)) {
173
dp = JSVAL_TO_DOUBLE(v);
174
return HASH_DOUBLE(dp);
176
if (JSVAL_IS_OBJECT(v))
177
return HASH_OBJECT(JSVAL_TO_OBJECT(v));
178
if (JSVAL_IS_BOOLEAN(v))
179
return HASH_BOOLEAN(JSVAL_TO_BOOLEAN(v));
180
return (JSHashNumber)v;
183
JS_STATIC_DLL_CALLBACK(intN)
184
js_compare_atom_keys(const void *k1, const void *k2)
188
v1 = (jsval)k1, v2 = (jsval)k2;
189
if (JSVAL_IS_STRING(v1) && JSVAL_IS_STRING(v2))
190
return !js_CompareStrings(JSVAL_TO_STRING(v1), JSVAL_TO_STRING(v2));
191
if (JSVAL_IS_DOUBLE(v1) && JSVAL_IS_DOUBLE(v2)) {
192
double d1 = *JSVAL_TO_DOUBLE(v1);
193
double d2 = *JSVAL_TO_DOUBLE(v2);
194
if (JSDOUBLE_IS_NaN(d1))
195
return JSDOUBLE_IS_NaN(d2);
197
/* XXX MSVC miscompiles such that (NaN == 0) */
198
if (JSDOUBLE_IS_NaN(d2))
206
JS_STATIC_DLL_CALLBACK(int)
207
js_compare_stub(const void *v1, const void *v2)
212
/* These next two are exported to jsscript.c and used similarly there. */
213
void * JS_DLL_CALLBACK
214
js_alloc_table_space(void *priv, size_t size)
220
js_free_table_space(void *priv, void *item)
225
JS_STATIC_DLL_CALLBACK(JSHashEntry *)
226
js_alloc_atom(void *priv, const void *key)
228
JSAtomState *state = (JSAtomState *) priv;
231
atom = (JSAtom *) malloc(sizeof(JSAtom));
237
atom->entry.key = key;
238
atom->entry.value = NULL;
240
atom->number = state->number++;
244
JS_STATIC_DLL_CALLBACK(void)
245
js_free_atom(void *priv, JSHashEntry *he, uintN flag)
247
if (flag != HT_FREE_ENTRY)
250
((JSAtomState *)priv)->tablegen++;
255
static JSHashAllocOps atom_alloc_ops = {
256
js_alloc_table_space, js_free_table_space,
257
js_alloc_atom, js_free_atom
260
#define JS_ATOM_HASH_SIZE 1024
263
js_InitAtomState(JSContext *cx, JSAtomState *state)
265
state->table = JS_NewHashTable(JS_ATOM_HASH_SIZE, js_hash_atom_key,
266
js_compare_atom_keys, js_compare_stub,
267
&atom_alloc_ops, state);
269
JS_ReportOutOfMemory(cx);
273
state->runtime = cx->runtime;
275
js_InitLock(&state->lock);
279
if (!js_InitPinnedAtoms(cx, state)) {
280
js_FreeAtomState(cx, state);
287
js_InitPinnedAtoms(JSContext *cx, JSAtomState *state)
291
#define FROB(lval,str) \
293
if (!(state->lval = js_Atomize(cx, str, strlen(str), ATOM_PINNED))) \
297
JS_ASSERT(sizeof js_type_str / sizeof js_type_str[0] == JSTYPE_LIMIT);
298
for (i = 0; i < JSTYPE_LIMIT; i++)
299
FROB(typeAtoms[i], js_type_str[i]);
301
FROB(booleanAtoms[0], js_false_str);
302
FROB(booleanAtoms[1], js_true_str);
303
FROB(nullAtom, js_null_str);
305
FROB(ArgumentsAtom, js_Arguments_str);
306
FROB(ArrayAtom, js_Array_str);
307
FROB(BooleanAtom, js_Boolean_str);
308
FROB(CallAtom, js_Call_str);
309
FROB(DateAtom, js_Date_str);
310
#if JS_HAS_ERROR_EXCEPTIONS
311
FROB(ErrorAtom, js_Error_str);
313
FROB(FunctionAtom, js_Function_str);
314
FROB(MathAtom, js_Math_str);
315
FROB(NamespaceAtom, js_Namespace_str);
316
FROB(NumberAtom, js_Number_str);
317
FROB(ObjectAtom, js_Object_str);
318
FROB(QNameAtom, js_QName_str);
319
FROB(RegExpAtom, js_RegExp_str);
320
FROB(ScriptAtom, js_Script_str);
321
FROB(StringAtom, js_String_str);
322
FROB(XMLAtom, js_XML_str);
323
FROB(FileAtom, js_File_str);
324
FROB(anonymousAtom, js_anonymous_str);
325
FROB(argumentsAtom, js_arguments_str);
326
FROB(arityAtom, js_arity_str);
327
FROB(calleeAtom, js_callee_str);
328
FROB(callerAtom, js_caller_str);
329
FROB(classPrototypeAtom, js_class_prototype_str);
330
FROB(constructorAtom, js_constructor_str);
331
FROB(countAtom, js_count_str);
332
FROB(eachAtom, js_each_str);
333
FROB(evalAtom, js_eval_str);
334
FROB(getAtom, js_get_str);
335
FROB(getterAtom, js_getter_str);
336
FROB(indexAtom, js_index_str);
337
FROB(inputAtom, js_input_str);
338
FROB(lengthAtom, js_length_str);
339
FROB(nameAtom, js_name_str);
340
FROB(noSuchMethodAtom, js_noSuchMethod_str);
341
FROB(parentAtom, js_parent_str);
342
FROB(protoAtom, js_proto_str);
343
FROB(setAtom, js_set_str);
344
FROB(setterAtom, js_setter_str);
345
FROB(toSourceAtom, js_toSource_str);
346
FROB(toStringAtom, js_toString_str);
347
FROB(toLocaleStringAtom, js_toLocaleString_str);
348
FROB(valueOfAtom, js_valueOf_str);
350
#if JS_HAS_XML_SUPPORT
351
FROB(etagoAtom, js_etago_str);
352
FROB(namespaceAtom, js_namespace_str);
353
FROB(ptagcAtom, js_ptagc_str);
354
FROB(qualifierAtom, js_qualifier_str);
355
FROB(spaceAtom, js_space_str);
356
FROB(stagoAtom, js_stago_str);
357
FROB(starAtom, js_star_str);
358
FROB(starQualifierAtom, js_starQualifier_str);
359
FROB(tagcAtom, js_tagc_str);
360
FROB(xmlAtom, js_xml_str);
364
FROB(callAtom, js_call_str);
365
FROB(constructAtom, js_construct_str);
366
FROB(hasInstanceAtom, js_hasInstance_str);
367
FROB(ExecutionContextAtom, js_ExecutionContext_str);
368
FROB(currentAtom, js_current_str);
373
memset(&state->lazy, 0, sizeof state->lazy);
377
/* NB: cx unused; js_FinishAtomState calls us with null cx. */
379
js_FreeAtomState(JSContext *cx, JSAtomState *state)
382
JS_HashTableDestroy(state->table);
384
js_FinishLock(&state->lock);
386
memset(state, 0, sizeof *state);
389
typedef struct UninternArgs {
394
JS_STATIC_DLL_CALLBACK(intN)
395
js_atom_uninterner(JSHashEntry *he, intN i, void *arg)
401
args = (UninternArgs *)arg;
402
if (ATOM_IS_STRING(atom))
403
js_FinalizeStringRT(args->rt, ATOM_TO_STRING(atom));
404
else if (ATOM_IS_OBJECT(atom))
406
return HT_ENUMERATE_NEXT;
410
js_FinishAtomState(JSAtomState *state)
416
args.rt = state->runtime;
418
JS_HashTableEnumerateEntries(state->table, js_atom_uninterner, &args);
420
if (args.leaks != 0) {
422
"JS engine warning: %lu atoms remain after destroying the JSRuntime.\n"
423
" These atoms may point to freed memory. Things reachable\n"
424
" through them have not been finalized.\n",
425
(unsigned long) args.leaks);
428
js_FreeAtomState(NULL, state);
431
typedef struct MarkArgs {
433
JSGCThingMarker mark;
437
JS_STATIC_DLL_CALLBACK(intN)
438
js_atom_marker(JSHashEntry *he, intN i, void *arg)
445
args = (MarkArgs *)arg;
446
if ((atom->flags & (ATOM_PINNED | ATOM_INTERNED)) ||
447
(args->gcflags & GC_KEEP_ATOMS)) {
448
atom->flags |= ATOM_MARK;
449
key = ATOM_KEY(atom);
450
if (JSVAL_IS_GCTHING(key))
451
args->mark(JSVAL_TO_GCTHING(key), args->data);
453
return HT_ENUMERATE_NEXT;
457
js_MarkAtomState(JSAtomState *state, uintN gcflags, JSGCThingMarker mark,
464
args.gcflags = gcflags;
467
JS_HashTableEnumerateEntries(state->table, js_atom_marker, &args);
470
JS_STATIC_DLL_CALLBACK(intN)
471
js_atom_sweeper(JSHashEntry *he, intN i, void *arg)
477
if (atom->flags & ATOM_MARK) {
478
atom->flags &= ~ATOM_MARK;
479
state = (JSAtomState *)arg;
481
return HT_ENUMERATE_NEXT;
483
JS_ASSERT((atom->flags & (ATOM_PINNED | ATOM_INTERNED)) == 0);
484
atom->entry.key = atom->entry.value = NULL;
486
return HT_ENUMERATE_REMOVE;
490
js_SweepAtomState(JSAtomState *state)
492
state->liveAtoms = 0;
494
JS_HashTableEnumerateEntries(state->table, js_atom_sweeper, state);
497
JS_STATIC_DLL_CALLBACK(intN)
498
js_atom_unpinner(JSHashEntry *he, intN i, void *arg)
503
atom->flags &= ~ATOM_PINNED;
504
return HT_ENUMERATE_NEXT;
508
js_UnpinPinnedAtoms(JSAtomState *state)
511
JS_HashTableEnumerateEntries(state->table, js_atom_unpinner, NULL);
515
js_AtomizeHashedKey(JSContext *cx, jsval key, JSHashNumber keyHash, uintN flags)
519
JSHashEntry *he, **hep;
522
state = &cx->runtime->atomState;
523
JS_LOCK(&state->lock, cx);
524
table = state->table;
525
hep = JS_HashTableRawLookup(table, keyHash, (void *)key);
526
if ((he = *hep) == NULL) {
527
he = JS_HashTableRawAdd(table, hep, keyHash, (void *)key, NULL);
529
JS_ReportOutOfMemory(cx);
536
atom->flags |= flags;
537
cx->weakRoots.lastAtom = atom;
539
JS_UNLOCK(&state->lock,cx);
544
js_AtomizeObject(JSContext *cx, JSObject *obj, uintN flags)
547
JSHashNumber keyHash;
549
/* XXX must be set in the following order or MSVC1.52 will crash */
550
keyHash = HASH_OBJECT(obj);
551
key = OBJECT_TO_JSVAL(obj);
552
return js_AtomizeHashedKey(cx, key, keyHash, flags);
556
js_AtomizeBoolean(JSContext *cx, JSBool b, uintN flags)
559
JSHashNumber keyHash;
561
key = BOOLEAN_TO_JSVAL(b);
562
keyHash = HASH_BOOLEAN(b);
563
return js_AtomizeHashedKey(cx, key, keyHash, flags);
567
js_AtomizeInt(JSContext *cx, jsint i, uintN flags)
570
JSHashNumber keyHash;
572
key = INT_TO_JSVAL(i);
573
keyHash = HASH_INT(i);
574
return js_AtomizeHashedKey(cx, key, keyHash, flags);
577
/* Worst-case alignment grain and aligning macro for 2x-sized buffer. */
578
#define ALIGNMENT(t) JS_MAX(JSVAL_ALIGN, sizeof(t))
579
#define ALIGN(b,t) ((t*) &(b)[ALIGNMENT(t) - (jsuword)(b) % ALIGNMENT(t)])
582
js_AtomizeDouble(JSContext *cx, jsdouble d, uintN flags)
585
JSHashNumber keyHash;
589
JSHashEntry *he, **hep;
591
char buf[2 * ALIGNMENT(double)];
593
dp = ALIGN(buf, double);
595
keyHash = HASH_DOUBLE(dp);
596
key = DOUBLE_TO_JSVAL(dp);
597
state = &cx->runtime->atomState;
598
JS_LOCK(&state->lock, cx);
599
table = state->table;
600
hep = JS_HashTableRawLookup(table, keyHash, (void *)key);
601
if ((he = *hep) == NULL) {
603
uint32 gen = state->tablegen;
605
JS_UNLOCK(&state->lock,cx);
606
if (!js_NewDoubleValue(cx, d, &key))
608
JS_LOCK(&state->lock, cx);
610
if (state->tablegen != gen) {
611
hep = JS_HashTableRawLookup(table, keyHash, (void *)key);
612
if ((he = *hep) != NULL) {
618
he = JS_HashTableRawAdd(table, hep, keyHash, (void *)key, NULL);
620
JS_ReportOutOfMemory(cx);
627
atom->flags |= flags;
628
cx->weakRoots.lastAtom = atom;
630
JS_UNLOCK(&state->lock,cx);
635
* To put an atom into the hidden subspace. XOR its keyHash with this value,
636
* which is (sqrt(2)-1) in 32-bit fixed point.
638
#define HIDDEN_ATOM_SUBSPACE_KEYHASH 0x6A09E667
641
js_AtomizeString(JSContext *cx, JSString *str, uintN flags)
643
JSHashNumber keyHash;
647
JSHashEntry *he, **hep;
650
keyHash = js_HashString(str);
651
if (flags & ATOM_HIDDEN)
652
keyHash ^= HIDDEN_ATOM_SUBSPACE_KEYHASH;
653
key = STRING_TO_JSVAL(str);
654
state = &cx->runtime->atomState;
655
JS_LOCK(&state->lock, cx);
656
table = state->table;
657
hep = JS_HashTableRawLookup(table, keyHash, (void *)key);
658
if ((he = *hep) == NULL) {
660
uint32 gen = state->tablegen;
661
JS_UNLOCK(&state->lock, cx);
664
if (flags & ATOM_TMPSTR) {
665
str = (flags & ATOM_NOCOPY)
666
? js_NewString(cx, str->chars, str->length, 0)
667
: js_NewStringCopyN(cx, str->chars, str->length, 0);
670
key = STRING_TO_JSVAL(str);
672
if (!JS_MakeStringImmutable(cx, str))
677
JS_LOCK(&state->lock, cx);
678
if (state->tablegen != gen) {
679
hep = JS_HashTableRawLookup(table, keyHash, (void *)key);
680
if ((he = *hep) != NULL) {
682
if (flags & ATOM_NOCOPY)
689
he = JS_HashTableRawAdd(table, hep, keyHash, (void *)key, NULL);
691
JS_ReportOutOfMemory(cx);
698
atom->flags |= flags & (ATOM_PINNED | ATOM_INTERNED | ATOM_HIDDEN);
699
cx->weakRoots.lastAtom = atom;
701
JS_UNLOCK(&state->lock,cx);
705
JS_FRIEND_API(JSAtom *)
706
js_Atomize(JSContext *cx, const char *bytes, size_t length, uintN flags)
711
char buf[2 * ALIGNMENT(JSString)];
714
* Avoiding the malloc in js_InflateString on shorter strings saves us
715
* over 20,000 malloc calls on mozilla browser startup. This compares to
716
* only 131 calls where the string is longer than a 31 char (net) buffer.
717
* The vast majority of atomized strings are already in the hashtable. So
718
* js_AtomizeString rarely has to copy the temp string we make.
720
#define ATOMIZE_BUF_MAX 32
721
jschar inflated[ATOMIZE_BUF_MAX];
722
size_t inflatedLength = ATOMIZE_BUF_MAX - 1;
724
if (length < ATOMIZE_BUF_MAX) {
725
js_InflateStringToBuffer(cx, bytes, length, inflated, &inflatedLength);
726
inflated[inflatedLength] = 0;
729
inflatedLength = length;
730
chars = js_InflateString(cx, bytes, &inflatedLength);
733
flags |= ATOM_NOCOPY;
736
str = ALIGN(buf, JSString);
739
str->length = inflatedLength;
740
atom = js_AtomizeString(cx, str, ATOM_TMPSTR | flags);
741
if (chars != inflated && (!atom || ATOM_TO_STRING(atom)->chars != chars))
746
JS_FRIEND_API(JSAtom *)
747
js_AtomizeChars(JSContext *cx, const jschar *chars, size_t length, uintN flags)
750
char buf[2 * ALIGNMENT(JSString)];
752
str = ALIGN(buf, JSString);
753
str->chars = (jschar *)chars;
754
str->length = length;
755
return js_AtomizeString(cx, str, ATOM_TMPSTR | flags);
759
js_AtomizeValue(JSContext *cx, jsval value, uintN flags)
761
if (JSVAL_IS_STRING(value))
762
return js_AtomizeString(cx, JSVAL_TO_STRING(value), flags);
763
if (JSVAL_IS_INT(value))
764
return js_AtomizeInt(cx, JSVAL_TO_INT(value), flags);
765
if (JSVAL_IS_DOUBLE(value))
766
return js_AtomizeDouble(cx, *JSVAL_TO_DOUBLE(value), flags);
767
if (JSVAL_IS_OBJECT(value))
768
return js_AtomizeObject(cx, JSVAL_TO_OBJECT(value), flags);
769
if (JSVAL_IS_BOOLEAN(value))
770
return js_AtomizeBoolean(cx, JSVAL_TO_BOOLEAN(value), flags);
771
return js_AtomizeHashedKey(cx, value, (JSHashNumber)value, flags);
775
js_ValueToStringAtom(JSContext *cx, jsval v)
779
str = js_ValueToString(cx, v);
782
return js_AtomizeString(cx, str, 0);
785
JS_STATIC_DLL_CALLBACK(JSHashNumber)
786
js_hash_atom_ptr(const void *key)
788
const JSAtom *atom = key;
792
JS_STATIC_DLL_CALLBACK(void *)
793
js_alloc_temp_space(void *priv, size_t size)
795
JSContext *cx = priv;
798
JS_ARENA_ALLOCATE(space, &cx->tempPool, size);
800
JS_ReportOutOfMemory(cx);
804
JS_STATIC_DLL_CALLBACK(void)
805
js_free_temp_space(void *priv, void *item)
809
JS_STATIC_DLL_CALLBACK(JSHashEntry *)
810
js_alloc_temp_entry(void *priv, const void *key)
812
JSContext *cx = priv;
813
JSAtomListElement *ale;
815
JS_ARENA_ALLOCATE_TYPE(ale, JSAtomListElement, &cx->tempPool);
817
JS_ReportOutOfMemory(cx);
823
JS_STATIC_DLL_CALLBACK(void)
824
js_free_temp_entry(void *priv, JSHashEntry *he, uintN flag)
828
static JSHashAllocOps temp_alloc_ops = {
829
js_alloc_temp_space, js_free_temp_space,
830
js_alloc_temp_entry, js_free_temp_entry
834
js_IndexAtom(JSContext *cx, JSAtom *atom, JSAtomList *al)
836
JSAtomListElement *ale, *ale2, *next;
839
ATOM_LIST_LOOKUP(ale, hep, al, atom);
841
if (al->count < 10) {
842
/* Few enough for linear search, no hash table needed. */
843
JS_ASSERT(!al->table);
844
ale = (JSAtomListElement *)js_alloc_temp_entry(cx, atom);
847
ALE_SET_ATOM(ale, atom);
848
ALE_SET_NEXT(ale, al->list);
851
/* We want to hash. Have we already made a hash table? */
853
/* No hash table yet, so hep had better be null! */
855
al->table = JS_NewHashTable(al->count + 1, js_hash_atom_ptr,
856
JS_CompareValues, JS_CompareValues,
857
&temp_alloc_ops, cx);
862
* Set ht->nentries explicitly, because we are moving entries
863
* from al to ht, not calling JS_HashTable(Raw|)Add.
865
al->table->nentries = al->count;
867
/* Insert each ale on al->list into the new hash table. */
868
for (ale2 = al->list; ale2; ale2 = next) {
869
next = ALE_NEXT(ale2);
870
ale2->entry.keyHash = ALE_ATOM(ale2)->number;
871
hep = JS_HashTableRawLookup(al->table, ale2->entry.keyHash,
873
ALE_SET_NEXT(ale2, *hep);
878
/* Set hep for insertion of atom's ale, immediately below. */
879
hep = JS_HashTableRawLookup(al->table, atom->number, atom);
882
/* Finally, add an entry for atom into the hash bucket at hep. */
883
ale = (JSAtomListElement *)
884
JS_HashTableRawAdd(al->table, hep, atom->number, atom, NULL);
889
ALE_SET_INDEX(ale, al->count++);
894
JS_FRIEND_API(JSAtom *)
895
js_GetAtom(JSContext *cx, JSAtomMap *map, jsatomid i)
900
JS_ASSERT(map->vector && i < map->length);
901
if (!map->vector || i >= map->length) {
903
JS_snprintf(numBuf, sizeof numBuf, "%lu", (unsigned long)i);
904
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
905
JSMSG_BAD_ATOMIC_NUMBER, numBuf);
908
atom = map->vector[i];
913
JS_STATIC_DLL_CALLBACK(intN)
914
js_map_atom(JSHashEntry *he, intN i, void *arg)
916
JSAtomListElement *ale = (JSAtomListElement *)he;
917
JSAtom **vector = arg;
919
vector[ALE_INDEX(ale)] = ALE_ATOM(ale);
920
return HT_ENUMERATE_NEXT;
924
static jsrefcount js_atom_map_count;
925
static jsrefcount js_atom_map_hash_table_count;
928
JS_FRIEND_API(JSBool)
929
js_InitAtomMap(JSContext *cx, JSAtomMap *map, JSAtomList *al)
932
JSAtomListElement *ale;
936
JS_ATOMIC_INCREMENT(&js_atom_map_count);
939
if (!ale && !al->table) {
946
if (count >= ATOM_INDEX_LIMIT) {
947
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
948
JSMSG_TOO_MANY_LITERALS);
951
vector = (JSAtom **) JS_malloc(cx, (size_t) count * sizeof *vector);
957
JS_ATOMIC_INCREMENT(&js_atom_map_hash_table_count);
959
JS_HashTableEnumerateEntries(al->table, js_map_atom, vector);
962
vector[ALE_INDEX(ale)] = ALE_ATOM(ale);
963
} while ((ale = ALE_NEXT(ale)) != NULL);
967
map->vector = vector;
968
map->length = (jsatomid)count;
973
js_FreeAtomMap(JSContext *cx, JSAtomMap *map)
976
JS_free(cx, map->vector);