1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sw=2 et tw=80:
4 * This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
8 #include "vm/ErrorObject-inl.h"
10 #include "mozilla/Assertions.h"
11 #include "mozilla/Attributes.h"
12 #include "mozilla/DebugOnly.h"
13 #include "mozilla/Maybe.h"
19 #include "NamespaceImports.h"
21 #include "gc/AllocKind.h"
22 #include "gc/GCContext.h"
23 #include "js/CallArgs.h"
24 #include "js/CallNonGenericMethod.h"
25 #include "js/CharacterEncoding.h" // JS::ConstUTF8CharsZ
27 #include "js/ColumnNumber.h" // JS::ColumnNumberOneOrigin
28 #include "js/Conversions.h"
29 #include "js/ErrorReport.h"
30 #include "js/friend/ErrorMessages.h" // js::GetErrorMessage, JSMSG_*
31 #include "js/friend/StackLimits.h" // js::AutoCheckRecursionLimit
32 #include "js/PropertySpec.h"
33 #include "js/RootingAPI.h"
35 #include "js/TypeDecls.h"
36 #include "js/Utility.h"
38 #include "js/Wrapper.h"
39 #include "util/StringBuffer.h"
40 #include "vm/GlobalObject.h"
41 #include "vm/Iteration.h"
42 #include "vm/JSAtomUtils.h" // ClassName
43 #include "vm/JSFunction.h"
44 #include "vm/JSObject.h"
45 #include "vm/NativeObject.h"
46 #include "vm/ObjectOperations.h"
47 #include "vm/SavedStacks.h"
48 #include "vm/SelfHosting.h"
51 #include "vm/StringType.h"
52 #include "vm/ToSource.h" // js::ValueToSource
54 #include "vm/JSContext-inl.h"
55 #include "vm/JSObject-inl.h"
56 #include "vm/ObjectOperations-inl.h"
57 #include "vm/SavedStacks-inl.h"
58 #include "vm/Shape-inl.h"
62 #define IMPLEMENT_ERROR_PROTO_CLASS(name) \
64 #name ".prototype", JSCLASS_HAS_CACHED_PROTO(JSProto_##name), \
66 &ErrorObject::classSpecs[JSProto_##name - JSProto_Error] \
69 const JSClass
ErrorObject::protoClasses
[JSEXN_ERROR_LIMIT
] = {
70 IMPLEMENT_ERROR_PROTO_CLASS(Error
),
72 IMPLEMENT_ERROR_PROTO_CLASS(InternalError
),
73 IMPLEMENT_ERROR_PROTO_CLASS(AggregateError
),
74 IMPLEMENT_ERROR_PROTO_CLASS(EvalError
),
75 IMPLEMENT_ERROR_PROTO_CLASS(RangeError
),
76 IMPLEMENT_ERROR_PROTO_CLASS(ReferenceError
),
77 IMPLEMENT_ERROR_PROTO_CLASS(SyntaxError
),
78 IMPLEMENT_ERROR_PROTO_CLASS(TypeError
),
79 IMPLEMENT_ERROR_PROTO_CLASS(URIError
),
81 IMPLEMENT_ERROR_PROTO_CLASS(DebuggeeWouldRun
),
82 IMPLEMENT_ERROR_PROTO_CLASS(CompileError
),
83 IMPLEMENT_ERROR_PROTO_CLASS(LinkError
),
84 IMPLEMENT_ERROR_PROTO_CLASS(RuntimeError
)};
86 static bool exn_toSource(JSContext
* cx
, unsigned argc
, Value
* vp
);
88 static const JSFunctionSpec error_methods
[] = {
89 JS_FN("toSource", exn_toSource
, 0, 0),
90 JS_SELF_HOSTED_FN("toString", "ErrorToString", 0, 0), JS_FS_END
};
92 // Error.prototype and NativeError.prototype have own .message and .name
94 #define COMMON_ERROR_PROPERTIES(name) \
95 JS_STRING_PS("message", "", 0), JS_STRING_PS("name", #name, 0)
97 static const JSPropertySpec error_properties
[] = {
98 COMMON_ERROR_PROPERTIES(Error
),
99 // Only Error.prototype has .stack!
100 JS_PSGS("stack", ErrorObject::getStack
, ErrorObject::setStack
, 0),
103 #define IMPLEMENT_NATIVE_ERROR_PROPERTIES(name) \
104 static const JSPropertySpec name##_properties[] = { \
105 COMMON_ERROR_PROPERTIES(name), JS_PS_END};
107 IMPLEMENT_NATIVE_ERROR_PROPERTIES(InternalError
)
108 IMPLEMENT_NATIVE_ERROR_PROPERTIES(AggregateError
)
109 IMPLEMENT_NATIVE_ERROR_PROPERTIES(EvalError
)
110 IMPLEMENT_NATIVE_ERROR_PROPERTIES(RangeError
)
111 IMPLEMENT_NATIVE_ERROR_PROPERTIES(ReferenceError
)
112 IMPLEMENT_NATIVE_ERROR_PROPERTIES(SyntaxError
)
113 IMPLEMENT_NATIVE_ERROR_PROPERTIES(TypeError
)
114 IMPLEMENT_NATIVE_ERROR_PROPERTIES(URIError
)
115 IMPLEMENT_NATIVE_ERROR_PROPERTIES(DebuggeeWouldRun
)
116 IMPLEMENT_NATIVE_ERROR_PROPERTIES(CompileError
)
117 IMPLEMENT_NATIVE_ERROR_PROPERTIES(LinkError
)
118 IMPLEMENT_NATIVE_ERROR_PROPERTIES(RuntimeError
)
120 #define IMPLEMENT_NATIVE_ERROR_SPEC(name) \
122 ErrorObject::createConstructor, ErrorObject::createProto, nullptr, \
123 nullptr, nullptr, name##_properties, nullptr, JSProto_Error \
126 #define IMPLEMENT_NONGLOBAL_ERROR_SPEC(name) \
128 ErrorObject::createConstructor, ErrorObject::createProto, nullptr, \
129 nullptr, nullptr, name##_properties, nullptr, \
130 JSProto_Error | ClassSpec::DontDefineConstructor \
133 const ClassSpec
ErrorObject::classSpecs
[JSEXN_ERROR_LIMIT
] = {
134 {ErrorObject::createConstructor
, ErrorObject::createProto
, nullptr, nullptr,
135 error_methods
, error_properties
},
137 IMPLEMENT_NATIVE_ERROR_SPEC(InternalError
),
138 IMPLEMENT_NATIVE_ERROR_SPEC(AggregateError
),
139 IMPLEMENT_NATIVE_ERROR_SPEC(EvalError
),
140 IMPLEMENT_NATIVE_ERROR_SPEC(RangeError
),
141 IMPLEMENT_NATIVE_ERROR_SPEC(ReferenceError
),
142 IMPLEMENT_NATIVE_ERROR_SPEC(SyntaxError
),
143 IMPLEMENT_NATIVE_ERROR_SPEC(TypeError
),
144 IMPLEMENT_NATIVE_ERROR_SPEC(URIError
),
146 IMPLEMENT_NONGLOBAL_ERROR_SPEC(DebuggeeWouldRun
),
147 IMPLEMENT_NONGLOBAL_ERROR_SPEC(CompileError
),
148 IMPLEMENT_NONGLOBAL_ERROR_SPEC(LinkError
),
149 IMPLEMENT_NONGLOBAL_ERROR_SPEC(RuntimeError
)};
151 #define IMPLEMENT_ERROR_CLASS_CORE(name, reserved_slots) \
154 JSCLASS_HAS_CACHED_PROTO(JSProto_##name) | \
155 JSCLASS_HAS_RESERVED_SLOTS(reserved_slots) | \
156 JSCLASS_BACKGROUND_FINALIZE, \
157 &ErrorObjectClassOps, \
158 &ErrorObject::classSpecs[JSProto_##name - JSProto_Error] \
161 #define IMPLEMENT_ERROR_CLASS(name) \
162 IMPLEMENT_ERROR_CLASS_CORE(name, ErrorObject::RESERVED_SLOTS)
164 // Only used for classes that could be a Wasm trap. Classes that use this
165 // macro should be kept in sync with the exception types that mightBeWasmTrap()
166 // will return true for.
167 #define IMPLEMENT_ERROR_CLASS_MAYBE_WASM_TRAP(name) \
168 IMPLEMENT_ERROR_CLASS_CORE(name, ErrorObject::RESERVED_SLOTS_MAYBE_WASM_TRAP)
170 static void exn_finalize(JS::GCContext
* gcx
, JSObject
* obj
);
172 static const JSClassOps ErrorObjectClassOps
= {
173 nullptr, // addProperty
174 nullptr, // delProperty
175 nullptr, // enumerate
176 nullptr, // newEnumerate
178 nullptr, // mayResolve
179 exn_finalize
, // finalize
181 nullptr, // construct
185 const JSClass
ErrorObject::classes
[JSEXN_ERROR_LIMIT
] = {
186 IMPLEMENT_ERROR_CLASS(Error
),
187 IMPLEMENT_ERROR_CLASS_MAYBE_WASM_TRAP(InternalError
),
188 IMPLEMENT_ERROR_CLASS(AggregateError
), IMPLEMENT_ERROR_CLASS(EvalError
),
189 IMPLEMENT_ERROR_CLASS(RangeError
), IMPLEMENT_ERROR_CLASS(ReferenceError
),
190 IMPLEMENT_ERROR_CLASS(SyntaxError
), IMPLEMENT_ERROR_CLASS(TypeError
),
191 IMPLEMENT_ERROR_CLASS(URIError
),
192 // These Error subclasses are not accessible via the global object:
193 IMPLEMENT_ERROR_CLASS(DebuggeeWouldRun
),
194 IMPLEMENT_ERROR_CLASS(CompileError
), IMPLEMENT_ERROR_CLASS(LinkError
),
195 IMPLEMENT_ERROR_CLASS_MAYBE_WASM_TRAP(RuntimeError
)};
197 static void exn_finalize(JS::GCContext
* gcx
, JSObject
* obj
) {
198 if (JSErrorReport
* report
= obj
->as
<ErrorObject
>().getErrorReport()) {
199 // Bug 1560019: This allocation is not currently tracked.
200 gcx
->deleteUntracked(report
);
204 static ErrorObject
* CreateErrorObject(JSContext
* cx
, const CallArgs
& args
,
205 unsigned messageArg
, JSExnType exnType
,
206 HandleObject proto
) {
207 // Compute the error message, if any.
208 RootedString
message(cx
, nullptr);
209 if (args
.hasDefined(messageArg
)) {
210 message
= ToString
<CanGC
>(cx
, args
[messageArg
]);
216 // Don't interpret the two parameters following the message parameter as the
217 // non-standard fileName and lineNumber arguments when we have an options
219 bool hasOptions
= args
.get(messageArg
+ 1).isObject();
221 Rooted
<mozilla::Maybe
<Value
>> cause(cx
, mozilla::Nothing());
223 RootedObject
options(cx
, &args
[messageArg
+ 1].toObject());
225 bool hasCause
= false;
226 if (!HasProperty(cx
, options
, cx
->names().cause
, &hasCause
)) {
231 RootedValue
causeValue(cx
);
232 if (!GetProperty(cx
, options
, options
, cx
->names().cause
, &causeValue
)) {
235 cause
= mozilla::Some(causeValue
.get());
239 // Find the scripted caller, but only ones we're allowed to know about.
240 NonBuiltinFrameIter
iter(cx
, cx
->realm()->principals());
242 RootedString
fileName(cx
);
243 uint32_t sourceId
= 0;
244 if (!hasOptions
&& args
.length() > messageArg
+ 1) {
245 fileName
= ToString
<CanGC
>(cx
, args
[messageArg
+ 1]);
247 fileName
= cx
->runtime()->emptyString
;
249 if (const char* cfilename
= iter
.filename()) {
250 fileName
= JS_NewStringCopyUTF8Z(
251 cx
, JS::ConstUTF8CharsZ(cfilename
, strlen(cfilename
)));
253 if (iter
.hasScript()) {
254 sourceId
= iter
.script()->scriptSource()->id();
263 JS::ColumnNumberOneOrigin columnNumber
;
264 if (!hasOptions
&& args
.length() > messageArg
+ 2) {
265 if (!ToUint32(cx
, args
[messageArg
+ 2], &lineNumber
)) {
269 JS::TaggedColumnNumberOneOrigin tmp
;
270 lineNumber
= iter
.done() ? 0 : iter
.computeLine(&tmp
);
271 columnNumber
= JS::ColumnNumberOneOrigin(tmp
.oneOriginValue());
274 RootedObject
stack(cx
);
275 if (!CaptureStack(cx
, &stack
)) {
279 return ErrorObject::create(cx
, exnType
, stack
, fileName
, sourceId
, lineNumber
,
280 columnNumber
, nullptr, message
, cause
, proto
);
283 static bool Error(JSContext
* cx
, unsigned argc
, Value
* vp
) {
284 CallArgs args
= CallArgsFromVp(argc
, vp
);
286 // ECMA ed. 3, 15.11.1 requires Error, etc., to construct even when
287 // called as functions, without operator new. But as we do not give
288 // each constructor a distinct JSClass, we must get the exception type
291 JSExnType(args
.callee().as
<JSFunction
>().getExtendedSlot(0).toInt32());
293 MOZ_ASSERT(exnType
!= JSEXN_AGGREGATEERR
,
294 "AggregateError has its own constructor function");
296 JSProtoKey protoKey
=
297 JSCLASS_CACHED_PROTO_KEY(&ErrorObject::classes
[exnType
]);
299 // ES6 19.5.1.1 mandates the .prototype lookup happens before the toString
300 RootedObject
proto(cx
);
301 if (!GetPrototypeFromBuiltinConstructor(cx
, args
, protoKey
, &proto
)) {
305 auto* obj
= CreateErrorObject(cx
, args
, 0, exnType
, proto
);
310 args
.rval().setObject(*obj
);
314 // AggregateError ( errors, message )
315 static bool AggregateError(JSContext
* cx
, unsigned argc
, Value
* vp
) {
316 CallArgs args
= CallArgsFromVp(argc
, vp
);
318 mozilla::DebugOnly
<JSExnType
> exnType
=
319 JSExnType(args
.callee().as
<JSFunction
>().getExtendedSlot(0).toInt32());
321 MOZ_ASSERT(exnType
== JSEXN_AGGREGATEERR
);
323 // Steps 1-2. (9.1.13 OrdinaryCreateFromConstructor, steps 1-2).
324 RootedObject
proto(cx
);
325 if (!GetPrototypeFromBuiltinConstructor(cx
, args
, JSProto_AggregateError
,
330 // TypeError anyway, but this gives a better error message.
331 if (!args
.requireAtLeast(cx
, "AggregateError", 1)) {
335 // 9.1.13 OrdinaryCreateFromConstructor, step 3.
337 Rooted
<ErrorObject
*> obj(
338 cx
, CreateErrorObject(cx
, args
, 1, JSEXN_AGGREGATEERR
, proto
));
345 Rooted
<ArrayObject
*> errorsList(cx
);
346 if (!IterableToArray(cx
, args
.get(0), &errorsList
)) {
351 RootedValue
errorsVal(cx
, JS::ObjectValue(*errorsList
));
352 if (!NativeDefineDataProperty(cx
, obj
, cx
->names().errors
, errorsVal
, 0)) {
357 args
.rval().setObject(*obj
);
362 JSObject
* ErrorObject::createProto(JSContext
* cx
, JSProtoKey key
) {
363 JSExnType type
= ExnTypeFromProtoKey(key
);
365 if (type
== JSEXN_ERR
) {
366 return GlobalObject::createBlankPrototype(
367 cx
, cx
->global(), &ErrorObject::protoClasses
[JSEXN_ERR
]);
370 RootedObject
protoProto(
371 cx
, GlobalObject::getOrCreateErrorPrototype(cx
, cx
->global()));
376 return GlobalObject::createBlankPrototypeInheriting(
377 cx
, &ErrorObject::protoClasses
[type
], protoProto
);
381 JSObject
* ErrorObject::createConstructor(JSContext
* cx
, JSProtoKey key
) {
382 JSExnType type
= ExnTypeFromProtoKey(key
);
383 RootedObject
ctor(cx
);
385 if (type
== JSEXN_ERR
) {
386 ctor
= GenericCreateConstructor
<Error
, 1, gc::AllocKind::FUNCTION_EXTENDED
>(
389 RootedFunction
proto(
390 cx
, GlobalObject::getOrCreateErrorConstructor(cx
, cx
->global()));
397 if (type
== JSEXN_AGGREGATEERR
) {
398 native
= AggregateError
;
406 NewFunctionWithProto(cx
, native
, nargs
, FunctionFlags::NATIVE_CTOR
,
407 nullptr, ClassName(key
, cx
), proto
,
408 gc::AllocKind::FUNCTION_EXTENDED
, TenuredObject
);
415 ctor
->as
<JSFunction
>().setExtendedSlot(0, Int32Value(type
));
420 SharedShape
* js::ErrorObject::assignInitialShape(JSContext
* cx
,
421 Handle
<ErrorObject
*> obj
) {
422 MOZ_ASSERT(obj
->empty());
424 constexpr PropertyFlags propFlags
= {PropertyFlag::Configurable
,
425 PropertyFlag::Writable
};
427 if (!NativeObject::addPropertyInReservedSlot(cx
, obj
, cx
->names().fileName
,
428 FILENAME_SLOT
, propFlags
)) {
432 if (!NativeObject::addPropertyInReservedSlot(cx
, obj
, cx
->names().lineNumber
,
433 LINENUMBER_SLOT
, propFlags
)) {
437 if (!NativeObject::addPropertyInReservedSlot(
438 cx
, obj
, cx
->names().columnNumber
, COLUMNNUMBER_SLOT
, propFlags
)) {
442 return obj
->sharedShape();
446 bool js::ErrorObject::init(JSContext
* cx
, Handle
<ErrorObject
*> obj
,
447 JSExnType type
, UniquePtr
<JSErrorReport
> errorReport
,
448 HandleString fileName
, HandleObject stack
,
449 uint32_t sourceId
, uint32_t lineNumber
,
450 JS::ColumnNumberOneOrigin columnNumber
,
451 HandleString message
,
452 Handle
<mozilla::Maybe
<JS::Value
>> cause
) {
453 MOZ_ASSERT(JSEXN_ERR
<= type
&& type
< JSEXN_ERROR_LIMIT
);
454 AssertObjectIsSavedFrameOrWrapper(cx
, stack
);
455 cx
->check(obj
, stack
);
457 // Null out early in case of error, for exn_finalize's sake.
458 obj
->initReservedSlot(ERROR_REPORT_SLOT
, PrivateValue(nullptr));
460 if (!SharedShape::ensureInitialCustomShape
<ErrorObject
>(cx
, obj
)) {
464 // The .message property isn't part of the initial shape because it's
465 // present in some error objects -- |Error.prototype|, |new Error("f")|,
466 // |new Error("")| -- but not in others -- |new Error(undefined)|,
469 constexpr PropertyFlags propFlags
= {PropertyFlag::Configurable
,
470 PropertyFlag::Writable
};
471 if (!NativeObject::addPropertyInReservedSlot(cx
, obj
, cx
->names().message
,
472 MESSAGE_SLOT
, propFlags
)) {
477 // Similar to the .message property, .cause is present only in some error
478 // objects -- |new Error("f", {cause: cause})| -- but not in other --
479 // |Error.prototype|, |new Error()|, |new Error("f")|.
480 if (cause
.isSome()) {
481 constexpr PropertyFlags propFlags
= {PropertyFlag::Configurable
,
482 PropertyFlag::Writable
};
483 if (!NativeObject::addPropertyInReservedSlot(cx
, obj
, cx
->names().cause
,
484 CAUSE_SLOT
, propFlags
)) {
489 MOZ_ASSERT(obj
->lookupPure(NameToId(cx
->names().fileName
))->slot() ==
491 MOZ_ASSERT(obj
->lookupPure(NameToId(cx
->names().lineNumber
))->slot() ==
493 MOZ_ASSERT(obj
->lookupPure(NameToId(cx
->names().columnNumber
))->slot() ==
497 obj
->lookupPure(NameToId(cx
->names().message
))->slot() == MESSAGE_SLOT
);
500 obj
->lookupPure(NameToId(cx
->names().cause
))->slot() == CAUSE_SLOT
);
502 JSErrorReport
* report
= errorReport
.release();
503 obj
->initReservedSlot(STACK_SLOT
, ObjectOrNullValue(stack
));
504 obj
->setReservedSlot(ERROR_REPORT_SLOT
, PrivateValue(report
));
505 obj
->initReservedSlot(FILENAME_SLOT
, StringValue(fileName
));
506 obj
->initReservedSlot(LINENUMBER_SLOT
, Int32Value(lineNumber
));
507 obj
->initReservedSlot(COLUMNNUMBER_SLOT
,
508 Int32Value(columnNumber
.oneOriginValue()));
510 obj
->initReservedSlot(MESSAGE_SLOT
, StringValue(message
));
512 if (cause
.isSome()) {
513 obj
->initReservedSlot(CAUSE_SLOT
, *cause
.get());
515 obj
->initReservedSlot(CAUSE_SLOT
, MagicValue(JS_ERROR_WITHOUT_CAUSE
));
517 obj
->initReservedSlot(SOURCEID_SLOT
, Int32Value(sourceId
));
518 if (obj
->mightBeWasmTrap()) {
519 MOZ_ASSERT(JSCLASS_RESERVED_SLOTS(obj
->getClass()) > WASM_TRAP_SLOT
);
520 obj
->initReservedSlot(WASM_TRAP_SLOT
, BooleanValue(false));
527 ErrorObject
* js::ErrorObject::create(JSContext
* cx
, JSExnType errorType
,
528 HandleObject stack
, HandleString fileName
,
529 uint32_t sourceId
, uint32_t lineNumber
,
530 JS::ColumnNumberOneOrigin columnNumber
,
531 UniquePtr
<JSErrorReport
> report
,
532 HandleString message
,
533 Handle
<mozilla::Maybe
<JS::Value
>> cause
,
534 HandleObject protoArg
/* = nullptr */) {
535 AssertObjectIsSavedFrameOrWrapper(cx
, stack
);
537 RootedObject
proto(cx
, protoArg
);
539 proto
= GlobalObject::getOrCreateCustomErrorPrototype(cx
, cx
->global(),
546 Rooted
<ErrorObject
*> errObject(cx
);
548 const JSClass
* clasp
= ErrorObject::classForType(errorType
);
549 JSObject
* obj
= NewObjectWithGivenProto(cx
, clasp
, proto
);
553 errObject
= &obj
->as
<ErrorObject
>();
556 if (!ErrorObject::init(cx
, errObject
, errorType
, std::move(report
), fileName
,
557 stack
, sourceId
, lineNumber
, columnNumber
, message
,
565 JSErrorReport
* js::ErrorObject::getOrCreateErrorReport(JSContext
* cx
) {
566 if (JSErrorReport
* r
= getErrorReport()) {
570 // We build an error report on the stack and then use CopyErrorReport to do
571 // the nitty-gritty malloc stuff.
572 JSErrorReport report
;
575 JSExnType type_
= type();
576 report
.exnType
= type_
;
579 RootedString
filename(cx
, fileName(cx
));
580 UniqueChars filenameStr
= JS_EncodeStringToUTF8(cx
, filename
);
584 report
.filename
= JS::ConstUTF8CharsZ(filenameStr
.get());
587 report
.sourceId
= sourceId();
588 report
.lineno
= lineNumber();
589 report
.column
= columnNumber();
591 // Message. Note that |new Error()| will result in an undefined |message|
592 // slot, so we need to explicitly substitute the empty string in that case.
593 RootedString
message(cx
, getMessage());
595 message
= cx
->runtime()->emptyString
;
598 UniqueChars utf8
= StringToNewUTF8CharsZ(cx
, *message
);
602 report
.initOwnedMessage(utf8
.release());
605 UniquePtr
<JSErrorReport
> copy
= CopyErrorReport(cx
, &report
);
609 setReservedSlot(ERROR_REPORT_SLOT
, PrivateValue(copy
.get()));
610 return copy
.release();
613 static bool FindErrorInstanceOrPrototype(JSContext
* cx
, HandleObject obj
,
614 MutableHandleObject result
) {
615 // Walk up the prototype chain until we find an error object instance or
616 // prototype object. This allows code like:
617 // Object.create(Error.prototype).stack
619 // function NYI() { }
620 // NYI.prototype = new Error;
622 // to continue returning stacks that are useless, but at least don't throw.
624 RootedObject
curr(cx
, obj
);
625 RootedObject
target(cx
);
627 target
= CheckedUnwrapStatic(curr
);
629 ReportAccessDenied(cx
);
632 if (IsErrorProtoKey(StandardProtoKeyOrNull(target
))) {
637 if (!GetPrototype(cx
, curr
, &curr
)) {
642 // We walked the whole prototype chain and did not find an Error
644 JS_ReportErrorNumberASCII(cx
, GetErrorMessage
, nullptr,
645 JSMSG_INCOMPATIBLE_PROTO
, "Error", "(get stack)",
646 obj
->getClass()->name
);
650 static MOZ_ALWAYS_INLINE
bool IsObject(HandleValue v
) { return v
.isObject(); }
653 bool js::ErrorObject::getStack(JSContext
* cx
, unsigned argc
, Value
* vp
) {
654 CallArgs args
= CallArgsFromVp(argc
, vp
);
655 // We accept any object here, because of poor-man's subclassing of Error.
656 return CallNonGenericMethod
<IsObject
, getStack_impl
>(cx
, args
);
660 bool js::ErrorObject::getStack_impl(JSContext
* cx
, const CallArgs
& args
) {
661 RootedObject
thisObj(cx
, &args
.thisv().toObject());
663 RootedObject
obj(cx
);
664 if (!FindErrorInstanceOrPrototype(cx
, thisObj
, &obj
)) {
668 if (!obj
->is
<ErrorObject
>()) {
669 args
.rval().setString(cx
->runtime()->emptyString
);
673 // Do frame filtering based on the ErrorObject's principals. This ensures we
674 // don't see chrome frames when chrome code accesses .stack over Xrays.
675 JSPrincipals
* principals
= obj
->as
<ErrorObject
>().realm()->principals();
677 RootedObject
savedFrameObj(cx
, obj
->as
<ErrorObject
>().stack());
678 RootedString
stackString(cx
);
679 if (!BuildStackString(cx
, principals
, savedFrameObj
, &stackString
)) {
683 if (cx
->runtime()->stackFormat() == js::StackFormat::V8
) {
684 // When emulating V8 stack frames, we also need to prepend the
685 // stringified Error to the stack string.
686 Handle
<PropertyName
*> name
= cx
->names().ErrorToStringWithTrailingNewline
;
687 FixedInvokeArgs
<0> args2(cx
);
688 RootedValue
rval(cx
);
689 if (!CallSelfHostedFunction(cx
, name
, args
.thisv(), args2
, &rval
)) {
693 if (!rval
.isString()) {
694 args
.rval().setString(cx
->runtime()->emptyString
);
698 RootedString
stringified(cx
, rval
.toString());
699 stackString
= ConcatStrings
<CanGC
>(cx
, stringified
, stackString
);
702 args
.rval().setString(stackString
);
707 bool js::ErrorObject::setStack(JSContext
* cx
, unsigned argc
, Value
* vp
) {
708 CallArgs args
= CallArgsFromVp(argc
, vp
);
709 // We accept any object here, because of poor-man's subclassing of Error.
710 return CallNonGenericMethod
<IsObject
, setStack_impl
>(cx
, args
);
714 bool js::ErrorObject::setStack_impl(JSContext
* cx
, const CallArgs
& args
) {
715 RootedObject
thisObj(cx
, &args
.thisv().toObject());
717 if (!args
.requireAtLeast(cx
, "(set stack)", 1)) {
720 RootedValue
val(cx
, args
[0]);
722 return DefineDataProperty(cx
, thisObj
, cx
->names().stack
, val
);
725 void js::ErrorObject::setFromWasmTrap() {
726 MOZ_ASSERT(mightBeWasmTrap());
727 MOZ_ASSERT(JSCLASS_RESERVED_SLOTS(getClass()) > WASM_TRAP_SLOT
);
728 setReservedSlot(WASM_TRAP_SLOT
, BooleanValue(true));
731 JSString
* js::ErrorToSource(JSContext
* cx
, HandleObject obj
) {
732 RootedValue
nameVal(cx
);
733 RootedString
name(cx
);
734 if (!GetProperty(cx
, obj
, obj
, cx
->names().name
, &nameVal
) ||
735 !(name
= ToString
<CanGC
>(cx
, nameVal
))) {
739 RootedValue
messageVal(cx
);
740 RootedString
message(cx
);
741 if (!GetProperty(cx
, obj
, obj
, cx
->names().message
, &messageVal
) ||
742 !(message
= ValueToSource(cx
, messageVal
))) {
746 RootedValue
filenameVal(cx
);
747 RootedString
filename(cx
);
748 if (!GetProperty(cx
, obj
, obj
, cx
->names().fileName
, &filenameVal
) ||
749 !(filename
= ValueToSource(cx
, filenameVal
))) {
753 RootedValue
linenoVal(cx
);
755 if (!GetProperty(cx
, obj
, obj
, cx
->names().lineNumber
, &linenoVal
) ||
756 !ToUint32(cx
, linenoVal
, &lineno
)) {
760 JSStringBuilder
sb(cx
);
761 if (!sb
.append("(new ") || !sb
.append(name
) || !sb
.append("(")) {
765 if (!sb
.append(message
)) {
769 if (!filename
->empty()) {
770 if (!sb
.append(", ") || !sb
.append(filename
)) {
775 /* We have a line, but no filename, add empty string */
776 if (filename
->empty() && !sb
.append(", \"\"")) {
780 JSString
* linenumber
= ToString
<CanGC
>(cx
, linenoVal
);
784 if (!sb
.append(", ") || !sb
.append(linenumber
)) {
789 if (!sb
.append("))")) {
793 return sb
.finishString();
797 * Return a string that may eval to something similar to the original object.
799 static bool exn_toSource(JSContext
* cx
, unsigned argc
, Value
* vp
) {
800 AutoCheckRecursionLimit
recursion(cx
);
801 if (!recursion
.check(cx
)) {
804 CallArgs args
= CallArgsFromVp(argc
, vp
);
806 RootedObject
obj(cx
, ToObject(cx
, args
.thisv()));
811 JSString
* str
= ErrorToSource(cx
, obj
);
816 args
.rval().setString(str
);