mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-08-15 08:53:07 +09:00
Issue #2304 - Part 3 - Implement the error cause proposal. https://bugzilla.mozilla.org/show_bug.cgi?id=1679653
This commit is contained in:
parent
64dc722b28
commit
36285d0405
6 changed files with 81 additions and 12 deletions
|
|
@ -221,6 +221,12 @@ typedef enum JSWhyMagic
|
|||
/** for local use */
|
||||
JS_GENERIC_MAGIC,
|
||||
|
||||
/**
|
||||
* When an error object is created without the error cause argument, we set
|
||||
* the error's cause slot to this magic value.
|
||||
*/
|
||||
JS_ERROR_WITHOUT_CAUSE,
|
||||
|
||||
JS_WHY_MAGIC_COUNT
|
||||
} JSWhyMagic;
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
#include "jsexn.h"
|
||||
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/PodOperations.h"
|
||||
#include "mozilla/Sprintf.h"
|
||||
|
||||
|
|
@ -329,6 +330,9 @@ js::ErrorToException(JSContext* cx, JSErrorReport* reportp,
|
|||
uint32_t lineNumber = reportp->lineno;
|
||||
uint32_t columnNumber = reportp->column;
|
||||
|
||||
// Error reports don't provide a |cause|, so we default to |Nothing| here.
|
||||
auto cause = JS::NothingHandleValue;
|
||||
|
||||
RootedObject stack(cx);
|
||||
if (!CaptureStack(cx, &stack))
|
||||
return;
|
||||
|
|
@ -338,7 +342,7 @@ js::ErrorToException(JSContext* cx, JSErrorReport* reportp,
|
|||
return;
|
||||
|
||||
RootedObject errObject(cx, ErrorObject::create(cx, exnType, stack, fileName,
|
||||
lineNumber, columnNumber, &report, messageStr));
|
||||
lineNumber, columnNumber, &report, messageStr, cause));
|
||||
if (!errObject)
|
||||
return;
|
||||
|
||||
|
|
@ -660,13 +664,21 @@ js::CopyErrorObject(JSContext* cx, Handle<ErrorObject*> err)
|
|||
RootedObject stack(cx, err->stack());
|
||||
if (!cx->compartment()->wrap(cx, &stack))
|
||||
return nullptr;
|
||||
Rooted<mozilla::Maybe<Value>> cause(cx, mozilla::Nothing());
|
||||
if (auto maybeCause = err->getCause()) {
|
||||
RootedValue errorCause(cx, maybeCause.value());
|
||||
if (!cx->compartment()->wrap(cx, &errorCause)) {
|
||||
return nullptr;
|
||||
}
|
||||
cause = mozilla::Some(errorCause.get());
|
||||
}
|
||||
uint32_t lineNumber = err->lineNumber();
|
||||
uint32_t columnNumber = err->columnNumber();
|
||||
JSExnType errorType = err->type();
|
||||
|
||||
// Create the Error object.
|
||||
return ErrorObject::create(cx, errorType, stack, fileName,
|
||||
lineNumber, columnNumber, ©Report, message);
|
||||
lineNumber, columnNumber, ©Report, message, cause);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
|
|
@ -681,9 +693,13 @@ JS::CreateError(JSContext* cx, JSExnType type, HandleObject stack, HandleString
|
|||
if (report)
|
||||
rep = CopyErrorReport(cx, report);
|
||||
|
||||
// The public API doesn't (yet) support a |cause| argument, so we default to
|
||||
// |Nothing()| here.
|
||||
auto cause = JS::NothingHandleValue;
|
||||
|
||||
RootedObject obj(cx,
|
||||
js::ErrorObject::create(cx, type, stack, fileName,
|
||||
lineNumber, columnNumber, &rep, message));
|
||||
lineNumber, columnNumber, &rep, message, cause));
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@
|
|||
macro(case, case_, "case") \
|
||||
macro(caseFirst, caseFirst, "caseFirst") \
|
||||
macro(catch, catch_, "catch") \
|
||||
macro(cause, cause, "cause") \
|
||||
macro(class, class_, "class") \
|
||||
macro(close, close, "close") \
|
||||
macro(collation, collation, "collation") \
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#include "vm/ErrorObject-inl.h"
|
||||
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/Range.h"
|
||||
|
||||
#include "jsapi.h"
|
||||
|
|
@ -211,12 +212,35 @@ static ErrorObject* CreateErrorObject(JSContext* cx, const CallArgs& args,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
// Don't interpret the two parameters following the message parameter as the
|
||||
// non-standard fileName and lineNumber arguments when we have an options
|
||||
// object argument.
|
||||
bool hasOptions = args.get(messageArg + 1).isObject();
|
||||
|
||||
Rooted<mozilla::Maybe<Value>> cause(cx, mozilla::Nothing());
|
||||
if (hasOptions) {
|
||||
RootedObject options(cx, &args[messageArg + 1].toObject());
|
||||
|
||||
bool hasCause = false;
|
||||
if (!HasProperty(cx, options, cx->names().cause, &hasCause)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (hasCause) {
|
||||
RootedValue causeValue(cx);
|
||||
if (!GetProperty(cx, options, options, cx->names().cause, &causeValue)) {
|
||||
return nullptr;
|
||||
}
|
||||
cause = mozilla::Some(causeValue.get());
|
||||
}
|
||||
}
|
||||
|
||||
/* 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() > messageArg + 1) {
|
||||
if (!hasOptions && args.length() > messageArg + 1) {
|
||||
fileName = ToString<CanGC>(cx, args[messageArg + 1]);
|
||||
} else {
|
||||
fileName = cx->runtime()->emptyString;
|
||||
|
|
@ -230,7 +254,7 @@ static ErrorObject* CreateErrorObject(JSContext* cx, const CallArgs& args,
|
|||
|
||||
/* Set the 'lineNumber' property. */
|
||||
uint32_t lineNumber, columnNumber = 0;
|
||||
if (args.length() > messageArg + 2) {
|
||||
if (!hasOptions && args.length() > messageArg + 2) {
|
||||
if (!ToUint32(cx, args[messageArg + 2], &lineNumber))
|
||||
return nullptr;
|
||||
} else {
|
||||
|
|
@ -246,7 +270,7 @@ static ErrorObject* CreateErrorObject(JSContext* cx, const CallArgs& args,
|
|||
return nullptr;
|
||||
|
||||
return ErrorObject::create(cx, exnType, stack, fileName, lineNumber,
|
||||
columnNumber, nullptr, message, proto);
|
||||
columnNumber, nullptr, message, cause, proto);
|
||||
}
|
||||
|
||||
static bool Error(JSContext* cx, unsigned argc, Value* vp)
|
||||
|
|
@ -422,7 +446,7 @@ js::ErrorObject::assignInitialShape(ExclusiveContext* cx, Handle<ErrorObject*> o
|
|||
js::ErrorObject::init(JSContext* cx, Handle<ErrorObject*> obj, JSExnType type,
|
||||
ScopedJSFreePtr<JSErrorReport>* errorReport, HandleString fileName,
|
||||
HandleObject stack, uint32_t lineNumber, uint32_t columnNumber,
|
||||
HandleString message)
|
||||
HandleString message, Handle<mozilla::Maybe<JS::Value>> cause)
|
||||
{
|
||||
AssertObjectIsSavedFrameOrWrapper(cx, stack);
|
||||
assertSameCompartment(cx, obj, stack);
|
||||
|
|
@ -453,6 +477,9 @@ js::ErrorObject::init(JSContext* cx, Handle<ErrorObject*> obj, JSExnType type,
|
|||
obj->lookupPure(NameToId(cx->names().message))->slot() == MESSAGE_SLOT);
|
||||
|
||||
MOZ_ASSERT(JSEXN_ERR <= type && type < JSEXN_LIMIT);
|
||||
MOZ_ASSERT_IF(
|
||||
cause.isSome(),
|
||||
obj->lookupPure(NameToId(cx->names().cause))->slot() == CAUSE_SLOT);
|
||||
|
||||
JSErrorReport* report = errorReport ? errorReport->forget() : nullptr;
|
||||
obj->initReservedSlot(EXNTYPE_SLOT, Int32Value(type));
|
||||
|
|
@ -463,6 +490,11 @@ js::ErrorObject::init(JSContext* cx, Handle<ErrorObject*> obj, JSExnType type,
|
|||
obj->initReservedSlot(COLUMNNUMBER_SLOT, Int32Value(columnNumber));
|
||||
if (message)
|
||||
obj->setSlotWithType(cx, messageShape, StringValue(message));
|
||||
if (cause.isSome()) {
|
||||
obj->initReservedSlot(CAUSE_SLOT, *cause.get());
|
||||
} else {
|
||||
obj->initReservedSlot(CAUSE_SLOT, MagicValue(JS_ERROR_WITHOUT_CAUSE));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -471,6 +503,7 @@ js::ErrorObject::init(JSContext* cx, Handle<ErrorObject*> obj, JSExnType type,
|
|||
js::ErrorObject::create(JSContext* cx, JSExnType errorType, HandleObject stack,
|
||||
HandleString fileName, uint32_t lineNumber, uint32_t columnNumber,
|
||||
ScopedJSFreePtr<JSErrorReport>* report, HandleString message,
|
||||
Handle<mozilla::Maybe<JS::Value>> cause,
|
||||
HandleObject protoArg /* = nullptr */)
|
||||
{
|
||||
AssertObjectIsSavedFrameOrWrapper(cx, stack);
|
||||
|
|
@ -492,7 +525,7 @@ js::ErrorObject::create(JSContext* cx, JSExnType errorType, HandleObject stack,
|
|||
}
|
||||
|
||||
if (!ErrorObject::init(cx, errObject, errorType, report, fileName, stack,
|
||||
lineNumber, columnNumber, message))
|
||||
lineNumber, columnNumber, message, cause))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#define vm_ErrorObject_h_
|
||||
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
|
||||
#include "vm/NativeObject.h"
|
||||
#include "vm/SavedStacks.h"
|
||||
|
|
@ -26,7 +27,7 @@ class ErrorObject : public NativeObject
|
|||
static bool
|
||||
init(JSContext* cx, Handle<ErrorObject*> obj, JSExnType type,
|
||||
ScopedJSFreePtr<JSErrorReport>* errorReport, HandleString fileName, HandleObject stack,
|
||||
uint32_t lineNumber, uint32_t columnNumber, HandleString message);
|
||||
uint32_t lineNumber, uint32_t columnNumber, HandleString message, Handle<mozilla::Maybe<JS::Value>> cause);
|
||||
|
||||
static const ClassSpec classSpecs[JSEXN_ERROR_LIMIT];
|
||||
static const Class protoClasses[JSEXN_ERROR_LIMIT];
|
||||
|
|
@ -39,8 +40,9 @@ class ErrorObject : public NativeObject
|
|||
static const uint32_t LINENUMBER_SLOT = FILENAME_SLOT + 1;
|
||||
static const uint32_t COLUMNNUMBER_SLOT = LINENUMBER_SLOT + 1;
|
||||
static const uint32_t MESSAGE_SLOT = COLUMNNUMBER_SLOT + 1;
|
||||
static const uint32_t CAUSE_SLOT = MESSAGE_SLOT + 1;
|
||||
|
||||
static const uint32_t RESERVED_SLOTS = MESSAGE_SLOT + 1;
|
||||
static const uint32_t RESERVED_SLOTS = CAUSE_SLOT + 1;
|
||||
|
||||
public:
|
||||
static const Class classes[JSEXN_ERROR_LIMIT];
|
||||
|
|
@ -61,7 +63,7 @@ class ErrorObject : public NativeObject
|
|||
static ErrorObject*
|
||||
create(JSContext* cx, JSExnType type, HandleObject stack, HandleString fileName,
|
||||
uint32_t lineNumber, uint32_t columnNumber, ScopedJSFreePtr<JSErrorReport>* report,
|
||||
HandleString message, HandleObject proto = nullptr);
|
||||
HandleString message, Handle<mozilla::Maybe<JS::Value>> cause, HandleObject proto = nullptr);
|
||||
|
||||
/*
|
||||
* Assign the initial error shape to the empty object. (This shape does
|
||||
|
|
@ -94,6 +96,14 @@ class ErrorObject : public NativeObject
|
|||
return slot.isString() ? slot.toString() : nullptr;
|
||||
}
|
||||
|
||||
mozilla::Maybe<Value> getCause() const {
|
||||
const auto& value = getReservedSlot(CAUSE_SLOT);
|
||||
if (value.isMagic(JS_ERROR_WITHOUT_CAUSE)) {
|
||||
return mozilla::Nothing();
|
||||
}
|
||||
return mozilla::Some(value);
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
|
|
|||
|
|
@ -1680,8 +1680,11 @@ Reject(JSContext* cx, const CompileArgs& args, UniqueChars error, Handle<Promise
|
|||
if (!message)
|
||||
return false;
|
||||
|
||||
// There's no error |cause| available here.
|
||||
auto cause = JS::NothingHandleValue;
|
||||
|
||||
RootedObject errorObj(cx,
|
||||
ErrorObject::create(cx, JSEXN_WASMCOMPILEERROR, stack, filename, line, column, nullptr, message));
|
||||
ErrorObject::create(cx, JSEXN_WASMCOMPILEERROR, stack, filename, line, column, nullptr, message, cause));
|
||||
if (!errorObj)
|
||||
return false;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue