Imported Upstream version 1.0.0
[platform/upstream/js.git] / js / src / jsatom.h
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 #ifndef jsatom_h___
41 #define jsatom_h___
42 /*
43  * JS atom table.
44  */
45 #include <stddef.h>
46 #include "jsversion.h"
47 #include "jsapi.h"
48 #include "jsprvtd.h"
49 #include "jshash.h"
50 #include "jshashtable.h"
51 #include "jspubtd.h"
52 #include "jsstr.h"
53 #include "jslock.h"
54 #include "jsvalue.h"
55
56 #define ATOM_PINNED     0x1       /* atom is pinned against GC */
57 #define ATOM_INTERNED   0x2       /* pinned variant for JS_Intern* API */
58 #define ATOM_NOCOPY     0x4       /* don't copy atom string bytes */
59 #define ATOM_TMPSTR     0x8       /* internal, to avoid extra string */
60
61 #define STRING_TO_ATOM(str)       (JS_ASSERT(str->isAtomized()),             \
62                                    (JSAtom *)str)
63 #define ATOM_TO_STRING(atom)      (atom)
64 #define ATOM_TO_JSVAL(atom)       STRING_TO_JSVAL(ATOM_TO_STRING(atom))
65
66 /* Engine-internal extensions of jsid */
67
68 static JS_ALWAYS_INLINE jsid
69 JSID_FROM_BITS(size_t bits)
70 {
71     jsid id;
72     JSID_BITS(id) = bits;
73     return id;
74 }
75
76 static JS_ALWAYS_INLINE jsid
77 ATOM_TO_JSID(JSAtom *atom)
78 {
79     JS_ASSERT(((size_t)atom & 0x7) == 0);
80     return JSID_FROM_BITS((size_t)atom);
81 }
82
83 /* All strings stored in jsids are atomized. */
84 static JS_ALWAYS_INLINE JSBool
85 JSID_IS_ATOM(jsid id)
86 {
87     return JSID_IS_STRING(id);
88 }
89
90 static JS_ALWAYS_INLINE JSBool
91 JSID_IS_ATOM(jsid id, JSAtom *atom)
92 {
93     return JSID_BITS(id) == JSID_BITS(ATOM_TO_JSID(atom));
94 }
95
96 static JS_ALWAYS_INLINE JSAtom *
97 JSID_TO_ATOM(jsid id)
98 {
99     return (JSAtom *)JSID_TO_STRING(id);
100 }
101
102 namespace js {
103
104 static JS_ALWAYS_INLINE Value
105 IdToValue(jsid id)
106 {
107     if (JSID_IS_STRING(id))
108         return StringValue(JSID_TO_STRING(id));
109     if (JS_LIKELY(JSID_IS_INT(id)))
110         return Int32Value(JSID_TO_INT(id));
111     if (JS_LIKELY(JSID_IS_OBJECT(id)))
112         return ObjectValue(*JSID_TO_OBJECT(id));
113     JS_ASSERT(JSID_IS_DEFAULT_XML_NAMESPACE(id) || JSID_IS_VOID(id));
114     return UndefinedValue();
115 }
116
117 static JS_ALWAYS_INLINE jsval
118 IdToJsval(jsid id)
119 {
120     return Jsvalify(IdToValue(id));
121 }
122
123 }
124
125 #if JS_BYTES_PER_WORD == 4
126 # define ATOM_HASH(atom)          ((JSHashNumber)(atom) >> 2)
127 #elif JS_BYTES_PER_WORD == 8
128 # define ATOM_HASH(atom)          (((JSHashNumber)(jsuword)(atom) >> 3) ^     \
129                                    (JSHashNumber)((jsuword)(atom) >> 32))
130 #else
131 # error "Unsupported configuration"
132 #endif
133
134 /*
135  * Return a printable, lossless char[] representation of a string-type atom.
136  * The lifetime of the result matches the lifetime of bytes.
137  */
138 extern const char *
139 js_AtomToPrintableString(JSContext *cx, JSAtom *atom, JSAutoByteString *bytes);
140
141 struct JSAtomListElement {
142     JSHashEntry         entry;
143 };
144
145 #define ALE_ATOM(ale)   ((JSAtom *) (ale)->entry.key)
146 #define ALE_INDEX(ale)  (jsatomid(uintptr_t((ale)->entry.value)))
147 #define ALE_VALUE(ale)  ((jsboxedword) (ale)->entry.value)
148 #define ALE_NEXT(ale)   ((JSAtomListElement *) (ale)->entry.next)
149
150 /*
151  * In an upvars list, ALE_DEFN(ale)->resolve() is the outermost definition the
152  * name may reference. If a with block or a function that calls eval encloses
153  * the use, the name may end up referring to something else at runtime.
154  */
155 #define ALE_DEFN(ale)   ((JSDefinition *) (ale)->entry.value)
156
157 #define ALE_SET_ATOM(ale,atom)  ((ale)->entry.key = (const void *)(atom))
158 #define ALE_SET_INDEX(ale,index)((ale)->entry.value = (void *)(index))
159 #define ALE_SET_DEFN(ale, dn)   ((ale)->entry.value = (void *)(dn))
160 #define ALE_SET_VALUE(ale, v)   ((ale)->entry.value = (void *)(v))
161 #define ALE_SET_NEXT(ale,nxt)   ((ale)->entry.next = (JSHashEntry *)(nxt))
162
163 /*
164  * NB: JSAtomSet must be plain-old-data as it is embedded in the pn_u union in
165  * JSParseNode. JSAtomList encapsulates all operational uses of a JSAtomSet.
166  *
167  * The JSAtomList name is traditional, even though the implementation is a map
168  * (not to be confused with JSAtomMap). In particular the "ALE" and "ale" short
169  * names for JSAtomListElement variables roll off the fingers, compared to ASE
170  * or AME alternatives.
171  */
172 struct JSAtomSet {
173     JSHashEntry         *list;          /* literals indexed for mapping */
174     JSHashTable         *table;         /* hash table if list gets too long */
175     jsuint              count;          /* count of indexed literals */
176 };
177
178 struct JSAtomList : public JSAtomSet
179 {
180 #ifdef DEBUG
181     const JSAtomSet* set;               /* asserted null in mutating methods */
182 #endif
183
184     JSAtomList() {
185         list = NULL; table = NULL; count = 0;
186 #ifdef DEBUG
187         set = NULL;
188 #endif
189     }
190
191     JSAtomList(const JSAtomSet& as) {
192         list = as.list; table = as.table; count = as.count;
193 #ifdef DEBUG
194         set = &as;
195 #endif
196     }
197
198     void clear() { JS_ASSERT(!set); list = NULL; table = NULL; count = 0; }
199
200     JSAtomListElement *lookup(JSAtom *atom) {
201         JSHashEntry **hep;
202         return rawLookup(atom, hep);
203     }
204
205     JSAtomListElement *rawLookup(JSAtom *atom, JSHashEntry **&hep);
206
207     enum AddHow { UNIQUE, SHADOW, HOIST };
208
209     JSAtomListElement *add(js::Parser *parser, JSAtom *atom, AddHow how = UNIQUE);
210
211     void remove(js::Parser *parser, JSAtom *atom) {
212         JSHashEntry **hep;
213         JSAtomListElement *ale = rawLookup(atom, hep);
214         if (ale)
215             rawRemove(parser, ale, hep);
216     }
217
218     void rawRemove(js::Parser *parser, JSAtomListElement *ale, JSHashEntry **hep);
219 };
220
221 /*
222  * A subclass of JSAtomList with a destructor.  This atom list owns its
223  * hash table and its entries, but no keys or values.
224  */
225 struct JSAutoAtomList: public JSAtomList
226 {
227     JSAutoAtomList(js::Parser *p): parser(p) {}
228     ~JSAutoAtomList();
229   private:
230     js::Parser *parser;         /* For freeing list entries. */
231 };
232
233 /*
234  * Iterate over an atom list. We define a call operator to minimize the syntax
235  * tax for users. We do not use a more standard pattern using ++ and * because
236  * (a) it's the wrong pattern for a non-scalar; (b) it's overkill -- one method
237  * is enough. (This comment is overkill!)
238  */
239 class JSAtomListIterator {
240     JSAtomList*         list;
241     JSAtomListElement*  next;
242     uint32              index;
243
244   public:
245     JSAtomListIterator(JSAtomList* al) : list(al) { reset(); }
246
247     void reset() {
248         next = (JSAtomListElement *) list->list;
249         index = 0;
250     }
251
252     JSAtomListElement* operator ()();
253 };
254
255 struct JSAtomMap {
256     JSAtom              **vector;       /* array of ptrs to indexed atoms */
257     jsatomid            length;         /* count of (to-be-)indexed atoms */
258 };
259
260 namespace js {
261
262 #define ATOM_ENTRY_FLAG_MASK            ((size_t)(ATOM_PINNED | ATOM_INTERNED))
263
264 JS_STATIC_ASSERT(ATOM_ENTRY_FLAG_MASK < JS_GCTHING_ALIGN);
265
266 typedef uintptr_t AtomEntryType;
267
268 static JS_ALWAYS_INLINE JSAtom *
269 AtomEntryToKey(AtomEntryType entry)
270 {
271     JS_ASSERT(entry != 0);
272     return (JSAtom *)(entry & ~ATOM_ENTRY_FLAG_MASK);
273 }
274
275 struct AtomHasher
276 {
277     typedef JSLinearString *Lookup;
278
279     static HashNumber hash(JSLinearString *str) {
280         return js_HashString(str);
281     }
282
283     static bool match(AtomEntryType entry, JSLinearString *lookup) {
284         return entry ? EqualStrings(AtomEntryToKey(entry), lookup) : false;
285     }
286 };
287
288 typedef HashSet<AtomEntryType, AtomHasher, SystemAllocPolicy> AtomSet;
289
290 }  /* namespace js */
291
292 struct JSAtomState
293 {
294     js::AtomSet         atoms;
295
296 #ifdef JS_THREADSAFE
297     JSThinLock          lock;
298 #endif
299
300     /*
301      * From this point until the end of struct definition the struct must
302      * contain only JSAtom fields. We use this to access the storage occupied
303      * by the common atoms in js_FinishCommonAtoms.
304      *
305      * js_common_atom_names defined in jsatom.c contains C strings for atoms
306      * in the order of atom fields here. Therefore you must update that array
307      * if you change member order here.
308      */
309
310     /* The rt->emptyString atom, see jsstr.c's js_InitRuntimeStringState. */
311     JSAtom              *emptyAtom;
312
313     /*
314      * Literal value and type names.
315      * NB: booleanAtoms must come right before typeAtoms!
316      */
317     JSAtom              *booleanAtoms[2];
318     JSAtom              *typeAtoms[JSTYPE_LIMIT];
319     JSAtom              *nullAtom;
320
321     /* Standard class constructor or prototype names. */
322     JSAtom              *classAtoms[JSProto_LIMIT];
323
324     /* Various built-in or commonly-used atoms, pinned on first context. */
325     JSAtom              *anonymousAtom;
326     JSAtom              *applyAtom;
327     JSAtom              *argumentsAtom;
328     JSAtom              *arityAtom;
329     JSAtom              *callAtom;
330     JSAtom              *calleeAtom;
331     JSAtom              *callerAtom;
332     JSAtom              *classPrototypeAtom;
333     JSAtom              *constructorAtom;
334     JSAtom              *eachAtom;
335     JSAtom              *evalAtom;
336     JSAtom              *fileNameAtom;
337     JSAtom              *getAtom;
338     JSAtom              *globalAtom;
339     JSAtom              *ignoreCaseAtom;
340     JSAtom              *indexAtom;
341     JSAtom              *inputAtom;
342     JSAtom              *toISOStringAtom;
343     JSAtom              *iteratorAtom;
344     JSAtom              *joinAtom;
345     JSAtom              *lastIndexAtom;
346     JSAtom              *lengthAtom;
347     JSAtom              *lineNumberAtom;
348     JSAtom              *messageAtom;
349     JSAtom              *multilineAtom;
350     JSAtom              *nameAtom;
351     JSAtom              *nextAtom;
352     JSAtom              *noSuchMethodAtom;
353     JSAtom              *objectNullAtom;
354     JSAtom              *objectUndefinedAtom;
355     JSAtom              *protoAtom;
356     JSAtom              *setAtom;
357     JSAtom              *sourceAtom;
358     JSAtom              *stackAtom;
359     JSAtom              *stickyAtom;
360     JSAtom              *toGMTStringAtom;
361     JSAtom              *toLocaleStringAtom;
362     JSAtom              *toSourceAtom;
363     JSAtom              *toStringAtom;
364     JSAtom              *toUTCStringAtom;
365     JSAtom              *valueOfAtom;
366     JSAtom              *toJSONAtom;
367     JSAtom              *void0Atom;
368     JSAtom              *enumerableAtom;
369     JSAtom              *configurableAtom;
370     JSAtom              *writableAtom;
371     JSAtom              *valueAtom;
372     JSAtom              *testAtom;
373     JSAtom              *useStrictAtom;
374     JSAtom              *locAtom;
375     JSAtom              *lineAtom;
376     JSAtom              *InfinityAtom;
377     JSAtom              *NaNAtom;
378     JSAtom              *builderAtom;
379
380 #if JS_HAS_XML_SUPPORT
381     JSAtom              *etagoAtom;
382     JSAtom              *namespaceAtom;
383     JSAtom              *ptagcAtom;
384     JSAtom              *qualifierAtom;
385     JSAtom              *spaceAtom;
386     JSAtom              *stagoAtom;
387     JSAtom              *starAtom;
388     JSAtom              *starQualifierAtom;
389     JSAtom              *tagcAtom;
390     JSAtom              *xmlAtom;
391
392     /* Represents an invalid URI, for internal use only. */
393     JSAtom              *functionNamespaceURIAtom;
394 #endif
395
396     JSAtom              *ProxyAtom;
397
398     JSAtom              *getOwnPropertyDescriptorAtom;
399     JSAtom              *getPropertyDescriptorAtom;
400     JSAtom              *definePropertyAtom;
401     JSAtom              *deleteAtom;
402     JSAtom              *getOwnPropertyNamesAtom;
403     JSAtom              *enumerateAtom;
404     JSAtom              *fixAtom;
405
406     JSAtom              *hasAtom;
407     JSAtom              *hasOwnAtom;
408     JSAtom              *keysAtom;
409     JSAtom              *iterateAtom;
410
411     /* Less frequently used atoms, pinned lazily by JS_ResolveStandardClass. */
412     struct {
413         JSAtom          *XMLListAtom;
414         JSAtom          *decodeURIAtom;
415         JSAtom          *decodeURIComponentAtom;
416         JSAtom          *defineGetterAtom;
417         JSAtom          *defineSetterAtom;
418         JSAtom          *encodeURIAtom;
419         JSAtom          *encodeURIComponentAtom;
420         JSAtom          *escapeAtom;
421         JSAtom          *hasOwnPropertyAtom;
422         JSAtom          *isFiniteAtom;
423         JSAtom          *isNaNAtom;
424         JSAtom          *isPrototypeOfAtom;
425         JSAtom          *isXMLNameAtom;
426         JSAtom          *lookupGetterAtom;
427         JSAtom          *lookupSetterAtom;
428         JSAtom          *parseFloatAtom;
429         JSAtom          *parseIntAtom;
430         JSAtom          *propertyIsEnumerableAtom;
431         JSAtom          *unescapeAtom;
432         JSAtom          *unevalAtom;
433         JSAtom          *unwatchAtom;
434         JSAtom          *watchAtom;
435     } lazy;
436 };
437
438 #define ATOM(name) cx->runtime->atomState.name##Atom
439
440 #define ATOM_OFFSET_START       offsetof(JSAtomState, emptyAtom)
441 #define LAZY_ATOM_OFFSET_START  offsetof(JSAtomState, lazy)
442 #define ATOM_OFFSET_LIMIT       (sizeof(JSAtomState))
443
444 #define COMMON_ATOMS_START(state)                                             \
445     ((JSAtom **)((uint8 *)(state) + ATOM_OFFSET_START))
446 #define COMMON_ATOM_INDEX(name)                                               \
447     ((offsetof(JSAtomState, name##Atom) - ATOM_OFFSET_START)                  \
448      / sizeof(JSAtom*))
449 #define COMMON_TYPE_ATOM_INDEX(type)                                          \
450     ((offsetof(JSAtomState, typeAtoms[type]) - ATOM_OFFSET_START)             \
451      / sizeof(JSAtom*))
452
453 #define ATOM_OFFSET(name)       offsetof(JSAtomState, name##Atom)
454 #define OFFSET_TO_ATOM(rt,off)  (*(JSAtom **)((char*)&(rt)->atomState + (off)))
455 #define CLASS_ATOM_OFFSET(name) offsetof(JSAtomState,classAtoms[JSProto_##name])
456
457 #define CLASS_ATOM(cx,name) \
458     ((cx)->runtime->atomState.classAtoms[JSProto_##name])
459
460 extern const char *const js_common_atom_names[];
461 extern const size_t      js_common_atom_count;
462
463 /*
464  * Macros to access C strings for JSType and boolean literals.
465  */
466 #define JS_BOOLEAN_STR(type) (js_common_atom_names[1 + (type)])
467 #define JS_TYPE_STR(type)    (js_common_atom_names[1 + 2 + (type)])
468
469 /* Well-known predefined C strings. */
470 #define JS_PROTO(name,code,init) extern const char js_##name##_str[];
471 #include "jsproto.tbl"
472 #undef JS_PROTO
473
474 extern const char   js_anonymous_str[];
475 extern const char   js_apply_str[];
476 extern const char   js_arguments_str[];
477 extern const char   js_arity_str[];
478 extern const char   js_call_str[];
479 extern const char   js_callee_str[];
480 extern const char   js_caller_str[];
481 extern const char   js_class_prototype_str[];
482 extern const char   js_close_str[];
483 extern const char   js_constructor_str[];
484 extern const char   js_count_str[];
485 extern const char   js_etago_str[];
486 extern const char   js_each_str[];
487 extern const char   js_eval_str[];
488 extern const char   js_fileName_str[];
489 extern const char   js_get_str[];
490 extern const char   js_getter_str[];
491 extern const char   js_global_str[];
492 extern const char   js_ignoreCase_str[];
493 extern const char   js_index_str[];
494 extern const char   js_input_str[];
495 extern const char   js_iterator_str[];
496 extern const char   js_join_str[];
497 extern const char   js_lastIndex_str[];
498 extern const char   js_length_str[];
499 extern const char   js_lineNumber_str[];
500 extern const char   js_message_str[];
501 extern const char   js_multiline_str[];
502 extern const char   js_name_str[];
503 extern const char   js_namespace_str[];
504 extern const char   js_next_str[];
505 extern const char   js_noSuchMethod_str[];
506 extern const char   js_object_str[];
507 extern const char   js_proto_str[];
508 extern const char   js_ptagc_str[];
509 extern const char   js_qualifier_str[];
510 extern const char   js_send_str[];
511 extern const char   js_setter_str[];
512 extern const char   js_set_str[];
513 extern const char   js_source_str[];
514 extern const char   js_space_str[];
515 extern const char   js_stack_str[];
516 extern const char   js_sticky_str[];
517 extern const char   js_stago_str[];
518 extern const char   js_star_str[];
519 extern const char   js_starQualifier_str[];
520 extern const char   js_tagc_str[];
521 extern const char   js_toGMTString_str[];
522 extern const char   js_toLocaleString_str[];
523 extern const char   js_toSource_str[];
524 extern const char   js_toString_str[];
525 extern const char   js_toUTCString_str[];
526 extern const char   js_undefined_str[];
527 extern const char   js_valueOf_str[];
528 extern const char   js_toJSON_str[];
529 extern const char   js_xml_str[];
530 extern const char   js_enumerable_str[];
531 extern const char   js_configurable_str[];
532 extern const char   js_writable_str[];
533 extern const char   js_value_str[];
534 extern const char   js_test_str[];
535
536 /*
537  * Initialize atom state. Return true on success, false on failure to allocate
538  * memory. The caller must zero rt->atomState before calling this function and
539  * only call it after js_InitGC successfully returns.
540  */
541 extern JSBool
542 js_InitAtomState(JSRuntime *rt);
543
544 /*
545  * Free and clear atom state including any interned string atoms. This
546  * function must be called before js_FinishGC.
547  */
548 extern void
549 js_FinishAtomState(JSRuntime *rt);
550
551 /*
552  * Atom tracing and garbage collection hooks.
553  */
554
555 extern void
556 js_TraceAtomState(JSTracer *trc);
557
558 extern void
559 js_SweepAtomState(JSContext *cx);
560
561 extern JSBool
562 js_InitCommonAtoms(JSContext *cx);
563
564 extern void
565 js_FinishCommonAtoms(JSContext *cx);
566
567 /*
568  * Find or create the atom for a string. Return null on failure to allocate
569  * memory.
570  */
571 extern JSAtom *
572 js_AtomizeString(JSContext *cx, JSString *str, uintN flags);
573
574 extern JSAtom *
575 js_Atomize(JSContext *cx, const char *bytes, size_t length, uintN flags);
576
577 extern JSAtom *
578 js_AtomizeChars(JSContext *cx, const jschar *chars, size_t length, uintN flags);
579
580 /*
581  * Return an existing atom for the given char array or null if the char
582  * sequence is currently not atomized.
583  */
584 extern JSAtom *
585 js_GetExistingStringAtom(JSContext *cx, const jschar *chars, size_t length);
586
587 #ifdef DEBUG
588
589 extern JS_FRIEND_API(void)
590 js_DumpAtoms(JSContext *cx, FILE *fp);
591
592 #endif
593
594 inline bool
595 js_ValueToAtom(JSContext *cx, const js::Value &v, JSAtom **atomp);
596
597 inline bool
598 js_ValueToStringId(JSContext *cx, const js::Value &v, jsid *idp);
599
600 inline bool
601 js_InternNonIntElementId(JSContext *cx, JSObject *obj, const js::Value &idval,
602                          jsid *idp);
603 inline bool
604 js_InternNonIntElementId(JSContext *cx, JSObject *obj, const js::Value &idval,
605                          jsid *idp, js::Value *vp);
606 /*
607  * For all unmapped atoms recorded in al, add a mapping from the atom's index
608  * to its address. map->length must already be set to the number of atoms in
609  * the list and map->vector must point to pre-allocated memory.
610  */
611 extern void
612 js_InitAtomMap(JSContext *cx, JSAtomMap *map, JSAtomList *al);
613
614 #endif /* jsatom_h___ */