diff options
author | wolfbeast <mcwerewolf@gmail.com> | 2018-03-19 09:21:55 +0100 |
---|---|---|
committer | wolfbeast <mcwerewolf@gmail.com> | 2018-03-19 09:23:23 +0100 |
commit | faa5f0df26e09d1f2e633618476294d112c24322 (patch) | |
tree | d9cc82bd54a71c51146924e975aef4861e67cd27 /js | |
parent | 393ee744a8d44494a2a3750aec8e3e9845ecf780 (diff) | |
parent | 77e607426f03524bdaf06bfc6799f5e9273051b9 (diff) | |
download | UXP-faa5f0df26e09d1f2e633618476294d112c24322.tar UXP-faa5f0df26e09d1f2e633618476294d112c24322.tar.gz UXP-faa5f0df26e09d1f2e633618476294d112c24322.tar.lz UXP-faa5f0df26e09d1f2e633618476294d112c24322.tar.xz UXP-faa5f0df26e09d1f2e633618476294d112c24322.zip |
Prototypes should be regular objects.
This resolves #76
Merged remote-tracking branch 'janek/js_error_ordinary-object_1'
Diffstat (limited to 'js')
-rw-r--r-- | js/src/jsapi.h | 3 | ||||
-rw-r--r-- | js/src/jsexn.cpp | 226 | ||||
-rw-r--r-- | js/src/jsexn.h | 9 | ||||
-rw-r--r-- | js/src/tests/ecma_6/Error/constructor-proto.js | 17 | ||||
-rw-r--r-- | js/src/tests/ecma_6/Error/prototype-properties.js | 24 | ||||
-rw-r--r-- | js/src/tests/ecma_6/Error/prototype.js | 18 | ||||
-rw-r--r-- | js/src/tests/ecma_6/Error/shell.js | 0 | ||||
-rw-r--r-- | js/src/vm/ErrorObject.cpp | 69 | ||||
-rw-r--r-- | js/src/vm/ErrorObject.h | 8 | ||||
-rw-r--r-- | js/src/vm/GlobalObject.h | 17 | ||||
-rw-r--r-- | js/src/vm/ObjectGroup.cpp | 4 | ||||
-rw-r--r-- | js/xpconnect/tests/chrome/test_xrayToJS.xul | 11 | ||||
-rw-r--r-- | js/xpconnect/wrappers/XrayWrapper.cpp | 12 |
13 files changed, 274 insertions, 144 deletions
diff --git a/js/src/jsapi.h b/js/src/jsapi.h index a93852fa5..332ce8562 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -650,7 +650,8 @@ typedef enum JSExnType { JSEXN_DEBUGGEEWOULDRUN, JSEXN_WASMCOMPILEERROR, JSEXN_WASMRUNTIMEERROR, - JSEXN_WARN, + JSEXN_ERROR_LIMIT, + JSEXN_WARN = JSEXN_ERROR_LIMIT, JSEXN_LIMIT } JSExnType; diff --git a/js/src/jsexn.cpp b/js/src/jsexn.cpp index d17c6f8b7..9a8e364ed 100644 --- a/js/src/jsexn.cpp +++ b/js/src/jsexn.cpp @@ -48,18 +48,35 @@ using mozilla::PodArrayZero; static void exn_finalize(FreeOp* fop, JSObject* obj); -bool -Error(JSContext* cx, unsigned argc, Value* vp); - static bool exn_toSource(JSContext* cx, unsigned argc, Value* vp); -static const JSPropertySpec exception_properties[] = { - JS_PSGS("stack", ErrorObject::getStack, ErrorObject::setStack, 0), - JS_PS_END +#define IMPLEMENT_ERROR_PROTO_CLASS(name) \ + { \ + js_Object_str, \ + JSCLASS_HAS_CACHED_PROTO(JSProto_##name), \ + JS_NULL_CLASS_OPS, \ + &ErrorObject::classSpecs[JSProto_##name - JSProto_Error] \ + } + +const Class +ErrorObject::protoClasses[JSEXN_ERROR_LIMIT] = { + IMPLEMENT_ERROR_PROTO_CLASS(Error), + + IMPLEMENT_ERROR_PROTO_CLASS(InternalError), + IMPLEMENT_ERROR_PROTO_CLASS(EvalError), + IMPLEMENT_ERROR_PROTO_CLASS(RangeError), + IMPLEMENT_ERROR_PROTO_CLASS(ReferenceError), + IMPLEMENT_ERROR_PROTO_CLASS(SyntaxError), + IMPLEMENT_ERROR_PROTO_CLASS(TypeError), + IMPLEMENT_ERROR_PROTO_CLASS(URIError), + + IMPLEMENT_ERROR_PROTO_CLASS(DebuggeeWouldRun), + IMPLEMENT_ERROR_PROTO_CLASS(CompileError), + IMPLEMENT_ERROR_PROTO_CLASS(RuntimeError) }; -static const JSFunctionSpec exception_methods[] = { +static const JSFunctionSpec error_methods[] = { #if JS_HAS_TOSOURCE JS_FN(js_toSource_str, exn_toSource, 0, 0), #endif @@ -67,6 +84,92 @@ static const JSFunctionSpec exception_methods[] = { JS_FS_END }; +static const JSPropertySpec error_properties[] = { + JS_STRING_PS("message", "", 0), + JS_STRING_PS("name", "Error", 0), + // Only Error.prototype has .stack! + JS_PSGS("stack", ErrorObject::getStack, ErrorObject::setStack, 0), + JS_PS_END +}; + +#define IMPLEMENT_ERROR_PROPERTIES(name) \ + { \ + JS_STRING_PS("message", "", 0), \ + JS_STRING_PS("name", #name, 0), \ + JS_PS_END \ + } + +static const JSPropertySpec other_error_properties[JSEXN_ERROR_LIMIT - 1][3] = { + IMPLEMENT_ERROR_PROPERTIES(InternalError), + IMPLEMENT_ERROR_PROPERTIES(EvalError), + IMPLEMENT_ERROR_PROPERTIES(RangeError), + IMPLEMENT_ERROR_PROPERTIES(ReferenceError), + IMPLEMENT_ERROR_PROPERTIES(SyntaxError), + IMPLEMENT_ERROR_PROPERTIES(TypeError), + IMPLEMENT_ERROR_PROPERTIES(URIError), + IMPLEMENT_ERROR_PROPERTIES(DebuggeeWouldRun), + IMPLEMENT_ERROR_PROPERTIES(CompileError), + IMPLEMENT_ERROR_PROPERTIES(RuntimeError) +}; + +#define IMPLEMENT_NATIVE_ERROR_SPEC(name) \ + { \ + ErrorObject::createConstructor, \ + ErrorObject::createProto, \ + nullptr, \ + nullptr, \ + nullptr, \ + other_error_properties[JSProto_##name - JSProto_Error - 1], \ + nullptr, \ + JSProto_Error \ + } + +#define IMPLEMENT_NONGLOBAL_ERROR_SPEC(name) \ + { \ + ErrorObject::createConstructor, \ + ErrorObject::createProto, \ + nullptr, \ + nullptr, \ + nullptr, \ + other_error_properties[JSProto_##name - JSProto_Error - 1], \ + nullptr, \ + JSProto_Error | ClassSpec::DontDefineConstructor \ + } + +const ClassSpec +ErrorObject::classSpecs[JSEXN_ERROR_LIMIT] = { + { + ErrorObject::createConstructor, + ErrorObject::createProto, + nullptr, + nullptr, + error_methods, + error_properties + }, + + IMPLEMENT_NATIVE_ERROR_SPEC(InternalError), + IMPLEMENT_NATIVE_ERROR_SPEC(EvalError), + IMPLEMENT_NATIVE_ERROR_SPEC(RangeError), + IMPLEMENT_NATIVE_ERROR_SPEC(ReferenceError), + IMPLEMENT_NATIVE_ERROR_SPEC(SyntaxError), + IMPLEMENT_NATIVE_ERROR_SPEC(TypeError), + IMPLEMENT_NATIVE_ERROR_SPEC(URIError), + + IMPLEMENT_NONGLOBAL_ERROR_SPEC(DebuggeeWouldRun), + IMPLEMENT_NONGLOBAL_ERROR_SPEC(CompileError), + IMPLEMENT_NONGLOBAL_ERROR_SPEC(RuntimeError) +}; + +#define IMPLEMENT_ERROR_CLASS(name) \ + { \ + js_Error_str, /* yes, really */ \ + JSCLASS_HAS_CACHED_PROTO(JSProto_##name) | \ + JSCLASS_HAS_RESERVED_SLOTS(ErrorObject::RESERVED_SLOTS) | \ + JSCLASS_BACKGROUND_FINALIZE, \ + &ErrorObjectClassOps, \ + &ErrorObject::classSpecs[JSProto_##name - JSProto_Error ] \ + } + static const ClassOps ErrorObjectClassOps = { nullptr, /* addProperty */ nullptr, /* delProperty */ @@ -82,67 +185,20 @@ static const ClassOps ErrorObjectClassOps = { nullptr, /* trace */ }; -#define IMPLEMENT_ERROR_CLASS(name, classSpecPtr) \ - { \ - js_Error_str, /* yes, really */ \ - JSCLASS_HAS_CACHED_PROTO(JSProto_##name) | \ - JSCLASS_HAS_RESERVED_SLOTS(ErrorObject::RESERVED_SLOTS) | \ - JSCLASS_BACKGROUND_FINALIZE, \ - &ErrorObjectClassOps, \ - classSpecPtr \ - } - -const ClassSpec -ErrorObject::errorClassSpec_ = { - ErrorObject::createConstructor, - ErrorObject::createProto, - nullptr, - nullptr, - exception_methods, - exception_properties, - nullptr, - 0 -}; - -const ClassSpec -ErrorObject::subErrorClassSpec_ = { - ErrorObject::createConstructor, - ErrorObject::createProto, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - JSProto_Error -}; - -const ClassSpec -ErrorObject::nonGlobalErrorClassSpec_ = { - ErrorObject::createConstructor, - ErrorObject::createProto, - nullptr, - nullptr, - exception_methods, - exception_properties, - nullptr, - JSProto_Error | ClassSpec::DontDefineConstructor -}; - const Class -ErrorObject::classes[JSEXN_LIMIT] = { - IMPLEMENT_ERROR_CLASS(Error, &ErrorObject::errorClassSpec_), - IMPLEMENT_ERROR_CLASS(InternalError, &ErrorObject::subErrorClassSpec_), - IMPLEMENT_ERROR_CLASS(EvalError, &ErrorObject::subErrorClassSpec_), - IMPLEMENT_ERROR_CLASS(RangeError, &ErrorObject::subErrorClassSpec_), - IMPLEMENT_ERROR_CLASS(ReferenceError, &ErrorObject::subErrorClassSpec_), - IMPLEMENT_ERROR_CLASS(SyntaxError, &ErrorObject::subErrorClassSpec_), - IMPLEMENT_ERROR_CLASS(TypeError, &ErrorObject::subErrorClassSpec_), - IMPLEMENT_ERROR_CLASS(URIError, &ErrorObject::subErrorClassSpec_), - +ErrorObject::classes[JSEXN_ERROR_LIMIT] = { + IMPLEMENT_ERROR_CLASS(Error), + IMPLEMENT_ERROR_CLASS(InternalError), + IMPLEMENT_ERROR_CLASS(EvalError), + IMPLEMENT_ERROR_CLASS(RangeError), + IMPLEMENT_ERROR_CLASS(ReferenceError), + IMPLEMENT_ERROR_CLASS(SyntaxError), + IMPLEMENT_ERROR_CLASS(TypeError), + IMPLEMENT_ERROR_CLASS(URIError), // These Error subclasses are not accessible via the global object: - IMPLEMENT_ERROR_CLASS(DebuggeeWouldRun, &ErrorObject::nonGlobalErrorClassSpec_), - IMPLEMENT_ERROR_CLASS(CompileError, &ErrorObject::nonGlobalErrorClassSpec_), - IMPLEMENT_ERROR_CLASS(RuntimeError, &ErrorObject::nonGlobalErrorClassSpec_) + IMPLEMENT_ERROR_CLASS(DebuggeeWouldRun), + IMPLEMENT_ERROR_CLASS(CompileError), + IMPLEMENT_ERROR_CLASS(RuntimeError) }; JSErrorReport* @@ -454,35 +510,41 @@ exn_toSource(JSContext* cx, unsigned argc, Value* vp) /* static */ JSObject* ErrorObject::createProto(JSContext* cx, JSProtoKey key) { - RootedObject errorProto(cx, GenericCreatePrototype(cx, key)); - if (!errorProto) - return nullptr; - - Rooted<ErrorObject*> err(cx, &errorProto->as<ErrorObject>()); - RootedString emptyStr(cx, cx->names().empty); JSExnType type = ExnTypeFromProtoKey(key); - if (!ErrorObject::init(cx, err, type, nullptr, emptyStr, nullptr, 0, 0, emptyStr)) - return nullptr; - // The various prototypes also have .name in addition to the normal error - // instance properties. - RootedPropertyName name(cx, ClassName(key, cx)); - RootedValue nameValue(cx, StringValue(name)); - if (!DefineProperty(cx, err, cx->names().name, nameValue, nullptr, nullptr, 0)) + if (type == JSEXN_ERR) + return cx->global()->createBlankPrototype(cx, &ErrorObject::protoClasses[JSEXN_ERR]); + + RootedObject protoProto(cx, GlobalObject::getOrCreateErrorPrototype(cx, cx->global())); + if (!protoProto) return nullptr; - return errorProto; + return cx->global()->createBlankPrototypeInheriting(cx, &ErrorObject::protoClasses[type], + protoProto); } /* static */ JSObject* ErrorObject::createConstructor(JSContext* cx, JSProtoKey key) { + JSExnType type = ExnTypeFromProtoKey(key); RootedObject ctor(cx); - ctor = GenericCreateConstructor<Error, 1, gc::AllocKind::FUNCTION_EXTENDED>(cx, key); + + if (type == JSEXN_ERR) { + ctor = GenericCreateConstructor<Error, 1, gc::AllocKind::FUNCTION_EXTENDED>(cx, key); + } else { + RootedFunction proto(cx, GlobalObject::getOrCreateErrorConstructor(cx, cx->global())); + if (!proto) + return nullptr; + + ctor = NewFunctionWithProto(cx, Error, 1, JSFunction::NATIVE_CTOR, nullptr, + ClassName(key, cx), proto, gc::AllocKind::FUNCTION_EXTENDED, + SingletonObject); + } + if (!ctor) return nullptr; - ctor->as<JSFunction>().setExtendedSlot(0, Int32Value(ExnTypeFromProtoKey(key))); + ctor->as<JSFunction>().setExtendedSlot(0, Int32Value(type)); return ctor; } diff --git a/js/src/jsexn.h b/js/src/jsexn.h index a63c70909..ae6335209 100644 --- a/js/src/jsexn.h +++ b/js/src/jsexn.h @@ -85,10 +85,17 @@ ExnTypeFromProtoKey(JSProtoKey key) { JSExnType type = static_cast<JSExnType>(key - JSProto_Error); MOZ_ASSERT(type >= JSEXN_ERR); - MOZ_ASSERT(type < JSEXN_WARN); + MOZ_ASSERT(type < JSEXN_ERROR_LIMIT); return type; } +static inline bool +IsErrorProtoKey(JSProtoKey key) +{ + JSExnType type = static_cast<JSExnType>(key - JSProto_Error); + return type >= JSEXN_ERR && type < JSEXN_ERROR_LIMIT; +} + class AutoClearPendingException { JSContext* cx; diff --git a/js/src/tests/ecma_6/Error/constructor-proto.js b/js/src/tests/ecma_6/Error/constructor-proto.js new file mode 100644 index 000000000..4ddc6025e --- /dev/null +++ b/js/src/tests/ecma_6/Error/constructor-proto.js @@ -0,0 +1,17 @@ +const nativeErrors = [ + InternalError, + EvalError, + RangeError, + ReferenceError, + SyntaxError, + TypeError, + URIError +]; + +assertEq(Reflect.getPrototypeOf(Error), Function.prototype) + +for (const error of nativeErrors) + assertEq(Reflect.getPrototypeOf(error), Error); + +if (typeof reportCompare === "function") + reportCompare(0, 0); diff --git a/js/src/tests/ecma_6/Error/prototype-properties.js b/js/src/tests/ecma_6/Error/prototype-properties.js new file mode 100644 index 000000000..c66caf2bc --- /dev/null +++ b/js/src/tests/ecma_6/Error/prototype-properties.js @@ -0,0 +1,24 @@ +const nativeErrors = [ + InternalError, + EvalError, + RangeError, + ReferenceError, + SyntaxError, + TypeError, + URIError +]; + + +assertEq(Reflect.ownKeys(Error.prototype).toString(), "toSource,toString,message,name,stack,constructor"); +assertEq(Error.prototype.name, "Error"); +assertEq(Error.prototype.message, ""); + +for (const error of nativeErrors) { + assertEq(Reflect.ownKeys(error.prototype).toString(), "message,name,constructor"); + assertEq(error.prototype.name, error.name); + assertEq(error.prototype.message, ""); + assertEq(error.prototype.constructor, error); +} + +if (typeof reportCompare === "function") + reportCompare(0, 0); diff --git a/js/src/tests/ecma_6/Error/prototype.js b/js/src/tests/ecma_6/Error/prototype.js new file mode 100644 index 000000000..b22a8e084 --- /dev/null +++ b/js/src/tests/ecma_6/Error/prototype.js @@ -0,0 +1,18 @@ +const nativeErrors = [ + InternalError, + EvalError, + RangeError, + ReferenceError, + SyntaxError, + TypeError, + URIError +]; + +assertEq(Reflect.getPrototypeOf(Error.prototype), Object.prototype) + +for (const error of nativeErrors) { + assertEq(Reflect.getPrototypeOf(error.prototype), Error.prototype); +} + +if (typeof reportCompare === "function") + reportCompare(0, 0); diff --git a/js/src/tests/ecma_6/Error/shell.js b/js/src/tests/ecma_6/Error/shell.js new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/js/src/tests/ecma_6/Error/shell.js diff --git a/js/src/vm/ErrorObject.cpp b/js/src/vm/ErrorObject.cpp index 47b61b57b..d8d29830b 100644 --- a/js/src/vm/ErrorObject.cpp +++ b/js/src/vm/ErrorObject.cpp @@ -164,29 +164,25 @@ js::ErrorObject::getOrCreateErrorReport(JSContext* cx) } static bool -ErrorObject_checkAndUnwrapThis(JSContext* cx, CallArgs& args, const char* fnName, - MutableHandle<ErrorObject*> error) +FindErrorInstanceOrPrototype(JSContext* cx, HandleObject obj, MutableHandleObject result) { - const Value& thisValue = args.thisv(); - - if (!thisValue.isObject()) { - JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT, - InformalValueTypeName(thisValue)); - return false; - } - - // Walk up the prototype chain until we find the first ErrorObject that has - // the slots we need. This allows us to support the poor-man's subclassing - // of error: Object.create(Error.prototype). - - RootedObject target(cx, CheckedUnwrap(&thisValue.toObject())); + // Walk up the prototype chain until we find an error object instance or + // prototype object. This allows code like: + // Object.create(Error.prototype).stack + // or + // function NYI() { } + // NYI.prototype = new Error; + // (new NYI).stack + // to continue returning stacks that are useless, but at least don't throw. + + RootedObject target(cx, CheckedUnwrap(obj)); if (!target) { JS_ReportErrorASCII(cx, "Permission denied to access object"); return false; } RootedObject proto(cx); - while (!target->is<ErrorObject>()) { + while (!IsErrorProtoKey(StandardProtoKeyOrNull(target))) { if (!GetPrototype(cx, target, &proto)) return false; @@ -194,7 +190,7 @@ ErrorObject_checkAndUnwrapThis(JSContext* cx, CallArgs& args, const char* fnName // We walked the whole prototype chain and did not find an Error // object. JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO, - js_Error_str, fnName, thisValue.toObject().getClass()->name); + js_Error_str, "(get stack)", obj->getClass()->name); return false; } @@ -205,19 +201,40 @@ ErrorObject_checkAndUnwrapThis(JSContext* cx, CallArgs& args, const char* fnName } } - error.set(&target->as<ErrorObject>()); + result.set(target); return true; } + +static MOZ_ALWAYS_INLINE bool +IsObject(HandleValue v) +{ + return v.isObject(); +} + /* static */ bool js::ErrorObject::getStack(JSContext* cx, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); - Rooted<ErrorObject*> error(cx); - if (!ErrorObject_checkAndUnwrapThis(cx, args, "(get stack)", &error)) + // We accept any object here, because of poor-man's subclassing of Error. + return CallNonGenericMethod<IsObject, getStack_impl>(cx, args); +} + +/* static */ bool +js::ErrorObject::getStack_impl(JSContext* cx, const CallArgs& args) +{ + RootedObject thisObj(cx, &args.thisv().toObject()); + + RootedObject obj(cx); + if (!FindErrorInstanceOrPrototype(cx, thisObj, &obj)) return false; - RootedObject savedFrameObj(cx, error->stack()); + if (!obj->is<ErrorObject>()) { + args.rval().setString(cx->runtime()->emptyString); + return true; + } + + RootedObject savedFrameObj(cx, obj->as<ErrorObject>().stack()); RootedString stackString(cx); if (!BuildStackString(cx, savedFrameObj, &stackString)) return false; @@ -245,12 +262,6 @@ js::ErrorObject::getStack(JSContext* cx, unsigned argc, Value* vp) return true; } -static MOZ_ALWAYS_INLINE bool -IsObject(HandleValue v) -{ - return v.isObject(); -} - /* static */ bool js::ErrorObject::setStack(JSContext* cx, unsigned argc, Value* vp) { @@ -262,9 +273,7 @@ js::ErrorObject::setStack(JSContext* cx, unsigned argc, Value* vp) /* static */ bool js::ErrorObject::setStack_impl(JSContext* cx, const CallArgs& args) { - const Value& thisValue = args.thisv(); - MOZ_ASSERT(thisValue.isObject()); - RootedObject thisObj(cx, &thisValue.toObject()); + RootedObject thisObj(cx, &args.thisv().toObject()); if (!args.requireAtLeast(cx, "(set stack)", 1)) return false; diff --git a/js/src/vm/ErrorObject.h b/js/src/vm/ErrorObject.h index 32a691bb4..0c2d00610 100644 --- a/js/src/vm/ErrorObject.h +++ b/js/src/vm/ErrorObject.h @@ -38,9 +38,8 @@ class ErrorObject : public NativeObject ScopedJSFreePtr<JSErrorReport>* errorReport, HandleString fileName, HandleObject stack, uint32_t lineNumber, uint32_t columnNumber, HandleString message); - static const ClassSpec errorClassSpec_; - static const ClassSpec subErrorClassSpec_; - static const ClassSpec nonGlobalErrorClassSpec_; + static const ClassSpec classSpecs[JSEXN_ERROR_LIMIT]; + static const Class protoClasses[JSEXN_ERROR_LIMIT]; protected: static const uint32_t EXNTYPE_SLOT = 0; @@ -54,7 +53,7 @@ class ErrorObject : public NativeObject static const uint32_t RESERVED_SLOTS = MESSAGE_SLOT + 1; public: - static const Class classes[JSEXN_LIMIT]; + static const Class classes[JSEXN_ERROR_LIMIT]; static const Class * classForType(JSExnType type) { MOZ_ASSERT(type < JSEXN_WARN); @@ -107,6 +106,7 @@ class ErrorObject : public NativeObject // Getter and setter for the Error.prototype.stack accessor. static bool getStack(JSContext* cx, unsigned argc, Value* vp); + static bool getStack_impl(JSContext* cx, const CallArgs& args); static bool setStack(JSContext* cx, unsigned argc, Value* vp); static bool setStack_impl(JSContext* cx, const CallArgs& args); }; diff --git a/js/src/vm/GlobalObject.h b/js/src/vm/GlobalObject.h index 05984bc5f..3534ef2f6 100644 --- a/js/src/vm/GlobalObject.h +++ b/js/src/vm/GlobalObject.h @@ -427,6 +427,18 @@ class GlobalObject : public NativeObject return &global->getPrototype(key).toObject(); } + static JSFunction* + getOrCreateErrorConstructor(JSContext* cx, Handle<GlobalObject*> global) { + if (!ensureConstructor(cx, global, JSProto_Error)) + return nullptr; + return &global->getConstructor(JSProto_Error).toObject().as<JSFunction>(); + } + + static JSObject* + getOrCreateErrorPrototype(JSContext* cx, Handle<GlobalObject*> global) { + return getOrCreateCustomErrorPrototype(cx, global, JSEXN_ERR); + } + static NativeObject* getOrCreateSetPrototype(JSContext* cx, Handle<GlobalObject*> global) { if (!ensureConstructor(cx, global, JSProto_Set)) return nullptr; @@ -1003,10 +1015,7 @@ GenericCreatePrototype(JSContext* cx, JSProtoKey key) inline JSProtoKey StandardProtoKeyOrNull(const JSObject* obj) { - JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(obj->getClass()); - if (key == JSProto_Error) - return GetExceptionProtoKey(obj->as<ErrorObject>().type()); - return key; + return JSCLASS_CACHED_PROTO_KEY(obj->getClass()); } JSObject* diff --git a/js/src/vm/ObjectGroup.cpp b/js/src/vm/ObjectGroup.cpp index 7be697fb6..d6a8fcaa4 100644 --- a/js/src/vm/ObjectGroup.cpp +++ b/js/src/vm/ObjectGroup.cpp @@ -6,6 +6,7 @@ #include "vm/ObjectGroup.h" +#include "jsexn.h" #include "jshashutil.h" #include "jsobj.h" @@ -578,11 +579,10 @@ ObjectGroup::defaultNewGroup(ExclusiveContext* cx, const Class* clasp, AddTypePropertyId(cx, group, nullptr, NameToId(names.lastIndex), TypeSet::Int32Type()); } else if (clasp == &StringObject::class_) { AddTypePropertyId(cx, group, nullptr, NameToId(names.length), TypeSet::Int32Type()); - } else if (ErrorObject::isErrorClass((clasp))) { + } else if (ErrorObject::isErrorClass(clasp)) { AddTypePropertyId(cx, group, nullptr, NameToId(names.fileName), TypeSet::StringType()); AddTypePropertyId(cx, group, nullptr, NameToId(names.lineNumber), TypeSet::Int32Type()); AddTypePropertyId(cx, group, nullptr, NameToId(names.columnNumber), TypeSet::Int32Type()); - AddTypePropertyId(cx, group, nullptr, NameToId(names.stack), TypeSet::StringType()); } return group; diff --git a/js/xpconnect/tests/chrome/test_xrayToJS.xul b/js/xpconnect/tests/chrome/test_xrayToJS.xul index 2f4e70f47..8e6b0f8a4 100644 --- a/js/xpconnect/tests/chrome/test_xrayToJS.xul +++ b/js/xpconnect/tests/chrome/test_xrayToJS.xul @@ -220,11 +220,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=933681 // There is no TypedArray constructor, looks like. is(window.TypedArray, undefined, "If this ever changes, add to this test!"); for (var c of errorObjectClasses) { - gPrototypeProperties[c] = ["constructor", "name", - // We don't actually resolve these empty data properties - // onto the Xray prototypes, but we list them here to make - // the test happy. - "lineNumber", "columnNumber", "fileName", "message", "stack"]; + gPrototypeProperties[c] = ["constructor", "name", "message", "stack"]; gConstructorProperties[c] = constructorProps([]); } // toString and toSource only live on the parent proto (Error.prototype). @@ -791,8 +787,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=933681 // We only invoke testXray with Error, because that function isn't set up // to deal with dependent classes and fixing it up is more trouble than // it's worth. - testXray('Error', new iwin.Error('some error message'), new iwin.Error(), - ['fileName', 'lineNumber', 'columnNumber', 'message']); + testXray('Error', new iwin.Error('some error message'), new iwin.Error()); // Make sure that the dependent classes have their prototypes set up correctly. for (let c of errorObjectClasses.filter(x => x != "Error")) { @@ -806,7 +801,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=933681 e.wrappedJSObject[name] = goodReplacement; is(e[name], goodReplacement, name + " property ok after replacement: " + goodReplacement); e.wrappedJSObject[name] = faultyReplacement; - is(e[name], undefined, name + " property censored after suspicious replacement"); + is(e[name], name == 'message' ? "" : undefined, name + " property skipped after suspicious replacement"); } testProperty('message', x => x == 'some message', 'some other message', 42); testProperty('fileName', x => x == '', 'otherFilename.html', new iwin.Object()); diff --git a/js/xpconnect/wrappers/XrayWrapper.cpp b/js/xpconnect/wrappers/XrayWrapper.cpp index 5e537692d..8011d207f 100644 --- a/js/xpconnect/wrappers/XrayWrapper.cpp +++ b/js/xpconnect/wrappers/XrayWrapper.cpp @@ -636,14 +636,6 @@ JSXrayTraits::resolveOwnProperty(JSContext* cx, const Wrapper& jsWrapper, return true; } - // Handle the 'name' property for error prototypes. - if (IsErrorObjectKey(key) && id == GetJSIDByIndex(cx, XPCJSContext::IDX_NAME)) { - RootedId className(cx); - ProtoKeyToId(cx, key, &className); - FillPropertyDescriptor(desc, wrapper, 0, UndefinedValue()); - return JS_IdToValue(cx, className, desc.value()); - } - // Handle the 'lastIndex' property for RegExp prototypes. if (key == JSProto_RegExp && id == GetJSIDByIndex(cx, XPCJSContext::IDX_LASTINDEX)) return getOwnPropertyFromWrapperIfSafe(cx, wrapper, id, desc); @@ -889,10 +881,6 @@ JSXrayTraits::enumerateNames(JSContext* cx, HandleObject wrapper, unsigned flags if (!props.append(GetJSIDByIndex(cx, XPCJSContext::IDX_CONSTRUCTOR))) return false; - // For Error protoypes, add the 'name' property. - if (IsErrorObjectKey(key) && !props.append(GetJSIDByIndex(cx, XPCJSContext::IDX_NAME))) - return false; - // For RegExp protoypes, add the 'lastIndex' property. if (key == JSProto_RegExp && !props.append(GetJSIDByIndex(cx, XPCJSContext::IDX_LASTINDEX))) return false; |