📄 jsexn.c
字号:
JSObject **objp){ JSExnPrivate *priv; JSString *str; JSAtom *atom; JSString *stack; const char *prop; jsval v; *objp = NULL; priv = GetExnPrivate(cx, obj); if (priv && JSVAL_IS_STRING(id)) { str = JSVAL_TO_STRING(id); atom = cx->runtime->atomState.messageAtom; if (str == ATOM_TO_STRING(atom)) { prop = js_message_str; v = STRING_TO_JSVAL(priv->message); goto define; } atom = cx->runtime->atomState.fileNameAtom; if (str == ATOM_TO_STRING(atom)) { prop = js_fileName_str; v = STRING_TO_JSVAL(priv->filename); goto define; } atom = cx->runtime->atomState.lineNumberAtom; if (str == ATOM_TO_STRING(atom)) { prop = js_lineNumber_str; v = INT_TO_JSVAL(priv->lineno); goto define; } atom = cx->runtime->atomState.stackAtom; if (str == ATOM_TO_STRING(atom)) { stack = StackTraceToString(cx, priv); if (!stack) return JS_FALSE; /* Allow to GC all things that were used to build stack trace. */ priv->stackDepth = 0; prop = js_stack_str; v = STRING_TO_JSVAL(stack); goto define; } } return JS_TRUE; define: if (!JS_DefineProperty(cx, obj, prop, v, NULL, NULL, JSPROP_ENUMERATE)) return JS_FALSE; *objp = obj; return JS_TRUE;}JSErrorReport *js_ErrorFromException(JSContext *cx, jsval exn){ JSObject *obj; JSExnPrivate *priv; if (JSVAL_IS_PRIMITIVE(exn)) return NULL; obj = JSVAL_TO_OBJECT(exn); if (OBJ_GET_CLASS(cx, obj) != &js_ErrorClass) return NULL; priv = GetExnPrivate(cx, obj); if (!priv) return NULL; return priv->errorReport;}struct JSExnSpec { int protoIndex; const char *name; JSProtoKey key; JSNative native;};/* * All *Error constructors share the same JSClass, js_ErrorClass. But each * constructor function for an *Error class must have a distinct native 'call' * function pointer, in order for instanceof to work properly across multiple * standard class sets. See jsfun.c:fun_hasInstance. */#define MAKE_EXCEPTION_CTOR(name) \static JSBool \name(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) \{ \ return Exception(cx, obj, argc, argv, rval); \}MAKE_EXCEPTION_CTOR(Error)MAKE_EXCEPTION_CTOR(InternalError)MAKE_EXCEPTION_CTOR(EvalError)MAKE_EXCEPTION_CTOR(RangeError)MAKE_EXCEPTION_CTOR(ReferenceError)MAKE_EXCEPTION_CTOR(SyntaxError)MAKE_EXCEPTION_CTOR(TypeError)MAKE_EXCEPTION_CTOR(URIError)#undef MAKE_EXCEPTION_CTORstatic struct JSExnSpec exceptions[] = { {JSEXN_NONE, js_Error_str, JSProto_Error, Error}, {JSEXN_ERR, js_InternalError_str, JSProto_InternalError, InternalError}, {JSEXN_ERR, js_EvalError_str, JSProto_EvalError, EvalError}, {JSEXN_ERR, js_RangeError_str, JSProto_RangeError, RangeError}, {JSEXN_ERR, js_ReferenceError_str, JSProto_ReferenceError, ReferenceError}, {JSEXN_ERR, js_SyntaxError_str, JSProto_SyntaxError, SyntaxError}, {JSEXN_ERR, js_TypeError_str, JSProto_TypeError, TypeError}, {JSEXN_ERR, js_URIError_str, JSProto_URIError, URIError}, {0, NULL, JSProto_Null, NULL}};static JSString *ValueToShortSource(JSContext *cx, jsval v){ JSString *str; /* Avoid toSource bloat and fallibility for object types. */ if (JSVAL_IS_PRIMITIVE(v)) { str = js_ValueToSource(cx, v); } else if (VALUE_IS_FUNCTION(cx, v)) { /* * XXX Avoid function decompilation bloat for now. */ str = JS_GetFunctionId(JS_ValueToFunction(cx, v)); if (!str && !(str = js_ValueToSource(cx, v))) { /* * Continue to soldier on if the function couldn't be * converted into a string. */ JS_ClearPendingException(cx); str = JS_NewStringCopyZ(cx, "[unknown function]"); } } else { /* * XXX Avoid toString on objects, it takes too long and uses too much * memory, for too many classes (see Mozilla bug 166743). */ char buf[100]; JS_snprintf(buf, sizeof buf, "[object %s]", OBJ_GET_CLASS(cx, JSVAL_TO_OBJECT(v))->name); str = JS_NewStringCopyZ(cx, buf); } return str;}static JSString *StackTraceToString(JSContext *cx, JSExnPrivate *priv){ jschar *stackbuf; size_t stacklen, stackmax; JSStackTraceElem *elem, *endElem; jsval *values; size_t i; JSString *str; const char *cp; char ulnbuf[11]; /* After this point, failing control flow must goto bad. */ stackbuf = NULL; stacklen = stackmax = 0;/* Limit the stackbuf length to a reasonable value to avoid overflow checks. */#define STACK_LENGTH_LIMIT JS_BIT(20)#define APPEND_CHAR_TO_STACK(c) \ JS_BEGIN_MACRO \ if (stacklen == stackmax) { \ void *ptr_; \ if (stackmax >= STACK_LENGTH_LIMIT) \ goto done; \ stackmax = stackmax ? 2 * stackmax : 64; \ ptr_ = JS_realloc(cx, stackbuf, (stackmax+1) * sizeof(jschar)); \ if (!ptr_) \ goto bad; \ stackbuf = ptr_; \ } \ stackbuf[stacklen++] = (c); \ JS_END_MACRO#define APPEND_STRING_TO_STACK(str) \ JS_BEGIN_MACRO \ JSString *str_ = str; \ size_t length_ = JSSTRING_LENGTH(str_); \ if (length_ > stackmax - stacklen) { \ void *ptr_; \ if (stackmax >= STACK_LENGTH_LIMIT || \ length_ >= STACK_LENGTH_LIMIT - stacklen) { \ goto done; \ } \ stackmax = JS_BIT(JS_CeilingLog2(stacklen + length_)); \ ptr_ = JS_realloc(cx, stackbuf, (stackmax+1) * sizeof(jschar)); \ if (!ptr_) \ goto bad; \ stackbuf = ptr_; \ } \ js_strncpy(stackbuf + stacklen, JSSTRING_CHARS(str_), length_); \ stacklen += length_; \ JS_END_MACRO values = GetStackTraceValueBuffer(priv); elem = priv->stackElems; for (endElem = elem + priv->stackDepth; elem != endElem; elem++) { if (elem->funName) { APPEND_STRING_TO_STACK(elem->funName); APPEND_CHAR_TO_STACK('('); for (i = 0; i != elem->argc; i++, values++) { if (i > 0) APPEND_CHAR_TO_STACK(','); str = ValueToShortSource(cx, *values); if (!str) goto bad; APPEND_STRING_TO_STACK(str); } APPEND_CHAR_TO_STACK(')'); } APPEND_CHAR_TO_STACK('@'); if (elem->filename) { for (cp = elem->filename; *cp; cp++) APPEND_CHAR_TO_STACK(*cp); } APPEND_CHAR_TO_STACK(':'); JS_snprintf(ulnbuf, sizeof ulnbuf, "%u", elem->ulineno); for (cp = ulnbuf; *cp; cp++) APPEND_CHAR_TO_STACK(*cp); APPEND_CHAR_TO_STACK('\n'); }#undef APPEND_CHAR_TO_STACK#undef APPEND_STRING_TO_STACK#undef STACK_LENGTH_LIMIT done: if (stacklen == 0) { JS_ASSERT(!stackbuf); return cx->runtime->emptyString; } if (stacklen < stackmax) { /* * Realloc can fail when shrinking on some FreeBSD versions, so * don't use JS_realloc here; simply let the oversized allocation * be owned by the string in that rare case. */ void *shrunk = JS_realloc(cx, stackbuf, (stacklen+1) * sizeof(jschar)); if (shrunk) stackbuf = shrunk; } stackbuf[stacklen] = 0; str = js_NewString(cx, stackbuf, stacklen, 0); if (str) return str; bad: if (stackbuf) JS_free(cx, stackbuf); return NULL;}/* XXXbe Consolidate the ugly truth that we don't treat filename as UTF-8 with these two functions. */static JSString *FilenameToString(JSContext *cx, const char *filename){ return JS_NewStringCopyZ(cx, filename);}static const char *StringToFilename(JSContext *cx, JSString *str){ return JS_GetStringBytes(str);}static JSBoolException(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ JSBool ok; uint32 lineno; JSString *message, *filename; JSStackFrame *fp; 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]), ATOM_TO_JSID(cx->runtime->atomState .classPrototypeAtom), rval); if (!ok) goto out; obj = js_NewObject(cx, &js_ErrorClass, JSVAL_TO_OBJECT(*rval), 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) == &js_ErrorClass) 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; } argv[0] = STRING_TO_JSVAL(message); } 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; } argv[1] = STRING_TO_JSVAL(filename); fp = NULL; } else { fp = JS_GetScriptedCaller(cx, NULL); if (fp) { filename = FilenameToString(cx, fp->script->filename); if (!filename) { ok = JS_FALSE; goto out; } } else { filename = cx->runtime->emptyString; } } /* Set the 'lineNumber' property. */ if (argc > 2) { ok = js_ValueToECMAUint32(cx, argv[2], &lineno); if (!ok) goto out; } else { if (!fp) fp = JS_GetScriptedCaller(cx, NULL); lineno = (fp && fp->pc) ? js_PCToLineNumber(cx, fp->script, fp->pc) : 0; } ok = (OBJ_GET_CLASS(cx, obj) != &js_ErrorClass) || InitExnPrivate(cx, obj, message, filename, lineno, NULL); out: cx->creatingException = JS_FALSE; return ok;}/* * Convert to string. * * This method only uses JavaScript-modifiable properties name, message. It * is left to the host to check for private data and report filename and line * number information along with this message. */static JSBoolexn_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ jsval v; JSString *name, *message, *result; jschar *chars, *cp; size_t name_length, message_length, length; if (!OBJ_GET_PROPERTY(cx, obj, ATOM_TO_JSID(cx->runtime->atomState.nameAtom), &v)) { return JS_FALSE; } name = JSVAL_IS_STRING(v) ? JSVAL_TO_STRING(v) : cx->runtime->emptyString; *rval = STRING_TO_JSVAL(name); if (!JS_GetProperty(cx, obj, js_message_str, &v)) return JS_FALSE; message = JSVAL_IS_STRING(v) ? JSVAL_TO_STRING(v) : cx->runtime->emptyString; if (JSSTRING_LENGTH(message) != 0) { name_length = JSSTRING_LENGTH(name); message_length = JSSTRING_LENGTH(message); length = (name_length ? name_length + 2 : 0) + message_length; cp = chars = (jschar*) JS_malloc(cx, (length + 1) * sizeof(jschar)); if (!chars) return JS_FALSE; if (name_length) { js_strncpy(cp, JSSTRING_CHARS(name), name_length); cp += name_length; *cp++ = ':'; *cp++ = ' '; } js_strncpy(cp, JSSTRING_CHARS(message), message_length); cp += message_length; *cp = 0; result = js_NewString(cx, chars, length, 0); if (!result) { JS_free(cx, chars); return JS_FALSE; } } else { result = name; } *rval = STRING_TO_JSVAL(result); return JS_TRUE;}#if JS_HAS_TOSOURCE/* * Return a string that may eval to something similar to the original object. */static JSBoolexn_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ jsval *vp; JSString *name, *message, *filename, *lineno_as_str, *result; uint32 lineno; size_t lineno_length, name_length, message_length, filename_length, length; jschar *chars, *cp; vp = argv + argc; /* beginning of explicit local roots */ if (!OBJ_GET_PROPERTY(cx, obj, ATOM_TO_JSID(cx->runtime->atomState.nameAtom), rval)) { return JS_FALSE; } name = js_ValueToString(cx, *rval);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -