/[jscoverage]/trunk/js/jsexn.cpp
ViewVC logotype

Annotation of /trunk/js/jsexn.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 332 - (hide annotations)
Thu Oct 23 19:03:33 2008 UTC (10 years, 11 months ago) by siliconforks
File size: 44944 byte(s)
Add SpiderMonkey from Firefox 3.1b1.

The following directories and files were removed:
correct/, correct.js
liveconnect/
nanojit/
t/
v8/
vprof/
xpconnect/
all JavaScript files (Y.js, call.js, if.js, math-partial-sums.js, md5.js, perfect.js, trace-test.js, trace.js)


1 siliconforks 332 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2     * vim: set ts=8 sw=4 et tw=78:
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 standard exception implementation.
43     */
44    
45     #include "jsstddef.h"
46     #include <stdlib.h>
47     #include <string.h>
48     #include "jstypes.h"
49     #include "jsbit.h"
50     #include "jsutil.h" /* Added by JSIFY */
51     #include "jsprf.h"
52     #include "jsapi.h"
53     #include "jscntxt.h"
54     #include "jsversion.h"
55     #include "jsdbgapi.h"
56     #include "jsexn.h"
57     #include "jsfun.h"
58     #include "jsinterp.h"
59     #include "jsnum.h"
60     #include "jsobj.h"
61     #include "jsopcode.h"
62     #include "jsscope.h"
63     #include "jsscript.h"
64     #include "jsstaticcheck.h"
65    
66     /* Forward declarations for js_ErrorClass's initializer. */
67     static JSBool
68     Exception(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
69    
70     static void
71     exn_finalize(JSContext *cx, JSObject *obj);
72    
73     static void
74     exn_trace(JSTracer *trc, JSObject *obj);
75    
76     static void
77     exn_finalize(JSContext *cx, JSObject *obj);
78    
79     static JSBool
80     exn_enumerate(JSContext *cx, JSObject *obj);
81    
82     static JSBool
83     exn_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
84     JSObject **objp);
85    
86     JSClass js_ErrorClass = {
87     js_Error_str,
88     JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE | JSCLASS_MARK_IS_TRACE |
89     JSCLASS_HAS_CACHED_PROTO(JSProto_Error),
90     JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
91     exn_enumerate, (JSResolveOp)exn_resolve, JS_ConvertStub, exn_finalize,
92     NULL, NULL, NULL, Exception,
93     NULL, NULL, JS_CLASS_TRACE(exn_trace), NULL
94     };
95    
96     typedef struct JSStackTraceElem {
97     JSString *funName;
98     size_t argc;
99     const char *filename;
100     uintN ulineno;
101     } JSStackTraceElem;
102    
103     typedef struct JSExnPrivate {
104     /* A copy of the JSErrorReport originally generated. */
105     JSErrorReport *errorReport;
106     JSString *message;
107     JSString *filename;
108     uintN lineno;
109     size_t stackDepth;
110     JSStackTraceElem stackElems[1];
111     } JSExnPrivate;
112    
113     static JSString *
114     StackTraceToString(JSContext *cx, JSExnPrivate *priv);
115    
116     static JSErrorReport *
117     CopyErrorReport(JSContext *cx, JSErrorReport *report)
118     {
119     /*
120     * We use a single malloc block to make a deep copy of JSErrorReport with
121     * the following layout:
122     * JSErrorReport
123     * array of copies of report->messageArgs
124     * jschar array with characters for all messageArgs
125     * jschar array with characters for ucmessage
126     * jschar array with characters for uclinebuf and uctokenptr
127     * char array with characters for linebuf and tokenptr
128     * char array with characters for filename
129     * Such layout together with the properties enforced by the following
130     * asserts does not need any extra alignment padding.
131     */
132     JS_STATIC_ASSERT(sizeof(JSErrorReport) % sizeof(const char *) == 0);
133     JS_STATIC_ASSERT(sizeof(const char *) % sizeof(jschar) == 0);
134    
135     size_t filenameSize;
136     size_t linebufSize;
137     size_t uclinebufSize;
138     size_t ucmessageSize;
139     size_t i, argsArraySize, argsCopySize, argSize;
140     size_t mallocSize;
141     JSErrorReport *copy;
142     uint8 *cursor;
143    
144     #define JS_CHARS_SIZE(jschars) ((js_strlen(jschars) + 1) * sizeof(jschar))
145    
146     filenameSize = report->filename ? strlen(report->filename) + 1 : 0;
147     linebufSize = report->linebuf ? strlen(report->linebuf) + 1 : 0;
148     uclinebufSize = report->uclinebuf ? JS_CHARS_SIZE(report->uclinebuf) : 0;
149     ucmessageSize = 0;
150     argsArraySize = 0;
151     argsCopySize = 0;
152     if (report->ucmessage) {
153     ucmessageSize = JS_CHARS_SIZE(report->ucmessage);
154     if (report->messageArgs) {
155     for (i = 0; report->messageArgs[i]; ++i)
156     argsCopySize += JS_CHARS_SIZE(report->messageArgs[i]);
157    
158     /* Non-null messageArgs should have at least one non-null arg. */
159     JS_ASSERT(i != 0);
160     argsArraySize = (i + 1) * sizeof(const jschar *);
161     }
162     }
163    
164     /*
165     * The mallocSize can not overflow since it represents the sum of the
166     * sizes of already allocated objects.
167     */
168     mallocSize = sizeof(JSErrorReport) + argsArraySize + argsCopySize +
169     ucmessageSize + uclinebufSize + linebufSize + filenameSize;
170     cursor = (uint8 *)JS_malloc(cx, mallocSize);
171     if (!cursor)
172     return NULL;
173    
174     copy = (JSErrorReport *)cursor;
175     memset(cursor, 0, sizeof(JSErrorReport));
176     cursor += sizeof(JSErrorReport);
177    
178     if (argsArraySize != 0) {
179     copy->messageArgs = (const jschar **)cursor;
180     cursor += argsArraySize;
181     for (i = 0; report->messageArgs[i]; ++i) {
182     copy->messageArgs[i] = (const jschar *)cursor;
183     argSize = JS_CHARS_SIZE(report->messageArgs[i]);
184     memcpy(cursor, report->messageArgs[i], argSize);
185     cursor += argSize;
186     }
187     copy->messageArgs[i] = NULL;
188     JS_ASSERT(cursor == (uint8 *)copy->messageArgs[0] + argsCopySize);
189     }
190    
191     if (report->ucmessage) {
192     copy->ucmessage = (const jschar *)cursor;
193     memcpy(cursor, report->ucmessage, ucmessageSize);
194     cursor += ucmessageSize;
195     }
196    
197     if (report->uclinebuf) {
198     copy->uclinebuf = (const jschar *)cursor;
199     memcpy(cursor, report->uclinebuf, uclinebufSize);
200     cursor += uclinebufSize;
201     if (report->uctokenptr) {
202     copy->uctokenptr = copy->uclinebuf + (report->uctokenptr -
203     report->uclinebuf);
204     }
205     }
206    
207     if (report->linebuf) {
208     copy->linebuf = (const char *)cursor;
209     memcpy(cursor, report->linebuf, linebufSize);
210     cursor += linebufSize;
211     if (report->tokenptr) {
212     copy->tokenptr = copy->linebuf + (report->tokenptr -
213     report->linebuf);
214     }
215     }
216    
217     if (report->filename) {
218     copy->filename = (const char *)cursor;
219     memcpy(cursor, report->filename, filenameSize);
220     }
221     JS_ASSERT(cursor + filenameSize == (uint8 *)copy + mallocSize);
222    
223     /* Copy non-pointer members. */
224     copy->lineno = report->lineno;
225     copy->errorNumber = report->errorNumber;
226    
227     /* Note that this is before it gets flagged with JSREPORT_EXCEPTION */
228     copy->flags = report->flags;
229    
230     #undef JS_CHARS_SIZE
231     return copy;
232     }
233    
234     static jsval *
235     GetStackTraceValueBuffer(JSExnPrivate *priv)
236     {
237     /*
238     * We use extra memory after JSExnPrivateInfo.stackElems to store jsvals
239     * that helps to produce more informative stack traces. The following
240     * assert allows us to assume that no gap after stackElems is necessary to
241     * align the buffer properly.
242     */
243     JS_STATIC_ASSERT(sizeof(JSStackTraceElem) % sizeof(jsval) == 0);
244    
245     return (jsval *)(priv->stackElems + priv->stackDepth);
246     }
247    
248     static JSBool
249     InitExnPrivate(JSContext *cx, JSObject *exnObject, JSString *message,
250     JSString *filename, uintN lineno, JSErrorReport *report)
251     {
252     JSSecurityCallbacks *callbacks;
253     JSCheckAccessOp checkAccess;
254     JSErrorReporter older;
255     JSExceptionState *state;
256     jsval callerid, v;
257     JSStackFrame *fp, *fpstop;
258     size_t stackDepth, valueCount, size;
259     JSBool overflow;
260     JSExnPrivate *priv;
261     JSStackTraceElem *elem;
262     jsval *values;
263    
264     JS_ASSERT(OBJ_GET_CLASS(cx, exnObject) == &js_ErrorClass);
265    
266     /*
267     * Prepare stack trace data.
268     *
269     * Set aside any error reporter for cx and save its exception state
270     * so we can suppress any checkAccess failures. Such failures should stop
271     * the backtrace procedure, not result in a failure of this constructor.
272     */
273     callbacks = JS_GetSecurityCallbacks(cx);
274     checkAccess = callbacks
275     ? callbacks->checkObjectAccess
276     : NULL;
277     older = JS_SetErrorReporter(cx, NULL);
278     state = JS_SaveExceptionState(cx);
279    
280     callerid = ATOM_KEY(cx->runtime->atomState.callerAtom);
281     stackDepth = 0;
282     valueCount = 0;
283     for (fp = cx->fp; fp; fp = fp->down) {
284     if (fp->fun && fp->argv) {
285     v = JSVAL_NULL;
286     if (checkAccess &&
287     !checkAccess(cx, fp->callee, callerid, JSACC_READ, &v)) {
288     break;
289     }
290     valueCount += fp->argc;
291     }
292     ++stackDepth;
293     }
294     JS_RestoreExceptionState(cx, state);
295     JS_SetErrorReporter(cx, older);
296     fpstop = fp;
297    
298     size = offsetof(JSExnPrivate, stackElems);
299     overflow = (stackDepth > ((size_t)-1 - size) / sizeof(JSStackTraceElem));
300     size += stackDepth * sizeof(JSStackTraceElem);
301     overflow |= (valueCount > ((size_t)-1 - size) / sizeof(jsval));
302     size += valueCount * sizeof(jsval);
303     if (overflow) {
304     js_ReportAllocationOverflow(cx);
305     return JS_FALSE;
306     }
307     priv = (JSExnPrivate *)JS_malloc(cx, size);
308     if (!priv)
309     return JS_FALSE;
310    
311     /*
312     * We initialize errorReport with a copy of report after setting the
313     * private slot, to prevent GC accessing a junk value we clear the field
314     * here.
315     */
316     priv->errorReport = NULL;
317     priv->message = message;
318     priv->filename = filename;
319     priv->lineno = lineno;
320     priv->stackDepth = stackDepth;
321    
322     values = GetStackTraceValueBuffer(priv);
323     elem = priv->stackElems;
324     for (fp = cx->fp; fp != fpstop; fp = fp->down) {
325     if (!fp->fun) {
326     elem->funName = NULL;
327     elem->argc = 0;
328     } else {
329     elem->funName = fp->fun->atom
330     ? ATOM_TO_STRING(fp->fun->atom)
331     : cx->runtime->emptyString;
332     elem->argc = fp->argc;
333     memcpy(values, fp->argv, fp->argc * sizeof(jsval));
334     values += fp->argc;
335     }
336     elem->ulineno = 0;
337     elem->filename = NULL;
338     if (fp->script) {
339     elem->filename = fp->script->filename;
340     if (fp->regs)
341     elem->ulineno = js_PCToLineNumber(cx, fp->script, fp->regs->pc);
342     }
343     ++elem;
344     }
345     JS_ASSERT(priv->stackElems + stackDepth == elem);
346     JS_ASSERT(GetStackTraceValueBuffer(priv) + valueCount == values);
347    
348     STOBJ_SET_SLOT(exnObject, JSSLOT_PRIVATE, PRIVATE_TO_JSVAL(priv));
349    
350     if (report) {
351     /*
352     * Construct a new copy of the error report struct. We can't use the
353     * error report struct that was passed in, because it's allocated on
354     * the stack, and also because it may point to transient data in the
355     * JSTokenStream.
356     */
357     priv->errorReport = CopyErrorReport(cx, report);
358     if (!priv->errorReport) {
359     /* The finalizer realeases priv since it is in the private slot. */
360     return JS_FALSE;
361     }
362     }
363    
364     return JS_TRUE;
365     }
366    
367     static JSExnPrivate *
368     GetExnPrivate(JSContext *cx, JSObject *obj)
369     {
370     jsval privateValue;
371     JSExnPrivate *priv;
372    
373     JS_ASSERT(OBJ_GET_CLASS(cx, obj) == &js_ErrorClass);
374     privateValue = OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE);
375     if (JSVAL_IS_VOID(privateValue))
376     return NULL;
377     priv = (JSExnPrivate *)JSVAL_TO_PRIVATE(privateValue);
378     JS_ASSERT(priv);
379     return priv;
380     }
381    
382     static void
383     exn_trace(JSTracer *trc, JSObject *obj)
384     {
385     JSExnPrivate *priv;
386     JSStackTraceElem *elem;
387     size_t vcount, i;
388     jsval *vp, v;
389    
390     priv = GetExnPrivate(trc->context, obj);
391     if (priv) {
392     if (priv->message)
393     JS_CALL_STRING_TRACER(trc, priv->message, "exception message");
394     if (priv->filename)
395     JS_CALL_STRING_TRACER(trc, priv->filename, "exception filename");
396    
397     elem = priv->stackElems;
398     for (vcount = i = 0; i != priv->stackDepth; ++i, ++elem) {
399     if (elem->funName) {
400     JS_CALL_STRING_TRACER(trc, elem->funName,
401     "stack trace function name");
402     }
403     if (IS_GC_MARKING_TRACER(trc) && elem->filename)
404     js_MarkScriptFilename(elem->filename);
405     vcount += elem->argc;
406     }
407     vp = GetStackTraceValueBuffer(priv);
408     for (i = 0; i != vcount; ++i, ++vp) {
409     v = *vp;
410     JS_CALL_VALUE_TRACER(trc, v, "stack trace argument");
411     }
412     }
413     }
414    
415     static void
416     exn_finalize(JSContext *cx, JSObject *obj)
417     {
418     JSExnPrivate *priv;
419    
420     priv = GetExnPrivate(cx, obj);
421     if (priv) {
422     if (priv->errorReport)
423     JS_free(cx, priv->errorReport);
424     JS_free(cx, priv);
425     }
426     }
427    
428     static JSBool
429     exn_enumerate(JSContext *cx, JSObject *obj)
430     {
431     JSAtomState *atomState;
432     uintN i;
433     JSAtom *atom;
434     JSObject *pobj;
435     JSProperty *prop;
436    
437     JS_STATIC_ASSERT(sizeof(JSAtomState) <= (size_t)(uint16)-1);
438     static const uint16 offsets[] = {
439     (uint16)offsetof(JSAtomState, messageAtom),
440     (uint16)offsetof(JSAtomState, fileNameAtom),
441     (uint16)offsetof(JSAtomState, lineNumberAtom),
442     (uint16)offsetof(JSAtomState, stackAtom),
443     };
444    
445     atomState = &cx->runtime->atomState;
446     for (i = 0; i != JS_ARRAY_LENGTH(offsets); ++i) {
447     atom = *(JSAtom **)((uint8 *)atomState + offsets[i]);
448     if (!js_LookupProperty(cx, obj, ATOM_TO_JSID(atom), &pobj, &prop))
449     return JS_FALSE;
450     if (prop)
451     OBJ_DROP_PROPERTY(cx, pobj, prop);
452     }
453     return JS_TRUE;
454     }
455    
456     static JSBool
457     exn_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
458     JSObject **objp)
459     {
460     JSExnPrivate *priv;
461     JSString *str;
462     JSAtom *atom;
463     JSString *stack;
464     const char *prop;
465     jsval v;
466    
467     *objp = NULL;
468     priv = GetExnPrivate(cx, obj);
469     if (priv && JSVAL_IS_STRING(id)) {
470     str = JSVAL_TO_STRING(id);
471    
472     atom = cx->runtime->atomState.messageAtom;
473     if (str == ATOM_TO_STRING(atom)) {
474     prop = js_message_str;
475     v = STRING_TO_JSVAL(priv->message);
476     goto define;
477     }
478    
479     atom = cx->runtime->atomState.fileNameAtom;
480     if (str == ATOM_TO_STRING(atom)) {
481     prop = js_fileName_str;
482     v = STRING_TO_JSVAL(priv->filename);
483     goto define;
484     }
485    
486     atom = cx->runtime->atomState.lineNumberAtom;
487     if (str == ATOM_TO_STRING(atom)) {
488     prop = js_lineNumber_str;
489     v = INT_TO_JSVAL(priv->lineno);
490     goto define;
491     }
492    
493     atom = cx->runtime->atomState.stackAtom;
494     if (str == ATOM_TO_STRING(atom)) {
495     stack = StackTraceToString(cx, priv);
496     if (!stack)
497     return JS_FALSE;
498    
499     /* Allow to GC all things that were used to build stack trace. */
500     priv->stackDepth = 0;
501     prop = js_stack_str;
502     v = STRING_TO_JSVAL(stack);
503     goto define;
504     }
505     }
506     return JS_TRUE;
507    
508     define:
509     if (!JS_DefineProperty(cx, obj, prop, v, NULL, NULL, JSPROP_ENUMERATE))
510     return JS_FALSE;
511     *objp = obj;
512     return JS_TRUE;
513     }
514    
515     JSErrorReport *
516     js_ErrorFromException(JSContext *cx, jsval exn)
517     {
518     JSObject *obj;
519     JSExnPrivate *priv;
520    
521     if (JSVAL_IS_PRIMITIVE(exn))
522     return NULL;
523     obj = JSVAL_TO_OBJECT(exn);
524     if (OBJ_GET_CLASS(cx, obj) != &js_ErrorClass)
525     return NULL;
526     priv = GetExnPrivate(cx, obj);
527     if (!priv)
528     return NULL;
529     return priv->errorReport;
530     }
531    
532     struct JSExnSpec {
533     int protoIndex;
534     const char *name;
535     JSProtoKey key;
536     JSNative native;
537     };
538    
539     /*
540     * All *Error constructors share the same JSClass, js_ErrorClass. But each
541     * constructor function for an *Error class must have a distinct native 'call'
542     * function pointer, in order for instanceof to work properly across multiple
543     * standard class sets. See jsfun.c:fun_hasInstance.
544     */
545     #define MAKE_EXCEPTION_CTOR(name) \
546     static JSBool \
547     name(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) \
548     { \
549     return Exception(cx, obj, argc, argv, rval); \
550     }
551    
552     MAKE_EXCEPTION_CTOR(Error)
553     MAKE_EXCEPTION_CTOR(InternalError)
554     MAKE_EXCEPTION_CTOR(EvalError)
555     MAKE_EXCEPTION_CTOR(RangeError)
556     MAKE_EXCEPTION_CTOR(ReferenceError)
557     MAKE_EXCEPTION_CTOR(SyntaxError)
558     MAKE_EXCEPTION_CTOR(TypeError)
559     MAKE_EXCEPTION_CTOR(URIError)
560    
561     #undef MAKE_EXCEPTION_CTOR
562    
563     static struct JSExnSpec exceptions[] = {
564     {JSEXN_NONE, js_Error_str, JSProto_Error, Error},
565     {JSEXN_ERR, js_InternalError_str, JSProto_InternalError, InternalError},
566     {JSEXN_ERR, js_EvalError_str, JSProto_EvalError, EvalError},
567     {JSEXN_ERR, js_RangeError_str, JSProto_RangeError, RangeError},
568     {JSEXN_ERR, js_ReferenceError_str, JSProto_ReferenceError, ReferenceError},
569     {JSEXN_ERR, js_SyntaxError_str, JSProto_SyntaxError, SyntaxError},
570     {JSEXN_ERR, js_TypeError_str, JSProto_TypeError, TypeError},
571     {JSEXN_ERR, js_URIError_str, JSProto_URIError, URIError},
572     {0, NULL, JSProto_Null, NULL}
573     };
574    
575     static JSString *
576     ValueToShortSource(JSContext *cx, jsval v)
577     {
578     JSString *str;
579    
580     /* Avoid toSource bloat and fallibility for object types. */
581     if (JSVAL_IS_PRIMITIVE(v)) {
582     str = js_ValueToSource(cx, v);
583     } else if (VALUE_IS_FUNCTION(cx, v)) {
584     /*
585     * XXX Avoid function decompilation bloat for now.
586     */
587     str = JS_GetFunctionId(JS_ValueToFunction(cx, v));
588     if (!str && !(str = js_ValueToSource(cx, v))) {
589     /*
590     * Continue to soldier on if the function couldn't be
591     * converted into a string.
592     */
593     JS_ClearPendingException(cx);
594     str = JS_NewStringCopyZ(cx, "[unknown function]");
595     }
596     } else {
597     /*
598     * XXX Avoid toString on objects, it takes too long and uses too much
599     * memory, for too many classes (see Mozilla bug 166743).
600     */
601     char buf[100];
602     JS_snprintf(buf, sizeof buf, "[object %s]",
603     OBJ_GET_CLASS(cx, JSVAL_TO_OBJECT(v))->name);
604     str = JS_NewStringCopyZ(cx, buf);
605     }
606     return str;
607     }
608    
609     static JSString *
610     StackTraceToString(JSContext *cx, JSExnPrivate *priv)
611     {
612     jschar *stackbuf;
613     size_t stacklen, stackmax;
614     JSStackTraceElem *elem, *endElem;
615     jsval *values;
616     size_t i;
617     JSString *str;
618     const char *cp;
619     char ulnbuf[11];
620    
621     /* After this point, failing control flow must goto bad. */
622     stackbuf = NULL;
623     stacklen = stackmax = 0;
624    
625     /* Limit the stackbuf length to a reasonable value to avoid overflow checks. */
626     #define STACK_LENGTH_LIMIT JS_BIT(20)
627    
628     #define APPEND_CHAR_TO_STACK(c) \
629     JS_BEGIN_MACRO \
630     if (stacklen == stackmax) { \
631     void *ptr_; \
632     if (stackmax >= STACK_LENGTH_LIMIT) \
633     goto done; \
634     stackmax = stackmax ? 2 * stackmax : 64; \
635     ptr_ = JS_realloc(cx, stackbuf, (stackmax+1) * sizeof(jschar)); \
636     if (!ptr_) \
637     goto bad; \
638     stackbuf = (jschar *) ptr_; \
639     } \
640     stackbuf[stacklen++] = (c); \
641     JS_END_MACRO
642    
643     #define APPEND_STRING_TO_STACK(str) \
644     JS_BEGIN_MACRO \
645     JSString *str_ = str; \
646     jschar *chars_; \
647     size_t length_; \
648     \
649     JSSTRING_CHARS_AND_LENGTH(str_, chars_, length_); \
650     if (length_ > stackmax - stacklen) { \
651     void *ptr_; \
652     if (stackmax >= STACK_LENGTH_LIMIT || \
653     length_ >= STACK_LENGTH_LIMIT - stacklen) { \
654     goto done; \
655     } \
656     stackmax = JS_BIT(JS_CeilingLog2(stacklen + length_)); \
657     ptr_ = JS_realloc(cx, stackbuf, (stackmax+1) * sizeof(jschar)); \
658     if (!ptr_) \
659     goto bad; \
660     stackbuf = (jschar *) ptr_; \
661     } \
662     js_strncpy(stackbuf + stacklen, chars_, length_); \
663     stacklen += length_; \
664     JS_END_MACRO
665    
666     values = GetStackTraceValueBuffer(priv);
667     elem = priv->stackElems;
668     for (endElem = elem + priv->stackDepth; elem != endElem; elem++) {
669     if (elem->funName) {
670     APPEND_STRING_TO_STACK(elem->funName);
671     APPEND_CHAR_TO_STACK('(');
672     for (i = 0; i != elem->argc; i++, values++) {
673     if (i > 0)
674     APPEND_CHAR_TO_STACK(',');
675     str = ValueToShortSource(cx, *values);
676     if (!str)
677     goto bad;
678     APPEND_STRING_TO_STACK(str);
679     }
680     APPEND_CHAR_TO_STACK(')');
681     }
682     APPEND_CHAR_TO_STACK('@');
683     if (elem->filename) {
684     for (cp = elem->filename; *cp; cp++)
685     APPEND_CHAR_TO_STACK(*cp);
686     }
687     APPEND_CHAR_TO_STACK(':');
688     JS_snprintf(ulnbuf, sizeof ulnbuf, "%u", elem->ulineno);
689     for (cp = ulnbuf; *cp; cp++)
690     APPEND_CHAR_TO_STACK(*cp);
691     APPEND_CHAR_TO_STACK('\n');
692     }
693     #undef APPEND_CHAR_TO_STACK
694     #undef APPEND_STRING_TO_STACK
695     #undef STACK_LENGTH_LIMIT
696    
697     done:
698     if (stacklen == 0) {
699     JS_ASSERT(!stackbuf);
700     return cx->runtime->emptyString;
701     }
702     if (stacklen < stackmax) {
703     /*
704     * Realloc can fail when shrinking on some FreeBSD versions, so
705     * don't use JS_realloc here; simply let the oversized allocation
706     * be owned by the string in that rare case.
707     */
708     void *shrunk = JS_realloc(cx, stackbuf, (stacklen+1) * sizeof(jschar));
709     if (shrunk)
710     stackbuf = (jschar *) shrunk;
711     }
712    
713     stackbuf[stacklen] = 0;
714     str = js_NewString(cx, stackbuf, stacklen);
715     if (str)
716     return str;
717    
718     bad:
719     if (stackbuf)
720     JS_free(cx, stackbuf);
721     return NULL;
722     }
723    
724     /* XXXbe Consolidate the ugly truth that we don't treat filename as UTF-8
725     with these two functions. */
726     static JSString *
727     FilenameToString(JSContext *cx, const char *filename)
728     {
729     return JS_NewStringCopyZ(cx, filename);
730     }
731    
732     static const char *
733     StringToFilename(JSContext *cx, JSString *str)
734     {
735     return js_GetStringBytes(cx, str);
736     }
737    
738     static JSBool
739     Exception(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
740     {
741     uint32 lineno;
742     JSString *message, *filename;
743     JSStackFrame *fp;
744    
745     if (!(cx->fp->flags & JSFRAME_CONSTRUCTING)) {
746     /*
747     * ECMA ed. 3, 15.11.1 requires Error, etc., to construct even when
748     * called as functions, without operator new. But as we do not give
749     * each constructor a distinct JSClass, whose .name member is used by
750     * js_NewObject to find the class prototype, we must get the class
751     * prototype ourselves.
752     */
753     if (!OBJ_GET_PROPERTY(cx, JSVAL_TO_OBJECT(argv[-2]),
754     ATOM_TO_JSID(cx->runtime->atomState
755     .classPrototypeAtom),
756     rval))
757     return JS_FALSE;
758     obj = js_NewObject(cx, &js_ErrorClass, JSVAL_TO_OBJECT(*rval), NULL, 0);
759     if (!obj)
760     return JS_FALSE;
761     *rval = OBJECT_TO_JSVAL(obj);
762     }
763    
764     /*
765     * If it's a new object of class Exception, then null out the private
766     * data so that the finalizer doesn't attempt to free it.
767     */
768     if (OBJ_GET_CLASS(cx, obj) == &js_ErrorClass)
769     STOBJ_SET_SLOT(obj, JSSLOT_PRIVATE, JSVAL_VOID);
770    
771     /* Set the 'message' property. */
772     if (argc != 0) {
773     message = js_ValueToString(cx, argv[0]);
774     if (!message)
775     return JS_FALSE;
776     argv[0] = STRING_TO_JSVAL(message);
777     } else {
778     message = cx->runtime->emptyString;
779     }
780    
781     /* Set the 'fileName' property. */
782     if (argc > 1) {
783     filename = js_ValueToString(cx, argv[1]);
784     if (!filename)
785     return JS_FALSE;
786     argv[1] = STRING_TO_JSVAL(filename);
787     fp = NULL;
788     } else {
789     fp = JS_GetScriptedCaller(cx, NULL);
790     if (fp) {
791     filename = FilenameToString(cx, fp->script->filename);
792     if (!filename)
793     return JS_FALSE;
794     } else {
795     filename = cx->runtime->emptyString;
796     }
797     }
798    
799     /* Set the 'lineNumber' property. */
800     if (argc > 2) {
801     lineno = js_ValueToECMAUint32(cx, &argv[2]);
802     if (JSVAL_IS_NULL(argv[2]))
803     return JS_FALSE;
804     } else {
805     if (!fp)
806     fp = JS_GetScriptedCaller(cx, NULL);
807     lineno = (fp && fp->regs)
808     ? js_PCToLineNumber(cx, fp->script, fp->regs->pc)
809     : 0;
810     }
811    
812     return (OBJ_GET_CLASS(cx, obj) != &js_ErrorClass) ||
813     InitExnPrivate(cx, obj, message, filename, lineno, NULL);
814     }
815    
816     /*
817     * Convert to string.
818     *
819     * This method only uses JavaScript-modifiable properties name, message. It
820     * is left to the host to check for private data and report filename and line
821     * number information along with this message.
822     */
823     static JSBool
824     exn_toString(JSContext *cx, uintN argc, jsval *vp)
825     {
826     JSObject *obj;
827     jsval v;
828     JSString *name, *message, *result;
829     jschar *chars, *cp;
830     size_t name_length, message_length, length;
831    
832     obj = JS_THIS_OBJECT(cx, vp);
833     if (!obj ||
834     !OBJ_GET_PROPERTY(cx, obj,
835     ATOM_TO_JSID(cx->runtime->atomState.nameAtom),
836     &v)) {
837     return JS_FALSE;
838     }
839     name = JSVAL_IS_STRING(v) ? JSVAL_TO_STRING(v) : cx->runtime->emptyString;
840     *vp = STRING_TO_JSVAL(name);
841    
842     if (!JS_GetProperty(cx, obj, js_message_str, &v))
843     return JS_FALSE;
844     message = JSVAL_IS_STRING(v) ? JSVAL_TO_STRING(v)
845     : cx->runtime->emptyString;
846    
847     if (JSSTRING_LENGTH(message) != 0) {
848     name_length = JSSTRING_LENGTH(name);
849     message_length = JSSTRING_LENGTH(message);
850     length = (name_length ? name_length + 2 : 0) + message_length;
851     cp = chars = (jschar *) JS_malloc(cx, (length + 1) * sizeof(jschar));
852     if (!chars)
853     return JS_FALSE;
854    
855     if (name_length) {
856     js_strncpy(cp, JSSTRING_CHARS(name), name_length);
857     cp += name_length;
858     *cp++ = ':'; *cp++ = ' ';
859     }
860     js_strncpy(cp, JSSTRING_CHARS(message), message_length);
861     cp += message_length;
862     *cp = 0;
863    
864     result = js_NewString(cx, chars, length);
865     if (!result) {
866     JS_free(cx, chars);
867     return JS_FALSE;
868     }
869     } else {
870     result = name;
871     }
872    
873     *vp = STRING_TO_JSVAL(result);
874     return JS_TRUE;
875     }
876    
877     #if JS_HAS_TOSOURCE
878     /*
879     * Return a string that may eval to something similar to the original object.
880     */
881     static JSBool
882     exn_toSource(JSContext *cx, uintN argc, jsval *vp)
883     {
884     JSObject *obj;
885     JSString *name, *message, *filename, *lineno_as_str, *result;
886     jsval localroots[3] = {JSVAL_NULL, JSVAL_NULL, JSVAL_NULL};
887     JSTempValueRooter tvr;
888     JSBool ok;
889     uint32 lineno;
890     size_t lineno_length, name_length, message_length, filename_length, length;
891     jschar *chars, *cp;
892    
893     obj = JS_THIS_OBJECT(cx, vp);
894     if (!obj ||
895     !OBJ_GET_PROPERTY(cx, obj,
896     ATOM_TO_JSID(cx->runtime->atomState.nameAtom),
897     vp)) {
898     return JS_FALSE;
899     }
900     name = js_ValueToString(cx, *vp);
901     if (!name)
902     return JS_FALSE;
903     *vp = STRING_TO_JSVAL(name);
904    
905     MUST_FLOW_THROUGH("out");
906     JS_PUSH_TEMP_ROOT(cx, 3, localroots, &tvr);
907    
908     #ifdef __GNUC__
909     message = filename = NULL;
910     #endif
911     ok = JS_GetProperty(cx, obj, js_message_str, &localroots[0]) &&
912     (message = js_ValueToSource(cx, localroots[0]));
913     if (!ok)
914     goto out;
915     localroots[0] = STRING_TO_JSVAL(message);
916    
917     ok = JS_GetProperty(cx, obj, js_fileName_str, &localroots[1]) &&
918     (filename = js_ValueToSource(cx, localroots[1]));
919     if (!ok)
920     goto out;
921     localroots[1] = STRING_TO_JSVAL(filename);
922    
923     ok = JS_GetProperty(cx, obj, js_lineNumber_str, &localroots[2]);
924     if (!ok)
925     goto out;
926     lineno = js_ValueToECMAUint32 (cx, &localroots[2]);
927     ok = !JSVAL_IS_NULL(localroots[2]);
928     if (!ok)
929     goto out;
930    
931     if (lineno != 0) {
932     lineno_as_str = js_ValueToString(cx, localroots[2]);
933     if (!lineno_as_str) {
934     ok = JS_FALSE;
935     goto out;
936     }
937     lineno_length = JSSTRING_LENGTH(lineno_as_str);
938     } else {
939     lineno_as_str = NULL;
940     lineno_length = 0;
941     }
942    
943     /* Magic 8, for the characters in ``(new ())''. */
944     name_length = JSSTRING_LENGTH(name);
945     message_length = JSSTRING_LENGTH(message);
946     length = 8 + name_length + message_length;
947    
948     filename_length = JSSTRING_LENGTH(filename);
949     if (filename_length != 0) {
950     /* append filename as ``, {filename}'' */
951     length += 2 + filename_length;
952     if (lineno_as_str) {
953     /* append lineno as ``, {lineno_as_str}'' */
954     length += 2 + lineno_length;
955     }
956     } else {
957     if (lineno_as_str) {
958     /*
959     * no filename, but have line number,
960     * need to append ``, "", {lineno_as_str}''
961     */
962     length += 6 + lineno_length;
963     }
964     }
965    
966     cp = chars = (jschar *) JS_malloc(cx, (length + 1) * sizeof(jschar));
967     if (!chars) {
968     ok = JS_FALSE;
969     goto out;
970     }
971    
972     *cp++ = '('; *cp++ = 'n'; *cp++ = 'e'; *cp++ = 'w'; *cp++ = ' ';
973     js_strncpy(cp, JSSTRING_CHARS(name), name_length);
974     cp += name_length;
975     *cp++ = '(';
976     if (message_length != 0) {
977     js_strncpy(cp, JSSTRING_CHARS(message), message_length);
978     cp += message_length;
979     }
980    
981     if (filename_length != 0) {
982     /* append filename as ``, {filename}'' */
983     *cp++ = ','; *cp++ = ' ';
984     js_strncpy(cp, JSSTRING_CHARS(filename), filename_length);
985     cp += filename_length;
986     } else {
987     if (lineno_as_str) {
988     /*
989     * no filename, but have line number,
990     * need to append ``, "", {lineno_as_str}''
991     */
992     *cp++ = ','; *cp++ = ' '; *cp++ = '"'; *cp++ = '"';
993     }
994     }
995     if (lineno_as_str) {
996     /* append lineno as ``, {lineno_as_str}'' */
997     *cp++ = ','; *cp++ = ' ';
998     js_strncpy(cp, JSSTRING_CHARS(lineno_as_str), lineno_length);
999     cp += lineno_length;
1000     }
1001    
1002     *cp++ = ')'; *cp++ = ')'; *cp = 0;
1003    
1004     result = js_NewString(cx, chars, length);
1005     if (!result) {
1006     JS_free(cx, chars);
1007     ok = JS_FALSE;
1008     goto out;
1009     }
1010     *vp = STRING_TO_JSVAL(result);
1011     ok = JS_TRUE;
1012    
1013     out:
1014     JS_POP_TEMP_ROOT(cx, &tvr);
1015     return ok;
1016     }
1017     #endif
1018    
1019     static JSFunctionSpec exception_methods[] = {
1020     #if JS_HAS_TOSOURCE
1021     JS_FN(js_toSource_str, exn_toSource, 0,0),
1022     #endif
1023     JS_FN(js_toString_str, exn_toString, 0,0),
1024     JS_FS_END
1025     };
1026    
1027     JSObject *
1028     js_InitExceptionClasses(JSContext *cx, JSObject *obj)
1029     {
1030     JSObject *obj_proto, *protos[JSEXN_LIMIT];
1031     int i;
1032    
1033     /*
1034     * If lazy class initialization occurs for any Error subclass, then all
1035     * classes are initialized, starting with Error. To avoid reentry and
1036     * redundant initialization, we must not pass a null proto parameter to
1037     * js_NewObject below, when called for the Error superclass. We need to
1038     * ensure that Object.prototype is the proto of Error.prototype.
1039     *
1040     * See the equivalent code to ensure that parent_proto is non-null when
1041     * JS_InitClass calls js_NewObject, in jsapi.c.
1042     */
1043     if (!js_GetClassPrototype(cx, obj, INT_TO_JSID(JSProto_Object),
1044     &obj_proto)) {
1045     return NULL;
1046     }
1047    
1048     if (!js_EnterLocalRootScope(cx))
1049     return NULL;
1050    
1051     /* Initialize the prototypes first. */
1052     for (i = 0; exceptions[i].name != 0; i++) {
1053     JSAtom *atom;
1054     JSFunction *fun;
1055     JSString *nameString;
1056     int protoIndex = exceptions[i].protoIndex;
1057    
1058     /* Make the prototype for the current constructor name. */
1059     protos[i] = js_NewObject(cx, &js_ErrorClass,
1060     (protoIndex != JSEXN_NONE)
1061     ? protos[protoIndex]
1062     : obj_proto,
1063     obj, 0);
1064     if (!protos[i])
1065     break;
1066    
1067     /* So exn_finalize knows whether to destroy private data. */
1068     STOBJ_SET_SLOT(protos[i], JSSLOT_PRIVATE, JSVAL_VOID);
1069    
1070     /* Make a constructor function for the current name. */
1071     atom = cx->runtime->atomState.classAtoms[exceptions[i].key];
1072     fun = js_DefineFunction(cx, obj, atom, exceptions[i].native, 3, 0);
1073     if (!fun)
1074     break;
1075    
1076     /* Make this constructor make objects of class Exception. */
1077     fun->u.n.clasp = &js_ErrorClass;
1078    
1079     /* Make the prototype and constructor links. */
1080     if (!js_SetClassPrototype(cx, FUN_OBJECT(fun), protos[i],
1081     JSPROP_READONLY | JSPROP_PERMANENT)) {
1082     break;
1083     }
1084    
1085     /* proto bootstrap bit from JS_InitClass omitted. */
1086     nameString = JS_NewStringCopyZ(cx, exceptions[i].name);
1087     if (!nameString)
1088     break;
1089    
1090     /* Add the name property to the prototype. */
1091     if (!JS_DefineProperty(cx, protos[i], js_name_str,
1092     STRING_TO_JSVAL(nameString),
1093     NULL, NULL,
1094     JSPROP_ENUMERATE)) {
1095     break;
1096     }
1097    
1098     /* Finally, stash the constructor for later uses. */
1099     if (!js_SetClassObject(cx, obj, exceptions[i].key, FUN_OBJECT(fun)))
1100     break;
1101     }
1102    
1103     js_LeaveLocalRootScope(cx);
1104     if (exceptions[i].name)
1105     return NULL;
1106    
1107     /*
1108     * Add an empty message property. (To Exception.prototype only,
1109     * because this property will be the same for all the exception
1110     * protos.)
1111     */
1112     if (!JS_DefineProperty(cx, protos[0], js_message_str,
1113     STRING_TO_JSVAL(cx->runtime->emptyString),
1114     NULL, NULL, JSPROP_ENUMERATE)) {
1115     return NULL;
1116     }
1117     if (!JS_DefineProperty(cx, protos[0], js_fileName_str,
1118     STRING_TO_JSVAL(cx->runtime->emptyString),
1119     NULL, NULL, JSPROP_ENUMERATE)) {
1120     return NULL;
1121     }
1122     if (!JS_DefineProperty(cx, protos[0], js_lineNumber_str,
1123     INT_TO_JSVAL(0),
1124     NULL, NULL, JSPROP_ENUMERATE)) {
1125     return NULL;
1126     }
1127    
1128     /*
1129     * Add methods only to Exception.prototype, because ostensibly all
1130     * exception types delegate to that.
1131     */
1132     if (!JS_DefineFunctions(cx, protos[0], exception_methods))
1133     return NULL;
1134    
1135     return protos[0];
1136     }
1137    
1138     const JSErrorFormatString*
1139     js_GetLocalizedErrorMessage(JSContext* cx, void *userRef, const char *locale,
1140     const uintN errorNumber)
1141     {
1142     const JSErrorFormatString *errorString = NULL;
1143    
1144     if (cx->localeCallbacks && cx->localeCallbacks->localeGetErrorMessage) {
1145     errorString = cx->localeCallbacks
1146     ->localeGetErrorMessage(userRef, locale, errorNumber);
1147     }
1148     if (!errorString)
1149     errorString = js_GetErrorMessage(userRef, locale, errorNumber);
1150     return errorString;
1151     }
1152    
1153     #if defined ( DEBUG_mccabe ) && defined ( PRINTNAMES )
1154     /* For use below... get character strings for error name and exception name */
1155     static struct exnname { char *name; char *exception; } errortoexnname[] = {
1156     #define MSG_DEF(name, number, count, exception, format) \
1157     {#name, #exception},
1158     #include "js.msg"
1159     #undef MSG_DEF
1160     };
1161     #endif /* DEBUG */
1162    
1163     JSBool
1164     js_ErrorToException(JSContext *cx, const char *message, JSErrorReport *reportp)
1165     {
1166     JSErrNum errorNumber;
1167     const JSErrorFormatString *errorString;
1168     JSExnType exn;
1169     jsval tv[4];
1170     JSTempValueRooter tvr;
1171     JSBool ok;
1172     JSObject *errProto, *errObject;
1173     JSString *messageStr, *filenameStr;
1174    
1175     /*
1176     * Tell our caller to report immediately if this report is just a warning.
1177     */
1178     JS_ASSERT(reportp);
1179     if (JSREPORT_IS_WARNING(reportp->flags))
1180     return JS_FALSE;
1181    
1182     /* Find the exception index associated with this error. */
1183     errorNumber = (JSErrNum) reportp->errorNumber;
1184     errorString = js_GetLocalizedErrorMessage(cx, NULL, NULL, errorNumber);
1185     exn = errorString ? (JSExnType) errorString->exnType : JSEXN_NONE;
1186     JS_ASSERT(exn < JSEXN_LIMIT);
1187    
1188     #if defined( DEBUG_mccabe ) && defined ( PRINTNAMES )
1189     /* Print the error name and the associated exception name to stderr */
1190     fprintf(stderr, "%s\t%s\n",
1191     errortoexnname[errorNumber].name,
1192     errortoexnname[errorNumber].exception);
1193     #endif
1194    
1195     /*
1196     * Return false (no exception raised) if no exception is associated
1197     * with the given error number.
1198     */
1199     if (exn == JSEXN_NONE)
1200     return JS_FALSE;
1201    
1202     /*
1203     * Prevent runaway recursion, via cx->generatingError. If an out-of-memory
1204     * error occurs, no exception object will be created, but we don't assume
1205     * that OOM is the only kind of error that subroutines of this function
1206     * called below might raise.
1207     */
1208     if (cx->generatingError)
1209     return JS_FALSE;
1210    
1211     MUST_FLOW_THROUGH("out");
1212     cx->generatingError = JS_TRUE;
1213    
1214     /* Protect the newly-created strings below from nesting GCs. */
1215     memset(tv, 0, sizeof tv);
1216     JS_PUSH_TEMP_ROOT(cx, JS_ARRAY_LENGTH(tv), tv, &tvr);
1217    
1218     /*
1219     * Try to get an appropriate prototype by looking up the corresponding
1220     * exception constructor name in the scope chain of the current context's
1221     * top stack frame, or in the global object if no frame is active.
1222     */
1223     ok = js_GetClassPrototype(cx, NULL, INT_TO_JSID(exceptions[exn].key),
1224     &errProto);
1225     if (!ok)
1226     goto out;
1227     tv[0] = OBJECT_TO_JSVAL(errProto);
1228    
1229     errObject = js_NewObject(cx, &js_ErrorClass, errProto, NULL, 0);
1230     if (!errObject) {
1231     ok = JS_FALSE;
1232     goto out;
1233     }
1234     tv[1] = OBJECT_TO_JSVAL(errObject);
1235    
1236     messageStr = JS_NewStringCopyZ(cx, message);
1237     if (!messageStr) {
1238     ok = JS_FALSE;
1239     goto out;
1240     }
1241     tv[2] = STRING_TO_JSVAL(messageStr);
1242    
1243     filenameStr = JS_NewStringCopyZ(cx, reportp->filename);
1244     if (!filenameStr) {
1245     ok = JS_FALSE;
1246     goto out;
1247     }
1248     tv[3] = STRING_TO_JSVAL(filenameStr);
1249    
1250     ok = InitExnPrivate(cx, errObject, messageStr, filenameStr,
1251     reportp->lineno, reportp);
1252     if (!ok)
1253     goto out;
1254    
1255     JS_SetPendingException(cx, OBJECT_TO_JSVAL(errObject));
1256    
1257     /* Flag the error report passed in to indicate an exception was raised. */
1258     reportp->flags |= JSREPORT_EXCEPTION;
1259    
1260     out:
1261     JS_POP_TEMP_ROOT(cx, &tvr);
1262     cx->generatingError = JS_FALSE;
1263     return ok;
1264     }
1265    
1266     JSBool
1267     js_ReportUncaughtException(JSContext *cx)
1268     {
1269     jsval exn;
1270     JSObject *exnObject;
1271     jsval roots[5];
1272     JSTempValueRooter tvr;
1273     JSErrorReport *reportp, report;
1274     JSString *str;
1275     const char *bytes;
1276     JSBool ok;
1277    
1278     if (!JS_IsExceptionPending(cx))
1279     return JS_TRUE;
1280    
1281     if (!JS_GetPendingException(cx, &exn))
1282     return JS_FALSE;
1283    
1284     memset(roots, 0, sizeof roots);
1285     JS_PUSH_TEMP_ROOT(cx, JS_ARRAY_LENGTH(roots), roots, &tvr);
1286    
1287     /*
1288     * Because js_ValueToString below could error and an exception object
1289     * could become unrooted, we must root exnObject. Later, if exnObject is
1290     * non-null, we need to root other intermediates, so allocate an operand
1291     * stack segment to protect all of these values.
1292     */
1293     if (JSVAL_IS_PRIMITIVE(exn)) {
1294     exnObject = NULL;
1295     } else {
1296     exnObject = JSVAL_TO_OBJECT(exn);
1297     roots[0] = exn;
1298     }
1299    
1300     JS_ClearPendingException(cx);
1301     reportp = js_ErrorFromException(cx, exn);
1302    
1303     /* XXX L10N angels cry once again (see also jsemit.c, /L10N gaffes/) */
1304     str = js_ValueToString(cx, exn);
1305     if (!str) {
1306     bytes = "unknown (can't convert to string)";
1307     } else {
1308     roots[1] = STRING_TO_JSVAL(str);
1309     bytes = js_GetStringBytes(cx, str);
1310     if (!bytes) {
1311     ok = JS_FALSE;
1312     goto out;
1313     }
1314     }
1315     ok = JS_TRUE;
1316    
1317     if (!reportp &&
1318     exnObject &&
1319     OBJ_GET_CLASS(cx, exnObject) == &js_ErrorClass) {
1320     const char *filename;
1321     uint32 lineno;
1322    
1323     ok = JS_GetProperty(cx, exnObject, js_message_str, &roots[2]);
1324     if (!ok)
1325     goto out;
1326     if (JSVAL_IS_STRING(roots[2])) {
1327     bytes = js_GetStringBytes(cx, JSVAL_TO_STRING(roots[2]));
1328     if (!bytes) {
1329     ok = JS_FALSE;
1330     goto out;
1331     }
1332     }
1333    
1334     ok = JS_GetProperty(cx, exnObject, js_fileName_str, &roots[3]);
1335     if (!ok)
1336     goto out;
1337     str = js_ValueToString(cx, roots[3]);
1338     if (!str) {
1339     ok = JS_FALSE;
1340     goto out;
1341     }
1342     filename = StringToFilename(cx, str);
1343     if (!filename) {
1344     ok = JS_FALSE;
1345     goto out;
1346     }
1347    
1348     ok = JS_GetProperty(cx, exnObject, js_lineNumber_str, &roots[4]);
1349     if (!ok)
1350     goto out;
1351     lineno = js_ValueToECMAUint32 (cx, &roots[4]);
1352     ok = !JSVAL_IS_NULL(roots[4]);
1353     if (!ok)
1354     goto out;
1355    
1356     reportp = &report;
1357     memset(&report, 0, sizeof report);
1358     report.filename = filename;
1359     report.lineno = (uintN) lineno;
1360     }
1361    
1362     if (!reportp) {
1363     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
1364     JSMSG_UNCAUGHT_EXCEPTION, bytes);
1365     } else {
1366     /* Flag the error as an exception. */
1367     reportp->flags |= JSREPORT_EXCEPTION;
1368    
1369     /* Pass the exception object. */
1370     JS_SetPendingException(cx, exn);
1371     js_ReportErrorAgain(cx, bytes, reportp);
1372     JS_ClearPendingException(cx);
1373     }
1374    
1375     out:
1376     JS_POP_TEMP_ROOT(cx, &tvr);
1377     return ok;
1378     }

  ViewVC Help
Powered by ViewVC 1.1.24