summaryrefslogtreecommitdiffstats
path: root/js/src/vm
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/vm')
-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
4 files changed, 58 insertions, 40 deletions
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;