~ubuntu-branches/ubuntu/utopic/mongodb/utopic

« back to all changes in this revision

Viewing changes to src/third_party/js-1.7/jscntxt.c

  • Committer: Package Import Robot
  • Author(s): James Page
  • Date: 2014-07-03 09:23:46 UTC
  • mfrom: (1.3.10) (44.1.14 sid)
  • Revision ID: package-import@ubuntu.com-20140703092346-c5bvt46wnzougyly
Tags: 1:2.6.3-0ubuntu1
* New upstream stable release:
  - Dropped patches, included upstream:
    + 0003-All-platforms-but-Windows-find-hash-in-std-tr1.patch
    + 0008-Use-system-libstemmer.patch
    + 0011-Use-a-signed-char-to-store-BSONType-enumerations.patch
    + 0001-SERVER-12064-Atomic-operations-for-gcc-non-Intel-arc.patch
    + 0002-SERVER-12065-Support-ARM-and-AArch64-builds.patch
  - d/p/*: Refreshed/rebased remaining patches.
  - Use system provided libyaml-cpp:
    + d/control: Add libyaml-cpp-dev to BD's.
    + d/rules: Enable --with-system-yaml option.
    + d/p/fix-yaml-detection.patch: Fix detection of libyaml-cpp library.
  - d/mongodb-server.mongodb.upstart: Sync changes from upstream.
  - d/control,mongodb-dev.*: Drop mongodb-dev package; it has no reverse
    dependencies and upstream no longer install header files.
  - d/NEWS: Point users to upstream upgrade documentation for upgrades
    from 2.4 to 2.6.
* Merge from Debian unstable.
* d/control: BD on libv8-3.14-dev to ensure that transitioning to new v8
  versions is a explicit action due to changes in behaviour in >= 3.25
  (LP: #1295723).
* d/mongodb-server.prerm: Dropped debug echo call from maintainer script
  (LP: #1294455).

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
 
 * vim: set ts=8 sw=4 et tw=80:
3
 
 *
4
 
 * ***** BEGIN LICENSE BLOCK *****
5
 
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6
 
 *
7
 
 * The contents of this file are subject to the Mozilla Public License Version
8
 
 * 1.1 (the "License"); you may not use this file except in compliance with
9
 
 * the License. You may obtain a copy of the License at
10
 
 * http://www.mozilla.org/MPL/
11
 
 *
12
 
 * Software distributed under the License is distributed on an "AS IS" basis,
13
 
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14
 
 * for the specific language governing rights and limitations under the
15
 
 * License.
16
 
 *
17
 
 * The Original Code is Mozilla Communicator client code, released
18
 
 * March 31, 1998.
19
 
 *
20
 
 * The Initial Developer of the Original Code is
21
 
 * Netscape Communications Corporation.
22
 
 * Portions created by the Initial Developer are Copyright (C) 1998
23
 
 * the Initial Developer. All Rights Reserved.
24
 
 *
25
 
 * Contributor(s):
26
 
 *
27
 
 * Alternatively, the contents of this file may be used under the terms of
28
 
 * either of the GNU General Public License Version 2 or later (the "GPL"),
29
 
 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30
 
 * in which case the provisions of the GPL or the LGPL are applicable instead
31
 
 * of those above. If you wish to allow use of your version of this file only
32
 
 * under the terms of either the GPL or the LGPL, and not to allow others to
33
 
 * use your version of this file under the terms of the MPL, indicate your
34
 
 * decision by deleting the provisions above and replace them with the notice
35
 
 * and other provisions required by the GPL or the LGPL. If you do not delete
36
 
 * the provisions above, a recipient may use your version of this file under
37
 
 * the terms of any one of the MPL, the GPL or the LGPL.
38
 
 *
39
 
 * ***** END LICENSE BLOCK ***** */
40
 
 
41
 
/*
42
 
 * JS execution context.
43
 
 */
44
 
#include "jsstddef.h"
45
 
#include <stdarg.h>
46
 
#include <stdlib.h>
47
 
#include <string.h>
48
 
#include "jstypes.h"
49
 
#include "jsarena.h" /* Added by JSIFY */
50
 
#include "jsutil.h" /* Added by JSIFY */
51
 
#include "jsclist.h"
52
 
#include "jsprf.h"
53
 
#include "jsatom.h"
54
 
#include "jscntxt.h"
55
 
#include "jsconfig.h"
56
 
#include "jsdbgapi.h"
57
 
#include "jsexn.h"
58
 
#include "jsgc.h"
59
 
#include "jslock.h"
60
 
#include "jsnum.h"
61
 
#include "jsobj.h"
62
 
#include "jsopcode.h"
63
 
#include "jsscan.h"
64
 
#include "jsscope.h"
65
 
#include "jsscript.h"
66
 
#include "jsstr.h"
67
 
 
68
 
#ifdef JS_THREADSAFE
69
 
 
70
 
/*
71
 
 * Callback function to delete a JSThread info when the thread that owns it
72
 
 * is destroyed.
73
 
 */
74
 
void JS_DLL_CALLBACK
75
 
js_ThreadDestructorCB(void *ptr)
76
 
{
77
 
    JSThread *thread = (JSThread *)ptr;
78
 
 
79
 
    if (!thread)
80
 
        return;
81
 
    while (!JS_CLIST_IS_EMPTY(&thread->contextList)) {
82
 
        /* NB: use a temporary, as the macro evaluates its args many times. */
83
 
        JSCList *link = thread->contextList.next;
84
 
 
85
 
        JS_REMOVE_AND_INIT_LINK(link);
86
 
    }
87
 
    GSN_CACHE_CLEAR(&thread->gsnCache);
88
 
    free(thread);
89
 
}
90
 
 
91
 
/*
92
 
 * Get current thread-local JSThread info, creating one if it doesn't exist.
93
 
 * Each thread has a unique JSThread pointer.
94
 
 *
95
 
 * Since we are dealing with thread-local data, no lock is needed.
96
 
 *
97
 
 * Return a pointer to the thread local info, NULL if the system runs out
98
 
 * of memory, or it failed to set thread private data (neither case is very
99
 
 * likely; both are probably due to out-of-memory).  It is up to the caller
100
 
 * to report an error, if possible.
101
 
 */
102
 
JSThread *
103
 
js_GetCurrentThread(JSRuntime *rt)
104
 
{
105
 
    JSThread *thread;
106
 
 
107
 
    thread = (JSThread *)PR_GetThreadPrivate(rt->threadTPIndex);
108
 
    if (!thread) {
109
 
        thread = (JSThread *) calloc(1, sizeof(JSThread));
110
 
        if (!thread)
111
 
            return NULL;
112
 
 
113
 
        if (PR_FAILURE == PR_SetThreadPrivate(rt->threadTPIndex, thread)) {
114
 
            free(thread);
115
 
            return NULL;
116
 
        }
117
 
 
118
 
        JS_INIT_CLIST(&thread->contextList);
119
 
        thread->id = js_CurrentThreadId();
120
 
 
121
 
        /* js_SetContextThread initialize gcFreeLists as necessary. */
122
 
#ifdef DEBUG
123
 
        memset(thread->gcFreeLists, JS_FREE_PATTERN,
124
 
               sizeof(thread->gcFreeLists));
125
 
#endif
126
 
    }
127
 
    return thread;
128
 
}
129
 
 
130
 
/*
131
 
 * Sets current thread as owning thread of a context by assigning the
132
 
 * thread-private info to the context. If the current thread doesn't have
133
 
 * private JSThread info, create one.
134
 
 */
135
 
JSBool
136
 
js_SetContextThread(JSContext *cx)
137
 
{
138
 
    JSThread *thread = js_GetCurrentThread(cx->runtime);
139
 
 
140
 
    if (!thread) {
141
 
        JS_ReportOutOfMemory(cx);
142
 
        return JS_FALSE;
143
 
    }
144
 
 
145
 
    /*
146
 
     * Clear gcFreeLists on each transition from 0 to 1 context active on the
147
 
     * current thread. See bug 351602.
148
 
     */
149
 
    if (JS_CLIST_IS_EMPTY(&thread->contextList))
150
 
        memset(thread->gcFreeLists, 0, sizeof(thread->gcFreeLists));
151
 
 
152
 
    cx->thread = thread;
153
 
    JS_REMOVE_LINK(&cx->threadLinks);
154
 
    JS_APPEND_LINK(&cx->threadLinks, &thread->contextList);
155
 
    return JS_TRUE;
156
 
}
157
 
 
158
 
/* Remove the owning thread info of a context. */
159
 
void
160
 
js_ClearContextThread(JSContext *cx)
161
 
{
162
 
    JS_REMOVE_AND_INIT_LINK(&cx->threadLinks);
163
 
#ifdef DEBUG
164
 
    if (JS_CLIST_IS_EMPTY(&cx->thread->contextList)) {
165
 
        memset(cx->thread->gcFreeLists, JS_FREE_PATTERN,
166
 
               sizeof(cx->thread->gcFreeLists));
167
 
    }
168
 
#endif
169
 
    cx->thread = NULL;
170
 
}
171
 
 
172
 
#endif /* JS_THREADSAFE */
173
 
 
174
 
void
175
 
js_OnVersionChange(JSContext *cx)
176
 
{
177
 
#ifdef DEBUG
178
 
    JSVersion version = JSVERSION_NUMBER(cx);
179
 
 
180
 
    JS_ASSERT(version == JSVERSION_DEFAULT || version >= JSVERSION_ECMA_3);
181
 
#endif
182
 
}
183
 
 
184
 
void
185
 
js_SetVersion(JSContext *cx, JSVersion version)
186
 
{
187
 
    cx->version = version;
188
 
    js_OnVersionChange(cx);
189
 
}
190
 
 
191
 
JSContext *
192
 
js_NewContext(JSRuntime *rt, size_t stackChunkSize)
193
 
{
194
 
    JSContext *cx;
195
 
    JSBool ok, first;
196
 
    JSContextCallback cxCallback;
197
 
 
198
 
    cx = (JSContext *) malloc(sizeof *cx);
199
 
    if (!cx)
200
 
        return NULL;
201
 
    memset(cx, 0, sizeof *cx);
202
 
 
203
 
    cx->runtime = rt;
204
 
#if JS_STACK_GROWTH_DIRECTION > 0
205
 
    cx->stackLimit = (jsuword)-1;
206
 
#endif
207
 
#ifdef JS_THREADSAFE
208
 
    JS_INIT_CLIST(&cx->threadLinks);
209
 
    js_SetContextThread(cx);
210
 
#endif
211
 
 
212
 
    JS_LOCK_GC(rt);
213
 
    for (;;) {
214
 
        first = (rt->contextList.next == &rt->contextList);
215
 
        if (rt->state == JSRTS_UP) {
216
 
            JS_ASSERT(!first);
217
 
            break;
218
 
        }
219
 
        if (rt->state == JSRTS_DOWN) {
220
 
            JS_ASSERT(first);
221
 
            rt->state = JSRTS_LAUNCHING;
222
 
            break;
223
 
        }
224
 
        JS_WAIT_CONDVAR(rt->stateChange, JS_NO_TIMEOUT);
225
 
    }
226
 
    JS_APPEND_LINK(&cx->links, &rt->contextList);
227
 
    JS_UNLOCK_GC(rt);
228
 
 
229
 
    /*
230
 
     * First we do the infallible, every-time per-context initializations.
231
 
     * Should a later, fallible initialization (js_InitRegExpStatics, e.g.,
232
 
     * or the stuff under 'if (first)' below) fail, at least the version
233
 
     * and arena-pools will be valid and safe to use (say, from the last GC
234
 
     * done by js_DestroyContext).
235
 
     */
236
 
    cx->version = JSVERSION_DEFAULT;
237
 
    cx->jsop_eq = JSOP_EQ;
238
 
    cx->jsop_ne = JSOP_NE;
239
 
    JS_InitArenaPool(&cx->stackPool, "stack", stackChunkSize, sizeof(jsval));
240
 
    JS_InitArenaPool(&cx->tempPool, "temp", 1024, sizeof(jsdouble));
241
 
 
242
 
    if (!js_InitRegExpStatics(cx, &cx->regExpStatics)) {
243
 
        js_DestroyContext(cx, JSDCM_NEW_FAILED);
244
 
        return NULL;
245
 
    }
246
 
 
247
 
    /*
248
 
     * If cx is the first context on this runtime, initialize well-known atoms,
249
 
     * keywords, numbers, and strings.  If one of these steps should fail, the
250
 
     * runtime will be left in a partially initialized state, with zeroes and
251
 
     * nulls stored in the default-initialized remainder of the struct.  We'll
252
 
     * clean the runtime up under js_DestroyContext, because cx will be "last"
253
 
     * as well as "first".
254
 
     */
255
 
    if (first) {
256
 
#ifdef JS_THREADSAFE
257
 
        JS_BeginRequest(cx);
258
 
#endif
259
 
        /*
260
 
         * Both atomState and the scriptFilenameTable may be left over from a
261
 
         * previous episode of non-zero contexts alive in rt, so don't re-init
262
 
         * either table if it's not necessary.  Just repopulate atomState with
263
 
         * well-known internal atoms, and with the reserved identifiers added
264
 
         * by the scanner.
265
 
         */
266
 
        ok = (rt->atomState.liveAtoms == 0)
267
 
             ? js_InitAtomState(cx, &rt->atomState)
268
 
             : js_InitPinnedAtoms(cx, &rt->atomState);
269
 
        if (ok && !rt->scriptFilenameTable)
270
 
            ok = js_InitRuntimeScriptState(rt);
271
 
        if (ok)
272
 
            ok = js_InitRuntimeNumberState(cx);
273
 
        if (ok)
274
 
            ok = js_InitRuntimeStringState(cx);
275
 
#ifdef JS_THREADSAFE
276
 
        JS_EndRequest(cx);
277
 
#endif
278
 
        if (!ok) {
279
 
            js_DestroyContext(cx, JSDCM_NEW_FAILED);
280
 
            return NULL;
281
 
        }
282
 
 
283
 
        JS_LOCK_GC(rt);
284
 
        rt->state = JSRTS_UP;
285
 
        JS_NOTIFY_ALL_CONDVAR(rt->stateChange);
286
 
        JS_UNLOCK_GC(rt);
287
 
    }
288
 
 
289
 
    cxCallback = rt->cxCallback;
290
 
    if (cxCallback && !cxCallback(cx, JSCONTEXT_NEW)) {
291
 
        js_DestroyContext(cx, JSDCM_NEW_FAILED);
292
 
        return NULL;
293
 
    }
294
 
    return cx;
295
 
}
296
 
 
297
 
void
298
 
js_DestroyContext(JSContext *cx, JSDestroyContextMode mode)
299
 
{
300
 
    JSRuntime *rt;
301
 
    JSContextCallback cxCallback;
302
 
    JSBool last;
303
 
    JSArgumentFormatMap *map;
304
 
    JSLocalRootStack *lrs;
305
 
    JSLocalRootChunk *lrc;
306
 
 
307
 
    rt = cx->runtime;
308
 
 
309
 
    if (mode != JSDCM_NEW_FAILED) {
310
 
        cxCallback = rt->cxCallback;
311
 
        if (cxCallback) {
312
 
            /*
313
 
             * JSCONTEXT_DESTROY callback is not allowed to fail and must
314
 
             * return true.
315
 
             */
316
 
#ifdef DEBUG
317
 
            JSBool callbackStatus =
318
 
#endif
319
 
            cxCallback(cx, JSCONTEXT_DESTROY);
320
 
            JS_ASSERT(callbackStatus);
321
 
        }
322
 
    }
323
 
 
324
 
    /* Remove cx from context list first. */
325
 
    JS_LOCK_GC(rt);
326
 
    JS_ASSERT(rt->state == JSRTS_UP || rt->state == JSRTS_LAUNCHING);
327
 
    JS_REMOVE_LINK(&cx->links);
328
 
    last = (rt->contextList.next == &rt->contextList);
329
 
    if (last)
330
 
        rt->state = JSRTS_LANDING;
331
 
    JS_UNLOCK_GC(rt);
332
 
 
333
 
    if (last) {
334
 
#ifdef JS_THREADSAFE
335
 
        /*
336
 
         * If cx is not in a request already, begin one now so that we wait
337
 
         * for any racing GC started on a not-last context to finish, before
338
 
         * we plow ahead and unpin atoms.  Note that even though we begin a
339
 
         * request here if necessary, we end all requests on cx below before
340
 
         * forcing a final GC.  This lets any not-last context destruction
341
 
         * racing in another thread try to force or maybe run the GC, but by
342
 
         * that point, rt->state will not be JSRTS_UP, and that GC attempt
343
 
         * will return early.
344
 
         */
345
 
        if (cx->requestDepth == 0)
346
 
            JS_BeginRequest(cx);
347
 
#endif
348
 
 
349
 
        /* Unpin all pinned atoms before final GC. */
350
 
        js_UnpinPinnedAtoms(&rt->atomState);
351
 
 
352
 
        /* Unlock and clear GC things held by runtime pointers. */
353
 
        js_FinishRuntimeNumberState(cx);
354
 
        js_FinishRuntimeStringState(cx);
355
 
 
356
 
        /* Clear debugging state to remove GC roots. */
357
 
        JS_ClearAllTraps(cx);
358
 
        JS_ClearAllWatchPoints(cx);
359
 
    }
360
 
 
361
 
    /*
362
 
     * Remove more GC roots in regExpStatics, then collect garbage.
363
 
     * XXX anti-modularity alert: we rely on the call to js_RemoveRoot within
364
 
     * XXX this function call to wait for any racing GC to complete, in the
365
 
     * XXX case where JS_DestroyContext is called outside of a request on cx
366
 
     */
367
 
    js_FreeRegExpStatics(cx, &cx->regExpStatics);
368
 
 
369
 
#ifdef JS_THREADSAFE
370
 
    /*
371
 
     * Destroying a context implicitly calls JS_EndRequest().  Also, we must
372
 
     * end our request here in case we are "last" -- in that event, another
373
 
     * js_DestroyContext that was not last might be waiting in the GC for our
374
 
     * request to end.  We'll let it run below, just before we do the truly
375
 
     * final GC and then free atom state.
376
 
     *
377
 
     * At this point, cx must be inaccessible to other threads.  It's off the
378
 
     * rt->contextList, and it should not be reachable via any object private
379
 
     * data structure.
380
 
     */
381
 
    while (cx->requestDepth != 0)
382
 
        JS_EndRequest(cx);
383
 
#endif
384
 
 
385
 
    if (last) {
386
 
        js_GC(cx, GC_LAST_CONTEXT);
387
 
 
388
 
        /* Try to free atom state, now that no unrooted scripts survive. */
389
 
        if (rt->atomState.liveAtoms == 0)
390
 
            js_FreeAtomState(cx, &rt->atomState);
391
 
 
392
 
        /* Also free the script filename table if it exists and is empty. */
393
 
        if (rt->scriptFilenameTable && rt->scriptFilenameTable->nentries == 0)
394
 
            js_FinishRuntimeScriptState(rt);
395
 
 
396
 
        /*
397
 
         * Free the deflated string cache, but only after the last GC has
398
 
         * collected all unleaked strings.
399
 
         */
400
 
        js_FinishDeflatedStringCache(rt);
401
 
 
402
 
        /* Take the runtime down, now that it has no contexts or atoms. */
403
 
        JS_LOCK_GC(rt);
404
 
        rt->state = JSRTS_DOWN;
405
 
        JS_NOTIFY_ALL_CONDVAR(rt->stateChange);
406
 
        JS_UNLOCK_GC(rt);
407
 
    } else {
408
 
        if (mode == JSDCM_FORCE_GC)
409
 
            js_GC(cx, GC_NORMAL);
410
 
        else if (mode == JSDCM_MAYBE_GC)
411
 
            JS_MaybeGC(cx);
412
 
    }
413
 
 
414
 
    /* Free the stuff hanging off of cx. */
415
 
    JS_FinishArenaPool(&cx->stackPool);
416
 
    JS_FinishArenaPool(&cx->tempPool);
417
 
 
418
 
    if (cx->lastMessage)
419
 
        free(cx->lastMessage);
420
 
 
421
 
    /* Remove any argument formatters. */
422
 
    map = cx->argumentFormatMap;
423
 
    while (map) {
424
 
        JSArgumentFormatMap *temp = map;
425
 
        map = map->next;
426
 
        JS_free(cx, temp);
427
 
    }
428
 
 
429
 
    /* Destroy the resolve recursion damper. */
430
 
    if (cx->resolvingTable) {
431
 
        JS_DHashTableDestroy(cx->resolvingTable);
432
 
        cx->resolvingTable = NULL;
433
 
    }
434
 
 
435
 
    lrs = cx->localRootStack;
436
 
    if (lrs) {
437
 
        while ((lrc = lrs->topChunk) != &lrs->firstChunk) {
438
 
            lrs->topChunk = lrc->down;
439
 
            JS_free(cx, lrc);
440
 
        }
441
 
        JS_free(cx, lrs);
442
 
    }
443
 
 
444
 
#ifdef JS_THREADSAFE
445
 
    js_ClearContextThread(cx);
446
 
#endif
447
 
 
448
 
    /* Finally, free cx itself. */
449
 
    free(cx);
450
 
}
451
 
 
452
 
JSBool
453
 
js_ValidContextPointer(JSRuntime *rt, JSContext *cx)
454
 
{
455
 
    JSCList *cl;
456
 
 
457
 
    for (cl = rt->contextList.next; cl != &rt->contextList; cl = cl->next) {
458
 
        if (cl == &cx->links)
459
 
            return JS_TRUE;
460
 
    }
461
 
    JS_RUNTIME_METER(rt, deadContexts);
462
 
    return JS_FALSE;
463
 
}
464
 
 
465
 
JSContext *
466
 
js_ContextIterator(JSRuntime *rt, JSBool unlocked, JSContext **iterp)
467
 
{
468
 
    JSContext *cx = *iterp;
469
 
 
470
 
    if (unlocked)
471
 
        JS_LOCK_GC(rt);
472
 
    if (!cx)
473
 
        cx = (JSContext *)&rt->contextList;
474
 
    cx = (JSContext *)cx->links.next;
475
 
    if (&cx->links == &rt->contextList)
476
 
        cx = NULL;
477
 
    *iterp = cx;
478
 
    if (unlocked)
479
 
        JS_UNLOCK_GC(rt);
480
 
    return cx;
481
 
}
482
 
 
483
 
JS_STATIC_DLL_CALLBACK(const void *)
484
 
resolving_GetKey(JSDHashTable *table, JSDHashEntryHdr *hdr)
485
 
{
486
 
    JSResolvingEntry *entry = (JSResolvingEntry *)hdr;
487
 
 
488
 
    return &entry->key;
489
 
}
490
 
 
491
 
JS_STATIC_DLL_CALLBACK(JSDHashNumber)
492
 
resolving_HashKey(JSDHashTable *table, const void *ptr)
493
 
{
494
 
    const JSResolvingKey *key = (const JSResolvingKey *)ptr;
495
 
 
496
 
    return ((JSDHashNumber)JS_PTR_TO_UINT32(key->obj) >> JSVAL_TAGBITS) ^ key->id;
497
 
}
498
 
 
499
 
JS_PUBLIC_API(JSBool)
500
 
resolving_MatchEntry(JSDHashTable *table,
501
 
                     const JSDHashEntryHdr *hdr,
502
 
                     const void *ptr)
503
 
{
504
 
    const JSResolvingEntry *entry = (const JSResolvingEntry *)hdr;
505
 
    const JSResolvingKey *key = (const JSResolvingKey *)ptr;
506
 
 
507
 
    return entry->key.obj == key->obj && entry->key.id == key->id;
508
 
}
509
 
 
510
 
static const JSDHashTableOps resolving_dhash_ops = {
511
 
    JS_DHashAllocTable,
512
 
    JS_DHashFreeTable,
513
 
    resolving_GetKey,
514
 
    resolving_HashKey,
515
 
    resolving_MatchEntry,
516
 
    JS_DHashMoveEntryStub,
517
 
    JS_DHashClearEntryStub,
518
 
    JS_DHashFinalizeStub,
519
 
    NULL
520
 
};
521
 
 
522
 
JSBool
523
 
js_StartResolving(JSContext *cx, JSResolvingKey *key, uint32 flag,
524
 
                  JSResolvingEntry **entryp)
525
 
{
526
 
    JSDHashTable *table;
527
 
    JSResolvingEntry *entry;
528
 
 
529
 
    table = cx->resolvingTable;
530
 
    if (!table) {
531
 
        table = JS_NewDHashTable(&resolving_dhash_ops, NULL,
532
 
                                 sizeof(JSResolvingEntry),
533
 
                                 JS_DHASH_MIN_SIZE);
534
 
        if (!table)
535
 
            goto outofmem;
536
 
        cx->resolvingTable = table;
537
 
    }
538
 
 
539
 
    entry = (JSResolvingEntry *)
540
 
            JS_DHashTableOperate(table, key, JS_DHASH_ADD);
541
 
    if (!entry)
542
 
        goto outofmem;
543
 
 
544
 
    if (entry->flags & flag) {
545
 
        /* An entry for (key, flag) exists already -- dampen recursion. */
546
 
        entry = NULL;
547
 
    } else {
548
 
        /* Fill in key if we were the first to add entry, then set flag. */
549
 
        if (!entry->key.obj)
550
 
            entry->key = *key;
551
 
        entry->flags |= flag;
552
 
    }
553
 
    *entryp = entry;
554
 
    return JS_TRUE;
555
 
 
556
 
outofmem:
557
 
    JS_ReportOutOfMemory(cx);
558
 
    return JS_FALSE;
559
 
}
560
 
 
561
 
void
562
 
js_StopResolving(JSContext *cx, JSResolvingKey *key, uint32 flag,
563
 
                 JSResolvingEntry *entry, uint32 generation)
564
 
{
565
 
    JSDHashTable *table;
566
 
 
567
 
    /*
568
 
     * Clear flag from entry->flags and return early if other flags remain.
569
 
     * We must take care to re-lookup entry if the table has changed since
570
 
     * it was found by js_StartResolving.
571
 
     */
572
 
    table = cx->resolvingTable;
573
 
    if (!entry || table->generation != generation) {
574
 
        entry = (JSResolvingEntry *)
575
 
                JS_DHashTableOperate(table, key, JS_DHASH_LOOKUP);
576
 
    }
577
 
    JS_ASSERT(JS_DHASH_ENTRY_IS_BUSY(&entry->hdr));
578
 
    entry->flags &= ~flag;
579
 
    if (entry->flags)
580
 
        return;
581
 
 
582
 
    /*
583
 
     * Do a raw remove only if fewer entries were removed than would cause
584
 
     * alpha to be less than .5 (alpha is at most .75).  Otherwise, we just
585
 
     * call JS_DHashTableOperate to re-lookup the key and remove its entry,
586
 
     * compressing or shrinking the table as needed.
587
 
     */
588
 
    if (table->removedCount < JS_DHASH_TABLE_SIZE(table) >> 2)
589
 
        JS_DHashTableRawRemove(table, &entry->hdr);
590
 
    else
591
 
        JS_DHashTableOperate(table, key, JS_DHASH_REMOVE);
592
 
}
593
 
 
594
 
JSBool
595
 
js_EnterLocalRootScope(JSContext *cx)
596
 
{
597
 
    JSLocalRootStack *lrs;
598
 
    int mark;
599
 
 
600
 
    lrs = cx->localRootStack;
601
 
    if (!lrs) {
602
 
        lrs = (JSLocalRootStack *) JS_malloc(cx, sizeof *lrs);
603
 
        if (!lrs)
604
 
            return JS_FALSE;
605
 
        lrs->scopeMark = JSLRS_NULL_MARK;
606
 
        lrs->rootCount = 0;
607
 
        lrs->topChunk = &lrs->firstChunk;
608
 
        lrs->firstChunk.down = NULL;
609
 
        cx->localRootStack = lrs;
610
 
    }
611
 
 
612
 
    /* Push lrs->scopeMark to save it for restore when leaving. */
613
 
    mark = js_PushLocalRoot(cx, lrs, INT_TO_JSVAL(lrs->scopeMark));
614
 
    if (mark < 0)
615
 
        return JS_FALSE;
616
 
    lrs->scopeMark = (uint32) mark;
617
 
    return JS_TRUE;
618
 
}
619
 
 
620
 
void
621
 
js_LeaveLocalRootScopeWithResult(JSContext *cx, jsval rval)
622
 
{
623
 
    JSLocalRootStack *lrs;
624
 
    uint32 mark, m, n;
625
 
    JSLocalRootChunk *lrc;
626
 
 
627
 
    /* Defend against buggy native callers. */
628
 
    lrs = cx->localRootStack;
629
 
    JS_ASSERT(lrs && lrs->rootCount != 0);
630
 
    if (!lrs || lrs->rootCount == 0)
631
 
        return;
632
 
 
633
 
    mark = lrs->scopeMark;
634
 
    JS_ASSERT(mark != JSLRS_NULL_MARK);
635
 
    if (mark == JSLRS_NULL_MARK)
636
 
        return;
637
 
 
638
 
    /* Free any chunks being popped by this leave operation. */
639
 
    m = mark >> JSLRS_CHUNK_SHIFT;
640
 
    n = (lrs->rootCount - 1) >> JSLRS_CHUNK_SHIFT;
641
 
    while (n > m) {
642
 
        lrc = lrs->topChunk;
643
 
        JS_ASSERT(lrc != &lrs->firstChunk);
644
 
        lrs->topChunk = lrc->down;
645
 
        JS_free(cx, lrc);
646
 
        --n;
647
 
    }
648
 
 
649
 
    /*
650
 
     * Pop the scope, restoring lrs->scopeMark.  If rval is a GC-thing, push
651
 
     * it on the caller's scope, or store it in lastInternalResult if we are
652
 
     * leaving the outermost scope.  We don't need to allocate a new lrc
653
 
     * because we can overwrite the old mark's slot with rval.
654
 
     */
655
 
    lrc = lrs->topChunk;
656
 
    m = mark & JSLRS_CHUNK_MASK;
657
 
    lrs->scopeMark = (uint32) JSVAL_TO_INT(lrc->roots[m]);
658
 
    if (JSVAL_IS_GCTHING(rval) && !JSVAL_IS_NULL(rval)) {
659
 
        if (mark == 0) {
660
 
            cx->weakRoots.lastInternalResult = rval;
661
 
        } else {
662
 
            /*
663
 
             * Increment m to avoid the "else if (m == 0)" case below.  If
664
 
             * rval is not a GC-thing, that case would take care of freeing
665
 
             * any chunk that contained only the old mark.  Since rval *is*
666
 
             * a GC-thing here, we want to reuse that old mark's slot.
667
 
             */
668
 
            lrc->roots[m++] = rval;
669
 
            ++mark;
670
 
        }
671
 
    }
672
 
    lrs->rootCount = (uint32) mark;
673
 
 
674
 
    /*
675
 
     * Free the stack eagerly, risking malloc churn.  The alternative would
676
 
     * require an lrs->entryCount member, maintained by Enter and Leave, and
677
 
     * tested by the GC in addition to the cx->localRootStack non-null test.
678
 
     *
679
 
     * That approach would risk hoarding 264 bytes (net) per context.  Right
680
 
     * now it seems better to give fresh (dirty in CPU write-back cache, and
681
 
     * the data is no longer needed) memory back to the malloc heap.
682
 
     */
683
 
    if (mark == 0) {
684
 
        cx->localRootStack = NULL;
685
 
        JS_free(cx, lrs);
686
 
    } else if (m == 0) {
687
 
        lrs->topChunk = lrc->down;
688
 
        JS_free(cx, lrc);
689
 
    }
690
 
}
691
 
 
692
 
void
693
 
js_ForgetLocalRoot(JSContext *cx, jsval v)
694
 
{
695
 
    JSLocalRootStack *lrs;
696
 
    uint32 i, j, m, n, mark;
697
 
    JSLocalRootChunk *lrc, *lrc2;
698
 
    jsval top;
699
 
 
700
 
    lrs = cx->localRootStack;
701
 
    JS_ASSERT(lrs && lrs->rootCount);
702
 
    if (!lrs || lrs->rootCount == 0)
703
 
        return;
704
 
 
705
 
    /* Prepare to pop the top-most value from the stack. */
706
 
    n = lrs->rootCount - 1;
707
 
    m = n & JSLRS_CHUNK_MASK;
708
 
    lrc = lrs->topChunk;
709
 
    top = lrc->roots[m];
710
 
 
711
 
    /* Be paranoid about calls on an empty scope. */
712
 
    mark = lrs->scopeMark;
713
 
    JS_ASSERT(mark < n);
714
 
    if (mark >= n)
715
 
        return;
716
 
 
717
 
    /* If v was not the last root pushed in the top scope, find it. */
718
 
    if (top != v) {
719
 
        /* Search downward in case v was recently pushed. */
720
 
        i = n;
721
 
        j = m;
722
 
        lrc2 = lrc;
723
 
        while (--i > mark) {
724
 
            if (j == 0)
725
 
                lrc2 = lrc2->down;
726
 
            j = i & JSLRS_CHUNK_MASK;
727
 
            if (lrc2->roots[j] == v)
728
 
                break;
729
 
        }
730
 
 
731
 
        /* If we didn't find v in this scope, assert and bail out. */
732
 
        JS_ASSERT(i != mark);
733
 
        if (i == mark)
734
 
            return;
735
 
 
736
 
        /* Swap top and v so common tail code can pop v. */
737
 
        lrc2->roots[j] = top;
738
 
    }
739
 
 
740
 
    /* Pop the last value from the stack. */
741
 
    lrc->roots[m] = JSVAL_NULL;
742
 
    lrs->rootCount = n;
743
 
    if (m == 0) {
744
 
        JS_ASSERT(n != 0);
745
 
        JS_ASSERT(lrc != &lrs->firstChunk);
746
 
        lrs->topChunk = lrc->down;
747
 
        JS_free(cx, lrc);
748
 
    }
749
 
}
750
 
 
751
 
int
752
 
js_PushLocalRoot(JSContext *cx, JSLocalRootStack *lrs, jsval v)
753
 
{
754
 
    uint32 n, m;
755
 
    JSLocalRootChunk *lrc;
756
 
 
757
 
    n = lrs->rootCount;
758
 
    m = n & JSLRS_CHUNK_MASK;
759
 
    if (n == 0 || m != 0) {
760
 
        /*
761
 
         * At start of first chunk, or not at start of a non-first top chunk.
762
 
         * Check for lrs->rootCount overflow.
763
 
         */
764
 
        if ((uint32)(n + 1) == 0) {
765
 
            JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
766
 
                                 JSMSG_TOO_MANY_LOCAL_ROOTS);
767
 
            return -1;
768
 
        }
769
 
        lrc = lrs->topChunk;
770
 
        JS_ASSERT(n != 0 || lrc == &lrs->firstChunk);
771
 
    } else {
772
 
        /*
773
 
         * After lrs->firstChunk, trying to index at a power-of-two chunk
774
 
         * boundary: need a new chunk.
775
 
         */
776
 
        lrc = (JSLocalRootChunk *) JS_malloc(cx, sizeof *lrc);
777
 
        if (!lrc)
778
 
            return -1;
779
 
        lrc->down = lrs->topChunk;
780
 
        lrs->topChunk = lrc;
781
 
    }
782
 
    lrs->rootCount = n + 1;
783
 
    lrc->roots[m] = v;
784
 
    return (int) n;
785
 
}
786
 
 
787
 
void
788
 
js_MarkLocalRoots(JSContext *cx, JSLocalRootStack *lrs)
789
 
{
790
 
    uint32 n, m, mark;
791
 
    JSLocalRootChunk *lrc;
792
 
 
793
 
    n = lrs->rootCount;
794
 
    if (n == 0)
795
 
        return;
796
 
 
797
 
    mark = lrs->scopeMark;
798
 
    lrc = lrs->topChunk;
799
 
    do {
800
 
        while (--n > mark) {
801
 
#ifdef GC_MARK_DEBUG
802
 
            char name[22];
803
 
            JS_snprintf(name, sizeof name, "<local root %u>", n);
804
 
#endif
805
 
            m = n & JSLRS_CHUNK_MASK;
806
 
            JS_ASSERT(JSVAL_IS_GCTHING(lrc->roots[m]));
807
 
            GC_MARK(cx, JSVAL_TO_GCTHING(lrc->roots[m]), name);
808
 
            if (m == 0)
809
 
                lrc = lrc->down;
810
 
        }
811
 
        m = n & JSLRS_CHUNK_MASK;
812
 
        mark = JSVAL_TO_INT(lrc->roots[m]);
813
 
        if (m == 0)
814
 
            lrc = lrc->down;
815
 
    } while (n != 0);
816
 
    JS_ASSERT(!lrc);
817
 
}
818
 
 
819
 
static void
820
 
ReportError(JSContext *cx, const char *message, JSErrorReport *reportp)
821
 
{
822
 
    /*
823
 
     * Check the error report, and set a JavaScript-catchable exception
824
 
     * if the error is defined to have an associated exception.  If an
825
 
     * exception is thrown, then the JSREPORT_EXCEPTION flag will be set
826
 
     * on the error report, and exception-aware hosts should ignore it.
827
 
     */
828
 
    JS_ASSERT(reportp);
829
 
    if (reportp->errorNumber == JSMSG_UNCAUGHT_EXCEPTION)
830
 
        reportp->flags |= JSREPORT_EXCEPTION;
831
 
 
832
 
    /*
833
 
     * Call the error reporter only if an exception wasn't raised.
834
 
     *
835
 
     * If an exception was raised, then we call the debugErrorHook
836
 
     * (if present) to give it a chance to see the error before it
837
 
     * propagates out of scope.  This is needed for compatability
838
 
     * with the old scheme.
839
 
     */
840
 
    if (!js_ErrorToException(cx, message, reportp)) {
841
 
        js_ReportErrorAgain(cx, message, reportp);
842
 
    } else if (cx->runtime->debugErrorHook && cx->errorReporter) {
843
 
        JSDebugErrorHook hook = cx->runtime->debugErrorHook;
844
 
        /* test local in case debugErrorHook changed on another thread */
845
 
        if (hook)
846
 
            hook(cx, message, reportp, cx->runtime->debugErrorHookData);
847
 
    }
848
 
}
849
 
 
850
 
/*
851
 
 * We don't post an exception in this case, since doing so runs into
852
 
 * complications of pre-allocating an exception object which required
853
 
 * running the Exception class initializer early etc.
854
 
 * Instead we just invoke the errorReporter with an "Out Of Memory"
855
 
 * type message, and then hope the process ends swiftly.
856
 
 */
857
 
void
858
 
js_ReportOutOfMemory(JSContext *cx)
859
 
{
860
 
    JSStackFrame *fp;
861
 
    JSErrorReport report;
862
 
    JSErrorReporter onError = cx->errorReporter;
863
 
 
864
 
    /* Get the message for this error, but we won't expand any arguments. */
865
 
    const JSErrorFormatString *efs =
866
 
        js_GetLocalizedErrorMessage(cx, NULL, NULL, JSMSG_OUT_OF_MEMORY);
867
 
    const char *msg = efs ? efs->format : "Out of memory";
868
 
 
869
 
    /* Fill out the report, but don't do anything that requires allocation. */
870
 
    memset(&report, 0, sizeof (struct JSErrorReport));
871
 
    report.flags = JSREPORT_ERROR;
872
 
    report.errorNumber = JSMSG_OUT_OF_MEMORY;
873
 
 
874
 
    /*
875
 
     * Walk stack until we find a frame that is associated with some script
876
 
     * rather than a native frame.
877
 
     */
878
 
    for (fp = cx->fp; fp; fp = fp->down) {
879
 
        if (fp->script && fp->pc) {
880
 
            report.filename = fp->script->filename;
881
 
            report.lineno = js_PCToLineNumber(cx, fp->script, fp->pc);
882
 
            break;
883
 
        }
884
 
    }
885
 
 
886
 
    /*
887
 
     * If debugErrorHook is present then we give it a chance to veto
888
 
     * sending the error on to the regular ErrorReporter.
889
 
     */
890
 
    if (onError) {
891
 
        JSDebugErrorHook hook = cx->runtime->debugErrorHook;
892
 
        if (hook &&
893
 
            !hook(cx, msg, &report, cx->runtime->debugErrorHookData)) {
894
 
            onError = NULL;
895
 
        }
896
 
    }
897
 
 
898
 
    if (onError)
899
 
        onError(cx, msg, &report);
900
 
}
901
 
 
902
 
JSBool
903
 
js_ReportErrorVA(JSContext *cx, uintN flags, const char *format, va_list ap)
904
 
{
905
 
    char *message;
906
 
    jschar *ucmessage;
907
 
    size_t messagelen;
908
 
    JSStackFrame *fp;
909
 
    JSErrorReport report;
910
 
    JSBool warning;
911
 
 
912
 
    if ((flags & JSREPORT_STRICT) && !JS_HAS_STRICT_OPTION(cx))
913
 
        return JS_TRUE;
914
 
 
915
 
    message = JS_vsmprintf(format, ap);
916
 
    if (!message)
917
 
        return JS_FALSE;
918
 
    messagelen = strlen(message);
919
 
 
920
 
    memset(&report, 0, sizeof (struct JSErrorReport));
921
 
    report.flags = flags;
922
 
    report.errorNumber = JSMSG_USER_DEFINED_ERROR;
923
 
    report.ucmessage = ucmessage = js_InflateString(cx, message, &messagelen);
924
 
 
925
 
    /* Find the top-most active script frame, for best line number blame. */
926
 
    for (fp = cx->fp; fp; fp = fp->down) {
927
 
        if (fp->script && fp->pc) {
928
 
            report.filename = fp->script->filename;
929
 
            report.lineno = js_PCToLineNumber(cx, fp->script, fp->pc);
930
 
            break;
931
 
        }
932
 
    }
933
 
 
934
 
    warning = JSREPORT_IS_WARNING(report.flags);
935
 
    if (warning && JS_HAS_WERROR_OPTION(cx)) {
936
 
        report.flags &= ~JSREPORT_WARNING;
937
 
        warning = JS_FALSE;
938
 
    }
939
 
 
940
 
    ReportError(cx, message, &report);
941
 
    free(message);
942
 
    JS_free(cx, ucmessage);
943
 
    return warning;
944
 
}
945
 
 
946
 
/*
947
 
 * The arguments from ap need to be packaged up into an array and stored
948
 
 * into the report struct.
949
 
 *
950
 
 * The format string addressed by the error number may contain operands
951
 
 * identified by the format {N}, where N is a decimal digit. Each of these
952
 
 * is to be replaced by the Nth argument from the va_list. The complete
953
 
 * message is placed into reportp->ucmessage converted to a JSString.
954
 
 *
955
 
 * Returns true if the expansion succeeds (can fail if out of memory).
956
 
 */
957
 
JSBool
958
 
js_ExpandErrorArguments(JSContext *cx, JSErrorCallback callback,
959
 
                        void *userRef, const uintN errorNumber,
960
 
                        char **messagep, JSErrorReport *reportp,
961
 
                        JSBool *warningp, JSBool charArgs, va_list ap)
962
 
{
963
 
    const JSErrorFormatString *efs;
964
 
    int i;
965
 
    int argCount;
966
 
 
967
 
    *warningp = JSREPORT_IS_WARNING(reportp->flags);
968
 
    if (*warningp && JS_HAS_WERROR_OPTION(cx)) {
969
 
        reportp->flags &= ~JSREPORT_WARNING;
970
 
        *warningp = JS_FALSE;
971
 
    }
972
 
 
973
 
    *messagep = NULL;
974
 
 
975
 
    /* Most calls supply js_GetErrorMessage; if this is so, assume NULL. */
976
 
    if (!callback || callback == js_GetErrorMessage)
977
 
        efs = js_GetLocalizedErrorMessage(cx, userRef, NULL, errorNumber);
978
 
    else
979
 
        efs = callback(userRef, NULL, errorNumber);
980
 
    if (efs) {
981
 
        size_t totalArgsLength = 0;
982
 
        size_t argLengths[10]; /* only {0} thru {9} supported */
983
 
        argCount = efs->argCount;
984
 
        JS_ASSERT(argCount <= 10);
985
 
        if (argCount > 0) {
986
 
            /*
987
 
             * Gather the arguments into an array, and accumulate
988
 
             * their sizes. We allocate 1 more than necessary and
989
 
             * null it out to act as the caboose when we free the
990
 
             * pointers later.
991
 
             */
992
 
            reportp->messageArgs = (const jschar **)
993
 
                JS_malloc(cx, sizeof(jschar *) * (argCount + 1));
994
 
            if (!reportp->messageArgs)
995
 
                return JS_FALSE;
996
 
            reportp->messageArgs[argCount] = NULL;
997
 
            for (i = 0; i < argCount; i++) {
998
 
                if (charArgs) {
999
 
                    char *charArg = va_arg(ap, char *);
1000
 
                    size_t charArgLength = strlen(charArg);
1001
 
                    reportp->messageArgs[i]
1002
 
                        = js_InflateString(cx, charArg, &charArgLength);
1003
 
                    if (!reportp->messageArgs[i])
1004
 
                        goto error;
1005
 
                } else {
1006
 
                    reportp->messageArgs[i] = va_arg(ap, jschar *);
1007
 
                }
1008
 
                argLengths[i] = js_strlen(reportp->messageArgs[i]);
1009
 
                totalArgsLength += argLengths[i];
1010
 
            }
1011
 
            /* NULL-terminate for easy copying. */
1012
 
            reportp->messageArgs[i] = NULL;
1013
 
        }
1014
 
        /*
1015
 
         * Parse the error format, substituting the argument X
1016
 
         * for {X} in the format.
1017
 
         */
1018
 
        if (argCount > 0) {
1019
 
            if (efs->format) {
1020
 
                jschar *buffer, *fmt, *out;
1021
 
                int expandedArgs = 0;
1022
 
                size_t expandedLength;
1023
 
                size_t len = strlen(efs->format);
1024
 
 
1025
 
                buffer = fmt = js_InflateString (cx, efs->format, &len);
1026
 
                if (!buffer)
1027
 
                    goto error;
1028
 
                expandedLength = len
1029
 
                                 - (3 * argCount)       /* exclude the {n} */
1030
 
                                 + totalArgsLength;
1031
 
 
1032
 
                /*
1033
 
                * Note - the above calculation assumes that each argument
1034
 
                * is used once and only once in the expansion !!!
1035
 
                */
1036
 
                reportp->ucmessage = out = (jschar *)
1037
 
                    JS_malloc(cx, (expandedLength + 1) * sizeof(jschar));
1038
 
                if (!out) {
1039
 
                    JS_free (cx, buffer);
1040
 
                    goto error;
1041
 
                }
1042
 
                while (*fmt) {
1043
 
                    if (*fmt == '{') {
1044
 
                        if (isdigit(fmt[1])) {
1045
 
                            int d = JS7_UNDEC(fmt[1]);
1046
 
                            JS_ASSERT(d < argCount);
1047
 
                            js_strncpy(out, reportp->messageArgs[d],
1048
 
                                       argLengths[d]);
1049
 
                            out += argLengths[d];
1050
 
                            fmt += 3;
1051
 
                            expandedArgs++;
1052
 
                            continue;
1053
 
                        }
1054
 
                    }
1055
 
                    *out++ = *fmt++;
1056
 
                }
1057
 
                JS_ASSERT(expandedArgs == argCount);
1058
 
                *out = 0;
1059
 
                JS_free (cx, buffer);
1060
 
                *messagep =
1061
 
                    js_DeflateString(cx, reportp->ucmessage,
1062
 
                                     (size_t)(out - reportp->ucmessage));
1063
 
                if (!*messagep)
1064
 
                    goto error;
1065
 
            }
1066
 
        } else {
1067
 
            /*
1068
 
             * Zero arguments: the format string (if it exists) is the
1069
 
             * entire message.
1070
 
             */
1071
 
            if (efs->format) {
1072
 
                size_t len;
1073
 
                *messagep = JS_strdup(cx, efs->format);
1074
 
                if (!*messagep)
1075
 
                    goto error;
1076
 
                len = strlen(*messagep);
1077
 
                reportp->ucmessage = js_InflateString(cx, *messagep, &len);
1078
 
                if (!reportp->ucmessage)
1079
 
                    goto error;
1080
 
            }
1081
 
        }
1082
 
    }
1083
 
    if (*messagep == NULL) {
1084
 
        /* where's the right place for this ??? */
1085
 
        const char *defaultErrorMessage
1086
 
            = "No error message available for error number %d";
1087
 
        size_t nbytes = strlen(defaultErrorMessage) + 16;
1088
 
        *messagep = (char *)JS_malloc(cx, nbytes);
1089
 
        if (!*messagep)
1090
 
            goto error;
1091
 
        JS_snprintf(*messagep, nbytes, defaultErrorMessage, errorNumber);
1092
 
    }
1093
 
    return JS_TRUE;
1094
 
 
1095
 
error:
1096
 
    if (reportp->messageArgs) {
1097
 
        /* free the arguments only if we allocated them */
1098
 
        if (charArgs) {
1099
 
            i = 0;
1100
 
            while (reportp->messageArgs[i])
1101
 
                JS_free(cx, (void *)reportp->messageArgs[i++]);
1102
 
        }
1103
 
        JS_free(cx, (void *)reportp->messageArgs);
1104
 
        reportp->messageArgs = NULL;
1105
 
    }
1106
 
    if (reportp->ucmessage) {
1107
 
        JS_free(cx, (void *)reportp->ucmessage);
1108
 
        reportp->ucmessage = NULL;
1109
 
    }
1110
 
    if (*messagep) {
1111
 
        JS_free(cx, (void *)*messagep);
1112
 
        *messagep = NULL;
1113
 
    }
1114
 
    return JS_FALSE;
1115
 
}
1116
 
 
1117
 
JSBool
1118
 
js_ReportErrorNumberVA(JSContext *cx, uintN flags, JSErrorCallback callback,
1119
 
                       void *userRef, const uintN errorNumber,
1120
 
                       JSBool charArgs, va_list ap)
1121
 
{
1122
 
    JSStackFrame *fp;
1123
 
    JSErrorReport report;
1124
 
    char *message;
1125
 
    JSBool warning;
1126
 
 
1127
 
    if ((flags & JSREPORT_STRICT) && !JS_HAS_STRICT_OPTION(cx))
1128
 
        return JS_TRUE;
1129
 
 
1130
 
    memset(&report, 0, sizeof (struct JSErrorReport));
1131
 
    report.flags = flags;
1132
 
    report.errorNumber = errorNumber;
1133
 
 
1134
 
    /*
1135
 
     * If we can't find out where the error was based on the current frame,
1136
 
     * see if the next frame has a script/pc combo we can use.
1137
 
     */
1138
 
    for (fp = cx->fp; fp; fp = fp->down) {
1139
 
        if (fp->script && fp->pc) {
1140
 
            report.filename = fp->script->filename;
1141
 
            report.lineno = js_PCToLineNumber(cx, fp->script, fp->pc);
1142
 
            break;
1143
 
        }
1144
 
    }
1145
 
 
1146
 
    if (!js_ExpandErrorArguments(cx, callback, userRef, errorNumber,
1147
 
                                 &message, &report, &warning, charArgs, ap)) {
1148
 
        return JS_FALSE;
1149
 
    }
1150
 
 
1151
 
    ReportError(cx, message, &report);
1152
 
 
1153
 
    if (message)
1154
 
        JS_free(cx, message);
1155
 
    if (report.messageArgs) {
1156
 
        /*
1157
 
         * js_ExpandErrorArguments owns its messageArgs only if it had to
1158
 
         * inflate the arguments (from regular |char *|s).
1159
 
         */
1160
 
        if (charArgs) {
1161
 
            int i = 0;
1162
 
            while (report.messageArgs[i])
1163
 
                JS_free(cx, (void *)report.messageArgs[i++]);
1164
 
        }
1165
 
        JS_free(cx, (void *)report.messageArgs);
1166
 
    }
1167
 
    if (report.ucmessage)
1168
 
        JS_free(cx, (void *)report.ucmessage);
1169
 
 
1170
 
    return warning;
1171
 
}
1172
 
 
1173
 
JS_FRIEND_API(void)
1174
 
js_ReportErrorAgain(JSContext *cx, const char *message, JSErrorReport *reportp)
1175
 
{
1176
 
    JSErrorReporter onError;
1177
 
 
1178
 
    if (!message)
1179
 
        return;
1180
 
 
1181
 
    if (cx->lastMessage)
1182
 
        free(cx->lastMessage);
1183
 
    cx->lastMessage = JS_strdup(cx, message);
1184
 
    if (!cx->lastMessage)
1185
 
        return;
1186
 
    onError = cx->errorReporter;
1187
 
 
1188
 
    /*
1189
 
     * If debugErrorHook is present then we give it a chance to veto
1190
 
     * sending the error on to the regular ErrorReporter.
1191
 
     */
1192
 
    if (onError) {
1193
 
        JSDebugErrorHook hook = cx->runtime->debugErrorHook;
1194
 
        if (hook &&
1195
 
            !hook(cx, cx->lastMessage, reportp,
1196
 
                  cx->runtime->debugErrorHookData)) {
1197
 
            onError = NULL;
1198
 
        }
1199
 
    }
1200
 
    if (onError)
1201
 
        onError(cx, cx->lastMessage, reportp);
1202
 
}
1203
 
 
1204
 
void
1205
 
js_ReportIsNotDefined(JSContext *cx, const char *name)
1206
 
{
1207
 
    JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_DEFINED, name);
1208
 
}
1209
 
 
1210
 
#if defined DEBUG && defined XP_UNIX
1211
 
/* For gdb usage. */
1212
 
void js_traceon(JSContext *cx)  { cx->tracefp = stderr; }
1213
 
void js_traceoff(JSContext *cx) { cx->tracefp = NULL; }
1214
 
#endif
1215
 
 
1216
 
JSErrorFormatString js_ErrorFormatString[JSErr_Limit] = {
1217
 
#define MSG_DEF(name, number, count, exception, format) \
1218
 
    { format, count, exception } ,
1219
 
#include "js.msg"
1220
 
#undef MSG_DEF
1221
 
};
1222
 
 
1223
 
const JSErrorFormatString *
1224
 
js_GetErrorMessage(void *userRef, const char *locale, const uintN errorNumber)
1225
 
{
1226
 
    if ((errorNumber > 0) && (errorNumber < JSErr_Limit))
1227
 
        return &js_ErrorFormatString[errorNumber];
1228
 
    return NULL;
1229
 
}