summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorwolfbeast <mcwerewolf@gmail.com>2018-03-19 09:21:55 +0100
committerwolfbeast <mcwerewolf@gmail.com>2018-03-19 09:23:23 +0100
commitfaa5f0df26e09d1f2e633618476294d112c24322 (patch)
treed9cc82bd54a71c51146924e975aef4861e67cd27
parent393ee744a8d44494a2a3750aec8e3e9845ecf780 (diff)
parent77e607426f03524bdaf06bfc6799f5e9273051b9 (diff)
downloaduxp-faa5f0df26e09d1f2e633618476294d112c24322.tar.gz
Prototypes should be regular objects.
This resolves #76 Merged remote-tracking branch 'janek/js_error_ordinary-object_1'
-rw-r--r--js/src/jsapi.h3
-rw-r--r--js/src/jsexn.cpp226
-rw-r--r--js/src/jsexn.h9
-rw-r--r--js/src/tests/ecma_6/Error/constructor-proto.js17
-rw-r--r--js/src/tests/ecma_6/Error/prototype-properties.js24
-rw-r--r--js/src/tests/ecma_6/Error/prototype.js18
-rw-r--r--js/src/tests/ecma_6/Error/shell.js0
-rw-r--r--js/src/vm/ErrorObject.cpp69
-rw-r--r--js/src/vm/ErrorObject.h8
-rw-r--r--js/src/vm/GlobalObject.h17
-rw-r--r--js/src/vm/ObjectGroup.cpp4
-rw-r--r--js/xpconnect/tests/chrome/test_xrayToJS.xul11
-rw-r--r--js/xpconnect/wrappers/XrayWrapper.cpp12
13 files changed, 274 insertions, 144 deletions
diff --git a/js/src/jsapi.h b/js/src/jsapi.h
index a93852fa5d..332ce85622 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 d17c6f8b7c..9a8e364edd 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 a63c70909e..ae6335209b 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 0000000000..4ddc6025e8
--- /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 0000000000..c66caf2bcb
--- /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 0000000000..b22a8e084b
--- /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 0000000000..e69de29bb2
--- /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 47b61b57b0..d8d29830b1 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 32a691bb4a..0c2d00610a 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 05984bc5f0..3534ef2f6c 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 7be697fb68..d6a8fcaa46 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 2f4e70f47c..8e6b0f8a40 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 5e537692d0..8011d207fe 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;