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 |
#if JS_BYTES_PER_WORD == 4 |
69 |
# define ATOM_HASH(atom) ((JSHashNumber)(atom) >> 2) |
70 |
#elif JS_BYTES_PER_WORD == 8 |
71 |
# define ATOM_HASH(atom) (((JSHashNumber)(jsuword)(atom) >> 3) ^ \ |
72 |
(JSHashNumber)((jsuword)(atom) >> 32)) |
73 |
#else |
74 |
# error "Unsupported configuration" |
75 |
#endif |
76 |
|
77 |
/* |
78 |
* Return a printable, lossless char[] representation of a string-type atom. |
79 |
* The lifetime of the result extends at least until the next GC activation, |
80 |
* longer if cx's string newborn root is not overwritten. |
81 |
*/ |
82 |
extern const char * |
83 |
js_AtomToPrintableString(JSContext *cx, JSAtom *atom); |
84 |
|
85 |
struct JSAtomListElement { |
86 |
JSHashEntry entry; |
87 |
}; |
88 |
|
89 |
#define ALE_ATOM(ale) ((JSAtom *) (ale)->entry.key) |
90 |
#define ALE_INDEX(ale) ((jsatomid) JS_PTR_TO_UINT32((ale)->entry.value)) |
91 |
#define ALE_VALUE(ale) ((jsval) (ale)->entry.value) |
92 |
#define ALE_NEXT(ale) ((JSAtomListElement *) (ale)->entry.next) |
93 |
|
94 |
/* |
95 |
* In an upvars list, ALE_DEFN(ale)->resolve() is the outermost definition the |
96 |
* name may reference. If a with block or a function that calls eval encloses |
97 |
* the use, the name may end up referring to something else at runtime. |
98 |
*/ |
99 |
#define ALE_DEFN(ale) ((JSDefinition *) (ale)->entry.value) |
100 |
|
101 |
#define ALE_SET_ATOM(ale,atom) ((ale)->entry.key = (const void *)(atom)) |
102 |
#define ALE_SET_INDEX(ale,index)((ale)->entry.value = JS_UINT32_TO_PTR(index)) |
103 |
#define ALE_SET_DEFN(ale, dn) ((ale)->entry.value = (void *)(dn)) |
104 |
#define ALE_SET_VALUE(ale, v) ((ale)->entry.value = (void *)(v)) |
105 |
#define ALE_SET_NEXT(ale,nxt) ((ale)->entry.next = (JSHashEntry *)(nxt)) |
106 |
|
107 |
/* |
108 |
* NB: JSAtomSet must be plain-old-data as it is embedded in the pn_u union in |
109 |
* JSParseNode. JSAtomList encapsulates all operational uses of a JSAtomSet. |
110 |
* |
111 |
* The JSAtomList name is traditional, even though the implementation is a map |
112 |
* (not to be confused with JSAtomMap). In particular the "ALE" and "ale" short |
113 |
* names for JSAtomListElement variables roll off the fingers, compared to ASE |
114 |
* or AME alternatives. |
115 |
*/ |
116 |
struct JSAtomSet { |
117 |
JSHashEntry *list; /* literals indexed for mapping */ |
118 |
JSHashTable *table; /* hash table if list gets too long */ |
119 |
jsuint count; /* count of indexed literals */ |
120 |
}; |
121 |
|
122 |
#ifdef __cplusplus |
123 |
|
124 |
struct JSAtomList : public JSAtomSet |
125 |
{ |
126 |
#ifdef DEBUG |
127 |
const JSAtomSet* set; /* asserted null in mutating methods */ |
128 |
#endif |
129 |
|
130 |
JSAtomList() { |
131 |
list = NULL; table = NULL; count = 0; |
132 |
#ifdef DEBUG |
133 |
set = NULL; |
134 |
#endif |
135 |
} |
136 |
|
137 |
JSAtomList(const JSAtomSet& as) { |
138 |
list = as.list; table = as.table; count = as.count; |
139 |
#ifdef DEBUG |
140 |
set = &as; |
141 |
#endif |
142 |
} |
143 |
|
144 |
void clear() { JS_ASSERT(!set); list = NULL; table = NULL; count = 0; } |
145 |
|
146 |
JSAtomListElement *lookup(JSAtom *atom) { |
147 |
JSHashEntry **hep; |
148 |
return rawLookup(atom, hep); |
149 |
} |
150 |
|
151 |
JSAtomListElement *rawLookup(JSAtom *atom, JSHashEntry **&hep); |
152 |
|
153 |
enum AddHow { UNIQUE, SHADOW, HOIST }; |
154 |
|
155 |
JSAtomListElement *add(JSCompiler *jsc, JSAtom *atom, AddHow how = UNIQUE); |
156 |
|
157 |
void remove(JSCompiler *jsc, JSAtom *atom) { |
158 |
JSHashEntry **hep; |
159 |
JSAtomListElement *ale = rawLookup(atom, hep); |
160 |
if (ale) |
161 |
rawRemove(jsc, ale, hep); |
162 |
} |
163 |
|
164 |
void rawRemove(JSCompiler *jsc, JSAtomListElement *ale, JSHashEntry **hep); |
165 |
}; |
166 |
|
167 |
/* |
168 |
* Iterate over an atom list. We define a call operator to minimize the syntax |
169 |
* tax for users. We do not use a more standard pattern using ++ and * because |
170 |
* (a) it's the wrong pattern for a non-scalar; (b) it's overkill -- one method |
171 |
* is enough. (This comment is overkill!) |
172 |
*/ |
173 |
class JSAtomListIterator { |
174 |
JSAtomList* list; |
175 |
JSAtomListElement* next; |
176 |
uint32 index; |
177 |
|
178 |
public: |
179 |
JSAtomListIterator(JSAtomList* al) : list(al) { reset(); } |
180 |
|
181 |
void reset() { |
182 |
next = (JSAtomListElement *) list->list; |
183 |
index = 0; |
184 |
} |
185 |
|
186 |
JSAtomListElement* operator ()(); |
187 |
}; |
188 |
|
189 |
#endif /* __cplusplus */ |
190 |
|
191 |
struct JSAtomMap { |
192 |
JSAtom **vector; /* array of ptrs to indexed atoms */ |
193 |
jsatomid length; /* count of (to-be-)indexed atoms */ |
194 |
}; |
195 |
|
196 |
struct JSAtomState { |
197 |
JSDHashTable stringAtoms; /* hash table with shared strings */ |
198 |
JSDHashTable doubleAtoms; /* hash table with shared doubles */ |
199 |
#ifdef JS_THREADSAFE |
200 |
JSThinLock lock; |
201 |
#endif |
202 |
|
203 |
/* |
204 |
* From this point until the end of struct definition the struct must |
205 |
* contain only JSAtom fields. We use this to access the storage occupied |
206 |
* by the common atoms in js_FinishCommonAtoms. |
207 |
* |
208 |
* js_common_atom_names defined in jsatom.c contains C strings for atoms |
209 |
* in the order of atom fields here. Therefore you must update that array |
210 |
* if you change member order here. |
211 |
*/ |
212 |
|
213 |
/* The rt->emptyString atom, see jsstr.c's js_InitRuntimeStringState. */ |
214 |
JSAtom *emptyAtom; |
215 |
|
216 |
/* |
217 |
* Literal value and type names. |
218 |
* NB: booleanAtoms must come right before typeAtoms! |
219 |
*/ |
220 |
JSAtom *booleanAtoms[2]; |
221 |
JSAtom *typeAtoms[JSTYPE_LIMIT]; |
222 |
JSAtom *nullAtom; |
223 |
|
224 |
/* Standard class constructor or prototype names. */ |
225 |
JSAtom *classAtoms[JSProto_LIMIT]; |
226 |
|
227 |
/* Various built-in or commonly-used atoms, pinned on first context. */ |
228 |
JSAtom *anonymousAtom; |
229 |
JSAtom *applyAtom; |
230 |
JSAtom *argumentsAtom; |
231 |
JSAtom *arityAtom; |
232 |
JSAtom *callAtom; |
233 |
JSAtom *calleeAtom; |
234 |
JSAtom *callerAtom; |
235 |
JSAtom *classPrototypeAtom; |
236 |
JSAtom *constructorAtom; |
237 |
JSAtom *countAtom; |
238 |
JSAtom *eachAtom; |
239 |
JSAtom *evalAtom; |
240 |
JSAtom *fileNameAtom; |
241 |
JSAtom *getAtom; |
242 |
JSAtom *getterAtom; |
243 |
JSAtom *indexAtom; |
244 |
JSAtom *inputAtom; |
245 |
JSAtom *iteratorAtom; |
246 |
JSAtom *lengthAtom; |
247 |
JSAtom *lineNumberAtom; |
248 |
JSAtom *messageAtom; |
249 |
JSAtom *nameAtom; |
250 |
JSAtom *nextAtom; |
251 |
JSAtom *noSuchMethodAtom; |
252 |
JSAtom *parentAtom; |
253 |
JSAtom *protoAtom; |
254 |
JSAtom *setAtom; |
255 |
JSAtom *setterAtom; |
256 |
JSAtom *stackAtom; |
257 |
JSAtom *toLocaleStringAtom; |
258 |
JSAtom *toSourceAtom; |
259 |
JSAtom *toStringAtom; |
260 |
JSAtom *valueOfAtom; |
261 |
JSAtom *toJSONAtom; |
262 |
JSAtom *void0Atom; |
263 |
|
264 |
#if JS_HAS_XML_SUPPORT |
265 |
JSAtom *etagoAtom; |
266 |
JSAtom *namespaceAtom; |
267 |
JSAtom *ptagcAtom; |
268 |
JSAtom *qualifierAtom; |
269 |
JSAtom *spaceAtom; |
270 |
JSAtom *stagoAtom; |
271 |
JSAtom *starAtom; |
272 |
JSAtom *starQualifierAtom; |
273 |
JSAtom *tagcAtom; |
274 |
JSAtom *xmlAtom; |
275 |
#endif |
276 |
|
277 |
#ifdef NARCISSUS |
278 |
JSAtom *__call__Atom; |
279 |
JSAtom *__construct__Atom; |
280 |
JSAtom *__hasInstance__Atom; |
281 |
JSAtom *ExecutionContextAtom; |
282 |
JSAtom *currentAtom; |
283 |
#endif |
284 |
|
285 |
/* Less frequently used atoms, pinned lazily by JS_ResolveStandardClass. */ |
286 |
struct { |
287 |
JSAtom *InfinityAtom; |
288 |
JSAtom *NaNAtom; |
289 |
JSAtom *XMLListAtom; |
290 |
JSAtom *decodeURIAtom; |
291 |
JSAtom *decodeURIComponentAtom; |
292 |
JSAtom *defineGetterAtom; |
293 |
JSAtom *defineSetterAtom; |
294 |
JSAtom *encodeURIAtom; |
295 |
JSAtom *encodeURIComponentAtom; |
296 |
JSAtom *escapeAtom; |
297 |
JSAtom *functionNamespaceURIAtom; |
298 |
JSAtom *hasOwnPropertyAtom; |
299 |
JSAtom *isFiniteAtom; |
300 |
JSAtom *isNaNAtom; |
301 |
JSAtom *isPrototypeOfAtom; |
302 |
JSAtom *isXMLNameAtom; |
303 |
JSAtom *lookupGetterAtom; |
304 |
JSAtom *lookupSetterAtom; |
305 |
JSAtom *parseFloatAtom; |
306 |
JSAtom *parseIntAtom; |
307 |
JSAtom *propertyIsEnumerableAtom; |
308 |
JSAtom *unescapeAtom; |
309 |
JSAtom *unevalAtom; |
310 |
JSAtom *unwatchAtom; |
311 |
JSAtom *watchAtom; |
312 |
} lazy; |
313 |
}; |
314 |
|
315 |
#define ATOM_OFFSET_START offsetof(JSAtomState, emptyAtom) |
316 |
#define LAZY_ATOM_OFFSET_START offsetof(JSAtomState, lazy) |
317 |
#define ATOM_OFFSET_LIMIT (sizeof(JSAtomState)) |
318 |
|
319 |
#define COMMON_ATOMS_START(state) \ |
320 |
((JSAtom **)((uint8 *)(state) + ATOM_OFFSET_START)) |
321 |
#define COMMON_ATOM_INDEX(name) \ |
322 |
((offsetof(JSAtomState, name##Atom) - ATOM_OFFSET_START) \ |
323 |
/ sizeof(JSAtom*)) |
324 |
#define COMMON_TYPE_ATOM_INDEX(type) \ |
325 |
((offsetof(JSAtomState, typeAtoms[type]) - ATOM_OFFSET_START) \ |
326 |
/ sizeof(JSAtom*)) |
327 |
|
328 |
#define ATOM_OFFSET(name) offsetof(JSAtomState, name##Atom) |
329 |
#define OFFSET_TO_ATOM(rt,off) (*(JSAtom **)((char*)&(rt)->atomState + (off))) |
330 |
#define CLASS_ATOM_OFFSET(name) offsetof(JSAtomState,classAtoms[JSProto_##name]) |
331 |
|
332 |
#define CLASS_ATOM(cx,name) \ |
333 |
((cx)->runtime->atomState.classAtoms[JSProto_##name]) |
334 |
|
335 |
extern const char *const js_common_atom_names[]; |
336 |
extern const size_t js_common_atom_count; |
337 |
|
338 |
/* |
339 |
* Macros to access C strings for JSType and boolean literals. |
340 |
*/ |
341 |
#define JS_BOOLEAN_STR(type) (js_common_atom_names[1 + (type)]) |
342 |
#define JS_TYPE_STR(type) (js_common_atom_names[1 + 2 + (type)]) |
343 |
|
344 |
/* Well-known predefined C strings. */ |
345 |
#define JS_PROTO(name,code,init) extern const char js_##name##_str[]; |
346 |
#include "jsproto.tbl" |
347 |
#undef JS_PROTO |
348 |
|
349 |
extern const char js_anonymous_str[]; |
350 |
extern const char js_apply_str[]; |
351 |
extern const char js_arguments_str[]; |
352 |
extern const char js_arity_str[]; |
353 |
extern const char js_call_str[]; |
354 |
extern const char js_callee_str[]; |
355 |
extern const char js_caller_str[]; |
356 |
extern const char js_class_prototype_str[]; |
357 |
extern const char js_close_str[]; |
358 |
extern const char js_constructor_str[]; |
359 |
extern const char js_count_str[]; |
360 |
extern const char js_etago_str[]; |
361 |
extern const char js_each_str[]; |
362 |
extern const char js_eval_str[]; |
363 |
extern const char js_fileName_str[]; |
364 |
extern const char js_get_str[]; |
365 |
extern const char js_getter_str[]; |
366 |
extern const char js_index_str[]; |
367 |
extern const char js_input_str[]; |
368 |
extern const char js_iterator_str[]; |
369 |
extern const char js_length_str[]; |
370 |
extern const char js_lineNumber_str[]; |
371 |
extern const char js_message_str[]; |
372 |
extern const char js_name_str[]; |
373 |
extern const char js_namespace_str[]; |
374 |
extern const char js_next_str[]; |
375 |
extern const char js_noSuchMethod_str[]; |
376 |
extern const char js_object_str[]; |
377 |
extern const char js_parent_str[]; |
378 |
extern const char js_proto_str[]; |
379 |
extern const char js_ptagc_str[]; |
380 |
extern const char js_qualifier_str[]; |
381 |
extern const char js_send_str[]; |
382 |
extern const char js_setter_str[]; |
383 |
extern const char js_set_str[]; |
384 |
extern const char js_space_str[]; |
385 |
extern const char js_stack_str[]; |
386 |
extern const char js_stago_str[]; |
387 |
extern const char js_star_str[]; |
388 |
extern const char js_starQualifier_str[]; |
389 |
extern const char js_tagc_str[]; |
390 |
extern const char js_toSource_str[]; |
391 |
extern const char js_toString_str[]; |
392 |
extern const char js_toLocaleString_str[]; |
393 |
extern const char js_undefined_str[]; |
394 |
extern const char js_valueOf_str[]; |
395 |
extern const char js_toJSON_str[]; |
396 |
extern const char js_xml_str[]; |
397 |
|
398 |
#ifdef NARCISSUS |
399 |
extern const char js___call___str[]; |
400 |
extern const char js___construct___str[]; |
401 |
extern const char js___hasInstance___str[]; |
402 |
extern const char js_ExecutionContext_str[]; |
403 |
extern const char js_current_str[]; |
404 |
#endif |
405 |
|
406 |
/* |
407 |
* Initialize atom state. Return true on success, false on failure to allocate |
408 |
* memory. The caller must zero rt->atomState before calling this function and |
409 |
* only call it after js_InitGC successfully returns. |
410 |
*/ |
411 |
extern JSBool |
412 |
js_InitAtomState(JSRuntime *rt); |
413 |
|
414 |
/* |
415 |
* Free and clear atom state including any interned string atoms. This |
416 |
* function must be called before js_FinishGC. |
417 |
*/ |
418 |
extern void |
419 |
js_FinishAtomState(JSRuntime *rt); |
420 |
|
421 |
/* |
422 |
* Atom tracing and garbage collection hooks. |
423 |
*/ |
424 |
|
425 |
extern void |
426 |
js_TraceAtomState(JSTracer *trc, JSBool allAtoms); |
427 |
|
428 |
extern void |
429 |
js_SweepAtomState(JSContext *cx); |
430 |
|
431 |
extern JSBool |
432 |
js_InitCommonAtoms(JSContext *cx); |
433 |
|
434 |
extern void |
435 |
js_FinishCommonAtoms(JSContext *cx); |
436 |
|
437 |
/* |
438 |
* Find or create the atom for a double value. Return null on failure to |
439 |
* allocate memory. |
440 |
*/ |
441 |
extern JSAtom * |
442 |
js_AtomizeDouble(JSContext *cx, jsdouble d); |
443 |
|
444 |
/* |
445 |
* Find or create the atom for a string. Return null on failure to allocate |
446 |
* memory. |
447 |
*/ |
448 |
extern JSAtom * |
449 |
js_AtomizeString(JSContext *cx, JSString *str, uintN flags); |
450 |
|
451 |
extern JSAtom * |
452 |
js_Atomize(JSContext *cx, const char *bytes, size_t length, uintN flags); |
453 |
|
454 |
extern JSAtom * |
455 |
js_AtomizeChars(JSContext *cx, const jschar *chars, size_t length, uintN flags); |
456 |
|
457 |
/* |
458 |
* Return an existing atom for the given char array or null if the char |
459 |
* sequence is currently not atomized. |
460 |
*/ |
461 |
extern JSAtom * |
462 |
js_GetExistingStringAtom(JSContext *cx, const jschar *chars, size_t length); |
463 |
|
464 |
/* |
465 |
* This variant handles all primitive values. |
466 |
*/ |
467 |
JSBool |
468 |
js_AtomizePrimitiveValue(JSContext *cx, jsval v, JSAtom **atomp); |
469 |
|
470 |
/* |
471 |
* Convert v to an atomized string and wrap it as an id. |
472 |
*/ |
473 |
extern JSBool |
474 |
js_ValueToStringId(JSContext *cx, jsval v, jsid *idp); |
475 |
|
476 |
#ifdef DEBUG |
477 |
|
478 |
extern JS_FRIEND_API(void) |
479 |
js_DumpAtoms(JSContext *cx, FILE *fp); |
480 |
|
481 |
#endif |
482 |
|
483 |
/* |
484 |
* For all unmapped atoms recorded in al, add a mapping from the atom's index |
485 |
* to its address. map->length must already be set to the number of atoms in |
486 |
* the list and map->vector must point to pre-allocated memory. |
487 |
*/ |
488 |
extern void |
489 |
js_InitAtomMap(JSContext *cx, JSAtomMap *map, JSAtomList *al); |
490 |
|
491 |
JS_END_EXTERN_C |
492 |
|
493 |
#endif /* jsatom_h___ */ |