mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-20 22:27:31 +09:00
Use ordinary objects for Error prototypes
This commit is contained in:
parent
b0fe82b857
commit
105cbadae7
4 changed files with 161 additions and 91 deletions
|
|
@ -650,7 +650,8 @@ typedef enum JSExnType {
|
||||||
JSEXN_DEBUGGEEWOULDRUN,
|
JSEXN_DEBUGGEEWOULDRUN,
|
||||||
JSEXN_WASMCOMPILEERROR,
|
JSEXN_WASMCOMPILEERROR,
|
||||||
JSEXN_WASMRUNTIMEERROR,
|
JSEXN_WASMRUNTIMEERROR,
|
||||||
JSEXN_WARN,
|
JSEXN_ERROR_LIMIT,
|
||||||
|
JSEXN_WARN = JSEXN_ERROR_LIMIT,
|
||||||
JSEXN_LIMIT
|
JSEXN_LIMIT
|
||||||
} JSExnType;
|
} JSExnType;
|
||||||
|
|
||||||
|
|
|
||||||
225
js/src/jsexn.cpp
225
js/src/jsexn.cpp
|
|
@ -48,18 +48,35 @@ using mozilla::PodArrayZero;
|
||||||
static void
|
static void
|
||||||
exn_finalize(FreeOp* fop, JSObject* obj);
|
exn_finalize(FreeOp* fop, JSObject* obj);
|
||||||
|
|
||||||
bool
|
|
||||||
Error(JSContext* cx, unsigned argc, Value* vp);
|
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
exn_toSource(JSContext* cx, unsigned argc, Value* vp);
|
exn_toSource(JSContext* cx, unsigned argc, Value* vp);
|
||||||
|
|
||||||
static const JSPropertySpec exception_properties[] = {
|
#define IMPLEMENT_ERROR_PROTO_CLASS(name) \
|
||||||
JS_PSGS("stack", ErrorObject::getStack, ErrorObject::setStack, 0),
|
{ \
|
||||||
JS_PS_END
|
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
|
#if JS_HAS_TOSOURCE
|
||||||
JS_FN(js_toSource_str, exn_toSource, 0, 0),
|
JS_FN(js_toSource_str, exn_toSource, 0, 0),
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -67,6 +84,92 @@ static const JSFunctionSpec exception_methods[] = {
|
||||||
JS_FS_END
|
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 = {
|
static const ClassOps ErrorObjectClassOps = {
|
||||||
nullptr, /* addProperty */
|
nullptr, /* addProperty */
|
||||||
nullptr, /* delProperty */
|
nullptr, /* delProperty */
|
||||||
|
|
@ -82,67 +185,20 @@ static const ClassOps ErrorObjectClassOps = {
|
||||||
nullptr, /* trace */
|
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
|
const Class
|
||||||
ErrorObject::classes[JSEXN_LIMIT] = {
|
ErrorObject::classes[JSEXN_ERROR_LIMIT] = {
|
||||||
IMPLEMENT_ERROR_CLASS(Error, &ErrorObject::errorClassSpec_),
|
IMPLEMENT_ERROR_CLASS(Error),
|
||||||
IMPLEMENT_ERROR_CLASS(InternalError, &ErrorObject::subErrorClassSpec_),
|
IMPLEMENT_ERROR_CLASS(InternalError),
|
||||||
IMPLEMENT_ERROR_CLASS(EvalError, &ErrorObject::subErrorClassSpec_),
|
IMPLEMENT_ERROR_CLASS(EvalError),
|
||||||
IMPLEMENT_ERROR_CLASS(RangeError, &ErrorObject::subErrorClassSpec_),
|
IMPLEMENT_ERROR_CLASS(RangeError),
|
||||||
IMPLEMENT_ERROR_CLASS(ReferenceError, &ErrorObject::subErrorClassSpec_),
|
IMPLEMENT_ERROR_CLASS(ReferenceError),
|
||||||
IMPLEMENT_ERROR_CLASS(SyntaxError, &ErrorObject::subErrorClassSpec_),
|
IMPLEMENT_ERROR_CLASS(SyntaxError),
|
||||||
IMPLEMENT_ERROR_CLASS(TypeError, &ErrorObject::subErrorClassSpec_),
|
IMPLEMENT_ERROR_CLASS(TypeError),
|
||||||
IMPLEMENT_ERROR_CLASS(URIError, &ErrorObject::subErrorClassSpec_),
|
IMPLEMENT_ERROR_CLASS(URIError),
|
||||||
|
|
||||||
// These Error subclasses are not accessible via the global object:
|
// These Error subclasses are not accessible via the global object:
|
||||||
IMPLEMENT_ERROR_CLASS(DebuggeeWouldRun, &ErrorObject::nonGlobalErrorClassSpec_),
|
IMPLEMENT_ERROR_CLASS(DebuggeeWouldRun),
|
||||||
IMPLEMENT_ERROR_CLASS(CompileError, &ErrorObject::nonGlobalErrorClassSpec_),
|
IMPLEMENT_ERROR_CLASS(CompileError),
|
||||||
IMPLEMENT_ERROR_CLASS(RuntimeError, &ErrorObject::nonGlobalErrorClassSpec_)
|
IMPLEMENT_ERROR_CLASS(RuntimeError)
|
||||||
};
|
};
|
||||||
|
|
||||||
JSErrorReport*
|
JSErrorReport*
|
||||||
|
|
@ -454,35 +510,40 @@ exn_toSource(JSContext* cx, unsigned argc, Value* vp)
|
||||||
/* static */ JSObject*
|
/* static */ JSObject*
|
||||||
ErrorObject::createProto(JSContext* cx, JSProtoKey key)
|
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);
|
JSExnType type = ExnTypeFromProtoKey(key);
|
||||||
if (!ErrorObject::init(cx, err, type, nullptr, emptyStr, nullptr, 0, 0, emptyStr))
|
|
||||||
|
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 nullptr;
|
||||||
|
|
||||||
// The various prototypes also have .name in addition to the normal error
|
return cx->global()->createBlankPrototypeInheriting(cx, &ErrorObject::protoClasses[type],
|
||||||
// instance properties.
|
protoProto);
|
||||||
RootedPropertyName name(cx, ClassName(key, cx));
|
|
||||||
RootedValue nameValue(cx, StringValue(name));
|
|
||||||
if (!DefineProperty(cx, err, cx->names().name, nameValue, nullptr, nullptr, 0))
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
return errorProto;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* static */ JSObject*
|
/* static */ JSObject*
|
||||||
ErrorObject::createConstructor(JSContext* cx, JSProtoKey key)
|
ErrorObject::createConstructor(JSContext* cx, JSProtoKey key)
|
||||||
{
|
{
|
||||||
|
JSExnType type = ExnTypeFromProtoKey(key);
|
||||||
RootedObject ctor(cx);
|
RootedObject ctor(cx);
|
||||||
|
|
||||||
|
if (type == JSEXN_ERR) {
|
||||||
ctor = GenericCreateConstructor<Error, 1, gc::AllocKind::FUNCTION_EXTENDED>(cx, key);
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
if (!ctor)
|
if (!ctor)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
ctor->as<JSFunction>().setExtendedSlot(0, Int32Value(ExnTypeFromProtoKey(key)));
|
ctor->as<JSFunction>().setExtendedSlot(0, Int32Value(type));
|
||||||
return ctor;
|
return ctor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -38,9 +38,8 @@ class ErrorObject : public NativeObject
|
||||||
ScopedJSFreePtr<JSErrorReport>* errorReport, HandleString fileName, HandleObject stack,
|
ScopedJSFreePtr<JSErrorReport>* errorReport, HandleString fileName, HandleObject stack,
|
||||||
uint32_t lineNumber, uint32_t columnNumber, HandleString message);
|
uint32_t lineNumber, uint32_t columnNumber, HandleString message);
|
||||||
|
|
||||||
static const ClassSpec errorClassSpec_;
|
static const ClassSpec classSpecs[JSEXN_ERROR_LIMIT];
|
||||||
static const ClassSpec subErrorClassSpec_;
|
static const Class protoClasses[JSEXN_ERROR_LIMIT];
|
||||||
static const ClassSpec nonGlobalErrorClassSpec_;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static const uint32_t EXNTYPE_SLOT = 0;
|
static const uint32_t EXNTYPE_SLOT = 0;
|
||||||
|
|
@ -54,7 +53,7 @@ class ErrorObject : public NativeObject
|
||||||
static const uint32_t RESERVED_SLOTS = MESSAGE_SLOT + 1;
|
static const uint32_t RESERVED_SLOTS = MESSAGE_SLOT + 1;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static const Class classes[JSEXN_LIMIT];
|
static const Class classes[JSEXN_ERROR_LIMIT];
|
||||||
|
|
||||||
static const Class * classForType(JSExnType type) {
|
static const Class * classForType(JSExnType type) {
|
||||||
MOZ_ASSERT(type < JSEXN_WARN);
|
MOZ_ASSERT(type < JSEXN_WARN);
|
||||||
|
|
|
||||||
|
|
@ -427,6 +427,18 @@ class GlobalObject : public NativeObject
|
||||||
return &global->getPrototype(key).toObject();
|
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) {
|
static NativeObject* getOrCreateSetPrototype(JSContext* cx, Handle<GlobalObject*> global) {
|
||||||
if (!ensureConstructor(cx, global, JSProto_Set))
|
if (!ensureConstructor(cx, global, JSProto_Set))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
@ -1003,10 +1015,7 @@ GenericCreatePrototype(JSContext* cx, JSProtoKey key)
|
||||||
inline JSProtoKey
|
inline JSProtoKey
|
||||||
StandardProtoKeyOrNull(const JSObject* obj)
|
StandardProtoKeyOrNull(const JSObject* obj)
|
||||||
{
|
{
|
||||||
JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(obj->getClass());
|
return JSCLASS_CACHED_PROTO_KEY(obj->getClass());
|
||||||
if (key == JSProto_Error)
|
|
||||||
return GetExceptionProtoKey(obj->as<ErrorObject>().type());
|
|
||||||
return key;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JSObject*
|
JSObject*
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue