From fcc6869f544b62c5014ca6f57dbae0bc79ce99bc Mon Sep 17 00:00:00 2001 From: "rogerl%netscape.com" Date: Tue, 21 Sep 1999 18:58:51 +0000 Subject: [PATCH] ECMA errors as exceptions changes - conformance to latest spec for hierarchy and names etc. Added attempt to make the base exceptions be instanceof equal across contexts. git-svn-id: svn://10.0.0.236/trunk@48586 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/js/src/js.msg | 23 +++++------ mozilla/js/src/jsarray.c | 77 ++++++++++++++++-------------------- mozilla/js/src/jsexn.c | 84 ++++++++++++++++++++++++++++------------ mozilla/js/src/jsexn.h | 4 ++ mozilla/js/src/jsfun.c | 22 ++++++++++- 5 files changed, 130 insertions(+), 80 deletions(-) diff --git a/mozilla/js/src/js.msg b/mozilla/js/src/js.msg index 7bded1953ed..31e37acbbe7 100644 --- a/mozilla/js/src/js.msg +++ b/mozilla/js/src/js.msg @@ -64,25 +64,25 @@ MSG_DEF(JSMSG_BAD_CHAR, 4, 1, JSEXN_NONE, "invalid format charac MSG_DEF(JSMSG_BAD_TYPE, 5, 1, JSEXN_NONE, "unknown type {0}") MSG_DEF(JSMSG_CANT_LOCK, 6, 0, JSEXN_NONE, "can't lock memory") MSG_DEF(JSMSG_CANT_UNLOCK, 7, 0, JSEXN_NONE, "can't unlock memory") -MSG_DEF(JSMSG_INCOMPATIBLE_PROTO, 8, 3, JSEXN_TARGETERR, "{0}.prototype.{1} called on incompatible {2}") +MSG_DEF(JSMSG_INCOMPATIBLE_PROTO, 8, 3, JSEXN_TYPEERR, "{0}.prototype.{1} called on incompatible {2}") MSG_DEF(JSMSG_NO_CONSTRUCTOR, 9, 1, JSEXN_NONE, "{0} has no constructor") MSG_DEF(JSMSG_CANT_ALIAS, 10, 3, JSEXN_NONE, "can't alias {0} to {1} in class {2}") MSG_DEF(JSMSG_NO_PROTO, 11, 1, JSEXN_INTERNALERR, "sorry, Array.prototype.{0} is not yet implemented") -MSG_DEF(JSMSG_BAD_SORT_ARG, 12, 0, JSEXN_ARRAYERR, "invalid Array.prototype.sort argument") +MSG_DEF(JSMSG_BAD_SORT_ARG, 12, 0, JSEXN_TYPEERR, "invalid Array.prototype.sort argument") MSG_DEF(JSMSG_BAD_ATOMIC_NUMBER, 13, 1, JSEXN_INTERNALERR, "internal error: no index for atom {0}") MSG_DEF(JSMSG_TOO_MANY_LITERALS, 14, 0, JSEXN_INTERNALERR, "too many literals") MSG_DEF(JSMSG_CANT_WATCH, 15, 1, JSEXN_NONE, "can't watch non-native objects of class {0}") MSG_DEF(JSMSG_STACK_UNDERFLOW, 16, 2, JSEXN_INTERNALERR, "internal error compiling {0}: stack underflow at pc {1}") -MSG_DEF(JSMSG_NEED_DIET, 17, 1, JSEXN_SYNTAXERR, "{0} too large") +MSG_DEF(JSMSG_NEED_DIET, 17, 1, JSEXN_INTERNALERR, "{0} too large") MSG_DEF(JSMSG_BAD_CASE, 18, 2, JSEXN_SYNTAXERR, "{0}, line {1}: invalid case expression") MSG_DEF(JSMSG_READ_ONLY, 19, 1, JSEXN_ERR, "{0} is read-only") MSG_DEF(JSMSG_BAD_FORMAL, 20, 0, JSEXN_SYNTAXERR, "malformed formal parameter") MSG_DEF(JSMSG_SAME_FORMAL, 21, 1, JSEXN_NONE, "duplicate formal argument {0}") -MSG_DEF(JSMSG_NOT_FUNCTION, 22, 1, JSEXN_CALLERR, "{0} is not a function") -MSG_DEF(JSMSG_NOT_CONSTRUCTOR, 23, 1, JSEXN_CONSTRUCTORERR, "{0} is not a constructor") -MSG_DEF(JSMSG_STACK_OVERFLOW, 24, 1, JSEXN_NONE, "stack overflow in {0}") +MSG_DEF(JSMSG_NOT_FUNCTION, 22, 1, JSEXN_TYPEERR, "{0} is not a function") +MSG_DEF(JSMSG_NOT_CONSTRUCTOR, 23, 1, JSEXN_TYPEERR, "{0} is not a constructor") +MSG_DEF(JSMSG_STACK_OVERFLOW, 24, 1, JSEXN_INTERNALERR, "stack overflow in {0}") MSG_DEF(JSMSG_NOT_EXPORTED, 25, 1, JSEXN_NONE, "{0} is not exported") -MSG_DEF(JSMSG_OVER_RECURSED, 26, 0, JSEXN_NONE, "too much recursion") +MSG_DEF(JSMSG_OVER_RECURSED, 26, 0, JSEXN_INTERNALERR, "too much recursion") MSG_DEF(JSMSG_IN_NOT_OBJECT, 27, 0, JSEXN_ERR, "target of 'in' operator must be an object") MSG_DEF(JSMSG_BAD_NEW_RESULT, 28, 1, JSEXN_NONE, "invalid new expression result {0}") MSG_DEF(JSMSG_BAD_SHARP_DEF, 29, 1, JSEXN_ERR, "invalid sharp variable definition #{0}=") @@ -91,11 +91,11 @@ MSG_DEF(JSMSG_BAD_INSTANCEOF_RHS, 31, 1, JSEXN_ERR, "invalid instanceof ope MSG_DEF(JSMSG_BAD_BYTECODE, 32, 1, JSEXN_INTERNALERR, "unimplemented JavaScript bytecode {0}") MSG_DEF(JSMSG_BAD_RADIX, 33, 1, JSEXN_ERR, "illegal radix {0}") MSG_DEF(JSMSG_NAN, 34, 1, JSEXN_ERR, "{0} is not a number") -MSG_DEF(JSMSG_CANT_CONVERT, 35, 1, JSEXN_TOPRIMITIVEERR, "can't convert {0} to an integer") +MSG_DEF(JSMSG_CANT_CONVERT, 35, 1, JSEXN_NONE, "can't convert {0} to an integer") MSG_DEF(JSMSG_CYCLIC_VALUE, 36, 1, JSEXN_ERR, "cyclic {0} value") MSG_DEF(JSMSG_PERMANENT, 37, 1, JSEXN_ERR, "{0} is permanent") -MSG_DEF(JSMSG_CANT_CONVERT_TO, 38, 2, JSEXN_DEFAULTVALUEERR, "can't convert {0} to {1}") -MSG_DEF(JSMSG_NO_PROPERTIES, 39, 1, JSEXN_TOOBJECTERR, "{0} has no properties") +MSG_DEF(JSMSG_CANT_CONVERT_TO, 38, 2, JSEXN_TYPEERR, "can't convert {0} to {1}") +MSG_DEF(JSMSG_NO_PROPERTIES, 39, 1, JSEXN_TYPEERR, "{0} has no properties") MSG_DEF(JSMSG_CANT_FIND_CLASS, 40, 1, JSEXN_NONE, "can't find class id {0}") MSG_DEF(JSMSG_CANT_XDR_CLASS, 41, 1, JSEXN_NONE, "can't XDR class {0}") MSG_DEF(JSMSG_BYTECODE_TOO_BIG, 42, 2, JSEXN_INTERNALERR, "bytecode {0} too large (limit {1})") @@ -202,9 +202,10 @@ MSG_DEF(JSMSG_BAD_REGEXP_FLAG, 142, 0, JSEXN_SYNTAXERR, "invalid flag aft MSG_DEF(JSMSG_SHARPVAR_TOO_BIG, 143, 0, JSEXN_SYNTAXERR, "overlarge sharp variable number") MSG_DEF(JSMSG_ILLEGAL_CHARACTER, 144, 0, JSEXN_SYNTAXERR, "illegal character") MSG_DEF(JSMSG_BAD_OCTAL, 145, 1, JSEXN_NONE, "{0} is not a legal ECMA-262 numeric constant") -MSG_DEF(JSMSG_BAD_INDIRECT_CALL, 146, 1, JSEXN_CALLERR, "function {0} must be called directly, and not by way of a function of another name.") +MSG_DEF(JSMSG_BAD_INDIRECT_CALL, 146, 1, JSEXN_EVALERR, "function {0} must be called directly, and not by way of a function of another name.") MSG_DEF(JSMSG_UNCAUGHT_EXCEPTION, 147, 1, JSEXN_NONE, "uncaught exception: {0}") MSG_DEF(JSMSG_INVALID_BACKREF, 148, 0, JSEXN_SYNTAXERR, "non-octal digit in an escape sequence that doesn't match a back-reference") MSG_DEF(JSMSG_BAD_BACKREF, 149, 0, JSEXN_SYNTAXERR, "back-reference exceeds number of capturing parentheses") MSG_DEF(JSMSG_PRECISION_RANGE, 150, 1, JSEXN_RANGEERR, "precision {0} out of range") MSG_DEF(JSMSG_BAD_GETTER_OR_SETTER, 151, 1, JSEXN_SYNTAXERR, "invalid {0} usage") +MSG_DEF(JSMSG_BAD_ARRAY_LENGTH, 152, 0, JSEXN_RANGEERR, "Inappropriate array length") diff --git a/mozilla/js/src/jsarray.c b/mozilla/js/src/jsarray.c index 84e00ca30a1..fd855fb4773 100644 --- a/mozilla/js/src/jsarray.c +++ b/mozilla/js/src/jsarray.c @@ -101,52 +101,37 @@ IdIsIndex(jsid id, jsuint *indexp) return JS_FALSE; } - static JSBool ValueIsLength(JSContext *cx, jsval v, jsuint *lengthp) { jsint i; - /* - * It's only an array length if it's an int or a double. Some relevant - * ECMA language is 15.4.2.2 - 'If the argument len is a number, then the - * length property of the newly constructed object is set to ToUint32(len) - * - I take 'is a number' to mean 'typeof len' returns 'number' in - * javascript. - */ if (JSVAL_IS_INT(v)) { i = JSVAL_TO_INT(v); - /* jsuint cast does ToUint32 */ + if (i < 0) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_BAD_ARRAY_LENGTH); + return JS_FALSE; + } if (lengthp) *lengthp = (jsuint) i; return JS_TRUE; } if (JSVAL_IS_DOUBLE(v)) { - /* - * XXXmccabe I'd love to add another check here, against - * js_DoubleToInteger(d) != d), so that ValueIsLength matches - * IdIsIndex, but it doesn't seem to follow from ECMA. - * (seems to be appropriate for IdIsIndex, though). - */ - return js_ValueToECMAUint32(cx, v, (uint32 *)lengthp); - } - return JS_FALSE; -} - - -static JSBool -ValueToIndex(JSContext *cx, jsval v, jsuint *lengthp) -{ - jsint i; - - if (JSVAL_IS_INT(v)) { - i = JSVAL_TO_INT(v); - /* jsuint cast does ToUint32. */ - if (lengthp) - *lengthp = (jsuint)i; + jsdouble d; + /* mccabe gets his wish */ + if (!js_ValueToNumber(cx, v, &d)) + return JS_FALSE; + if (!js_DoubleToECMAUint32(cx, d, (uint32 *)lengthp)) + return JS_FALSE; + if (d != *(uint32 *)lengthp) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_BAD_ARRAY_LENGTH); + return JS_FALSE; + } return JS_TRUE; } - return js_ValueToECMAUint32(cx, v, (uint32 *)lengthp); + return JS_FALSE; } JSBool @@ -250,7 +235,7 @@ array_length_setter(JSContext *cx, JSObject *obj, jsval id, jsval *vp) jsid id2; jsval junk; - if (!ValueToIndex(cx, *vp, &newlen)) + if (!ValueIsLength(cx, *vp, &newlen)) return JS_FALSE; if (!js_GetLengthProperty(cx, obj, &oldlen)) return JS_FALSE; @@ -1320,17 +1305,23 @@ Array(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) if (argc == 0) { length = 0; vector = NULL; - } else if (cx->version != JSVERSION_1_2 && - argc == 1 && ValueIsLength(cx, argv[0], &length)) - { - /* - * Only use 1 arg as first element for version 1.2; for any other - * version (including 1.3), follow ECMA and use it as a length. - */ - vector = NULL; + } else if (cx->version == JSVERSION_1_2) { + if (argc == 1 && ValueIsLength(cx, argv[0], &length)) + vector = NULL; + else { + length = (jsuint) argc; + vector = argv; + } } else { - length = (jsuint) argc; - vector = argv; + if (argc > 1) { + length = (jsuint) argc; + vector = argv; + } + else { + if (!ValueIsLength(cx, argv[0], &length)) + return JS_FALSE; + vector = NULL; + } } return InitArrayObject(cx, obj, length, vector); } diff --git a/mozilla/js/src/jsexn.c b/mozilla/js/src/jsexn.c index 154fab1ba99..fe0c668c104 100644 --- a/mozilla/js/src/jsexn.c +++ b/mozilla/js/src/jsexn.c @@ -39,11 +39,13 @@ /* Declaration to resolve circular reference of exn_class by Exception. */ static JSBool Exception(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval); +JSBool +js_exnHasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp); static void exn_finalize(JSContext *cx, JSObject *obj); -static JSClass exn_class = { +JSClass exn_class = { "Exception", JSCLASS_HAS_PRIVATE, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, @@ -209,20 +211,15 @@ js_ErrorFromException(JSContext *cx, jsval exn) /* This must be kept in synch with the exceptions array below. */ typedef enum JSExnType { JSEXN_NONE = -1, - JSEXN_EXCEPTION, JSEXN_ERR, JSEXN_INTERNALERR, - JSEXN_SYNTAXERR, - JSEXN_REFERENCEERR, - JSEXN_CALLERR, - JSEXN_TARGETERR, - JSEXN_CONSTRUCTORERR, JSEXN_CONVERSIONERR, - JSEXN_TOOBJECTERR, - JSEXN_TOPRIMITIVEERR, - JSEXN_DEFAULTVALUEERR, - JSEXN_ARRAYERR, + JSEXN_EVALERR, JSEXN_RANGEERR, + JSEXN_REFERENCEERR, + JSEXN_SYNTAXERR, + JSEXN_TYPEERR, + JSEXN_URIERR, JSEXN_LIMIT } JSExnType; @@ -232,20 +229,15 @@ struct JSExnSpec { }; static struct JSExnSpec exceptions[] = { - { JSEXN_NONE, "Exception" }, - { JSEXN_EXCEPTION, "Error" }, + { JSEXN_NONE, "Error" }, { JSEXN_ERR, "InternalError" }, - { JSEXN_ERR, "SyntaxError" }, - { JSEXN_ERR, "ReferenceError" }, - { JSEXN_ERR, "CallError" }, - { JSEXN_CALLERR, "TargetError" }, - { JSEXN_ERR, "ConstructorError" }, { JSEXN_ERR, "ConversionError" }, - { JSEXN_CONVERSIONERR, "ToObjectError" }, - { JSEXN_CONVERSIONERR, "ToPrimitiveError" }, - { JSEXN_CONVERSIONERR, "DefaultValueError" }, - { JSEXN_ERR, "ArrayError" }, + { JSEXN_ERR, "EvalError" }, { JSEXN_ERR, "RangeError" }, + { JSEXN_ERR, "ReferenceError" }, + { JSEXN_ERR, "SyntaxError" }, + { JSEXN_ERR, "TypeError" }, + { JSEXN_ERR, "URIError" }, {0} }; @@ -285,6 +277,35 @@ Exception(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) return JS_TRUE; } +/* +* Called by fun_hasInstance when 'obj' has exn_class, to see if +* 'v' could be an instanceof an exception from some other context +* - we'll know it is if it has that special 'something' +*/ + +JSBool +js_exnHasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp) +{ + JSFunction *fun; + JSAtom *functionName; + jsval pval; + + JSObject *obj2; + *bp = JS_FALSE; + + fun = (JSFunction *)JS_GetPrivate(cx, obj); + functionName = fun->atom; + + obj2 = JSVAL_TO_OBJECT(v); + if (!OBJ_GET_PROPERTY(cx, obj2, (jsid)functionName, &pval)) + return JS_FALSE; + + if (JSVAL_IS_INT(pval)) + *bp = JS_TRUE; + + return JS_TRUE; +} + /* * Convert to string. * @@ -416,6 +437,20 @@ js_InitExceptionClasses(JSContext *cx, JSObject *obj) atom = js_Atomize(cx, exceptions[i].name, strlen(exceptions[i].name), 0); + /* + Now add a property to this prototype that can be used to + identify these kind of exceptions across multiple contexts. + This is a little less than satisfying, since other proto + chains may include objects with the same property but it'll + pass for now. + */ + if (!JS_DefineProperty(cx, protos[i], exceptions[i].name, + INT_TO_JSVAL(i), + NULL, NULL, + JSPROP_READONLY | JSPROP_PERMANENT)) + return NULL; + + /* Make a constructor function for the current name. */ fun = js_DefineFunction(cx, obj, atom, Exception, 1, 0); if (!fun) @@ -425,8 +460,9 @@ js_InitExceptionClasses(JSContext *cx, JSObject *obj) fun->clasp = &exn_class; /* Make the prototype and constructor links. */ - if (!js_SetClassPrototype(cx, fun->object, protos[i], - JSPROP_READONLY | JSPROP_PERMANENT)) + if (!js_SetClassPrototype(cx, fun->object, + protos[i], + JSPROP_READONLY | JSPROP_PERMANENT)) return NULL; /* proto bootstrap bit from JS_InitClass omitted. */ diff --git a/mozilla/js/src/jsexn.h b/mozilla/js/src/jsexn.h index 4105dcd9d78..e60f81760bd 100644 --- a/mozilla/js/src/jsexn.h +++ b/mozilla/js/src/jsexn.h @@ -61,6 +61,10 @@ js_ErrorToException(JSContext *cx, const char *message, JSErrorReport *reportp); extern JSBool js_ReportUncaughtException(JSContext *cx); +extern JSClass exn_class; +extern JSBool +js_exnHasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp); + JS_END_EXTERN_C #endif /* jsexn_h___ */ diff --git a/mozilla/js/src/jsfun.c b/mozilla/js/src/jsfun.c index a19385e179d..6b981bf4261 100644 --- a/mozilla/js/src/jsfun.c +++ b/mozilla/js/src/jsfun.c @@ -40,6 +40,7 @@ #include "jsscope.h" #include "jsscript.h" #include "jsstr.h" +#include "jsexn.h" enum { CALL_ARGUMENTS = -1, /* predefined arguments local variable */ @@ -1110,8 +1111,25 @@ fun_hasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp) &pval)) { return JS_FALSE; } - if (!JSVAL_IS_PRIMITIVE(pval)) - return js_IsDelegate(cx, JSVAL_TO_OBJECT(pval), v, bp); + if (!JSVAL_IS_PRIMITIVE(pval)) { + JSObject *protoObj = JSVAL_TO_OBJECT(pval); + if (!js_IsDelegate(cx, protoObj, v, bp)) + return JS_FALSE; + +#if JS_HAS_ERROR_EXCEPTIONS +/* + For exceptions, we want cross-context exceptions to be equal, i.e. a + SyntaxError thrown from one context (another window) will still be a + 'instanceof SyntaxError' in another context (window). Here, if we're + asking if an object is an instance of an exception, make a special + call into js_exnHasInstance. +*/ + if (*bp == JS_TRUE) return JS_TRUE; + if (OBJ_GET_CLASS(cx, protoObj) == &exn_class) + return js_exnHasInstance(cx, obj, v, bp); +#endif /* JS_HAS_ERROR_EXCEPTIONS */ + return JS_TRUE; + } /* * Throw a runtime error if instanceof is called on a function