Bug 872273 - Generate a JSErrorReport when we need one. r=Waldo

This lets js_ReportUncaughtException get the report directly from the underlying
Error object, rather than trying to duck-type it (which fails for security
wrappers).
This commit is contained in:
Bobby Holley 2014-01-30 09:30:29 -08:00
parent 23bfb75afe
commit 1ee98a41c8
4 changed files with 57 additions and 5 deletions

View File

@ -61,8 +61,8 @@ const Class ErrorObject::class_ = {
nullptr /* construct */
};
static JSErrorReport *
CopyErrorReport(JSContext *cx, JSErrorReport *report)
JSErrorReport *
js::CopyErrorReport(JSContext *cx, JSErrorReport *report)
{
/*
* We use a single malloc block to make a deep copy of JSErrorReport with
@ -282,7 +282,7 @@ js_ErrorFromException(JSContext *cx, HandleObject objArg)
if (!obj->is<ErrorObject>())
return nullptr;
return obj->as<ErrorObject>().getErrorReport();
return obj->as<ErrorObject>().getOrCreateErrorReport(cx);
}
static bool
@ -753,10 +753,12 @@ js_ReportUncaughtException(JSContext *cx)
JSErrorReport report;
// If js_ErrorFromException didn't get us a JSErrorReport, then the object
// was not an ErrorObject, security-wrapped or otherwise. However, it might
// still quack like one. Give duck-typing a chance.
const char *filename_str = js_fileName_str;
JSAutoByteString filename;
if (!reportp && exnObject &&
(exnObject->is<ErrorObject>() || IsDuckTypedErrorObject(cx, exnObject, &filename_str)))
if (!reportp && exnObject && IsDuckTypedErrorObject(cx, exnObject, &filename_str))
{
RootedString name(cx);
if (JS_GetProperty(cx, exnObject, js_name_str, roots.handleAt(2)) && roots[2].isString())

View File

@ -16,6 +16,9 @@
namespace js {
class ErrorObject;
extern JSErrorReport *
CopyErrorReport(JSContext *cx, JSErrorReport *report);
}
/*

View File

@ -7,6 +7,8 @@
#include "vm/ErrorObject.h"
#include "jsexn.h"
#include "vm/GlobalObject.h"
#include "jsobjinlines.h"
@ -14,6 +16,7 @@
#include "vm/Shape-inl.h"
using namespace js;
using mozilla::PodZero;
/* static */ Shape *
js::ErrorObject::assignInitialShape(ExclusiveContext *cx, Handle<ErrorObject*> obj)
@ -104,3 +107,45 @@ js::ErrorObject::create(JSContext *cx, JSExnType errorType, HandleString stack,
return errObject;
}
JSErrorReport *
js::ErrorObject::getOrCreateErrorReport(JSContext *cx)
{
if (JSErrorReport *r = getErrorReport())
return r;
// We build an error report on the stack and then use CopyErrorReport to do
// the nitty-gritty malloc stuff.
JSErrorReport report;
PodZero(&report);
// Type.
JSExnType type_ = type();
report.exnType = type_;
// Filename.
JSAutoByteString filenameStr;
if (!filenameStr.encodeLatin1(cx, fileName()))
return nullptr;
report.filename = filenameStr.ptr();
// Coordinates.
report.lineno = lineNumber();
report.column = columnNumber();
// Message. Note that |new Error()| will result in an undefined |message|
// slot, so we need to explicitly substitute the empty string in that case.
RootedString message(cx, getMessage());
if (!message)
message = cx->runtime()->emptyString;
if (!message->ensureStable(cx))
return nullptr;
report.ucmessage = message->asStable().chars().get();
// Cache and return.
JSErrorReport *copy = CopyErrorReport(cx, &report);
if (!copy)
return nullptr;
setReservedSlot(ERROR_REPORT_SLOT, PrivateValue(copy));
return copy;
}

View File

@ -83,6 +83,8 @@ class ErrorObject : public JSObject
return static_cast<JSErrorReport*>(slot.toPrivate());
}
JSErrorReport * getOrCreateErrorReport(JSContext *cx);
JSString * fileName() const {
return getReservedSlot(FILENAME_SLOT).toString();
}