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/. */ 6 7 #ifndef vm_ErrorObject_h_ 8 #define vm_ErrorObject_h_ 9 10 #include "mozilla/ArrayUtils.h" 11 #include "mozilla/Assertions.h" 12 13 #include <stdint.h> 14 15 #include "jspubtd.h" 16 #include "NamespaceImports.h" 17 18 #include "gc/Barrier.h" 19 #include "js/Class.h" 20 #include "js/ErrorReport.h" 21 #include "js/RootingAPI.h" 22 #include "js/TypeDecls.h" 23 #include "js/UniquePtr.h" 24 #include "js/Value.h" 25 #include "vm/FunctionFlags.h" // js::FunctionFlags 26 #include "vm/JSObject.h" 27 #include "vm/NativeObject.h" 28 #include "vm/Shape.h" 29 30 namespace js { 31 class ArrayObject; 32 33 class ErrorObject : public NativeObject { 34 static JSObject* createProto(JSContext* cx, JSProtoKey key); 35 36 static JSObject* createConstructor(JSContext* cx, JSProtoKey key); 37 38 static bool init(JSContext* cx, Handle<ErrorObject*> obj, JSExnType type, 39 UniquePtr<JSErrorReport> errorReport, HandleString fileName, 40 HandleObject stack, uint32_t sourceId, uint32_t lineNumber, 41 uint32_t columnNumber, HandleString message); 42 43 static const ClassSpec classSpecs[JSEXN_ERROR_LIMIT]; 44 static const JSClass protoClasses[JSEXN_ERROR_LIMIT]; 45 46 protected: 47 static const uint32_t EXNTYPE_SLOT = 0; 48 static const uint32_t STACK_SLOT = EXNTYPE_SLOT + 1; 49 static const uint32_t ERROR_REPORT_SLOT = STACK_SLOT + 1; 50 static const uint32_t FILENAME_SLOT = ERROR_REPORT_SLOT + 1; 51 static const uint32_t LINENUMBER_SLOT = FILENAME_SLOT + 1; 52 static const uint32_t COLUMNNUMBER_SLOT = LINENUMBER_SLOT + 1; 53 static const uint32_t MESSAGE_SLOT = COLUMNNUMBER_SLOT + 1; 54 static const uint32_t SOURCEID_SLOT = MESSAGE_SLOT + 1; 55 56 static const uint32_t RESERVED_SLOTS = SOURCEID_SLOT + 1; 57 58 public: 59 static const JSClass classes[JSEXN_ERROR_LIMIT]; 60 classForType(JSExnType type)61 static const JSClass* classForType(JSExnType type) { 62 MOZ_ASSERT(type < JSEXN_WARN); 63 return &classes[type]; 64 } 65 isErrorClass(const JSClass * clasp)66 static bool isErrorClass(const JSClass* clasp) { 67 return &classes[0] <= clasp && 68 clasp < &classes[0] + mozilla::ArrayLength(classes); 69 } 70 71 // Create an error of the given type corresponding to the provided location 72 // info. If |message| is non-null, then the error will have a .message 73 // property with that value; otherwise the error will have no .message 74 // property. 75 static ErrorObject* create(JSContext* cx, JSExnType type, HandleObject stack, 76 HandleString fileName, uint32_t sourceId, 77 uint32_t lineNumber, uint32_t columnNumber, 78 UniquePtr<JSErrorReport> report, 79 HandleString message, 80 HandleObject proto = nullptr); 81 82 /* 83 * Assign the initial error shape to the empty object. (This shape does 84 * *not* include .message, which must be added separately if needed; see 85 * ErrorObject::init.) 86 */ 87 static Shape* assignInitialShape(JSContext* cx, Handle<ErrorObject*> obj); 88 type()89 JSExnType type() const { 90 return JSExnType(getReservedSlot(EXNTYPE_SLOT).toInt32()); 91 } 92 getErrorReport()93 JSErrorReport* getErrorReport() const { 94 const Value& slot = getReservedSlot(ERROR_REPORT_SLOT); 95 if (slot.isUndefined()) { 96 return nullptr; 97 } 98 return static_cast<JSErrorReport*>(slot.toPrivate()); 99 } 100 101 JSErrorReport* getOrCreateErrorReport(JSContext* cx); 102 103 inline JSString* fileName(JSContext* cx) const; 104 inline uint32_t sourceId() const; 105 inline uint32_t lineNumber() const; 106 inline uint32_t columnNumber() const; 107 inline JSObject* stack() const; 108 getMessage()109 JSString* getMessage() const { 110 const HeapSlot& slot = getReservedSlotRef(MESSAGE_SLOT); 111 return slot.isString() ? slot.toString() : nullptr; 112 } 113 114 // Getter and setter for the Error.prototype.stack accessor. 115 static bool getStack(JSContext* cx, unsigned argc, Value* vp); 116 static bool getStack_impl(JSContext* cx, const CallArgs& args); 117 static bool setStack(JSContext* cx, unsigned argc, Value* vp); 118 static bool setStack_impl(JSContext* cx, const CallArgs& args); 119 }; 120 121 class AggregateErrorObject : public ErrorObject { 122 friend class ErrorObject; 123 124 // [[AggregateErrors]] slot of AggregateErrorObjects. 125 static const uint32_t AGGREGATE_ERRORS_SLOT = ErrorObject::RESERVED_SLOTS; 126 static const uint32_t RESERVED_SLOTS = AGGREGATE_ERRORS_SLOT + 1; 127 128 public: 129 ArrayObject* aggregateErrors() const; 130 void setAggregateErrors(ArrayObject* errors); 131 132 // Getter for the AggregateError.prototype.errors accessor. 133 static bool getErrors(JSContext* cx, unsigned argc, Value* vp); 134 static bool getErrors_impl(JSContext* cx, const CallArgs& args); 135 }; 136 137 JSString* ErrorToSource(JSContext* cx, HandleObject obj); 138 139 } // namespace js 140 141 template <> 142 inline bool JSObject::is<js::ErrorObject>() const { 143 return js::ErrorObject::isErrorClass(getClass()); 144 } 145 146 template <> 147 inline bool JSObject::is<js::AggregateErrorObject>() const { 148 return hasClass(js::ErrorObject::classForType(JSEXN_AGGREGATEERR)); 149 } 150 151 #endif // vm_ErrorObject_h_ 152