static JSBool Exception(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { JSBool ok; jsval pval; int32 lineno; JSString *message, *filename; if (cx->creatingException) return JS_FALSE; cx->creatingException = JS_TRUE; if (!(cx->fp->flags & JSFRAME_CONSTRUCTING)) { /* * ECMA ed. 3, 15.11.1 requires Error, etc., to construct even when * called as functions, without operator new. But as we do not give * each constructor a distinct JSClass, whose .name member is used by * js_NewObject to find the class prototype, we must get the class * prototype ourselves. */ ok = OBJ_GET_PROPERTY(cx, JSVAL_TO_OBJECT(argv[-2]), (jsid)cx->runtime->atomState.classPrototypeAtom, &pval); if (!ok) goto out; obj = js_NewObject(cx, &ExceptionClass, JSVAL_TO_OBJECT(pval), NULL); if (!obj) { ok = JS_FALSE; goto out; } *rval = OBJECT_TO_JSVAL(obj); } /* * If it's a new object of class Exception, then null out the private * data so that the finalizer doesn't attempt to free it. */ if (OBJ_GET_CLASS(cx, obj) == &ExceptionClass) OBJ_SET_SLOT(cx, obj, JSSLOT_PRIVATE, JSVAL_VOID); /* Set the 'message' property. */ if (argc != 0) { message = js_ValueToString(cx, argv[0]); if (!message) { ok = JS_FALSE; goto out; } } else { message = cx->runtime->emptyString; } /* Set the 'fileName' property. */ if (argc > 1) { filename = js_ValueToString(cx, argv[1]); if (!filename) { ok = JS_FALSE; goto out; } } else { filename = cx->runtime->emptyString; } /* Set the 'lineNumber' property. */ if (argc > 2) { ok = js_ValueToInt32(cx, argv[2], &lineno); if (!ok) goto out; } else { lineno = 0; } ok = InitExceptionObject(cx, obj, message, filename, lineno); out: cx->creatingException = JS_FALSE; return ok; }
JSBool js_ErrorToException(JSContext *cx, const char *message, JSErrorReport *reportp) { JSErrNum errorNumber; JSExnType exn; JSBool ok; JSObject *errProto, *errObject; JSString *messageStr, *filenameStr; uintN lineno; JSExnPrivate *privateData; /* Find the exception index associated with this error. */ JS_ASSERT(reportp); if (JSREPORT_IS_WARNING(reportp->flags)) return JS_FALSE; errorNumber = (JSErrNum) reportp->errorNumber; exn = errorToExceptionNum[errorNumber]; JS_ASSERT(exn < JSEXN_LIMIT); #if defined( DEBUG_mccabe ) && defined ( PRINTNAMES ) /* Print the error name and the associated exception name to stderr */ fprintf(stderr, "%s\t%s\n", errortoexnname[errorNumber].name, errortoexnname[errorNumber].exception); #endif /* * Return false (no exception raised) if no exception is associated * with the given error number. */ if (exn == JSEXN_NONE) return JS_FALSE; /* * Prevent runaway recursion, just as the Exception native constructor * must do, via cx->creatingException. If an out-of-memory error occurs, * no exception object will be created, but we don't assume that OOM is * the only kind of error that subroutines of this function called below * might raise. */ if (cx->creatingException) return JS_FALSE; cx->creatingException = JS_TRUE; /* * Try to get an appropriate prototype by looking up the corresponding * exception constructor name in the scope chain of the current context's * top stack frame, or in the global object if no frame is active. * * XXXbe hack around JSCLASS_NEW_RESOLVE code in js_LookupProperty that * checks cx->fp, cx->fp->pc, and js_CodeSpec[*cx->fp->pc] in order * to compute resolve flags such as JSRESOLVE_ASSIGNING. The bug * is that this "internal" js_GetClassPrototype call may trigger a * resolve of exceptions[exn].name if the global object uses a lazy * standard class resolver (see JS_ResolveStandardClass), but the * current frame and bytecode end up affecting the resolve flags. */ { JSStackFrame *fp = cx->fp; jsbytecode *pc = NULL; if (fp) { pc = fp->pc; fp->pc = NULL; } ok = js_GetClassPrototype(cx, exceptions[exn].name, &errProto); if (pc) fp->pc = pc; if (!ok) goto out; } errObject = js_NewObject(cx, &ExceptionClass, errProto, NULL); if (!errObject) { ok = JS_FALSE; goto out; } messageStr = JS_NewStringCopyZ(cx, message); if (!messageStr) { ok = JS_FALSE; goto out; } if (reportp) { filenameStr = JS_NewStringCopyZ(cx, reportp->filename); if (!filenameStr) { ok = JS_FALSE; goto out; } lineno = reportp->lineno; } else { filenameStr = cx->runtime->emptyString; lineno = 0; } ok = InitExceptionObject(cx, errObject, messageStr, filenameStr, lineno); if (!ok) goto out; /* * Construct a new copy of the error report struct, and store it in the * exception object's private data. We can't use the error report struct * that was passed in, because it's stack-allocated, and also because it * may point to transient data in the JSTokenStream. */ privateData = exn_newPrivate(cx, reportp); if (!privateData) { ok = JS_FALSE; goto out; } OBJ_SET_SLOT(cx, errObject, JSSLOT_PRIVATE, PRIVATE_TO_JSVAL(privateData)); /* Set the generated Exception object as the current exception. */ JS_SetPendingException(cx, OBJECT_TO_JSVAL(errObject)); /* Flag the error report passed in to indicate an exception was raised. */ reportp->flags |= JSREPORT_EXCEPTION; out: cx->creatingException = JS_FALSE; return ok; }
JSBool js_ErrorToException(JSContext *cx, const char *message, JSErrorReport *reportp) { JSErrNum errorNumber; JSExnType exn; JSBool ok; JSObject *errProto, *errObject; JSString *messageStr, *filenameStr; uintN lineno; JSExnPrivate *privateData; const JSErrorFormatString *errorString; /* * Tell our caller to report immediately if cx has no active frames, or if * this report is just a warning. */ JS_ASSERT(reportp); if (!cx->fp || JSREPORT_IS_WARNING(reportp->flags)) return JS_FALSE; /* Find the exception index associated with this error. */ errorNumber = (JSErrNum) reportp->errorNumber; errorString = js_GetLocalizedErrorMessage(cx, NULL, NULL, errorNumber); exn = errorString ? errorString->exnType : JSEXN_NONE; JS_ASSERT(exn < JSEXN_LIMIT); #if defined( DEBUG_mccabe ) && defined ( PRINTNAMES ) /* Print the error name and the associated exception name to stderr */ fprintf(stderr, "%s\t%s\n", errortoexnname[errorNumber].name, errortoexnname[errorNumber].exception); #endif /* * Return false (no exception raised) if no exception is associated * with the given error number. */ if (exn == JSEXN_NONE) return JS_FALSE; /* * Prevent runaway recursion, just as the Exception native constructor * must do, via cx->creatingException. If an out-of-memory error occurs, * no exception object will be created, but we don't assume that OOM is * the only kind of error that subroutines of this function called below * might raise. */ if (cx->creatingException) return JS_FALSE; cx->creatingException = JS_TRUE; /* Protect the newly-created strings below from nesting GCs. */ ok = js_EnterLocalRootScope(cx); if (!ok) goto out; /* * Try to get an appropriate prototype by looking up the corresponding * exception constructor name in the scope chain of the current context's * top stack frame, or in the global object if no frame is active. */ ok = js_GetClassPrototype(cx, exceptions[exn].name, &errProto); if (!ok) goto out; errObject = js_NewObject(cx, &ExceptionClass, errProto, NULL); if (!errObject) { ok = JS_FALSE; goto out; } /* * Set the generated Exception object early, so it won't be GC'd by a last * ditch attempt to collect garbage, or a GC that otherwise nests or races * under any of the following calls. If one of the following calls fails, * it will overwrite this exception object with one of its own (except in * case of OOM errors, of course). */ JS_SetPendingException(cx, OBJECT_TO_JSVAL(errObject)); messageStr = JS_NewStringCopyZ(cx, message); if (!messageStr) { ok = JS_FALSE; goto out; } if (reportp) { filenameStr = JS_NewStringCopyZ(cx, reportp->filename); if (!filenameStr) { ok = JS_FALSE; goto out; } lineno = reportp->lineno; } else { filenameStr = cx->runtime->emptyString; lineno = 0; } ok = InitExceptionObject(cx, errObject, messageStr, filenameStr, lineno); if (!ok) goto out; /* * Construct a new copy of the error report struct, and store it in the * exception object's private data. We can't use the error report struct * that was passed in, because it's stack-allocated, and also because it * may point to transient data in the JSTokenStream. */ privateData = exn_newPrivate(cx, reportp); if (!privateData) { ok = JS_FALSE; goto out; } OBJ_SET_SLOT(cx, errObject, JSSLOT_PRIVATE, PRIVATE_TO_JSVAL(privateData)); /* Flag the error report passed in to indicate an exception was raised. */ reportp->flags |= JSREPORT_EXCEPTION; out: js_LeaveLocalRootScope(cx); cx->creatingException = JS_FALSE; return ok; }