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 : #include <stddef.h>
44 : #include "jsversion.h"
45 : #include "jsalloc.h"
46 : #include "jsapi.h"
47 : #include "jsprvtd.h"
48 : #include "jshash.h"
49 : #include "jspubtd.h"
50 : #include "jslock.h"
51 :
52 : #include "gc/Barrier.h"
53 : #include "js/HashTable.h"
54 :
55 : struct JSIdArray {
56 : int length;
57 : js::HeapId vector[1]; /* actually, length jsid words */
58 : };
59 :
60 : /* Engine-internal extensions of jsid */
61 :
62 : static JS_ALWAYS_INLINE jsid
63 : JSID_FROM_BITS(size_t bits)
64 : {
65 : jsid id;
66 : JSID_BITS(id) = bits;
67 : return id;
68 : }
69 :
70 : static JS_ALWAYS_INLINE jsid
71 : ATOM_TO_JSID(JSAtom *atom)
72 : {
73 : JS_ASSERT(((size_t)atom & 0x7) == 0);
74 : return JSID_FROM_BITS((size_t)atom);
75 : }
76 :
77 : /* All strings stored in jsids are atomized. */
78 : static JS_ALWAYS_INLINE JSBool
79 3712 : JSID_IS_ATOM(jsid id)
80 : {
81 3712 : return JSID_IS_STRING(id);
82 : }
83 :
84 : static JS_ALWAYS_INLINE JSBool
85 : JSID_IS_ATOM(jsid id, JSAtom *atom)
86 : {
87 : return JSID_BITS(id) == JSID_BITS(ATOM_TO_JSID(atom));
88 : }
89 :
90 : static JS_ALWAYS_INLINE JSAtom *
91 3712 : JSID_TO_ATOM(jsid id)
92 : {
93 3712 : return (JSAtom *)JSID_TO_STRING(id);
94 : }
95 :
96 : extern jsid
97 : js_CheckForStringIndex(jsid id);
98 :
99 : JS_STATIC_ASSERT(sizeof(JSHashNumber) == 4);
100 : JS_STATIC_ASSERT(sizeof(jsid) == JS_BYTES_PER_WORD);
101 :
102 : namespace js {
103 :
104 : static JS_ALWAYS_INLINE JSHashNumber
105 : HashId(jsid id)
106 : {
107 : JS_ASSERT(js_CheckForStringIndex(id) == id);
108 : JSHashNumber n =
109 : #if JS_BYTES_PER_WORD == 4
110 : JSHashNumber(JSID_BITS(id));
111 : #elif JS_BYTES_PER_WORD == 8
112 : JSHashNumber(JSID_BITS(id)) ^ JSHashNumber(JSID_BITS(id) >> 32);
113 : #else
114 : # error "Unsupported configuration"
115 : #endif
116 : return n * JS_GOLDEN_RATIO;
117 : }
118 :
119 : static JS_ALWAYS_INLINE Value
120 0 : IdToValue(jsid id)
121 : {
122 0 : if (JSID_IS_STRING(id))
123 0 : return StringValue(JSID_TO_STRING(id));
124 0 : if (JS_LIKELY(JSID_IS_INT(id)))
125 0 : return Int32Value(JSID_TO_INT(id));
126 0 : if (JS_LIKELY(JSID_IS_OBJECT(id)))
127 0 : return ObjectValue(*JSID_TO_OBJECT(id));
128 0 : JS_ASSERT(JSID_IS_DEFAULT_XML_NAMESPACE(id) || JSID_IS_VOID(id));
129 0 : return UndefinedValue();
130 : }
131 :
132 : static JS_ALWAYS_INLINE jsval
133 0 : IdToJsval(jsid id)
134 : {
135 0 : return IdToValue(id);
136 : }
137 :
138 : template<>
139 : struct DefaultHasher<jsid>
140 : {
141 : typedef jsid Lookup;
142 : static HashNumber hash(const Lookup &l) {
143 : JS_ASSERT(l == js_CheckForStringIndex(l));
144 : return HashNumber(JSID_BITS(l));
145 : }
146 : static bool match(const jsid &id, const Lookup &l) {
147 : JS_ASSERT(l == js_CheckForStringIndex(l));
148 : return id == l;
149 : }
150 : };
151 :
152 : }
153 :
154 : #if JS_BYTES_PER_WORD == 4
155 : # define ATOM_HASH(atom) ((JSHashNumber)(atom) >> 2)
156 : #elif JS_BYTES_PER_WORD == 8
157 : # define ATOM_HASH(atom) (((JSHashNumber)(uintptr_t)(atom) >> 3) ^ \
158 : (JSHashNumber)((uintptr_t)(atom) >> 32))
159 : #else
160 : # error "Unsupported configuration"
161 : #endif
162 :
163 : /*
164 : * Return a printable, lossless char[] representation of a string-type atom.
165 : * The lifetime of the result matches the lifetime of bytes.
166 : */
167 : extern const char *
168 : js_AtomToPrintableString(JSContext *cx, JSAtom *atom, JSAutoByteString *bytes);
169 :
170 : namespace js {
171 :
172 : /* Compute a hash function from chars/length. */
173 : inline uint32_t
174 : HashChars(const jschar *chars, size_t length)
175 : {
176 : uint32_t h = 0;
177 : for (; length; chars++, length--)
178 : h = JS_ROTATE_LEFT32(h, 4) ^ *chars;
179 : return h;
180 : }
181 :
182 : class AtomStateEntry
183 : {
184 : uintptr_t bits;
185 :
186 : static const uintptr_t NO_TAG_MASK = uintptr_t(-1) - 1;
187 :
188 : public:
189 : AtomStateEntry() : bits(0) {}
190 : AtomStateEntry(const AtomStateEntry &other) : bits(other.bits) {}
191 : AtomStateEntry(JSAtom *ptr, bool tagged)
192 : : bits(uintptr_t(ptr) | uintptr_t(tagged))
193 : {
194 : JS_ASSERT((uintptr_t(ptr) & 0x1) == 0);
195 : }
196 :
197 : bool isTagged() const {
198 : return bits & 0x1;
199 : }
200 :
201 : /*
202 : * Non-branching code sequence. Note that the const_cast is safe because
203 : * the hash function doesn't consider the tag to be a portion of the key.
204 : */
205 : void setTagged(bool enabled) const {
206 : const_cast<AtomStateEntry *>(this)->bits |= uintptr_t(enabled);
207 : }
208 :
209 : JSAtom *asPtr() const;
210 : };
211 :
212 : struct AtomHasher
213 : {
214 : struct Lookup
215 : {
216 : const jschar *chars;
217 : size_t length;
218 : const JSAtom *atom; /* Optional. */
219 :
220 : Lookup(const jschar *chars, size_t length) : chars(chars), length(length), atom(NULL) {}
221 : inline Lookup(const JSAtom *atom);
222 : };
223 :
224 : static HashNumber hash(const Lookup &l) { return HashChars(l.chars, l.length); }
225 : static inline bool match(const AtomStateEntry &entry, const Lookup &lookup);
226 : };
227 :
228 : typedef HashSet<AtomStateEntry, AtomHasher, SystemAllocPolicy> AtomSet;
229 :
230 : /*
231 : * On encodings:
232 : *
233 : * - Some string functions have an optional FlationCoding argument that allow
234 : * the caller to force CESU-8 encoding handling.
235 : * - Functions that don't take a FlationCoding base their NormalEncoding
236 : * behavior on the js_CStringsAreUTF8 value. NormalEncoding is either raw
237 : * (simple zero-extension) or UTF-8 depending on js_CStringsAreUTF8.
238 : * - Functions that explicitly state their encoding do not use the
239 : * js_CStringsAreUTF8 value.
240 : *
241 : * CESU-8 (Compatibility Encoding Scheme for UTF-16: 8-bit) is a variant of
242 : * UTF-8 that allows us to store any wide character string as a narrow
243 : * character string. For strings containing mostly ascii, it saves space.
244 : * http://www.unicode.org/reports/tr26/
245 : */
246 :
247 : enum FlationCoding
248 : {
249 : NormalEncoding,
250 : CESU8Encoding
251 : };
252 :
253 : class PropertyName;
254 :
255 : } /* namespace js */
256 :
257 : struct JSAtomState
258 : {
259 : js::AtomSet atoms;
260 :
261 : /*
262 : * From this point until the end of struct definition the struct must
263 : * contain only js::PropertyName fields. We use this to access the storage
264 : * occupied by the common atoms in js_FinishCommonAtoms.
265 : *
266 : * js_common_atom_names defined in jsatom.cpp contains C strings for atoms
267 : * in the order of atom fields here. Therefore you must update that array
268 : * if you change member order here.
269 : */
270 :
271 : /* The rt->emptyString atom, see jsstr.c's js_InitRuntimeStringState. */
272 : js::PropertyName *emptyAtom;
273 :
274 : /*
275 : * Literal value and type names.
276 : * NB: booleanAtoms must come right before typeAtoms!
277 : */
278 : js::PropertyName *booleanAtoms[2];
279 : js::PropertyName *typeAtoms[JSTYPE_LIMIT];
280 : js::PropertyName *nullAtom;
281 :
282 : /* Standard class constructor or prototype names. */
283 : js::PropertyName *classAtoms[JSProto_LIMIT];
284 :
285 : /* Various built-in or commonly-used atoms, pinned on first context. */
286 : js::PropertyName *anonymousAtom;
287 : js::PropertyName *applyAtom;
288 : js::PropertyName *argumentsAtom;
289 : js::PropertyName *arityAtom;
290 : js::PropertyName *BYTES_PER_ELEMENTAtom;
291 : js::PropertyName *callAtom;
292 : js::PropertyName *calleeAtom;
293 : js::PropertyName *callerAtom;
294 : js::PropertyName *classPrototypeAtom;
295 : js::PropertyName *constructorAtom;
296 : js::PropertyName *eachAtom;
297 : js::PropertyName *evalAtom;
298 : js::PropertyName *fileNameAtom;
299 : js::PropertyName *getAtom;
300 : js::PropertyName *globalAtom;
301 : js::PropertyName *ignoreCaseAtom;
302 : js::PropertyName *indexAtom;
303 : js::PropertyName *inputAtom;
304 : js::PropertyName *toISOStringAtom;
305 : js::PropertyName *iteratorAtom;
306 : js::PropertyName *joinAtom;
307 : js::PropertyName *lastIndexAtom;
308 : js::PropertyName *lengthAtom;
309 : js::PropertyName *lineNumberAtom;
310 : js::PropertyName *messageAtom;
311 : js::PropertyName *multilineAtom;
312 : js::PropertyName *nameAtom;
313 : js::PropertyName *nextAtom;
314 : js::PropertyName *noSuchMethodAtom;
315 : js::PropertyName *objectNullAtom;
316 : js::PropertyName *objectUndefinedAtom;
317 : js::PropertyName *ofAtom;
318 : js::PropertyName *protoAtom;
319 : js::PropertyName *setAtom;
320 : js::PropertyName *sourceAtom;
321 : js::PropertyName *stackAtom;
322 : js::PropertyName *stickyAtom;
323 : js::PropertyName *toGMTStringAtom;
324 : js::PropertyName *toLocaleStringAtom;
325 : js::PropertyName *toSourceAtom;
326 : js::PropertyName *toStringAtom;
327 : js::PropertyName *toUTCStringAtom;
328 : js::PropertyName *valueOfAtom;
329 : js::PropertyName *toJSONAtom;
330 : js::PropertyName *void0Atom;
331 : js::PropertyName *enumerableAtom;
332 : js::PropertyName *configurableAtom;
333 : js::PropertyName *writableAtom;
334 : js::PropertyName *valueAtom;
335 : js::PropertyName *testAtom;
336 : js::PropertyName *useStrictAtom;
337 : js::PropertyName *locAtom;
338 : js::PropertyName *lineAtom;
339 : js::PropertyName *InfinityAtom;
340 : js::PropertyName *NaNAtom;
341 : js::PropertyName *builderAtom;
342 :
343 : #if JS_HAS_XML_SUPPORT
344 : js::PropertyName *etagoAtom;
345 : js::PropertyName *namespaceAtom;
346 : js::PropertyName *ptagcAtom;
347 : js::PropertyName *qualifierAtom;
348 : js::PropertyName *spaceAtom;
349 : js::PropertyName *stagoAtom;
350 : js::PropertyName *starAtom;
351 : js::PropertyName *starQualifierAtom;
352 : js::PropertyName *tagcAtom;
353 : js::PropertyName *xmlAtom;
354 :
355 : /* Represents an invalid URI, for internal use only. */
356 : js::PropertyName *functionNamespaceURIAtom;
357 : #endif
358 :
359 : js::PropertyName *ProxyAtom;
360 :
361 : js::PropertyName *getOwnPropertyDescriptorAtom;
362 : js::PropertyName *getPropertyDescriptorAtom;
363 : js::PropertyName *definePropertyAtom;
364 : js::PropertyName *deleteAtom;
365 : js::PropertyName *getOwnPropertyNamesAtom;
366 : js::PropertyName *enumerateAtom;
367 : js::PropertyName *fixAtom;
368 :
369 : js::PropertyName *hasAtom;
370 : js::PropertyName *hasOwnAtom;
371 : js::PropertyName *keysAtom;
372 : js::PropertyName *iterateAtom;
373 :
374 : js::PropertyName *WeakMapAtom;
375 :
376 : js::PropertyName *byteLengthAtom;
377 :
378 : js::PropertyName *returnAtom;
379 : js::PropertyName *throwAtom;
380 :
381 : /* Less frequently used atoms, pinned lazily by JS_ResolveStandardClass. */
382 : struct {
383 : js::PropertyName *XMLListAtom;
384 : js::PropertyName *decodeURIAtom;
385 : js::PropertyName *decodeURIComponentAtom;
386 : js::PropertyName *defineGetterAtom;
387 : js::PropertyName *defineSetterAtom;
388 : js::PropertyName *encodeURIAtom;
389 : js::PropertyName *encodeURIComponentAtom;
390 : js::PropertyName *escapeAtom;
391 : js::PropertyName *hasOwnPropertyAtom;
392 : js::PropertyName *isFiniteAtom;
393 : js::PropertyName *isNaNAtom;
394 : js::PropertyName *isPrototypeOfAtom;
395 : js::PropertyName *isXMLNameAtom;
396 : js::PropertyName *lookupGetterAtom;
397 : js::PropertyName *lookupSetterAtom;
398 : js::PropertyName *parseFloatAtom;
399 : js::PropertyName *parseIntAtom;
400 : js::PropertyName *propertyIsEnumerableAtom;
401 : js::PropertyName *unescapeAtom;
402 : js::PropertyName *unevalAtom;
403 : js::PropertyName *unwatchAtom;
404 : js::PropertyName *watchAtom;
405 : } lazy;
406 :
407 : static const size_t commonAtomsOffset;
408 : static const size_t lazyAtomsOffset;
409 :
410 : void clearLazyAtoms() {
411 : memset(&lazy, 0, sizeof(lazy));
412 : }
413 :
414 : void junkAtoms() {
415 : #ifdef DEBUG
416 : memset(commonAtomsStart(), JS_FREE_PATTERN, sizeof(*this) - commonAtomsOffset);
417 : #endif
418 : }
419 :
420 : JSAtom **commonAtomsStart() {
421 : return reinterpret_cast<JSAtom **>(&emptyAtom);
422 : }
423 :
424 : void checkStaticInvariants();
425 : };
426 :
427 : extern bool
428 : AtomIsInterned(JSContext *cx, JSAtom *atom);
429 :
430 : #define ATOM(name) cx->runtime->atomState.name##Atom
431 :
432 : #define COMMON_ATOM_INDEX(name) \
433 : ((offsetof(JSAtomState, name##Atom) - JSAtomState::commonAtomsOffset) \
434 : / sizeof(JSAtom*))
435 : #define COMMON_TYPE_ATOM_INDEX(type) \
436 : ((offsetof(JSAtomState, typeAtoms[type]) - JSAtomState::commonAtomsOffset)\
437 : / sizeof(JSAtom*))
438 :
439 : #define ATOM_OFFSET(name) offsetof(JSAtomState, name##Atom)
440 : #define OFFSET_TO_ATOM(rt,off) (*(JSAtom **)((char*)&(rt)->atomState + (off)))
441 : #define CLASS_ATOM_OFFSET(name) offsetof(JSAtomState, classAtoms[JSProto_##name])
442 : #define CLASS_ATOM(cx,name) ((cx)->runtime->atomState.classAtoms[JSProto_##name])
443 :
444 : extern const char *const js_common_atom_names[];
445 : extern const size_t js_common_atom_count;
446 :
447 : /*
448 : * Macros to access C strings for JSType and boolean literals.
449 : */
450 : #define JS_BOOLEAN_STR(type) (js_common_atom_names[1 + (type)])
451 : #define JS_TYPE_STR(type) (js_common_atom_names[1 + 2 + (type)])
452 :
453 : /* Well-known predefined C strings. */
454 : #define JS_PROTO(name,code,init) extern const char js_##name##_str[];
455 : #include "jsproto.tbl"
456 : #undef JS_PROTO
457 :
458 : extern const char js_anonymous_str[];
459 : extern const char js_apply_str[];
460 : extern const char js_arguments_str[];
461 : extern const char js_arity_str[];
462 : extern const char js_BYTES_PER_ELEMENT_str[];
463 : extern const char js_call_str[];
464 : extern const char js_callee_str[];
465 : extern const char js_caller_str[];
466 : extern const char js_class_prototype_str[];
467 : extern const char js_close_str[];
468 : extern const char js_constructor_str[];
469 : extern const char js_count_str[];
470 : extern const char js_etago_str[];
471 : extern const char js_each_str[];
472 : extern const char js_eval_str[];
473 : extern const char js_fileName_str[];
474 : extern const char js_get_str[];
475 : extern const char js_getter_str[];
476 : extern const char js_global_str[];
477 : extern const char js_ignoreCase_str[];
478 : extern const char js_index_str[];
479 : extern const char js_input_str[];
480 : extern const char js_iterator_str[];
481 : extern const char js_join_str[];
482 : extern const char js_lastIndex_str[];
483 : extern const char js_length_str[];
484 : extern const char js_lineNumber_str[];
485 : extern const char js_message_str[];
486 : extern const char js_multiline_str[];
487 : extern const char js_name_str[];
488 : extern const char js_namespace_str[];
489 : extern const char js_next_str[];
490 : extern const char js_noSuchMethod_str[];
491 : extern const char js_object_str[];
492 : extern const char js_proto_str[];
493 : extern const char js_ptagc_str[];
494 : extern const char js_qualifier_str[];
495 : extern const char js_send_str[];
496 : extern const char js_setter_str[];
497 : extern const char js_set_str[];
498 : extern const char js_source_str[];
499 : extern const char js_space_str[];
500 : extern const char js_stack_str[];
501 : extern const char js_sticky_str[];
502 : extern const char js_stago_str[];
503 : extern const char js_star_str[];
504 : extern const char js_starQualifier_str[];
505 : extern const char js_tagc_str[];
506 : extern const char js_toGMTString_str[];
507 : extern const char js_toLocaleString_str[];
508 : extern const char js_toSource_str[];
509 : extern const char js_toString_str[];
510 : extern const char js_toUTCString_str[];
511 : extern const char js_undefined_str[];
512 : extern const char js_valueOf_str[];
513 : extern const char js_toJSON_str[];
514 : extern const char js_xml_str[];
515 : extern const char js_enumerable_str[];
516 : extern const char js_configurable_str[];
517 : extern const char js_writable_str[];
518 : extern const char js_value_str[];
519 : extern const char js_test_str[];
520 :
521 : /*
522 : * Initialize atom state. Return true on success, false on failure to allocate
523 : * memory. The caller must zero rt->atomState before calling this function and
524 : * only call it after js_InitGC successfully returns.
525 : */
526 : extern JSBool
527 : js_InitAtomState(JSRuntime *rt);
528 :
529 : /*
530 : * Free and clear atom state including any interned string atoms. This
531 : * function must be called before js_FinishGC.
532 : */
533 : extern void
534 : js_FinishAtomState(JSRuntime *rt);
535 :
536 : /*
537 : * Atom tracing and garbage collection hooks.
538 : */
539 :
540 : extern void
541 : js_TraceAtomState(JSTracer *trc);
542 :
543 : extern void
544 : js_SweepAtomState(JSRuntime *rt);
545 :
546 : extern bool
547 : js_InitCommonAtoms(JSContext *cx);
548 :
549 : extern void
550 : js_FinishCommonAtoms(JSContext *cx);
551 :
552 : namespace js {
553 :
554 : /* N.B. must correspond to boolean tagging behavior. */
555 : enum InternBehavior
556 : {
557 : DoNotInternAtom = false,
558 : InternAtom = true
559 : };
560 :
561 : } /* namespace js */
562 :
563 : extern JSAtom *
564 : js_Atomize(JSContext *cx, const char *bytes, size_t length,
565 : js::InternBehavior ib = js::DoNotInternAtom,
566 : js::FlationCoding fc = js::NormalEncoding);
567 :
568 : extern JSAtom *
569 : js_AtomizeChars(JSContext *cx, const jschar *chars, size_t length,
570 : js::InternBehavior ib = js::DoNotInternAtom);
571 :
572 : extern JSAtom *
573 : js_AtomizeString(JSContext *cx, JSString *str, js::InternBehavior ib = js::DoNotInternAtom);
574 :
575 : /*
576 : * Return an existing atom for the given char array or null if the char
577 : * sequence is currently not atomized.
578 : */
579 : extern JSAtom *
580 : js_GetExistingStringAtom(JSContext *cx, const jschar *chars, size_t length);
581 :
582 : #ifdef DEBUG
583 :
584 : extern JS_FRIEND_API(void)
585 : js_DumpAtoms(JSContext *cx, FILE *fp);
586 :
587 : #endif
588 :
589 : inline bool
590 : js_ValueToAtom(JSContext *cx, const js::Value &v, JSAtom **atomp);
591 :
592 : inline bool
593 : js_ValueToStringId(JSContext *cx, const js::Value &v, jsid *idp);
594 :
595 : inline bool
596 : js_InternNonIntElementId(JSContext *cx, JSObject *obj, const js::Value &idval,
597 : jsid *idp);
598 : inline bool
599 : js_InternNonIntElementId(JSContext *cx, JSObject *obj, const js::Value &idval,
600 : jsid *idp, js::Value *vp);
601 :
602 : /*
603 : * For all unmapped atoms recorded in al, add a mapping from the atom's index
604 : * to its address. map->length must already be set to the number of atoms in
605 : * the list and map->vector must point to pre-allocated memory.
606 : */
607 : extern void
608 : js_InitAtomMap(JSContext *cx, js::AtomIndexMap *indices, JSAtom **atoms);
609 :
610 : #endif /* jsatom_h___ */
|