mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-07 16:28:38 +09:00
Merge remote-tracking branch 'origin/tracking' into custom
This commit is contained in:
commit
fd45d63241
49 changed files with 816 additions and 347 deletions
|
|
@ -6,6 +6,7 @@
|
|||
#include "TimelineConsumers.h"
|
||||
|
||||
#include "mozilla/ClearOnShutdown.h"
|
||||
#include "jsapi.h"
|
||||
#include "nsAppRunner.h" // for XRE_IsContentProcess, XRE_IsParentProcess
|
||||
#include "nsDocShell.h"
|
||||
|
||||
|
|
@ -125,6 +126,9 @@ TimelineConsumers::AddConsumer(nsDocShell* aDocShell)
|
|||
UniquePtr<ObservedDocShell>& observed = aDocShell->mObserved;
|
||||
MOZ_ASSERT(!observed);
|
||||
|
||||
if (mActiveConsumers == 0) {
|
||||
JS::SetProfileTimelineRecordingEnabled(true);
|
||||
}
|
||||
mActiveConsumers++;
|
||||
|
||||
ObservedDocShell* obsDocShell = new ObservedDocShell(aDocShell);
|
||||
|
|
@ -144,6 +148,9 @@ TimelineConsumers::RemoveConsumer(nsDocShell* aDocShell)
|
|||
MOZ_ASSERT(observed);
|
||||
|
||||
mActiveConsumers--;
|
||||
if (mActiveConsumers == 0) {
|
||||
JS::SetProfileTimelineRecordingEnabled(false);
|
||||
}
|
||||
|
||||
// Clear all markers from the `mTimelineMarkers` store.
|
||||
observed.get()->ClearMarkers();
|
||||
|
|
|
|||
|
|
@ -224,16 +224,23 @@ ProcessNameForCollectorLog()
|
|||
|
||||
namespace xpc {
|
||||
|
||||
// This handles JS Exceptions (via ExceptionStackOrNull), as well as DOM and XPC
|
||||
// Exceptions.
|
||||
// This handles JS Exceptions (via ExceptionStackOrNull), DOM and XPC
|
||||
// Exceptions, and arbitrary values that were associated with a stack by the
|
||||
// JS engine when they were thrown, as specified by exceptionStack.
|
||||
//
|
||||
// Note that the returned object is _not_ wrapped into the compartment of
|
||||
// exceptionValue.
|
||||
JSObject*
|
||||
FindExceptionStackForConsoleReport(nsPIDOMWindowInner* win,
|
||||
JS::HandleValue exceptionValue)
|
||||
JS::HandleValue exceptionValue,
|
||||
JS::HandleObject exceptionStack)
|
||||
{
|
||||
if (!exceptionValue.isObject()) {
|
||||
// Use the stack provided by the JS engine, if available. This will not be
|
||||
// a wrapper.
|
||||
if (exceptionStack) {
|
||||
return exceptionStack;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
|
@ -257,6 +264,10 @@ FindExceptionStackForConsoleReport(nsPIDOMWindowInner* win,
|
|||
// Not a DOM Exception, try XPC Exception.
|
||||
UNWRAP_OBJECT(Exception, exceptionObject, exception);
|
||||
if (!exception) {
|
||||
// As above, use the stack provided by the JS engine, if available.
|
||||
if (exceptionStack) {
|
||||
return exceptionStack;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
|
@ -421,10 +432,12 @@ public:
|
|||
ScriptErrorEvent(nsPIDOMWindowInner* aWindow,
|
||||
JS::RootingContext* aRootingCx,
|
||||
xpc::ErrorReport* aReport,
|
||||
JS::Handle<JS::Value> aError)
|
||||
JS::Handle<JS::Value> aError,
|
||||
JS::Handle<JSObject*> aErrorStack)
|
||||
: mWindow(aWindow)
|
||||
, mReport(aReport)
|
||||
, mError(aRootingCx, aError)
|
||||
, mErrorStack(aRootingCx, aErrorStack)
|
||||
{}
|
||||
|
||||
NS_IMETHOD Run() override
|
||||
|
|
@ -471,7 +484,7 @@ public:
|
|||
|
||||
if (status != nsEventStatus_eConsumeNoDefault) {
|
||||
JS::Rooted<JSObject*> stack(rootingCx,
|
||||
xpc::FindExceptionStackForConsoleReport(win, mError));
|
||||
xpc::FindExceptionStackForConsoleReport(win, mError, mErrorStack));
|
||||
mReport->LogToConsoleWithStack(stack);
|
||||
}
|
||||
|
||||
|
|
@ -481,7 +494,8 @@ public:
|
|||
private:
|
||||
nsCOMPtr<nsPIDOMWindowInner> mWindow;
|
||||
RefPtr<xpc::ErrorReport> mReport;
|
||||
JS::PersistentRootedValue mError;
|
||||
JS::PersistentRootedValue mError;
|
||||
JS::PersistentRootedObject mErrorStack;
|
||||
|
||||
static bool sHandlingScriptError;
|
||||
};
|
||||
|
|
@ -494,9 +508,10 @@ namespace xpc {
|
|||
|
||||
void
|
||||
DispatchScriptErrorEvent(nsPIDOMWindowInner *win, JS::RootingContext* rootingCx,
|
||||
xpc::ErrorReport *xpcReport, JS::Handle<JS::Value> exception)
|
||||
xpc::ErrorReport *xpcReport, JS::Handle<JS::Value> exception,
|
||||
JS::Handle<JSObject*> exceptionStack)
|
||||
{
|
||||
nsContentUtils::AddScriptRunner(new ScriptErrorEvent(win, rootingCx, xpcReport, exception));
|
||||
nsContentUtils::AddScriptRunner(new ScriptErrorEvent(win, rootingCx, xpcReport, exception, exceptionStack));
|
||||
}
|
||||
|
||||
} /* namespace xpc */
|
||||
|
|
|
|||
|
|
@ -577,8 +577,9 @@ AutoJSAPI::ReportException()
|
|||
}
|
||||
JSAutoCompartment ac(cx(), errorGlobal);
|
||||
JS::Rooted<JS::Value> exn(cx());
|
||||
JS::Rooted<JSObject*> exnStack(cx());
|
||||
js::ErrorReport jsReport(cx());
|
||||
if (StealException(&exn) &&
|
||||
if (StealExceptionAndStack(&exn, &exnStack) &&
|
||||
jsReport.init(cx(), exn, js::ErrorReport::WithSideEffects)) {
|
||||
if (mIsMainThread) {
|
||||
RefPtr<xpc::ErrorReport> xpcReport = new xpc::ErrorReport();
|
||||
|
|
@ -595,10 +596,10 @@ AutoJSAPI::ReportException()
|
|||
inner ? inner->WindowID() : 0);
|
||||
if (inner && jsReport.report()->errorNumber != JSMSG_OUT_OF_MEMORY) {
|
||||
JS::RootingContext* rcx = JS::RootingContext::get(cx());
|
||||
DispatchScriptErrorEvent(inner, rcx, xpcReport, exn);
|
||||
DispatchScriptErrorEvent(inner, rcx, xpcReport, exn, exnStack);
|
||||
} else {
|
||||
JS::Rooted<JSObject*> stack(cx(),
|
||||
xpc::FindExceptionStackForConsoleReport(inner, exn));
|
||||
xpc::FindExceptionStackForConsoleReport(inner, exn, exnStack));
|
||||
xpcReport->LogToConsoleWithStack(stack);
|
||||
}
|
||||
} else {
|
||||
|
|
@ -638,9 +639,16 @@ AutoJSAPI::PeekException(JS::MutableHandle<JS::Value> aVal)
|
|||
bool
|
||||
AutoJSAPI::StealException(JS::MutableHandle<JS::Value> aVal)
|
||||
{
|
||||
JS::Rooted<JSObject*> stack(cx());
|
||||
return StealExceptionAndStack(aVal, &stack);
|
||||
}
|
||||
|
||||
bool AutoJSAPI::StealExceptionAndStack(JS::MutableHandle<JS::Value> aVal,
|
||||
JS::MutableHandle<JSObject*> aStack) {
|
||||
if (!PeekException(aVal)) {
|
||||
return false;
|
||||
}
|
||||
aStack.set(JS::GetPendingExceptionStack(cx()));
|
||||
JS_ClearPendingException(cx());
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -274,6 +274,12 @@ public:
|
|||
// into the current compartment.
|
||||
MOZ_MUST_USE bool StealException(JS::MutableHandle<JS::Value> aVal);
|
||||
|
||||
// As for StealException(), but put the saved frames for any stack trace
|
||||
// associated with the point the exception was thrown into aStack.
|
||||
// aVal will be in the current compartment, but aStack might not be.
|
||||
MOZ_MUST_USE bool StealExceptionAndStack(JS::MutableHandle<JS::Value> aVal,
|
||||
JS::MutableHandle<JSObject*> aStack);
|
||||
|
||||
// Peek the current exception from the JS engine, without stealing it.
|
||||
// Callers must ensure that HasException() is true, and that cx() is in a
|
||||
// non-null compartment.
|
||||
|
|
|
|||
|
|
@ -2479,7 +2479,18 @@ PromiseObject::unforgeableResolve(JSContext* cx, HandleValue value)
|
|||
return CommonStaticResolveRejectImpl(cx, cVal, value, ResolveMode);
|
||||
}
|
||||
|
||||
// ES2016, 25.4.4.6, implemented in Promise.js.
|
||||
/**
|
||||
* ES2016, 25.4.4.6 get Promise [ @@species ]
|
||||
*/
|
||||
static bool
|
||||
Promise_static_species(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
// Step 1: Return the this value.
|
||||
args.rval().set(args.thisv());
|
||||
return true;
|
||||
}
|
||||
|
||||
// ES2016, 25.4.5.1, implemented in Promise.js.
|
||||
|
||||
|
|
@ -2520,6 +2531,12 @@ NewReactionRecord(JSContext* cx, HandleObject resultPromise, HandleValue onFulfi
|
|||
return reaction;
|
||||
}
|
||||
|
||||
static bool
|
||||
IsPromiseSpecies(JSContext* cx, JSFunction* species)
|
||||
{
|
||||
return species->maybeNative() == Promise_static_species;
|
||||
}
|
||||
|
||||
// ES2016, 25.4.5.3., steps 3-5.
|
||||
MOZ_MUST_USE bool
|
||||
js::OriginalPromiseThen(JSContext* cx, Handle<PromiseObject*> promise,
|
||||
|
|
@ -2538,10 +2555,9 @@ js::OriginalPromiseThen(JSContext* cx, Handle<PromiseObject*> promise,
|
|||
|
||||
if (createDependent) {
|
||||
// Step 3.
|
||||
RootedValue ctorVal(cx);
|
||||
if (!SpeciesConstructor(cx, promiseObj, JSProto_Promise, &ctorVal))
|
||||
RootedObject C(cx, SpeciesConstructor(cx, promiseObj, JSProto_Promise, IsPromiseSpecies));
|
||||
if (!C)
|
||||
return false;
|
||||
RootedObject C(cx, &ctorVal.toObject());
|
||||
|
||||
// Step 4.
|
||||
if (!NewPromiseCapability(cx, C, &resultPromise, &resolve, &reject, true))
|
||||
|
|
@ -2577,6 +2593,13 @@ js::CreatePromiseObjectForAsync(JSContext* cx, HandleValue generatorVal)
|
|||
return promise;
|
||||
}
|
||||
|
||||
bool
|
||||
js::IsPromiseForAsync(JSObject* promise)
|
||||
{
|
||||
return promise->is<PromiseObject>() &&
|
||||
PromiseHasAnyFlag(promise->as<PromiseObject>(), PROMISE_FLAG_ASYNC);
|
||||
}
|
||||
|
||||
// ES 2018 draft 25.5.5.2 steps 3.f, 3.g.
|
||||
MOZ_MUST_USE bool
|
||||
js::AsyncFunctionThrown(JSContext* cx, Handle<PromiseObject*> resultPromise)
|
||||
|
|
@ -2838,6 +2861,8 @@ js::AsyncGeneratorResolve(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenO
|
|||
// Step 5.
|
||||
RootedObject resultPromise(cx, request->promise());
|
||||
|
||||
asyncGenObj->cacheRequest(request);
|
||||
|
||||
// Step 6.
|
||||
RootedObject resultObj(cx, CreateIterResultObject(cx, value, done));
|
||||
if (!resultObj)
|
||||
|
|
@ -2876,6 +2901,8 @@ js::AsyncGeneratorReject(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenOb
|
|||
// Step 5.
|
||||
RootedObject resultPromise(cx, request->promise());
|
||||
|
||||
asyncGenObj->cacheRequest(request);
|
||||
|
||||
// Step 6.
|
||||
if (!RejectMaybeWrappedPromise(cx, resultPromise, exception))
|
||||
return false;
|
||||
|
|
@ -3013,7 +3040,8 @@ js::AsyncGeneratorEnqueue(JSContext* cx, HandleValue asyncGenVal,
|
|||
|
||||
// Step 5 (reordered).
|
||||
Rooted<AsyncGeneratorRequest*> request(
|
||||
cx, AsyncGeneratorRequest::create(cx, completionKind, completionValue, resultPromise));
|
||||
cx, AsyncGeneratorObject::createRequest(cx, asyncGenObj, completionKind, completionValue,
|
||||
resultPromise));
|
||||
if (!request)
|
||||
return false;
|
||||
|
||||
|
|
@ -3186,11 +3214,10 @@ BlockOnPromise(JSContext* cx, HandleValue promiseVal, HandleObject blockedPromis
|
|||
RootedObject PromiseCtor(cx);
|
||||
if (!GetBuiltinConstructor(cx, JSProto_Promise, &PromiseCtor))
|
||||
return false;
|
||||
RootedValue PromiseCtorVal(cx, ObjectValue(*PromiseCtor));
|
||||
RootedValue CVal(cx);
|
||||
if (!SpeciesConstructor(cx, promiseObj, PromiseCtorVal, &CVal))
|
||||
|
||||
RootedObject C(cx, SpeciesConstructor(cx, PromiseCtor, JSProto_Promise, IsPromiseSpecies));
|
||||
if (!C)
|
||||
return false;
|
||||
RootedObject C(cx, &CVal.toObject());
|
||||
|
||||
RootedObject resultPromise(cx, blockedPromise_);
|
||||
RootedObject resolveFun(cx);
|
||||
|
|
@ -3572,7 +3599,7 @@ static const JSFunctionSpec promise_static_methods[] = {
|
|||
};
|
||||
|
||||
static const JSPropertySpec promise_static_properties[] = {
|
||||
JS_SELF_HOSTED_SYM_GET(species, "Promise_static_get_species", 0),
|
||||
JS_SYM_GET(species, Promise_static_species, 0),
|
||||
JS_PS_END
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -141,6 +141,9 @@ PromiseResolve(JSContext* cx, HandleObject constructor, HandleValue value);
|
|||
MOZ_MUST_USE PromiseObject*
|
||||
CreatePromiseObjectForAsync(JSContext* cx, HandleValue generatorVal);
|
||||
|
||||
MOZ_MUST_USE bool
|
||||
IsPromiseForAsync(JSObject* promise);
|
||||
|
||||
MOZ_MUST_USE bool
|
||||
AsyncFunctionReturned(JSContext* cx, Handle<PromiseObject*> resultPromise, HandleValue value);
|
||||
|
||||
|
|
|
|||
|
|
@ -2,13 +2,6 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// ES6, 25.4.4.6.
|
||||
function Promise_static_get_species() {
|
||||
// Step 1.
|
||||
return this;
|
||||
}
|
||||
_SetCanonicalName(Promise_static_get_species, "get [Symbol.species]");
|
||||
|
||||
// ES6, 25.4.5.1.
|
||||
function Promise_catch(onRejected) {
|
||||
// Steps 1-2.
|
||||
|
|
|
|||
|
|
@ -1398,6 +1398,11 @@ ResolvePromise(JSContext* cx, unsigned argc, Value* vp)
|
|||
return false;
|
||||
}
|
||||
|
||||
if (IsPromiseForAsync(promise)) {
|
||||
JS_ReportErrorASCII(cx, "async function's promise shouldn't be manually resolved");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool result = JS::ResolvePromise(cx, promise, resolution);
|
||||
if (result)
|
||||
args.rval().setUndefined();
|
||||
|
|
@ -1425,6 +1430,11 @@ RejectPromise(JSContext* cx, unsigned argc, Value* vp)
|
|||
return false;
|
||||
}
|
||||
|
||||
if (IsPromiseForAsync(promise)) {
|
||||
JS_ReportErrorASCII(cx, "async function's promise shouldn't be manually rejected");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool result = JS::RejectPromise(cx, promise, reason);
|
||||
if (result)
|
||||
args.rval().setUndefined();
|
||||
|
|
|
|||
|
|
@ -550,7 +550,7 @@ bool IsSupportedBinaryProperty(UProperty property) {
|
|||
case UCHAR_EMOJI_MODIFIER_BASE:
|
||||
case UCHAR_EMOJI_MODIFIER:
|
||||
case UCHAR_EMOJI_PRESENTATION:
|
||||
// case UCHAR_EXTENDED_PICTOGRAPHIC:
|
||||
case UCHAR_EXTENDED_PICTOGRAPHIC:
|
||||
case UCHAR_EXTENDER:
|
||||
case UCHAR_GRAPHEME_BASE:
|
||||
case UCHAR_GRAPHEME_EXTEND:
|
||||
|
|
|
|||
|
|
@ -4557,20 +4557,20 @@ BaselineCompiler::emit_JSOP_RESUME()
|
|||
Register initLength = regs.takeAny();
|
||||
masm.loadPtr(Address(scratch2, NativeObject::offsetOfElements()), scratch2);
|
||||
masm.load32(Address(scratch2, ObjectElements::offsetOfInitializedLength()), initLength);
|
||||
masm.store32(Imm32(0), Address(scratch2, ObjectElements::offsetOfInitializedLength()));
|
||||
|
||||
Label loop, loopDone;
|
||||
masm.bind(&loop);
|
||||
masm.branchTest32(Assembler::Zero, initLength, initLength, &loopDone);
|
||||
{
|
||||
masm.pushValue(Address(scratch2, 0));
|
||||
masm.patchableCallPreBarrier(exprStackSlot, MIRType::Value);
|
||||
masm.addPtr(Imm32(sizeof(Value)), scratch2);
|
||||
masm.sub32(Imm32(1), initLength);
|
||||
masm.jump(&loop);
|
||||
}
|
||||
masm.bind(&loopDone);
|
||||
|
||||
masm.patchableCallPreBarrier(exprStackSlot, MIRType::Value);
|
||||
masm.storeValue(NullValue(), exprStackSlot);
|
||||
regs.add(initLength);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -941,7 +941,7 @@ HandleDebugTrap(JSContext* cx, BaselineFrame* frame, uint8_t* retAddr, bool* mus
|
|||
return jit::DebugEpilogue(cx, frame, pc, true);
|
||||
|
||||
case JSTRAP_THROW:
|
||||
cx->setPendingException(rval);
|
||||
cx->setPendingExceptionAndCaptureStack(rval);
|
||||
return false;
|
||||
|
||||
default:
|
||||
|
|
|
|||
|
|
@ -984,8 +984,8 @@ LookupStdName(const JSAtomState& names, JSAtom* name, const JSStdName* table)
|
|||
* JSProtoKey does not correspond to a class with a meaningful constructor, we
|
||||
* insert a null entry into the table.
|
||||
*/
|
||||
#define STD_NAME_ENTRY(name, code, init, clasp) { EAGER_ATOM(name), static_cast<JSProtoKey>(code) },
|
||||
#define STD_DUMMY_ENTRY(name, code, init, dummy) { 0, JSProto_Null },
|
||||
#define STD_NAME_ENTRY(name, init, clasp) { EAGER_ATOM(name), JSProto_##name },
|
||||
#define STD_DUMMY_ENTRY(name, init, dummy) { 0, JSProto_Null },
|
||||
static const JSStdName standard_class_names[] = {
|
||||
JS_FOR_PROTOTYPES(STD_NAME_ENTRY, STD_DUMMY_ENTRY)
|
||||
{ 0, JSProto_LIMIT }
|
||||
|
|
@ -1276,6 +1276,20 @@ JS::detail::ComputeThis(JSContext* cx, Value* vp)
|
|||
return thisv;
|
||||
}
|
||||
|
||||
static bool gProfileTimelineRecordingEnabled = false;
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS::SetProfileTimelineRecordingEnabled(bool enabled)
|
||||
{
|
||||
gProfileTimelineRecordingEnabled = enabled;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS::IsProfileTimelineRecordingEnabled()
|
||||
{
|
||||
return gProfileTimelineRecordingEnabled;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void*)
|
||||
JS_malloc(JSContext* cx, size_t nbytes)
|
||||
{
|
||||
|
|
@ -6205,12 +6219,16 @@ JS_GetPendingException(JSContext* cx, MutableHandleValue vp)
|
|||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS_SetPendingException(JSContext* cx, HandleValue value)
|
||||
JS_SetPendingException(JSContext* cx, HandleValue value, JS::ExceptionStackBehavior behavior)
|
||||
{
|
||||
AssertHeapIsIdle(cx);
|
||||
CHECK_REQUEST(cx);
|
||||
releaseAssertSameCompartment(cx, value);
|
||||
cx->setPendingException(value);
|
||||
if (behavior == JS::ExceptionStackBehavior::Capture) {
|
||||
cx->setPendingExceptionAndCaptureStack(value);
|
||||
} else {
|
||||
cx->setPendingException(value, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
|
|
@ -6220,12 +6238,20 @@ JS_ClearPendingException(JSContext* cx)
|
|||
cx->clearPendingException();
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSObject*)
|
||||
JS::GetPendingExceptionStack(JSContext* cx)
|
||||
{
|
||||
AssertHeapIsIdle(cx);
|
||||
return cx->getPendingExceptionStack();
|
||||
}
|
||||
|
||||
JS::AutoSaveExceptionState::AutoSaveExceptionState(JSContext* cx)
|
||||
: context(cx),
|
||||
wasPropagatingForcedReturn(cx->propagatingForcedReturn_),
|
||||
wasOverRecursed(cx->overRecursed_),
|
||||
wasThrowing(cx->throwing),
|
||||
exceptionValue(cx)
|
||||
exceptionValue(cx),
|
||||
exceptionStack(cx)
|
||||
{
|
||||
AssertHeapIsIdle(cx);
|
||||
CHECK_REQUEST(cx);
|
||||
|
|
@ -6235,10 +6261,21 @@ JS::AutoSaveExceptionState::AutoSaveExceptionState(JSContext* cx)
|
|||
cx->overRecursed_ = false;
|
||||
if (wasThrowing) {
|
||||
exceptionValue = cx->unwrappedException_;
|
||||
exceptionStack = cx->unwrappedExceptionStack_;
|
||||
cx->clearPendingException();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
JS::AutoSaveExceptionState::drop()
|
||||
{
|
||||
wasPropagatingForcedReturn = false;
|
||||
wasOverRecursed = false;
|
||||
wasThrowing = false;
|
||||
exceptionValue.setUndefined();
|
||||
exceptionStack = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
JS::AutoSaveExceptionState::restore()
|
||||
{
|
||||
|
|
@ -6246,6 +6283,9 @@ JS::AutoSaveExceptionState::restore()
|
|||
context->overRecursed_ = wasOverRecursed;
|
||||
context->throwing = wasThrowing;
|
||||
context->unwrappedException_ = exceptionValue;
|
||||
if (exceptionStack) {
|
||||
context->unwrappedExceptionStack_ = &exceptionStack->as<SavedFrame>();
|
||||
}
|
||||
drop();
|
||||
}
|
||||
|
||||
|
|
@ -6258,6 +6298,9 @@ JS::AutoSaveExceptionState::~AutoSaveExceptionState()
|
|||
context->overRecursed_ = wasOverRecursed;
|
||||
context->throwing = true;
|
||||
context->unwrappedException_ = exceptionValue;
|
||||
if (exceptionStack) {
|
||||
context->unwrappedExceptionStack_ = &exceptionStack->as<SavedFrame>();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1545,6 +1545,22 @@ JS_DefineProfilingFunctions(JSContext* cx, JS::HandleObject obj);
|
|||
extern JS_PUBLIC_API(bool)
|
||||
JS_DefineDebuggerObject(JSContext* cx, JS::HandleObject obj);
|
||||
|
||||
namespace JS {
|
||||
|
||||
/**
|
||||
* Tell JS engine whether Profile Timeline Recording is enabled or not.
|
||||
* If Profile Timeline Recording is enabled, data shown there like stack won't
|
||||
* be optimized out.
|
||||
* This is global state and not associated with specific runtime or context.
|
||||
*/
|
||||
extern JS_PUBLIC_API(void)
|
||||
SetProfileTimelineRecordingEnabled(bool enabled);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
IsProfileTimelineRecordingEnabled();
|
||||
|
||||
} // namespace JS
|
||||
|
||||
#ifdef JS_HAS_CTYPES
|
||||
/**
|
||||
* Initialize the 'ctypes' object on a global variable 'obj'. The 'ctypes'
|
||||
|
|
@ -2054,6 +2070,9 @@ inline int CheckIsSetterOp(JSSetterOp op);
|
|||
#define JS_PSGS(name, getter, setter, flags) \
|
||||
JS_PS_ACCESSOR_SPEC(name, JSNATIVE_WRAPPER(getter), JSNATIVE_WRAPPER(setter), flags, \
|
||||
JSPROP_SHARED)
|
||||
#define JS_SYM_GET(symbol, getter, flags) \
|
||||
JS_PS_ACCESSOR_SPEC(reinterpret_cast<const char*>(uint32_t(::JS::SymbolCode::symbol) + 1), \
|
||||
JSNATIVE_WRAPPER(getter), JSNATIVE_WRAPPER(nullptr), flags, JSPROP_SHARED)
|
||||
#define JS_SELF_HOSTED_GET(name, getterName, flags) \
|
||||
JS_PS_ACCESSOR_SPEC(name, SELFHOSTED_WRAPPER(getterName), JSNATIVE_WRAPPER(nullptr), flags, \
|
||||
JSPROP_SHARED | JSPROP_GETTER)
|
||||
|
|
@ -5746,8 +5765,22 @@ JS_IsExceptionPending(JSContext* cx);
|
|||
extern JS_PUBLIC_API(bool)
|
||||
JS_GetPendingException(JSContext* cx, JS::MutableHandleValue vp);
|
||||
|
||||
namespace JS {
|
||||
|
||||
enum class ExceptionStackBehavior: bool {
|
||||
// Do not capture any stack.
|
||||
DoNotCapture,
|
||||
|
||||
// Capture the current JS stack when setting the exception. It may be
|
||||
// retrieved by JS::GetPendingExceptionStack.
|
||||
Capture
|
||||
};
|
||||
|
||||
} // namespace JS
|
||||
|
||||
extern JS_PUBLIC_API(void)
|
||||
JS_SetPendingException(JSContext* cx, JS::HandleValue v);
|
||||
JS_SetPendingException(JSContext* cx, JS::HandleValue v,
|
||||
JS::ExceptionStackBehavior behavior = JS::ExceptionStackBehavior::Capture);
|
||||
|
||||
extern JS_PUBLIC_API(void)
|
||||
JS_ClearPendingException(JSContext* cx);
|
||||
|
|
@ -5774,6 +5807,7 @@ class JS_PUBLIC_API(AutoSaveExceptionState)
|
|||
bool wasOverRecursed;
|
||||
bool wasThrowing;
|
||||
RootedValue exceptionValue;
|
||||
RootedObject exceptionStack;
|
||||
|
||||
public:
|
||||
/*
|
||||
|
|
@ -5792,12 +5826,7 @@ class JS_PUBLIC_API(AutoSaveExceptionState)
|
|||
* Discard any stored exception state.
|
||||
* If this is called, the destructor is a no-op.
|
||||
*/
|
||||
void drop() {
|
||||
wasPropagatingForcedReturn = false;
|
||||
wasOverRecursed = false;
|
||||
wasThrowing = false;
|
||||
exceptionValue.setUndefined();
|
||||
}
|
||||
void drop();
|
||||
|
||||
/*
|
||||
* Replace cx's exception state with the stored exception state. Then
|
||||
|
|
@ -5807,6 +5836,18 @@ class JS_PUBLIC_API(AutoSaveExceptionState)
|
|||
void restore();
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the SavedFrame stack object captured when the pending exception was set
|
||||
* on the JSContext. This fuzzily correlates with a `throw` statement in JS,
|
||||
* although arbitrary JSAPI consumers or VM code may also set pending exceptions
|
||||
* via `JS_SetPendingException`.
|
||||
*
|
||||
* This is not the same stack as `e.stack` when `e` is an `Error` object. (That
|
||||
* would be JS::ExceptionStackOrNull).
|
||||
*/
|
||||
MOZ_MUST_USE JS_PUBLIC_API(JSObject*)
|
||||
GetPendingExceptionStack(JSContext* cx);
|
||||
|
||||
} /* namespace JS */
|
||||
|
||||
/* Deprecated API. Use AutoSaveExceptionState instead. */
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ js::AtomToPrintableString(ExclusiveContext* cx, JSAtom* atom, JSAutoByteString*
|
|||
return bytes->encodeLatin1(cx, str);
|
||||
}
|
||||
|
||||
#define DEFINE_PROTO_STRING(name,code,init,clasp) const char js_##name##_str[] = #name;
|
||||
#define DEFINE_PROTO_STRING(name,init,clasp) const char js_##name##_str[] = #name;
|
||||
JS_FOR_EACH_PROTOTYPE(DEFINE_PROTO_STRING)
|
||||
#undef DEFINE_PROTO_STRING
|
||||
|
||||
|
|
@ -98,7 +98,7 @@ JSRuntime::initializeAtoms(JSContext* cx)
|
|||
#define COMMON_NAME_INFO(idpart, id, text) { js_##idpart##_str, sizeof(text) - 1 },
|
||||
FOR_EACH_COMMON_PROPERTYNAME(COMMON_NAME_INFO)
|
||||
#undef COMMON_NAME_INFO
|
||||
#define COMMON_NAME_INFO(name, code, init, clasp) { js_##name##_str, sizeof(#name) - 1 },
|
||||
#define COMMON_NAME_INFO(name, init, clasp) { js_##name##_str, sizeof(#name) - 1 },
|
||||
JS_FOR_EACH_PROTOTYPE(COMMON_NAME_INFO)
|
||||
#undef COMMON_NAME_INFO
|
||||
#define COMMON_NAME_INFO(name) { #name, sizeof(#name) - 1 },
|
||||
|
|
|
|||
|
|
@ -132,7 +132,7 @@ extern bool
|
|||
AtomIsPinned(JSContext* cx, JSAtom* atom);
|
||||
|
||||
/* Well-known predefined C strings. */
|
||||
#define DECLARE_PROTO_STR(name,code,init,clasp) extern const char js_##name##_str[];
|
||||
#define DECLARE_PROTO_STR(name,init,clasp) extern const char js_##name##_str[];
|
||||
JS_FOR_EACH_PROTOTYPE(DECLARE_PROTO_STR)
|
||||
#undef DECLARE_PROTO_STR
|
||||
|
||||
|
|
|
|||
|
|
@ -241,7 +241,8 @@ js::ReportOutOfMemory(ExclusiveContext* cxArg)
|
|||
if (JS::OutOfMemoryCallback oomCallback = cx->runtime()->oomCallback)
|
||||
oomCallback(cx, cx->runtime()->oomCallbackData);
|
||||
|
||||
cx->setPendingException(StringValue(cx->names().outOfMemory));
|
||||
RootedValue oomMessage(cx, StringValue(cx->names().outOfMemory));
|
||||
cx->setPendingException(oomMessage, nullptr);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -1013,6 +1014,7 @@ JSContext::JSContext(JSRuntime* parentRuntime)
|
|||
JSRuntime(parentRuntime),
|
||||
throwing(false),
|
||||
unwrappedException_(this),
|
||||
unwrappedExceptionStack_(this),
|
||||
overRecursed_(false),
|
||||
propagatingForcedReturn_(false),
|
||||
liveVolatileJitFrameIterators_(nullptr),
|
||||
|
|
@ -1038,6 +1040,24 @@ JSContext::~JSContext()
|
|||
MOZ_ASSERT(!resolvingList);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
JSContext::setPendingExceptionAndCaptureStack(HandleValue value)
|
||||
{
|
||||
static const size_t MAX_REPORTED_STACK_DEPTH = 1u << 7;
|
||||
|
||||
RootedObject stack(this);
|
||||
if (!CaptureCurrentStack(this, &stack, JS::StackCapture(JS::MaxFrames(MAX_REPORTED_STACK_DEPTH)))) {
|
||||
clearPendingException();
|
||||
}
|
||||
|
||||
RootedSavedFrame nstack(this);
|
||||
if (stack) {
|
||||
nstack = &stack->as<SavedFrame>();
|
||||
}
|
||||
setPendingException(value, nstack);
|
||||
}
|
||||
|
||||
bool
|
||||
JSContext::getPendingException(MutableHandleValue rval)
|
||||
{
|
||||
|
|
@ -1045,16 +1065,23 @@ JSContext::getPendingException(MutableHandleValue rval)
|
|||
rval.set(unwrappedException_);
|
||||
if (IsAtomsCompartment(compartment()))
|
||||
return true;
|
||||
RootedSavedFrame stack(this, unwrappedExceptionStack_);
|
||||
bool wasOverRecursed = overRecursed_;
|
||||
clearPendingException();
|
||||
if (!compartment()->wrap(this, rval))
|
||||
return false;
|
||||
assertSameCompartment(this, rval);
|
||||
setPendingException(rval);
|
||||
setPendingException(rval, stack);
|
||||
overRecursed_ = wasOverRecursed;
|
||||
return true;
|
||||
}
|
||||
|
||||
SavedFrame*
|
||||
JSContext::getPendingExceptionStack()
|
||||
{
|
||||
return unwrappedExceptionStack_;
|
||||
}
|
||||
|
||||
bool
|
||||
JSContext::isThrowingOutOfMemory()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -369,6 +369,7 @@ struct JSContext : public js::ExclusiveContext,
|
|||
/* Exception state -- the exception member is a GC root by definition. */
|
||||
bool throwing; /* is there a pending exception? */
|
||||
JS::PersistentRooted<JS::Value> unwrappedException_; /* most-recently-thrown exception */
|
||||
JS::PersistentRooted<js::SavedFrame*> unwrappedExceptionStack_; /* stack when the exception was thrown */
|
||||
|
||||
// True if the exception currently being thrown is by result of
|
||||
// ReportOverRecursed. See Debugger::slowPathOnExceptionUnwind.
|
||||
|
|
@ -495,17 +496,21 @@ struct JSContext : public js::ExclusiveContext,
|
|||
|
||||
MOZ_MUST_USE
|
||||
bool getPendingException(JS::MutableHandleValue rval);
|
||||
|
||||
js::SavedFrame* getPendingExceptionStack();
|
||||
|
||||
bool isThrowingOutOfMemory();
|
||||
bool isThrowingDebuggeeWouldRun();
|
||||
bool isClosingGenerator();
|
||||
|
||||
void setPendingException(const js::Value& v);
|
||||
void setPendingException(JS::HandleValue v, js::HandleSavedFrame stack);
|
||||
void setPendingExceptionAndCaptureStack(JS::HandleValue v);
|
||||
|
||||
void clearPendingException() {
|
||||
throwing = false;
|
||||
overRecursed_ = false;
|
||||
unwrappedException_.setUndefined();
|
||||
unwrappedExceptionStack_ = nullptr;
|
||||
}
|
||||
|
||||
bool isThrowingOverRecursed() const { return throwing && overRecursed_; }
|
||||
|
|
|
|||
|
|
@ -368,12 +368,13 @@ ExclusiveContext::typeLifoAlloc()
|
|||
} /* namespace js */
|
||||
|
||||
inline void
|
||||
JSContext::setPendingException(const js::Value& v)
|
||||
JSContext::setPendingException(JS::HandleValue v, js::HandleSavedFrame stack)
|
||||
{
|
||||
// overRecursed_ is set after the fact by ReportOverRecursed.
|
||||
this->overRecursed_ = false;
|
||||
this->throwing = true;
|
||||
this->unwrappedException_ = v;
|
||||
this->unwrappedExceptionStack_ = stack;
|
||||
// We don't use assertSameCompartment here to allow
|
||||
// js::SetPendingExceptionCrossContext to work.
|
||||
MOZ_ASSERT_IF(v.isObject(), v.toObject().compartment() == compartment());
|
||||
|
|
|
|||
|
|
@ -85,6 +85,7 @@ JSCompartment::JSCompartment(Zone* zone, const JS::CompartmentOptions& options =
|
|||
jitCompartment_(nullptr),
|
||||
mappedArgumentsTemplate_(nullptr),
|
||||
unmappedArgumentsTemplate_(nullptr),
|
||||
iterResultTemplate_(nullptr),
|
||||
lcovOutput()
|
||||
{
|
||||
runtime_->numCompartments++;
|
||||
|
|
@ -846,6 +847,9 @@ JSCompartment::sweepTemplateObjects()
|
|||
|
||||
if (unmappedArgumentsTemplate_ && IsAboutToBeFinalized(&unmappedArgumentsTemplate_))
|
||||
unmappedArgumentsTemplate_.set(nullptr);
|
||||
|
||||
if (iterResultTemplate_ && IsAboutToBeFinalized(&iterResultTemplate_))
|
||||
iterResultTemplate_.set(nullptr);
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
|
|
|
|||
|
|
@ -861,6 +861,7 @@ struct JSCompartment
|
|||
|
||||
js::ReadBarriered<js::ArgumentsObject*> mappedArgumentsTemplate_;
|
||||
js::ReadBarriered<js::ArgumentsObject*> unmappedArgumentsTemplate_;
|
||||
js::ReadBarriered<js::NativeObject*> iterResultTemplate_;
|
||||
|
||||
public:
|
||||
bool ensureJitCompartmentExists(JSContext* cx);
|
||||
|
|
@ -872,6 +873,10 @@ struct JSCompartment
|
|||
|
||||
js::ArgumentsObject* maybeArgumentsTemplateObject(bool mapped) const;
|
||||
|
||||
static const size_t IterResultObjectValueSlot = 0;
|
||||
static const size_t IterResultObjectDoneSlot = 1;
|
||||
js::NativeObject* getOrCreateIterResultTemplateObject(JSContext* cx);
|
||||
|
||||
public:
|
||||
// Aggregated output used to collect JSScript hit counts when code coverage
|
||||
// is enabled.
|
||||
|
|
|
|||
|
|
@ -361,13 +361,13 @@ struct SuppressErrorsGuard
|
|||
}
|
||||
};
|
||||
|
||||
// Cut off the stack if it gets too deep (most commonly for infinite recursion
|
||||
// errors).
|
||||
static const size_t MAX_REPORTED_STACK_DEPTH = 1u << 7;
|
||||
|
||||
static bool
|
||||
CaptureStack(JSContext* cx, MutableHandleObject stack)
|
||||
{
|
||||
// Cut off the stack if it gets too deep (most commonly for infinite recursion
|
||||
// errors).
|
||||
static const size_t MAX_REPORTED_STACK_DEPTH = 1u << 7;
|
||||
|
||||
return CaptureCurrentStack(cx, stack,
|
||||
JS::StackCapture(JS::MaxFrames(MAX_REPORTED_STACK_DEPTH)));
|
||||
}
|
||||
|
|
@ -699,7 +699,12 @@ js::ErrorToException(JSContext* cx, JSErrorReport* reportp,
|
|||
return;
|
||||
|
||||
// Throw it.
|
||||
cx->setPendingException(ObjectValue(*errObject));
|
||||
RootedValue errValue(cx, ObjectValue(*errObject));
|
||||
RootedSavedFrame nstack(cx);
|
||||
if (stack) {
|
||||
nstack = &stack->as<SavedFrame>();
|
||||
}
|
||||
cx->setPendingException(errValue, nstack);
|
||||
|
||||
// Flag the error report passed in to indicate an exception was raised.
|
||||
reportp->flags |= JSREPORT_EXCEPTION;
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
#include "jsiter.h"
|
||||
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/PodOperations.h"
|
||||
|
|
@ -45,6 +46,7 @@ using namespace js::gc;
|
|||
using JS::ForOfIterator;
|
||||
|
||||
using mozilla::ArrayLength;
|
||||
using mozilla::DebugOnly;
|
||||
using mozilla::Maybe;
|
||||
using mozilla::PodCopy;
|
||||
using mozilla::PodZero;
|
||||
|
|
@ -944,25 +946,78 @@ js::CreateIterResultObject(JSContext* cx, HandleValue value, bool done)
|
|||
// Step 1 (implicit).
|
||||
|
||||
// Step 2.
|
||||
RootedObject resultObj(cx, NewBuiltinClassInstance<PlainObject>(cx));
|
||||
if (!resultObj)
|
||||
RootedObject templateObject(cx, cx->compartment()->getOrCreateIterResultTemplateObject(cx));
|
||||
if (!templateObject)
|
||||
return nullptr;
|
||||
|
||||
NativeObject* resultObj = NativeObject::createWithTemplate(cx, gc::DefaultHeap, templateObject);
|
||||
if (!resultObj)
|
||||
return nullptr;
|
||||
|
||||
// Step 3.
|
||||
if (!DefineProperty(cx, resultObj, cx->names().value, value))
|
||||
return nullptr;
|
||||
resultObj->setSlot(JSCompartment::IterResultObjectValueSlot, value);
|
||||
|
||||
// Step 4.
|
||||
if (!DefineProperty(cx, resultObj, cx->names().done,
|
||||
done ? TrueHandleValue : FalseHandleValue))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
resultObj->setSlot(JSCompartment::IterResultObjectDoneSlot,
|
||||
done ? TrueHandleValue : FalseHandleValue);
|
||||
|
||||
// Step 5.
|
||||
return resultObj;
|
||||
}
|
||||
|
||||
NativeObject*
|
||||
JSCompartment::getOrCreateIterResultTemplateObject(JSContext* cx)
|
||||
{
|
||||
if (iterResultTemplate_)
|
||||
return iterResultTemplate_;
|
||||
|
||||
// Create template plain object
|
||||
RootedNativeObject templateObject(cx, NewBuiltinClassInstance<PlainObject>(cx, TenuredObject));
|
||||
if (!templateObject)
|
||||
return iterResultTemplate_; // = nullptr
|
||||
|
||||
// Create a new group for the template.
|
||||
Rooted<TaggedProto> proto(cx, templateObject->taggedProto());
|
||||
RootedObjectGroup group(cx, ObjectGroupCompartment::makeGroup(cx, templateObject->getClass(),
|
||||
proto));
|
||||
if (!group)
|
||||
return iterResultTemplate_; // = nullptr
|
||||
templateObject->setGroup(group);
|
||||
|
||||
// Set dummy `value` property
|
||||
if (!NativeDefineDataProperty(cx, templateObject, cx->names().value, UndefinedHandleValue,
|
||||
JSPROP_ENUMERATE))
|
||||
{
|
||||
return iterResultTemplate_; // = nullptr
|
||||
}
|
||||
|
||||
// Set dummy `done` property
|
||||
if (!NativeDefineDataProperty(cx, templateObject, cx->names().done, TrueHandleValue,
|
||||
JSPROP_ENUMERATE))
|
||||
{
|
||||
return iterResultTemplate_; // = nullptr
|
||||
}
|
||||
|
||||
// Update `value` property typeset, since it can be any value.
|
||||
HeapTypeSet* types = group->maybeGetProperty(NameToId(cx->names().value));
|
||||
MOZ_ASSERT(types);
|
||||
{
|
||||
AutoEnterAnalysis enter(cx);
|
||||
types->makeUnknown(cx);
|
||||
}
|
||||
|
||||
// Make sure that the properties are in the right slots.
|
||||
DebugOnly<Shape*> shape = templateObject->lastProperty();
|
||||
MOZ_ASSERT(shape->previous()->slot() == JSCompartment::IterResultObjectValueSlot &&
|
||||
shape->previous()->propidRef() == NameToId(cx->names().value));
|
||||
MOZ_ASSERT(shape->slot() == JSCompartment::IterResultObjectDoneSlot &&
|
||||
shape->propidRef() == NameToId(cx->names().done));
|
||||
|
||||
iterResultTemplate_.set(templateObject);
|
||||
|
||||
return iterResultTemplate_;
|
||||
}
|
||||
|
||||
bool
|
||||
js::ThrowStopIteration(JSContext* cx)
|
||||
{
|
||||
|
|
@ -971,8 +1026,10 @@ js::ThrowStopIteration(JSContext* cx)
|
|||
// StopIteration isn't a constructor, but it's stored in GlobalObject
|
||||
// as one, out of laziness. Hence the GetBuiltinConstructor call here.
|
||||
RootedObject ctor(cx);
|
||||
if (GetBuiltinConstructor(cx, JSProto_StopIteration, &ctor))
|
||||
cx->setPendingException(ObjectValue(*ctor));
|
||||
if (GetBuiltinConstructor(cx, JSProto_StopIteration, &ctor)) {
|
||||
RootedValue ctorval(cx, ObjectValue(*ctor));
|
||||
cx->setPendingExceptionAndCaptureStack(ctorval);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -1261,12 +1318,13 @@ js::UnwindIteratorForException(JSContext* cx, HandleObject obj)
|
|||
{
|
||||
RootedValue v(cx);
|
||||
bool getOk = cx->getPendingException(&v);
|
||||
RootedSavedFrame stack(cx, cx->getPendingExceptionStack());
|
||||
cx->clearPendingException();
|
||||
if (!CloseIterator(cx, obj))
|
||||
return false;
|
||||
if (!getOk)
|
||||
return false;
|
||||
cx->setPendingException(v);
|
||||
cx->setPendingException(v, stack);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3196,8 +3196,8 @@ GetObjectSlotNameFunctor::operator()(JS::CallbackTracer* trc, char* buf, size_t
|
|||
pattern = "CLASS_OBJECT(%s)";
|
||||
if (false)
|
||||
;
|
||||
#define TEST_SLOT_MATCHES_PROTOTYPE(name,code,init,clasp) \
|
||||
else if ((code) == slot) { slotname = js_##name##_str; }
|
||||
#define TEST_SLOT_MATCHES_PROTOTYPE(name,init,clasp) \
|
||||
else if ((JSProto_##name) == slot) { slotname = js_##name##_str; }
|
||||
JS_FOR_EACH_PROTOTYPE(TEST_SLOT_MATCHES_PROTOTYPE)
|
||||
#undef TEST_SLOT_MATCHES_PROTOTYPE
|
||||
} else {
|
||||
|
|
@ -3864,34 +3864,77 @@ JSObject::maybeConstructorDisplayAtom() const
|
|||
return displayAtomFromObjectGroup(*group());
|
||||
}
|
||||
|
||||
bool
|
||||
js::SpeciesConstructor(JSContext* cx, HandleObject obj, HandleValue defaultCtor, MutableHandleValue pctor)
|
||||
// ES 2016 7.3.20.
|
||||
MOZ_MUST_USE JSObject*
|
||||
js::SpeciesConstructor(JSContext* cx, HandleObject obj, HandleObject defaultCtor,
|
||||
bool (*isDefaultSpecies)(JSContext*, JSFunction*))
|
||||
{
|
||||
HandlePropertyName shName = cx->names().SpeciesConstructor;
|
||||
RootedValue func(cx);
|
||||
if (!GlobalObject::getSelfHostedFunction(cx, cx->global(), shName, shName, 2, &func))
|
||||
return false;
|
||||
// Step 1 (implicit).
|
||||
|
||||
FixedInvokeArgs<2> args(cx);
|
||||
// Fast-path for steps 2 - 8. Applies if all of the following conditions
|
||||
// are met:
|
||||
// - obj.constructor can be retrieved without side-effects.
|
||||
// - obj.constructor[[@@species]] can be retrieved without side-effects.
|
||||
// - obj.constructor[[@@species]] is the builtin's original @@species
|
||||
// getter.
|
||||
RootedValue ctor(cx);
|
||||
bool ctorGetSucceeded = GetPropertyPure(cx, obj, NameToId(cx->names().constructor),
|
||||
ctor.address());
|
||||
if (ctorGetSucceeded && ctor.isObject() && &ctor.toObject() == defaultCtor) {
|
||||
RootedObject ctorObj(cx, &ctor.toObject());
|
||||
RootedId speciesId(cx, SYMBOL_TO_JSID(cx->wellKnownSymbols().species));
|
||||
JSFunction* getter;
|
||||
if (GetGetterPure(cx, ctorObj, speciesId, &getter) && getter &&
|
||||
isDefaultSpecies(cx, getter))
|
||||
{
|
||||
return defaultCtor;
|
||||
}
|
||||
}
|
||||
|
||||
args[0].setObject(*obj);
|
||||
args[1].set(defaultCtor);
|
||||
// Step 2.
|
||||
if (!ctorGetSucceeded && !GetProperty(cx, obj, obj, cx->names().constructor, &ctor))
|
||||
return nullptr;
|
||||
|
||||
if (!Call(cx, func, UndefinedHandleValue, args, pctor))
|
||||
return false;
|
||||
// Step 3.
|
||||
if (ctor.isUndefined())
|
||||
return defaultCtor;
|
||||
|
||||
pctor.set(args.rval());
|
||||
return true;
|
||||
// Step 4.
|
||||
if (!ctor.isObject()) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT,
|
||||
"object's 'constructor' property");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Step 5.
|
||||
RootedObject ctorObj(cx, &ctor.toObject());
|
||||
RootedValue s(cx);
|
||||
RootedId speciesId(cx, SYMBOL_TO_JSID(cx->wellKnownSymbols().species));
|
||||
if (!GetProperty(cx, ctorObj, ctor, speciesId, &s))
|
||||
return nullptr;
|
||||
|
||||
// Step 6.
|
||||
if (s.isNullOrUndefined())
|
||||
return defaultCtor;
|
||||
|
||||
// Step 7.
|
||||
if (IsConstructor(s))
|
||||
return &s.toObject();
|
||||
|
||||
// Step 8.
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_CONSTRUCTOR,
|
||||
"[Symbol.species] property of object's constructor");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
MOZ_MUST_USE JSObject*
|
||||
js::SpeciesConstructor(JSContext* cx, HandleObject obj, JSProtoKey ctorKey,
|
||||
MutableHandleValue pctor)
|
||||
bool (*isDefaultSpecies)(JSContext*, JSFunction*))
|
||||
{
|
||||
if (!GlobalObject::ensureConstructor(cx, cx->global(), ctorKey))
|
||||
return false;
|
||||
RootedValue defaultCtor(cx, cx->global()->getConstructor(ctorKey));
|
||||
return SpeciesConstructor(cx, obj, defaultCtor, pctor);
|
||||
return nullptr;
|
||||
RootedObject defaultCtor(cx, &cx->global()->getConstructor(ctorKey).toObject());
|
||||
return SpeciesConstructor(cx, obj, defaultCtor, isDefaultSpecies);
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
|||
|
|
@ -1347,11 +1347,13 @@ FreezeObject(JSContext* cx, HandleObject obj)
|
|||
extern bool
|
||||
TestIntegrityLevel(JSContext* cx, HandleObject obj, IntegrityLevel level, bool* resultp);
|
||||
|
||||
extern bool
|
||||
SpeciesConstructor(JSContext* cx, HandleObject obj, HandleValue defaultCtor, MutableHandleValue pctor);
|
||||
extern MOZ_MUST_USE JSObject*
|
||||
SpeciesConstructor(JSContext* cx, HandleObject obj, HandleObject defaultCtor,
|
||||
bool (*isDefaultSpecies)(JSContext*, JSFunction*));
|
||||
|
||||
extern bool
|
||||
SpeciesConstructor(JSContext* cx, HandleObject obj, JSProtoKey ctorKey, MutableHandleValue pctor);
|
||||
extern MOZ_MUST_USE JSObject*
|
||||
SpeciesConstructor(JSContext* cx, HandleObject obj, JSProtoKey ctorKey,
|
||||
bool (*isDefaultSpecies)(JSContext*, JSFunction*));
|
||||
|
||||
extern bool
|
||||
GetObjectFromIncumbentGlobal(JSContext* cx, MutableHandleObject obj);
|
||||
|
|
|
|||
|
|
@ -9,9 +9,8 @@
|
|||
/* A higher-order macro for enumerating all JSProtoKey values. */
|
||||
/*
|
||||
* Consumers define macros as follows:
|
||||
* macro(name, code, init, clasp)
|
||||
* macro(name, init, clasp)
|
||||
* name: The canonical name of the class.
|
||||
* code: The enumerator code. There are part of the XDR API, and must not change.
|
||||
* init: Initialization function. These are |extern "C";|, and clients should use
|
||||
* |extern "C" {}| as appropriate when using this macro.
|
||||
* clasp: The JSClass for this object, or "dummy" if it doesn't exist.
|
||||
|
|
@ -57,61 +56,61 @@
|
|||
#endif
|
||||
|
||||
#define JS_FOR_PROTOTYPES(real,imaginary) \
|
||||
imaginary(Null, 0, InitNullClass, dummy) \
|
||||
real(Object, 1, InitViaClassSpec, OCLASP(Plain)) \
|
||||
real(Function, 2, InitViaClassSpec, &JSFunction::class_) \
|
||||
real(Array, 3, InitViaClassSpec, OCLASP(Array)) \
|
||||
real(Boolean, 4, InitBooleanClass, OCLASP(Boolean)) \
|
||||
real(JSON, 5, InitJSONClass, CLASP(JSON)) \
|
||||
real(Date, 6, InitViaClassSpec, OCLASP(Date)) \
|
||||
real(Math, 7, InitMathClass, CLASP(Math)) \
|
||||
real(Number, 8, InitNumberClass, OCLASP(Number)) \
|
||||
real(String, 9, InitStringClass, OCLASP(String)) \
|
||||
real(RegExp, 10, InitViaClassSpec, OCLASP(RegExp)) \
|
||||
real(Error, 11, InitViaClassSpec, ERROR_CLASP(JSEXN_ERR)) \
|
||||
real(InternalError, 12, InitViaClassSpec, ERROR_CLASP(JSEXN_INTERNALERR)) \
|
||||
real(EvalError, 13, InitViaClassSpec, ERROR_CLASP(JSEXN_EVALERR)) \
|
||||
real(RangeError, 14, InitViaClassSpec, ERROR_CLASP(JSEXN_RANGEERR)) \
|
||||
real(ReferenceError, 15, InitViaClassSpec, ERROR_CLASP(JSEXN_REFERENCEERR)) \
|
||||
real(SyntaxError, 16, InitViaClassSpec, ERROR_CLASP(JSEXN_SYNTAXERR)) \
|
||||
real(TypeError, 17, InitViaClassSpec, ERROR_CLASP(JSEXN_TYPEERR)) \
|
||||
real(URIError, 18, InitViaClassSpec, ERROR_CLASP(JSEXN_URIERR)) \
|
||||
real(DebuggeeWouldRun, 19, InitViaClassSpec, ERROR_CLASP(JSEXN_DEBUGGEEWOULDRUN)) \
|
||||
real(CompileError, 20, InitViaClassSpec, ERROR_CLASP(JSEXN_WASMCOMPILEERROR)) \
|
||||
real(RuntimeError, 21, InitViaClassSpec, ERROR_CLASP(JSEXN_WASMRUNTIMEERROR)) \
|
||||
real(Iterator, 22, InitLegacyIteratorClass,OCLASP(PropertyIterator)) \
|
||||
real(StopIteration, 23, InitStopIterationClass, OCLASP(StopIteration)) \
|
||||
real(ArrayBuffer, 24, InitViaClassSpec, OCLASP(ArrayBuffer)) \
|
||||
real(Int8Array, 25, InitViaClassSpec, TYPED_ARRAY_CLASP(Int8)) \
|
||||
real(Uint8Array, 26, InitViaClassSpec, TYPED_ARRAY_CLASP(Uint8)) \
|
||||
real(Int16Array, 27, InitViaClassSpec, TYPED_ARRAY_CLASP(Int16)) \
|
||||
real(Uint16Array, 28, InitViaClassSpec, TYPED_ARRAY_CLASP(Uint16)) \
|
||||
real(Int32Array, 29, InitViaClassSpec, TYPED_ARRAY_CLASP(Int32)) \
|
||||
real(Uint32Array, 30, InitViaClassSpec, TYPED_ARRAY_CLASP(Uint32)) \
|
||||
real(Float32Array, 31, InitViaClassSpec, TYPED_ARRAY_CLASP(Float32)) \
|
||||
real(Float64Array, 32, InitViaClassSpec, TYPED_ARRAY_CLASP(Float64)) \
|
||||
real(Uint8ClampedArray, 33, InitViaClassSpec, TYPED_ARRAY_CLASP(Uint8Clamped)) \
|
||||
real(Proxy, 34, InitProxyClass, js::ProxyClassPtr) \
|
||||
real(WeakMap, 35, InitWeakMapClass, OCLASP(WeakMap)) \
|
||||
real(Map, 36, InitMapClass, OCLASP(Map)) \
|
||||
real(Set, 37, InitSetClass, OCLASP(Set)) \
|
||||
real(DataView, 38, InitDataViewClass, OCLASP(DataView)) \
|
||||
real(Symbol, 39, InitSymbolClass, OCLASP(Symbol)) \
|
||||
IF_SAB(real,imaginary)(SharedArrayBuffer, 40, InitViaClassSpec, OCLASP(SharedArrayBuffer)) \
|
||||
IF_INTL(real,imaginary) (Intl, 41, InitIntlClass, CLASP(Intl)) \
|
||||
IF_BDATA(real,imaginary)(TypedObject, 42, InitTypedObjectModuleObject, OCLASP(TypedObjectModule)) \
|
||||
real(Reflect, 43, InitReflect, nullptr) \
|
||||
IF_SIMD(real,imaginary)(SIMD, 44, InitSimdClass, OCLASP(Simd)) \
|
||||
real(WeakSet, 45, InitWeakSetClass, OCLASP(WeakSet)) \
|
||||
real(TypedArray, 46, InitViaClassSpec, &js::TypedArrayObject::sharedTypedArrayPrototypeClass) \
|
||||
IF_SAB(real,imaginary)(Atomics, 47, InitAtomicsClass, OCLASP(Atomics)) \
|
||||
real(SavedFrame, 48, InitViaClassSpec, &js::SavedFrame::class_) \
|
||||
real(WebAssembly, 49, InitWebAssemblyClass, CLASP(WebAssembly)) \
|
||||
imaginary(WasmModule, 50, dummy, dummy) \
|
||||
imaginary(WasmInstance, 51, dummy, dummy) \
|
||||
imaginary(WasmMemory, 52, dummy, dummy) \
|
||||
imaginary(WasmTable, 53, dummy, dummy) \
|
||||
real(Promise, 54, InitViaClassSpec, OCLASP(Promise)) \
|
||||
imaginary(Null, InitNullClass, dummy) \
|
||||
real(Object, InitViaClassSpec, OCLASP(Plain)) \
|
||||
real(Function, InitViaClassSpec, &JSFunction::class_) \
|
||||
real(Array, InitViaClassSpec, OCLASP(Array)) \
|
||||
real(Boolean, InitBooleanClass, OCLASP(Boolean)) \
|
||||
real(JSON, InitJSONClass, CLASP(JSON)) \
|
||||
real(Date, InitViaClassSpec, OCLASP(Date)) \
|
||||
real(Math, InitMathClass, CLASP(Math)) \
|
||||
real(Number, InitNumberClass, OCLASP(Number)) \
|
||||
real(String, InitStringClass, OCLASP(String)) \
|
||||
real(RegExp, InitViaClassSpec, OCLASP(RegExp)) \
|
||||
real(Error, InitViaClassSpec, ERROR_CLASP(JSEXN_ERR)) \
|
||||
real(InternalError, InitViaClassSpec, ERROR_CLASP(JSEXN_INTERNALERR)) \
|
||||
real(EvalError, InitViaClassSpec, ERROR_CLASP(JSEXN_EVALERR)) \
|
||||
real(RangeError, InitViaClassSpec, ERROR_CLASP(JSEXN_RANGEERR)) \
|
||||
real(ReferenceError, InitViaClassSpec, ERROR_CLASP(JSEXN_REFERENCEERR)) \
|
||||
real(SyntaxError, InitViaClassSpec, ERROR_CLASP(JSEXN_SYNTAXERR)) \
|
||||
real(TypeError, InitViaClassSpec, ERROR_CLASP(JSEXN_TYPEERR)) \
|
||||
real(URIError, InitViaClassSpec, ERROR_CLASP(JSEXN_URIERR)) \
|
||||
real(DebuggeeWouldRun, InitViaClassSpec, ERROR_CLASP(JSEXN_DEBUGGEEWOULDRUN)) \
|
||||
real(CompileError, InitViaClassSpec, ERROR_CLASP(JSEXN_WASMCOMPILEERROR)) \
|
||||
real(RuntimeError, InitViaClassSpec, ERROR_CLASP(JSEXN_WASMRUNTIMEERROR)) \
|
||||
real(Iterator, InitLegacyIteratorClass,OCLASP(PropertyIterator)) \
|
||||
real(StopIteration, InitStopIterationClass, OCLASP(StopIteration)) \
|
||||
real(ArrayBuffer, InitViaClassSpec, OCLASP(ArrayBuffer)) \
|
||||
real(Int8Array, InitViaClassSpec, TYPED_ARRAY_CLASP(Int8)) \
|
||||
real(Uint8Array, InitViaClassSpec, TYPED_ARRAY_CLASP(Uint8)) \
|
||||
real(Int16Array, InitViaClassSpec, TYPED_ARRAY_CLASP(Int16)) \
|
||||
real(Uint16Array, InitViaClassSpec, TYPED_ARRAY_CLASP(Uint16)) \
|
||||
real(Int32Array, InitViaClassSpec, TYPED_ARRAY_CLASP(Int32)) \
|
||||
real(Uint32Array, InitViaClassSpec, TYPED_ARRAY_CLASP(Uint32)) \
|
||||
real(Float32Array, InitViaClassSpec, TYPED_ARRAY_CLASP(Float32)) \
|
||||
real(Float64Array, InitViaClassSpec, TYPED_ARRAY_CLASP(Float64)) \
|
||||
real(Uint8ClampedArray, InitViaClassSpec, TYPED_ARRAY_CLASP(Uint8Clamped)) \
|
||||
real(Proxy, InitProxyClass, js::ProxyClassPtr) \
|
||||
real(WeakMap, InitWeakMapClass, OCLASP(WeakMap)) \
|
||||
real(Map, InitMapClass, OCLASP(Map)) \
|
||||
real(Set, InitSetClass, OCLASP(Set)) \
|
||||
real(DataView, InitDataViewClass, OCLASP(DataView)) \
|
||||
real(Symbol, InitSymbolClass, OCLASP(Symbol)) \
|
||||
IF_SAB(real,imaginary)(SharedArrayBuffer, InitViaClassSpec, OCLASP(SharedArrayBuffer)) \
|
||||
IF_INTL(real,imaginary) (Intl, InitIntlClass, CLASP(Intl)) \
|
||||
IF_BDATA(real,imaginary)(TypedObject, InitTypedObjectModuleObject, OCLASP(TypedObjectModule)) \
|
||||
real(Reflect, InitReflect, nullptr) \
|
||||
IF_SIMD(real,imaginary)(SIMD, InitSimdClass, OCLASP(Simd)) \
|
||||
real(WeakSet, InitWeakSetClass, OCLASP(WeakSet)) \
|
||||
real(TypedArray, InitViaClassSpec, &js::TypedArrayObject::sharedTypedArrayPrototypeClass) \
|
||||
IF_SAB(real,imaginary)(Atomics, InitAtomicsClass, OCLASP(Atomics)) \
|
||||
real(SavedFrame, InitViaClassSpec, &js::SavedFrame::class_) \
|
||||
real(WebAssembly, InitWebAssemblyClass, CLASP(WebAssembly)) \
|
||||
imaginary(WasmModule, dummy, dummy) \
|
||||
imaginary(WasmInstance, dummy, dummy) \
|
||||
imaginary(WasmMemory, dummy, dummy) \
|
||||
imaginary(WasmTable, dummy, dummy) \
|
||||
real(Promise, InitViaClassSpec, OCLASP(Promise)) \
|
||||
|
||||
#define JS_FOR_EACH_PROTOTYPE(macro) JS_FOR_PROTOTYPES(macro,macro)
|
||||
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ enum JSType {
|
|||
|
||||
/* Dense index into cached prototypes and class atoms for standard objects. */
|
||||
enum JSProtoKey {
|
||||
#define PROTOKEY_AND_INITIALIZER(name,code,init,clasp) JSProto_##name = code,
|
||||
#define PROTOKEY_AND_INITIALIZER(name,init,clasp) JSProto_##name,
|
||||
JS_FOR_EACH_PROTOTYPE(PROTOKEY_AND_INITIALIZER)
|
||||
#undef PROTOKEY_AND_INITIALIZER
|
||||
JSProto_LIMIT
|
||||
|
|
|
|||
|
|
@ -408,12 +408,15 @@ ErrorCopier::~ErrorCopier()
|
|||
{
|
||||
RootedValue exc(cx);
|
||||
if (cx->getPendingException(&exc) && exc.isObject() && exc.toObject().is<ErrorObject>()) {
|
||||
RootedSavedFrame stack(cx, cx->getPendingExceptionStack());
|
||||
cx->clearPendingException();
|
||||
ac.reset();
|
||||
Rooted<ErrorObject*> errObj(cx, &exc.toObject().as<ErrorObject>());
|
||||
JSObject* copyobj = CopyErrorObject(cx, errObj);
|
||||
if (copyobj)
|
||||
cx->setPendingException(ObjectValue(*copyobj));
|
||||
if (copyobj) {
|
||||
RootedValue rootedCopy(cx, ObjectValue(*copyobj));
|
||||
cx->setPendingException(rootedCopy, stack);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,89 @@
|
|||
// 22.2.4.3 TypedArray ( typedArray )
|
||||
|
||||
// Test [[Prototype]] of newly created typed array and its array buffer, and
|
||||
// ensure they are both created in the correct global.
|
||||
|
||||
const thisGlobal = this;
|
||||
const otherGlobal = newGlobal();
|
||||
const ta_i32 = otherGlobal.eval("new Int32Array(0)");
|
||||
|
||||
function assertBufferPrototypeFrom(newTypedArray, prototype) {
|
||||
var typedArrayName = newTypedArray.constructor.name;
|
||||
|
||||
assertEq(Object.getPrototypeOf(newTypedArray), thisGlobal[typedArrayName].prototype);
|
||||
assertEq(Object.getPrototypeOf(newTypedArray.buffer), prototype);
|
||||
}
|
||||
|
||||
const EMPTY = {};
|
||||
|
||||
// Test SpeciesConstructor() implementation selects the correct (fallback) constructor.
|
||||
const testCases = [
|
||||
// Create the array buffer from the species constructor.
|
||||
{ constructor: EMPTY, prototype: otherGlobal.ArrayBuffer.prototype },
|
||||
|
||||
// Use %ArrayBuffer% from this global if constructor is undefined.
|
||||
{ constructor: undefined, prototype: ArrayBuffer.prototype },
|
||||
|
||||
// Use %ArrayBuffer% from this global if species is undefined.
|
||||
{ constructor: {[Symbol.species]: undefined}, prototype: ArrayBuffer.prototype },
|
||||
|
||||
// Use %ArrayBuffer% from this global if species is null.
|
||||
{ constructor: {[Symbol.species]: null}, prototype: ArrayBuffer.prototype },
|
||||
];
|
||||
|
||||
for (let { constructor, prototype } of testCases) {
|
||||
if (constructor !== EMPTY) {
|
||||
ta_i32.buffer.constructor = constructor;
|
||||
}
|
||||
|
||||
// Same element type.
|
||||
assertBufferPrototypeFrom(new Int32Array(ta_i32), prototype);
|
||||
|
||||
// Different element type.
|
||||
assertBufferPrototypeFrom(new Int16Array(ta_i32), prototype);
|
||||
}
|
||||
|
||||
|
||||
// Also ensure TypeErrors are thrown from the correct global.
|
||||
const errorTestCases = [
|
||||
// Constructor property is neither undefined nor an object.
|
||||
{ constructor: null },
|
||||
{ constructor: 123 },
|
||||
|
||||
// Species property is neither undefined/null nor a constructor function.
|
||||
{ constructor: { [Symbol.species]: 123 } },
|
||||
{ constructor: { [Symbol.species]: [] } },
|
||||
{ constructor: { [Symbol.species]: () => {} } },
|
||||
];
|
||||
|
||||
for (let { constructor } of errorTestCases) {
|
||||
ta_i32.buffer.constructor = constructor;
|
||||
|
||||
// Same element type.
|
||||
assertThrowsInstanceOf(() => new Int32Array(ta_i32), TypeError);
|
||||
|
||||
// Different element type.
|
||||
assertThrowsInstanceOf(() => new Int32Array(ta_i32), TypeError);
|
||||
}
|
||||
|
||||
|
||||
// TypedArrays using SharedArrayBuffers never call the SpeciesConstructor operation.
|
||||
if (this.SharedArrayBuffer) {
|
||||
const ta_i32_shared = otherGlobal.eval("new Int32Array(new SharedArrayBuffer(0))");
|
||||
|
||||
Object.defineProperty(ta_i32_shared.buffer, "constructor", {
|
||||
get() {
|
||||
throw new Error("constructor property accessed");
|
||||
}
|
||||
});
|
||||
|
||||
// Same element type.
|
||||
assertBufferPrototypeFrom(new Int32Array(ta_i32_shared), ArrayBuffer.prototype);
|
||||
|
||||
// Different element type.
|
||||
assertBufferPrototypeFrom(new Int16Array(ta_i32_shared), ArrayBuffer.prototype);
|
||||
}
|
||||
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(0, 0);
|
||||
|
|
@ -311,9 +311,24 @@ AsyncGeneratorObject::create(JSContext* cx, HandleFunction asyncGen, HandleValue
|
|||
// Step 8.
|
||||
asyncGenObj->clearSingleQueueRequest();
|
||||
|
||||
asyncGenObj->clearCachedRequest();
|
||||
|
||||
return asyncGenObj;
|
||||
}
|
||||
|
||||
/* static */ AsyncGeneratorRequest*
|
||||
AsyncGeneratorObject::createRequest(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
|
||||
CompletionKind completionKind, HandleValue completionValue,
|
||||
HandleObject promise)
|
||||
{
|
||||
if (!asyncGenObj->hasCachedRequest())
|
||||
return AsyncGeneratorRequest::create(cx, completionKind, completionValue, promise);
|
||||
|
||||
AsyncGeneratorRequest* request = asyncGenObj->takeCachedRequest();
|
||||
request->init(completionKind, completionValue, promise);
|
||||
return request;
|
||||
}
|
||||
|
||||
static MOZ_MUST_USE bool
|
||||
InternalEnqueue(JSContext* cx, HandleArrayObject queue, HandleValue val)
|
||||
{
|
||||
|
|
@ -428,17 +443,15 @@ const Class AsyncGeneratorRequest::class_ = {
|
|||
|
||||
// Async Iteration proposal 11.4.3.1.
|
||||
/* static */ AsyncGeneratorRequest*
|
||||
AsyncGeneratorRequest::create(JSContext* cx, CompletionKind completionKind_,
|
||||
HandleValue completionValue_, HandleObject promise_)
|
||||
AsyncGeneratorRequest::create(JSContext* cx, CompletionKind completionKind,
|
||||
HandleValue completionValue, HandleObject promise)
|
||||
{
|
||||
RootedObject obj(cx, NewNativeObjectWithGivenProto(cx, &class_, nullptr));
|
||||
if (!obj)
|
||||
return nullptr;
|
||||
|
||||
Handle<AsyncGeneratorRequest*> request = obj.as<AsyncGeneratorRequest>();
|
||||
request->setCompletionKind(completionKind_);
|
||||
request->setCompletionValue(completionValue_);
|
||||
request->setPromise(promise_);
|
||||
request->init(completionKind, completionValue, promise);
|
||||
return request;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -50,6 +50,8 @@ AsyncGeneratorYieldReturnAwaitedRejected(JSContext* cx,
|
|||
Handle<AsyncGeneratorObject*> asyncGenObj,
|
||||
HandleValue reason);
|
||||
|
||||
class AsyncGeneratorObject;
|
||||
|
||||
class AsyncGeneratorRequest : public NativeObject
|
||||
{
|
||||
private:
|
||||
|
|
@ -60,23 +62,26 @@ class AsyncGeneratorRequest : public NativeObject
|
|||
Slots,
|
||||
};
|
||||
|
||||
void setCompletionKind(CompletionKind completionKind_) {
|
||||
void init(CompletionKind completionKind, HandleValue completionValue,
|
||||
HandleObject promise) {
|
||||
setFixedSlot(Slot_CompletionKind,
|
||||
Int32Value(static_cast<int32_t>(completionKind_)));
|
||||
Int32Value(static_cast<int32_t>(completionKind)));
|
||||
setFixedSlot(Slot_CompletionValue, completionValue);
|
||||
setFixedSlot(Slot_Promise, ObjectValue(*promise));
|
||||
}
|
||||
void setCompletionValue(HandleValue completionValue_) {
|
||||
setFixedSlot(Slot_CompletionValue, completionValue_);
|
||||
}
|
||||
void setPromise(HandleObject promise_) {
|
||||
setFixedSlot(Slot_Promise, ObjectValue(*promise_));
|
||||
|
||||
void clearData() {
|
||||
setFixedSlot(Slot_CompletionValue, NullValue());
|
||||
setFixedSlot(Slot_Promise, NullValue());
|
||||
}
|
||||
|
||||
friend AsyncGeneratorObject;
|
||||
|
||||
public:
|
||||
static const Class class_;
|
||||
|
||||
static AsyncGeneratorRequest*
|
||||
create(JSContext* cx, CompletionKind completionKind, HandleValue completionValue,
|
||||
HandleObject promise);
|
||||
static AsyncGeneratorRequest* create(JSContext* cx, CompletionKind completionKind,
|
||||
HandleValue completionValue, HandleObject promise);
|
||||
|
||||
CompletionKind completionKind() const {
|
||||
return static_cast<CompletionKind>(getFixedSlot(Slot_CompletionKind).toInt32());
|
||||
|
|
@ -96,6 +101,7 @@ class AsyncGeneratorObject : public NativeObject
|
|||
Slot_State = 0,
|
||||
Slot_Generator,
|
||||
Slot_QueueOrRequest,
|
||||
Slot_CachedRequest,
|
||||
Slots
|
||||
};
|
||||
|
||||
|
|
@ -139,7 +145,7 @@ class AsyncGeneratorObject : public NativeObject
|
|||
setFixedSlot(Slot_QueueOrRequest, ObjectValue(*request));
|
||||
}
|
||||
void clearSingleQueueRequest() {
|
||||
setFixedSlot(Slot_QueueOrRequest, NullHandleValue);
|
||||
setFixedSlot(Slot_QueueOrRequest, NullValue());
|
||||
}
|
||||
AsyncGeneratorRequest* singleQueueRequest() const {
|
||||
return &getFixedSlot(Slot_QueueOrRequest).toObject().as<AsyncGeneratorRequest>();
|
||||
|
|
@ -218,6 +224,41 @@ class AsyncGeneratorObject : public NativeObject
|
|||
return isSingleQueueEmpty();
|
||||
return queue()->length() == 0;
|
||||
}
|
||||
|
||||
// This function does either of the following:
|
||||
// * return a cached request object with the slots updated
|
||||
// * create a new request object with the slots set
|
||||
static AsyncGeneratorRequest* createRequest(JSContext* cx,
|
||||
Handle<AsyncGeneratorObject*> asyncGenObj,
|
||||
CompletionKind completionKind,
|
||||
HandleValue completionValue,
|
||||
HandleObject promise);
|
||||
|
||||
// Stores the given request to the generator's cache after clearing its data
|
||||
// slots. The cached request will be reused in the subsequent createRequest
|
||||
// call.
|
||||
void cacheRequest(AsyncGeneratorRequest* request) {
|
||||
if (hasCachedRequest())
|
||||
return;
|
||||
|
||||
request->clearData();
|
||||
setFixedSlot(Slot_CachedRequest, ObjectValue(*request));
|
||||
}
|
||||
|
||||
private:
|
||||
bool hasCachedRequest() const {
|
||||
return getFixedSlot(Slot_CachedRequest).isObject();
|
||||
}
|
||||
|
||||
AsyncGeneratorRequest* takeCachedRequest() {
|
||||
auto request = &getFixedSlot(Slot_CachedRequest).toObject().as<AsyncGeneratorRequest>();
|
||||
clearCachedRequest();
|
||||
return request;
|
||||
}
|
||||
|
||||
void clearCachedRequest() {
|
||||
setFixedSlot(Slot_CachedRequest, NullValue());
|
||||
}
|
||||
};
|
||||
|
||||
JSObject*
|
||||
|
|
|
|||
|
|
@ -848,7 +848,7 @@ Debugger::slowPathOnEnterFrame(JSContext* cx, AbstractFramePtr frame)
|
|||
break;
|
||||
|
||||
case JSTRAP_THROW:
|
||||
cx->setPendingException(rval);
|
||||
cx->setPendingExceptionAndCaptureStack(rval);
|
||||
break;
|
||||
|
||||
case JSTRAP_ERROR:
|
||||
|
|
@ -960,7 +960,7 @@ Debugger::slowPathOnLeaveFrame(JSContext* cx, AbstractFramePtr frame, jsbytecode
|
|||
return true;
|
||||
|
||||
case JSTRAP_THROW:
|
||||
cx->setPendingException(value);
|
||||
cx->setPendingExceptionAndCaptureStack(value);
|
||||
return false;
|
||||
|
||||
case JSTRAP_ERROR:
|
||||
|
|
@ -993,7 +993,7 @@ Debugger::slowPathOnDebuggerStatement(JSContext* cx, AbstractFramePtr frame)
|
|||
break;
|
||||
|
||||
case JSTRAP_THROW:
|
||||
cx->setPendingException(rval);
|
||||
cx->setPendingExceptionAndCaptureStack(rval);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
@ -1028,7 +1028,7 @@ Debugger::slowPathOnExceptionUnwind(JSContext* cx, AbstractFramePtr frame)
|
|||
break;
|
||||
|
||||
case JSTRAP_THROW:
|
||||
cx->setPendingException(rval);
|
||||
cx->setPendingExceptionAndCaptureStack(rval);
|
||||
break;
|
||||
|
||||
case JSTRAP_ERROR:
|
||||
|
|
@ -1321,7 +1321,7 @@ public:
|
|||
|
||||
bool operator()(JSContext* cx) override
|
||||
{
|
||||
cx->setPendingException(exn_);
|
||||
cx->setPendingExceptionAndCaptureStack(exn_);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -1753,6 +1753,7 @@ Debugger::fireExceptionUnwind(JSContext* cx, MutableHandleValue vp)
|
|||
MOZ_ASSERT(hook->isCallable());
|
||||
|
||||
RootedValue exc(cx);
|
||||
RootedSavedFrame stack(cx, cx->getPendingExceptionStack());
|
||||
if (!cx->getPendingException(&exc))
|
||||
return JSTRAP_ERROR;
|
||||
cx->clearPendingException();
|
||||
|
|
@ -1772,7 +1773,7 @@ Debugger::fireExceptionUnwind(JSContext* cx, MutableHandleValue vp)
|
|||
bool ok = js::Call(cx, fval, object, scriptFrame, wrappedExc, &rv);
|
||||
JSTrapStatus st = processHandlerResult(ac, ok, rv, iter.abstractFramePtr(), iter.pc(), vp);
|
||||
if (st == JSTRAP_CONTINUE)
|
||||
cx->setPendingException(exc);
|
||||
cx->setPendingException(exc, stack);
|
||||
return st;
|
||||
}
|
||||
|
||||
|
|
@ -2005,13 +2006,7 @@ Debugger::onSingleStep(JSContext* cx, MutableHandleValue vp)
|
|||
* onStep handlers mess with that (other than by returning a resumption
|
||||
* value).
|
||||
*/
|
||||
RootedValue exception(cx, UndefinedValue());
|
||||
bool exceptionPending = cx->isExceptionPending();
|
||||
if (exceptionPending) {
|
||||
if (!cx->getPendingException(&exception))
|
||||
return JSTRAP_ERROR;
|
||||
cx->clearPendingException();
|
||||
}
|
||||
JS::AutoSaveExceptionState savedExc(cx);
|
||||
|
||||
/*
|
||||
* Build list of Debugger.Frame instances referring to this frame with
|
||||
|
|
@ -2070,13 +2065,13 @@ Debugger::onSingleStep(JSContext* cx, MutableHandleValue vp)
|
|||
bool ok = js::Call(cx, fval, frame, &rval);
|
||||
JSTrapStatus st = dbg->processHandlerResult(ac, ok, rval, iter.abstractFramePtr(),
|
||||
iter.pc(), vp);
|
||||
if (st != JSTRAP_CONTINUE)
|
||||
if (st != JSTRAP_CONTINUE) {
|
||||
savedExc.drop();
|
||||
return st;
|
||||
}
|
||||
}
|
||||
|
||||
vp.setUndefined();
|
||||
if (exceptionPending)
|
||||
cx->setPendingException(exception);
|
||||
return JSTRAP_CONTINUE;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -158,9 +158,12 @@ ForOfIterator::closeThrow()
|
|||
MOZ_ASSERT(iterator);
|
||||
|
||||
RootedValue completionException(cx_);
|
||||
RootedSavedFrame completionExceptionStack(cx_);
|
||||
if (cx_->isExceptionPending()) {
|
||||
if (!GetAndClearException(cx_, &completionException))
|
||||
if (!GetAndClearExceptionAndStack(cx_, &completionException, &completionExceptionStack)) {
|
||||
completionException.setUndefined();
|
||||
completionExceptionStack = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// Steps 1-2 (implicit)
|
||||
|
|
@ -172,7 +175,7 @@ ForOfIterator::closeThrow()
|
|||
|
||||
// Step 4.
|
||||
if (returnVal.isUndefined()) {
|
||||
cx_->setPendingException(completionException);
|
||||
cx_->setPendingException(completionException, completionExceptionStack);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -195,7 +198,7 @@ ForOfIterator::closeThrow()
|
|||
}
|
||||
|
||||
// Step 6.
|
||||
cx_->setPendingException(completionException);
|
||||
cx_->setPendingException(completionException, completionExceptionStack);
|
||||
|
||||
// Steps 7-9 (skipped).
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -10,7 +10,9 @@
|
|||
#include "jsatominlines.h"
|
||||
#include "jsscriptinlines.h"
|
||||
|
||||
#include "vm/ArrayObject-inl.h"
|
||||
#include "vm/NativeObject-inl.h"
|
||||
#include "vm/UnboxedObject-inl.h"
|
||||
#include "vm/Stack-inl.h"
|
||||
|
||||
using namespace js;
|
||||
|
|
@ -66,7 +68,7 @@ GeneratorObject::suspend(JSContext* cx, HandleObject obj, AbstractFramePtr frame
|
|||
MOZ_ASSERT(*pc == JSOP_INITIALYIELD || *pc == JSOP_YIELD || *pc == JSOP_AWAIT);
|
||||
|
||||
Rooted<GeneratorObject*> genObj(cx, &obj->as<GeneratorObject>());
|
||||
MOZ_ASSERT(!genObj->hasExpressionStack());
|
||||
MOZ_ASSERT(!genObj->hasExpressionStack() || genObj->isExpressionStackEmpty());
|
||||
MOZ_ASSERT_IF(*pc == JSOP_AWAIT, genObj->callee().isAsync());
|
||||
MOZ_ASSERT_IF(*pc == JSOP_YIELD,
|
||||
genObj->callee().isStarGenerator() ||
|
||||
|
|
@ -78,16 +80,33 @@ GeneratorObject::suspend(JSContext* cx, HandleObject obj, AbstractFramePtr frame
|
|||
return false;
|
||||
}
|
||||
|
||||
ArrayObject* stack = nullptr;
|
||||
if (nvalues) {
|
||||
do {
|
||||
if (genObj->hasExpressionStack()) {
|
||||
MOZ_ASSERT(genObj->expressionStack().getDenseInitializedLength() == 0);
|
||||
auto result = SetOrExtendAnyBoxedOrUnboxedDenseElements(cx,
|
||||
&genObj->expressionStack().as<JSObject>(),
|
||||
0, vp, nvalues, ShouldUpdateTypes::DontUpdate);
|
||||
if (result == DenseElementResult::Success) {
|
||||
MOZ_ASSERT(genObj->expressionStack().getDenseInitializedLength() == nvalues);
|
||||
break;
|
||||
}
|
||||
if (result == DenseElementResult::Failure)
|
||||
return false;
|
||||
}
|
||||
|
||||
stack = NewDenseCopiedArray(cx, nvalues, vp);
|
||||
if (!stack)
|
||||
return false;
|
||||
} while (false);
|
||||
}
|
||||
|
||||
uint32_t yieldAndAwaitIndex = GET_UINT24(pc);
|
||||
genObj->setYieldAndAwaitIndex(yieldAndAwaitIndex);
|
||||
genObj->setEnvironmentChain(*frame.environmentChain());
|
||||
|
||||
if (nvalues) {
|
||||
ArrayObject* stack = NewDenseCopiedArray(cx, nvalues, vp);
|
||||
if (!stack)
|
||||
return false;
|
||||
if (stack)
|
||||
genObj->setExpressionStack(*stack);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -131,7 +150,7 @@ js::GeneratorThrowOrClose(JSContext* cx, AbstractFramePtr frame, Handle<Generato
|
|||
HandleValue arg, uint32_t resumeKind)
|
||||
{
|
||||
if (resumeKind == GeneratorObject::THROW) {
|
||||
cx->setPendingException(arg);
|
||||
cx->setPendingExceptionAndCaptureStack(arg);
|
||||
genObj->setRunning();
|
||||
} else {
|
||||
MOZ_ASSERT(resumeKind == GeneratorObject::CLOSE);
|
||||
|
|
@ -143,7 +162,8 @@ js::GeneratorThrowOrClose(JSContext* cx, AbstractFramePtr frame, Handle<Generato
|
|||
MOZ_ASSERT(arg.isUndefined());
|
||||
}
|
||||
|
||||
cx->setPendingException(MagicValue(JS_GENERATOR_CLOSING));
|
||||
RootedValue closing(cx, MagicValue(JS_GENERATOR_CLOSING));
|
||||
cx->setPendingException(closing, nullptr);
|
||||
genObj->setClosing();
|
||||
}
|
||||
return false;
|
||||
|
|
@ -166,13 +186,13 @@ GeneratorObject::resume(JSContext* cx, InterpreterActivation& activation,
|
|||
if (genObj->hasArgsObj())
|
||||
activation.regs().fp()->initArgsObj(genObj->argsObj());
|
||||
|
||||
if (genObj->hasExpressionStack()) {
|
||||
uint32_t len = genObj->expressionStack().length();
|
||||
if (genObj->hasExpressionStack() && !genObj->isExpressionStackEmpty()) {
|
||||
uint32_t len = genObj->expressionStack().getDenseInitializedLength();
|
||||
MOZ_ASSERT(activation.regs().spForStackDepth(len));
|
||||
const Value* src = genObj->expressionStack().getDenseElements();
|
||||
mozilla::PodCopy(activation.regs().sp, src, len);
|
||||
activation.regs().sp += len;
|
||||
genObj->clearExpressionStack();
|
||||
genObj->expressionStack().setDenseInitializedLength(0);
|
||||
}
|
||||
|
||||
JSScript* script = callee->nonLazyScript();
|
||||
|
|
|
|||
|
|
@ -99,6 +99,9 @@ class GeneratorObject : public NativeObject
|
|||
bool hasExpressionStack() const {
|
||||
return getFixedSlot(EXPRESSION_STACK_SLOT).isObject();
|
||||
}
|
||||
bool isExpressionStackEmpty() const {
|
||||
return expressionStack().getDenseInitializedLength() == 0;
|
||||
}
|
||||
ArrayObject& expressionStack() const {
|
||||
return getFixedSlot(EXPRESSION_STACK_SLOT).toObject().as<ArrayObject>();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ struct ProtoTableEntry {
|
|||
|
||||
namespace js {
|
||||
|
||||
#define DECLARE_PROTOTYPE_CLASS_INIT(name,code,init,clasp) \
|
||||
#define DECLARE_PROTOTYPE_CLASS_INIT(name,init,clasp) \
|
||||
extern JSObject* init(JSContext* cx, Handle<JSObject*> obj);
|
||||
JS_FOR_EACH_PROTOTYPE(DECLARE_PROTOTYPE_CLASS_INIT)
|
||||
#undef DECLARE_PROTOTYPE_CLASS_INIT
|
||||
|
|
@ -65,8 +65,8 @@ js::InitViaClassSpec(JSContext* cx, Handle<JSObject*> obj)
|
|||
}
|
||||
|
||||
static const ProtoTableEntry protoTable[JSProto_LIMIT] = {
|
||||
#define INIT_FUNC(name,code,init,clasp) { clasp, init },
|
||||
#define INIT_FUNC_DUMMY(name,code,init,clasp) { nullptr, nullptr },
|
||||
#define INIT_FUNC(name,init,clasp) { clasp, init },
|
||||
#define INIT_FUNC_DUMMY(name,init,clasp) { nullptr, nullptr },
|
||||
JS_FOR_PROTOTYPES(INIT_FUNC, INIT_FUNC_DUMMY)
|
||||
#undef INIT_FUNC_DUMMY
|
||||
#undef INIT_FUNC
|
||||
|
|
@ -93,21 +93,20 @@ js::GlobalObject::getTypedObjectModule() const {
|
|||
/* static */ bool
|
||||
GlobalObject::skipDeselectedConstructor(JSContext* cx, JSProtoKey key)
|
||||
{
|
||||
if (key == JSProto_WebAssembly)
|
||||
// Return true if the given constructor has been disabled at run-time.
|
||||
switch (key) {
|
||||
case JSProto_WebAssembly:
|
||||
return !wasm::HasSupport(cx);
|
||||
|
||||
#ifdef ENABLE_SHARED_ARRAY_BUFFER
|
||||
// Return true if the given constructor has been disabled at run-time.
|
||||
switch (key) {
|
||||
case JSProto_Atomics:
|
||||
case JSProto_SharedArrayBuffer:
|
||||
return !cx->compartment()->creationOptions().getSharedMemoryAndAtomicsEnabled();
|
||||
#endif
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
|
|
|
|||
|
|
@ -1883,7 +1883,7 @@ CASE(EnableInterruptsPseudoOpcode)
|
|||
goto error;
|
||||
goto successful_return_continuation;
|
||||
case JSTRAP_THROW:
|
||||
cx->setPendingException(rval);
|
||||
cx->setPendingExceptionAndCaptureStack(rval);
|
||||
goto error;
|
||||
default:;
|
||||
}
|
||||
|
|
@ -1905,7 +1905,7 @@ CASE(EnableInterruptsPseudoOpcode)
|
|||
goto error;
|
||||
goto successful_return_continuation;
|
||||
case JSTRAP_THROW:
|
||||
cx->setPendingException(rval);
|
||||
cx->setPendingExceptionAndCaptureStack(rval);
|
||||
goto error;
|
||||
default:
|
||||
break;
|
||||
|
|
@ -3825,7 +3825,8 @@ CASE(JSOP_RETSUB)
|
|||
* be necessary, but it seems clearer. And it points out a FIXME:
|
||||
* 350509, due to Igor Bukanov.
|
||||
*/
|
||||
cx->setPendingException(rval);
|
||||
ReservedRooted<Value> v(&rootValue0, rval);
|
||||
cx->setPendingExceptionAndCaptureStack(v);
|
||||
goto error;
|
||||
}
|
||||
MOZ_ASSERT(rval.isInt32());
|
||||
|
|
@ -4331,7 +4332,7 @@ bool
|
|||
js::Throw(JSContext* cx, HandleValue v)
|
||||
{
|
||||
MOZ_ASSERT(!cx->isExceptionPending());
|
||||
cx->setPendingException(v);
|
||||
cx->setPendingExceptionAndCaptureStack(v);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -4342,7 +4343,7 @@ js::ThrowingOperation(JSContext* cx, HandleValue v)
|
|||
// execution instead of calling the (JIT) exception handler.
|
||||
|
||||
MOZ_ASSERT(!cx->isExceptionPending());
|
||||
cx->setPendingException(v);
|
||||
cx->setPendingExceptionAndCaptureStack(v);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -4548,16 +4549,25 @@ js::ThrowMsgOperation(JSContext* cx, const unsigned errorNum)
|
|||
}
|
||||
|
||||
bool
|
||||
js::GetAndClearException(JSContext* cx, MutableHandleValue res)
|
||||
js::GetAndClearExceptionAndStack(JSContext* cx, MutableHandleValue res,
|
||||
MutableHandleSavedFrame stack)
|
||||
{
|
||||
if (!cx->getPendingException(res))
|
||||
return false;
|
||||
stack.set(cx->getPendingExceptionStack());
|
||||
cx->clearPendingException();
|
||||
|
||||
// Allow interrupting deeply nested exception handling.
|
||||
return CheckForInterrupt(cx);
|
||||
}
|
||||
|
||||
bool
|
||||
js::GetAndClearException(JSContext* cx, MutableHandleValue res)
|
||||
{
|
||||
RootedSavedFrame stack(cx);
|
||||
return GetAndClearExceptionAndStack(cx, res, &stack);
|
||||
}
|
||||
|
||||
template <bool strict>
|
||||
bool
|
||||
js::DeletePropertyJit(JSContext* cx, HandleValue v, HandlePropertyName name, bool* bp)
|
||||
|
|
|
|||
|
|
@ -489,6 +489,9 @@ ThrowMsgOperation(JSContext* cx, const unsigned errorNum);
|
|||
bool
|
||||
GetAndClearException(JSContext* cx, MutableHandleValue res);
|
||||
|
||||
bool
|
||||
GetAndClearExceptionAndStack(JSContext* cx, MutableHandleValue res, MutableHandleSavedFrame stack);
|
||||
|
||||
bool
|
||||
DeleteNameOperation(JSContext* cx, HandlePropertyName name, HandleObject scopeObj,
|
||||
MutableHandleValue res);
|
||||
|
|
|
|||
|
|
@ -242,6 +242,23 @@ NativeObject::getDenseOrTypedArrayElement(uint32_t idx)
|
|||
return getDenseElement(idx);
|
||||
}
|
||||
|
||||
/* static */ inline NativeObject*
|
||||
NativeObject::createWithTemplate(JSContext* cx, gc::InitialHeap heap,
|
||||
HandleObject templateObject)
|
||||
{
|
||||
RootedObjectGroup group(cx, templateObject->group());
|
||||
RootedShape shape(cx, templateObject->as<NativeObject>().lastProperty());
|
||||
|
||||
gc::AllocKind kind = gc::GetGCObjectKind(shape->numFixedSlots());
|
||||
MOZ_ASSERT(CanBeFinalizedInBackground(kind, shape->getObjectClass()));
|
||||
kind = gc::GetBackgroundAllocKind(kind);
|
||||
|
||||
JSObject* baseObj = create(cx, kind, heap, shape, group);
|
||||
if (!baseObj)
|
||||
return nullptr;
|
||||
return &baseObj->as<NativeObject>();
|
||||
}
|
||||
|
||||
/* static */ inline NativeObject*
|
||||
NativeObject::copy(ExclusiveContext* cx, gc::AllocKind kind, gc::InitialHeap heap,
|
||||
HandleNativeObject templateObject)
|
||||
|
|
|
|||
|
|
@ -1675,6 +1675,41 @@ js::NativeDefineProperty(ExclusiveContext* cx, HandleNativeObject obj, PropertyN
|
|||
return NativeDefineProperty(cx, obj, id, value, getter, setter, attrs);
|
||||
}
|
||||
|
||||
bool
|
||||
js::NativeDefineDataProperty(JSContext* cx, Handle<NativeObject*> obj, HandleId id, HandleValue value,
|
||||
unsigned attrs, ObjectOpResult& result)
|
||||
{
|
||||
Rooted<PropertyDescriptor> desc(cx);
|
||||
desc.initFields(nullptr, value, attrs, nullptr, nullptr);
|
||||
return NativeDefineProperty(cx, obj, id, desc, result);
|
||||
}
|
||||
|
||||
bool
|
||||
js::NativeDefineDataProperty(JSContext* cx, Handle<NativeObject*> obj, HandleId id, HandleValue value,
|
||||
unsigned attrs)
|
||||
{
|
||||
ObjectOpResult result;
|
||||
if (!NativeDefineDataProperty(cx, obj, id, value, attrs, result)) {
|
||||
return false;
|
||||
}
|
||||
if (!result) {
|
||||
// Off-thread callers should not get here: they must call this
|
||||
// function only with known-valid arguments. Populating a new
|
||||
// PlainObject with configurable properties is fine.
|
||||
MOZ_ASSERT(!cx->isHelperThreadContext());
|
||||
result.reportError(cx, obj, id);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
js::NativeDefineDataProperty(JSContext* cx, Handle<NativeObject*> obj, PropertyName* name, HandleValue value,
|
||||
unsigned attrs)
|
||||
{
|
||||
RootedId id(cx, NameToId(name));
|
||||
return NativeDefineDataProperty(cx, obj, id, value, attrs);
|
||||
}
|
||||
|
||||
/*** [[HasProperty]] *****************************************************************************/
|
||||
|
||||
|
|
|
|||
|
|
@ -485,6 +485,9 @@ class NativeObject : public ShapedObject
|
|||
return cells && cells->hasCell(cell);
|
||||
}
|
||||
|
||||
static inline NativeObject*
|
||||
createWithTemplate(JSContext* cx, js::gc::InitialHeap heap, HandleObject templateObject);
|
||||
|
||||
protected:
|
||||
#ifdef DEBUG
|
||||
void checkShapeConsistency();
|
||||
|
|
@ -1399,6 +1402,18 @@ NativeDefineProperty(ExclusiveContext* cx, HandleNativeObject obj, PropertyName*
|
|||
HandleValue value, JSGetterOp getter, JSSetterOp setter,
|
||||
unsigned attrs);
|
||||
|
||||
bool
|
||||
NativeDefineDataProperty(JSContext* cx, Handle<NativeObject*> obj, HandleId id, HandleValue value,
|
||||
unsigned attrs, ObjectOpResult& result);
|
||||
|
||||
extern bool
|
||||
NativeDefineDataProperty(JSContext* cx, Handle<NativeObject*> obj, HandleId id,
|
||||
HandleValue value, unsigned attrs);
|
||||
|
||||
extern bool
|
||||
NativeDefineDataProperty(JSContext* cx, Handle<NativeObject*> obj, PropertyName* name,
|
||||
HandleValue value, unsigned attrs);
|
||||
|
||||
extern bool
|
||||
NativeHasProperty(JSContext* cx, HandleNativeObject obj, HandleId id, bool* foundp);
|
||||
|
||||
|
|
|
|||
|
|
@ -970,6 +970,7 @@ RegExpShared::trace(JSTracer* trc)
|
|||
TraceNullableEdge(trc, &source, "RegExpShared source");
|
||||
for (auto& comp : compilationArray)
|
||||
TraceNullableEdge(trc, &comp.jitCode, "RegExpShared code");
|
||||
TraceNullableEdge(trc, &groupsTemplate_, "RegExpShared groupsTemplate");
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
|||
|
|
@ -548,7 +548,7 @@ InvokeInterruptCallback(JSContext* cx)
|
|||
Debugger::propagateForcedReturn(cx, iter.abstractFramePtr(), rval);
|
||||
return false;
|
||||
case JSTRAP_THROW:
|
||||
cx->setPendingException(rval);
|
||||
cx->setPendingExceptionAndCaptureStack(rval);
|
||||
return false;
|
||||
default:;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -169,7 +169,7 @@ struct JSAtomState
|
|||
#define PROPERTYNAME_FIELD(idpart, id, text) js::ImmutablePropertyNamePtr id;
|
||||
FOR_EACH_COMMON_PROPERTYNAME(PROPERTYNAME_FIELD)
|
||||
#undef PROPERTYNAME_FIELD
|
||||
#define PROPERTYNAME_FIELD(name, code, init, clasp) js::ImmutablePropertyNamePtr name;
|
||||
#define PROPERTYNAME_FIELD(name, init, clasp) js::ImmutablePropertyNamePtr name;
|
||||
JS_FOR_EACH_PROTOTYPE(PROPERTYNAME_FIELD)
|
||||
#undef PROPERTYNAME_FIELD
|
||||
#define PROPERTYNAME_FIELD(name) js::ImmutablePropertyNamePtr name;
|
||||
|
|
|
|||
|
|
@ -601,23 +601,6 @@ intrinsic_FinishBoundFunctionInit(JSContext* cx, unsigned argc, Value* vp)
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
intrinsic_SetPrototype(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
MOZ_ASSERT(args.length() == 2);
|
||||
MOZ_ASSERT(args[0].isObject());
|
||||
MOZ_ASSERT(args[1].isObjectOrNull());
|
||||
|
||||
RootedObject obj(cx, &args[0].toObject());
|
||||
RootedObject proto(cx, args[1].toObjectOrNull());
|
||||
if (!SetPrototype(cx, obj, proto))
|
||||
return false;
|
||||
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Used to decompile values in the nearest non-builtin stack frame, falling
|
||||
* back to decompiling in the current frame. Helpful for printing higher-order
|
||||
|
|
@ -768,34 +751,6 @@ intrinsic_UnsafeGetBooleanFromReservedSlot(JSContext* cx, unsigned argc, Value*
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Intrinsic for creating an empty array in the compartment of the object
|
||||
* passed as the first argument.
|
||||
*
|
||||
* Returns the array, wrapped in the default wrapper to use between the two
|
||||
* compartments.
|
||||
*/
|
||||
static bool
|
||||
intrinsic_NewArrayInCompartment(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
MOZ_ASSERT(args.length() == 1);
|
||||
RootedObject wrapped(cx, &args[0].toObject());
|
||||
MOZ_ASSERT(IsWrapper(wrapped));
|
||||
RootedObject obj(cx, UncheckedUnwrap(wrapped));
|
||||
|
||||
RootedArrayObject arr(cx);
|
||||
{
|
||||
AutoCompartment ac(cx, obj);
|
||||
arr = NewDenseEmptyArray(cx);
|
||||
if (!arr)
|
||||
return false;
|
||||
}
|
||||
|
||||
args.rval().setObject(*arr);
|
||||
return wrapped->compartment()->wrap(cx, args.rval());
|
||||
}
|
||||
|
||||
static bool
|
||||
intrinsic_IsPackedArray(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
|
|
@ -2189,8 +2144,6 @@ static const JSFunctionSpec intrinsic_functions[] = {
|
|||
JS_INLINABLE_FN("std_Math_max", math_max, 2,0, MathMax),
|
||||
JS_INLINABLE_FN("std_Math_min", math_min, 2,0, MathMin),
|
||||
JS_INLINABLE_FN("std_Math_abs", math_abs, 1,0, MathAbs),
|
||||
JS_INLINABLE_FN("std_Math_imul", math_imul, 2,0, MathImul),
|
||||
JS_INLINABLE_FN("std_Math_log2", math_log2, 1,0, MathLog2),
|
||||
|
||||
JS_FN("std_Map_has", MapObject::has, 1,0),
|
||||
JS_FN("std_Map_iterator", MapObject::entries, 0,0),
|
||||
|
|
@ -2203,7 +2156,6 @@ static const JSFunctionSpec intrinsic_functions[] = {
|
|||
JS_FN("std_Object_getOwnPropertyNames", obj_getOwnPropertyNames, 1,0),
|
||||
JS_FN("std_Object_getOwnPropertyDescriptor", obj_getOwnPropertyDescriptor, 2,0),
|
||||
JS_FN("std_Object_hasOwnProperty", obj_hasOwnProperty, 1,0),
|
||||
JS_FN("std_Object_setPrototypeOf", intrinsic_SetPrototype, 2,0),
|
||||
JS_FN("std_Object_toString", obj_toString, 0,0),
|
||||
|
||||
JS_FN("std_Reflect_getPrototypeOf", Reflect_getPrototypeOf, 1,0),
|
||||
|
|
@ -2265,7 +2217,6 @@ static const JSFunctionSpec intrinsic_functions[] = {
|
|||
JS_INLINABLE_FN("IsCallable", intrinsic_IsCallable, 1,0, IntrinsicIsCallable),
|
||||
JS_INLINABLE_FN("IsConstructor", intrinsic_IsConstructor, 1,0,
|
||||
IntrinsicIsConstructor),
|
||||
JS_FN("IsFunctionObject",intrinsic_IsInstanceOfBuiltin<JSFunction>, 1,0),
|
||||
JS_FN("GetBuiltinConstructorImpl", intrinsic_GetBuiltinConstructor, 1,0),
|
||||
JS_FN("MakeConstructible", intrinsic_MakeConstructible, 2,0),
|
||||
JS_FN("_ConstructFunction", intrinsic_ConstructFunction, 2,0),
|
||||
|
|
@ -2306,8 +2257,6 @@ static const JSFunctionSpec intrinsic_functions[] = {
|
|||
JS_INLINABLE_FN("UnsafeGetBooleanFromReservedSlot", intrinsic_UnsafeGetBooleanFromReservedSlot,2,0,
|
||||
IntrinsicUnsafeGetBooleanFromReservedSlot),
|
||||
|
||||
JS_FN("NewArrayInCompartment", intrinsic_NewArrayInCompartment, 1,0),
|
||||
|
||||
JS_FN("IsPackedArray", intrinsic_IsPackedArray, 1,0),
|
||||
|
||||
JS_FN("GetIteratorPrototype", intrinsic_GetIteratorPrototype, 0,0),
|
||||
|
|
@ -2444,10 +2393,6 @@ static const JSFunctionSpec intrinsic_functions[] = {
|
|||
JS_FN("CallWeakSetMethodIfWrapped",
|
||||
CallNonGenericSelfhostedMethod<Is<WeakSetObject>>, 2, 0),
|
||||
|
||||
JS_FN("Promise_static_resolve", Promise_static_resolve, 1, 0),
|
||||
JS_FN("Promise_static_reject", Promise_reject, 1, 0),
|
||||
JS_FN("Promise_then", Promise_then, 2, 0),
|
||||
|
||||
// See builtin/TypedObject.h for descriptors of the typedobj functions.
|
||||
JS_FN("NewOpaqueTypedObject", js::NewOpaqueTypedObject, 1, 0),
|
||||
JS_FN("NewDerivedTypedObject", js::NewDerivedTypedObject, 3, 0),
|
||||
|
|
|
|||
|
|
@ -620,6 +620,11 @@ class ConstraintTypeSet : public TypeSet
|
|||
*/
|
||||
void addType(ExclusiveContext* cx, Type type);
|
||||
|
||||
/* Generalize to any type. */
|
||||
void makeUnknown(ExclusiveContext* cx) {
|
||||
addType(cx, UnknownType());
|
||||
}
|
||||
|
||||
// Trigger a post barrier when writing to this set, if necessary.
|
||||
// addType(cx, type) takes care of this automatically.
|
||||
void postWriteBarrier(ExclusiveContext* cx, Type type);
|
||||
|
|
|
|||
|
|
@ -1063,65 +1063,28 @@ TypedArrayObjectTemplate<T>::AllocateArrayBuffer(JSContext* cx, HandleValue ctor
|
|||
}
|
||||
|
||||
static bool
|
||||
IsArrayBufferConstructor(const Value& v)
|
||||
IsArrayBufferSpecies(JSContext* cx, JSFunction* species)
|
||||
{
|
||||
return v.isObject() &&
|
||||
v.toObject().is<JSFunction>() &&
|
||||
v.toObject().as<JSFunction>().isNative() &&
|
||||
v.toObject().as<JSFunction>().native() == ArrayBufferObject::class_constructor;
|
||||
return IsSelfHostedFunctionWithName(species, cx->names().ArrayBufferSpecies);
|
||||
}
|
||||
|
||||
static bool
|
||||
IsArrayBufferSpecies(JSContext* cx, HandleObject origBuffer)
|
||||
{
|
||||
RootedValue ctor(cx);
|
||||
if (!GetPropertyPure(cx, origBuffer, NameToId(cx->names().constructor), ctor.address()))
|
||||
return false;
|
||||
|
||||
if (!IsArrayBufferConstructor(ctor))
|
||||
return false;
|
||||
|
||||
RootedObject ctorObj(cx, &ctor.toObject());
|
||||
RootedId speciesId(cx, SYMBOL_TO_JSID(cx->wellKnownSymbols().species));
|
||||
JSFunction* getter;
|
||||
if (!GetGetterPure(cx, ctorObj, speciesId, &getter))
|
||||
return false;
|
||||
|
||||
if (!getter)
|
||||
return false;
|
||||
|
||||
return IsSelfHostedFunctionWithName(getter, cx->names().ArrayBufferSpecies);
|
||||
}
|
||||
|
||||
static bool
|
||||
static JSObject*
|
||||
GetSpeciesConstructor(JSContext* cx, HandleObject obj, bool isWrapped,
|
||||
SpeciesConstructorOverride override, MutableHandleValue ctor)
|
||||
SpeciesConstructorOverride override)
|
||||
{
|
||||
if (!isWrapped) {
|
||||
if (!GlobalObject::ensureConstructor(cx, cx->global(), JSProto_ArrayBuffer))
|
||||
return false;
|
||||
RootedValue defaultCtor(cx, cx->global()->getConstructor(JSProto_ArrayBuffer));
|
||||
// The second disjunct is an optimization.
|
||||
if (override == SpeciesConstructorOverride::ArrayBuffer || IsArrayBufferSpecies(cx, obj))
|
||||
ctor.set(defaultCtor);
|
||||
else if (!SpeciesConstructor(cx, obj, defaultCtor, ctor))
|
||||
return false;
|
||||
if (!GlobalObject::ensureConstructor(cx, cx->global(), JSProto_ArrayBuffer))
|
||||
return nullptr;
|
||||
RootedObject defaultCtor(cx, &cx->global()->getConstructor(JSProto_ArrayBuffer).toObject());
|
||||
|
||||
return true;
|
||||
}
|
||||
// Use the current global's ArrayBuffer if the override is set.
|
||||
if (override == SpeciesConstructorOverride::ArrayBuffer)
|
||||
return defaultCtor;
|
||||
|
||||
{
|
||||
JSAutoCompartment ac(cx, obj);
|
||||
if (!GlobalObject::ensureConstructor(cx, cx->global(), JSProto_ArrayBuffer))
|
||||
return false;
|
||||
RootedValue defaultCtor(cx, cx->global()->getConstructor(JSProto_ArrayBuffer));
|
||||
if (override == SpeciesConstructorOverride::ArrayBuffer)
|
||||
ctor.set(defaultCtor);
|
||||
else if (!SpeciesConstructor(cx, obj, defaultCtor, ctor))
|
||||
return false;
|
||||
}
|
||||
RootedObject wrappedObj(cx, obj);
|
||||
if (isWrapped && !cx->compartment()->wrap(cx, &wrappedObj))
|
||||
return nullptr;
|
||||
|
||||
return JS_WrapValue(cx, ctor);
|
||||
return SpeciesConstructor(cx, wrappedObj, defaultCtor, IsArrayBufferSpecies);
|
||||
}
|
||||
|
||||
// ES 2017 draft rev 8633ffd9394b203b8876bb23cb79aff13eb07310 24.1.1.4.
|
||||
|
|
@ -1137,9 +1100,10 @@ TypedArrayObjectTemplate<T>::CloneArrayBufferNoCopy(JSContext* cx,
|
|||
// Step 1 (skipped).
|
||||
|
||||
// Step 2.a.
|
||||
RootedValue cloneCtor(cx);
|
||||
if (!GetSpeciesConstructor(cx, srcBuffer, isWrapped, override, &cloneCtor))
|
||||
JSObject* ctorObj = GetSpeciesConstructor(cx, srcBuffer, isWrapped, override);
|
||||
if (!ctorObj)
|
||||
return false;
|
||||
RootedValue cloneCtor(cx, ObjectValue(*ctorObj));
|
||||
|
||||
// Step 2.b.
|
||||
if (srcBuffer->isDetached()) {
|
||||
|
|
@ -1181,7 +1145,8 @@ TypedArrayObjectTemplate<T>::fromArray(JSContext* cx, HandleObject other,
|
|||
return fromObject(cx, other, newTarget);
|
||||
}
|
||||
|
||||
// ES 2017 draft rev 8633ffd9394b203b8876bb23cb79aff13eb07310 22.2.4.3.
|
||||
// ES2017 draft rev 6390c2f1b34b309895d31d8c0512eac8660a0210
|
||||
// 22.2.4.3 TypedArray ( typedArray )
|
||||
template<typename T>
|
||||
/* static */ JSObject*
|
||||
TypedArrayObjectTemplate<T>::fromTypedArray(JSContext* cx, HandleObject other, bool isWrapped,
|
||||
|
|
@ -1229,61 +1194,62 @@ TypedArrayObjectTemplate<T>::fromTypedArray(JSContext* cx, HandleObject other, b
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
// Steps 10.
|
||||
// Step 9.
|
||||
uint32_t elementLength = srcArray->length();
|
||||
|
||||
// Steps 11-12.
|
||||
// Steps 10-11.
|
||||
Scalar::Type srcType = srcArray->type();
|
||||
|
||||
// Step 13 (skipped).
|
||||
// Step 12 (skipped).
|
||||
|
||||
// Step 14.
|
||||
// Step 13.
|
||||
uint32_t srcByteOffset = srcArray->byteOffset();
|
||||
|
||||
// Step 17, modified for SharedArrayBuffer.
|
||||
// Steps 16-17.
|
||||
bool isShared = srcArray->isSharedMemory();
|
||||
SpeciesConstructorOverride override = isShared ? SpeciesConstructorOverride::ArrayBuffer
|
||||
: SpeciesConstructorOverride::None;
|
||||
|
||||
// Steps 8-9, 17.
|
||||
// Steps 8, 16-17.
|
||||
Rooted<ArrayBufferObject*> buffer(cx);
|
||||
if (ArrayTypeID() == srcType) {
|
||||
// Step 17.a.
|
||||
// Step 16.a.
|
||||
uint32_t srcLength = srcArray->byteLength();
|
||||
|
||||
// Step 17.b, modified for SharedArrayBuffer
|
||||
// Steps 16.b-c.
|
||||
if (!CloneArrayBufferNoCopy(cx, srcData, isWrapped, srcByteOffset, srcLength, override,
|
||||
&buffer))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
} else {
|
||||
// Step 18.a, modified for SharedArrayBuffer
|
||||
RootedValue bufferCtor(cx);
|
||||
if (!GetSpeciesConstructor(cx, srcData, isWrapped, override, &bufferCtor))
|
||||
// Steps 17.a-b.
|
||||
JSObject* ctorObj = GetSpeciesConstructor(cx, srcData, isWrapped, override);
|
||||
if (!ctorObj)
|
||||
return nullptr;
|
||||
RootedValue bufferCtor(cx, ObjectValue(*ctorObj));
|
||||
|
||||
// Step 15-16, 18.b.
|
||||
// Steps 14-15, 17.c.
|
||||
if (!AllocateArrayBuffer(cx, bufferCtor, elementLength, BYTES_PER_ELEMENT, &buffer))
|
||||
return nullptr;
|
||||
|
||||
// Step 18.c.
|
||||
// Step 17.d.
|
||||
if (srcArray->hasDetachedBuffer()) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// Steps 3, 4 (remaining part), 19-22.
|
||||
// Steps 3-4 (remaining part), 18-21.
|
||||
Rooted<TypedArrayObject*> obj(cx, makeInstance(cx, buffer, 0, elementLength, proto));
|
||||
if (!obj)
|
||||
return nullptr;
|
||||
|
||||
// Step 18.d-g or 24.1.1.4 step 11.
|
||||
// Steps 17.e-h or 24.1.1.4 step 8.
|
||||
if (!TypedArrayMethods<TypedArrayObject>::setFromTypedArray(cx, obj, srcArray))
|
||||
return nullptr;
|
||||
|
||||
// Step 23.
|
||||
// Step 22.
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1729,7 +1729,8 @@ RejectWithPendingException(JSContext* cx, Handle<PromiseObject*> promise)
|
|||
return false;
|
||||
|
||||
RootedValue rejectionValue(cx);
|
||||
if (!GetAndClearException(cx, &rejectionValue))
|
||||
RootedSavedFrame stack(cx);
|
||||
if (!GetAndClearExceptionAndStack(cx, &rejectionValue, &stack))
|
||||
return false;
|
||||
|
||||
return PromiseObject::reject(cx, promise, rejectionValue);
|
||||
|
|
|
|||
|
|
@ -2310,7 +2310,7 @@ nsXPCComponents_Utils::ReportError(HandleValue error, JSContext* cx)
|
|||
|
||||
if (errorObj) {
|
||||
JS::RootedObject stackVal(cx,
|
||||
FindExceptionStackForConsoleReport(win, error));
|
||||
FindExceptionStackForConsoleReport(win, error, nullptr));
|
||||
if (stackVal) {
|
||||
scripterr = new nsScriptErrorWithStack(stackVal);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -590,11 +590,13 @@ class ErrorReport : public ErrorBase {
|
|||
|
||||
void
|
||||
DispatchScriptErrorEvent(nsPIDOMWindowInner* win, JS::RootingContext* rootingCx,
|
||||
xpc::ErrorReport* xpcReport, JS::Handle<JS::Value> exception);
|
||||
xpc::ErrorReport* xpcReport, JS::Handle<JS::Value> exception,
|
||||
JS::Handle<JSObject*> exceptionStack);
|
||||
|
||||
// Get a stack of the sort that can be passed to
|
||||
// xpc::ErrorReport::LogToConsoleWithStack from the given exception value. Can
|
||||
// return null if the exception value doesn't have an associated stack. The
|
||||
// be nullptr if the exception value doesn't have an associated stack, and if
|
||||
// there is no stack supplied by the JS engine in exceptionStack. The
|
||||
// returned stack, if any, may also not be in the same compartment as
|
||||
// exceptionValue.
|
||||
//
|
||||
|
|
@ -605,7 +607,8 @@ DispatchScriptErrorEvent(nsPIDOMWindowInner* win, JS::RootingContext* rootingCx,
|
|||
// the stack in the console message keeping the window alive.
|
||||
JSObject*
|
||||
FindExceptionStackForConsoleReport(nsPIDOMWindowInner* win,
|
||||
JS::HandleValue exceptionValue);
|
||||
JS::HandleValue exceptionValue,
|
||||
JS::HandleObject exceptionStack);
|
||||
|
||||
// Return a name for the compartment.
|
||||
// This function makes reasonable efforts to make this name both mostly human-readable
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue