~ubuntu-branches/ubuntu/hardy/avidemux/hardy

« back to all changes in this revision

Viewing changes to avidemux/ADM_libraries/ADM_smjs/jsatom.c

  • Committer: Bazaar Package Importer
  • Author(s): Matvey Kozhev
  • Date: 2007-12-18 13:53:04 UTC
  • mfrom: (1.1.7 upstream)
  • Revision ID: james.westby@ubuntu.com-20071218135304-cdqec2lg2bglyz15
Tags: 1:2.4~preview3-0.0ubuntu1
* Upload to Ubuntu. (LP: #163287, LP: #126572)
* debian/changelog: re-added Ubuntu releases.
* debian/control:
  - Require debhelper >= 5.0.51 (for dh_icons) and imagemagick.
  - Build-depend on libsdl1.2-dev instead of libsdl-dev.
  - Build against newer libx264-dev. (LP: #138854)
  - Removed libamrnb-dev, not in Ubuntu yet.
* debian/rules:
  - Install all icon sizes, using convert (upstream installs none).
  - Added missing calls to dh_installmenu, dh_installman, dh_icons and
    dh_desktop.
* debian/menu, debian/avidemux-qt.menu:
  - Corrected package and executable names.
* debian/avidemux-common.install: Install icons.
* debian/avidemux.common.manpages: Install man/avidemux.1.
* debian/links, debian/avidemux-cli.links, debian/avidemux-gtk.links:
  - Link manpages to avidemux.1.gz.
* debian/install, debian/avidemux-qt.install, debian/avidemux-gtk.desktop,
  debian/avidemux-qt.desktop: Install desktop files.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
/*
 
41
 * JS atom table.
 
42
 */
 
43
#include "jsstddef.h"
 
44
#include <stdlib.h>
 
45
#include <string.h>
 
46
#include "jstypes.h"
 
47
#include "jsutil.h" /* Added by JSIFY */
 
48
#include "jshash.h" /* Added by JSIFY */
 
49
#include "jsprf.h"
 
50
#include "jsapi.h"
 
51
#include "jsatom.h"
 
52
#include "jscntxt.h"
 
53
#include "jsconfig.h"
 
54
#include "jsgc.h"
 
55
#include "jslock.h"
 
56
#include "jsnum.h"
 
57
#include "jsopcode.h"
 
58
#include "jsstr.h"
 
59
 
 
60
JS_FRIEND_API(const char *)
 
61
js_AtomToPrintableString(JSContext *cx, JSAtom *atom)
 
62
{
 
63
    return js_ValueToPrintableString(cx, ATOM_KEY(atom));
 
64
}
 
65
 
 
66
#if JS_HAS_ERROR_EXCEPTIONS
 
67
extern const char js_Error_str[];       /* trivial, from jsexn.h */
 
68
#endif
 
69
 
 
70
/*
 
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.
 
73
 */
 
74
const char *js_type_str[] = {
 
75
    "undefined",
 
76
    js_object_str,
 
77
    "function",
 
78
    "string",
 
79
    "number",
 
80
    "boolean",
 
81
    "null",
 
82
    "xml",
 
83
};
 
84
 
 
85
const char *js_boolean_str[] = {
 
86
    js_false_str,
 
87
    js_true_str
 
88
};
 
89
 
 
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";
 
133
 
 
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";
 
145
#endif
 
146
 
 
147
#ifdef NARCISSUS
 
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";
 
153
#endif
 
154
 
 
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))
 
159
 
 
160
JS_STATIC_DLL_CALLBACK(JSHashNumber)
 
161
js_hash_atom_key(const void *key)
 
162
{
 
163
    jsval v;
 
164
    jsdouble *dp;
 
165
 
 
166
    /* Order JSVAL_IS_* tests by likelihood of success. */
 
167
    v = (jsval)key;
 
168
    if (JSVAL_IS_STRING(v))
 
169
        return js_HashString(JSVAL_TO_STRING(v));
 
170
    if (JSVAL_IS_INT(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);
 
175
    }
 
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;
 
181
}
 
182
 
 
183
JS_STATIC_DLL_CALLBACK(intN)
 
184
js_compare_atom_keys(const void *k1, const void *k2)
 
185
{
 
186
    jsval v1, v2;
 
187
 
 
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);
 
196
#if defined(XP_WIN)
 
197
        /* XXX MSVC miscompiles such that (NaN == 0) */
 
198
        if (JSDOUBLE_IS_NaN(d2))
 
199
            return JS_FALSE;
 
200
#endif
 
201
        return d1 == d2;
 
202
    }
 
203
    return v1 == v2;
 
204
}
 
205
 
 
206
JS_STATIC_DLL_CALLBACK(int)
 
207
js_compare_stub(const void *v1, const void *v2)
 
208
{
 
209
    return 1;
 
210
}
 
211
 
 
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)
 
215
{
 
216
    return malloc(size);
 
217
}
 
218
 
 
219
void JS_DLL_CALLBACK
 
220
js_free_table_space(void *priv, void *item)
 
221
{
 
222
    free(item);
 
223
}
 
224
 
 
225
JS_STATIC_DLL_CALLBACK(JSHashEntry *)
 
226
js_alloc_atom(void *priv, const void *key)
 
227
{
 
228
    JSAtomState *state = (JSAtomState *) priv;
 
229
    JSAtom *atom;
 
230
 
 
231
    atom = (JSAtom *) malloc(sizeof(JSAtom));
 
232
    if (!atom)
 
233
        return NULL;
 
234
#ifdef JS_THREADSAFE
 
235
    state->tablegen++;
 
236
#endif
 
237
    atom->entry.key = key;
 
238
    atom->entry.value = NULL;
 
239
    atom->flags = 0;
 
240
    atom->number = state->number++;
 
241
    return &atom->entry;
 
242
}
 
243
 
 
244
JS_STATIC_DLL_CALLBACK(void)
 
245
js_free_atom(void *priv, JSHashEntry *he, uintN flag)
 
246
{
 
247
    if (flag != HT_FREE_ENTRY)
 
248
        return;
 
249
#ifdef JS_THREADSAFE
 
250
    ((JSAtomState *)priv)->tablegen++;
 
251
#endif
 
252
    free(he);
 
253
}
 
254
 
 
255
static JSHashAllocOps atom_alloc_ops = {
 
256
    js_alloc_table_space,   js_free_table_space,
 
257
    js_alloc_atom,          js_free_atom
 
258
};
 
259
 
 
260
#define JS_ATOM_HASH_SIZE   1024
 
261
 
 
262
JSBool
 
263
js_InitAtomState(JSContext *cx, JSAtomState *state)
 
264
{
 
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);
 
268
    if (!state->table) {
 
269
        JS_ReportOutOfMemory(cx);
 
270
        return JS_FALSE;
 
271
    }
 
272
 
 
273
    state->runtime = cx->runtime;
 
274
#ifdef JS_THREADSAFE
 
275
    js_InitLock(&state->lock);
 
276
    state->tablegen = 0;
 
277
#endif
 
278
 
 
279
    if (!js_InitPinnedAtoms(cx, state)) {
 
280
        js_FreeAtomState(cx, state);
 
281
        return JS_FALSE;
 
282
    }
 
283
    return JS_TRUE;
 
284
}
 
285
 
 
286
JSBool
 
287
js_InitPinnedAtoms(JSContext *cx, JSAtomState *state)
 
288
{
 
289
    uintN i;
 
290
 
 
291
#define FROB(lval,str)                                                        \
 
292
    JS_BEGIN_MACRO                                                            \
 
293
        if (!(state->lval = js_Atomize(cx, str, strlen(str), ATOM_PINNED)))   \
 
294
            return JS_FALSE;                                                  \
 
295
    JS_END_MACRO
 
296
 
 
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]);
 
300
 
 
301
    FROB(booleanAtoms[0],         js_false_str);
 
302
    FROB(booleanAtoms[1],         js_true_str);
 
303
    FROB(nullAtom,                js_null_str);
 
304
 
 
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);
 
312
#endif
 
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);
 
349
 
 
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);
 
361
#endif
 
362
 
 
363
#ifdef NARCISSUS
 
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);
 
369
#endif
 
370
 
 
371
#undef FROB
 
372
 
 
373
    memset(&state->lazy, 0, sizeof state->lazy);
 
374
    return JS_TRUE;
 
375
}
 
376
 
 
377
/* NB: cx unused; js_FinishAtomState calls us with null cx. */
 
378
void
 
379
js_FreeAtomState(JSContext *cx, JSAtomState *state)
 
380
{
 
381
    if (state->table)
 
382
        JS_HashTableDestroy(state->table);
 
383
#ifdef JS_THREADSAFE
 
384
    js_FinishLock(&state->lock);
 
385
#endif
 
386
    memset(state, 0, sizeof *state);
 
387
}
 
388
 
 
389
typedef struct UninternArgs {
 
390
    JSRuntime   *rt;
 
391
    jsatomid    leaks;
 
392
} UninternArgs;
 
393
 
 
394
JS_STATIC_DLL_CALLBACK(intN)
 
395
js_atom_uninterner(JSHashEntry *he, intN i, void *arg)
 
396
{
 
397
    JSAtom *atom;
 
398
    UninternArgs *args;
 
399
 
 
400
    atom = (JSAtom *)he;
 
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))
 
405
        args->leaks++;
 
406
    return HT_ENUMERATE_NEXT;
 
407
}
 
408
 
 
409
void
 
410
js_FinishAtomState(JSAtomState *state)
 
411
{
 
412
    UninternArgs args;
 
413
 
 
414
    if (!state->table)
 
415
        return;
 
416
    args.rt = state->runtime;
 
417
    args.leaks = 0;
 
418
    JS_HashTableEnumerateEntries(state->table, js_atom_uninterner, &args);
 
419
#ifdef DEBUG
 
420
    if (args.leaks != 0) {
 
421
        fprintf(stderr,
 
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);
 
426
    }
 
427
#endif
 
428
    js_FreeAtomState(NULL, state);
 
429
}
 
430
 
 
431
typedef struct MarkArgs {
 
432
    uintN           gcflags;
 
433
    JSGCThingMarker mark;
 
434
    void            *data;
 
435
} MarkArgs;
 
436
 
 
437
JS_STATIC_DLL_CALLBACK(intN)
 
438
js_atom_marker(JSHashEntry *he, intN i, void *arg)
 
439
{
 
440
    JSAtom *atom;
 
441
    MarkArgs *args;
 
442
    jsval key;
 
443
 
 
444
    atom = (JSAtom *)he;
 
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);
 
452
    }
 
453
    return HT_ENUMERATE_NEXT;
 
454
}
 
455
 
 
456
void
 
457
js_MarkAtomState(JSAtomState *state, uintN gcflags, JSGCThingMarker mark,
 
458
                 void *data)
 
459
{
 
460
    MarkArgs args;
 
461
 
 
462
    if (!state->table)
 
463
        return;
 
464
    args.gcflags = gcflags;
 
465
    args.mark = mark;
 
466
    args.data = data;
 
467
    JS_HashTableEnumerateEntries(state->table, js_atom_marker, &args);
 
468
}
 
469
 
 
470
JS_STATIC_DLL_CALLBACK(intN)
 
471
js_atom_sweeper(JSHashEntry *he, intN i, void *arg)
 
472
{
 
473
    JSAtom *atom;
 
474
    JSAtomState *state;
 
475
 
 
476
    atom = (JSAtom *)he;
 
477
    if (atom->flags & ATOM_MARK) {
 
478
        atom->flags &= ~ATOM_MARK;
 
479
        state = (JSAtomState *)arg;
 
480
        state->liveAtoms++;
 
481
        return HT_ENUMERATE_NEXT;
 
482
    }
 
483
    JS_ASSERT((atom->flags & (ATOM_PINNED | ATOM_INTERNED)) == 0);
 
484
    atom->entry.key = atom->entry.value = NULL;
 
485
    atom->flags = 0;
 
486
    return HT_ENUMERATE_REMOVE;
 
487
}
 
488
 
 
489
void
 
490
js_SweepAtomState(JSAtomState *state)
 
491
{
 
492
    state->liveAtoms = 0;
 
493
    if (state->table)
 
494
        JS_HashTableEnumerateEntries(state->table, js_atom_sweeper, state);
 
495
}
 
496
 
 
497
JS_STATIC_DLL_CALLBACK(intN)
 
498
js_atom_unpinner(JSHashEntry *he, intN i, void *arg)
 
499
{
 
500
    JSAtom *atom;
 
501
 
 
502
    atom = (JSAtom *)he;
 
503
    atom->flags &= ~ATOM_PINNED;
 
504
    return HT_ENUMERATE_NEXT;
 
505
}
 
506
 
 
507
void
 
508
js_UnpinPinnedAtoms(JSAtomState *state)
 
509
{
 
510
    if (state->table)
 
511
        JS_HashTableEnumerateEntries(state->table, js_atom_unpinner, NULL);
 
512
}
 
513
 
 
514
static JSAtom *
 
515
js_AtomizeHashedKey(JSContext *cx, jsval key, JSHashNumber keyHash, uintN flags)
 
516
{
 
517
    JSAtomState *state;
 
518
    JSHashTable *table;
 
519
    JSHashEntry *he, **hep;
 
520
    JSAtom *atom;
 
521
 
 
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);
 
528
        if (!he) {
 
529
            JS_ReportOutOfMemory(cx);
 
530
            atom = NULL;
 
531
            goto out;
 
532
        }
 
533
    }
 
534
 
 
535
    atom = (JSAtom *)he;
 
536
    atom->flags |= flags;
 
537
    cx->weakRoots.lastAtom = atom;
 
538
out:
 
539
    JS_UNLOCK(&state->lock,cx);
 
540
    return atom;
 
541
}
 
542
 
 
543
JSAtom *
 
544
js_AtomizeObject(JSContext *cx, JSObject *obj, uintN flags)
 
545
{
 
546
    jsval key;
 
547
    JSHashNumber keyHash;
 
548
 
 
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);
 
553
}
 
554
 
 
555
JSAtom *
 
556
js_AtomizeBoolean(JSContext *cx, JSBool b, uintN flags)
 
557
{
 
558
    jsval key;
 
559
    JSHashNumber keyHash;
 
560
 
 
561
    key = BOOLEAN_TO_JSVAL(b);
 
562
    keyHash = HASH_BOOLEAN(b);
 
563
    return js_AtomizeHashedKey(cx, key, keyHash, flags);
 
564
}
 
565
 
 
566
JSAtom *
 
567
js_AtomizeInt(JSContext *cx, jsint i, uintN flags)
 
568
{
 
569
    jsval key;
 
570
    JSHashNumber keyHash;
 
571
 
 
572
    key = INT_TO_JSVAL(i);
 
573
    keyHash = HASH_INT(i);
 
574
    return js_AtomizeHashedKey(cx, key, keyHash, flags);
 
575
}
 
576
 
 
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)])
 
580
 
 
581
JSAtom *
 
582
js_AtomizeDouble(JSContext *cx, jsdouble d, uintN flags)
 
583
{
 
584
    jsdouble *dp;
 
585
    JSHashNumber keyHash;
 
586
    jsval key;
 
587
    JSAtomState *state;
 
588
    JSHashTable *table;
 
589
    JSHashEntry *he, **hep;
 
590
    JSAtom *atom;
 
591
    char buf[2 * ALIGNMENT(double)];
 
592
 
 
593
    dp = ALIGN(buf, double);
 
594
    *dp = d;
 
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) {
 
602
#ifdef JS_THREADSAFE
 
603
        uint32 gen = state->tablegen;
 
604
#endif
 
605
        JS_UNLOCK(&state->lock,cx);
 
606
        if (!js_NewDoubleValue(cx, d, &key))
 
607
            return NULL;
 
608
        JS_LOCK(&state->lock, cx);
 
609
#ifdef JS_THREADSAFE
 
610
        if (state->tablegen != gen) {
 
611
            hep = JS_HashTableRawLookup(table, keyHash, (void *)key);
 
612
            if ((he = *hep) != NULL) {
 
613
                atom = (JSAtom *)he;
 
614
                goto out;
 
615
            }
 
616
        }
 
617
#endif
 
618
        he = JS_HashTableRawAdd(table, hep, keyHash, (void *)key, NULL);
 
619
        if (!he) {
 
620
            JS_ReportOutOfMemory(cx);
 
621
            atom = NULL;
 
622
            goto out;
 
623
        }
 
624
    }
 
625
 
 
626
    atom = (JSAtom *)he;
 
627
    atom->flags |= flags;
 
628
    cx->weakRoots.lastAtom = atom;
 
629
out:
 
630
    JS_UNLOCK(&state->lock,cx);
 
631
    return atom;
 
632
}
 
633
 
 
634
/*
 
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.
 
637
 */
 
638
#define HIDDEN_ATOM_SUBSPACE_KEYHASH    0x6A09E667
 
639
 
 
640
JSAtom *
 
641
js_AtomizeString(JSContext *cx, JSString *str, uintN flags)
 
642
{
 
643
    JSHashNumber keyHash;
 
644
    jsval key;
 
645
    JSAtomState *state;
 
646
    JSHashTable *table;
 
647
    JSHashEntry *he, **hep;
 
648
    JSAtom *atom;
 
649
 
 
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) {
 
659
#ifdef JS_THREADSAFE
 
660
        uint32 gen = state->tablegen;
 
661
        JS_UNLOCK(&state->lock, cx);
 
662
#endif
 
663
 
 
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);
 
668
            if (!str)
 
669
                return NULL;
 
670
            key = STRING_TO_JSVAL(str);
 
671
        } else {
 
672
            if (!JS_MakeStringImmutable(cx, str))
 
673
                return NULL;
 
674
        }
 
675
 
 
676
#ifdef JS_THREADSAFE
 
677
        JS_LOCK(&state->lock, cx);
 
678
        if (state->tablegen != gen) {
 
679
            hep = JS_HashTableRawLookup(table, keyHash, (void *)key);
 
680
            if ((he = *hep) != NULL) {
 
681
                atom = (JSAtom *)he;
 
682
                if (flags & ATOM_NOCOPY)
 
683
                    str->chars = NULL;
 
684
                goto out;
 
685
            }
 
686
        }
 
687
#endif
 
688
 
 
689
        he = JS_HashTableRawAdd(table, hep, keyHash, (void *)key, NULL);
 
690
        if (!he) {
 
691
            JS_ReportOutOfMemory(cx);
 
692
            atom = NULL;
 
693
            goto out;
 
694
        }
 
695
    }
 
696
 
 
697
    atom = (JSAtom *)he;
 
698
    atom->flags |= flags & (ATOM_PINNED | ATOM_INTERNED | ATOM_HIDDEN);
 
699
    cx->weakRoots.lastAtom = atom;
 
700
out:
 
701
    JS_UNLOCK(&state->lock,cx);
 
702
    return atom;
 
703
}
 
704
 
 
705
JS_FRIEND_API(JSAtom *)
 
706
js_Atomize(JSContext *cx, const char *bytes, size_t length, uintN flags)
 
707
{
 
708
    jschar *chars;
 
709
    JSString *str;
 
710
    JSAtom *atom;
 
711
    char buf[2 * ALIGNMENT(JSString)];
 
712
 
 
713
    /*
 
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.
 
719
     */
 
720
#define ATOMIZE_BUF_MAX 32
 
721
    jschar inflated[ATOMIZE_BUF_MAX];
 
722
    size_t inflatedLength = ATOMIZE_BUF_MAX - 1;
 
723
 
 
724
    if (length < ATOMIZE_BUF_MAX) {
 
725
        js_InflateStringToBuffer(cx, bytes, length, inflated, &inflatedLength);
 
726
        inflated[inflatedLength] = 0;
 
727
        chars = inflated;
 
728
    } else {
 
729
        inflatedLength = length;
 
730
        chars = js_InflateString(cx, bytes, &inflatedLength);
 
731
        if (!chars)
 
732
            return NULL;
 
733
        flags |= ATOM_NOCOPY;
 
734
    }
 
735
 
 
736
    str = ALIGN(buf, JSString);
 
737
 
 
738
    str->chars = chars;
 
739
    str->length = inflatedLength;
 
740
    atom = js_AtomizeString(cx, str, ATOM_TMPSTR | flags);
 
741
    if (chars != inflated && (!atom || ATOM_TO_STRING(atom)->chars != chars))
 
742
        JS_free(cx, chars);
 
743
    return atom;
 
744
}
 
745
 
 
746
JS_FRIEND_API(JSAtom *)
 
747
js_AtomizeChars(JSContext *cx, const jschar *chars, size_t length, uintN flags)
 
748
{
 
749
    JSString *str;
 
750
    char buf[2 * ALIGNMENT(JSString)];
 
751
 
 
752
    str = ALIGN(buf, JSString);
 
753
    str->chars = (jschar *)chars;
 
754
    str->length = length;
 
755
    return js_AtomizeString(cx, str, ATOM_TMPSTR | flags);
 
756
}
 
757
 
 
758
JSAtom *
 
759
js_AtomizeValue(JSContext *cx, jsval value, uintN flags)
 
760
{
 
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);
 
772
}
 
773
 
 
774
JSAtom *
 
775
js_ValueToStringAtom(JSContext *cx, jsval v)
 
776
{
 
777
    JSString *str;
 
778
 
 
779
    str = js_ValueToString(cx, v);
 
780
    if (!str)
 
781
        return NULL;
 
782
    return js_AtomizeString(cx, str, 0);
 
783
}
 
784
 
 
785
JS_STATIC_DLL_CALLBACK(JSHashNumber)
 
786
js_hash_atom_ptr(const void *key)
 
787
{
 
788
    const JSAtom *atom = key;
 
789
    return atom->number;
 
790
}
 
791
 
 
792
JS_STATIC_DLL_CALLBACK(void *)
 
793
js_alloc_temp_space(void *priv, size_t size)
 
794
{
 
795
    JSContext *cx = priv;
 
796
    void *space;
 
797
 
 
798
    JS_ARENA_ALLOCATE(space, &cx->tempPool, size);
 
799
    if (!space)
 
800
        JS_ReportOutOfMemory(cx);
 
801
    return space;
 
802
}
 
803
 
 
804
JS_STATIC_DLL_CALLBACK(void)
 
805
js_free_temp_space(void *priv, void *item)
 
806
{
 
807
}
 
808
 
 
809
JS_STATIC_DLL_CALLBACK(JSHashEntry *)
 
810
js_alloc_temp_entry(void *priv, const void *key)
 
811
{
 
812
    JSContext *cx = priv;
 
813
    JSAtomListElement *ale;
 
814
 
 
815
    JS_ARENA_ALLOCATE_TYPE(ale, JSAtomListElement, &cx->tempPool);
 
816
    if (!ale) {
 
817
        JS_ReportOutOfMemory(cx);
 
818
        return NULL;
 
819
    }
 
820
    return &ale->entry;
 
821
}
 
822
 
 
823
JS_STATIC_DLL_CALLBACK(void)
 
824
js_free_temp_entry(void *priv, JSHashEntry *he, uintN flag)
 
825
{
 
826
}
 
827
 
 
828
static JSHashAllocOps temp_alloc_ops = {
 
829
    js_alloc_temp_space,    js_free_temp_space,
 
830
    js_alloc_temp_entry,    js_free_temp_entry
 
831
};
 
832
 
 
833
JSAtomListElement *
 
834
js_IndexAtom(JSContext *cx, JSAtom *atom, JSAtomList *al)
 
835
{
 
836
    JSAtomListElement *ale, *ale2, *next;
 
837
    JSHashEntry **hep;
 
838
 
 
839
    ATOM_LIST_LOOKUP(ale, hep, al, atom);
 
840
    if (!ale) {
 
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);
 
845
            if (!ale)
 
846
                return NULL;
 
847
            ALE_SET_ATOM(ale, atom);
 
848
            ALE_SET_NEXT(ale, al->list);
 
849
            al->list = ale;
 
850
        } else {
 
851
            /* We want to hash.  Have we already made a hash table? */
 
852
            if (!al->table) {
 
853
                /* No hash table yet, so hep had better be null! */
 
854
                JS_ASSERT(!hep);
 
855
                al->table = JS_NewHashTable(al->count + 1, js_hash_atom_ptr,
 
856
                                            JS_CompareValues, JS_CompareValues,
 
857
                                            &temp_alloc_ops, cx);
 
858
                if (!al->table)
 
859
                    return NULL;
 
860
 
 
861
                /*
 
862
                 * Set ht->nentries explicitly, because we are moving entries
 
863
                 * from al to ht, not calling JS_HashTable(Raw|)Add.
 
864
                 */
 
865
                al->table->nentries = al->count;
 
866
 
 
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,
 
872
                                                ale2->entry.key);
 
873
                    ALE_SET_NEXT(ale2, *hep);
 
874
                    *hep = &ale2->entry;
 
875
                }
 
876
                al->list = NULL;
 
877
 
 
878
                /* Set hep for insertion of atom's ale, immediately below. */
 
879
                hep = JS_HashTableRawLookup(al->table, atom->number, atom);
 
880
            }
 
881
 
 
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);
 
885
            if (!ale)
 
886
                return NULL;
 
887
        }
 
888
 
 
889
        ALE_SET_INDEX(ale, al->count++);
 
890
    }
 
891
    return ale;
 
892
}
 
893
 
 
894
JS_FRIEND_API(JSAtom *)
 
895
js_GetAtom(JSContext *cx, JSAtomMap *map, jsatomid i)
 
896
{
 
897
    JSAtom *atom;
 
898
    static JSAtom dummy;
 
899
 
 
900
    JS_ASSERT(map->vector && i < map->length);
 
901
    if (!map->vector || i >= map->length) {
 
902
        char numBuf[12];
 
903
        JS_snprintf(numBuf, sizeof numBuf, "%lu", (unsigned long)i);
 
904
        JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
 
905
                             JSMSG_BAD_ATOMIC_NUMBER, numBuf);
 
906
        return &dummy;
 
907
    }
 
908
    atom = map->vector[i];
 
909
    JS_ASSERT(atom);
 
910
    return atom;
 
911
}
 
912
 
 
913
JS_STATIC_DLL_CALLBACK(intN)
 
914
js_map_atom(JSHashEntry *he, intN i, void *arg)
 
915
{
 
916
    JSAtomListElement *ale = (JSAtomListElement *)he;
 
917
    JSAtom **vector = arg;
 
918
 
 
919
    vector[ALE_INDEX(ale)] = ALE_ATOM(ale);
 
920
    return HT_ENUMERATE_NEXT;
 
921
}
 
922
 
 
923
#ifdef DEBUG
 
924
static jsrefcount js_atom_map_count;
 
925
static jsrefcount js_atom_map_hash_table_count;
 
926
#endif
 
927
 
 
928
JS_FRIEND_API(JSBool)
 
929
js_InitAtomMap(JSContext *cx, JSAtomMap *map, JSAtomList *al)
 
930
{
 
931
    JSAtom **vector;
 
932
    JSAtomListElement *ale;
 
933
    uint32 count;
 
934
 
 
935
#ifdef DEBUG
 
936
    JS_ATOMIC_INCREMENT(&js_atom_map_count);
 
937
#endif
 
938
    ale = al->list;
 
939
    if (!ale && !al->table) {
 
940
        map->vector = NULL;
 
941
        map->length = 0;
 
942
        return JS_TRUE;
 
943
    }
 
944
 
 
945
    count = al->count;
 
946
    if (count >= ATOM_INDEX_LIMIT) {
 
947
        JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
 
948
                             JSMSG_TOO_MANY_LITERALS);
 
949
        return JS_FALSE;
 
950
    }
 
951
    vector = (JSAtom **) JS_malloc(cx, (size_t) count * sizeof *vector);
 
952
    if (!vector)
 
953
        return JS_FALSE;
 
954
 
 
955
    if (al->table) {
 
956
#ifdef DEBUG
 
957
        JS_ATOMIC_INCREMENT(&js_atom_map_hash_table_count);
 
958
#endif
 
959
        JS_HashTableEnumerateEntries(al->table, js_map_atom, vector);
 
960
    } else {
 
961
        do {
 
962
            vector[ALE_INDEX(ale)] = ALE_ATOM(ale);
 
963
        } while ((ale = ALE_NEXT(ale)) != NULL);
 
964
    }
 
965
    ATOM_LIST_INIT(al);
 
966
 
 
967
    map->vector = vector;
 
968
    map->length = (jsatomid)count;
 
969
    return JS_TRUE;
 
970
}
 
971
 
 
972
JS_FRIEND_API(void)
 
973
js_FreeAtomMap(JSContext *cx, JSAtomMap *map)
 
974
{
 
975
    if (map->vector) {
 
976
        JS_free(cx, map->vector);
 
977
        map->vector = NULL;
 
978
    }
 
979
    map->length = 0;
 
980
}