1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef vm_ErrorObject_h_
8 #define vm_ErrorObject_h_
10 #include "mozilla/Assertions.h"
11 #include "mozilla/Maybe.h"
17 #include "NamespaceImports.h"
20 #include "js/ColumnNumber.h" // JS::ColumnNumberOneOrigin
21 #include "js/ErrorReport.h"
22 #include "js/RootingAPI.h"
23 #include "js/TypeDecls.h"
24 #include "js/UniquePtr.h"
26 #include "vm/JSObject.h"
27 #include "vm/NativeObject.h"
31 class ErrorObject
: public NativeObject
{
32 static JSObject
* createProto(JSContext
* cx
, JSProtoKey key
);
34 static JSObject
* createConstructor(JSContext
* cx
, JSProtoKey key
);
36 static bool init(JSContext
* cx
, Handle
<ErrorObject
*> obj
, JSExnType type
,
37 UniquePtr
<JSErrorReport
> errorReport
, HandleString fileName
,
38 HandleObject stack
, uint32_t sourceId
, uint32_t lineNumber
,
39 JS::ColumnNumberOneOrigin columnNumber
, HandleString message
,
40 Handle
<mozilla::Maybe
<JS::Value
>> cause
);
42 static const ClassSpec classSpecs
[JSEXN_ERROR_LIMIT
];
43 static const JSClass protoClasses
[JSEXN_ERROR_LIMIT
];
46 static const uint32_t STACK_SLOT
= 0;
47 static const uint32_t ERROR_REPORT_SLOT
= STACK_SLOT
+ 1;
48 static const uint32_t FILENAME_SLOT
= ERROR_REPORT_SLOT
+ 1;
49 static const uint32_t LINENUMBER_SLOT
= FILENAME_SLOT
+ 1;
50 static const uint32_t COLUMNNUMBER_SLOT
= LINENUMBER_SLOT
+ 1;
51 static const uint32_t MESSAGE_SLOT
= COLUMNNUMBER_SLOT
+ 1;
52 static const uint32_t CAUSE_SLOT
= MESSAGE_SLOT
+ 1;
53 static const uint32_t SOURCEID_SLOT
= CAUSE_SLOT
+ 1;
55 static const uint32_t RESERVED_SLOTS
= SOURCEID_SLOT
+ 1;
57 // This slot is only used for errors that could be Wasm traps.
58 static const uint32_t WASM_TRAP_SLOT
= SOURCEID_SLOT
+ 1;
59 static const uint32_t RESERVED_SLOTS_MAYBE_WASM_TRAP
= WASM_TRAP_SLOT
+ 1;
62 static const JSClass classes
[JSEXN_ERROR_LIMIT
];
64 static const JSClass
* classForType(JSExnType type
) {
65 MOZ_ASSERT(type
< JSEXN_ERROR_LIMIT
);
66 return &classes
[type
];
69 static bool isErrorClass(const JSClass
* clasp
) {
70 return &classes
[0] <= clasp
&& clasp
< &classes
[0] + std::size(classes
);
73 // Create an error of the given type corresponding to the provided location
74 // info. If |message| is non-null, then the error will have a .message
75 // property with that value; otherwise the error will have no .message
77 static ErrorObject
* create(JSContext
* cx
, JSExnType type
, HandleObject stack
,
78 HandleString fileName
, uint32_t sourceId
,
80 JS::ColumnNumberOneOrigin columnNumber
,
81 UniquePtr
<JSErrorReport
> report
,
83 Handle
<mozilla::Maybe
<JS::Value
>> cause
,
84 HandleObject proto
= nullptr);
87 * Assign the initial error shape to the empty object. (This shape does
88 * *not* include .message, which must be added separately if needed; see
91 static SharedShape
* assignInitialShape(JSContext
* cx
,
92 Handle
<ErrorObject
*> obj
);
94 JSExnType
type() const {
95 MOZ_ASSERT(isErrorClass(getClass()));
96 return static_cast<JSExnType
>(getClass() - &classes
[0]);
99 JSErrorReport
* getErrorReport() const {
100 const Value
& slot
= getReservedSlot(ERROR_REPORT_SLOT
);
101 if (slot
.isUndefined()) {
104 return static_cast<JSErrorReport
*>(slot
.toPrivate());
107 JSErrorReport
* getOrCreateErrorReport(JSContext
* cx
);
109 inline JSString
* fileName(JSContext
* cx
) const;
110 inline uint32_t sourceId() const;
112 // Line number (1-origin).
113 inline uint32_t lineNumber() const;
115 // Column number in UTF-16 code units.
116 inline JS::ColumnNumberOneOrigin
columnNumber() const;
118 // Returns nullptr or a (possibly wrapped) SavedFrame object.
119 inline JSObject
* stack() const;
121 JSString
* getMessage() const {
122 Value val
= getReservedSlot(MESSAGE_SLOT
);
123 return val
.isString() ? val
.toString() : nullptr;
127 * Return Nothing if the error was created without an initial cause or if the
128 * initial cause data property has been redefined to an accessor property.
130 mozilla::Maybe
<Value
> getCause() const {
131 const auto& value
= getReservedSlot(CAUSE_SLOT
);
132 if (value
.isMagic(JS_ERROR_WITHOUT_CAUSE
) || value
.isPrivateGCThing()) {
133 return mozilla::Nothing();
135 return mozilla::Some(value
);
138 void setStackSlot(const Value
& stack
) {
139 MOZ_ASSERT(stack
.isObjectOrNull());
140 setReservedSlot(STACK_SLOT
, stack
);
143 void setCauseSlot(const Value
& cause
) {
144 MOZ_ASSERT(!cause
.isMagic());
145 MOZ_ASSERT(getCause().isSome());
146 setReservedSlot(CAUSE_SLOT
, cause
);
149 // Getter and setter for the Error.prototype.stack accessor.
150 static bool getStack(JSContext
* cx
, unsigned argc
, Value
* vp
);
151 static bool getStack_impl(JSContext
* cx
, const CallArgs
& args
);
152 static bool setStack(JSContext
* cx
, unsigned argc
, Value
* vp
);
153 static bool setStack_impl(JSContext
* cx
, const CallArgs
& args
);
155 // Used to distinguish errors created from Wasm traps.
156 bool mightBeWasmTrap() const {
157 return type() == JSEXN_WASMRUNTIMEERROR
|| type() == JSEXN_INTERNALERR
;
159 bool fromWasmTrap() const {
160 if (!mightBeWasmTrap()) {
163 MOZ_ASSERT(JSCLASS_RESERVED_SLOTS(getClass()) > WASM_TRAP_SLOT
);
164 return getReservedSlot(WASM_TRAP_SLOT
).toBoolean();
167 void setFromWasmTrap();
170 JSString
* ErrorToSource(JSContext
* cx
, HandleObject obj
);
175 inline bool JSObject::is
<js::ErrorObject
>() const {
176 return js::ErrorObject::isErrorClass(getClass());
179 #endif // vm_ErrorObject_h_