68 |
Exception(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval); |
Exception(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval); |
69 |
|
|
70 |
static void |
static void |
|
exn_finalize(JSContext *cx, JSObject *obj); |
|
|
|
|
|
static void |
|
71 |
exn_trace(JSTracer *trc, JSObject *obj); |
exn_trace(JSTracer *trc, JSObject *obj); |
72 |
|
|
73 |
static void |
static void |
277 |
callerid = ATOM_KEY(cx->runtime->atomState.callerAtom); |
callerid = ATOM_KEY(cx->runtime->atomState.callerAtom); |
278 |
stackDepth = 0; |
stackDepth = 0; |
279 |
valueCount = 0; |
valueCount = 0; |
280 |
for (fp = cx->fp; fp; fp = fp->down) { |
for (fp = js_GetTopStackFrame(cx); fp; fp = fp->down) { |
281 |
if (fp->fun && fp->argv) { |
if (fp->fun && fp->argv) { |
282 |
v = JSVAL_NULL; |
v = JSVAL_NULL; |
283 |
if (checkAccess && |
if (checkAccess && |
318 |
|
|
319 |
values = GetStackTraceValueBuffer(priv); |
values = GetStackTraceValueBuffer(priv); |
320 |
elem = priv->stackElems; |
elem = priv->stackElems; |
321 |
for (fp = cx->fp; fp != fpstop; fp = fp->down) { |
for (fp = js_GetTopStackFrame(cx); fp != fpstop; fp = fp->down) { |
322 |
if (!fp->fun) { |
if (!fp->fun) { |
323 |
elem->funName = NULL; |
elem->funName = NULL; |
324 |
elem->argc = 0; |
elem->argc = 0; |
526 |
return priv->errorReport; |
return priv->errorReport; |
527 |
} |
} |
528 |
|
|
|
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_CTOR |
|
|
|
|
|
static 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} |
|
|
}; |
|
|
|
|
529 |
static JSString * |
static JSString * |
530 |
ValueToShortSource(JSContext *cx, jsval v) |
ValueToShortSource(JSContext *cx, jsval v) |
531 |
{ |
{ |
696 |
JSString *message, *filename; |
JSString *message, *filename; |
697 |
JSStackFrame *fp; |
JSStackFrame *fp; |
698 |
|
|
699 |
if (!(cx->fp->flags & JSFRAME_CONSTRUCTING)) { |
if (!JS_IsConstructing(cx)) { |
700 |
/* |
/* |
701 |
* ECMA ed. 3, 15.11.1 requires Error, etc., to construct even when |
* ECMA ed. 3, 15.11.1 requires Error, etc., to construct even when |
702 |
* called as functions, without operator new. But as we do not give |
* called as functions, without operator new. But as we do not give |
740 |
argv[1] = STRING_TO_JSVAL(filename); |
argv[1] = STRING_TO_JSVAL(filename); |
741 |
fp = NULL; |
fp = NULL; |
742 |
} else { |
} else { |
743 |
fp = JS_GetScriptedCaller(cx, NULL); |
fp = js_GetScriptedCaller(cx, NULL); |
744 |
if (fp) { |
if (fp) { |
745 |
filename = FilenameToString(cx, fp->script->filename); |
filename = FilenameToString(cx, fp->script->filename); |
746 |
if (!filename) |
if (!filename) |
757 |
return JS_FALSE; |
return JS_FALSE; |
758 |
} else { |
} else { |
759 |
if (!fp) |
if (!fp) |
760 |
fp = JS_GetScriptedCaller(cx, NULL); |
fp = js_GetScriptedCaller(cx, NULL); |
761 |
lineno = (fp && fp->regs) ? js_FramePCToLineNumber(cx, fp) : 0; |
lineno = (fp && fp->regs) ? js_FramePCToLineNumber(cx, fp) : 0; |
762 |
} |
} |
763 |
|
|
976 |
JS_FS_END |
JS_FS_END |
977 |
}; |
}; |
978 |
|
|
979 |
|
/* JSProto_ ordering for exceptions shall match JSEXN_ constants. */ |
980 |
|
JS_STATIC_ASSERT(JSEXN_ERR == 0); |
981 |
|
JS_STATIC_ASSERT(JSProto_Error + JSEXN_INTERNALERR == JSProto_InternalError); |
982 |
|
JS_STATIC_ASSERT(JSProto_Error + JSEXN_EVALERR == JSProto_EvalError); |
983 |
|
JS_STATIC_ASSERT(JSProto_Error + JSEXN_RANGEERR == JSProto_RangeError); |
984 |
|
JS_STATIC_ASSERT(JSProto_Error + JSEXN_REFERENCEERR == JSProto_ReferenceError); |
985 |
|
JS_STATIC_ASSERT(JSProto_Error + JSEXN_SYNTAXERR == JSProto_SyntaxError); |
986 |
|
JS_STATIC_ASSERT(JSProto_Error + JSEXN_TYPEERR == JSProto_TypeError); |
987 |
|
JS_STATIC_ASSERT(JSProto_Error + JSEXN_URIERR == JSProto_URIError); |
988 |
|
|
989 |
|
static JS_INLINE JSProtoKey |
990 |
|
GetExceptionProtoKey(intN exn) |
991 |
|
{ |
992 |
|
JS_ASSERT(JSEXN_ERR <= exn); |
993 |
|
JS_ASSERT(exn < JSEXN_LIMIT); |
994 |
|
return (JSProtoKey) (JSProto_Error + exn); |
995 |
|
} |
996 |
|
|
997 |
JSObject * |
JSObject * |
998 |
js_InitExceptionClasses(JSContext *cx, JSObject *obj) |
js_InitExceptionClasses(JSContext *cx, JSObject *obj) |
999 |
{ |
{ |
1000 |
JSObject *obj_proto, *protos[JSEXN_LIMIT]; |
jsval roots[3]; |
1001 |
int i; |
JSObject *obj_proto, *error_proto; |
1002 |
|
jsval empty; |
1003 |
|
|
1004 |
/* |
/* |
1005 |
* If lazy class initialization occurs for any Error subclass, then all |
* If lazy class initialization occurs for any Error subclass, then all |
1016 |
return NULL; |
return NULL; |
1017 |
} |
} |
1018 |
|
|
1019 |
if (!js_EnterLocalRootScope(cx)) |
memset(roots, 0, sizeof(roots)); |
1020 |
return NULL; |
JSAutoTempValueRooter tvr(cx, JS_ARRAY_LENGTH(roots), roots); |
1021 |
|
|
1022 |
|
#ifdef __GNUC__ |
1023 |
|
error_proto = NULL; /* quell GCC overwarning */ |
1024 |
|
#endif |
1025 |
|
|
1026 |
/* Initialize the prototypes first. */ |
/* Initialize the prototypes first. */ |
1027 |
for (i = 0; exceptions[i].name != 0; i++) { |
for (intN i = JSEXN_ERR; i != JSEXN_LIMIT; i++) { |
1028 |
|
JSObject *proto; |
1029 |
|
JSProtoKey protoKey; |
1030 |
JSAtom *atom; |
JSAtom *atom; |
1031 |
JSFunction *fun; |
JSFunction *fun; |
|
JSString *nameString; |
|
|
int protoIndex = exceptions[i].protoIndex; |
|
1032 |
|
|
1033 |
/* Make the prototype for the current constructor name. */ |
/* Make the prototype for the current constructor name. */ |
1034 |
protos[i] = js_NewObject(cx, &js_ErrorClass, |
proto = js_NewObject(cx, &js_ErrorClass, |
1035 |
(protoIndex != JSEXN_NONE) |
(i != JSEXN_ERR) ? error_proto : obj_proto, |
1036 |
? protos[protoIndex] |
obj, 0); |
1037 |
: obj_proto, |
if (!proto) |
1038 |
obj, 0); |
return NULL; |
1039 |
if (!protos[i]) |
if (i == JSEXN_ERR) { |
1040 |
break; |
error_proto = proto; |
1041 |
|
roots[0] = OBJECT_TO_JSVAL(proto); |
1042 |
|
} else { |
1043 |
|
// We cannot share the root for error_proto and other prototypes |
1044 |
|
// as error_proto must be rooted until the function returns. |
1045 |
|
roots[1] = OBJECT_TO_JSVAL(proto); |
1046 |
|
} |
1047 |
|
|
1048 |
/* So exn_finalize knows whether to destroy private data. */ |
/* So exn_finalize knows whether to destroy private data. */ |
1049 |
STOBJ_SET_SLOT(protos[i], JSSLOT_PRIVATE, JSVAL_VOID); |
STOBJ_SET_SLOT(proto, JSSLOT_PRIVATE, JSVAL_VOID); |
1050 |
|
|
1051 |
/* Make a constructor function for the current name. */ |
/* Make a constructor function for the current name. */ |
1052 |
atom = cx->runtime->atomState.classAtoms[exceptions[i].key]; |
protoKey = GetExceptionProtoKey(i); |
1053 |
fun = js_DefineFunction(cx, obj, atom, exceptions[i].native, 3, 0); |
atom = cx->runtime->atomState.classAtoms[protoKey]; |
1054 |
|
fun = js_DefineFunction(cx, obj, atom, Exception, 3, 0); |
1055 |
if (!fun) |
if (!fun) |
1056 |
break; |
return NULL; |
1057 |
|
roots[2] = OBJECT_TO_JSVAL(FUN_OBJECT(fun)); |
1058 |
|
|
1059 |
/* Make this constructor make objects of class Exception. */ |
/* Make this constructor make objects of class Exception. */ |
1060 |
FUN_CLASP(fun) = &js_ErrorClass; |
FUN_CLASP(fun) = &js_ErrorClass; |
1061 |
|
|
1062 |
/* Make the prototype and constructor links. */ |
/* Make the prototype and constructor links. */ |
1063 |
if (!js_SetClassPrototype(cx, FUN_OBJECT(fun), protos[i], |
if (!js_SetClassPrototype(cx, FUN_OBJECT(fun), proto, |
1064 |
JSPROP_READONLY | JSPROP_PERMANENT)) { |
JSPROP_READONLY | JSPROP_PERMANENT)) { |
1065 |
break; |
return NULL; |
1066 |
} |
} |
1067 |
|
|
|
/* proto bootstrap bit from JS_InitClass omitted. */ |
|
|
nameString = JS_NewStringCopyZ(cx, exceptions[i].name); |
|
|
if (!nameString) |
|
|
break; |
|
|
|
|
1068 |
/* Add the name property to the prototype. */ |
/* Add the name property to the prototype. */ |
1069 |
if (!JS_DefineProperty(cx, protos[i], js_name_str, |
if (!JS_DefineProperty(cx, proto, js_name_str, ATOM_KEY(atom), |
1070 |
STRING_TO_JSVAL(nameString), |
NULL, NULL, JSPROP_ENUMERATE)) { |
1071 |
NULL, NULL, |
return NULL; |
|
JSPROP_ENUMERATE)) { |
|
|
break; |
|
1072 |
} |
} |
1073 |
|
|
1074 |
/* Finally, stash the constructor for later uses. */ |
/* Finally, stash the constructor for later uses. */ |
1075 |
if (!js_SetClassObject(cx, obj, exceptions[i].key, FUN_OBJECT(fun))) |
if (!js_SetClassObject(cx, obj, protoKey, FUN_OBJECT(fun))) |
1076 |
break; |
return NULL; |
1077 |
} |
} |
1078 |
|
|
|
js_LeaveLocalRootScope(cx); |
|
|
if (exceptions[i].name) |
|
|
return NULL; |
|
|
|
|
1079 |
/* |
/* |
1080 |
* Add an empty message property. (To Exception.prototype only, |
* Set default values and add methods. We do it only for Error.prototype |
1081 |
* because this property will be the same for all the exception |
* as the rest of exceptions delegate to it. |
|
* protos.) |
|
1082 |
*/ |
*/ |
1083 |
if (!JS_DefineProperty(cx, protos[0], js_message_str, |
empty = STRING_TO_JSVAL(cx->runtime->emptyString); |
1084 |
STRING_TO_JSVAL(cx->runtime->emptyString), |
if (!JS_DefineProperty(cx, error_proto, js_message_str, empty, |
1085 |
NULL, NULL, JSPROP_ENUMERATE)) { |
NULL, NULL, JSPROP_ENUMERATE) || |
1086 |
|
!JS_DefineProperty(cx, error_proto, js_fileName_str, empty, |
1087 |
|
NULL, NULL, JSPROP_ENUMERATE) || |
1088 |
|
!JS_DefineProperty(cx, error_proto, js_lineNumber_str, JSVAL_ZERO, |
1089 |
|
NULL, NULL, JSPROP_ENUMERATE) || |
1090 |
|
!JS_DefineFunctions(cx, error_proto, exception_methods)) { |
1091 |
return NULL; |
return NULL; |
1092 |
} |
} |
|
if (!JS_DefineProperty(cx, protos[0], js_fileName_str, |
|
|
STRING_TO_JSVAL(cx->runtime->emptyString), |
|
|
NULL, NULL, JSPROP_ENUMERATE)) { |
|
|
return NULL; |
|
|
} |
|
|
if (!JS_DefineProperty(cx, protos[0], js_lineNumber_str, |
|
|
INT_TO_JSVAL(0), |
|
|
NULL, NULL, JSPROP_ENUMERATE)) { |
|
|
return NULL; |
|
|
} |
|
|
|
|
|
/* |
|
|
* Add methods only to Exception.prototype, because ostensibly all |
|
|
* exception types delegate to that. |
|
|
*/ |
|
|
if (!JS_DefineFunctions(cx, protos[0], exception_methods)) |
|
|
return NULL; |
|
1093 |
|
|
1094 |
return protos[0]; |
return error_proto; |
1095 |
} |
} |
1096 |
|
|
1097 |
const JSErrorFormatString* |
const JSErrorFormatString* |
1179 |
* exception constructor name in the scope chain of the current context's |
* exception constructor name in the scope chain of the current context's |
1180 |
* top stack frame, or in the global object if no frame is active. |
* top stack frame, or in the global object if no frame is active. |
1181 |
*/ |
*/ |
1182 |
ok = js_GetClassPrototype(cx, NULL, INT_TO_JSID(exceptions[exn].key), |
ok = js_GetClassPrototype(cx, NULL, INT_TO_JSID(GetExceptionProtoKey(exn)), |
1183 |
&errProto); |
&errProto); |
1184 |
if (!ok) |
if (!ok) |
1185 |
goto out; |
goto out; |