jsexn.c
来自「一个基于alice开发的机器人」· C语言 代码 · 共 1,082 行 · 第 1/3 页
C
1,082 行
* so we can suppress any checkAccess failures. Such failures should stop
* the backtrace procedure, not result in a failure of this constructor.
*/
checkAccess = cx->runtime->checkObjectAccess;
if (checkAccess) {
older = JS_SetErrorReporter(cx, NULL);
state = JS_SaveExceptionState(cx);
}
#ifdef __GNUC__ /* suppress bogus gcc warnings */
else {
older = NULL;
state = NULL;
}
#endif
callerid = ATOM_KEY(cx->runtime->atomState.callerAtom);
/*
* Prepare to allocate a jschar buffer at stackbuf, where stacklen indexes
* the next free jschar slot, and with room for at most stackmax non-null
* jschars. If stackbuf is non-null, it always contains an extra slot for
* the null terminator we'll store at the end, as a backstop.
*
* All early returns must goto done after this point, till the after-loop
* cleanup code has run!
*/
stackbuf = NULL;
stacklen = stackmax = 0;
ok = JS_TRUE;
#define APPEND_CHAR_TO_STACK(c) \
JS_BEGIN_MACRO \
if (stacklen == stackmax) { \
void *ptr_; \
stackmax = stackmax ? 2 * stackmax : 64; \
ptr_ = JS_realloc(cx, stackbuf, (stackmax+1) * sizeof(jschar)); \
if (!ptr_) { \
ok = JS_FALSE; \
goto done; \
} \
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 (stacklen + length_ > stackmax) { \
void *ptr_; \
stackmax = JS_BIT(JS_CeilingLog2(stacklen + length_)); \
ptr_ = JS_realloc(cx, stackbuf, (stackmax+1) * sizeof(jschar)); \
if (!ptr_) { \
ok = JS_FALSE; \
goto done; \
} \
stackbuf = ptr_; \
} \
js_strncpy(stackbuf + stacklen, JSSTRING_CHARS(str_), length_); \
stacklen += length_; \
JS_END_MACRO
for (fp = cx->fp; fp; fp = fp->down) {
if (checkAccess) {
v = (fp->fun && fp->argv) ? fp->argv[-2] : JSVAL_NULL;
if (!JSVAL_IS_PRIMITIVE(v)) {
ok = checkAccess(cx, fp->fun->object, callerid, JSACC_READ, &v);
if (!ok) {
ok = JS_TRUE;
break;
}
}
}
if (fp->fun) {
if (fp->fun->atom)
APPEND_STRING_TO_STACK(ATOM_TO_STRING(fp->fun->atom));
APPEND_CHAR_TO_STACK('(');
for (i = 0; i < fp->argc; i++) {
/* Avoid toSource bloat and fallibility for object types. */
v = fp->argv[i];
if (JSVAL_IS_PRIMITIVE(v)) {
argsrc = js_ValueToSource(cx, v);
} else if (JSVAL_IS_FUNCTION(cx, v)) {
/* XXX Avoid function decompilation bloat for now. */
argsrc = JS_GetFunctionId(JS_ValueToFunction(cx, v));
if (!argsrc)
argsrc = js_ValueToSource(cx, v);
} 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);
argsrc = JS_NewStringCopyZ(cx, buf);
}
if (!argsrc) {
ok = JS_FALSE;
goto done;
}
if (i > 0)
APPEND_CHAR_TO_STACK(',');
APPEND_STRING_TO_STACK(argsrc);
}
APPEND_CHAR_TO_STACK(')');
}
APPEND_CHAR_TO_STACK('@');
if (fp->script && fp->script->filename) {
for (cp = fp->script->filename; *cp; cp++)
APPEND_CHAR_TO_STACK(*cp);
}
APPEND_CHAR_TO_STACK(':');
if (fp->script && fp->pc) {
ulineno = js_PCToLineNumber(cx, fp->script, fp->pc);
JS_snprintf(ulnbuf, sizeof ulnbuf, "%u", ulineno);
for (cp = ulnbuf; *cp; cp++)
APPEND_CHAR_TO_STACK(*cp);
} else {
APPEND_CHAR_TO_STACK('0');
}
APPEND_CHAR_TO_STACK('\n');
}
#undef APPEND_CHAR_TO_STACK
#undef APPEND_STRING_TO_STACK
done:
if (checkAccess) {
if (ok)
JS_RestoreExceptionState(cx, state);
else
JS_DropExceptionState(cx, state);
JS_SetErrorReporter(cx, older);
}
if (!ok) {
JS_free(cx, stackbuf);
return JS_FALSE;
}
if (!stackbuf) {
stack = cx->runtime->emptyString;
} else {
/* NB: if stackbuf was allocated, it has room for the terminator. */
JS_ASSERT(stacklen <= stackmax);
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 = realloc(stackbuf, (stacklen+1) * sizeof(jschar));
if (shrunk)
stackbuf = shrunk;
}
stackbuf[stacklen] = 0;
stack = js_NewString(cx, stackbuf, stacklen, 0);
if (!stack) {
JS_free(cx, stackbuf);
return JS_FALSE;
}
}
return JS_DefineProperty(cx, obj, js_stack_str,
STRING_TO_JSVAL(stack),
NULL, NULL, JSPROP_ENUMERATE);
}
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;
}
/*
* 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 JSBool
exn_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, (jsid)cx->runtime->atomState.nameAtom, &v))
return JS_FALSE;
name = js_ValueToString(cx, v);
if (!name)
return JS_FALSE;
if (!JS_GetProperty(cx, obj, js_message_str, &v) ||
!(message = js_ValueToString(cx, v))) {
return JS_FALSE;
}
if (JSSTRING_LENGTH(message) != 0) {
name_length = JSSTRING_LENGTH(name);
message_length = JSSTRING_LENGTH(message);
length = name_length + message_length + 2;
cp = chars = (jschar*) JS_malloc(cx, (length + 1) * sizeof(jschar));
if (!chars)
return JS_FALSE;
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 JSBool
exn_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
jsval v;
JSString *name, *message, *filename, *lineno_as_str, *result;
int32 lineno;
size_t lineno_length, name_length, message_length, filename_length, length;
jschar *chars, *cp;
if (!OBJ_GET_PROPERTY(cx, obj, (jsid)cx->runtime->atomState.nameAtom, &v))
return JS_FALSE;
name = js_ValueToString(cx, v);
if (!name)
return JS_FALSE;
if (!JS_GetProperty(cx, obj, js_message_str, &v) ||
!(message = js_ValueToSource(cx, v))) {
return JS_FALSE;
}
if (!JS_GetProperty(cx, obj, js_filename_str, &v) ||
!(filename = js_ValueToSource(cx, v))) {
return JS_FALSE;
}
if (!JS_GetProperty(cx, obj, js_lineno_str, &v) ||
!js_ValueToInt32 (cx, v, &lineno)) {
return JS_FALSE;
}
if (lineno != 0) {
if (!(lineno_as_str = js_ValueToString(cx, v))) {
return JS_FALSE;
}
lineno_length = JSSTRING_LENGTH(lineno_as_str);
} else {
lineno_as_str = NULL;
lineno_length = 0;
}
/* Magic 8, for the characters in ``(new ())''. */
name_length = JSSTRING_LENGTH(name);
message_length = JSSTRING_LENGTH(message);
length = 8 + name_length + message_length;
filename_length = JSSTRING_LENGTH(filename);
if (filename_length != 0) {
/* append filename as ``, {filename}'' */
length += 2 + filename_length;
if (lineno_as_str) {
/* append lineno as ``, {lineno_as_str}'' */
length += 2 + lineno_length;
}
} else {
if (lineno_as_str) {
/*
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?