--- trunk/js/jsexn.cpp 2008/12/09 03:37:47 399 +++ trunk/js/jsexn.cpp 2009/09/26 23:15:22 460 @@ -68,9 +68,6 @@ Exception(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval); static void -exn_finalize(JSContext *cx, JSObject *obj); - -static void exn_trace(JSTracer *trc, JSObject *obj); static void @@ -280,7 +277,7 @@ callerid = ATOM_KEY(cx->runtime->atomState.callerAtom); stackDepth = 0; valueCount = 0; - for (fp = cx->fp; fp; fp = fp->down) { + for (fp = js_GetTopStackFrame(cx); fp; fp = fp->down) { if (fp->fun && fp->argv) { v = JSVAL_NULL; if (checkAccess && @@ -321,7 +318,7 @@ values = GetStackTraceValueBuffer(priv); elem = priv->stackElems; - for (fp = cx->fp; fp != fpstop; fp = fp->down) { + for (fp = js_GetTopStackFrame(cx); fp != fpstop; fp = fp->down) { if (!fp->fun) { elem->funName = NULL; elem->argc = 0; @@ -529,49 +526,6 @@ 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_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} -}; - static JSString * ValueToShortSource(JSContext *cx, jsval v) { @@ -742,7 +696,7 @@ JSString *message, *filename; JSStackFrame *fp; - if (!(cx->fp->flags & JSFRAME_CONSTRUCTING)) { + if (!JS_IsConstructing(cx)) { /* * 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 @@ -786,7 +740,7 @@ argv[1] = STRING_TO_JSVAL(filename); fp = NULL; } else { - fp = JS_GetScriptedCaller(cx, NULL); + fp = js_GetScriptedCaller(cx, NULL); if (fp) { filename = FilenameToString(cx, fp->script->filename); if (!filename) @@ -803,7 +757,7 @@ return JS_FALSE; } else { if (!fp) - fp = JS_GetScriptedCaller(cx, NULL); + fp = js_GetScriptedCaller(cx, NULL); lineno = (fp && fp->regs) ? js_FramePCToLineNumber(cx, fp) : 0; } @@ -1022,11 +976,30 @@ JS_FS_END }; +/* JSProto_ ordering for exceptions shall match JSEXN_ constants. */ +JS_STATIC_ASSERT(JSEXN_ERR == 0); +JS_STATIC_ASSERT(JSProto_Error + JSEXN_INTERNALERR == JSProto_InternalError); +JS_STATIC_ASSERT(JSProto_Error + JSEXN_EVALERR == JSProto_EvalError); +JS_STATIC_ASSERT(JSProto_Error + JSEXN_RANGEERR == JSProto_RangeError); +JS_STATIC_ASSERT(JSProto_Error + JSEXN_REFERENCEERR == JSProto_ReferenceError); +JS_STATIC_ASSERT(JSProto_Error + JSEXN_SYNTAXERR == JSProto_SyntaxError); +JS_STATIC_ASSERT(JSProto_Error + JSEXN_TYPEERR == JSProto_TypeError); +JS_STATIC_ASSERT(JSProto_Error + JSEXN_URIERR == JSProto_URIError); + +static JS_INLINE JSProtoKey +GetExceptionProtoKey(intN exn) +{ + JS_ASSERT(JSEXN_ERR <= exn); + JS_ASSERT(exn < JSEXN_LIMIT); + return (JSProtoKey) (JSProto_Error + exn); +} + JSObject * js_InitExceptionClasses(JSContext *cx, JSObject *obj) { - JSObject *obj_proto, *protos[JSEXN_LIMIT]; - int i; + jsval roots[3]; + JSObject *obj_proto, *error_proto; + jsval empty; /* * If lazy class initialization occurs for any Error subclass, then all @@ -1043,94 +1016,82 @@ return NULL; } - if (!js_EnterLocalRootScope(cx)) - return NULL; + memset(roots, 0, sizeof(roots)); + JSAutoTempValueRooter tvr(cx, JS_ARRAY_LENGTH(roots), roots); + +#ifdef __GNUC__ + error_proto = NULL; /* quell GCC overwarning */ +#endif /* Initialize the prototypes first. */ - for (i = 0; exceptions[i].name != 0; i++) { + for (intN i = JSEXN_ERR; i != JSEXN_LIMIT; i++) { + JSObject *proto; + JSProtoKey protoKey; JSAtom *atom; JSFunction *fun; - JSString *nameString; - int protoIndex = exceptions[i].protoIndex; /* Make the prototype for the current constructor name. */ - protos[i] = js_NewObject(cx, &js_ErrorClass, - (protoIndex != JSEXN_NONE) - ? protos[protoIndex] - : obj_proto, - obj, 0); - if (!protos[i]) - break; + proto = js_NewObject(cx, &js_ErrorClass, + (i != JSEXN_ERR) ? error_proto : obj_proto, + obj, 0); + if (!proto) + return NULL; + if (i == JSEXN_ERR) { + error_proto = proto; + roots[0] = OBJECT_TO_JSVAL(proto); + } else { + // We cannot share the root for error_proto and other prototypes + // as error_proto must be rooted until the function returns. + roots[1] = OBJECT_TO_JSVAL(proto); + } /* So exn_finalize knows whether to destroy private data. */ - STOBJ_SET_SLOT(protos[i], JSSLOT_PRIVATE, JSVAL_VOID); + STOBJ_SET_SLOT(proto, JSSLOT_PRIVATE, JSVAL_VOID); /* Make a constructor function for the current name. */ - atom = cx->runtime->atomState.classAtoms[exceptions[i].key]; - fun = js_DefineFunction(cx, obj, atom, exceptions[i].native, 3, 0); + protoKey = GetExceptionProtoKey(i); + atom = cx->runtime->atomState.classAtoms[protoKey]; + fun = js_DefineFunction(cx, obj, atom, Exception, 3, 0); if (!fun) - break; + return NULL; + roots[2] = OBJECT_TO_JSVAL(FUN_OBJECT(fun)); /* Make this constructor make objects of class Exception. */ FUN_CLASP(fun) = &js_ErrorClass; /* Make the prototype and constructor links. */ - if (!js_SetClassPrototype(cx, FUN_OBJECT(fun), protos[i], + if (!js_SetClassPrototype(cx, FUN_OBJECT(fun), proto, JSPROP_READONLY | JSPROP_PERMANENT)) { - break; + return NULL; } - /* proto bootstrap bit from JS_InitClass omitted. */ - nameString = JS_NewStringCopyZ(cx, exceptions[i].name); - if (!nameString) - break; - /* Add the name property to the prototype. */ - if (!JS_DefineProperty(cx, protos[i], js_name_str, - STRING_TO_JSVAL(nameString), - NULL, NULL, - JSPROP_ENUMERATE)) { - break; + if (!JS_DefineProperty(cx, proto, js_name_str, ATOM_KEY(atom), + NULL, NULL, JSPROP_ENUMERATE)) { + return NULL; } /* Finally, stash the constructor for later uses. */ - if (!js_SetClassObject(cx, obj, exceptions[i].key, FUN_OBJECT(fun))) - break; + if (!js_SetClassObject(cx, obj, protoKey, FUN_OBJECT(fun))) + return NULL; } - js_LeaveLocalRootScope(cx); - if (exceptions[i].name) - return NULL; - /* - * Add an empty message property. (To Exception.prototype only, - * because this property will be the same for all the exception - * protos.) + * Set default values and add methods. We do it only for Error.prototype + * as the rest of exceptions delegate to it. */ - if (!JS_DefineProperty(cx, protos[0], js_message_str, - STRING_TO_JSVAL(cx->runtime->emptyString), - NULL, NULL, JSPROP_ENUMERATE)) { + empty = STRING_TO_JSVAL(cx->runtime->emptyString); + if (!JS_DefineProperty(cx, error_proto, js_message_str, empty, + NULL, NULL, JSPROP_ENUMERATE) || + !JS_DefineProperty(cx, error_proto, js_fileName_str, empty, + NULL, NULL, JSPROP_ENUMERATE) || + !JS_DefineProperty(cx, error_proto, js_lineNumber_str, JSVAL_ZERO, + NULL, NULL, JSPROP_ENUMERATE) || + !JS_DefineFunctions(cx, error_proto, exception_methods)) { return NULL; } - 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; - return protos[0]; + return error_proto; } const JSErrorFormatString* @@ -1218,7 +1179,7 @@ * 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, NULL, INT_TO_JSID(exceptions[exn].key), + ok = js_GetClassPrototype(cx, NULL, INT_TO_JSID(GetExceptionProtoKey(exn)), &errProto); if (!ok) goto out;