зеркало из https://github.com/mozilla/gecko-dev.git
merge mozilla-central to autoland. r=merge a=merge
This commit is contained in:
Коммит
0714f6271f
|
@ -149,76 +149,68 @@ CallbackObject::CallSetup::CallSetup(CallbackObject* aCallback,
|
|||
JSObject* realCallback = js::UncheckedUnwrap(wrappedCallback);
|
||||
nsIGlobalObject* globalObject = nullptr;
|
||||
|
||||
JSContext* cx;
|
||||
{
|
||||
// Bug 955660: we cannot do "proper" rooting here because we need the
|
||||
// global to get a context. Everything here is simple getters that cannot
|
||||
// GC, so just paper over the necessary dataflow inversion.
|
||||
JS::AutoSuppressGCAnalysis nogc;
|
||||
|
||||
// Now get the global for this callback. Note that for the case of
|
||||
// JS-implemented WebIDL we never have a window here.
|
||||
nsGlobalWindow* win = mIsMainThread && !aIsJSImplementedWebIDL
|
||||
? xpc::WindowGlobalOrNull(realCallback)
|
||||
: nullptr;
|
||||
if (win) {
|
||||
MOZ_ASSERT(win->IsInnerWindow());
|
||||
// We don't want to run script in windows that have been navigated away
|
||||
// from.
|
||||
if (!win->AsInner()->HasActiveDocument()) {
|
||||
aRv.ThrowDOMException(NS_ERROR_DOM_NOT_SUPPORTED_ERR,
|
||||
NS_LITERAL_CSTRING("Refusing to execute function from window "
|
||||
"whose document is no longer active."));
|
||||
return;
|
||||
}
|
||||
globalObject = win;
|
||||
} else {
|
||||
// No DOM Window. Store the global.
|
||||
JSObject* global = js::GetGlobalForObjectCrossCompartment(realCallback);
|
||||
globalObject = xpc::NativeGlobal(global);
|
||||
MOZ_ASSERT(globalObject);
|
||||
}
|
||||
|
||||
// Bail out if there's no useful global. This seems to happen intermittently
|
||||
// on gaia-ui tests, probably because nsInProcessTabChildGlobal is returning
|
||||
// null in some kind of teardown state.
|
||||
if (!globalObject->GetGlobalJSObject()) {
|
||||
// Now get the global for this callback. Note that for the case of
|
||||
// JS-implemented WebIDL we never have a window here.
|
||||
nsGlobalWindow* win = mIsMainThread && !aIsJSImplementedWebIDL
|
||||
? xpc::WindowGlobalOrNull(realCallback)
|
||||
: nullptr;
|
||||
if (win) {
|
||||
MOZ_ASSERT(win->IsInnerWindow());
|
||||
// We don't want to run script in windows that have been navigated away
|
||||
// from.
|
||||
if (!win->AsInner()->HasActiveDocument()) {
|
||||
aRv.ThrowDOMException(NS_ERROR_DOM_NOT_SUPPORTED_ERR,
|
||||
NS_LITERAL_CSTRING("Refusing to execute function from global which is "
|
||||
"being torn down."));
|
||||
NS_LITERAL_CSTRING("Refusing to execute function from window "
|
||||
"whose document is no longer active."));
|
||||
return;
|
||||
}
|
||||
globalObject = win;
|
||||
} else {
|
||||
// No DOM Window. Store the global.
|
||||
JSObject* global = js::GetGlobalForObjectCrossCompartment(realCallback);
|
||||
globalObject = xpc::NativeGlobal(global);
|
||||
MOZ_ASSERT(globalObject);
|
||||
}
|
||||
|
||||
mAutoEntryScript.emplace(globalObject, aExecutionReason, mIsMainThread);
|
||||
mAutoEntryScript->SetWebIDLCallerPrincipal(webIDLCallerPrincipal);
|
||||
nsIGlobalObject* incumbent = aCallback->IncumbentGlobalOrNull();
|
||||
if (incumbent) {
|
||||
// The callback object traces its incumbent JS global, so in general it
|
||||
// should be alive here. However, it's possible that we could run afoul
|
||||
// of the same IPC global weirdness described above, wherein the
|
||||
// nsIGlobalObject has severed its reference to the JS global. Let's just
|
||||
// be safe here, so that nobody has to waste a day debugging gaia-ui tests.
|
||||
if (!incumbent->GetGlobalJSObject()) {
|
||||
// Bail out if there's no useful global. This seems to happen intermittently
|
||||
// on gaia-ui tests, probably because nsInProcessTabChildGlobal is returning
|
||||
// null in some kind of teardown state.
|
||||
if (!globalObject->GetGlobalJSObject()) {
|
||||
aRv.ThrowDOMException(NS_ERROR_DOM_NOT_SUPPORTED_ERR,
|
||||
NS_LITERAL_CSTRING("Refusing to execute function from global which is "
|
||||
"being torn down."));
|
||||
return;
|
||||
}
|
||||
|
||||
mAutoEntryScript.emplace(globalObject, aExecutionReason, mIsMainThread);
|
||||
mAutoEntryScript->SetWebIDLCallerPrincipal(webIDLCallerPrincipal);
|
||||
nsIGlobalObject* incumbent = aCallback->IncumbentGlobalOrNull();
|
||||
if (incumbent) {
|
||||
// The callback object traces its incumbent JS global, so in general it
|
||||
// should be alive here. However, it's possible that we could run afoul
|
||||
// of the same IPC global weirdness described above, wherein the
|
||||
// nsIGlobalObject has severed its reference to the JS global. Let's just
|
||||
// be safe here, so that nobody has to waste a day debugging gaia-ui tests.
|
||||
if (!incumbent->GetGlobalJSObject()) {
|
||||
aRv.ThrowDOMException(NS_ERROR_DOM_NOT_SUPPORTED_ERR,
|
||||
NS_LITERAL_CSTRING("Refusing to execute function because our "
|
||||
"incumbent global is being torn down."));
|
||||
return;
|
||||
}
|
||||
mAutoIncumbentScript.emplace(incumbent);
|
||||
return;
|
||||
}
|
||||
|
||||
cx = mAutoEntryScript->cx();
|
||||
|
||||
// Unmark the callable (by invoking CallbackOrNull() and not the
|
||||
// CallbackPreserveColor() variant), and stick it in a Rooted before it can
|
||||
// go gray again.
|
||||
// Nothing before us in this function can trigger a CC, so it's safe to wait
|
||||
// until here it do the unmark. This allows us to construct mRootedCallable
|
||||
// with the cx from mAutoEntryScript, avoiding the cost of finding another
|
||||
// JSContext. (Rooted<> does not care about requests or compartments.)
|
||||
mRootedCallable.emplace(cx, aCallback->CallbackOrNull());
|
||||
mAutoIncumbentScript.emplace(incumbent);
|
||||
}
|
||||
|
||||
JSContext* cx = mAutoEntryScript->cx();
|
||||
|
||||
// Unmark the callable (by invoking CallbackOrNull() and not the
|
||||
// CallbackPreserveColor() variant), and stick it in a Rooted before it can
|
||||
// go gray again.
|
||||
// Nothing before us in this function can trigger a CC, so it's safe to wait
|
||||
// until here it do the unmark. This allows us to construct mRootedCallable
|
||||
// with the cx from mAutoEntryScript, avoiding the cost of finding another
|
||||
// JSContext. (Rooted<> does not care about requests or compartments.)
|
||||
mRootedCallable.emplace(cx, aCallback->CallbackOrNull());
|
||||
|
||||
// JS-implemented WebIDL is always OK to run, since it runs with Chrome
|
||||
// privileges anyway.
|
||||
if (mIsMainThread && !aIsJSImplementedWebIDL) {
|
||||
|
|
|
@ -327,6 +327,10 @@ HTMLEditor::ShowGrabberOnElement(nsIDOMElement* aElement)
|
|||
nsCOMPtr<Element> element = do_QueryInterface(aElement);
|
||||
NS_ENSURE_ARG_POINTER(element);
|
||||
|
||||
if (NS_WARN_IF(!IsDescendantOfEditorRoot(element))) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
if (mGrabber) {
|
||||
NS_ERROR("call HideGrabber first");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
|
|
|
@ -304,6 +304,10 @@ HTMLEditor::ShowResizersInner(Element& aResizedElement)
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(!IsDescendantOfEditorRoot(&aResizedElement))) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
mResizedObject = &aResizedElement;
|
||||
|
||||
// The resizers and the shadow will be anonymous siblings of the element.
|
||||
|
|
|
@ -48,10 +48,15 @@ HTMLEditor::ShowInlineTableEditingUI(nsIDOMElement* aCell)
|
|||
NS_ENSURE_ARG_POINTER(aCell);
|
||||
|
||||
// do nothing if aCell is not a table cell...
|
||||
if (!HTMLEditUtils::IsTableCell(aCell)) {
|
||||
nsCOMPtr<Element> cell = do_QueryInterface(aCell);
|
||||
if (!cell || !HTMLEditUtils::IsTableCell(cell)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(!IsDescendantOfEditorRoot(cell))) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
if (mInlineEditedCell) {
|
||||
NS_ERROR("call HideInlineTableEditingUI first");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
|
|
|
@ -571,17 +571,20 @@ WebRenderLayerManager::GenerateFallbackData(nsDisplayItem* aItem,
|
|||
gfx::SurfaceFormat::A8 : gfx::SurfaceFormat::B8G8R8A8;
|
||||
if (!geometry || !invalidRegion.IsEmpty() || fallbackData->IsInvalid()) {
|
||||
if (gfxPrefs::WebRenderBlobImages()) {
|
||||
bool snapped;
|
||||
bool isOpaque = aItem->GetOpaqueRegion(aDisplayListBuilder, &snapped).Contains(clippedBounds);
|
||||
|
||||
RefPtr<gfx::DrawEventRecorderMemory> recorder = MakeAndAddRef<gfx::DrawEventRecorderMemory>();
|
||||
// TODO: should use 'format' to replace gfx::SurfaceFormat::B8G8R8X8. Currently blob image doesn't support A8 format.
|
||||
// TODO: should use 'format' to replace gfx::SurfaceFormat::B8G8R8A8. Currently blob image doesn't support A8 format.
|
||||
RefPtr<gfx::DrawTarget> dummyDt =
|
||||
gfx::Factory::CreateDrawTarget(gfx::BackendType::SKIA, gfx::IntSize(1, 1), gfx::SurfaceFormat::B8G8R8X8);
|
||||
gfx::Factory::CreateDrawTarget(gfx::BackendType::SKIA, gfx::IntSize(1, 1), gfx::SurfaceFormat::B8G8R8A8);
|
||||
RefPtr<gfx::DrawTarget> dt = gfx::Factory::CreateRecordingDrawTarget(recorder, dummyDt, imageSize.ToUnknownSize());
|
||||
PaintItemByDrawTarget(aItem, dt, aImageRect, aOffset, aDisplayListBuilder);
|
||||
recorder->Finish();
|
||||
|
||||
Range<uint8_t> bytes((uint8_t*)recorder->mOutputStream.mData, recorder->mOutputStream.mLength);
|
||||
wr::ImageKey key = WrBridge()->GetNextImageKey();
|
||||
wr::ImageDescriptor descriptor(imageSize.ToUnknownSize(), 0, dt->GetFormat());
|
||||
wr::ImageDescriptor descriptor(imageSize.ToUnknownSize(), 0, dt->GetFormat(), isOpaque);
|
||||
aBuilder.Resources().AddBlobImage(key, descriptor, bytes);
|
||||
fallbackData->SetKey(key);
|
||||
} else {
|
||||
|
|
|
@ -112,6 +112,16 @@ struct ImageDescriptor: public wr::WrImageDescriptor {
|
|||
stride = aByteStride;
|
||||
is_opaque = gfx::IsOpaqueFormat(aFormat);
|
||||
}
|
||||
|
||||
ImageDescriptor(const gfx::IntSize& aSize, uint32_t aByteStride, gfx::SurfaceFormat aFormat, bool opaque)
|
||||
{
|
||||
format = wr::SurfaceFormatToImageFormat(aFormat).value();
|
||||
width = aSize.width;
|
||||
height = aSize.height;
|
||||
stride = aByteStride;
|
||||
is_opaque = opaque;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// Whenever possible, use wr::WindowId instead of manipulating uint64_t.
|
||||
|
|
|
@ -2341,7 +2341,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.
|
||||
|
||||
|
@ -2373,6 +2384,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,
|
||||
|
@ -2391,10 +2408,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))
|
||||
|
@ -3039,11 +3055,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);
|
||||
|
@ -3617,7 +3632,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
|
||||
};
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -92,11 +92,6 @@ CompileStandaloneAsyncGenerator(JSContext* cx, MutableHandleFunction fun,
|
|||
JS::SourceBufferHolder& srcBuf,
|
||||
const mozilla::Maybe<uint32_t>& parameterListEnd);
|
||||
|
||||
MOZ_MUST_USE bool
|
||||
CompileAsyncFunctionBody(JSContext* cx, MutableHandleFunction fun,
|
||||
const ReadOnlyCompileOptions& options,
|
||||
Handle<PropertyNameVector> formals, JS::SourceBufferHolder& srcBuf);
|
||||
|
||||
ScriptSourceObject*
|
||||
CreateScriptSourceObject(JSContext* cx, const ReadOnlyCompileOptions& options,
|
||||
const mozilla::Maybe<uint32_t>& parameterListEnd = mozilla::Nothing());
|
||||
|
|
|
@ -3665,22 +3665,6 @@ BytecodeEmitter::reportExtraWarning(ParseNode* pn, unsigned errorNumber, ...)
|
|||
return result;
|
||||
}
|
||||
|
||||
bool
|
||||
BytecodeEmitter::reportStrictModeError(ParseNode* pn, unsigned errorNumber, ...)
|
||||
{
|
||||
TokenPos pos = pn ? pn->pn_pos : tokenStream().currentToken().pos;
|
||||
|
||||
va_list args;
|
||||
va_start(args, errorNumber);
|
||||
// FIXME: parser.tokenStream() should be a TokenStreamAnyChars for bug 1351107,
|
||||
// but caused problems, cf. bug 1363116.
|
||||
bool result = parser.tokenStream()
|
||||
.reportStrictModeErrorNumberVA(nullptr, pos.begin, sc->strict(),
|
||||
errorNumber, args);
|
||||
va_end(args);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool
|
||||
BytecodeEmitter::emitNewInit(JSProtoKey key)
|
||||
{
|
||||
|
@ -3710,8 +3694,8 @@ BytecodeEmitter::iteratorResultShape(unsigned* shape)
|
|||
if (!obj)
|
||||
return false;
|
||||
|
||||
Rooted<jsid> value_id(cx, AtomToId(cx->names().value));
|
||||
Rooted<jsid> done_id(cx, AtomToId(cx->names().done));
|
||||
Rooted<jsid> value_id(cx, NameToId(cx->names().value));
|
||||
Rooted<jsid> done_id(cx, NameToId(cx->names().done));
|
||||
if (!NativeDefineProperty(cx, obj, value_id, UndefinedHandleValue, nullptr, nullptr,
|
||||
JSPROP_ENUMERATE))
|
||||
{
|
||||
|
@ -3760,18 +3744,6 @@ BytecodeEmitter::emitFinishIteratorResult(bool done)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BytecodeEmitter::emitToIteratorResult(bool done)
|
||||
{
|
||||
if (!emitPrepareIteratorResult()) // VALUE OBJ
|
||||
return false;
|
||||
if (!emit1(JSOP_SWAP)) // OBJ VALUE
|
||||
return false;
|
||||
if (!emitFinishIteratorResult(done)) // RESULT
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BytecodeEmitter::emitGetNameAtLocation(JSAtom* name, const NameLocation& loc, bool callContext)
|
||||
{
|
||||
|
|
|
@ -417,7 +417,6 @@ struct MOZ_STACK_CLASS BytecodeEmitter
|
|||
|
||||
void reportError(ParseNode* pn, unsigned errorNumber, ...);
|
||||
bool reportExtraWarning(ParseNode* pn, unsigned errorNumber, ...);
|
||||
bool reportStrictModeError(ParseNode* pn, unsigned errorNumber, ...);
|
||||
|
||||
// If pn contains a useful expression, return true with *answer set to true.
|
||||
// If pn contains a useless expression, return true with *answer set to
|
||||
|
@ -632,7 +631,6 @@ struct MOZ_STACK_CLASS BytecodeEmitter
|
|||
MOZ_MUST_USE bool emitPrepareIteratorResult();
|
||||
MOZ_MUST_USE bool emitFinishIteratorResult(bool done);
|
||||
MOZ_MUST_USE bool iteratorResultShape(unsigned* shape);
|
||||
MOZ_MUST_USE bool emitToIteratorResult(bool done);
|
||||
|
||||
MOZ_MUST_USE bool emitGetDotGenerator();
|
||||
|
||||
|
|
|
@ -9479,68 +9479,97 @@ Parser<SyntaxParseHandler, char16_t>::newRegExp()
|
|||
return handler.newRegExp(SyntaxParseHandler::NodeGeneric, pos(), *this);
|
||||
}
|
||||
|
||||
// |exprPossibleError| is the PossibleError state within |expr|,
|
||||
// |possibleError| is the surrounding PossibleError state.
|
||||
template <class ParseHandler, typename CharT>
|
||||
void
|
||||
bool
|
||||
Parser<ParseHandler, CharT>::checkDestructuringAssignmentTarget(Node expr, TokenPos exprPos,
|
||||
PossibleError* exprPossibleError,
|
||||
PossibleError* possibleError,
|
||||
TargetBehavior behavior)
|
||||
{
|
||||
// Report any pending expression error if we're definitely not in a
|
||||
// destructuring context or the possible destructuring target is a
|
||||
// property accessor.
|
||||
if (!possibleError || handler.isPropertyAccess(expr))
|
||||
return exprPossibleError->checkForExpressionError();
|
||||
|
||||
// |expr| may end up as a destructuring assignment target, so we need to
|
||||
// validate it's either a name or can be parsed as a nested destructuring
|
||||
// pattern. Property accessors are also valid assignment targets, but
|
||||
// those are already handled above.
|
||||
|
||||
exprPossibleError->transferErrorsTo(possibleError);
|
||||
|
||||
// Return early if a pending destructuring error is already present.
|
||||
if (possibleError->hasPendingDestructuringError())
|
||||
return true;
|
||||
|
||||
if (handler.isNameAnyParentheses(expr)) {
|
||||
checkDestructuringAssignmentName(expr, exprPos, possibleError);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (handler.isUnparenthesizedDestructuringPattern(expr)) {
|
||||
if (behavior == TargetBehavior::ForbidAssignmentPattern)
|
||||
possibleError->setPendingDestructuringErrorAt(exprPos, JSMSG_BAD_DESTRUCT_TARGET);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Parentheses are forbidden around destructuring *patterns* (but allowed
|
||||
// around names). Use our nicer error message for parenthesized, nested
|
||||
// patterns if nested destructuring patterns are allowed.
|
||||
if (handler.isParenthesizedDestructuringPattern(expr) &&
|
||||
behavior != TargetBehavior::ForbidAssignmentPattern)
|
||||
{
|
||||
possibleError->setPendingDestructuringErrorAt(exprPos, JSMSG_BAD_DESTRUCT_PARENS);
|
||||
} else {
|
||||
possibleError->setPendingDestructuringErrorAt(exprPos, JSMSG_BAD_DESTRUCT_TARGET);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class ParseHandler, typename CharT>
|
||||
void
|
||||
Parser<ParseHandler, CharT>::checkDestructuringAssignmentName(Node name, TokenPos namePos,
|
||||
PossibleError* possibleError)
|
||||
{
|
||||
MOZ_ASSERT(handler.isNameAnyParentheses(name));
|
||||
|
||||
// Return early if a pending destructuring error is already present.
|
||||
if (possibleError->hasPendingDestructuringError())
|
||||
return;
|
||||
|
||||
if (pc->sc()->needStrictChecks()) {
|
||||
if (handler.isArgumentsAnyParentheses(expr, context)) {
|
||||
if (handler.isArgumentsAnyParentheses(name, context)) {
|
||||
if (pc->sc()->strict()) {
|
||||
possibleError->setPendingDestructuringErrorAt(exprPos,
|
||||
possibleError->setPendingDestructuringErrorAt(namePos,
|
||||
JSMSG_BAD_STRICT_ASSIGN_ARGUMENTS);
|
||||
} else {
|
||||
possibleError->setPendingDestructuringWarningAt(exprPos,
|
||||
possibleError->setPendingDestructuringWarningAt(namePos,
|
||||
JSMSG_BAD_STRICT_ASSIGN_ARGUMENTS);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (handler.isEvalAnyParentheses(expr, context)) {
|
||||
if (handler.isEvalAnyParentheses(name, context)) {
|
||||
if (pc->sc()->strict()) {
|
||||
possibleError->setPendingDestructuringErrorAt(exprPos,
|
||||
possibleError->setPendingDestructuringErrorAt(namePos,
|
||||
JSMSG_BAD_STRICT_ASSIGN_EVAL);
|
||||
} else {
|
||||
possibleError->setPendingDestructuringWarningAt(exprPos,
|
||||
possibleError->setPendingDestructuringWarningAt(namePos,
|
||||
JSMSG_BAD_STRICT_ASSIGN_EVAL);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (behavior == TargetBehavior::ForbidAssignmentPattern) {
|
||||
if (handler.isUnparenthesizedDestructuringPattern(expr) ||
|
||||
handler.isParenthesizedDestructuringPattern(expr))
|
||||
{
|
||||
possibleError->setPendingDestructuringErrorAt(exprPos, JSMSG_BAD_DESTRUCT_TARGET);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// The expression must be either a simple assignment target, i.e. a name
|
||||
// or a property accessor, or a nested destructuring pattern.
|
||||
if (!handler.isUnparenthesizedDestructuringPattern(expr) &&
|
||||
!handler.isNameAnyParentheses(expr) &&
|
||||
!handler.isPropertyAccess(expr))
|
||||
{
|
||||
// Parentheses are forbidden around destructuring *patterns* (but
|
||||
// allowed around names). Use our nicer error message for
|
||||
// parenthesized, nested patterns.
|
||||
if (handler.isParenthesizedDestructuringPattern(expr))
|
||||
possibleError->setPendingDestructuringErrorAt(exprPos, JSMSG_BAD_DESTRUCT_PARENS);
|
||||
else
|
||||
possibleError->setPendingDestructuringErrorAt(exprPos, JSMSG_BAD_DESTRUCT_TARGET);
|
||||
}
|
||||
}
|
||||
|
||||
template <class ParseHandler, typename CharT>
|
||||
void
|
||||
bool
|
||||
Parser<ParseHandler, CharT>::checkDestructuringAssignmentElement(Node expr, TokenPos exprPos,
|
||||
PossibleError* exprPossibleError,
|
||||
PossibleError* possibleError)
|
||||
{
|
||||
// ES2018 draft rev 0719f44aab93215ed9a626b2f45bd34f36916834
|
||||
|
@ -9553,8 +9582,16 @@ Parser<ParseHandler, CharT>::checkDestructuringAssignmentElement(Node expr, Toke
|
|||
// If |expr| is an assignment element with an initializer expression, its
|
||||
// destructuring assignment target was already validated in assignExpr().
|
||||
// Otherwise we need to check that |expr| is a valid destructuring target.
|
||||
if (!handler.isUnparenthesizedAssignment(expr))
|
||||
checkDestructuringAssignmentTarget(expr, exprPos, possibleError);
|
||||
if (handler.isUnparenthesizedAssignment(expr)) {
|
||||
// Report any pending expression error if we're definitely not in a
|
||||
// destructuring context.
|
||||
if (!possibleError)
|
||||
return exprPossibleError->checkForExpressionError();
|
||||
|
||||
exprPossibleError->transferErrorsTo(possibleError);
|
||||
return true;
|
||||
}
|
||||
return checkDestructuringAssignmentTarget(expr, exprPos, exprPossibleError, possibleError);
|
||||
}
|
||||
|
||||
template <class ParseHandler, typename CharT>
|
||||
|
@ -9612,12 +9649,17 @@ Parser<ParseHandler, CharT>::arrayInitializer(YieldHandling yieldHandling,
|
|||
if (!tokenStream.peekTokenPos(&innerPos, TokenStream::Operand))
|
||||
return null();
|
||||
|
||||
PossibleError possibleErrorInner(*this);
|
||||
Node inner = assignExpr(InAllowed, yieldHandling, TripledotProhibited,
|
||||
possibleError);
|
||||
&possibleErrorInner);
|
||||
if (!inner)
|
||||
return null();
|
||||
if (possibleError)
|
||||
checkDestructuringAssignmentTarget(inner, innerPos, possibleError);
|
||||
if (!checkDestructuringAssignmentTarget(inner, innerPos, &possibleErrorInner,
|
||||
possibleError))
|
||||
{
|
||||
return null();
|
||||
}
|
||||
|
||||
if (!handler.addSpreadElement(literal, begin, inner))
|
||||
return null();
|
||||
} else {
|
||||
|
@ -9625,12 +9667,16 @@ Parser<ParseHandler, CharT>::arrayInitializer(YieldHandling yieldHandling,
|
|||
if (!tokenStream.peekTokenPos(&elementPos, TokenStream::Operand))
|
||||
return null();
|
||||
|
||||
PossibleError possibleErrorInner(*this);
|
||||
Node element = assignExpr(InAllowed, yieldHandling, TripledotProhibited,
|
||||
possibleError);
|
||||
&possibleErrorInner);
|
||||
if (!element)
|
||||
return null();
|
||||
if (possibleError)
|
||||
checkDestructuringAssignmentElement(element, elementPos, possibleError);
|
||||
if (!checkDestructuringAssignmentElement(element, elementPos, &possibleErrorInner,
|
||||
possibleError))
|
||||
{
|
||||
return null();
|
||||
}
|
||||
if (foldConstants && !FoldConstants(context, &element, this))
|
||||
return null();
|
||||
handler.addArrayElement(literal, element);
|
||||
|
@ -9913,13 +9959,16 @@ Parser<ParseHandler, CharT>::objectLiteral(YieldHandling yieldHandling,
|
|||
if (!tokenStream.peekTokenPos(&innerPos, TokenStream::Operand))
|
||||
return null();
|
||||
|
||||
PossibleError possibleErrorInner(*this);
|
||||
Node inner = assignExpr(InAllowed, yieldHandling, TripledotProhibited,
|
||||
possibleError);
|
||||
&possibleErrorInner);
|
||||
if (!inner)
|
||||
return null();
|
||||
if (possibleError) {
|
||||
checkDestructuringAssignmentTarget(inner, innerPos, possibleError,
|
||||
TargetBehavior::ForbidAssignmentPattern);
|
||||
if (!checkDestructuringAssignmentTarget(inner, innerPos, &possibleErrorInner,
|
||||
possibleError,
|
||||
TargetBehavior::ForbidAssignmentPattern))
|
||||
{
|
||||
return null();
|
||||
}
|
||||
if (!handler.addSpreadProperty(literal, begin, inner))
|
||||
return null();
|
||||
|
@ -9936,23 +9985,27 @@ Parser<ParseHandler, CharT>::objectLiteral(YieldHandling yieldHandling,
|
|||
if (!tokenStream.peekTokenPos(&exprPos, TokenStream::Operand))
|
||||
return null();
|
||||
|
||||
PossibleError possibleErrorInner(*this);
|
||||
Node propExpr = assignExpr(InAllowed, yieldHandling, TripledotProhibited,
|
||||
possibleError);
|
||||
&possibleErrorInner);
|
||||
if (!propExpr)
|
||||
return null();
|
||||
|
||||
handler.checkAndSetIsDirectRHSAnonFunction(propExpr);
|
||||
|
||||
if (possibleError)
|
||||
checkDestructuringAssignmentElement(propExpr, exprPos, possibleError);
|
||||
if (!checkDestructuringAssignmentElement(propExpr, exprPos, &possibleErrorInner,
|
||||
possibleError))
|
||||
{
|
||||
return null();
|
||||
}
|
||||
|
||||
if (foldConstants && !FoldConstants(context, &propExpr, this))
|
||||
return null();
|
||||
|
||||
if (propAtom == context->names().proto) {
|
||||
if (seenPrototypeMutation) {
|
||||
// Directly report the error when we're not in a
|
||||
// destructuring context.
|
||||
// Directly report the error when we're definitely not
|
||||
// in a destructuring context.
|
||||
if (!possibleError) {
|
||||
errorAt(namePos.begin, JSMSG_DUPLICATE_PROTO_PROPERTY);
|
||||
return null();
|
||||
|
@ -9993,7 +10046,7 @@ Parser<ParseHandler, CharT>::objectLiteral(YieldHandling yieldHandling,
|
|||
return null();
|
||||
|
||||
if (possibleError)
|
||||
checkDestructuringAssignmentTarget(nameExpr, namePos, possibleError);
|
||||
checkDestructuringAssignmentName(nameExpr, namePos, possibleError);
|
||||
|
||||
if (!handler.addShorthand(literal, propName, nameExpr))
|
||||
return null();
|
||||
|
|
|
@ -928,10 +928,14 @@ class Parser final : public ParserBase, private JS::AutoGCRooter
|
|||
PermitAssignmentPattern,
|
||||
ForbidAssignmentPattern
|
||||
};
|
||||
void checkDestructuringAssignmentTarget(Node expr, TokenPos exprPos,
|
||||
bool checkDestructuringAssignmentTarget(Node expr, TokenPos exprPos,
|
||||
PossibleError* exprPossibleError,
|
||||
PossibleError* possibleError,
|
||||
TargetBehavior behavior = TargetBehavior::PermitAssignmentPattern);
|
||||
void checkDestructuringAssignmentElement(Node expr, TokenPos exprPos,
|
||||
void checkDestructuringAssignmentName(Node name, TokenPos namePos,
|
||||
PossibleError* possibleError);
|
||||
bool checkDestructuringAssignmentElement(Node expr, TokenPos exprPos,
|
||||
PossibleError* exprPossibleError,
|
||||
PossibleError* possibleError);
|
||||
|
||||
Node newNumber(const Token& tok) {
|
||||
|
|
|
@ -1059,10 +1059,8 @@ IonBuilder::inlineBoolean(CallInfo& callInfo)
|
|||
IonBuilder::InliningResult
|
||||
IonBuilder::inlineNewIterator(CallInfo& callInfo, MNewIterator::Type type)
|
||||
{
|
||||
if (callInfo.argc() != 0 || callInfo.constructing()) {
|
||||
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
|
||||
return InliningStatus_NotInlined;
|
||||
}
|
||||
MOZ_ASSERT(!callInfo.constructing());
|
||||
MOZ_ASSERT(callInfo.argc() == 0);
|
||||
|
||||
JSObject* templateObject = nullptr;
|
||||
switch (type) {
|
||||
|
@ -1698,10 +1696,8 @@ IonBuilder::inlineConstantStringSplitString(CallInfo& callInfo)
|
|||
IonBuilder::InliningResult
|
||||
IonBuilder::inlineStringSplitString(CallInfo& callInfo)
|
||||
{
|
||||
if (callInfo.argc() != 2 || callInfo.constructing()) {
|
||||
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
|
||||
return InliningStatus_NotInlined;
|
||||
}
|
||||
MOZ_ASSERT(!callInfo.constructing());
|
||||
MOZ_ASSERT(callInfo.argc() == 2);
|
||||
|
||||
MDefinition* strArg = callInfo.getArg(0);
|
||||
MDefinition* sepArg = callInfo.getArg(1);
|
||||
|
@ -1748,10 +1744,8 @@ IonBuilder::inlineStringSplitString(CallInfo& callInfo)
|
|||
IonBuilder::InliningResult
|
||||
IonBuilder::inlineObjectHasPrototype(CallInfo& callInfo)
|
||||
{
|
||||
if (callInfo.argc() != 2 || callInfo.constructing()) {
|
||||
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
|
||||
return InliningStatus_NotInlined;
|
||||
}
|
||||
MOZ_ASSERT(!callInfo.constructing());
|
||||
MOZ_ASSERT(callInfo.argc() == 2);
|
||||
|
||||
MDefinition* objArg = callInfo.getArg(0);
|
||||
MDefinition* protoArg = callInfo.getArg(1);
|
||||
|
@ -2070,10 +2064,8 @@ IonBuilder::inlineRegExpMatcher(CallInfo& callInfo)
|
|||
// This is called from Self-hosted JS, after testing each argument,
|
||||
// most of following tests should be passed.
|
||||
|
||||
if (callInfo.argc() != 3 || callInfo.constructing()) {
|
||||
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
|
||||
return InliningStatus_NotInlined;
|
||||
}
|
||||
MOZ_ASSERT(!callInfo.constructing());
|
||||
MOZ_ASSERT(callInfo.argc() == 3);
|
||||
|
||||
MDefinition* rxArg = callInfo.getArg(0);
|
||||
MDefinition* strArg = callInfo.getArg(1);
|
||||
|
@ -2087,7 +2079,7 @@ IonBuilder::inlineRegExpMatcher(CallInfo& callInfo)
|
|||
if (clasp != &RegExpObject::class_)
|
||||
return InliningStatus_NotInlined;
|
||||
|
||||
if (strArg->mightBeType(MIRType::Object))
|
||||
if (strArg->type() != MIRType::String && strArg->type() != MIRType::Value)
|
||||
return InliningStatus_NotInlined;
|
||||
|
||||
if (lastIndexArg->type() != MIRType::Int32)
|
||||
|
@ -2116,10 +2108,8 @@ IonBuilder::inlineRegExpSearcher(CallInfo& callInfo)
|
|||
// This is called from Self-hosted JS, after testing each argument,
|
||||
// most of following tests should be passed.
|
||||
|
||||
if (callInfo.argc() != 3 || callInfo.constructing()) {
|
||||
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
|
||||
return InliningStatus_NotInlined;
|
||||
}
|
||||
MOZ_ASSERT(!callInfo.constructing());
|
||||
MOZ_ASSERT(callInfo.argc() == 3);
|
||||
|
||||
MDefinition* rxArg = callInfo.getArg(0);
|
||||
MDefinition* strArg = callInfo.getArg(1);
|
||||
|
@ -2133,7 +2123,7 @@ IonBuilder::inlineRegExpSearcher(CallInfo& callInfo)
|
|||
if (clasp != &RegExpObject::class_)
|
||||
return InliningStatus_NotInlined;
|
||||
|
||||
if (strArg->mightBeType(MIRType::Object))
|
||||
if (strArg->type() != MIRType::String && strArg->type() != MIRType::Value)
|
||||
return InliningStatus_NotInlined;
|
||||
|
||||
if (lastIndexArg->type() != MIRType::Int32)
|
||||
|
@ -2162,10 +2152,8 @@ IonBuilder::inlineRegExpTester(CallInfo& callInfo)
|
|||
// This is called from Self-hosted JS, after testing each argument,
|
||||
// most of following tests should be passed.
|
||||
|
||||
if (callInfo.argc() != 3 || callInfo.constructing()) {
|
||||
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
|
||||
return InliningStatus_NotInlined;
|
||||
}
|
||||
MOZ_ASSERT(!callInfo.constructing());
|
||||
MOZ_ASSERT(callInfo.argc() == 3);
|
||||
|
||||
MDefinition* rxArg = callInfo.getArg(0);
|
||||
MDefinition* strArg = callInfo.getArg(1);
|
||||
|
@ -2179,7 +2167,7 @@ IonBuilder::inlineRegExpTester(CallInfo& callInfo)
|
|||
if (clasp != &RegExpObject::class_)
|
||||
return InliningStatus_NotInlined;
|
||||
|
||||
if (strArg->mightBeType(MIRType::Object))
|
||||
if (strArg->type() != MIRType::String && strArg->type() != MIRType::Value)
|
||||
return InliningStatus_NotInlined;
|
||||
|
||||
if (lastIndexArg->type() != MIRType::Int32)
|
||||
|
@ -2204,32 +2192,39 @@ IonBuilder::inlineRegExpTester(CallInfo& callInfo)
|
|||
IonBuilder::InliningResult
|
||||
IonBuilder::inlineIsRegExpObject(CallInfo& callInfo)
|
||||
{
|
||||
if (callInfo.constructing() || callInfo.argc() != 1) {
|
||||
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
|
||||
return InliningStatus_NotInlined;
|
||||
}
|
||||
MOZ_ASSERT(!callInfo.constructing());
|
||||
MOZ_ASSERT(callInfo.argc() == 1);
|
||||
|
||||
if (getInlineReturnType() != MIRType::Boolean)
|
||||
return InliningStatus_NotInlined;
|
||||
|
||||
MDefinition* arg = callInfo.getArg(0);
|
||||
|
||||
bool isRegExpObject;
|
||||
if (!arg->mightBeType(MIRType::Object)) {
|
||||
isRegExpObject = false;
|
||||
} else {
|
||||
if (arg->type() != MIRType::Object)
|
||||
return InliningStatus_NotInlined;
|
||||
|
||||
bool isRegExpObjectKnown = false;
|
||||
bool isRegExpObjectConstant;
|
||||
if (arg->type() == MIRType::Object) {
|
||||
TemporaryTypeSet* types = arg->resultTypeSet();
|
||||
const Class* clasp = types ? types->getKnownClass(constraints()) : nullptr;
|
||||
if (!clasp || clasp->isProxy())
|
||||
return InliningStatus_NotInlined;
|
||||
|
||||
isRegExpObject = (clasp == &RegExpObject::class_);
|
||||
if (clasp) {
|
||||
isRegExpObjectKnown = true;
|
||||
isRegExpObjectConstant = (clasp == &RegExpObject::class_);
|
||||
}
|
||||
} else if (!arg->mightBeType(MIRType::Object)) {
|
||||
// NB: This case only happens when Phi-nodes flow into IsRegExpObject.
|
||||
// IsRegExpObject itself will never be called with a non-Object value.
|
||||
isRegExpObjectKnown = true;
|
||||
isRegExpObjectConstant = false;
|
||||
} else if (arg->type() != MIRType::Value) {
|
||||
return InliningStatus_NotInlined;
|
||||
}
|
||||
|
||||
pushConstant(BooleanValue(isRegExpObject));
|
||||
if (isRegExpObjectKnown) {
|
||||
pushConstant(BooleanValue(isRegExpObjectConstant));
|
||||
} else {
|
||||
MHasClass* hasClass = MHasClass::New(alloc(), arg, &RegExpObject::class_);
|
||||
current->add(hasClass);
|
||||
current->push(hasClass);
|
||||
}
|
||||
|
||||
callInfo.setImplicitlyUsedUnchecked();
|
||||
return InliningStatus_Inlined;
|
||||
|
@ -2238,10 +2233,8 @@ IonBuilder::inlineIsRegExpObject(CallInfo& callInfo)
|
|||
IonBuilder::InliningResult
|
||||
IonBuilder::inlineRegExpPrototypeOptimizable(CallInfo& callInfo)
|
||||
{
|
||||
if (callInfo.argc() != 1 || callInfo.constructing()) {
|
||||
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
|
||||
return InliningStatus_NotInlined;
|
||||
}
|
||||
MOZ_ASSERT(!callInfo.constructing());
|
||||
MOZ_ASSERT(callInfo.argc() == 1);
|
||||
|
||||
MDefinition* protoArg = callInfo.getArg(0);
|
||||
|
||||
|
@ -2263,15 +2256,13 @@ IonBuilder::inlineRegExpPrototypeOptimizable(CallInfo& callInfo)
|
|||
IonBuilder::InliningResult
|
||||
IonBuilder::inlineRegExpInstanceOptimizable(CallInfo& callInfo)
|
||||
{
|
||||
if (callInfo.argc() != 2 || callInfo.constructing()) {
|
||||
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
|
||||
return InliningStatus_NotInlined;
|
||||
}
|
||||
MOZ_ASSERT(!callInfo.constructing());
|
||||
MOZ_ASSERT(callInfo.argc() == 2);
|
||||
|
||||
MDefinition* rxArg = callInfo.getArg(0);
|
||||
MDefinition* protoArg = callInfo.getArg(1);
|
||||
|
||||
if (rxArg->type() != MIRType::Object)
|
||||
if (rxArg->type() != MIRType::Object && rxArg->type() != MIRType::Value)
|
||||
return InliningStatus_NotInlined;
|
||||
|
||||
if (protoArg->type() != MIRType::Object)
|
||||
|
@ -2292,10 +2283,8 @@ IonBuilder::inlineRegExpInstanceOptimizable(CallInfo& callInfo)
|
|||
IonBuilder::InliningResult
|
||||
IonBuilder::inlineGetFirstDollarIndex(CallInfo& callInfo)
|
||||
{
|
||||
if (callInfo.argc() != 1 || callInfo.constructing()) {
|
||||
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
|
||||
return InliningStatus_NotInlined;
|
||||
}
|
||||
MOZ_ASSERT(!callInfo.constructing());
|
||||
MOZ_ASSERT(callInfo.argc() == 1);
|
||||
|
||||
MDefinition* strArg = callInfo.getArg(0);
|
||||
|
||||
|
@ -2317,10 +2306,8 @@ IonBuilder::inlineGetFirstDollarIndex(CallInfo& callInfo)
|
|||
IonBuilder::InliningResult
|
||||
IonBuilder::inlineStringReplaceString(CallInfo& callInfo)
|
||||
{
|
||||
if (callInfo.argc() != 3 || callInfo.constructing()) {
|
||||
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
|
||||
return InliningStatus_NotInlined;
|
||||
}
|
||||
MOZ_ASSERT(!callInfo.constructing());
|
||||
MOZ_ASSERT(callInfo.argc() == 3);
|
||||
|
||||
if (getInlineReturnType() != MIRType::String)
|
||||
return InliningStatus_NotInlined;
|
||||
|
@ -2351,8 +2338,8 @@ IonBuilder::inlineStringReplaceString(CallInfo& callInfo)
|
|||
IonBuilder::InliningResult
|
||||
IonBuilder::inlineSubstringKernel(CallInfo& callInfo)
|
||||
{
|
||||
MOZ_ASSERT(callInfo.argc() == 3);
|
||||
MOZ_ASSERT(!callInfo.constructing());
|
||||
MOZ_ASSERT(callInfo.argc() == 3);
|
||||
|
||||
// Return: String.
|
||||
if (getInlineReturnType() != MIRType::String)
|
||||
|
@ -2499,10 +2486,8 @@ IonBuilder::inlineHasClass(CallInfo& callInfo,
|
|||
const Class* clasp1, const Class* clasp2,
|
||||
const Class* clasp3, const Class* clasp4)
|
||||
{
|
||||
if (callInfo.constructing() || callInfo.argc() != 1) {
|
||||
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
|
||||
return InliningStatus_NotInlined;
|
||||
}
|
||||
MOZ_ASSERT(!callInfo.constructing());
|
||||
MOZ_ASSERT(callInfo.argc() == 1);
|
||||
|
||||
if (callInfo.getArg(0)->type() != MIRType::Object)
|
||||
return InliningStatus_NotInlined;
|
||||
|
@ -2546,10 +2531,8 @@ IonBuilder::inlineHasClass(CallInfo& callInfo,
|
|||
IonBuilder::InliningResult
|
||||
IonBuilder::inlineGetNextEntryForIterator(CallInfo& callInfo, MGetNextEntryForIterator::Mode mode)
|
||||
{
|
||||
if (callInfo.argc() != 2 || callInfo.constructing()) {
|
||||
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
|
||||
return InliningStatus_NotInlined;
|
||||
}
|
||||
MOZ_ASSERT(!callInfo.constructing());
|
||||
MOZ_ASSERT(callInfo.argc() == 2);
|
||||
|
||||
MDefinition* iterArg = callInfo.getArg(0);
|
||||
MDefinition* resultArg = callInfo.getArg(1);
|
||||
|
@ -2875,10 +2858,8 @@ IonBuilder::inlineSetDisjointTypedElements(CallInfo& callInfo)
|
|||
IonBuilder::InliningResult
|
||||
IonBuilder::inlineObjectIsTypeDescr(CallInfo& callInfo)
|
||||
{
|
||||
if (callInfo.constructing() || callInfo.argc() != 1) {
|
||||
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
|
||||
return InliningStatus_NotInlined;
|
||||
}
|
||||
MOZ_ASSERT(!callInfo.constructing());
|
||||
MOZ_ASSERT(callInfo.argc() == 1);
|
||||
|
||||
if (callInfo.getArg(0)->type() != MIRType::Object)
|
||||
return InliningStatus_NotInlined;
|
||||
|
@ -2914,10 +2895,8 @@ IonBuilder::inlineObjectIsTypeDescr(CallInfo& callInfo)
|
|||
IonBuilder::InliningResult
|
||||
IonBuilder::inlineSetTypedObjectOffset(CallInfo& callInfo)
|
||||
{
|
||||
if (callInfo.argc() != 2 || callInfo.constructing()) {
|
||||
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
|
||||
return InliningStatus_NotInlined;
|
||||
}
|
||||
MOZ_ASSERT(!callInfo.constructing());
|
||||
MOZ_ASSERT(callInfo.argc() == 2);
|
||||
|
||||
MDefinition* typedObj = callInfo.getArg(0);
|
||||
MDefinition* offset = callInfo.getArg(1);
|
||||
|
@ -2958,10 +2937,9 @@ IonBuilder::inlineSetTypedObjectOffset(CallInfo& callInfo)
|
|||
IonBuilder::InliningResult
|
||||
IonBuilder::inlineUnsafeSetReservedSlot(CallInfo& callInfo)
|
||||
{
|
||||
if (callInfo.argc() != 3 || callInfo.constructing()) {
|
||||
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
|
||||
return InliningStatus_NotInlined;
|
||||
}
|
||||
MOZ_ASSERT(!callInfo.constructing());
|
||||
MOZ_ASSERT(callInfo.argc() == 3);
|
||||
|
||||
if (getInlineReturnType() != MIRType::Undefined)
|
||||
return InliningStatus_NotInlined;
|
||||
|
||||
|
@ -2998,10 +2976,8 @@ IonBuilder::inlineUnsafeSetReservedSlot(CallInfo& callInfo)
|
|||
IonBuilder::InliningResult
|
||||
IonBuilder::inlineUnsafeGetReservedSlot(CallInfo& callInfo, MIRType knownValueType)
|
||||
{
|
||||
if (callInfo.argc() != 2 || callInfo.constructing()) {
|
||||
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
|
||||
return InliningStatus_NotInlined;
|
||||
}
|
||||
MOZ_ASSERT(!callInfo.constructing());
|
||||
MOZ_ASSERT(callInfo.argc() == 2);
|
||||
|
||||
MDefinition* obj = callInfo.getArg(0);
|
||||
if (obj->type() != MIRType::Object && obj->type() != MIRType::Value)
|
||||
|
@ -3045,10 +3021,8 @@ IonBuilder::inlineUnsafeGetReservedSlot(CallInfo& callInfo, MIRType knownValueTy
|
|||
IonBuilder::InliningResult
|
||||
IonBuilder::inlineIsCallable(CallInfo& callInfo)
|
||||
{
|
||||
if (callInfo.argc() != 1 || callInfo.constructing()) {
|
||||
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
|
||||
return InliningStatus_NotInlined;
|
||||
}
|
||||
MOZ_ASSERT(!callInfo.constructing());
|
||||
MOZ_ASSERT(callInfo.argc() == 1);
|
||||
|
||||
if (getInlineReturnType() != MIRType::Boolean)
|
||||
return InliningStatus_NotInlined;
|
||||
|
@ -3113,10 +3087,9 @@ IonBuilder::inlineIsConstructor(CallInfo& callInfo)
|
|||
IonBuilder::InliningResult
|
||||
IonBuilder::inlineIsObject(CallInfo& callInfo)
|
||||
{
|
||||
if (callInfo.argc() != 1 || callInfo.constructing()) {
|
||||
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
|
||||
return InliningStatus_NotInlined;
|
||||
}
|
||||
MOZ_ASSERT(!callInfo.constructing());
|
||||
MOZ_ASSERT(callInfo.argc() == 1);
|
||||
|
||||
if (getInlineReturnType() != MIRType::Boolean)
|
||||
return InliningStatus_NotInlined;
|
||||
|
||||
|
@ -3134,10 +3107,8 @@ IonBuilder::inlineIsObject(CallInfo& callInfo)
|
|||
IonBuilder::InliningResult
|
||||
IonBuilder::inlineToObject(CallInfo& callInfo)
|
||||
{
|
||||
if (callInfo.argc() != 1 || callInfo.constructing()) {
|
||||
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
|
||||
return InliningStatus_NotInlined;
|
||||
}
|
||||
MOZ_ASSERT(!callInfo.constructing());
|
||||
MOZ_ASSERT(callInfo.argc() == 1);
|
||||
|
||||
if (getInlineReturnType() != MIRType::Object)
|
||||
return InliningStatus_NotInlined;
|
||||
|
@ -3165,10 +3136,8 @@ IonBuilder::inlineToObject(CallInfo& callInfo)
|
|||
IonBuilder::InliningResult
|
||||
IonBuilder::inlineIsWrappedArrayConstructor(CallInfo& callInfo)
|
||||
{
|
||||
if (callInfo.constructing() || callInfo.argc() != 1) {
|
||||
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
|
||||
return InliningStatus_NotInlined;
|
||||
}
|
||||
MOZ_ASSERT(!callInfo.constructing());
|
||||
MOZ_ASSERT(callInfo.argc() == 1);
|
||||
|
||||
if (getInlineReturnType() != MIRType::Boolean)
|
||||
return InliningStatus_NotInlined;
|
||||
|
@ -3196,10 +3165,8 @@ IonBuilder::inlineIsWrappedArrayConstructor(CallInfo& callInfo)
|
|||
IonBuilder::InliningResult
|
||||
IonBuilder::inlineToInteger(CallInfo& callInfo)
|
||||
{
|
||||
if (callInfo.argc() != 1 || callInfo.constructing()) {
|
||||
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
|
||||
return InliningStatus_NotInlined;
|
||||
}
|
||||
MOZ_ASSERT(!callInfo.constructing());
|
||||
MOZ_ASSERT(callInfo.argc() == 1);
|
||||
|
||||
MDefinition* input = callInfo.getArg(0);
|
||||
|
||||
|
@ -3231,8 +3198,8 @@ IonBuilder::inlineToInteger(CallInfo& callInfo)
|
|||
IonBuilder::InliningResult
|
||||
IonBuilder::inlineToString(CallInfo& callInfo)
|
||||
{
|
||||
if (callInfo.argc() != 1 || callInfo.constructing())
|
||||
return InliningStatus_NotInlined;
|
||||
MOZ_ASSERT(!callInfo.constructing());
|
||||
MOZ_ASSERT(callInfo.argc() == 1);
|
||||
|
||||
if (getInlineReturnType() != MIRType::String)
|
||||
return InliningStatus_NotInlined;
|
||||
|
|
|
@ -13644,7 +13644,8 @@ class MHasClass
|
|||
: MUnaryInstruction(classOpcode, object)
|
||||
, class_(clasp)
|
||||
{
|
||||
MOZ_ASSERT(object->type() == MIRType::Object);
|
||||
MOZ_ASSERT(object->type() == MIRType::Object ||
|
||||
(object->type() == MIRType::Value && object->mightBeType(MIRType::Object)));
|
||||
setResultType(MIRType::Boolean);
|
||||
setMovable();
|
||||
}
|
||||
|
|
|
@ -2278,6 +2278,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)
|
||||
|
|
|
@ -635,11 +635,13 @@ static bool
|
|||
array_length_setter(JSContext* cx, HandleObject obj, HandleId id, MutableHandleValue vp,
|
||||
ObjectOpResult& result)
|
||||
{
|
||||
MOZ_ASSERT(id == NameToId(cx->names().length));
|
||||
|
||||
if (!obj->is<ArrayObject>()) {
|
||||
// This array .length property was found on the prototype
|
||||
// chain. Ideally the setter should not have been called, but since
|
||||
// we're here, do an impression of SetPropertyByDefining.
|
||||
return DefineDataProperty(cx, obj, cx->names().length, vp, JSPROP_ENUMERATE, result);
|
||||
return DefineDataProperty(cx, obj, id, vp, JSPROP_ENUMERATE, result);
|
||||
}
|
||||
|
||||
Rooted<ArrayObject*> arr(cx, &obj->as<ArrayObject>());
|
||||
|
|
|
@ -47,6 +47,10 @@ AtomToId(JSAtom* atom)
|
|||
return JSID_FROM_BITS(size_t(atom));
|
||||
}
|
||||
|
||||
// Use the NameToId method instead!
|
||||
inline jsid
|
||||
AtomToId(PropertyName* name) = delete;
|
||||
|
||||
inline bool
|
||||
ValueToIdPure(const Value& v, jsid* id)
|
||||
{
|
||||
|
|
|
@ -749,9 +749,6 @@ DefineFunction(JSContext* cx, HandleObject obj, HandleId id, JSNative native,
|
|||
unsigned nargs, unsigned flags,
|
||||
gc::AllocKind allocKind = gc::AllocKind::FUNCTION);
|
||||
|
||||
bool
|
||||
FunctionHasResolveHook(const JSAtomState& atomState, jsid id);
|
||||
|
||||
extern bool
|
||||
fun_toString(JSContext* cx, unsigned argc, Value* vp);
|
||||
|
||||
|
|
|
@ -94,9 +94,6 @@ GenerateRandomSeed();
|
|||
extern void
|
||||
GenerateXorShift128PlusSeed(mozilla::Array<uint64_t, 2>& seed);
|
||||
|
||||
extern uint64_t
|
||||
random_next(uint64_t* rngState, int bits);
|
||||
|
||||
extern double
|
||||
math_random_impl(JSContext* cx);
|
||||
|
||||
|
|
|
@ -1440,14 +1440,6 @@ js::NumberToAtom(JSContext* cx, double d)
|
|||
return atom;
|
||||
}
|
||||
|
||||
JSFlatString*
|
||||
js::NumberToString(JSContext* cx, double d)
|
||||
{
|
||||
if (JSString* str = NumberToStringWithBase<CanGC>(cx, d, 10))
|
||||
return &str->asFlat();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
JSFlatString*
|
||||
js::IndexToString(JSContext* cx, uint32_t index)
|
||||
{
|
||||
|
|
|
@ -92,10 +92,6 @@ IsInteger(const Value& val);
|
|||
extern MOZ_MUST_USE bool JS_FASTCALL
|
||||
NumberValueToStringBuffer(JSContext* cx, const Value& v, StringBuffer& sb);
|
||||
|
||||
/* Same as js_NumberToString, different signature. */
|
||||
extern JSFlatString*
|
||||
NumberToString(JSContext* cx, double d);
|
||||
|
||||
extern JSFlatString*
|
||||
IndexToString(JSContext* cx, uint32_t index);
|
||||
|
||||
|
|
103
js/src/jsobj.cpp
103
js/src/jsobj.cpp
|
@ -265,29 +265,13 @@ js::Throw(JSContext* cx, jsid id, unsigned errorNumber, const char* details)
|
|||
if (details) {
|
||||
JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, errorNumber, bytes.ptr(),
|
||||
details);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, errorNumber, bytes.ptr());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
js::Throw(JSContext* cx, JSObject* obj, unsigned errorNumber)
|
||||
{
|
||||
if (js_ErrorFormatString[errorNumber].argCount == 1) {
|
||||
RootedValue val(cx, ObjectValue(*obj));
|
||||
ReportValueErrorFlags(cx, JSREPORT_ERROR, errorNumber,
|
||||
JSDVG_IGNORE_STACK, val, nullptr,
|
||||
nullptr, nullptr);
|
||||
} else {
|
||||
MOZ_ASSERT(js_ErrorFormatString[errorNumber].argCount == 0);
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, errorNumber);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/*** PropertyDescriptor operations and DefineProperties ******************************************/
|
||||
|
||||
|
@ -1949,9 +1933,9 @@ JSObject::fixupAfterMovingGC()
|
|||
}
|
||||
}
|
||||
|
||||
bool
|
||||
js::SetClassAndProto(JSContext* cx, HandleObject obj,
|
||||
const Class* clasp, Handle<js::TaggedProto> proto)
|
||||
static bool
|
||||
SetClassAndProto(JSContext* cx, HandleObject obj,
|
||||
const Class* clasp, Handle<js::TaggedProto> proto)
|
||||
{
|
||||
// Regenerate the object's shape. If the object is a proto (isDelegate()),
|
||||
// we also need to regenerate shapes for all of the objects along the old
|
||||
|
@ -4056,34 +4040,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
|
||||
|
|
|
@ -42,30 +42,6 @@ namespace gc {
|
|||
class RelocationOverlay;
|
||||
} // namespace gc
|
||||
|
||||
inline JSObject*
|
||||
CastAsObject(GetterOp op)
|
||||
{
|
||||
return JS_FUNC_TO_DATA_PTR(JSObject*, op);
|
||||
}
|
||||
|
||||
inline JSObject*
|
||||
CastAsObject(SetterOp op)
|
||||
{
|
||||
return JS_FUNC_TO_DATA_PTR(JSObject*, op);
|
||||
}
|
||||
|
||||
inline Value
|
||||
CastAsObjectJsval(GetterOp op)
|
||||
{
|
||||
return ObjectOrNullValue(CastAsObject(op));
|
||||
}
|
||||
|
||||
inline Value
|
||||
CastAsObjectJsval(SetterOp op)
|
||||
{
|
||||
return ObjectOrNullValue(CastAsObject(op));
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
extern const Class IntlClass;
|
||||
|
@ -884,30 +860,15 @@ GetElement(JSContext* cx, HandleObject obj, HandleObject receiver, uint32_t inde
|
|||
inline bool
|
||||
GetPropertyNoGC(JSContext* cx, JSObject* obj, const Value& receiver, jsid id, Value* vp);
|
||||
|
||||
inline bool
|
||||
GetPropertyNoGC(JSContext* cx, JSObject* obj, JSObject* receiver, jsid id, Value* vp)
|
||||
{
|
||||
return GetPropertyNoGC(cx, obj, ObjectValue(*receiver), id, vp);
|
||||
}
|
||||
|
||||
inline bool
|
||||
GetPropertyNoGC(JSContext* cx, JSObject* obj, const Value& receiver, PropertyName* name, Value* vp)
|
||||
{
|
||||
return GetPropertyNoGC(cx, obj, receiver, NameToId(name), vp);
|
||||
}
|
||||
|
||||
inline bool
|
||||
GetPropertyNoGC(JSContext* cx, JSObject* obj, JSObject* receiver, PropertyName* name, Value* vp)
|
||||
{
|
||||
return GetPropertyNoGC(cx, obj, ObjectValue(*receiver), name, vp);
|
||||
}
|
||||
|
||||
inline bool
|
||||
GetElementNoGC(JSContext* cx, JSObject* obj, const Value& receiver, uint32_t index, Value* vp);
|
||||
|
||||
inline bool
|
||||
GetElementNoGC(JSContext* cx, JSObject* obj, JSObject* receiver, uint32_t index, Value* vp);
|
||||
|
||||
// Returns whether |obj| or an object on its proto chain may have an interesting
|
||||
// symbol property (see JSObject::hasInterestingSymbolProperty). If it returns
|
||||
// true, *holder is set to the object that may have this property.
|
||||
|
@ -1124,31 +1085,11 @@ GetBuiltinPrototype(JSContext* cx, JSProtoKey key, MutableHandleObject objp);
|
|||
JSObject*
|
||||
GetBuiltinPrototypePure(GlobalObject* global, JSProtoKey protoKey);
|
||||
|
||||
extern bool
|
||||
SetClassAndProto(JSContext* cx, HandleObject obj,
|
||||
const Class* clasp, Handle<TaggedProto> proto);
|
||||
|
||||
extern bool
|
||||
IsStandardPrototype(JSObject* obj, JSProtoKey key);
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
/*
|
||||
* Select Object.prototype method names shared between jsapi.cpp and jsobj.cpp.
|
||||
*/
|
||||
extern const char js_watch_str[];
|
||||
extern const char js_unwatch_str[];
|
||||
extern const char js_hasOwnProperty_str[];
|
||||
extern const char js_isPrototypeOf_str[];
|
||||
extern const char js_propertyIsEnumerable_str[];
|
||||
|
||||
#ifdef JS_OLD_GETTER_SETTER_METHODS
|
||||
extern const char js_defineGetter_str[];
|
||||
extern const char js_defineSetter_str[];
|
||||
extern const char js_lookupGetter_str[];
|
||||
extern const char js_lookupSetter_str[];
|
||||
#endif
|
||||
|
||||
namespace js {
|
||||
|
||||
inline gc::InitialHeap
|
||||
|
@ -1284,9 +1225,6 @@ LookupNameUnqualified(JSContext* cx, HandlePropertyName name, HandleObject scope
|
|||
|
||||
namespace js {
|
||||
|
||||
extern JSObject*
|
||||
FindVariableScope(JSContext* cx, JSFunction** funp);
|
||||
|
||||
bool
|
||||
LookupPropertyPure(JSContext* cx, JSObject* obj, jsid id, JSObject** objp,
|
||||
PropertyResult* propp);
|
||||
|
@ -1314,9 +1252,6 @@ bool
|
|||
GetOwnPropertyDescriptor(JSContext* cx, HandleObject obj, HandleId id,
|
||||
MutableHandle<JS::PropertyDescriptor> desc);
|
||||
|
||||
bool
|
||||
GetOwnPropertyDescriptor(JSContext* cx, HandleObject obj, HandleId id, MutableHandleValue vp);
|
||||
|
||||
/*
|
||||
* Like JS::FromPropertyDescriptor, but ignore desc.object() and always set vp
|
||||
* to an object on success.
|
||||
|
@ -1412,13 +1347,10 @@ extern bool
|
|||
GetFirstArgumentAsObject(JSContext* cx, const CallArgs& args, const char* method,
|
||||
MutableHandleObject objp);
|
||||
|
||||
/* Helpers for throwing. These always return false. */
|
||||
/* Helper for throwing, always returns false. */
|
||||
extern bool
|
||||
Throw(JSContext* cx, jsid id, unsigned errorNumber, const char* details = nullptr);
|
||||
|
||||
extern bool
|
||||
Throw(JSContext* cx, JSObject* obj, unsigned errorNumber);
|
||||
|
||||
/*
|
||||
* ES6 rev 29 (6 Dec 2014) 7.3.13. Mark obj as non-extensible, and adjust each
|
||||
* of obj's own properties' attributes appropriately: each property becomes
|
||||
|
@ -1441,11 +1373,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);
|
||||
|
|
|
@ -251,12 +251,6 @@ js::GetElementNoGC(JSContext* cx, JSObject* obj, const Value& receiver, uint32_t
|
|||
return GetPropertyNoGC(cx, obj, receiver, INT_TO_JSID(index), vp);
|
||||
}
|
||||
|
||||
inline bool
|
||||
js::GetElementNoGC(JSContext* cx, JSObject* obj, JSObject* receiver, uint32_t index, Value* vp)
|
||||
{
|
||||
return GetElementNoGC(cx, obj, ObjectValue(*receiver), index, vp);
|
||||
}
|
||||
|
||||
inline bool
|
||||
js::DeleteProperty(JSContext* cx, HandleObject obj, HandleId id, ObjectOpResult& result)
|
||||
{
|
||||
|
|
|
@ -86,14 +86,11 @@ enum JSProtoKey {
|
|||
/* Struct forward declarations. */
|
||||
struct JSClass;
|
||||
struct JSCompartment;
|
||||
struct JSCrossCompartmentCall;
|
||||
class JSErrorReport;
|
||||
struct JSExceptionState;
|
||||
struct JSFunctionSpec;
|
||||
struct JSLocaleCallbacks;
|
||||
struct JSObjectMap;
|
||||
struct JSPrincipals;
|
||||
struct JSPropertyName;
|
||||
struct JSPropertySpec;
|
||||
struct JSRuntime;
|
||||
struct JSSecurityCallbacks;
|
||||
|
|
|
@ -1867,15 +1867,6 @@ StringMatch(JSLinearString* text, JSLinearString* pat, uint32_t start = 0)
|
|||
|
||||
static const size_t sRopeMatchThresholdRatioLog2 = 4;
|
||||
|
||||
bool
|
||||
js::StringHasPattern(JSLinearString* text, const char16_t* pat, uint32_t patLen)
|
||||
{
|
||||
AutoCheckCannotGC nogc;
|
||||
return text->hasLatin1Chars()
|
||||
? StringMatch(text->latin1Chars(nogc), text->length(), pat, patLen) != -1
|
||||
: StringMatch(text->twoByteChars(nogc), text->length(), pat, patLen) != -1;
|
||||
}
|
||||
|
||||
int
|
||||
js::StringFindPattern(JSLinearString* text, JSLinearString* pat, size_t start)
|
||||
{
|
||||
|
|
|
@ -234,10 +234,6 @@ CompareAtoms(JSAtom* atom1, JSAtom* atom2);
|
|||
extern bool
|
||||
StringEqualsAscii(JSLinearString* str, const char* asciiBytes);
|
||||
|
||||
/* Return true if the string contains a pattern anywhere inside it. */
|
||||
extern bool
|
||||
StringHasPattern(JSLinearString* text, const char16_t* pat, uint32_t patlen);
|
||||
|
||||
extern int
|
||||
StringFindPattern(JSLinearString* text, JSLinearString* pat, size_t start);
|
||||
|
||||
|
|
|
@ -47,44 +47,6 @@ js_memcpy(void* dst_, const void* src_, size_t len)
|
|||
|
||||
namespace js {
|
||||
|
||||
template <class T>
|
||||
class AlignedPtrAndFlag
|
||||
{
|
||||
uintptr_t bits;
|
||||
|
||||
public:
|
||||
AlignedPtrAndFlag(T* t, bool aFlag) {
|
||||
MOZ_ASSERT((uintptr_t(t) & 1) == 0);
|
||||
bits = uintptr_t(t) | uintptr_t(aFlag);
|
||||
}
|
||||
|
||||
T* ptr() const {
|
||||
return (T*)(bits & ~uintptr_t(1));
|
||||
}
|
||||
|
||||
bool flag() const {
|
||||
return (bits & 1) != 0;
|
||||
}
|
||||
|
||||
void setPtr(T* t) {
|
||||
MOZ_ASSERT((uintptr_t(t) & 1) == 0);
|
||||
bits = uintptr_t(t) | uintptr_t(flag());
|
||||
}
|
||||
|
||||
void setFlag() {
|
||||
bits |= 1;
|
||||
}
|
||||
|
||||
void unsetFlag() {
|
||||
bits &= ~uintptr_t(1);
|
||||
}
|
||||
|
||||
void set(T* t, bool aFlag) {
|
||||
MOZ_ASSERT((uintptr_t(t) & 1) == 0);
|
||||
bits = uintptr_t(t) | aFlag;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
static inline void
|
||||
Reverse(T* beg, T* end)
|
||||
|
@ -183,22 +145,6 @@ Max(T t1, T t2)
|
|||
return t1 > t2 ? t1 : t2;
|
||||
}
|
||||
|
||||
/* Allows a const variable to be initialized after its declaration. */
|
||||
template <class T>
|
||||
static T&
|
||||
InitConst(const T& t)
|
||||
{
|
||||
return const_cast<T&>(t);
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
MOZ_ALWAYS_INLINE T&
|
||||
ImplicitCast(U& u)
|
||||
{
|
||||
T& t = u;
|
||||
return t;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
class MOZ_RAII AutoScopedAssign
|
||||
{
|
||||
|
|
|
@ -1409,7 +1409,7 @@ js::proxy_revocable(JSContext* cx, unsigned argc, Value* vp)
|
|||
MOZ_ASSERT(proxyVal.toObject().is<ProxyObject>());
|
||||
|
||||
RootedObject revoker(cx, NewFunctionByIdWithReserved(cx, RevokeProxy, 0, 0,
|
||||
AtomToId(cx->names().revoke)));
|
||||
NameToId(cx->names().revoke)));
|
||||
if (!revoker)
|
||||
return false;
|
||||
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
// Ensure array or object literals with trailing property accessors are not
|
||||
// treated as nested destructuring patterns in assignment destructuring
|
||||
// contexts.
|
||||
|
||||
// Array destructuring with normal element.
|
||||
[{a: 0}.x] = [];
|
||||
[[0].x] = [];
|
||||
|
||||
// Array destructuring with spread element.
|
||||
[...{a: 0}.x] = [];
|
||||
[...[0].x] = [];
|
||||
|
||||
// Object destructuring with normal property.
|
||||
({a: {b: 0}.x} = {});
|
||||
({a: [0].x} = {});
|
||||
|
||||
// Object destructuring with spread property.
|
||||
({...{b: 0}.x} = {});
|
||||
({...[0].x} = {});
|
||||
|
||||
// Object literal with initializer shorthand in destructuring context.
|
||||
assertThrowsInstanceOf(() => Function(`[{a = 0}.x] = [];`), SyntaxError);
|
||||
assertThrowsInstanceOf(() => Function(`[...{a = 0}.x] = [];`), SyntaxError);
|
||||
assertThrowsInstanceOf(() => Function(`({a: {b = 0}.x} = {});`), SyntaxError);
|
||||
assertThrowsInstanceOf(() => Function(`({...{b = 0}.x} = {});`), SyntaxError);
|
||||
|
||||
// Object destructuring with "eval" or "arguments" shorthand in strict mode.
|
||||
(function() {
|
||||
"use strict";
|
||||
|
||||
// Ensure "eval" resp. "arguments" is not treated as an assignment.
|
||||
[{eval}.x] = [];
|
||||
[...{eval}.x] = [];
|
||||
({a: {eval}.x} = {});
|
||||
({...{eval}.x} = {});
|
||||
|
||||
[{arguments}.x] = [];
|
||||
[...{arguments}.x] = [];
|
||||
({a: {arguments}.x} = {});
|
||||
({...{arguments}.x} = {});
|
||||
})();
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(0, 0);
|
|
@ -6761,10 +6761,10 @@ DebuggerScript_getOffsetsCoverage(JSContext* cx, unsigned argc, Value* vp)
|
|||
if (!result)
|
||||
return false;
|
||||
|
||||
RootedId offsetId(cx, AtomToId(cx->names().offset));
|
||||
RootedId lineNumberId(cx, AtomToId(cx->names().lineNumber));
|
||||
RootedId columnNumberId(cx, AtomToId(cx->names().columnNumber));
|
||||
RootedId countId(cx, AtomToId(cx->names().count));
|
||||
RootedId offsetId(cx, NameToId(cx->names().offset));
|
||||
RootedId lineNumberId(cx, NameToId(cx->names().lineNumber));
|
||||
RootedId columnNumberId(cx, NameToId(cx->names().columnNumber));
|
||||
RootedId countId(cx, NameToId(cx->names().count));
|
||||
|
||||
RootedObject item(cx);
|
||||
RootedValue offsetValue(cx);
|
||||
|
|
|
@ -1858,34 +1858,6 @@ js::NativeDefineProperty(JSContext* cx, HandleNativeObject obj, HandleId id,
|
|||
return NativeDefineProperty(cx, obj, id, desc, result);
|
||||
}
|
||||
|
||||
bool
|
||||
js::NativeDefineProperty(JSContext* cx, HandleNativeObject obj, PropertyName* name,
|
||||
HandleValue value, GetterOp getter, SetterOp setter, unsigned attrs,
|
||||
ObjectOpResult& result)
|
||||
{
|
||||
RootedId id(cx, NameToId(name));
|
||||
return NativeDefineProperty(cx, obj, id, value, getter, setter, attrs, result);
|
||||
}
|
||||
|
||||
bool
|
||||
js::NativeDefineElement(JSContext* cx, HandleNativeObject obj, uint32_t index,
|
||||
HandleValue value, GetterOp getter, SetterOp setter, unsigned attrs,
|
||||
ObjectOpResult& result)
|
||||
{
|
||||
RootedId id(cx);
|
||||
if (index <= JSID_INT_MAX) {
|
||||
id = INT_TO_JSID(index);
|
||||
return NativeDefineProperty(cx, obj, id, value, getter, setter, attrs, result);
|
||||
}
|
||||
|
||||
AutoRooterGetterSetter gsRoot(cx, attrs, &getter, &setter);
|
||||
|
||||
if (!IndexToId(cx, index, &id))
|
||||
return false;
|
||||
|
||||
return NativeDefineProperty(cx, obj, id, value, getter, setter, attrs, result);
|
||||
}
|
||||
|
||||
bool
|
||||
js::NativeDefineProperty(JSContext* cx, HandleNativeObject obj, HandleId id,
|
||||
HandleValue value, JSGetterOp getter, JSSetterOp setter,
|
||||
|
|
|
@ -1397,16 +1397,6 @@ NativeDefineProperty(JSContext* cx, HandleNativeObject obj, HandleId id, HandleV
|
|||
JSGetterOp getter, JSSetterOp setter, unsigned attrs,
|
||||
ObjectOpResult& result);
|
||||
|
||||
extern bool
|
||||
NativeDefineProperty(JSContext* cx, HandleNativeObject obj, PropertyName* name,
|
||||
HandleValue value, GetterOp getter, SetterOp setter,
|
||||
unsigned attrs, ObjectOpResult& result);
|
||||
|
||||
extern bool
|
||||
NativeDefineElement(JSContext* cx, HandleNativeObject obj, uint32_t index, HandleValue value,
|
||||
JSGetterOp getter, JSSetterOp setter, unsigned attrs,
|
||||
ObjectOpResult& result);
|
||||
|
||||
/* If the result out-param is omitted, throw on failure. */
|
||||
extern bool
|
||||
NativeDefineProperty(JSContext* cx, HandleNativeObject obj, HandleId id, HandleValue value,
|
||||
|
|
|
@ -186,13 +186,12 @@ intrinsic_IsConstructor(JSContext* cx, unsigned argc, Value* vp)
|
|||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
MOZ_ASSERT(args.length() == 1);
|
||||
|
||||
RootedValue val(cx, args[0]);
|
||||
if (!IsConstructor(val)) {
|
||||
if (!IsConstructor(args[0])) {
|
||||
args.rval().setBoolean(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
RootedObject obj(cx, &val.toObject());
|
||||
JSObject* obj = &args[0].toObject();
|
||||
if (!IsWrapper(obj)) {
|
||||
args.rval().setBoolean(true);
|
||||
return true;
|
||||
|
|
|
@ -1067,70 +1067,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 (!GlobalObject::ensureConstructor(cx, cx->global(), JSProto_ArrayBuffer))
|
||||
return false;
|
||||
RootedValue defaultCtor(cx, cx->global()->getConstructor(JSProto_ArrayBuffer));
|
||||
return nullptr;
|
||||
RootedObject defaultCtor(cx, &cx->global()->getConstructor(JSProto_ArrayBuffer).toObject());
|
||||
|
||||
// Use the current global's ArrayBuffer if the override is set.
|
||||
if (override == SpeciesConstructorOverride::ArrayBuffer) {
|
||||
ctor.set(defaultCtor);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!isWrapped) {
|
||||
// As an optimization, avoid calling into self-hosted code if |obj|'s
|
||||
// constructor is the built-in ArrayBuffer and the constructor's
|
||||
// species property is the original ArrayBuffer[@@species] function.
|
||||
if (IsArrayBufferSpecies(cx, obj))
|
||||
ctor.set(defaultCtor);
|
||||
else if (!SpeciesConstructor(cx, obj, defaultCtor, ctor))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
if (override == SpeciesConstructorOverride::ArrayBuffer)
|
||||
return defaultCtor;
|
||||
|
||||
RootedObject wrappedObj(cx, obj);
|
||||
if (!cx->compartment()->wrap(cx, &wrappedObj))
|
||||
return false;
|
||||
if (isWrapped && !cx->compartment()->wrap(cx, &wrappedObj))
|
||||
return nullptr;
|
||||
|
||||
if (!SpeciesConstructor(cx, wrappedObj, defaultCtor, ctor))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
return SpeciesConstructor(cx, wrappedObj, defaultCtor, IsArrayBufferSpecies);
|
||||
}
|
||||
|
||||
// ES 2017 draft rev 8633ffd9394b203b8876bb23cb79aff13eb07310 24.1.1.4.
|
||||
|
@ -1146,9 +1104,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()) {
|
||||
|
@ -1266,9 +1225,10 @@ TypedArrayObjectTemplate<T>::fromTypedArray(JSContext* cx, HandleObject other, b
|
|||
}
|
||||
} else {
|
||||
// Steps 17.a-b.
|
||||
RootedValue bufferCtor(cx);
|
||||
if (!GetSpeciesConstructor(cx, srcData, isWrapped, override, &bufferCtor))
|
||||
JSObject* ctorObj = GetSpeciesConstructor(cx, srcData, isWrapped, override);
|
||||
if (!ctorObj)
|
||||
return nullptr;
|
||||
RootedValue bufferCtor(cx, ObjectValue(*ctorObj));
|
||||
|
||||
// Steps 14-15, 17.c.
|
||||
if (!AllocateArrayBuffer(cx, bufferCtor, elementLength, BYTES_PER_ELEMENT, &buffer))
|
||||
|
|
|
@ -1765,7 +1765,7 @@ static bool
|
|||
CombineArrayObjectElements(JSContext* cx, ArrayObject* obj, JSValueType* elementType)
|
||||
{
|
||||
if (obj->inDictionaryMode() ||
|
||||
obj->lastProperty()->propid() != AtomToId(cx->names().length) ||
|
||||
obj->lastProperty()->propid() != NameToId(cx->names().length) ||
|
||||
!obj->lastProperty()->previous()->isEmptyShape())
|
||||
{
|
||||
// Only use an unboxed representation if the object has no properties.
|
||||
|
|
|
@ -60,7 +60,8 @@ using namespace xpc;
|
|||
using namespace JS;
|
||||
|
||||
static const char kObserverServiceContractID[] = "@mozilla.org/observer-service;1";
|
||||
static const char kJSCachePrefix[] = "jsloader";
|
||||
|
||||
#define JS_CACHE_PREFIX(aType) "jsloader/" aType
|
||||
|
||||
/**
|
||||
* Buffer sizes for serialization and deserialization of scripts.
|
||||
|
@ -303,7 +304,16 @@ mozJSComponentLoader::ReallyInit()
|
|||
{
|
||||
MOZ_ASSERT(!mInitialized);
|
||||
|
||||
mShareLoaderGlobal = Preferences::GetBool("jsloader.shareGlobal");
|
||||
const char* shareGlobal = PR_GetEnv("MOZ_LOADER_SHARE_GLOBAL");
|
||||
if (shareGlobal && *shareGlobal) {
|
||||
nsDependentCString val(shareGlobal);
|
||||
mShareLoaderGlobal = !(val.EqualsLiteral("0") ||
|
||||
val.LowerCaseEqualsLiteral("no") ||
|
||||
val.LowerCaseEqualsLiteral("false") ||
|
||||
val.LowerCaseEqualsLiteral("off"));
|
||||
} else {
|
||||
mShareLoaderGlobal = Preferences::GetBool("jsloader.shareGlobal");
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIObserverService> obsSvc =
|
||||
|
@ -701,7 +711,8 @@ mozJSComponentLoader::ObjectForLocation(ComponentLoaderInfo& aInfo,
|
|||
|
||||
aInfo.EnsureResolvedURI();
|
||||
|
||||
nsAutoCString cachePath(kJSCachePrefix);
|
||||
nsAutoCString cachePath(reuseGlobal ? JS_CACHE_PREFIX("non-syntactic")
|
||||
: JS_CACHE_PREFIX("global"));
|
||||
rv = PathifyURI(aInfo.ResolvedURI(), cachePath);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
[test_loader_global_sharing.py]
|
||||
skip-if = !manage_instance || appname == 'fennec'
|
|
@ -0,0 +1,7 @@
|
|||
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# 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/.
|
||||
|
||||
MARIONETTE_UNIT_MANIFESTS += ['manifest.ini']
|
|
@ -0,0 +1,119 @@
|
|||
from __future__ import print_function
|
||||
|
||||
from marionette_harness import MarionetteTestCase
|
||||
|
||||
|
||||
GLOBAL_SHARING_PREF = 'jsloader.shareGlobal'
|
||||
GLOBAL_SHARING_VAR = 'MOZ_LOADER_SHARE_GLOBAL'
|
||||
|
||||
|
||||
class TestLoaderGlobalSharing(MarionetteTestCase):
|
||||
sandbox_name = 'loader-global-sharing'
|
||||
|
||||
def execute_script(self, code, *args, **kwargs):
|
||||
with self.marionette.using_context(self.marionette.CONTEXT_CHROME):
|
||||
return self.marionette.execute_script(code,
|
||||
new_sandbox=False,
|
||||
sandbox=self.sandbox_name,
|
||||
*args, **kwargs)
|
||||
|
||||
def get_global_sharing_enabled(self):
|
||||
return self.execute_script(r'''
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
return (Cu.getGlobalForObject(Services) ===
|
||||
Cu.getGlobalForObject(XPCOMUtils))
|
||||
''')
|
||||
|
||||
def set_env(self, env, value):
|
||||
self.execute_script('env.set(arguments[0], arguments[1]);',
|
||||
script_args=(env, value))
|
||||
|
||||
def get_env(self, env):
|
||||
return self.execute_script('return env.get(arguments[0]);',
|
||||
script_args=(env,))
|
||||
|
||||
def restart(self, prefs=None, env=None):
|
||||
if prefs:
|
||||
self.marionette.set_prefs(prefs)
|
||||
|
||||
if env:
|
||||
for name, value in env.items():
|
||||
self.set_env(name, value)
|
||||
|
||||
self.marionette.restart(in_app=True, clean=False)
|
||||
self.setUpSession()
|
||||
|
||||
# Sanity check our environment.
|
||||
if prefs:
|
||||
for key, val in prefs.items():
|
||||
self.assertEqual(self.marionette.get_pref(key), val)
|
||||
if env:
|
||||
for key, val in env.items():
|
||||
self.assertEqual(self.get_env(key), val or '')
|
||||
|
||||
def setUpSession(self):
|
||||
self.marionette.set_context(self.marionette.CONTEXT_CHROME)
|
||||
|
||||
self.execute_script(r'''
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} =
|
||||
Components;
|
||||
|
||||
// We're running in a function, in a sandbox, that inherits from an
|
||||
// X-ray wrapped window. Anything we want to be globally available
|
||||
// needs to be defined on that window.
|
||||
Object.assign(window, {Cc, Ci, Cu, Cr});
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
window.env = Cc["@mozilla.org/process/environment;1"]
|
||||
.getService(Ci.nsIEnvironment);
|
||||
''')
|
||||
|
||||
def setUp(self):
|
||||
super(TestLoaderGlobalSharing, self).setUp()
|
||||
|
||||
self.default_pref_value = self.marionette.get_pref(GLOBAL_SHARING_PREF)
|
||||
|
||||
self.setUpSession()
|
||||
|
||||
def tearDown(self):
|
||||
self.marionette.restart(clean=True)
|
||||
|
||||
super(TestLoaderGlobalSharing, self).tearDown()
|
||||
|
||||
def test_global_sharing_settings(self):
|
||||
# The different cases to test, with the first element being the value
|
||||
# of the MOZ_LOADER_SHARE_GLOBAL environment variable, and the second
|
||||
# being the value of the "jsloader.shareGlobal" preference.
|
||||
#
|
||||
# The browser is restarted after each change, but the profile is not
|
||||
# reset.
|
||||
CASES = (
|
||||
(None, False),
|
||||
(None, True),
|
||||
('0', True),
|
||||
('1', True),
|
||||
('0', False),
|
||||
('1', False),
|
||||
)
|
||||
|
||||
for var, pref in CASES:
|
||||
print('Testing %s=%r %s=%r' % (GLOBAL_SHARING_VAR, var,
|
||||
GLOBAL_SHARING_PREF, pref))
|
||||
|
||||
# The value of the environment variable takes precedence if it's
|
||||
# defined.
|
||||
expect_sharing = pref if var is None else var != '0'
|
||||
|
||||
self.restart(prefs={GLOBAL_SHARING_PREF: pref},
|
||||
env={GLOBAL_SHARING_VAR: var})
|
||||
|
||||
have_sharing = self.get_global_sharing_enabled()
|
||||
|
||||
# FIXME: User preference values currently do not always take
|
||||
# effect early enough to influence loader behavior.
|
||||
msg = ('Global sharing state should match settings: %r != %r'
|
||||
% (have_sharing, expect_sharing))
|
||||
if var is not None or pref == self.default_pref_value:
|
||||
self.assertEqual(have_sharing, expect_sharing, msg)
|
||||
elif have_sharing != expect_sharing:
|
||||
print('TEST-EXPECTED-FAIL: ' + msg)
|
|
@ -5,6 +5,7 @@
|
|||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
TEST_DIRS += [
|
||||
'marionette',
|
||||
'mochitest',
|
||||
'chrome',
|
||||
'browser',
|
||||
|
|
|
@ -43,6 +43,15 @@ public:
|
|||
, mPendingWrapperRestyles(aPendingWrapperRestyles)
|
||||
, mPendingWrapperRestyleOffset(aPendingWrapperRestyles.Length())
|
||||
, mChangesHandled(nsChangeHint(0))
|
||||
#ifdef DEBUG
|
||||
// If !mOwner, then we wouldn't have processed our wrapper restyles, because
|
||||
// we only process those when handling an element with a frame. But that's
|
||||
// OK, because if we started our traversal at an element with no frame
|
||||
// (e.g. it's display:contents), that means the wrapper frames in our list
|
||||
// actually inherit from one of its ancestors, not from it, and hence not
|
||||
// restyling them is OK.
|
||||
, mAssertWrapperRestyleLength(false)
|
||||
#endif // DEBUG
|
||||
{}
|
||||
|
||||
// We shouldn't assume that changes handled from our parent are handled for
|
||||
|
@ -159,7 +168,7 @@ private:
|
|||
// Whether we should assert in our destructor that we've processed all of the
|
||||
// relevant wrapper restyles.
|
||||
#ifdef DEBUG
|
||||
const bool mAssertWrapperRestyleLength = true;
|
||||
const bool mAssertWrapperRestyleLength;
|
||||
#endif // DEBUG
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<script>
|
||||
window.onload = () => {
|
||||
a = document.createElement("x")
|
||||
document.documentElement.appendChild(a)
|
||||
a.animate([{ "filter": "sepia(7)" }], 3000)
|
||||
b = document.createElement("caption")
|
||||
a.appendChild(b)
|
||||
a.style = "display:contents"
|
||||
//DDBEGIN
|
||||
b.animate([{ "padding": "912q" }], 1500)
|
||||
//DDEND
|
||||
a.animate([{}])
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
</html>
|
|
@ -0,0 +1,20 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<script>
|
||||
window.onload = () => {
|
||||
a = document.createElement("x")
|
||||
document.documentElement.appendChild(a)
|
||||
a.animate([{ "color": "green" }], 3000)
|
||||
b = document.createElement("caption")
|
||||
a.appendChild(b)
|
||||
a.style = "display:contents"
|
||||
//DDBEGIN
|
||||
b.animate([{ "text-indent": "912q" }], 1500)
|
||||
//DDEND
|
||||
a.animate([{}])
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
</html>
|
|
@ -0,0 +1,8 @@
|
|||
<!DOCTYPE html>
|
||||
<span id="x" style="display: contents">
|
||||
<span style="display: table-caption">
|
||||
</span>
|
||||
<script>
|
||||
document.body.offsetWidth;
|
||||
x.style.color = "green";
|
||||
</script>
|
|
@ -497,3 +497,6 @@ asserts-if(!stylo,1) load 1388625-1.html # bug 1389286
|
|||
load 1390389.html
|
||||
load 1395591-1.html
|
||||
load 1395715-1.html
|
||||
load 1397398-1.html
|
||||
load 1397398-2.html
|
||||
load 1397398-3.html
|
||||
|
|
|
@ -7743,10 +7743,39 @@ nsCSSFrameConstructor::ContentAppended(nsIContent* aContainer,
|
|||
|
||||
// Deal with possible :after generated content on the parent
|
||||
nsIFrame* parentAfterFrame;
|
||||
nsContainerFrame* preAdjustedParentFrame = parentFrame;
|
||||
parentFrame =
|
||||
::AdjustAppendParentForAfterContent(this, insertion.mContainer, parentFrame,
|
||||
aFirstNewContent, &parentAfterFrame);
|
||||
|
||||
// See if the containing block has :first-letter style applied.
|
||||
bool haveFirstLetterStyle = false, haveFirstLineStyle = false;
|
||||
nsContainerFrame* containingBlock = GetFloatContainingBlock(parentFrame);
|
||||
if (containingBlock) {
|
||||
haveFirstLetterStyle = HasFirstLetterStyle(containingBlock);
|
||||
haveFirstLineStyle =
|
||||
ShouldHaveFirstLineStyle(containingBlock->GetContent(),
|
||||
containingBlock->StyleContext());
|
||||
}
|
||||
|
||||
if (haveFirstLetterStyle) {
|
||||
AutoWeakFrame wf(parentAfterFrame);
|
||||
// Before we get going, remove the current letter frames
|
||||
RemoveLetterFrames(mPresShell, containingBlock);
|
||||
|
||||
if (parentAfterFrame && !wf) {
|
||||
// Ouch, parentAfterFrame was a letter frame and we just deleted it!
|
||||
// Retry AdjustAppendParentForAfterContent; fortunately this is rare.
|
||||
parentFrame =
|
||||
::AdjustAppendParentForAfterContent(this, insertion.mContainer,
|
||||
preAdjustedParentFrame,
|
||||
aFirstNewContent, &parentAfterFrame);
|
||||
if (parentFrame != preAdjustedParentFrame) {
|
||||
containingBlock = GetFloatContainingBlock(parentFrame);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create some new frames
|
||||
//
|
||||
// We use the provided tree match context, or create a new one on the fly
|
||||
|
@ -7760,22 +7789,7 @@ nsCSSFrameConstructor::ContentAppended(nsIContent* aContainer,
|
|||
matchContext.ptrOr(aProvidedTreeMatchContext),
|
||||
GetAbsoluteContainingBlock(parentFrame, FIXED_POS),
|
||||
GetAbsoluteContainingBlock(parentFrame, ABS_POS),
|
||||
GetFloatContainingBlock(parentFrame));
|
||||
|
||||
// See if the containing block has :first-letter style applied.
|
||||
bool haveFirstLetterStyle = false, haveFirstLineStyle = false;
|
||||
nsContainerFrame* containingBlock = state.mFloatedItems.containingBlock;
|
||||
if (containingBlock) {
|
||||
haveFirstLetterStyle = HasFirstLetterStyle(containingBlock);
|
||||
haveFirstLineStyle =
|
||||
ShouldHaveFirstLineStyle(containingBlock->GetContent(),
|
||||
containingBlock->StyleContext());
|
||||
}
|
||||
|
||||
if (haveFirstLetterStyle) {
|
||||
// Before we get going, remove the current letter frames
|
||||
RemoveLetterFrames(state.mPresShell, containingBlock);
|
||||
}
|
||||
containingBlock);
|
||||
|
||||
LayoutFrameType frameType = parentFrame->Type();
|
||||
|
||||
|
|
|
@ -146,6 +146,12 @@ FRAME_ID(nsXULLabelFrame, XULLabel, NotLeaf)
|
|||
FRAME_ID(nsXULScrollFrame, Scroll, NotLeaf)
|
||||
FRAME_ID(ViewportFrame, Viewport, NotLeaf)
|
||||
|
||||
// The following ABSTRACT_FRAME_IDs needs to come after the above
|
||||
// FRAME_IDs, because we have two separate enums, one that includes
|
||||
// only FRAME_IDs and another which includes both and we depend on
|
||||
// FRAME_IDs to have the same number in both.
|
||||
// See ClassID (the former) and FrameIID in nsQueryFrame.h.
|
||||
|
||||
// Non-concrete classes (for FrameIID use)
|
||||
ABSTRACT_FRAME_ID(nsContainerFrame)
|
||||
ABSTRACT_FRAME_ID(nsFormControlFrame)
|
||||
|
|
|
@ -713,6 +713,7 @@ protected:
|
|||
friend class nsLineBox; // needed to pass aDestructRoot through to children
|
||||
friend class nsContainerFrame; // needed to pass aDestructRoot through to children
|
||||
friend class nsFrame; // need to assign mParent
|
||||
template<class Source> friend class do_QueryFrameHelper; // to read mClass
|
||||
public:
|
||||
|
||||
/**
|
||||
|
@ -4486,6 +4487,13 @@ private:
|
|||
nsIFrame* mFrame;
|
||||
};
|
||||
|
||||
// Use nsIFrame's fast-path to avoid QueryFrame:
|
||||
inline do_QueryFrameHelper<nsIFrame>
|
||||
do_QueryFrame(AutoWeakFrame& s)
|
||||
{
|
||||
return do_QueryFrameHelper<nsIFrame>(s.GetFrame());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see AutoWeakFrame
|
||||
*/
|
||||
|
@ -4543,6 +4551,13 @@ private:
|
|||
nsIFrame* mFrame;
|
||||
};
|
||||
|
||||
// Use nsIFrame's fast-path to avoid QueryFrame:
|
||||
inline do_QueryFrameHelper<nsIFrame>
|
||||
do_QueryFrame(WeakFrame& s)
|
||||
{
|
||||
return do_QueryFrameHelper<nsIFrame>(s.GetFrame());
|
||||
}
|
||||
|
||||
inline bool
|
||||
nsFrameList::ContinueRemoveFrame(nsIFrame* aFrame)
|
||||
{
|
||||
|
|
|
@ -82,29 +82,66 @@ public:
|
|||
virtual void* QueryFrame(FrameIID id) = 0;
|
||||
};
|
||||
|
||||
class do_QueryFrame
|
||||
class nsIFrame;
|
||||
|
||||
template<class Source>
|
||||
class do_QueryFrameHelper
|
||||
{
|
||||
public:
|
||||
explicit do_QueryFrame(nsQueryFrame *s) : mRawPtr(s) { }
|
||||
explicit do_QueryFrameHelper(Source* s) : mRawPtr(s) { }
|
||||
|
||||
// The return and argument types here are arbitrarily selected so no
|
||||
// corresponding member function exists.
|
||||
typedef void (do_QueryFrame::* MatchNullptr)(double, float);
|
||||
typedef void (do_QueryFrameHelper::* MatchNullptr)(double, float);
|
||||
// Implicit constructor for nullptr, trick borrowed from already_AddRefed.
|
||||
MOZ_IMPLICIT do_QueryFrame(MatchNullptr aRawPtr) : mRawPtr(nullptr) {}
|
||||
MOZ_IMPLICIT do_QueryFrameHelper(MatchNullptr aRawPtr) : mRawPtr(nullptr) {}
|
||||
|
||||
template<class Dest>
|
||||
operator Dest*() {
|
||||
static_assert(mozilla::IsSame<Dest, typename Dest::Has_NS_DECL_QUERYFRAME_TARGET>::value,
|
||||
"Dest must declare itself as a queryframe target");
|
||||
if (!mRawPtr)
|
||||
if (!mRawPtr) {
|
||||
return nullptr;
|
||||
|
||||
}
|
||||
if (Dest* f = FastQueryFrame<Source, Dest>::QueryFrame(mRawPtr)) {
|
||||
MOZ_ASSERT(f ==
|
||||
reinterpret_cast<Dest*>(mRawPtr->QueryFrame(Dest::kFrameIID)),
|
||||
"fast and slow paths should give the same result");
|
||||
return f;
|
||||
}
|
||||
return reinterpret_cast<Dest*>(mRawPtr->QueryFrame(Dest::kFrameIID));
|
||||
}
|
||||
|
||||
private:
|
||||
nsQueryFrame *mRawPtr;
|
||||
// For non-nsIFrame types there is no fast-path.
|
||||
template<class Src, class Dst, typename = void, typename = void>
|
||||
struct FastQueryFrame
|
||||
{
|
||||
static Dst* QueryFrame(Src* aFrame) { return nullptr; }
|
||||
};
|
||||
|
||||
// Specialization for any nsIFrame type to any nsIFrame type -- if the source
|
||||
// instance's mClass matches kFrameIID of the destination type then
|
||||
// downcasting is safe.
|
||||
template<class Src, class Dst>
|
||||
struct FastQueryFrame<Src, Dst,
|
||||
typename mozilla::EnableIf<mozilla::IsBaseOf<nsIFrame, Src>::value>::Type,
|
||||
typename mozilla::EnableIf<mozilla::IsBaseOf<nsIFrame, Dst>::value>::Type>
|
||||
{
|
||||
static Dst* QueryFrame(Src* aFrame) {
|
||||
return nsQueryFrame::FrameIID(aFrame->mClass) == Dst::kFrameIID ?
|
||||
reinterpret_cast<Dst*>(aFrame) : nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
Source* mRawPtr;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
inline do_QueryFrameHelper<T>
|
||||
do_QueryFrame(T* s)
|
||||
{
|
||||
return do_QueryFrameHelper<T>(s);
|
||||
}
|
||||
|
||||
#endif // nsQueryFrame_h
|
||||
|
|
|
@ -1233,7 +1233,7 @@ fuzzy-if(skiaContent,1,12000) fails-if(webrender) == 461512-1.html 461512-1-ref.
|
|||
== 462844-3.html 462844-ref.html
|
||||
== 462844-4.html 462844-ref.html
|
||||
== 463204-1.html 463204-1-ref.html
|
||||
fuzzy-if(webrender,16,3425) == 463217-1.xul 463217-1-ref.xul
|
||||
fuzzy-if(webrender,16-16,3425-3425) == 463217-1.xul 463217-1-ref.xul
|
||||
== 463952-1.html 463952-1-ref.html
|
||||
== 464811-1.html 464811-1-ref.html
|
||||
== 465574-1.html 465574-1-ref.html # bug 421436
|
||||
|
|
|
@ -111,6 +111,16 @@ public:
|
|||
// clearly identify in DMD's output the memory measured here.
|
||||
*aCVsSize += ServoComputedValuesMallocEnclosingSizeOf(this);
|
||||
mSource.AddSizeOfExcludingThis(aSizes);
|
||||
|
||||
if (mNextInheritingAnonBoxStyle &&
|
||||
!aSizes.mState.HaveSeenPtr(mNextInheritingAnonBoxStyle)) {
|
||||
mNextInheritingAnonBoxStyle->AddSizeOfIncludingThis(aSizes, aCVsSize);
|
||||
}
|
||||
|
||||
if (mNextLazyPseudoStyle &&
|
||||
!aSizes.mState.HaveSeenPtr(mNextLazyPseudoStyle)) {
|
||||
mNextLazyPseudoStyle->AddSizeOfIncludingThis(aSizes, aCVsSize);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
|
@ -94,6 +94,8 @@ if CONFIG['MOZ_XUL']:
|
|||
if CONFIG['MOZ_XUL']:
|
||||
DIRS += ['tree', 'grid']
|
||||
|
||||
include('/ipc/chromium/chromium-config.mozbuild')
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
LOCAL_INCLUDES += [
|
||||
'../base',
|
||||
|
|
|
@ -52,6 +52,12 @@
|
|||
#include "mozilla/Maybe.h"
|
||||
#include "SVGImageContext.h"
|
||||
#include "Units.h"
|
||||
#include "mozilla/layers/WebRenderLayerManager.h"
|
||||
|
||||
#if defined(XP_WIN)
|
||||
// Undefine LoadImage to prevent naming conflict with Windows.
|
||||
#undef LoadImage
|
||||
#endif
|
||||
|
||||
#define ONLOAD_CALLED_TOO_EARLY 1
|
||||
|
||||
|
@ -341,32 +347,53 @@ nsImageBoxFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
|||
aLists.Content()->AppendToTop(&list);
|
||||
}
|
||||
|
||||
DrawResult
|
||||
nsImageBoxFrame::PaintImage(gfxContext& aRenderingContext,
|
||||
const nsRect& aDirtyRect, nsPoint aPt,
|
||||
uint32_t aFlags)
|
||||
already_AddRefed<imgIContainer>
|
||||
nsImageBoxFrame::GetImageContainerForPainting(const nsPoint& aPt,
|
||||
DrawResult& aDrawResult,
|
||||
Maybe<nsPoint>& aAnchorPoint,
|
||||
nsRect& aDest)
|
||||
{
|
||||
if (!mImageRequest) {
|
||||
// This probably means we're drawn by a native theme.
|
||||
return DrawResult::SUCCESS;
|
||||
aDrawResult = DrawResult::SUCCESS;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Don't draw if the image's size isn't available.
|
||||
uint32_t imgStatus;
|
||||
if (!NS_SUCCEEDED(mImageRequest->GetImageStatus(&imgStatus)) ||
|
||||
!(imgStatus & imgIRequest::STATUS_SIZE_AVAILABLE)) {
|
||||
return DrawResult::NOT_READY;
|
||||
aDrawResult = DrawResult::NOT_READY;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsCOMPtr<imgIContainer> imgCon;
|
||||
mImageRequest->GetImage(getter_AddRefs(imgCon));
|
||||
|
||||
if (!imgCon) {
|
||||
return DrawResult::NOT_READY;
|
||||
aDrawResult = DrawResult::NOT_READY;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
aDest = GetDestRect(aPt, aAnchorPoint);
|
||||
aDrawResult = DrawResult::SUCCESS;
|
||||
return imgCon.forget();
|
||||
}
|
||||
|
||||
DrawResult
|
||||
nsImageBoxFrame::PaintImage(gfxContext& aRenderingContext,
|
||||
const nsRect& aDirtyRect, nsPoint aPt,
|
||||
uint32_t aFlags)
|
||||
{
|
||||
DrawResult result;
|
||||
Maybe<nsPoint> anchorPoint;
|
||||
nsRect dest = GetDestRect(aPt, anchorPoint);
|
||||
nsRect dest;
|
||||
nsCOMPtr<imgIContainer> imgCon = GetImageContainerForPainting(aPt, result,
|
||||
anchorPoint,
|
||||
dest);
|
||||
if (!imgCon) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// don't draw if the image is not dirty
|
||||
// XXX(seth): Can this actually happen anymore?
|
||||
|
@ -389,6 +416,54 @@ nsImageBoxFrame::PaintImage(gfxContext& aRenderingContext,
|
|||
hasSubRect ? &mSubRect : nullptr);
|
||||
}
|
||||
|
||||
DrawResult
|
||||
nsImageBoxFrame::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
|
||||
const StackingContextHelper& aSc,
|
||||
mozilla::layers::WebRenderLayerManager* aManager,
|
||||
nsDisplayItem* aItem,
|
||||
nsPoint aPt,
|
||||
uint32_t aFlags)
|
||||
{
|
||||
DrawResult result;
|
||||
Maybe<nsPoint> anchorPoint;
|
||||
nsRect dest;
|
||||
nsCOMPtr<imgIContainer> imgCon = GetImageContainerForPainting(aPt, result,
|
||||
anchorPoint,
|
||||
dest);
|
||||
if (!imgCon) {
|
||||
return result;
|
||||
}
|
||||
|
||||
uint32_t containerFlags = imgIContainer::FLAG_NONE;
|
||||
if (aFlags & nsImageRenderer::FLAG_SYNC_DECODE_IMAGES) {
|
||||
containerFlags |= imgIContainer::FLAG_SYNC_DECODE;
|
||||
}
|
||||
RefPtr<layers::ImageContainer> container =
|
||||
imgCon->GetImageContainer(aManager, containerFlags);
|
||||
if (!container) {
|
||||
NS_WARNING("Failed to get image container");
|
||||
return DrawResult::NOT_READY;
|
||||
}
|
||||
|
||||
gfx::IntSize size;
|
||||
Maybe<wr::ImageKey> key = aManager->CreateImageKey(aItem, container, aBuilder, aSc, size);
|
||||
if (key.isNothing()) {
|
||||
return DrawResult::BAD_IMAGE;
|
||||
}
|
||||
const int32_t appUnitsPerDevPixel = PresContext()->AppUnitsPerDevPixel();
|
||||
LayoutDeviceRect fillRect = LayoutDeviceRect::FromAppUnits(dest,
|
||||
appUnitsPerDevPixel);
|
||||
wr::LayoutRect fill = aSc.ToRelativeLayoutRect(fillRect);
|
||||
|
||||
LayoutDeviceSize gapSize(0, 0);
|
||||
SamplingFilter sampleFilter = nsLayoutUtils::GetSamplingFilterForFrame(aItem->Frame());
|
||||
aBuilder.PushImage(fill, fill,
|
||||
wr::ToLayoutSize(fillRect.Size()), wr::ToLayoutSize(gapSize),
|
||||
wr::ToImageRendering(sampleFilter), key.value());
|
||||
|
||||
return DrawResult::SUCCESS;
|
||||
}
|
||||
|
||||
nsRect
|
||||
nsImageBoxFrame::GetDestRect(const nsPoint& aOffset, Maybe<nsPoint>& aAnchorPoint)
|
||||
{
|
||||
|
@ -453,6 +528,55 @@ void nsDisplayXULImage::Paint(nsDisplayListBuilder* aBuilder,
|
|||
nsDisplayItemGenericImageGeometry::UpdateDrawResult(this, result);
|
||||
}
|
||||
|
||||
LayerState
|
||||
nsDisplayXULImage::GetLayerState(nsDisplayListBuilder* aBuilder,
|
||||
LayerManager* aManager,
|
||||
const ContainerLayerParameters& aParameters)
|
||||
{
|
||||
if (ShouldUseAdvancedLayer(aManager, gfxPrefs::LayersAllowImageLayers) &&
|
||||
CanOptimizeToImageLayer(aManager, aBuilder)) {
|
||||
return LAYER_ACTIVE;
|
||||
}
|
||||
return LAYER_NONE;
|
||||
}
|
||||
|
||||
already_AddRefed<Layer>
|
||||
nsDisplayXULImage::BuildLayer(nsDisplayListBuilder* aBuilder,
|
||||
LayerManager* aManager,
|
||||
const ContainerLayerParameters& aContainerParameters)
|
||||
{
|
||||
return BuildDisplayItemLayer(aBuilder, aManager, aContainerParameters);
|
||||
}
|
||||
|
||||
bool
|
||||
nsDisplayXULImage::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
|
||||
const StackingContextHelper& aSc,
|
||||
nsTArray<WebRenderParentCommand>& aParentCommands,
|
||||
mozilla::layers::WebRenderLayerManager* aManager,
|
||||
nsDisplayListBuilder* aDisplayListBuilder)
|
||||
{
|
||||
if (aManager->IsLayersFreeTransaction()) {
|
||||
ContainerLayerParameters parameter;
|
||||
if (GetLayerState(aDisplayListBuilder, aManager, parameter) != LAYER_ACTIVE) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t flags = imgIContainer::FLAG_SYNC_DECODE_IF_FAST;
|
||||
if (aDisplayListBuilder->ShouldSyncDecodeImages()) {
|
||||
flags |= imgIContainer::FLAG_SYNC_DECODE;
|
||||
}
|
||||
if (aDisplayListBuilder->IsPaintingToWindow()) {
|
||||
flags |= imgIContainer::FLAG_HIGH_QUALITY_SCALING;
|
||||
}
|
||||
|
||||
DrawResult result = static_cast<nsImageBoxFrame*>(mFrame)->
|
||||
CreateWebRenderCommands(aBuilder, aSc, aManager, this, ToReferenceFrame(), flags);
|
||||
|
||||
nsDisplayItemGenericImageGeometry::UpdateDrawResult(this, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
nsDisplayItemGeometry*
|
||||
nsDisplayXULImage::AllocateGeometry(nsDisplayListBuilder* aBuilder)
|
||||
{
|
||||
|
|
|
@ -90,10 +90,22 @@ public:
|
|||
|
||||
virtual ~nsImageBoxFrame();
|
||||
|
||||
already_AddRefed<imgIContainer> GetImageContainerForPainting(const nsPoint& aPt,
|
||||
DrawResult& aDrawResult,
|
||||
Maybe<nsPoint>& aAnchorPoint,
|
||||
nsRect& aDest);
|
||||
|
||||
DrawResult PaintImage(gfxContext& aRenderingContext,
|
||||
const nsRect& aDirtyRect,
|
||||
nsPoint aPt, uint32_t aFlags);
|
||||
|
||||
DrawResult CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
|
||||
const mozilla::layers::StackingContextHelper& aSc,
|
||||
mozilla::layers::WebRenderLayerManager* aManager,
|
||||
nsDisplayItem* aItem,
|
||||
nsPoint aPt,
|
||||
uint32_t aFlags);
|
||||
|
||||
bool CanOptimizeToImageLayer();
|
||||
|
||||
nsRect GetDestRect(const nsPoint& aOffset, Maybe<nsPoint>& aAnchorPoint);
|
||||
|
@ -158,6 +170,21 @@ public:
|
|||
// event receiver for us
|
||||
virtual void Paint(nsDisplayListBuilder* aBuilder,
|
||||
gfxContext* aCtx) override;
|
||||
|
||||
virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
|
||||
LayerManager* aManager,
|
||||
const ContainerLayerParameters& aParameters) override;
|
||||
|
||||
virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
|
||||
LayerManager* aManager,
|
||||
const ContainerLayerParameters& aContainerParameters) override;
|
||||
|
||||
virtual bool CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
|
||||
const StackingContextHelper& aSc,
|
||||
nsTArray<WebRenderParentCommand>& aParentCommands,
|
||||
mozilla::layers::WebRenderLayerManager* aManager,
|
||||
nsDisplayListBuilder* aDisplayListBuilder) override;
|
||||
|
||||
NS_DISPLAY_DECL_NAME("XULImage", TYPE_XUL_IMAGE)
|
||||
};
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
fails-if(Android) == textbox-multiline-noresize.xul textbox-multiline-ref.xul # reference is blank on Android (due to no native theme support?)
|
||||
!= textbox-multiline-resize.xul textbox-multiline-ref.xul
|
||||
== popup-explicit-size.xul popup-explicit-size-ref.xul
|
||||
random-if(Android) fuzzy-if(webrender,21-21,10746-10746) == image-size.xul image-size-ref.xul
|
||||
random-if(Android) == image-size.xul image-size-ref.xul
|
||||
== image-scaling-min-height-1.xul image-scaling-min-height-1-ref.xul
|
||||
== textbox-text-transform.xul textbox-text-transform-ref.xul
|
||||
|
|
|
@ -1140,4 +1140,4 @@ static const TransportSecurityPreload kPublicKeyPinningPreloadList[] = {
|
|||
|
||||
static const int32_t kUnknownId = -1;
|
||||
|
||||
static const PRTime kPreloadPKPinsExpirationTime = INT64_C(1513358056232000);
|
||||
static const PRTime kPreloadPKPinsExpirationTime = INT64_C(1513444695639000);
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -169,12 +169,15 @@ linux64-jsdcov/opt:
|
|||
windows7-32/debug:
|
||||
build-platform: win32/debug
|
||||
test-sets:
|
||||
- windows-reftest-gpu
|
||||
- windows-tests
|
||||
|
||||
windows7-32/opt:
|
||||
build-platform: win32/opt
|
||||
test-sets:
|
||||
- awsy
|
||||
- desktop-screenshot-capture
|
||||
- windows-reftest-gpu
|
||||
- windows-talos
|
||||
- windows-talos-stylo-disabled
|
||||
- windows-tests
|
||||
|
@ -184,21 +187,24 @@ windows7-32-pgo/opt:
|
|||
test-sets:
|
||||
- awsy
|
||||
- desktop-screenshot-capture
|
||||
- windows-tests
|
||||
- windows-reftest-gpu
|
||||
- windows-talos
|
||||
- windows-talos-stylo-disabled
|
||||
- windows-tests
|
||||
|
||||
windows7-32-nightly/opt:
|
||||
build-platform: win32-nightly/opt
|
||||
test-sets:
|
||||
- awsy
|
||||
- desktop-screenshot-capture
|
||||
- windows-reftest-gpu
|
||||
- windows-tests
|
||||
|
||||
windows7-32-devedition/opt:
|
||||
build-platform: win32-devedition-nightly/opt
|
||||
test-sets:
|
||||
- desktop-screenshot-capture
|
||||
- windows-reftest-gpu
|
||||
- windows-tests
|
||||
|
||||
# win64
|
||||
|
|
|
@ -146,6 +146,9 @@ linux-talos-stylo-disabled:
|
|||
- talos-perf-reftest-stylo-disabled
|
||||
- talos-perf-reftest-singletons-stylo-disabled
|
||||
|
||||
windows-reftest-gpu:
|
||||
- reftest-gpu
|
||||
|
||||
windows-tests:
|
||||
- cppunit
|
||||
- crashtest
|
||||
|
@ -167,7 +170,6 @@ windows-tests:
|
|||
- mochitest-media
|
||||
- mochitest-webgl
|
||||
- reftest
|
||||
- reftest-gpu
|
||||
- reftest-no-accel
|
||||
- web-platform-tests
|
||||
- web-platform-tests-reftests
|
||||
|
|
|
@ -10,3 +10,6 @@ skip-if = asan # Bug 1223277, 1348961
|
|||
|
||||
# migration tests
|
||||
[include:../../../../../browser/components/migration/tests/marionette/manifest.ini]
|
||||
|
||||
# xpconnect tests
|
||||
[include:../../../../../js/xpconnect/tests/marionette/manifest.ini]
|
||||
|
|
Загрузка…
Ссылка в новой задаче