summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--js/src/jsexn.cpp362
-rw-r--r--js/src/jsexn.h3
-rw-r--r--js/src/vm/ErrorObject.cpp356
-rw-r--r--js/src/vm/ErrorObject.h10
4 files changed, 362 insertions, 369 deletions
diff --git a/js/src/jsexn.cpp b/js/src/jsexn.cpp
index 2eb8e7d105..5329fd4eb8 100644
--- a/js/src/jsexn.cpp
+++ b/js/src/jsexn.cpp
@@ -45,162 +45,6 @@ using namespace js::gc;
using mozilla::ArrayLength;
using mozilla::PodArrayZero;
-static void
-exn_finalize(FreeOp* fop, JSObject* obj);
-
-static bool
-exn_toSource(JSContext* cx, unsigned argc, Value* vp);
-
-#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 error_methods[] = {
-#if JS_HAS_TOSOURCE
- JS_FN(js_toSource_str, exn_toSource, 0, 0),
-#endif
- JS_SELF_HOSTED_FN(js_toString_str, "ErrorToString", 0,0),
- 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 */
- nullptr, /* getProperty */
- nullptr, /* setProperty */
- nullptr, /* enumerate */
- nullptr, /* resolve */
- nullptr, /* mayResolve */
- exn_finalize,
- nullptr, /* call */
- nullptr, /* hasInstance */
- nullptr, /* construct */
- nullptr, /* trace */
-};
-
-const Class
-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),
- IMPLEMENT_ERROR_CLASS(CompileError),
- IMPLEMENT_ERROR_CLASS(RuntimeError)
-};
-
size_t
ExtraMallocSize(JSErrorReport* report)
{
@@ -361,8 +205,9 @@ struct SuppressErrorsGuard
}
};
-static bool
-CaptureStack(JSContext* cx, MutableHandleObject stack)
+
+bool
+js::CaptureStack(JSContext* cx, MutableHandleObject stack)
{
// Cut off the stack if it gets too deep (most commonly for infinite recursion
// errors).
@@ -388,14 +233,6 @@ js::ComputeStackString(JSContext* cx)
return str.get();
}
-static void
-exn_finalize(FreeOp* fop, JSObject* obj)
-{
- MOZ_ASSERT(fop->maybeOffMainThread());
- if (JSErrorReport* report = obj->as<ErrorObject>().getErrorReport())
- fop->delete_(report);
-}
-
JSErrorReport*
js::ErrorFromException(JSContext* cx, HandleObject objArg)
{
@@ -429,199 +266,6 @@ ExceptionStackOrNull(HandleObject objArg)
return obj->as<ErrorObject>().stack();
}
-bool
-Error(JSContext* cx, unsigned argc, Value* vp)
-{
- CallArgs args = CallArgsFromVp(argc, vp);
-
- // ES6 19.5.1.1 mandates the .prototype lookup happens before the toString
- RootedObject proto(cx);
- if (!GetPrototypeFromCallableConstructor(cx, args, &proto))
- return false;
-
- /* Compute the error message, if any. */
- RootedString message(cx, nullptr);
- if (args.hasDefined(0)) {
- message = ToString<CanGC>(cx, args[0]);
- if (!message)
- return false;
- }
-
- /* Find the scripted caller, but only ones we're allowed to know about. */
- NonBuiltinFrameIter iter(cx, cx->compartment()->principals());
-
- /* Set the 'fileName' property. */
- RootedString fileName(cx);
- if (args.length() > 1) {
- fileName = ToString<CanGC>(cx, args[1]);
- } else {
- fileName = cx->runtime()->emptyString;
- if (!iter.done()) {
- if (const char* cfilename = iter.filename())
- fileName = JS_NewStringCopyZ(cx, cfilename);
- }
- }
- if (!fileName)
- return false;
-
- /* Set the 'lineNumber' property. */
- uint32_t lineNumber, columnNumber = 0;
- if (args.length() > 2) {
- if (!ToUint32(cx, args[2], &lineNumber))
- return false;
- } else {
- lineNumber = iter.done() ? 0 : iter.computeLine(&columnNumber);
- // XXX: Make the column 1-based as in other browsers, instead of 0-based
- // which is how SpiderMonkey stores it internally. This will be
- // unnecessary once bug 1144340 is fixed.
- ++columnNumber;
- }
-
- RootedObject stack(cx);
- if (!CaptureStack(cx, &stack))
- return false;
-
- /*
- * ECMA ed. 3, 15.11.1 requires Error, etc., to construct even when
- * called as functions, without operator new. But as we do not give
- * each constructor a distinct JSClass, we must get the exception type
- * ourselves.
- */
- JSExnType exnType = JSExnType(args.callee().as<JSFunction>().getExtendedSlot(0).toInt32());
-
- RootedObject obj(cx, ErrorObject::create(cx, exnType, stack, fileName,
- lineNumber, columnNumber, nullptr, message, proto));
- if (!obj)
- return false;
-
- args.rval().setObject(*obj);
- return true;
-}
-
-#if JS_HAS_TOSOURCE
-/*
- * Return a string that may eval to something similar to the original object.
- */
-static bool
-exn_toSource(JSContext* cx, unsigned argc, Value* vp)
-{
- JS_CHECK_RECURSION(cx, return false);
- CallArgs args = CallArgsFromVp(argc, vp);
-
- RootedObject obj(cx, ToObject(cx, args.thisv()));
- if (!obj)
- return false;
-
- RootedValue nameVal(cx);
- RootedString name(cx);
- if (!GetProperty(cx, obj, obj, cx->names().name, &nameVal) ||
- !(name = ToString<CanGC>(cx, nameVal)))
- {
- return false;
- }
-
- RootedValue messageVal(cx);
- RootedString message(cx);
- if (!GetProperty(cx, obj, obj, cx->names().message, &messageVal) ||
- !(message = ValueToSource(cx, messageVal)))
- {
- return false;
- }
-
- RootedValue filenameVal(cx);
- RootedString filename(cx);
- if (!GetProperty(cx, obj, obj, cx->names().fileName, &filenameVal) ||
- !(filename = ValueToSource(cx, filenameVal)))
- {
- return false;
- }
-
- RootedValue linenoVal(cx);
- uint32_t lineno;
- if (!GetProperty(cx, obj, obj, cx->names().lineNumber, &linenoVal) ||
- !ToUint32(cx, linenoVal, &lineno))
- {
- return false;
- }
-
- StringBuffer sb(cx);
- if (!sb.append("(new ") || !sb.append(name) || !sb.append("("))
- return false;
-
- if (!sb.append(message))
- return false;
-
- if (!filename->empty()) {
- if (!sb.append(", ") || !sb.append(filename))
- return false;
- }
- if (lineno != 0) {
- /* We have a line, but no filename, add empty string */
- if (filename->empty() && !sb.append(", \"\""))
- return false;
-
- JSString* linenumber = ToString<CanGC>(cx, linenoVal);
- if (!linenumber)
- return false;
- if (!sb.append(", ") || !sb.append(linenumber))
- return false;
- }
-
- if (!sb.append("))"))
- return false;
-
- JSString* str = sb.finishString();
- if (!str)
- return false;
- args.rval().setString(str);
- return true;
-}
-#endif
-
-/* static */ JSObject*
-ErrorObject::createProto(JSContext* cx, JSProtoKey key)
-{
- JSExnType type = ExnTypeFromProtoKey(key);
-
- if (type == JSEXN_ERR) {
- return GlobalObject::createBlankPrototype(cx, cx->global(),
- &ErrorObject::protoClasses[JSEXN_ERR]);
- }
-
- RootedObject protoProto(cx, GlobalObject::getOrCreateErrorPrototype(cx, cx->global()));
- if (!protoProto)
- return nullptr;
-
- return GlobalObject::createBlankPrototypeInheriting(cx, cx->global(),
- &ErrorObject::protoClasses[type],
- protoProto);
-}
-
-/* static */ JSObject*
-ErrorObject::createConstructor(JSContext* cx, JSProtoKey key)
-{
- JSExnType type = ExnTypeFromProtoKey(key);
- RootedObject ctor(cx);
-
- 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(type));
- return ctor;
-}
-
JS_FRIEND_API(JSFlatString*)
js::GetErrorTypeName(JSContext* cx, int16_t exnType)
{
diff --git a/js/src/jsexn.h b/js/src/jsexn.h
index 16380c696a..a1ed55b4a1 100644
--- a/js/src/jsexn.h
+++ b/js/src/jsexn.h
@@ -23,6 +23,9 @@ CopyErrorNote(JSContext* cx, JSErrorNotes::Note* note);
JSErrorReport*
CopyErrorReport(JSContext* cx, JSErrorReport* report);
+bool
+CaptureStack(JSContext* cx, MutableHandleObject stack);
+
JSString*
ComputeStackString(JSContext* cx);
diff --git a/js/src/vm/ErrorObject.cpp b/js/src/vm/ErrorObject.cpp
index 8976d81d27..192b0758db 100644
--- a/js/src/vm/ErrorObject.cpp
+++ b/js/src/vm/ErrorObject.cpp
@@ -12,6 +12,7 @@
#include "js/CallArgs.h"
#include "js/CharacterEncoding.h"
+#include "vm/StringBuffer.h"
#include "vm/GlobalObject.h"
#include "vm/String.h"
@@ -23,6 +24,283 @@
using namespace js;
+#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 bool
+exn_toSource(JSContext* cx, unsigned argc, Value* vp);
+
+static const JSFunctionSpec error_methods[] = {
+#if JS_HAS_TOSOURCE
+ JS_FN(js_toSource_str, exn_toSource, 0, 0),
+#endif
+ JS_SELF_HOSTED_FN(js_toString_str, "ErrorToString", 0,0),
+ 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 void
+exn_finalize(FreeOp* fop, JSObject* obj);
+
+static const ClassOps ErrorObjectClassOps = {
+ nullptr, /* addProperty */
+ nullptr, /* delProperty */
+ nullptr, /* getProperty */
+ nullptr, /* setProperty */
+ nullptr, /* enumerate */
+ nullptr, /* resolve */
+ nullptr, /* mayResolve */
+ exn_finalize,
+ nullptr, /* call */
+ nullptr, /* hasInstance */
+ nullptr, /* construct */
+ nullptr, /* trace */
+};
+
+const Class
+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),
+ IMPLEMENT_ERROR_CLASS(CompileError),
+ IMPLEMENT_ERROR_CLASS(RuntimeError)
+};
+
+static void
+exn_finalize(FreeOp* fop, JSObject* obj)
+{
+ MOZ_ASSERT(fop->maybeOffMainThread());
+ if (JSErrorReport* report = obj->as<ErrorObject>().getErrorReport())
+ fop->delete_(report);
+}
+
+bool
+Error(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+
+ // ES6 19.5.1.1 mandates the .prototype lookup happens before the toString
+ RootedObject proto(cx);
+ if (!GetPrototypeFromCallableConstructor(cx, args, &proto))
+ return false;
+
+ /* Compute the error message, if any. */
+ RootedString message(cx, nullptr);
+ if (args.hasDefined(0)) {
+ message = ToString<CanGC>(cx, args[0]);
+ if (!message)
+ return false;
+ }
+
+ /* Find the scripted caller, but only ones we're allowed to know about. */
+ NonBuiltinFrameIter iter(cx, cx->compartment()->principals());
+
+ /* Set the 'fileName' property. */
+ RootedString fileName(cx);
+ if (args.length() > 1) {
+ fileName = ToString<CanGC>(cx, args[1]);
+ } else {
+ fileName = cx->runtime()->emptyString;
+ if (!iter.done()) {
+ if (const char* cfilename = iter.filename())
+ fileName = JS_NewStringCopyZ(cx, cfilename);
+ }
+ }
+ if (!fileName)
+ return false;
+
+ /* Set the 'lineNumber' property. */
+ uint32_t lineNumber, columnNumber = 0;
+ if (args.length() > 2) {
+ if (!ToUint32(cx, args[2], &lineNumber))
+ return false;
+ } else {
+ lineNumber = iter.done() ? 0 : iter.computeLine(&columnNumber);
+ // XXX: Make the column 1-based as in other browsers, instead of 0-based
+ // which is how SpiderMonkey stores it internally. This will be
+ // unnecessary once bug 1144340 is fixed.
+ ++columnNumber;
+ }
+
+ RootedObject stack(cx);
+ if (!CaptureStack(cx, &stack))
+ return false;
+
+ /*
+ * ECMA ed. 3, 15.11.1 requires Error, etc., to construct even when
+ * called as functions, without operator new. But as we do not give
+ * each constructor a distinct JSClass, we must get the exception type
+ * ourselves.
+ */
+ JSExnType exnType = JSExnType(args.callee().as<JSFunction>().getExtendedSlot(0).toInt32());
+
+ RootedObject obj(cx, ErrorObject::create(cx, exnType, stack, fileName,
+ lineNumber, columnNumber, nullptr, message, proto));
+ if (!obj)
+ return false;
+
+ args.rval().setObject(*obj);
+ return true;
+}
+
+/* static */ JSObject*
+ErrorObject::createProto(JSContext* cx, JSProtoKey key)
+{
+ JSExnType type = ExnTypeFromProtoKey(key);
+
+ if (type == JSEXN_ERR) {
+ return GlobalObject::createBlankPrototype(cx, cx->global(),
+ &ErrorObject::protoClasses[JSEXN_ERR]);
+ }
+
+ RootedObject protoProto(cx, GlobalObject::getOrCreateErrorPrototype(cx, cx->global()));
+ if (!protoProto)
+ return nullptr;
+
+ return GlobalObject::createBlankPrototypeInheriting(cx, cx->global(),
+ &ErrorObject::protoClasses[type],
+ protoProto);
+}
+
+/* static */ JSObject*
+ErrorObject::createConstructor(JSContext* cx, JSProtoKey key)
+{
+ JSExnType type = ExnTypeFromProtoKey(key);
+ RootedObject ctor(cx);
+
+ 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(type));
+ return ctor;
+}
+
/* static */ Shape*
js::ErrorObject::assignInitialShape(ExclusiveContext* cx, Handle<ErrorObject*> obj)
{
@@ -280,3 +558,81 @@ js::ErrorObject::setStack_impl(JSContext* cx, const CallArgs& args)
return DefineProperty(cx, thisObj, cx->names().stack, val);
}
+
+/*
+ * Return a string that may eval to something similar to the original object.
+ */
+static bool
+exn_toSource(JSContext* cx, unsigned argc, Value* vp)
+{
+ JS_CHECK_RECURSION(cx, return false);
+ CallArgs args = CallArgsFromVp(argc, vp);
+
+ RootedObject obj(cx, ToObject(cx, args.thisv()));
+ if (!obj)
+ return false;
+
+ RootedValue nameVal(cx);
+ RootedString name(cx);
+ if (!GetProperty(cx, obj, obj, cx->names().name, &nameVal) ||
+ !(name = ToString<CanGC>(cx, nameVal)))
+ {
+ return false;
+ }
+
+ RootedValue messageVal(cx);
+ RootedString message(cx);
+ if (!GetProperty(cx, obj, obj, cx->names().message, &messageVal) ||
+ !(message = ValueToSource(cx, messageVal)))
+ {
+ return false;
+ }
+
+ RootedValue filenameVal(cx);
+ RootedString filename(cx);
+ if (!GetProperty(cx, obj, obj, cx->names().fileName, &filenameVal) ||
+ !(filename = ValueToSource(cx, filenameVal)))
+ {
+ return false;
+ }
+
+ RootedValue linenoVal(cx);
+ uint32_t lineno;
+ if (!GetProperty(cx, obj, obj, cx->names().lineNumber, &linenoVal) ||
+ !ToUint32(cx, linenoVal, &lineno))
+ {
+ return false;
+ }
+
+ StringBuffer sb(cx);
+ if (!sb.append("(new ") || !sb.append(name) || !sb.append("("))
+ return false;
+
+ if (!sb.append(message))
+ return false;
+
+ if (!filename->empty()) {
+ if (!sb.append(", ") || !sb.append(filename))
+ return false;
+ }
+ if (lineno != 0) {
+ /* We have a line, but no filename, add empty string */
+ if (filename->empty() && !sb.append(", \"\""))
+ return false;
+
+ JSString* linenumber = ToString<CanGC>(cx, linenoVal);
+ if (!linenumber)
+ return false;
+ if (!sb.append(", ") || !sb.append(linenumber))
+ return false;
+ }
+
+ if (!sb.append("))"))
+ return false;
+
+ JSString* str = sb.finishString();
+ if (!str)
+ return false;
+ args.rval().setString(str);
+ return true;
+}
diff --git a/js/src/vm/ErrorObject.h b/js/src/vm/ErrorObject.h
index 1c32538c11..6e99dfa2c6 100644
--- a/js/src/vm/ErrorObject.h
+++ b/js/src/vm/ErrorObject.h
@@ -14,12 +14,6 @@
namespace js {
-/*
- * Initialize the exception constructor/prototype hierarchy.
- */
-extern JSObject*
-InitExceptionClasses(JSContext* cx, HandleObject obj);
-
class ErrorObject : public NativeObject
{
static JSObject*
@@ -28,10 +22,6 @@ class ErrorObject : public NativeObject
static JSObject*
createConstructor(JSContext* cx, JSProtoKey key);
- /* For access to createProto. */
- friend JSObject*
- js::InitExceptionClasses(JSContext* cx, HandleObject global);
-
static bool
init(JSContext* cx, Handle<ErrorObject*> obj, JSExnType type,
ScopedJSFreePtr<JSErrorReport>* errorReport, HandleString fileName, HandleObject stack,