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

Annotation of /trunk/js/jsexn.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 399 - (hide annotations)
Tue Dec 9 03:37:47 2008 UTC (11 years, 10 months ago) by siliconforks
File size: 44876 byte(s)
Use SpiderMonkey from Firefox 3.1b2.

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 siliconforks 399 elem->ulineno = js_FramePCToLineNumber(cx, fp);
342 siliconforks 332 }
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 siliconforks 399 lineno = (fp && fp->regs) ? js_FramePCToLineNumber(cx, fp) : 0;
808 siliconforks 332 }
809    
810     return (OBJ_GET_CLASS(cx, obj) != &js_ErrorClass) ||
811     InitExnPrivate(cx, obj, message, filename, lineno, NULL);
812     }
813    
814     /*
815     * Convert to string.
816     *
817     * This method only uses JavaScript-modifiable properties name, message. It
818     * is left to the host to check for private data and report filename and line
819     * number information along with this message.
820     */
821     static JSBool
822     exn_toString(JSContext *cx, uintN argc, jsval *vp)
823     {
824     JSObject *obj;
825     jsval v;
826     JSString *name, *message, *result;
827     jschar *chars, *cp;
828     size_t name_length, message_length, length;
829    
830     obj = JS_THIS_OBJECT(cx, vp);
831     if (!obj ||
832     !OBJ_GET_PROPERTY(cx, obj,
833     ATOM_TO_JSID(cx->runtime->atomState.nameAtom),
834     &v)) {
835     return JS_FALSE;
836     }
837     name = JSVAL_IS_STRING(v) ? JSVAL_TO_STRING(v) : cx->runtime->emptyString;
838     *vp = STRING_TO_JSVAL(name);
839    
840     if (!JS_GetProperty(cx, obj, js_message_str, &v))
841     return JS_FALSE;
842     message = JSVAL_IS_STRING(v) ? JSVAL_TO_STRING(v)
843     : cx->runtime->emptyString;
844    
845     if (JSSTRING_LENGTH(message) != 0) {
846     name_length = JSSTRING_LENGTH(name);
847     message_length = JSSTRING_LENGTH(message);
848     length = (name_length ? name_length + 2 : 0) + message_length;
849     cp = chars = (jschar *) JS_malloc(cx, (length + 1) * sizeof(jschar));
850     if (!chars)
851     return JS_FALSE;
852    
853     if (name_length) {
854     js_strncpy(cp, JSSTRING_CHARS(name), name_length);
855     cp += name_length;
856     *cp++ = ':'; *cp++ = ' ';
857     }
858     js_strncpy(cp, JSSTRING_CHARS(message), message_length);
859     cp += message_length;
860     *cp = 0;
861    
862     result = js_NewString(cx, chars, length);
863     if (!result) {
864     JS_free(cx, chars);
865     return JS_FALSE;
866     }
867     } else {
868     result = name;
869     }
870    
871     *vp = STRING_TO_JSVAL(result);
872     return JS_TRUE;
873     }
874    
875     #if JS_HAS_TOSOURCE
876     /*
877     * Return a string that may eval to something similar to the original object.
878     */
879     static JSBool
880     exn_toSource(JSContext *cx, uintN argc, jsval *vp)
881     {
882     JSObject *obj;
883     JSString *name, *message, *filename, *lineno_as_str, *result;
884     jsval localroots[3] = {JSVAL_NULL, JSVAL_NULL, JSVAL_NULL};
885     JSTempValueRooter tvr;
886     JSBool ok;
887     uint32 lineno;
888     size_t lineno_length, name_length, message_length, filename_length, length;
889     jschar *chars, *cp;
890    
891     obj = JS_THIS_OBJECT(cx, vp);
892     if (!obj ||
893     !OBJ_GET_PROPERTY(cx, obj,
894     ATOM_TO_JSID(cx->runtime->atomState.nameAtom),
895     vp)) {
896     return JS_FALSE;
897     }
898     name = js_ValueToString(cx, *vp);
899     if (!name)
900     return JS_FALSE;
901     *vp = STRING_TO_JSVAL(name);
902    
903     MUST_FLOW_THROUGH("out");
904     JS_PUSH_TEMP_ROOT(cx, 3, localroots, &tvr);
905    
906     #ifdef __GNUC__
907     message = filename = NULL;
908     #endif
909     ok = JS_GetProperty(cx, obj, js_message_str, &localroots[0]) &&
910     (message = js_ValueToSource(cx, localroots[0]));
911     if (!ok)
912     goto out;
913     localroots[0] = STRING_TO_JSVAL(message);
914    
915     ok = JS_GetProperty(cx, obj, js_fileName_str, &localroots[1]) &&
916     (filename = js_ValueToSource(cx, localroots[1]));
917     if (!ok)
918     goto out;
919     localroots[1] = STRING_TO_JSVAL(filename);
920    
921     ok = JS_GetProperty(cx, obj, js_lineNumber_str, &localroots[2]);
922     if (!ok)
923     goto out;
924     lineno = js_ValueToECMAUint32 (cx, &localroots[2]);
925     ok = !JSVAL_IS_NULL(localroots[2]);
926     if (!ok)
927     goto out;
928    
929     if (lineno != 0) {
930     lineno_as_str = js_ValueToString(cx, localroots[2]);
931     if (!lineno_as_str) {
932     ok = JS_FALSE;
933     goto out;
934     }
935     lineno_length = JSSTRING_LENGTH(lineno_as_str);
936     } else {
937     lineno_as_str = NULL;
938     lineno_length = 0;
939     }
940    
941     /* Magic 8, for the characters in ``(new ())''. */
942     name_length = JSSTRING_LENGTH(name);
943     message_length = JSSTRING_LENGTH(message);
944     length = 8 + name_length + message_length;
945    
946     filename_length = JSSTRING_LENGTH(filename);
947     if (filename_length != 0) {
948     /* append filename as ``, {filename}'' */
949     length += 2 + filename_length;
950     if (lineno_as_str) {
951     /* append lineno as ``, {lineno_as_str}'' */
952     length += 2 + lineno_length;
953     }
954     } else {
955     if (lineno_as_str) {
956     /*
957     * no filename, but have line number,
958     * need to append ``, "", {lineno_as_str}''
959     */
960     length += 6 + lineno_length;
961     }
962     }
963    
964     cp = chars = (jschar *) JS_malloc(cx, (length + 1) * sizeof(jschar));
965     if (!chars) {
966     ok = JS_FALSE;
967     goto out;
968     }
969    
970     *cp++ = '('; *cp++ = 'n'; *cp++ = 'e'; *cp++ = 'w'; *cp++ = ' ';
971     js_strncpy(cp, JSSTRING_CHARS(name), name_length);
972     cp += name_length;
973     *cp++ = '(';
974     if (message_length != 0) {
975     js_strncpy(cp, JSSTRING_CHARS(message), message_length);
976     cp += message_length;
977     }
978    
979     if (filename_length != 0) {
980     /* append filename as ``, {filename}'' */
981     *cp++ = ','; *cp++ = ' ';
982     js_strncpy(cp, JSSTRING_CHARS(filename), filename_length);
983     cp += filename_length;
984     } else {
985     if (lineno_as_str) {
986     /*
987     * no filename, but have line number,
988     * need to append ``, "", {lineno_as_str}''
989     */
990     *cp++ = ','; *cp++ = ' '; *cp++ = '"'; *cp++ = '"';
991     }
992     }
993     if (lineno_as_str) {
994     /* append lineno as ``, {lineno_as_str}'' */
995     *cp++ = ','; *cp++ = ' ';
996     js_strncpy(cp, JSSTRING_CHARS(lineno_as_str), lineno_length);
997     cp += lineno_length;
998     }
999    
1000     *cp++ = ')'; *cp++ = ')'; *cp = 0;
1001    
1002     result = js_NewString(cx, chars, length);
1003     if (!result) {
1004     JS_free(cx, chars);
1005     ok = JS_FALSE;
1006     goto out;
1007     }
1008     *vp = STRING_TO_JSVAL(result);
1009     ok = JS_TRUE;
1010    
1011     out:
1012     JS_POP_TEMP_ROOT(cx, &tvr);
1013     return ok;
1014     }
1015     #endif
1016    
1017     static JSFunctionSpec exception_methods[] = {
1018     #if JS_HAS_TOSOURCE
1019     JS_FN(js_toSource_str, exn_toSource, 0,0),
1020     #endif
1021     JS_FN(js_toString_str, exn_toString, 0,0),
1022     JS_FS_END
1023     };
1024    
1025     JSObject *
1026     js_InitExceptionClasses(JSContext *cx, JSObject *obj)
1027     {
1028     JSObject *obj_proto, *protos[JSEXN_LIMIT];
1029     int i;
1030    
1031     /*
1032     * If lazy class initialization occurs for any Error subclass, then all
1033     * classes are initialized, starting with Error. To avoid reentry and
1034     * redundant initialization, we must not pass a null proto parameter to
1035     * js_NewObject below, when called for the Error superclass. We need to
1036     * ensure that Object.prototype is the proto of Error.prototype.
1037     *
1038     * See the equivalent code to ensure that parent_proto is non-null when
1039     * JS_InitClass calls js_NewObject, in jsapi.c.
1040     */
1041     if (!js_GetClassPrototype(cx, obj, INT_TO_JSID(JSProto_Object),
1042     &obj_proto)) {
1043     return NULL;
1044     }
1045    
1046     if (!js_EnterLocalRootScope(cx))
1047     return NULL;
1048    
1049     /* Initialize the prototypes first. */
1050     for (i = 0; exceptions[i].name != 0; i++) {
1051     JSAtom *atom;
1052     JSFunction *fun;
1053     JSString *nameString;
1054     int protoIndex = exceptions[i].protoIndex;
1055    
1056     /* Make the prototype for the current constructor name. */
1057     protos[i] = js_NewObject(cx, &js_ErrorClass,
1058     (protoIndex != JSEXN_NONE)
1059     ? protos[protoIndex]
1060     : obj_proto,
1061     obj, 0);
1062     if (!protos[i])
1063     break;
1064    
1065     /* So exn_finalize knows whether to destroy private data. */
1066     STOBJ_SET_SLOT(protos[i], JSSLOT_PRIVATE, JSVAL_VOID);
1067    
1068     /* Make a constructor function for the current name. */
1069     atom = cx->runtime->atomState.classAtoms[exceptions[i].key];
1070     fun = js_DefineFunction(cx, obj, atom, exceptions[i].native, 3, 0);
1071     if (!fun)
1072     break;
1073    
1074     /* Make this constructor make objects of class Exception. */
1075 siliconforks 399 FUN_CLASP(fun) = &js_ErrorClass;
1076 siliconforks 332
1077     /* Make the prototype and constructor links. */
1078     if (!js_SetClassPrototype(cx, FUN_OBJECT(fun), protos[i],
1079     JSPROP_READONLY | JSPROP_PERMANENT)) {
1080     break;
1081     }
1082    
1083     /* proto bootstrap bit from JS_InitClass omitted. */
1084     nameString = JS_NewStringCopyZ(cx, exceptions[i].name);
1085     if (!nameString)
1086     break;
1087    
1088     /* Add the name property to the prototype. */
1089     if (!JS_DefineProperty(cx, protos[i], js_name_str,
1090     STRING_TO_JSVAL(nameString),
1091     NULL, NULL,
1092     JSPROP_ENUMERATE)) {
1093     break;
1094     }
1095    
1096     /* Finally, stash the constructor for later uses. */
1097     if (!js_SetClassObject(cx, obj, exceptions[i].key, FUN_OBJECT(fun)))
1098     break;
1099     }
1100    
1101     js_LeaveLocalRootScope(cx);
1102     if (exceptions[i].name)
1103     return NULL;
1104    
1105     /*
1106     * Add an empty message property. (To Exception.prototype only,
1107     * because this property will be the same for all the exception
1108     * protos.)
1109     */
1110     if (!JS_DefineProperty(cx, protos[0], js_message_str,
1111     STRING_TO_JSVAL(cx->runtime->emptyString),
1112     NULL, NULL, JSPROP_ENUMERATE)) {
1113     return NULL;
1114     }
1115     if (!JS_DefineProperty(cx, protos[0], js_fileName_str,
1116     STRING_TO_JSVAL(cx->runtime->emptyString),
1117     NULL, NULL, JSPROP_ENUMERATE)) {
1118     return NULL;
1119     }
1120     if (!JS_DefineProperty(cx, protos[0], js_lineNumber_str,
1121     INT_TO_JSVAL(0),
1122     NULL, NULL, JSPROP_ENUMERATE)) {
1123     return NULL;
1124     }
1125    
1126     /*
1127     * Add methods only to Exception.prototype, because ostensibly all
1128     * exception types delegate to that.
1129     */
1130     if (!JS_DefineFunctions(cx, protos[0], exception_methods))
1131     return NULL;
1132    
1133     return protos[0];
1134     }
1135    
1136     const JSErrorFormatString*
1137     js_GetLocalizedErrorMessage(JSContext* cx, void *userRef, const char *locale,
1138     const uintN errorNumber)
1139     {
1140     const JSErrorFormatString *errorString = NULL;
1141    
1142     if (cx->localeCallbacks && cx->localeCallbacks->localeGetErrorMessage) {
1143     errorString = cx->localeCallbacks
1144     ->localeGetErrorMessage(userRef, locale, errorNumber);
1145     }
1146     if (!errorString)
1147     errorString = js_GetErrorMessage(userRef, locale, errorNumber);
1148     return errorString;
1149     }
1150    
1151     #if defined ( DEBUG_mccabe ) && defined ( PRINTNAMES )
1152     /* For use below... get character strings for error name and exception name */
1153     static struct exnname { char *name; char *exception; } errortoexnname[] = {
1154     #define MSG_DEF(name, number, count, exception, format) \
1155     {#name, #exception},
1156     #include "js.msg"
1157     #undef MSG_DEF
1158     };
1159     #endif /* DEBUG */
1160    
1161     JSBool
1162     js_ErrorToException(JSContext *cx, const char *message, JSErrorReport *reportp)
1163     {
1164     JSErrNum errorNumber;
1165     const JSErrorFormatString *errorString;
1166     JSExnType exn;
1167     jsval tv[4];
1168     JSTempValueRooter tvr;
1169     JSBool ok;
1170     JSObject *errProto, *errObject;
1171     JSString *messageStr, *filenameStr;
1172    
1173     /*
1174     * Tell our caller to report immediately if this report is just a warning.
1175     */
1176     JS_ASSERT(reportp);
1177     if (JSREPORT_IS_WARNING(reportp->flags))
1178     return JS_FALSE;
1179    
1180     /* Find the exception index associated with this error. */
1181     errorNumber = (JSErrNum) reportp->errorNumber;
1182     errorString = js_GetLocalizedErrorMessage(cx, NULL, NULL, errorNumber);
1183     exn = errorString ? (JSExnType) errorString->exnType : JSEXN_NONE;
1184     JS_ASSERT(exn < JSEXN_LIMIT);
1185    
1186     #if defined( DEBUG_mccabe ) && defined ( PRINTNAMES )
1187     /* Print the error name and the associated exception name to stderr */
1188     fprintf(stderr, "%s\t%s\n",
1189     errortoexnname[errorNumber].name,
1190     errortoexnname[errorNumber].exception);
1191     #endif
1192    
1193     /*
1194     * Return false (no exception raised) if no exception is associated
1195     * with the given error number.
1196     */
1197     if (exn == JSEXN_NONE)
1198     return JS_FALSE;
1199    
1200     /*
1201     * Prevent runaway recursion, via cx->generatingError. If an out-of-memory
1202     * error occurs, no exception object will be created, but we don't assume
1203     * that OOM is the only kind of error that subroutines of this function
1204     * called below might raise.
1205     */
1206     if (cx->generatingError)
1207     return JS_FALSE;
1208    
1209     MUST_FLOW_THROUGH("out");
1210     cx->generatingError = JS_TRUE;
1211    
1212     /* Protect the newly-created strings below from nesting GCs. */
1213     memset(tv, 0, sizeof tv);
1214     JS_PUSH_TEMP_ROOT(cx, JS_ARRAY_LENGTH(tv), tv, &tvr);
1215    
1216     /*
1217     * Try to get an appropriate prototype by looking up the corresponding
1218     * exception constructor name in the scope chain of the current context's
1219     * top stack frame, or in the global object if no frame is active.
1220     */
1221     ok = js_GetClassPrototype(cx, NULL, INT_TO_JSID(exceptions[exn].key),
1222     &errProto);
1223     if (!ok)
1224     goto out;
1225     tv[0] = OBJECT_TO_JSVAL(errProto);
1226    
1227     errObject = js_NewObject(cx, &js_ErrorClass, errProto, NULL, 0);
1228     if (!errObject) {
1229     ok = JS_FALSE;
1230     goto out;
1231     }
1232     tv[1] = OBJECT_TO_JSVAL(errObject);
1233    
1234     messageStr = JS_NewStringCopyZ(cx, message);
1235     if (!messageStr) {
1236     ok = JS_FALSE;
1237     goto out;
1238     }
1239     tv[2] = STRING_TO_JSVAL(messageStr);
1240    
1241     filenameStr = JS_NewStringCopyZ(cx, reportp->filename);
1242     if (!filenameStr) {
1243     ok = JS_FALSE;
1244     goto out;
1245     }
1246     tv[3] = STRING_TO_JSVAL(filenameStr);
1247    
1248     ok = InitExnPrivate(cx, errObject, messageStr, filenameStr,
1249     reportp->lineno, reportp);
1250     if (!ok)
1251     goto out;
1252    
1253     JS_SetPendingException(cx, OBJECT_TO_JSVAL(errObject));
1254    
1255     /* Flag the error report passed in to indicate an exception was raised. */
1256     reportp->flags |= JSREPORT_EXCEPTION;
1257    
1258     out:
1259     JS_POP_TEMP_ROOT(cx, &tvr);
1260     cx->generatingError = JS_FALSE;
1261     return ok;
1262     }
1263    
1264     JSBool
1265     js_ReportUncaughtException(JSContext *cx)
1266     {
1267     jsval exn;
1268     JSObject *exnObject;
1269     jsval roots[5];
1270     JSTempValueRooter tvr;
1271     JSErrorReport *reportp, report;
1272     JSString *str;
1273     const char *bytes;
1274     JSBool ok;
1275    
1276     if (!JS_IsExceptionPending(cx))
1277     return JS_TRUE;
1278    
1279     if (!JS_GetPendingException(cx, &exn))
1280     return JS_FALSE;
1281    
1282     memset(roots, 0, sizeof roots);
1283     JS_PUSH_TEMP_ROOT(cx, JS_ARRAY_LENGTH(roots), roots, &tvr);
1284    
1285     /*
1286     * Because js_ValueToString below could error and an exception object
1287     * could become unrooted, we must root exnObject. Later, if exnObject is
1288     * non-null, we need to root other intermediates, so allocate an operand
1289     * stack segment to protect all of these values.
1290     */
1291     if (JSVAL_IS_PRIMITIVE(exn)) {
1292     exnObject = NULL;
1293     } else {
1294     exnObject = JSVAL_TO_OBJECT(exn);
1295     roots[0] = exn;
1296     }
1297    
1298     JS_ClearPendingException(cx);
1299     reportp = js_ErrorFromException(cx, exn);
1300    
1301     /* XXX L10N angels cry once again (see also jsemit.c, /L10N gaffes/) */
1302     str = js_ValueToString(cx, exn);
1303     if (!str) {
1304     bytes = "unknown (can't convert to string)";
1305     } else {
1306     roots[1] = STRING_TO_JSVAL(str);
1307     bytes = js_GetStringBytes(cx, str);
1308     if (!bytes) {
1309     ok = JS_FALSE;
1310     goto out;
1311     }
1312     }
1313     ok = JS_TRUE;
1314    
1315     if (!reportp &&
1316     exnObject &&
1317     OBJ_GET_CLASS(cx, exnObject) == &js_ErrorClass) {
1318     const char *filename;
1319     uint32 lineno;
1320    
1321     ok = JS_GetProperty(cx, exnObject, js_message_str, &roots[2]);
1322     if (!ok)
1323     goto out;
1324     if (JSVAL_IS_STRING(roots[2])) {
1325     bytes = js_GetStringBytes(cx, JSVAL_TO_STRING(roots[2]));
1326     if (!bytes) {
1327     ok = JS_FALSE;
1328     goto out;
1329     }
1330     }
1331    
1332     ok = JS_GetProperty(cx, exnObject, js_fileName_str, &roots[3]);
1333     if (!ok)
1334     goto out;
1335     str = js_ValueToString(cx, roots[3]);
1336     if (!str) {
1337     ok = JS_FALSE;
1338     goto out;
1339     }
1340     filename = StringToFilename(cx, str);
1341     if (!filename) {
1342     ok = JS_FALSE;
1343     goto out;
1344     }
1345    
1346     ok = JS_GetProperty(cx, exnObject, js_lineNumber_str, &roots[4]);
1347     if (!ok)
1348     goto out;
1349     lineno = js_ValueToECMAUint32 (cx, &roots[4]);
1350     ok = !JSVAL_IS_NULL(roots[4]);
1351     if (!ok)
1352     goto out;
1353    
1354     reportp = &report;
1355     memset(&report, 0, sizeof report);
1356     report.filename = filename;
1357     report.lineno = (uintN) lineno;
1358     }
1359    
1360     if (!reportp) {
1361     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
1362     JSMSG_UNCAUGHT_EXCEPTION, bytes);
1363     } else {
1364     /* Flag the error as an exception. */
1365     reportp->flags |= JSREPORT_EXCEPTION;
1366    
1367     /* Pass the exception object. */
1368     JS_SetPendingException(cx, exn);
1369     js_ReportErrorAgain(cx, bytes, reportp);
1370     JS_ClearPendingException(cx);
1371     }
1372    
1373     out:
1374     JS_POP_TEMP_ROOT(cx, &tvr);
1375     return ok;
1376     }

  ViewVC Help
Powered by ViewVC 1.1.24