diff options
Diffstat (limited to 'js/src/vm')
-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 |
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; |