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 "jstypes.h" |
48 |
#include "jshash.h" /* Added by JSIFY */ |
49 |
#include "jsdhash.h" |
50 |
#include "jsapi.h" |
51 |
#include "jsprvtd.h" |
52 |
#include "jspubtd.h" |
53 |
#include "jslock.h" |
54 |
|
55 |
JS_BEGIN_EXTERN_C |
56 |
|
57 |
#define ATOM_PINNED 0x1 /* atom is pinned against GC */ |
58 |
#define ATOM_INTERNED 0x2 /* pinned variant for JS_Intern* API */ |
59 |
#define ATOM_NOCOPY 0x4 /* don't copy atom string bytes */ |
60 |
#define ATOM_TMPSTR 0x8 /* internal, to avoid extra string */ |
61 |
|
62 |
#define ATOM_KEY(atom) ((jsval)(atom)) |
63 |
#define ATOM_IS_DOUBLE(atom) JSVAL_IS_DOUBLE(ATOM_KEY(atom)) |
64 |
#define ATOM_TO_DOUBLE(atom) JSVAL_TO_DOUBLE(ATOM_KEY(atom)) |
65 |
#define ATOM_IS_STRING(atom) JSVAL_IS_STRING(ATOM_KEY(atom)) |
66 |
#define ATOM_TO_STRING(atom) JSVAL_TO_STRING(ATOM_KEY(atom)) |
67 |
|
68 |
JS_STATIC_ASSERT(sizeof(JSHashNumber) == 4); |
69 |
JS_STATIC_ASSERT(sizeof(JSAtom *) == JS_BYTES_PER_WORD); |
70 |
|
71 |
#if JS_BYTES_PER_WORD == 4 |
72 |
# define ATOM_HASH(atom) ((JSHashNumber)(atom) >> 2) |
73 |
#elif JS_BYTES_PER_WORD == 8 |
74 |
# define ATOM_HASH(atom) (((JSHashNumber)(jsuword)(atom) >> 3) ^ \ |
75 |
(JSHashNumber)((jsuword)(atom) >> 32)) |
76 |
#else |
77 |
# error "Unsupported configuration" |
78 |
#endif |
79 |
|
80 |
/* |
81 |
* Return a printable, lossless char[] representation of a string-type atom. |
82 |
* The lifetime of the result extends at least until the next GC activation, |
83 |
* longer if cx's string newborn root is not overwritten. |
84 |
*/ |
85 |
extern const char * |
86 |
js_AtomToPrintableString(JSContext *cx, JSAtom *atom); |
87 |
|
88 |
struct JSAtomListElement { |
89 |
JSHashEntry entry; |
90 |
}; |
91 |
|
92 |
#define ALE_ATOM(ale) ((JSAtom *) (ale)->entry.key) |
93 |
#define ALE_INDEX(ale) ((jsatomid) JS_PTR_TO_UINT32((ale)->entry.value)) |
94 |
#define ALE_JSOP(ale) ((JSOp) JS_PTR_TO_UINT32((ale)->entry.value)) |
95 |
#define ALE_VALUE(ale) ((jsval) (ale)->entry.value) |
96 |
#define ALE_NEXT(ale) ((JSAtomListElement *) (ale)->entry.next) |
97 |
|
98 |
#define ALE_SET_ATOM(ale,atom) ((ale)->entry.key = (const void *)(atom)) |
99 |
#define ALE_SET_INDEX(ale,index)((ale)->entry.value = JS_UINT32_TO_PTR(index)) |
100 |
#define ALE_SET_JSOP(ale,op) ((ale)->entry.value = JS_UINT32_TO_PTR(op)) |
101 |
#define ALE_SET_VALUE(ale, v) ((ale)->entry.value = (void *)(v)) |
102 |
|
103 |
struct JSAtomList { |
104 |
JSHashEntry *list; /* literals indexed for mapping */ |
105 |
JSHashTable *table; /* hash table if list gets too long */ |
106 |
jsuint count; /* count of indexed literals */ |
107 |
}; |
108 |
|
109 |
#define ATOM_LIST_INIT(al) ((al)->list = NULL, (al)->table = NULL, \ |
110 |
(al)->count = 0) |
111 |
|
112 |
#define ATOM_LIST_SEARCH(_ale,_al,_atom) \ |
113 |
JS_BEGIN_MACRO \ |
114 |
JSHashEntry **_hep; \ |
115 |
ATOM_LIST_LOOKUP(_ale, _hep, _al, _atom); \ |
116 |
JS_END_MACRO |
117 |
|
118 |
#define ATOM_LIST_LOOKUP(_ale,_hep,_al,_atom) \ |
119 |
JS_BEGIN_MACRO \ |
120 |
if ((_al)->table) { \ |
121 |
_hep = JS_HashTableRawLookup((_al)->table, ATOM_HASH(_atom), \ |
122 |
_atom); \ |
123 |
_ale = *_hep ? (JSAtomListElement *) *_hep : NULL; \ |
124 |
} else { \ |
125 |
JSHashEntry **_alep = &(_al)->list; \ |
126 |
_hep = NULL; \ |
127 |
while ((_ale = (JSAtomListElement *)*_alep) != NULL) { \ |
128 |
if (ALE_ATOM(_ale) == (_atom)) { \ |
129 |
/* Hit, move atom's element to the front of the list. */ \ |
130 |
*_alep = (_ale)->entry.next; \ |
131 |
(_ale)->entry.next = (_al)->list; \ |
132 |
(_al)->list = &_ale->entry; \ |
133 |
break; \ |
134 |
} \ |
135 |
_alep = &_ale->entry.next; \ |
136 |
} \ |
137 |
} \ |
138 |
JS_END_MACRO |
139 |
|
140 |
struct JSAtomMap { |
141 |
JSAtom **vector; /* array of ptrs to indexed atoms */ |
142 |
jsatomid length; /* count of (to-be-)indexed atoms */ |
143 |
}; |
144 |
|
145 |
struct JSAtomState { |
146 |
JSDHashTable stringAtoms; /* hash table with shared strings */ |
147 |
JSDHashTable doubleAtoms; /* hash table with shared doubles */ |
148 |
#ifdef JS_THREADSAFE |
149 |
JSThinLock lock; |
150 |
#endif |
151 |
|
152 |
/* |
153 |
* From this point until the end of struct definition the struct must |
154 |
* contain only JSAtom fields. We use this to access the storage occupied |
155 |
* by the common atoms in js_FinishCommonAtoms. |
156 |
* |
157 |
* js_common_atom_names defined in jsatom.c contains C strings for atoms |
158 |
* in the order of atom fields here. Therefore you must update that array |
159 |
* if you change member order here. |
160 |
*/ |
161 |
|
162 |
/* The rt->emptyString atom, see jsstr.c's js_InitRuntimeStringState. */ |
163 |
JSAtom *emptyAtom; |
164 |
|
165 |
/* |
166 |
* Literal value and type names. |
167 |
* NB: booleanAtoms must come right before typeAtoms! |
168 |
*/ |
169 |
JSAtom *booleanAtoms[2]; |
170 |
JSAtom *typeAtoms[JSTYPE_LIMIT]; |
171 |
JSAtom *nullAtom; |
172 |
|
173 |
/* Standard class constructor or prototype names. */ |
174 |
JSAtom *classAtoms[JSProto_LIMIT]; |
175 |
|
176 |
/* Various built-in or commonly-used atoms, pinned on first context. */ |
177 |
JSAtom *anonymousAtom; |
178 |
JSAtom *applyAtom; |
179 |
JSAtom *argumentsAtom; |
180 |
JSAtom *arityAtom; |
181 |
JSAtom *callAtom; |
182 |
JSAtom *calleeAtom; |
183 |
JSAtom *callerAtom; |
184 |
JSAtom *classPrototypeAtom; |
185 |
JSAtom *constructorAtom; |
186 |
JSAtom *countAtom; |
187 |
JSAtom *eachAtom; |
188 |
JSAtom *evalAtom; |
189 |
JSAtom *fileNameAtom; |
190 |
JSAtom *getAtom; |
191 |
JSAtom *getterAtom; |
192 |
JSAtom *indexAtom; |
193 |
JSAtom *inputAtom; |
194 |
JSAtom *iteratorAtom; |
195 |
JSAtom *lengthAtom; |
196 |
JSAtom *lineNumberAtom; |
197 |
JSAtom *messageAtom; |
198 |
JSAtom *nameAtom; |
199 |
JSAtom *nextAtom; |
200 |
JSAtom *noSuchMethodAtom; |
201 |
JSAtom *parentAtom; |
202 |
JSAtom *protoAtom; |
203 |
JSAtom *setAtom; |
204 |
JSAtom *setterAtom; |
205 |
JSAtom *stackAtom; |
206 |
JSAtom *toLocaleStringAtom; |
207 |
JSAtom *toSourceAtom; |
208 |
JSAtom *toStringAtom; |
209 |
JSAtom *valueOfAtom; |
210 |
JSAtom *toJSONAtom; |
211 |
JSAtom *void0Atom; |
212 |
|
213 |
#if JS_HAS_XML_SUPPORT |
214 |
JSAtom *etagoAtom; |
215 |
JSAtom *namespaceAtom; |
216 |
JSAtom *ptagcAtom; |
217 |
JSAtom *qualifierAtom; |
218 |
JSAtom *spaceAtom; |
219 |
JSAtom *stagoAtom; |
220 |
JSAtom *starAtom; |
221 |
JSAtom *starQualifierAtom; |
222 |
JSAtom *tagcAtom; |
223 |
JSAtom *xmlAtom; |
224 |
#endif |
225 |
|
226 |
#ifdef NARCISSUS |
227 |
JSAtom *__call__Atom; |
228 |
JSAtom *__construct__Atom; |
229 |
JSAtom *__hasInstance__Atom; |
230 |
JSAtom *ExecutionContextAtom; |
231 |
JSAtom *currentAtom; |
232 |
#endif |
233 |
|
234 |
/* Less frequently used atoms, pinned lazily by JS_ResolveStandardClass. */ |
235 |
struct { |
236 |
JSAtom *InfinityAtom; |
237 |
JSAtom *NaNAtom; |
238 |
JSAtom *XMLListAtom; |
239 |
JSAtom *decodeURIAtom; |
240 |
JSAtom *decodeURIComponentAtom; |
241 |
JSAtom *defineGetterAtom; |
242 |
JSAtom *defineSetterAtom; |
243 |
JSAtom *encodeURIAtom; |
244 |
JSAtom *encodeURIComponentAtom; |
245 |
JSAtom *escapeAtom; |
246 |
JSAtom *functionNamespaceURIAtom; |
247 |
JSAtom *hasOwnPropertyAtom; |
248 |
JSAtom *isFiniteAtom; |
249 |
JSAtom *isNaNAtom; |
250 |
JSAtom *isPrototypeOfAtom; |
251 |
JSAtom *isXMLNameAtom; |
252 |
JSAtom *lookupGetterAtom; |
253 |
JSAtom *lookupSetterAtom; |
254 |
JSAtom *parseFloatAtom; |
255 |
JSAtom *parseIntAtom; |
256 |
JSAtom *propertyIsEnumerableAtom; |
257 |
JSAtom *unescapeAtom; |
258 |
JSAtom *unevalAtom; |
259 |
JSAtom *unwatchAtom; |
260 |
JSAtom *watchAtom; |
261 |
} lazy; |
262 |
}; |
263 |
|
264 |
#define ATOM_OFFSET_START offsetof(JSAtomState, emptyAtom) |
265 |
#define LAZY_ATOM_OFFSET_START offsetof(JSAtomState, lazy) |
266 |
#define ATOM_OFFSET_LIMIT (sizeof(JSAtomState)) |
267 |
|
268 |
#define COMMON_ATOMS_START(state) \ |
269 |
((JSAtom **)((uint8 *)(state) + ATOM_OFFSET_START)) |
270 |
#define COMMON_ATOM_INDEX(name) \ |
271 |
((offsetof(JSAtomState, name##Atom) - ATOM_OFFSET_START) \ |
272 |
/ sizeof(JSAtom*)) |
273 |
#define COMMON_TYPE_ATOM_INDEX(type) \ |
274 |
((offsetof(JSAtomState, typeAtoms[type]) - ATOM_OFFSET_START) \ |
275 |
/ sizeof(JSAtom*)) |
276 |
|
277 |
/* Start and limit offsets should correspond to atoms. */ |
278 |
JS_STATIC_ASSERT(ATOM_OFFSET_START % sizeof(JSAtom *) == 0); |
279 |
JS_STATIC_ASSERT(ATOM_OFFSET_LIMIT % sizeof(JSAtom *) == 0); |
280 |
|
281 |
#define ATOM_OFFSET(name) offsetof(JSAtomState, name##Atom) |
282 |
#define OFFSET_TO_ATOM(rt,off) (*(JSAtom **)((char*)&(rt)->atomState + (off))) |
283 |
#define CLASS_ATOM_OFFSET(name) offsetof(JSAtomState,classAtoms[JSProto_##name]) |
284 |
|
285 |
#define CLASS_ATOM(cx,name) \ |
286 |
((cx)->runtime->atomState.classAtoms[JSProto_##name]) |
287 |
|
288 |
extern const char *const js_common_atom_names[]; |
289 |
extern const size_t js_common_atom_count; |
290 |
|
291 |
/* |
292 |
* Macros to access C strings for JSType and boolean literals together with |
293 |
* checks that boolean names start from index 1 and type names from 1+2. |
294 |
*/ |
295 |
#define JS_BOOLEAN_STR(type) (js_common_atom_names[1 + (type)]) |
296 |
#define JS_TYPE_STR(type) (js_common_atom_names[1 + 2 + (type)]) |
297 |
|
298 |
JS_STATIC_ASSERT(1 * sizeof(JSAtom *) == |
299 |
offsetof(JSAtomState, booleanAtoms) - ATOM_OFFSET_START); |
300 |
JS_STATIC_ASSERT((1 + 2) * sizeof(JSAtom *) == |
301 |
offsetof(JSAtomState, typeAtoms) - ATOM_OFFSET_START); |
302 |
|
303 |
/* Well-known predefined C strings. */ |
304 |
#define JS_PROTO(name,code,init) extern const char js_##name##_str[]; |
305 |
#include "jsproto.tbl" |
306 |
#undef JS_PROTO |
307 |
|
308 |
extern const char js_anonymous_str[]; |
309 |
extern const char js_apply_str[]; |
310 |
extern const char js_arguments_str[]; |
311 |
extern const char js_arity_str[]; |
312 |
extern const char js_call_str[]; |
313 |
extern const char js_callee_str[]; |
314 |
extern const char js_caller_str[]; |
315 |
extern const char js_class_prototype_str[]; |
316 |
extern const char js_close_str[]; |
317 |
extern const char js_constructor_str[]; |
318 |
extern const char js_count_str[]; |
319 |
extern const char js_etago_str[]; |
320 |
extern const char js_each_str[]; |
321 |
extern const char js_eval_str[]; |
322 |
extern const char js_fileName_str[]; |
323 |
extern const char js_get_str[]; |
324 |
extern const char js_getter_str[]; |
325 |
extern const char js_index_str[]; |
326 |
extern const char js_input_str[]; |
327 |
extern const char js_iterator_str[]; |
328 |
extern const char js_length_str[]; |
329 |
extern const char js_lineNumber_str[]; |
330 |
extern const char js_message_str[]; |
331 |
extern const char js_name_str[]; |
332 |
extern const char js_namespace_str[]; |
333 |
extern const char js_next_str[]; |
334 |
extern const char js_noSuchMethod_str[]; |
335 |
extern const char js_object_str[]; |
336 |
extern const char js_parent_str[]; |
337 |
extern const char js_proto_str[]; |
338 |
extern const char js_ptagc_str[]; |
339 |
extern const char js_qualifier_str[]; |
340 |
extern const char js_send_str[]; |
341 |
extern const char js_setter_str[]; |
342 |
extern const char js_set_str[]; |
343 |
extern const char js_space_str[]; |
344 |
extern const char js_stack_str[]; |
345 |
extern const char js_stago_str[]; |
346 |
extern const char js_star_str[]; |
347 |
extern const char js_starQualifier_str[]; |
348 |
extern const char js_tagc_str[]; |
349 |
extern const char js_toSource_str[]; |
350 |
extern const char js_toString_str[]; |
351 |
extern const char js_toLocaleString_str[]; |
352 |
extern const char js_undefined_str[]; |
353 |
extern const char js_valueOf_str[]; |
354 |
extern const char js_toJSON_str[]; |
355 |
extern const char js_xml_str[]; |
356 |
|
357 |
#ifdef NARCISSUS |
358 |
extern const char js___call___str[]; |
359 |
extern const char js___construct___str[]; |
360 |
extern const char js___hasInstance___str[]; |
361 |
extern const char js_ExecutionContext_str[]; |
362 |
extern const char js_current_str[]; |
363 |
#endif |
364 |
|
365 |
/* |
366 |
* Initialize atom state. Return true on success, false on failure to allocate |
367 |
* memory. The caller must zero rt->atomState before calling this function and |
368 |
* only call it after js_InitGC successfully returns. |
369 |
*/ |
370 |
extern JSBool |
371 |
js_InitAtomState(JSRuntime *rt); |
372 |
|
373 |
/* |
374 |
* Free and clear atom state including any interned string atoms. This |
375 |
* function must be called before js_FinishGC. |
376 |
*/ |
377 |
extern void |
378 |
js_FinishAtomState(JSRuntime *rt); |
379 |
|
380 |
/* |
381 |
* Atom tracing and garbage collection hooks. |
382 |
*/ |
383 |
|
384 |
extern void |
385 |
js_TraceAtomState(JSTracer *trc, JSBool allAtoms); |
386 |
|
387 |
extern void |
388 |
js_SweepAtomState(JSContext *cx); |
389 |
|
390 |
extern JSBool |
391 |
js_InitCommonAtoms(JSContext *cx); |
392 |
|
393 |
extern void |
394 |
js_FinishCommonAtoms(JSContext *cx); |
395 |
|
396 |
/* |
397 |
* Find or create the atom for a double value. Return null on failure to |
398 |
* allocate memory. |
399 |
*/ |
400 |
extern JSAtom * |
401 |
js_AtomizeDouble(JSContext *cx, jsdouble d); |
402 |
|
403 |
/* |
404 |
* Find or create the atom for a string. Return null on failure to allocate |
405 |
* memory. |
406 |
*/ |
407 |
extern JSAtom * |
408 |
js_AtomizeString(JSContext *cx, JSString *str, uintN flags); |
409 |
|
410 |
extern JSAtom * |
411 |
js_Atomize(JSContext *cx, const char *bytes, size_t length, uintN flags); |
412 |
|
413 |
extern JSAtom * |
414 |
js_AtomizeChars(JSContext *cx, const jschar *chars, size_t length, uintN flags); |
415 |
|
416 |
/* |
417 |
* Return an existing atom for the given char array or null if the char |
418 |
* sequence is currently not atomized. |
419 |
*/ |
420 |
extern JSAtom * |
421 |
js_GetExistingStringAtom(JSContext *cx, const jschar *chars, size_t length); |
422 |
|
423 |
/* |
424 |
* This variant handles all primitive values. |
425 |
*/ |
426 |
JSBool |
427 |
js_AtomizePrimitiveValue(JSContext *cx, jsval v, JSAtom **atomp); |
428 |
|
429 |
/* |
430 |
* Convert v to an atomized string and wrap it as an id. |
431 |
*/ |
432 |
extern JSBool |
433 |
js_ValueToStringId(JSContext *cx, jsval v, jsid *idp); |
434 |
|
435 |
#ifdef DEBUG |
436 |
|
437 |
extern JS_FRIEND_API(void) |
438 |
js_DumpAtoms(JSContext *cx, FILE *fp); |
439 |
|
440 |
#endif |
441 |
|
442 |
/* |
443 |
* Assign atom an index and insert it on al. |
444 |
*/ |
445 |
extern JSAtomListElement * |
446 |
js_IndexAtom(JSContext *cx, JSAtom *atom, JSAtomList *al); |
447 |
|
448 |
/* |
449 |
* For all unmapped atoms recorded in al, add a mapping from the atom's index |
450 |
* to its address. map->length must already be set to the number of atoms in |
451 |
* the list and map->vector must point to pre-allocated memory. |
452 |
*/ |
453 |
extern void |
454 |
js_InitAtomMap(JSContext *cx, JSAtomMap *map, JSAtomList *al); |
455 |
|
456 |
JS_END_EXTERN_C |
457 |
|
458 |
#endif /* jsatom_h___ */ |