Merge inbound to central, a=merge

MozReview-Commit-ID: 5H1ZxSV0XuM
This commit is contained in:
Wes Kocher 2017-02-07 16:33:31 -08:00
Родитель eba276a4fb 4f53741ced
Коммит 672c83ed65
103 изменённых файлов: 2340 добавлений и 1297 удалений

Просмотреть файл

@ -31,6 +31,7 @@ support-files =
[browser_cubic-bezier-04.js]
[browser_cubic-bezier-05.js]
[browser_cubic-bezier-06.js]
[browser_cubic-bezier-07.js]
[browser_filter-editor-01.js]
[browser_filter-editor-02.js]
[browser_filter-editor-03.js]

Просмотреть файл

@ -0,0 +1,53 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Tests that changing the cubic-bezier curve in the widget does change the dot animation
// preview too.
const {CubicBezierWidget} = require("devtools/client/shared/widgets/CubicBezierWidget");
const {PREDEFINED} = require("devtools/client/shared/widgets/CubicBezierPresets");
const TEST_URI = `data:text/html,<div id="cubic-bezier-container" />`;
add_task(function* () {
let [host,, doc] = yield createHost("bottom", TEST_URI);
let container = doc.querySelector("#cubic-bezier-container");
let w = new CubicBezierWidget(container, PREDEFINED.linear);
yield previewDotReactsToChanges(w, [0.6, -0.28, 0.74, 0.05]);
yield previewDotReactsToChanges(w, [0.9, 0.03, 0.69, 0.22]);
yield previewDotReactsToChanges(w, [0.68, -0.55, 0.27, 1.55]);
yield previewDotReactsToChanges(w, PREDEFINED.ease, "ease");
yield previewDotReactsToChanges(w, PREDEFINED["ease-in-out"], "ease-in-out");
w.destroy();
host.destroy();
});
function* previewDotReactsToChanges(widget, coords, expectedEasing) {
let onUpdated = widget.once("updated");
widget.coordinates = coords;
yield onUpdated;
let animatedDot = widget.timingPreview.dot;
let animations = animatedDot.getAnimations();
if (!expectedEasing) {
expectedEasing =
`cubic-bezier(${coords[0]}, ${coords[1]}, ${coords[2]}, ${coords[3]})`;
}
is(animations.length, 1, "The dot is animated");
let goingToRight = animations[0].effect.getKeyframes()[2];
is(goingToRight.easing, expectedEasing,
`The easing when going to the right was set correctly to ${coords}`);
let goingToLeft = animations[0].effect.getKeyframes()[6];
is(goingToLeft.easing, expectedEasing,
`The easing when going to the left was set correctly to ${coords}`);
}

Просмотреть файл

@ -418,7 +418,7 @@ CubicBezierWidget.prototype = {
this.bezierCanvas.plot();
this.emit("updated", this.bezierCanvas.bezier);
this.timingPreview.preview(this.bezierCanvas.bezier + "");
this.timingPreview.preview(this.bezierCanvas.bezier.toString());
},
/**
@ -721,7 +721,6 @@ CubicBezierPresetWidget.prototype = {
*/
function TimingFunctionPreviewWidget(parent) {
this.previousValue = null;
this.autoRestartAnimation = null;
this.parent = parent;
this._initMarkup();
@ -748,7 +747,7 @@ TimingFunctionPreviewWidget.prototype = {
},
destroy: function () {
clearTimeout(this.autoRestartAnimation);
this.dot.getAnimations().forEach(anim => anim.cancel());
this.parent.querySelector(".timing-function-preview").remove();
this.parent = this.dot = null;
},
@ -765,35 +764,42 @@ TimingFunctionPreviewWidget.prototype = {
return;
}
clearTimeout(this.autoRestartAnimation);
if (parseTimingFunction(value)) {
this.dot.style.animationTimingFunction = value;
this.restartAnimation();
this.restartAnimation(value);
}
this.previousValue = value;
},
/**
* Re-start the preview animation from the beginning
* Re-start the preview animation from the beginning.
* @param {String} timingFunction The value for the timing-function.
*/
restartAnimation: function () {
// Just toggling the class won't do it unless there's a sync reflow
this.dot.animate([
{ left: "-7px", offset: 0 },
{ left: "143px", offset: 0.25 },
{ left: "143px", offset: 0.5 },
{ left: "-7px", offset: 0.75 },
{ left: "-7px", offset: 1 }
], {
duration: (this.PREVIEW_DURATION * 2),
fill: "forwards"
});
restartAnimation: function (timingFunction) {
// Cancel the previous animation if there was any.
this.dot.getAnimations().forEach(anim => anim.cancel());
// Restart it again after a while
this.autoRestartAnimation = setTimeout(this.restartAnimation.bind(this),
this.PREVIEW_DURATION * 2);
// And start the new one.
// The animation consists of a few keyframes that move the dot to the right of the
// container, and then move it back to the left.
// It also contains some pause where the dot is semi transparent, before it moves to
// the right, and once again, before it comes back to the left.
// The timing function passed to this function is applied to the keyframes that
// actually move the dot. This way it can be previewed in both direction, instead of
// being spread over the whole animation.
this.dot.animate([
{ left: "-7px", opacity: .5, offset: 0 },
{ left: "-7px", opacity: .5, offset: .19 },
{ left: "-7px", opacity: 1, offset: .2, easing: timingFunction },
{ left: "143px", opacity: 1, offset: .5 },
{ left: "143px", opacity: .5, offset: .51 },
{ left: "143px", opacity: .5, offset: .7 },
{ left: "143px", opacity: 1, offset: .71, easing: timingFunction },
{ left: "-7px", opacity: 1, offset: 1 }
], {
duration: this.PREVIEW_DURATION * 2,
iterations: Infinity
});
}
};

Просмотреть файл

@ -50,3 +50,4 @@ DEPRECATED_OPERATION(PrefixedFullscreenAPI)
DEPRECATED_OPERATION(LenientSetter)
DEPRECATED_OPERATION(FileLastModifiedDate)
DEPRECATED_OPERATION(ImageBitmapRenderingContext_TransferImageBitmap)
DEPRECATED_OPERATION(URLCreateObjectURL_MediaStream)

Просмотреть файл

@ -3618,8 +3618,15 @@ DeprecationWarning(JSContext* aCx, JSObject* aObject,
return;
}
DeprecationWarning(global, aOperation);
}
void
DeprecationWarning(const GlobalObject& aGlobal,
nsIDocument::DeprecatedOperations aOperation)
{
if (NS_IsMainThread()) {
nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(global.GetAsSupports());
nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aGlobal.GetAsSupports());
if (window && window->GetExtantDoc()) {
window->GetExtantDoc()->WarnOnceAbout(aOperation);
}
@ -3627,7 +3634,7 @@ DeprecationWarning(JSContext* aCx, JSObject* aObject,
return;
}
WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx);
WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aGlobal.Context());
if (!workerPrivate) {
return;
}

Просмотреть файл

@ -3195,6 +3195,10 @@ void
DeprecationWarning(JSContext* aCx, JSObject* aObject,
nsIDocument::DeprecatedOperations aOperation);
void
DeprecationWarning(const GlobalObject& aGlobal,
nsIDocument::DeprecatedOperations aOperation);
// A callback to perform funToString on an interface object
JSString*
InterfaceObjectToString(JSContext* aCx, JS::Handle<JSObject*> aObject,

Просмотреть файл

@ -59,7 +59,7 @@ skip-if = toolkit == 'android'
[test_browserElement_inproc_AudioChannelSeeking.html]
tags = audiochannel
[test_browserElement_inproc_AudioPlayback.html]
skip-if = toolkit == 'android' # bug 1332850
skip-if = true # bug 1332850, bug 1332862
[test_browserElement_inproc_AudioChannel.html]
tags = audiochannel
[test_browserElement_inproc_AudioChannel_nested.html]

Просмотреть файл

@ -0,0 +1,201 @@
/* 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/. */
#ifndef BasicRenderingContext2D_h
#define BasicRenderingContext2D_h
#include "mozilla/dom/CanvasRenderingContext2DBinding.h"
namespace mozilla {
namespace dom {
class HTMLImageElementOrHTMLCanvasElementOrHTMLVideoElementOrImageBitmap;
typedef HTMLImageElementOrHTMLCanvasElementOrHTMLVideoElementOrImageBitmap
CanvasImageSource;
/*
* BasicRenderingContext2D
*/
class BasicRenderingContext2D
{
public:
//
// CanvasState
//
virtual void Save() = 0;
virtual void Restore() = 0;
//
// CanvasTransform
//
virtual void Scale(double aX, double aY, mozilla::ErrorResult& aError) = 0;
virtual void Rotate(double aAngle, mozilla::ErrorResult& aError) = 0;
virtual void Translate(double aX,
double aY,
mozilla::ErrorResult& aError) = 0;
virtual void Transform(double aM11,
double aM12,
double aM21,
double aM22,
double aDx,
double aDy,
mozilla::ErrorResult& aError) = 0;
virtual void SetTransform(double aM11,
double aM12,
double aM21,
double aM22,
double aDx,
double aDy,
mozilla::ErrorResult& aError) = 0;
virtual void ResetTransform(mozilla::ErrorResult& aError) = 0;
//
// CanvasCompositing
//
virtual double GlobalAlpha() = 0;
virtual void SetGlobalAlpha(double aGlobalAlpha) = 0;
virtual void GetGlobalCompositeOperation(nsAString& aOp,
mozilla::ErrorResult& aError) = 0;
virtual void SetGlobalCompositeOperation(const nsAString& aOp,
mozilla::ErrorResult& aError) = 0;
//
// CanvasImageSmoothing
//
virtual bool ImageSmoothingEnabled() = 0;
virtual void SetImageSmoothingEnabled(bool aImageSmoothingEnabled) = 0;
//
// CanvasFillStrokeStyles
//
virtual void GetStrokeStyle(
OwningStringOrCanvasGradientOrCanvasPattern& aValue) = 0;
virtual void SetStrokeStyle(
const StringOrCanvasGradientOrCanvasPattern& aValue) = 0;
virtual void GetFillStyle(
OwningStringOrCanvasGradientOrCanvasPattern& aValue) = 0;
virtual void SetFillStyle(
const StringOrCanvasGradientOrCanvasPattern& aValue) = 0;
virtual already_AddRefed<CanvasGradient> CreateLinearGradient(double aX0,
double aY0,
double aX1,
double aY1) = 0;
virtual already_AddRefed<CanvasGradient> CreateRadialGradient(
double aX0,
double aY0,
double aR0,
double aX1,
double aY1,
double aR1,
ErrorResult& aError) = 0;
virtual already_AddRefed<CanvasPattern> CreatePattern(
const CanvasImageSource& aElement,
const nsAString& aRepeat,
ErrorResult& aError) = 0;
//
// CanvasShadowStyles
//
virtual double ShadowOffsetX() = 0;
virtual void SetShadowOffsetX(double aShadowOffsetX) = 0;
virtual double ShadowOffsetY() = 0;
virtual void SetShadowOffsetY(double aShadowOffsetY) = 0;
virtual double ShadowBlur() = 0;
virtual void SetShadowBlur(double aShadowBlur) = 0;
virtual void GetShadowColor(nsAString& aShadowColor) = 0;
virtual void SetShadowColor(const nsAString& aShadowColor) = 0;
//
// CanvasRect
//
virtual void ClearRect(double aX, double aY, double aW, double aH) = 0;
virtual void FillRect(double aX, double aY, double aW, double aH) = 0;
virtual void StrokeRect(double aX, double aY, double aW, double aH) = 0;
//
// CanvasDrawImage
//
virtual void DrawImage(const CanvasImageSource& aImage,
double aDx,
double aDy,
mozilla::ErrorResult& aError) = 0;
virtual void DrawImage(const CanvasImageSource& aImage,
double aDx,
double aDy,
double aDw,
double aDh,
mozilla::ErrorResult& aError) = 0;
virtual void DrawImage(const CanvasImageSource& aImage,
double aSx,
double aSy,
double aSw,
double aSh,
double aDx,
double aDy,
double aDw,
double aDh,
mozilla::ErrorResult& aError) = 0;
//
// CanvasPathDrawingStyles
//
virtual double LineWidth() = 0;
virtual void SetLineWidth(double aWidth) = 0;
virtual void GetLineCap(nsAString& aLinecapStyle) = 0;
virtual void SetLineCap(const nsAString& aLinecapStyle) = 0;
virtual void GetLineJoin(nsAString& aLinejoinStyle,
mozilla::ErrorResult& aError) = 0;
virtual void SetLineJoin(const nsAString& aLinejoinStyle) = 0;
virtual double MiterLimit() = 0;
virtual void SetMiterLimit(double aMiter) = 0;
virtual void SetLineDash(const Sequence<double>& aSegments,
mozilla::ErrorResult& aRv) = 0;
virtual void GetLineDash(nsTArray<double>& aSegments) const = 0;
virtual void SetLineDashOffset(double aOffset) = 0;
virtual double LineDashOffset() const = 0;
//
// CanvasPath
//
virtual void ClosePath() = 0;
virtual void MoveTo(double aX, double aY) = 0;
virtual void LineTo(double aX, double aY) = 0;
virtual void QuadraticCurveTo(double aCpx,
double aCpy,
double aX,
double aY) = 0;
virtual void BezierCurveTo(double aCp1x,
double aCp1y,
double aCp2x,
double aCp2y,
double aX,
double aY) = 0;
virtual void ArcTo(double aX1,
double aY1,
double aX2,
double aY2,
double aRadius,
mozilla::ErrorResult& aError) = 0;
virtual void Rect(double aX, double aY, double aW, double aH) = 0;
virtual void Arc(double aX,
double aY,
double aRadius,
double aStartAngle,
double aEndAngle,
bool aAnticlockwise,
mozilla::ErrorResult& aError) = 0;
virtual void Ellipse(double aX,
double aY,
double aRadiusX,
double aRadiusY,
double aRotation,
double aStartAngle,
double aEndAngle,
bool aAnticlockwise,
ErrorResult& aError) = 0;
};
} // namespace dom
} // namespace mozilla
#endif /* BasicRenderingContext2D_h */

Просмотреть файл

@ -15,6 +15,7 @@
#include "mozilla/dom/HTMLVideoElement.h"
#include "gfxTextRun.h"
#include "mozilla/ErrorResult.h"
#include "mozilla/dom/BasicRenderingContext2D.h"
#include "mozilla/dom/CanvasGradient.h"
#include "mozilla/dom/CanvasRenderingContext2DBinding.h"
#include "mozilla/dom/CanvasPattern.h"
@ -61,7 +62,8 @@ class CanvasShutdownObserver;
**/
class CanvasRenderingContext2D final :
public nsICanvasRenderingContextInternal,
public nsWrapperCache
public nsWrapperCache,
public BasicRenderingContext2D
{
virtual ~CanvasRenderingContext2D();
@ -80,18 +82,18 @@ public:
return mCanvasElement->GetOriginalCanvas();
}
void Save();
void Restore();
void Scale(double aX, double aY, mozilla::ErrorResult& aError);
void Rotate(double aAngle, mozilla::ErrorResult& aError);
void Translate(double aX, double aY, mozilla::ErrorResult& aError);
void Transform(double aM11, double aM12, double aM21, double aM22, double aDx,
double aDy, mozilla::ErrorResult& aError);
void SetTransform(double aM11, double aM12, double aM21, double aM22, double aDx,
double aDy, mozilla::ErrorResult& aError);
void ResetTransform(mozilla::ErrorResult& aError);
void Save() override;
void Restore() override;
void Scale(double aX, double aY, mozilla::ErrorResult& aError) override;
void Rotate(double aAngle, mozilla::ErrorResult& aError) override;
void Translate(double aX, double aY, mozilla::ErrorResult& aError) override;
void Transform(double aM11, double aM12, double aM21, double aM22,
double aDx, double aDy, mozilla::ErrorResult& aError) override;
void SetTransform(double aM11, double aM12, double aM21, double aM22,
double aDx, double aDy, mozilla::ErrorResult& aError) override;
void ResetTransform(mozilla::ErrorResult& aError) override;
double GlobalAlpha()
double GlobalAlpha() override
{
return CurrentState().globalAlpha;
}
@ -99,79 +101,85 @@ public:
// Useful for silencing cast warnings
static mozilla::gfx::Float ToFloat(double aValue) { return mozilla::gfx::Float(aValue); }
void SetGlobalAlpha(double aGlobalAlpha)
void SetGlobalAlpha(double aGlobalAlpha) override
{
if (aGlobalAlpha >= 0.0 && aGlobalAlpha <= 1.0) {
CurrentState().globalAlpha = ToFloat(aGlobalAlpha);
}
}
void GetGlobalCompositeOperation(nsAString& aOp, mozilla::ErrorResult& aError);
void GetGlobalCompositeOperation(nsAString& aOp,
mozilla::ErrorResult& aError) override;
void SetGlobalCompositeOperation(const nsAString& aOp,
mozilla::ErrorResult& aError);
mozilla::ErrorResult& aError) override;
void GetStrokeStyle(OwningStringOrCanvasGradientOrCanvasPattern& aValue)
void
GetStrokeStyle(OwningStringOrCanvasGradientOrCanvasPattern& aValue) override
{
GetStyleAsUnion(aValue, Style::STROKE);
}
void SetStrokeStyle(const StringOrCanvasGradientOrCanvasPattern& aValue)
void
SetStrokeStyle(const StringOrCanvasGradientOrCanvasPattern& aValue) override
{
SetStyleFromUnion(aValue, Style::STROKE);
}
void GetFillStyle(OwningStringOrCanvasGradientOrCanvasPattern& aValue)
void
GetFillStyle(OwningStringOrCanvasGradientOrCanvasPattern& aValue) override
{
GetStyleAsUnion(aValue, Style::FILL);
}
void SetFillStyle(const StringOrCanvasGradientOrCanvasPattern& aValue)
void
SetFillStyle(const StringOrCanvasGradientOrCanvasPattern& aValue) override
{
SetStyleFromUnion(aValue, Style::FILL);
}
already_AddRefed<CanvasGradient>
CreateLinearGradient(double aX0, double aY0, double aX1, double aY1);
CreateLinearGradient(double aX0, double aY0, double aX1, double aY1) override;
already_AddRefed<CanvasGradient>
CreateRadialGradient(double aX0, double aY0, double aR0, double aX1, double aY1,
double aR1, ErrorResult& aError);
CreateRadialGradient(double aX0, double aY0, double aR0,
double aX1, double aY1, double aR1,
ErrorResult& aError) override;
already_AddRefed<CanvasPattern>
CreatePattern(const CanvasImageSource& aElement,
const nsAString& aRepeat, ErrorResult& aError);
const nsAString& aRepeat, ErrorResult& aError) override;
double ShadowOffsetX()
double ShadowOffsetX() override
{
return CurrentState().shadowOffset.x;
}
void SetShadowOffsetX(double aShadowOffsetX)
void SetShadowOffsetX(double aShadowOffsetX) override
{
CurrentState().shadowOffset.x = ToFloat(aShadowOffsetX);
}
double ShadowOffsetY()
double ShadowOffsetY() override
{
return CurrentState().shadowOffset.y;
}
void SetShadowOffsetY(double aShadowOffsetY)
void SetShadowOffsetY(double aShadowOffsetY) override
{
CurrentState().shadowOffset.y = ToFloat(aShadowOffsetY);
}
double ShadowBlur()
double ShadowBlur() override
{
return CurrentState().shadowBlur;
}
void SetShadowBlur(double aShadowBlur)
void SetShadowBlur(double aShadowBlur) override
{
if (aShadowBlur >= 0.0) {
CurrentState().shadowBlur = ToFloat(aShadowBlur);
}
}
void GetShadowColor(nsAString& aShadowColor)
void GetShadowColor(nsAString& aShadowColor) override
{
StyleColorToString(CurrentState().shadowColor, aShadowColor);
}
@ -181,11 +189,11 @@ public:
aFilter = CurrentState().filterString;
}
void SetShadowColor(const nsAString& aShadowColor);
void SetShadowColor(const nsAString& aShadowColor) override;
void SetFilter(const nsAString& aFilter, mozilla::ErrorResult& aError);
void ClearRect(double aX, double aY, double aW, double aH);
void FillRect(double aX, double aY, double aW, double aH);
void StrokeRect(double aX, double aY, double aW, double aH);
void ClearRect(double aX, double aY, double aW, double aH) override;
void FillRect(double aX, double aY, double aW, double aH) override;
void StrokeRect(double aX, double aY, double aW, double aH) override;
void BeginPath();
void Fill(const CanvasWindingRule& aWinding);
void Fill(const CanvasPath& aPath, const CanvasWindingRule& aWinding);
@ -212,22 +220,22 @@ public:
void RemoveHitRegion(const nsAString& aId);
void ClearHitRegions();
void DrawImage(const CanvasImageSource& aImage,
double aDx, double aDy, mozilla::ErrorResult& aError)
void DrawImage(const CanvasImageSource& aImage, double aDx, double aDy,
mozilla::ErrorResult& aError) override
{
DrawImage(aImage, 0.0, 0.0, 0.0, 0.0, aDx, aDy, 0.0, 0.0, 0, aError);
}
void DrawImage(const CanvasImageSource& aImage,
double aDx, double aDy, double aDw, double aDh,
mozilla::ErrorResult& aError)
void DrawImage(const CanvasImageSource& aImage, double aDx, double aDy,
double aDw, double aDh, mozilla::ErrorResult& aError) override
{
DrawImage(aImage, 0.0, 0.0, 0.0, 0.0, aDx, aDy, aDw, aDh, 2, aError);
}
void DrawImage(const CanvasImageSource& aImage,
double aSx, double aSy, double aSw, double aSh, double aDx,
double aDy, double aDw, double aDh, mozilla::ErrorResult& aError)
double aSx, double aSy, double aSw, double aSh,
double aDx, double aDy, double aDw, double aDh,
mozilla::ErrorResult& aError) override
{
DrawImage(aImage, aSx, aSy, aSw, aSh, aDx, aDy, aDw, aDh, 6, aError);
}
@ -248,28 +256,29 @@ public:
double aDirtyWidth, double aDirtyHeight,
mozilla::ErrorResult& aError);
double LineWidth()
double LineWidth() override
{
return CurrentState().lineWidth;
}
void SetLineWidth(double aWidth)
void SetLineWidth(double aWidth) override
{
if (aWidth > 0.0) {
CurrentState().lineWidth = ToFloat(aWidth);
}
}
void GetLineCap(nsAString& aLinecapStyle);
void SetLineCap(const nsAString& aLinecapStyle);
void GetLineJoin(nsAString& aLinejoinStyle, mozilla::ErrorResult& aError);
void SetLineJoin(const nsAString& aLinejoinStyle);
void GetLineCap(nsAString& aLinecapStyle) override;
void SetLineCap(const nsAString& aLinecapStyle) override;
void GetLineJoin(nsAString& aLinejoinStyle,
mozilla::ErrorResult& aError) override;
void SetLineJoin(const nsAString& aLinejoinStyle) override;
double MiterLimit()
double MiterLimit() override
{
return CurrentState().miterLimit;
}
void SetMiterLimit(double aMiter)
void SetMiterLimit(double aMiter) override
{
if (aMiter > 0.0) {
CurrentState().miterLimit = ToFloat(aMiter);
@ -287,7 +296,7 @@ public:
void GetTextBaseline(nsAString& aTextBaseline);
void SetTextBaseline(const nsAString& aTextBaseline);
void ClosePath()
void ClosePath() override
{
EnsureWritablePath();
@ -298,7 +307,7 @@ public:
}
}
void MoveTo(double aX, double aY)
void MoveTo(double aX, double aY) override
{
EnsureWritablePath();
@ -310,14 +319,14 @@ public:
}
}
void LineTo(double aX, double aY)
void LineTo(double aX, double aY) override
{
EnsureWritablePath();
LineTo(mozilla::gfx::Point(ToFloat(aX), ToFloat(aY)));
}
void QuadraticCurveTo(double aCpx, double aCpy, double aX, double aY)
void QuadraticCurveTo(double aCpx, double aCpy, double aX, double aY) override
{
EnsureWritablePath();
@ -333,7 +342,8 @@ public:
}
}
void BezierCurveTo(double aCp1x, double aCp1y, double aCp2x, double aCp2y, double aX, double aY)
void BezierCurveTo(double aCp1x, double aCp1y, double aCp2x, double aCp2y,
double aX, double aY) override
{
EnsureWritablePath();
@ -342,14 +352,15 @@ public:
mozilla::gfx::Point(ToFloat(aX), ToFloat(aY)));
}
void ArcTo(double aX1, double aY1, double aX2, double aY2, double aRadius,
mozilla::ErrorResult& aError);
void Rect(double aX, double aY, double aW, double aH);
void ArcTo(double aX1, double aY1, double aX2, double aY2,
double aRadius, mozilla::ErrorResult& aError) override;
void Rect(double aX, double aY, double aW, double aH) override;
void Arc(double aX, double aY, double aRadius, double aStartAngle,
double aEndAngle, bool aAnticlockwise, mozilla::ErrorResult& aError);
double aEndAngle, bool aAnticlockwise,
mozilla::ErrorResult& aError) override;
void Ellipse(double aX, double aY, double aRadiusX, double aRadiusY,
double aRotation, double aStartAngle, double aEndAngle,
bool aAnticlockwise, ErrorResult& aError);
bool aAnticlockwise, ErrorResult& aError) override;
void GetMozCurrentTransform(JSContext* aCx,
JS::MutableHandle<JSObject*> aResult,
@ -367,11 +378,11 @@ public:
void SetFillRule(const nsAString& aFillRule);
void SetLineDash(const Sequence<double>& aSegments,
mozilla::ErrorResult& aRv);
void GetLineDash(nsTArray<double>& aSegments) const;
mozilla::ErrorResult& aRv) override;
void GetLineDash(nsTArray<double>& aSegments) const override;
void SetLineDashOffset(double aOffset);
double LineDashOffset() const;
void SetLineDashOffset(double aOffset) override;
double LineDashOffset() const override;
void GetMozTextStyle(nsAString& aMozTextStyle)
{
@ -384,12 +395,12 @@ public:
SetFont(aMozTextStyle, aError);
}
bool ImageSmoothingEnabled()
bool ImageSmoothingEnabled() override
{
return CurrentState().imageSmoothingEnabled;
}
void SetImageSmoothingEnabled(bool aImageSmoothingEnabled)
void SetImageSmoothingEnabled(bool aImageSmoothingEnabled) override
{
if (aImageSmoothingEnabled != CurrentState().imageSmoothingEnabled) {
CurrentState().imageSmoothingEnabled = aImageSmoothingEnabled;

Просмотреть файл

@ -55,6 +55,7 @@ EXPORTS.mozilla.ipc += [
]
EXPORTS.mozilla.dom += [
'BasicRenderingContext2D.h',
'CanvasGradient.h',
'CanvasPath.h',
'CanvasPattern.h',

Просмотреть файл

@ -6671,6 +6671,13 @@ class DatabaseFile final
{
friend class Database;
// mBlobImpl's ownership lifecycle:
// - Initialized on the background thread at creation time. Then
// responsibility is handed off to the connection thread.
// - Checked and used by the connection thread to generate a stream to write
// the blob to disk by an add/put operation.
// - Cleared on the connection thread once the file has successfully been
// written to disk.
RefPtr<BlobImpl> mBlobImpl;
RefPtr<FileInfo> mFileInfo;
@ -6685,16 +6692,6 @@ public:
return mFileInfo;
}
/**
* Is there a blob available to provide an input stream? This may be called
* on any thread under current lifecycle constraints.
*/
bool
HasBlobImpl() const
{
return (bool)mBlobImpl;
}
/**
* If mBlobImpl is non-null (implying the contents of this file have not yet
* been written to disk), then return an input stream that is guaranteed to
@ -6734,10 +6731,17 @@ public:
already_AddRefed<nsIInputStream>
GetBlockingInputStream(ErrorResult &rv) const;
/**
* To be called upon successful copying of the stream GetBlockingInputStream()
* returned so that we won't try and redundantly write the file to disk in the
* future. This is a separate step from GetBlockingInputStream() because
* the write could fail due to quota errors that happen now but that might
* not happen in a future attempt.
*/
void
ClearInputStream()
WriteSucceededClearBlobImpl()
{
AssertIsOnBackgroundThread();
MOZ_ASSERT(!IsOnBackgroundThread());
mBlobImpl = nullptr;
}
@ -6773,8 +6777,8 @@ private:
already_AddRefed<nsIInputStream>
DatabaseFile::GetBlockingInputStream(ErrorResult &rv) const
{
// We should only be called from a database I/O thread, not the background
// thread. The background thread should call HasBlobImpl().
// We should only be called from our DB connection thread, not the background
// thread.
MOZ_ASSERT(!IsOnBackgroundThread());
if (!mBlobImpl) {
@ -8320,8 +8324,6 @@ class ObjectStoreAddOrPutRequestOp final
FallibleTArray<StoredFileInfo> mStoredFileInfos;
RefPtr<FileManager> mFileManager;
Key mResponse;
const nsCString mGroup;
const nsCString mOrigin;
@ -8361,11 +8363,9 @@ struct ObjectStoreAddOrPutRequestOp::StoredFileInfo final
// still have a stream for us to write.
nsCOMPtr<nsIInputStream> mInputStream;
StructuredCloneFile::FileType mType;
bool mCopiedSuccessfully;
StoredFileInfo()
: mType(StructuredCloneFile::eBlob)
, mCopiedSuccessfully(false)
{
AssertIsOnBackgroundThread();
@ -26155,10 +26155,6 @@ ObjectStoreAddOrPutRequestOp::Init(TransactionBase* aTransaction)
return false;
}
RefPtr<FileManager> fileManager =
aTransaction->GetDatabase()->GetFileManager();
MOZ_ASSERT(fileManager);
for (uint32_t index = 0; index < count; index++) {
const FileAddInfo& fileAddInfo = fileAddInfos[index];
@ -26185,10 +26181,6 @@ ObjectStoreAddOrPutRequestOp::Init(TransactionBase* aTransaction)
storedFileInfo->mFileInfo = storedFileInfo->mFileActor->GetFileInfo();
MOZ_ASSERT(storedFileInfo->mFileInfo);
if (storedFileInfo->mFileActor->HasBlobImpl() && !mFileManager) {
mFileManager = fileManager;
}
storedFileInfo->mType = StructuredCloneFile::eBlob;
break;
}
@ -26222,10 +26214,6 @@ ObjectStoreAddOrPutRequestOp::Init(TransactionBase* aTransaction)
storedFileInfo->mFileInfo = storedFileInfo->mFileActor->GetFileInfo();
MOZ_ASSERT(storedFileInfo->mFileInfo);
if (storedFileInfo->mFileActor->HasBlobImpl() && !mFileManager) {
mFileManager = fileManager;
}
storedFileInfo->mType = fileAddInfo.type();
break;
}
@ -26240,12 +26228,11 @@ ObjectStoreAddOrPutRequestOp::Init(TransactionBase* aTransaction)
StoredFileInfo* storedFileInfo = mStoredFileInfos.AppendElement(fallible);
MOZ_ASSERT(storedFileInfo);
if (!mFileManager) {
mFileManager = aTransaction->GetDatabase()->GetFileManager();
MOZ_ASSERT(mFileManager);
}
RefPtr<FileManager> fileManager =
aTransaction->GetDatabase()->GetFileManager();
MOZ_ASSERT(fileManager);
storedFileInfo->mFileInfo = mFileManager->GetNewFileInfo();
storedFileInfo->mFileInfo = fileManager->GetNewFileInfo();
storedFileInfo->mInputStream =
new SCInputStream(mParams.cloneInfo().data().data);
@ -26262,7 +26249,6 @@ ObjectStoreAddOrPutRequestOp::DoDatabaseWork(DatabaseConnection* aConnection)
MOZ_ASSERT(aConnection);
aConnection->AssertIsOnConnectionThread();
MOZ_ASSERT(aConnection->GetStorageConnection());
MOZ_ASSERT_IF(mFileManager, !mStoredFileInfos.IsEmpty());
PROFILER_LABEL("IndexedDB",
"ObjectStoreAddOrPutRequestOp::DoDatabaseWork",
@ -26439,19 +26425,10 @@ ObjectStoreAddOrPutRequestOp::DoDatabaseWork(DatabaseConnection* aConnection)
}
}
Maybe<FileHelper> fileHelper;
if (mFileManager) {
fileHelper.emplace(mFileManager);
rv = fileHelper->Init();
if (NS_WARN_IF(NS_FAILED(rv))) {
IDB_REPORT_INTERNAL_ERR();
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
}
if (!mStoredFileInfos.IsEmpty()) {
// Moved outside the loop to allow it to be cached when demanded by the
// first write. (We may have mStoredFileInfos without any required writes.)
Maybe<FileHelper> fileHelper;
nsAutoString fileIds;
for (uint32_t count = mStoredFileInfos.Length(), index = 0;
@ -26465,8 +26442,7 @@ ObjectStoreAddOrPutRequestOp::DoDatabaseWork(DatabaseConnection* aConnection)
// MUST be non-null.
// - This is a reference to a Blob that may or may not have already been
// written to disk. storedFileInfo.mFileActor MUST be non-null, but
// its HasBlobImpl() may return false and so GetBlockingInputStream may
// return null (so don't assert on them).
// its GetBlockingInputStream may return null (so don't assert on them).
// - It's a mutable file. No writing will be performed.
MOZ_ASSERT(storedFileInfo.mInputStream || storedFileInfo.mFileActor ||
storedFileInfo.mType == StructuredCloneFile::eMutableFile);
@ -26485,6 +26461,19 @@ ObjectStoreAddOrPutRequestOp::DoDatabaseWork(DatabaseConnection* aConnection)
}
if (inputStream) {
if (fileHelper.isNothing()) {
RefPtr<FileManager> fileManager =
Transaction()->GetDatabase()->GetFileManager();
MOZ_ASSERT(fileManager);
fileHelper.emplace(fileManager);
rv = fileHelper->Init();
if (NS_WARN_IF(NS_FAILED(rv))) {
IDB_REPORT_INTERNAL_ERR();
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
}
RefPtr<FileInfo>& fileInfo = storedFileInfo.mFileInfo;
nsCOMPtr<nsIFile> file = fileHelper->GetFile(fileInfo);
@ -26521,7 +26510,9 @@ ObjectStoreAddOrPutRequestOp::DoDatabaseWork(DatabaseConnection* aConnection)
return rv;
}
storedFileInfo.mCopiedSuccessfully = true;
if (storedFileInfo.mFileActor) {
storedFileInfo.mFileActor->WriteSucceededClearBlobImpl();
}
}
if (index) {
@ -26605,23 +26596,7 @@ ObjectStoreAddOrPutRequestOp::Cleanup()
{
AssertIsOnOwningThread();
if (!mStoredFileInfos.IsEmpty()) {
for (uint32_t count = mStoredFileInfos.Length(), index = 0;
index < count;
index++) {
StoredFileInfo& storedFileInfo = mStoredFileInfos[index];
MOZ_ASSERT_IF(storedFileInfo.mType == StructuredCloneFile::eMutableFile,
!storedFileInfo.mCopiedSuccessfully);
RefPtr<DatabaseFile>& fileActor = storedFileInfo.mFileActor;
if (fileActor && storedFileInfo.mCopiedSuccessfully) {
fileActor->ClearInputStream();
}
}
mStoredFileInfos.Clear();
}
mStoredFileInfos.Clear();
NormalTransactionOp::Cleanup();
}

Просмотреть файл

@ -321,3 +321,5 @@ LargeAllocationNonE10S=A Large-Allocation header was ignored due to the document
GeolocationInsecureRequestIsForbidden=A Geolocation request can only be fulfilled in a secure context.
# LOCALIZATION NOTE: Do not translate "Large-Allocation", as it is a literal header name.
LargeAllocationNonWin32=This page would be loaded in a new process due to a Large-Allocation header, however Large-Allocation process creation is disabled on non-Win32 platforms.
# LOCALIZATION NOTE: Do not translate URL.createObjectURL(MediaStream).
URLCreateObjectURL_MediaStream=URL.createObjectURL(MediaStream) is deprecated and will be removed soon.

Просмотреть файл

@ -7,18 +7,6 @@
#ifndef WMF_H_
#define WMF_H_
#if WINVER < _WIN32_WINNT_WIN7
#error \
You must include WMF.h before including mozilla headers, \
otherwise mozconfig.h will be included \
and that sets WINVER to WinXP, \
which makes Windows Media Foundation unavailable.
#endif
#pragma push_macro("WINVER")
#undef WINVER
#define WINVER _WIN32_WINNT_WIN7
#include <windows.h>
#include <mfapi.h>
#include <mfidl.h>
@ -35,7 +23,7 @@ which makes Windows Media Foundation unavailable.
#include <codecapi.h>
// The Windows headers helpfully declare min and max macros, which don't
// compile in the prescence of std::min and std::max and unified builds.
// compile in the presence of std::min and std::max and unified builds.
// So undef them here.
#ifdef min
#undef min
@ -97,8 +85,4 @@ HRESULT MFCreateDXGISurfaceBuffer(REFIID riid,
} // end namespace wmf
} // end namespace mozilla
#pragma pop_macro("WINVER")
#endif

Просмотреть файл

@ -1727,6 +1727,9 @@ URL::CreateObjectURL(const GlobalObject& aGlobal, DOMMediaStream& aStream,
nsAString& aResult, ErrorResult& aRv)
{
MOZ_ASSERT(NS_IsMainThread());
DeprecationWarning(aGlobal, nsIDocument::eURLCreateObjectURL_MediaStream);
URLMainThread::CreateObjectURL(aGlobal, aStream, aResult, aRv);
}

Просмотреть файл

@ -872,17 +872,9 @@ private:
WorkerPrivate* parentWorker = mWorkerPrivate->GetParent();
// Figure out which principal to use.
nsIPrincipal* principal = mWorkerPrivate->GetPrincipal();
nsCOMPtr<nsILoadGroup> loadGroup = mWorkerPrivate->GetLoadGroup();
if (!principal) {
NS_ASSERTION(parentWorker, "Must have a principal!");
NS_ASSERTION(mIsMainScript, "Must have a principal for importScripts!");
principal = parentWorker->GetPrincipal();
loadGroup = parentWorker->GetLoadGroup();
}
NS_ASSERTION(principal, "This should never be null here!");
MOZ_DIAGNOSTIC_ASSERT(principal);
MOZ_ASSERT(NS_LoadGroupMatchesPrincipal(loadGroup, principal));
// Figure out our base URI.
@ -1137,61 +1129,7 @@ private:
// Store the channel info if needed.
mWorkerPrivate->InitChannelInfo(channel);
// Now to figure out which principal to give this worker.
WorkerPrivate* parent = mWorkerPrivate->GetParent();
NS_ASSERTION(mWorkerPrivate->GetPrincipal() || parent,
"Must have one of these!");
nsCOMPtr<nsIPrincipal> loadPrincipal = mWorkerPrivate->GetPrincipal() ?
mWorkerPrivate->GetPrincipal() :
parent->GetPrincipal();
nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
NS_ASSERTION(ssm, "Should never be null!");
nsCOMPtr<nsIPrincipal> channelPrincipal;
rv = ssm->GetChannelResultPrincipal(channel, getter_AddRefs(channelPrincipal));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsILoadGroup> channelLoadGroup;
rv = channel->GetLoadGroup(getter_AddRefs(channelLoadGroup));
NS_ENSURE_SUCCESS(rv, rv);
MOZ_ASSERT(channelLoadGroup);
// If the load principal is the system principal then the channel
// principal must also be the system principal (we do not allow chrome
// code to create workers with non-chrome scripts, and if we ever decide
// to change this we need to make sure we don't always set
// mPrincipalIsSystem to true in WorkerPrivate::GetLoadInfo()). Otherwise
// this channel principal must be same origin with the load principal (we
// check again here in case redirects changed the location of the script).
if (nsContentUtils::IsSystemPrincipal(loadPrincipal)) {
if (!nsContentUtils::IsSystemPrincipal(channelPrincipal)) {
// See if this is a resource URI. Since JSMs usually come from
// resource:// URIs we're currently considering all URIs with the
// URI_IS_UI_RESOURCE flag as valid for creating privileged workers.
bool isResource;
rv = NS_URIChainHasFlags(finalURI,
nsIProtocolHandler::URI_IS_UI_RESOURCE,
&isResource);
NS_ENSURE_SUCCESS(rv, rv);
if (isResource) {
// Assign the system principal to the resource:// worker only if it
// was loaded from code using the system principal.
channelPrincipal = loadPrincipal;
} else {
return NS_ERROR_DOM_BAD_URI;
}
}
}
// The principal can change, but it should still match the original
// load group's appId and browser element flag.
MOZ_ASSERT(NS_LoadGroupMatchesPrincipal(channelLoadGroup, channelPrincipal));
mWorkerPrivate->SetPrincipal(channelPrincipal, channelLoadGroup);
MOZ_DIAGNOSTIC_ASSERT(mWorkerPrivate->FinalChannelPrincipalIsValid(channel));
// We did inherit CSP in bug 1223647. If we do not already have a CSP, we
// should get it from the HTTP headers on the worker script.
@ -1239,6 +1177,7 @@ private:
}
}
}
WorkerPrivate* parent = mWorkerPrivate->GetParent();
if (parent) {
// XHR Params Allowed
mWorkerPrivate->SetXHRParamsAllowed(parent->XHRParamsAllowed());
@ -1308,7 +1247,7 @@ private:
MOZ_ASSERT(equal);
mWorkerPrivate->InitChannelInfo(aChannelInfo);
mWorkerPrivate->SetPrincipal(responsePrincipal, loadGroup);
mWorkerPrivate->SetPrincipalOnMainThread(responsePrincipal, loadGroup);
}
if (NS_SUCCEEDED(rv)) {
@ -1795,17 +1734,17 @@ CacheScriptLoader::OnStreamComplete(nsIStreamLoader* aLoader, nsISupports* aCont
class ChannelGetterRunnable final : public WorkerMainThreadRunnable
{
const nsAString& mScriptURL;
nsIChannel** mChannel;
WorkerLoadInfo& mLoadInfo;
nsresult mResult;
public:
ChannelGetterRunnable(WorkerPrivate* aParentWorker,
const nsAString& aScriptURL,
nsIChannel** aChannel)
WorkerLoadInfo& aLoadInfo)
: WorkerMainThreadRunnable(aParentWorker,
NS_LITERAL_CSTRING("ScriptLoader :: ChannelGetter"))
, mScriptURL(aScriptURL)
, mChannel(aChannel)
, mLoadInfo(aLoadInfo)
, mResult(NS_ERROR_FAILURE)
{
MOZ_ASSERT(aParentWorker);
@ -1817,8 +1756,12 @@ public:
{
AssertIsOnMainThread();
nsIPrincipal* principal = mWorkerPrivate->GetPrincipal();
MOZ_ASSERT(principal);
// Initialize the WorkerLoadInfo principal to our triggering principal
// before doing anything else. Normally we do this in the WorkerPrivate
// Constructor, but we can't do so off the main thread when creating
// a nested worker. So do it here instead.
mLoadInfo.mPrincipal = mWorkerPrivate->GetPrincipal();
MOZ_ASSERT(mLoadInfo.mPrincipal);
// Figure out our base URI.
nsCOMPtr<nsIURI> baseURI = mWorkerPrivate->GetBaseURI();
@ -1827,22 +1770,25 @@ public:
// May be null.
nsCOMPtr<nsIDocument> parentDoc = mWorkerPrivate->GetDocument();
nsCOMPtr<nsILoadGroup> loadGroup = mWorkerPrivate->GetLoadGroup();
mLoadInfo.mLoadGroup = mWorkerPrivate->GetLoadGroup();
nsCOMPtr<nsIChannel> channel;
mResult =
scriptloader::ChannelFromScriptURLMainThread(principal, baseURI,
parentDoc, loadGroup,
scriptloader::ChannelFromScriptURLMainThread(mLoadInfo.mPrincipal,
baseURI, parentDoc,
mLoadInfo.mLoadGroup,
mScriptURL,
// Nested workers are always dedicated.
nsIContentPolicy::TYPE_INTERNAL_WORKER,
// Nested workers use default uri encoding.
true,
getter_AddRefs(channel));
if (NS_SUCCEEDED(mResult)) {
channel.forget(mChannel);
}
NS_ENSURE_SUCCESS(mResult, true);
mResult = mLoadInfo.SetPrincipalFromChannel(channel);
NS_ENSURE_SUCCESS(mResult, true);
mLoadInfo.mChannel = channel.forget();
return true;
}
@ -2178,12 +2124,12 @@ nsresult
ChannelFromScriptURLWorkerThread(JSContext* aCx,
WorkerPrivate* aParent,
const nsAString& aScriptURL,
nsIChannel** aChannel)
WorkerLoadInfo& aLoadInfo)
{
aParent->AssertIsOnWorkerThread();
RefPtr<ChannelGetterRunnable> getter =
new ChannelGetterRunnable(aParent, aScriptURL, aChannel);
new ChannelGetterRunnable(aParent, aScriptURL, aLoadInfo);
ErrorResult rv;
getter->Dispatch(Terminating, rv);

Просмотреть файл

@ -46,7 +46,7 @@ nsresult
ChannelFromScriptURLWorkerThread(JSContext* aCx,
WorkerPrivate* aParent,
const nsAString& aScriptURL,
nsIChannel** aChannel);
WorkerLoadInfo& aLoadInfo);
void ReportLoadError(ErrorResult& aRv, nsresult aLoadResult,
const nsAString& aScriptURL);

Просмотреть файл

@ -395,15 +395,7 @@ private:
virtual bool
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
{
nsCOMPtr<nsILoadGroup> loadGroupToCancel;
mFinishedWorker->ForgetOverridenLoadGroup(loadGroupToCancel);
nsTArray<nsCOMPtr<nsISupports>> doomed;
mFinishedWorker->ForgetMainThreadObjects(doomed);
RefPtr<MainThreadReleaseRunnable> runnable =
new MainThreadReleaseRunnable(doomed, loadGroupToCancel);
if (NS_FAILED(mWorkerPrivate->DispatchToMainThread(runnable.forget()))) {
if (!mFinishedWorker->ProxyReleaseMainThreadObjects()) {
NS_WARNING("Failed to dispatch, going to leak!");
}
@ -447,15 +439,7 @@ private:
runtime->UnregisterWorker(mFinishedWorker);
nsCOMPtr<nsILoadGroup> loadGroupToCancel;
mFinishedWorker->ForgetOverridenLoadGroup(loadGroupToCancel);
nsTArray<nsCOMPtr<nsISupports> > doomed;
mFinishedWorker->ForgetMainThreadObjects(doomed);
RefPtr<MainThreadReleaseRunnable> runnable =
new MainThreadReleaseRunnable(doomed, loadGroupToCancel);
if (NS_FAILED(NS_DispatchToCurrentThread(runnable))) {
if (!mFinishedWorker->ProxyReleaseMainThreadObjects()) {
NS_WARNING("Failed to dispatch, going to leak!");
}
@ -1851,6 +1835,193 @@ WorkerLoadInfo::StealFrom(WorkerLoadInfo& aOther)
mOriginAttributes = aOther.mOriginAttributes;
}
void
WorkerLoadInfo::SetPrincipalOnMainThread(nsIPrincipal* aPrincipal,
nsILoadGroup* aLoadGroup)
{
AssertIsOnMainThread();
MOZ_ASSERT(NS_LoadGroupMatchesPrincipal(aLoadGroup, aPrincipal));
MOZ_ASSERT(!mPrincipalInfo);
mPrincipal = aPrincipal;
mPrincipalIsSystem = nsContentUtils::IsSystemPrincipal(aPrincipal);
aPrincipal->GetCsp(getter_AddRefs(mCSP));
if (mCSP) {
mCSP->GetAllowsEval(&mReportCSPViolations, &mEvalAllowed);
// Set ReferrerPolicy
bool hasReferrerPolicy = false;
uint32_t rp = mozilla::net::RP_Unset;
nsresult rv = mCSP->GetReferrerPolicy(&rp, &hasReferrerPolicy);
NS_ENSURE_SUCCESS_VOID(rv);
if (hasReferrerPolicy) {
mReferrerPolicy = static_cast<net::ReferrerPolicy>(rp);
}
} else {
mEvalAllowed = true;
mReportCSPViolations = false;
}
mLoadGroup = aLoadGroup;
mPrincipalInfo = new PrincipalInfo();
mOriginAttributes = nsContentUtils::GetOriginAttributes(aLoadGroup);
MOZ_ALWAYS_SUCCEEDS(
PrincipalToPrincipalInfo(aPrincipal, mPrincipalInfo));
}
nsresult
WorkerLoadInfo::GetPrincipalAndLoadGroupFromChannel(nsIChannel* aChannel,
nsIPrincipal** aPrincipalOut,
nsILoadGroup** aLoadGroupOut)
{
AssertIsOnMainThread();
MOZ_DIAGNOSTIC_ASSERT(aChannel);
MOZ_DIAGNOSTIC_ASSERT(aPrincipalOut);
MOZ_DIAGNOSTIC_ASSERT(aLoadGroupOut);
// Initial triggering principal should be set
MOZ_DIAGNOSTIC_ASSERT(mPrincipal);
nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
MOZ_DIAGNOSTIC_ASSERT(ssm);
nsCOMPtr<nsIPrincipal> channelPrincipal;
nsresult rv = ssm->GetChannelResultPrincipal(aChannel, getter_AddRefs(channelPrincipal));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsILoadGroup> channelLoadGroup;
rv = aChannel->GetLoadGroup(getter_AddRefs(channelLoadGroup));
NS_ENSURE_SUCCESS(rv, rv);
MOZ_ASSERT(channelLoadGroup);
// If the load principal is the system principal then the channel
// principal must also be the system principal (we do not allow chrome
// code to create workers with non-chrome scripts, and if we ever decide
// to change this we need to make sure we don't always set
// mPrincipalIsSystem to true in WorkerPrivate::GetLoadInfo()). Otherwise
// this channel principal must be same origin with the load principal (we
// check again here in case redirects changed the location of the script).
if (nsContentUtils::IsSystemPrincipal(mPrincipal)) {
if (!nsContentUtils::IsSystemPrincipal(channelPrincipal)) {
nsCOMPtr<nsIURI> finalURI;
rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(finalURI));
NS_ENSURE_SUCCESS(rv, rv);
// See if this is a resource URI. Since JSMs usually come from
// resource:// URIs we're currently considering all URIs with the
// URI_IS_UI_RESOURCE flag as valid for creating privileged workers.
bool isResource;
rv = NS_URIChainHasFlags(finalURI,
nsIProtocolHandler::URI_IS_UI_RESOURCE,
&isResource);
NS_ENSURE_SUCCESS(rv, rv);
if (isResource) {
// Assign the system principal to the resource:// worker only if it
// was loaded from code using the system principal.
channelPrincipal = mPrincipal;
} else {
return NS_ERROR_DOM_BAD_URI;
}
}
}
// The principal can change, but it should still match the original
// load group's appId and browser element flag.
MOZ_ASSERT(NS_LoadGroupMatchesPrincipal(channelLoadGroup, channelPrincipal));
channelPrincipal.forget(aPrincipalOut);
channelLoadGroup.forget(aLoadGroupOut);
return NS_OK;
}
nsresult
WorkerLoadInfo::SetPrincipalFromChannel(nsIChannel* aChannel)
{
AssertIsOnMainThread();
nsCOMPtr<nsIPrincipal> principal;
nsCOMPtr<nsILoadGroup> loadGroup;
nsresult rv = GetPrincipalAndLoadGroupFromChannel(aChannel,
getter_AddRefs(principal),
getter_AddRefs(loadGroup));
NS_ENSURE_SUCCESS(rv, rv);
SetPrincipalOnMainThread(principal, loadGroup);
return NS_OK;
}
#if defined(DEBUG) || !defined(RELEASE_OR_BETA)
bool
WorkerLoadInfo::FinalChannelPrincipalIsValid(nsIChannel* aChannel)
{
AssertIsOnMainThread();
nsCOMPtr<nsIPrincipal> principal;
nsCOMPtr<nsILoadGroup> loadGroup;
nsresult rv = GetPrincipalAndLoadGroupFromChannel(aChannel,
getter_AddRefs(principal),
getter_AddRefs(loadGroup));
NS_ENSURE_SUCCESS(rv, false);
// Verify that the channel is still a null principal. We don't care
// if these are the exact same null principal object, though. From
// the worker's perspective its the same effect.
if (principal->GetIsNullPrincipal() && mPrincipal->GetIsNullPrincipal()) {
return true;
}
// Otherwise we require exact equality. Redirects can happen, but they
// are not allowed to change our principal.
if (principal->Equals(mPrincipal)) {
return true;
}
return false;
}
#endif // defined(DEBUG) || !defined(RELEASE_OR_BETA)
bool
WorkerLoadInfo::ProxyReleaseMainThreadObjects(WorkerPrivate* aWorkerPrivate)
{
nsCOMPtr<nsILoadGroup> nullLoadGroup;
return ProxyReleaseMainThreadObjects(aWorkerPrivate, nullLoadGroup);
}
bool
WorkerLoadInfo::ProxyReleaseMainThreadObjects(WorkerPrivate* aWorkerPrivate,
nsCOMPtr<nsILoadGroup>& aLoadGroupToCancel)
{
static const uint32_t kDoomedCount = 10;
nsTArray<nsCOMPtr<nsISupports>> doomed(kDoomedCount);
SwapToISupportsArray(mWindow, doomed);
SwapToISupportsArray(mScriptContext, doomed);
SwapToISupportsArray(mBaseURI, doomed);
SwapToISupportsArray(mResolvedScriptURI, doomed);
SwapToISupportsArray(mPrincipal, doomed);
SwapToISupportsArray(mChannel, doomed);
SwapToISupportsArray(mCSP, doomed);
SwapToISupportsArray(mLoadGroup, doomed);
SwapToISupportsArray(mLoadFailedAsyncRunnable, doomed);
SwapToISupportsArray(mInterfaceRequestor, doomed);
// Before adding anything here update kDoomedCount above!
MOZ_ASSERT(doomed.Length() == kDoomedCount);
RefPtr<MainThreadReleaseRunnable> runnable =
new MainThreadReleaseRunnable(doomed, aLoadGroupToCancel);
return NS_SUCCEEDED(aWorkerPrivate->DispatchToMainThread(runnable.forget()));
}
template <class Derived>
class WorkerPrivateParent<Derived>::EventTarget final
: public nsIEventTarget
@ -3031,48 +3202,25 @@ WorkerPrivateParent<Derived>::ModifyBusyCount(bool aIncrease)
}
template <class Derived>
void
WorkerPrivateParent<Derived>::ForgetOverridenLoadGroup(
nsCOMPtr<nsILoadGroup>& aLoadGroupOut)
{
AssertIsOnParentThread();
// If we're not overriden, then do nothing here. Let the load group get
// handled in ForgetMainThreadObjects().
if (!mLoadInfo.mInterfaceRequestor) {
return;
}
mLoadInfo.mLoadGroup.swap(aLoadGroupOut);
}
template <class Derived>
void
WorkerPrivateParent<Derived>::ForgetMainThreadObjects(
nsTArray<nsCOMPtr<nsISupports> >& aDoomed)
bool
WorkerPrivateParent<Derived>::ProxyReleaseMainThreadObjects()
{
AssertIsOnParentThread();
MOZ_ASSERT(!mMainThreadObjectsForgotten);
static const uint32_t kDoomedCount = 10;
nsCOMPtr<nsILoadGroup> loadGroupToCancel;
// If we're not overriden, then do nothing here. Let the load group get
// handled in ForgetMainThreadObjects().
if (mLoadInfo.mInterfaceRequestor) {
mLoadInfo.mLoadGroup.swap(loadGroupToCancel);
}
aDoomed.SetCapacity(kDoomedCount);
SwapToISupportsArray(mLoadInfo.mWindow, aDoomed);
SwapToISupportsArray(mLoadInfo.mScriptContext, aDoomed);
SwapToISupportsArray(mLoadInfo.mBaseURI, aDoomed);
SwapToISupportsArray(mLoadInfo.mResolvedScriptURI, aDoomed);
SwapToISupportsArray(mLoadInfo.mPrincipal, aDoomed);
SwapToISupportsArray(mLoadInfo.mChannel, aDoomed);
SwapToISupportsArray(mLoadInfo.mCSP, aDoomed);
SwapToISupportsArray(mLoadInfo.mLoadGroup, aDoomed);
SwapToISupportsArray(mLoadInfo.mLoadFailedAsyncRunnable, aDoomed);
SwapToISupportsArray(mLoadInfo.mInterfaceRequestor, aDoomed);
// Before adding anything here update kDoomedCount above!
MOZ_ASSERT(aDoomed.Length() == kDoomedCount);
bool result = mLoadInfo.ProxyReleaseMainThreadObjects(ParentAsWorkerPrivate(),
loadGroupToCancel);
mMainThreadObjectsForgotten = true;
return result;
}
template <class Derived>
@ -3656,45 +3804,28 @@ WorkerPrivateParent<Derived>::SetBaseURI(nsIURI* aBaseURI)
template <class Derived>
void
WorkerPrivateParent<Derived>::SetPrincipal(nsIPrincipal* aPrincipal,
nsILoadGroup* aLoadGroup)
WorkerPrivateParent<Derived>::SetPrincipalOnMainThread(nsIPrincipal* aPrincipal,
nsILoadGroup* aLoadGroup)
{
AssertIsOnMainThread();
MOZ_ASSERT(NS_LoadGroupMatchesPrincipal(aLoadGroup, aPrincipal));
MOZ_ASSERT(!mLoadInfo.mPrincipalInfo);
mLoadInfo.mPrincipal = aPrincipal;
mLoadInfo.mPrincipalIsSystem = nsContentUtils::IsSystemPrincipal(aPrincipal);
aPrincipal->GetCsp(getter_AddRefs(mLoadInfo.mCSP));
if (mLoadInfo.mCSP) {
mLoadInfo.mCSP->GetAllowsEval(&mLoadInfo.mReportCSPViolations,
&mLoadInfo.mEvalAllowed);
// Set ReferrerPolicy
bool hasReferrerPolicy = false;
uint32_t rp = mozilla::net::RP_Unset;
nsresult rv = mLoadInfo.mCSP->GetReferrerPolicy(&rp, &hasReferrerPolicy);
NS_ENSURE_SUCCESS_VOID(rv);
if (hasReferrerPolicy) {
mLoadInfo.mReferrerPolicy = static_cast<net::ReferrerPolicy>(rp);
}
} else {
mLoadInfo.mEvalAllowed = true;
mLoadInfo.mReportCSPViolations = false;
}
mLoadInfo.mLoadGroup = aLoadGroup;
mLoadInfo.mPrincipalInfo = new PrincipalInfo();
mLoadInfo.mOriginAttributes = nsContentUtils::GetOriginAttributes(aLoadGroup);
MOZ_ALWAYS_SUCCEEDS(
PrincipalToPrincipalInfo(aPrincipal, mLoadInfo.mPrincipalInfo));
mLoadInfo.SetPrincipalOnMainThread(aPrincipal, aLoadGroup);
}
template <class Derived>
nsresult
WorkerPrivateParent<Derived>::SetPrincipalFromChannel(nsIChannel* aChannel)
{
return mLoadInfo.SetPrincipalFromChannel(aChannel);
}
#if defined(DEBUG) || !defined(RELEASE_OR_BETA)
template <class Derived>
bool
WorkerPrivateParent<Derived>::FinalChannelPrincipalIsValid(nsIChannel* aChannel)
{
return mLoadInfo.FinalChannelPrincipalIsValid(aChannel);
}
#endif
template <class Derived>
void
WorkerPrivateParent<Derived>::UpdateOverridenLoadGroup(nsILoadGroup* aBaseLoadGroup)
@ -4447,12 +4578,14 @@ WorkerPrivate::GetLoadInfo(JSContext* aCx, nsPIDOMWindowInner* aWindow,
return NS_ERROR_FAILURE;
}
// StartAssignment() is used instead getter_AddRefs because, getter_AddRefs
// does QI in debug build and, if this worker runs in a child process,
// HttpChannelChild will crash because it's not thread-safe.
// Passing a pointer to our stack loadInfo is safe here because this
// method uses a sync runnable to get the channel from the main thread.
rv = ChannelFromScriptURLWorkerThread(aCx, aParent, aScriptURL,
loadInfo.mChannel.StartAssignment());
NS_ENSURE_SUCCESS(rv, rv);
loadInfo);
if (NS_FAILED(rv)) {
MOZ_ALWAYS_TRUE(loadInfo.ProxyReleaseMainThreadObjects(aParent));
return rv;
}
// Now that we've spun the loop there's no guarantee that our parent is
// still alive. We may have received control messages initiating shutdown.
@ -4462,7 +4595,7 @@ WorkerPrivate::GetLoadInfo(JSContext* aCx, nsPIDOMWindowInner* aWindow,
}
if (parentStatus > Running) {
NS_ReleaseOnMainThread(loadInfo.mChannel.forget());
MOZ_ALWAYS_TRUE(loadInfo.ProxyReleaseMainThreadObjects(aParent));
return NS_ERROR_FAILURE;
}
@ -4662,6 +4795,9 @@ WorkerPrivate::GetLoadInfo(JSContext* aCx, nsPIDOMWindowInner* aWindow,
rv = NS_GetFinalChannelURI(loadInfo.mChannel,
getter_AddRefs(loadInfo.mResolvedScriptURI));
NS_ENSURE_SUCCESS(rv, rv);
rv = loadInfo.SetPrincipalFromChannel(loadInfo.mChannel);
NS_ENSURE_SUCCESS(rv, rv);
}
aLoadInfo->StealFrom(loadInfo);

Просмотреть файл

@ -353,11 +353,8 @@ public:
bool
ModifyBusyCount(bool aIncrease);
void
ForgetOverridenLoadGroup(nsCOMPtr<nsILoadGroup>& aLoadGroupOut);
void
ForgetMainThreadObjects(nsTArray<nsCOMPtr<nsISupports> >& aDoomed);
bool
ProxyReleaseMainThreadObjects();
void
PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
@ -611,7 +608,15 @@ public:
}
void
SetPrincipal(nsIPrincipal* aPrincipal, nsILoadGroup* aLoadGroup);
SetPrincipalOnMainThread(nsIPrincipal* aPrincipal, nsILoadGroup* aLoadGroup);
nsresult
SetPrincipalFromChannel(nsIChannel* aChannel);
#if defined(DEBUG) || !defined(RELEASE_OR_BETA)
bool
FinalChannelPrincipalIsValid(nsIChannel* aChannel);
#endif
bool
UsesSystemPrincipal() const

Просмотреть файл

@ -277,6 +277,29 @@ struct WorkerLoadInfo
~WorkerLoadInfo();
void StealFrom(WorkerLoadInfo& aOther);
void
SetPrincipalOnMainThread(nsIPrincipal* aPrincipal, nsILoadGroup* aLoadGroup);
nsresult
GetPrincipalAndLoadGroupFromChannel(nsIChannel* aChannel,
nsIPrincipal** aPrincipalOut,
nsILoadGroup** aLoadGroupOut);
nsresult
SetPrincipalFromChannel(nsIChannel* aChannel);
#if defined(DEBUG) || !defined(RELEASE_OR_BETA)
bool
FinalChannelPrincipalIsValid(nsIChannel* aChannel);
#endif
bool
ProxyReleaseMainThreadObjects(WorkerPrivate* aWorkerPrivate);
bool
ProxyReleaseMainThreadObjects(WorkerPrivate* aWorkerPrivate,
nsCOMPtr<nsILoadGroup>& aLoadGroupToCancel);
};
// All of these are implemented in RuntimeService.cpp

Просмотреть файл

@ -1,7 +1 @@
/**
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
onmessage = function(event) {
throw "Shouldn't be able to read this!";
}
// doesn't matter what is in here if the URL is bad

Просмотреть файл

@ -21,23 +21,13 @@ onmessage = function(event) {
}
// We shouldn't be able to make a ChromeWorker to a non-chrome URL.
let worker = new ChromeWorker(mochitestURL);
worker.onmessage = function(event) {
throw event.data;
};
worker.onerror = function(event) {
event.preventDefault();
// And we shouldn't be able to make a regular Worker to a non-chrome URL.
worker = new Worker(mochitestURL);
worker.onmessage = function(event) {
throw event.data;
};
worker.onerror = function(event) {
event.preventDefault();
try{
new ChromeWorker(mochitestURL);
} catch(e) {
if (e.name === 'SecurityError') {
postMessage("Done");
};
worker.postMessage("Hi");
};
worker.postMessage("Hi");
return;
}
}
throw('creating a chrome worker with a bad URL should throw a SecurityError');
};

Просмотреть файл

@ -511,8 +511,8 @@ FrameAnimator::DoBlend(IntRect* aDirtyRect,
// Create the Compositing Frame
if (!mCompositingFrame) {
RefPtr<imgFrame> newFrame = new imgFrame;
nsresult rv = newFrame->InitForDecoder(mSize,
SurfaceFormat::B8G8R8A8);
nsresult rv = newFrame->InitForAnimator(mSize,
SurfaceFormat::B8G8R8A8);
if (NS_FAILED(rv)) {
mCompositingFrame.reset();
return false;
@ -652,8 +652,8 @@ FrameAnimator::DoBlend(IntRect* aDirtyRect,
// overwrite.
if (!mCompositingPrevFrame) {
RefPtr<imgFrame> newFrame = new imgFrame;
nsresult rv = newFrame->InitForDecoder(mSize,
SurfaceFormat::B8G8R8A8);
nsresult rv = newFrame->InitForAnimator(mSize,
SurfaceFormat::B8G8R8A8);
if (NS_FAILED(rv)) {
mCompositingPrevFrame.reset();
return false;

Просмотреть файл

@ -605,7 +605,7 @@ RasterImage::GetImageContainer(LayerManager* aManager, uint32_t aFlags)
}
// |image| holds a reference to a SourceSurface which in turn holds a lock on
// the current frame's VolatileBuffer, ensuring that it doesn't get freed as
// the current frame's data buffer, ensuring that it doesn't get freed as
// long as the layer system keeps this ImageContainer alive.
AutoTArray<ImageContainer::NonOwningImage, 1> imageList;
imageList.AppendElement(ImageContainer::NonOwningImage(image, TimeStamp(),

Просмотреть файл

@ -20,6 +20,7 @@
#include "MainThreadUtils.h"
#include "mozilla/CheckedInt.h"
#include "mozilla/gfx/Tools.h"
#include "mozilla/layers/SourceSurfaceVolatileData.h"
#include "mozilla/Likely.h"
#include "mozilla/MemoryReporting.h"
#include "nsMargin.h"
@ -33,9 +34,9 @@ using namespace gfx;
namespace image {
static void
VolatileBufferRelease(void* vbuf)
ScopedMapRelease(void* aMap)
{
delete static_cast<VolatileBufferPtr<unsigned char>*>(vbuf);
delete static_cast<DataSourceSurface::ScopedMap*>(aMap);
}
static int32_t
@ -46,63 +47,62 @@ VolatileSurfaceStride(const IntSize& size, SurfaceFormat format)
}
static already_AddRefed<DataSourceSurface>
CreateLockedSurface(VolatileBuffer* vbuf,
CreateLockedSurface(DataSourceSurface *aSurface,
const IntSize& size,
SurfaceFormat format)
{
VolatileBufferPtr<unsigned char>* vbufptr =
new VolatileBufferPtr<unsigned char>(vbuf);
MOZ_ASSERT(!vbufptr->WasBufferPurged(), "Expected image data!");
const int32_t stride = VolatileSurfaceStride(size, format);
// The VolatileBufferPtr is held by this DataSourceSurface.
RefPtr<DataSourceSurface> surf =
Factory::CreateWrappingDataSourceSurface(*vbufptr, stride, size, format,
&VolatileBufferRelease,
static_cast<void*>(vbufptr));
if (!surf) {
delete vbufptr;
return nullptr;
DataSourceSurface::ScopedMap* smap =
new DataSourceSurface::ScopedMap(aSurface, DataSourceSurface::READ_WRITE);
if (smap->IsMapped()) {
// The ScopedMap is held by this DataSourceSurface.
RefPtr<DataSourceSurface> surf =
Factory::CreateWrappingDataSourceSurface(smap->GetData(),
aSurface->Stride(),
size,
format,
&ScopedMapRelease,
static_cast<void*>(smap));
if (surf) {
return surf.forget();
}
}
return surf.forget();
delete smap;
return nullptr;
}
static already_AddRefed<VolatileBuffer>
AllocateBufferForImage(const IntSize& size, SurfaceFormat format)
static already_AddRefed<DataSourceSurface>
AllocateBufferForImage(const IntSize& size,
SurfaceFormat format,
bool aIsAnimated = false)
{
int32_t stride = VolatileSurfaceStride(size, format);
RefPtr<VolatileBuffer> buf = new VolatileBuffer();
if (buf->Init(stride * size.height,
size_t(1) << gfxAlphaRecovery::GoodAlignmentLog2())) {
return buf.forget();
RefPtr<SourceSurfaceVolatileData> newSurf = new SourceSurfaceVolatileData();
if (newSurf->Init(size, stride, format)) {
return newSurf.forget();
}
return nullptr;
}
static bool
ClearSurface(VolatileBuffer* aVBuf, const IntSize& aSize, SurfaceFormat aFormat)
ClearSurface(DataSourceSurface* aSurface, const IntSize& aSize, SurfaceFormat aFormat)
{
VolatileBufferPtr<unsigned char> vbufptr(aVBuf);
if (vbufptr.WasBufferPurged()) {
NS_WARNING("VolatileBuffer was purged");
return false;
}
int32_t stride = aSurface->Stride();
uint8_t* data = aSurface->GetData();
MOZ_ASSERT(data);
int32_t stride = VolatileSurfaceStride(aSize, aFormat);
if (aFormat == SurfaceFormat::B8G8R8X8) {
// Skia doesn't support RGBX surfaces, so ensure the alpha value is set
// to opaque white. While it would be nice to only do this for Skia,
// imgFrame can run off main thread and past shutdown where
// we might not have gfxPlatform, so just memset everytime instead.
memset(vbufptr, 0xFF, stride * aSize.height);
} else if (aVBuf->OnHeap()) {
memset(data, 0xFF, stride * aSize.height);
} else if (aSurface->OnHeap()) {
// We only need to memset it if the buffer was allocated on the heap.
// Otherwise, it's allocated via mmap and refers to a zeroed page and will
// be COW once it's written to.
memset(vbufptr, 0, stride * aSize.height);
memset(data, 0, stride * aSize.height);
}
return true;
@ -191,7 +191,8 @@ imgFrame::InitForDecoder(const nsIntSize& aImageSize,
const nsIntRect& aRect,
SurfaceFormat aFormat,
uint8_t aPaletteDepth /* = 0 */,
bool aNonPremult /* = false */)
bool aNonPremult /* = false */,
bool aIsAnimated /* = false */)
{
// Assert for properties that should be verified by decoders,
// warn for properties related to bad content.
@ -239,23 +240,22 @@ imgFrame::InitForDecoder(const nsIntSize& aImageSize,
}
NS_ENSURE_TRUE(mPalettedImageData, NS_ERROR_OUT_OF_MEMORY);
} else {
MOZ_ASSERT(!mImageSurface, "Called imgFrame::InitForDecoder() twice?");
MOZ_ASSERT(!mLockedSurface, "Called imgFrame::InitForDecoder() twice?");
mVBuf = AllocateBufferForImage(mFrameRect.Size(), mFormat);
if (!mVBuf) {
mRawSurface = AllocateBufferForImage(mFrameRect.Size(), mFormat, aIsAnimated);
if (!mRawSurface) {
mAborted = true;
return NS_ERROR_OUT_OF_MEMORY;
}
mImageSurface = CreateLockedSurface(mVBuf, mFrameRect.Size(), mFormat);
if (!mImageSurface) {
NS_WARNING("Failed to create ImageSurface");
mLockedSurface = CreateLockedSurface(mRawSurface, mFrameRect.Size(), mFormat);
if (!mLockedSurface) {
NS_WARNING("Failed to create LockedSurface");
mAborted = true;
return NS_ERROR_OUT_OF_MEMORY;
}
if (!ClearSurface(mVBuf, mFrameRect.Size(), mFormat)) {
if (!ClearSurface(mRawSurface, mFrameRect.Size(), mFormat)) {
NS_WARNING("Could not clear allocated buffer");
mAborted = true;
return NS_ERROR_OUT_OF_MEMORY;
@ -295,39 +295,31 @@ imgFrame::InitWithDrawable(gfxDrawable* aDrawable,
if (canUseDataSurface) {
// It's safe to use data surfaces for content on this platform, so we can
// get away with using volatile buffers.
MOZ_ASSERT(!mImageSurface, "Called imgFrame::InitWithDrawable() twice?");
MOZ_ASSERT(!mLockedSurface, "Called imgFrame::InitWithDrawable() twice?");
mVBuf = AllocateBufferForImage(mFrameRect.Size(), mFormat);
if (!mVBuf) {
mRawSurface = AllocateBufferForImage(mFrameRect.Size(), mFormat);
if (!mRawSurface) {
mAborted = true;
return NS_ERROR_OUT_OF_MEMORY;
}
int32_t stride = VolatileSurfaceStride(mFrameRect.Size(), mFormat);
VolatileBufferPtr<uint8_t> ptr(mVBuf);
if (!ptr) {
mLockedSurface = CreateLockedSurface(mRawSurface, mFrameRect.Size(), mFormat);
if (!mLockedSurface) {
NS_WARNING("Failed to create LockedSurface");
mAborted = true;
return NS_ERROR_OUT_OF_MEMORY;
}
mImageSurface = CreateLockedSurface(mVBuf, mFrameRect.Size(), mFormat);
if (!mImageSurface) {
NS_WARNING("Failed to create ImageSurface");
mAborted = true;
return NS_ERROR_OUT_OF_MEMORY;
}
if (!ClearSurface(mVBuf, mFrameRect.Size(), mFormat)) {
if (!ClearSurface(mRawSurface, mFrameRect.Size(), mFormat)) {
NS_WARNING("Could not clear allocated buffer");
mAborted = true;
return NS_ERROR_OUT_OF_MEMORY;
}
target = gfxPlatform::CreateDrawTargetForData(
ptr,
mLockedSurface->GetData(),
mFrameRect.Size(),
stride,
mLockedSurface->Stride(),
mFormat);
} else {
// We can't use data surfaces for content, so we'll create an offscreen
@ -357,7 +349,7 @@ imgFrame::InitWithDrawable(gfxDrawable* aDrawable,
ImageRegion::Create(ThebesRect(mFrameRect)),
mFormat, aSamplingFilter, aImageFlags);
if (canUseDataSurface && !mImageSurface) {
if (canUseDataSurface && !mLockedSurface) {
NS_WARNING("Failed to create VolatileDataSourceSurface");
mAborted = true;
return NS_ERROR_OUT_OF_MEMORY;
@ -422,23 +414,23 @@ imgFrame::Optimize(DrawTarget* aTarget)
}
mOptSurface = gfxPlatform::GetPlatform()
->ScreenReferenceDrawTarget()->OptimizeSourceSurface(mImageSurface);
if (mOptSurface == mImageSurface) {
->ScreenReferenceDrawTarget()->OptimizeSourceSurface(mLockedSurface);
if (mOptSurface == mLockedSurface) {
mOptSurface = nullptr;
}
if (mOptSurface) {
// There's no reason to keep our volatile buffer around at all if we have an
// There's no reason to keep our original surface around if we have an
// optimized surface. Release our reference to it. This will leave
// |mVBufPtr| and |mImageSurface| as the only things keeping it alive, so
// it'll get freed below.
mVBuf = nullptr;
// |mLockedSurface| as the only thing keeping it alive, so it'll get freed
// below.
mRawSurface = nullptr;
}
// Release all strong references to our volatile buffer's memory. This will
// allow the operating system to free the memory if it needs to.
mVBufPtr = nullptr;
mImageSurface = nullptr;
// Release all strong references to the surface's memory. If the underlying
// surface is volatile, this will allow the operating system to free the
// memory if it needs to.
mLockedSurface = nullptr;
mOptimizable = false;
return NS_OK;
@ -536,7 +528,7 @@ bool imgFrame::Draw(gfxContext* aContext, const ImageRegion& aRegion,
MonitorAutoLock lock(mMonitor);
// Possibly convert this image into a GPU texture, this may also cause our
// mImageSurface to be released and the OS to release the underlying memory.
// mLockedSurface to be released and the OS to release the underlying memory.
Optimize(aContext->GetDrawTarget());
bool doPartialDecode = !AreAllPixelsWritten();
@ -610,7 +602,7 @@ imgFrame::GetImageBytesPerRow() const
{
mMonitor.AssertCurrentThreadOwns();
if (mVBuf) {
if (mRawSurface) {
return mFrameRect.width * BytesPerPixel(mFormat);
}
@ -640,17 +632,17 @@ imgFrame::GetImageDataInternal(uint8_t** aData, uint32_t* aLength) const
mMonitor.AssertCurrentThreadOwns();
MOZ_ASSERT(mLockCount > 0, "Image data should be locked");
if (mImageSurface) {
*aData = mVBufPtr;
if (mLockedSurface) {
*aData = mLockedSurface->GetData();
MOZ_ASSERT(*aData,
"mImageSurface is non-null, but mVBufPtr is null in GetImageData");
"mLockedSurface is non-null, but GetData is null in GetImageData");
} else if (mPalettedImageData) {
*aData = mPalettedImageData + PaletteDataLength();
MOZ_ASSERT(*aData,
"mPalettedImageData is non-null, but result is null in GetImageData");
} else {
MOZ_ASSERT(false,
"Have neither mImageSurface nor mPalettedImageData in GetImageData");
"Have neither mLockedSurface nor mPalettedImageData in GetImageData");
*aData = nullptr;
}
@ -712,9 +704,8 @@ imgFrame::LockImageData()
return NS_OK;
}
// If we're the first lock, but have an image surface, we're OK.
if (mImageSurface) {
mVBufPtr = mVBuf;
// If we're the first lock, but have the locked surface, we're OK.
if (mLockedSurface) {
return NS_OK;
}
@ -783,21 +774,12 @@ imgFrame::GetSourceSurfaceInternal()
}
}
if (mImageSurface) {
RefPtr<SourceSurface> surf(mImageSurface);
if (mLockedSurface) {
RefPtr<SourceSurface> surf(mLockedSurface);
return surf.forget();
}
if (!mVBuf) {
return nullptr;
}
VolatileBufferPtr<char> buf(mVBuf);
if (buf.WasBufferPurged()) {
return nullptr;
}
return CreateLockedSurface(mVBuf, mFrameRect.Size(), mFormat);
return CreateLockedSurface(mRawSurface, mFrameRect.Size(), mFormat);
}
AnimationData
@ -891,17 +873,16 @@ imgFrame::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
if (mPalettedImageData) {
aHeapSizeOut += aMallocSizeOf(mPalettedImageData);
}
if (mImageSurface) {
aHeapSizeOut += aMallocSizeOf(mImageSurface);
if (mLockedSurface) {
aHeapSizeOut += aMallocSizeOf(mLockedSurface);
}
if (mOptSurface) {
aHeapSizeOut += aMallocSizeOf(mOptSurface);
}
if (mVBuf) {
aHeapSizeOut += aMallocSizeOf(mVBuf);
aHeapSizeOut += mVBuf->HeapSizeOfExcludingThis(aMallocSizeOf);
aNonHeapSizeOut += mVBuf->NonHeapSizeOfExcludingThis();
if (mRawSurface) {
aHeapSizeOut += aMallocSizeOf(mRawSurface);
mRawSurface->AddSizeOfExcludingThis(aMallocSizeOf, aHeapSizeOut,
aNonHeapSizeOut);
}
}

Просмотреть файл

@ -11,10 +11,10 @@
#include "mozilla/MemoryReporting.h"
#include "mozilla/Monitor.h"
#include "mozilla/Move.h"
#include "mozilla/VolatileBuffer.h"
#include "gfxDrawable.h"
#include "imgIContainer.h"
#include "MainThreadUtils.h"
#include "nsAutoPtr.h"
namespace mozilla {
namespace image {
@ -210,14 +210,14 @@ public:
const nsIntRect& aRect,
SurfaceFormat aFormat,
uint8_t aPaletteDepth = 0,
bool aNonPremult = false);
bool aNonPremult = false,
bool aIsAnimated = false);
nsresult InitForDecoder(const nsIntSize& aSize,
SurfaceFormat aFormat,
uint8_t aPaletteDepth = 0)
nsresult InitForAnimator(const nsIntSize& aSize,
SurfaceFormat aFormat)
{
return InitForDecoder(aSize, nsIntRect(0, 0, aSize.width, aSize.height),
aFormat, aPaletteDepth);
aFormat, 0, false, true);
}
@ -395,11 +395,25 @@ private: // data
mutable Monitor mMonitor;
RefPtr<DataSourceSurface> mImageSurface;
RefPtr<SourceSurface> mOptSurface;
/**
* Surface which contains either a weak or a strong reference to its
* underlying data buffer. If it is a weak reference, and there are no strong
* references, the buffer may be released due to events such as low memory.
*/
RefPtr<DataSourceSurface> mRawSurface;
RefPtr<VolatileBuffer> mVBuf;
VolatileBufferPtr<uint8_t> mVBufPtr;
/**
* Refers to the same data as mRawSurface, but when set, it guarantees that
* we hold a strong reference to the underlying data buffer.
*/
RefPtr<DataSourceSurface> mLockedSurface;
/**
* Optimized copy of mRawSurface for the DrawTarget that will render it. This
* is unused if the DrawTarget is able to render DataSourceSurface buffers
* directly.
*/
RefPtr<SourceSurface> mOptSurface;
nsIntRect mDecoded;
@ -450,16 +464,27 @@ private: // data
*/
class DrawableFrameRef final
{
typedef gfx::DataSourceSurface DataSourceSurface;
public:
DrawableFrameRef() { }
explicit DrawableFrameRef(imgFrame* aFrame)
: mFrame(aFrame)
, mRef(aFrame->mVBuf)
{
if (mRef.WasBufferPurged()) {
mFrame = nullptr;
mRef = nullptr;
// Paletted images won't have a surface so there is no strong reference
// to hold on to. Since Draw() and GetSourceSurface() calls will not work
// in that case, we should be using RawAccessFrameRef exclusively instead.
// See FrameAnimator::GetRawFrame for an example of this behaviour.
if (aFrame->mRawSurface) {
mRef = new DataSourceSurface::ScopedMap(aFrame->mRawSurface,
DataSourceSurface::READ_WRITE);
if (!mRef->IsMapped()) {
mFrame = nullptr;
mRef = nullptr;
}
} else {
MOZ_ASSERT(aFrame->mOptSurface || aFrame->GetIsPaletted());
}
}
@ -503,7 +528,7 @@ private:
DrawableFrameRef(const DrawableFrameRef& aOther) = delete;
RefPtr<imgFrame> mFrame;
VolatileBufferPtr<uint8_t> mRef;
nsAutoPtr<DataSourceSurface::ScopedMap> mRef;
};
/**

Просмотреть файл

@ -15,6 +15,9 @@
#ifndef ENABLE_INTL_API
#include "nsCOMPtr.h"
#include "nsIUnicodeDecoder.h"
#else
#include "gtest/MozGtestFriend.h"
#include "unicode/udat.h"
#endif
namespace mozilla {
@ -47,6 +50,15 @@ private:
static nsresult Initialize();
#ifdef ENABLE_INTL_API
FRIEND_TEST(DateTimeFormat, FormatPRExplodedTime);
// performs a locale sensitive date formatting operation on the UDate parameter
static nsresult FormatUDateTime(const nsDateFormatSelector aDateFormatSelector,
const nsTimeFormatSelector aTimeFormatSelector,
const UDate aUDateTime,
const PRTimeParameters* aTimeParameters,
nsAString& aStringOut);
static nsCString* mLocale;
#else
// performs a locale sensitive date formatting operation on the struct tm parameter

Просмотреть файл

@ -8,7 +8,6 @@
#include "nsCOMPtr.h"
#include "nsIServiceManager.h"
#include "nsILocaleService.h"
#include "unicode/udat.h"
namespace mozilla {
@ -58,6 +57,27 @@ DateTimeFormat::FormatPRTime(const nsDateFormatSelector aDateFormatSelector,
const nsTimeFormatSelector aTimeFormatSelector,
const PRTime aPrTime,
nsAString& aStringOut)
{
return FormatUDateTime(aDateFormatSelector, aTimeFormatSelector, (aPrTime / PR_USEC_PER_MSEC), nullptr, aStringOut);
}
// performs a locale sensitive date formatting operation on the PRExplodedTime parameter
/*static*/ nsresult
DateTimeFormat::FormatPRExplodedTime(const nsDateFormatSelector aDateFormatSelector,
const nsTimeFormatSelector aTimeFormatSelector,
const PRExplodedTime* aExplodedTime,
nsAString& aStringOut)
{
return FormatUDateTime(aDateFormatSelector, aTimeFormatSelector, (PR_ImplodeTime(aExplodedTime) / PR_USEC_PER_MSEC), &(aExplodedTime->tm_params), aStringOut);
}
// performs a locale sensitive date formatting operation on the UDate parameter
/*static*/ nsresult
DateTimeFormat::FormatUDateTime(const nsDateFormatSelector aDateFormatSelector,
const nsTimeFormatSelector aTimeFormatSelector,
const UDate aUDateTime,
const PRTimeParameters* aTimeParameters,
nsAString& aStringOut)
{
#define DATETIME_FORMAT_INITIAL_LEN 127
int32_t dateTimeLen = 0;
@ -76,8 +96,6 @@ DateTimeFormat::FormatPRTime(const nsDateFormatSelector aDateFormatSelector,
return rv;
}
UDate timeUDate = aPrTime / PR_USEC_PER_MSEC;
// Get the date style for the formatter:
UDateFormatStyle dateStyle;
switch (aDateFormatSelector) {
@ -116,16 +134,31 @@ DateTimeFormat::FormatPRTime(const nsDateFormatSelector aDateFormatSelector,
UErrorCode status = U_ZERO_ERROR;
UDateFormat* dateTimeFormat = udat_open(timeStyle, dateStyle, mLocale->get(), nullptr, -1, nullptr, -1, &status);
UDateFormat* dateTimeFormat;
if (aTimeParameters) {
nsAutoString timeZoneID(u"GMT");
int32_t totalOffsetMinutes = (aTimeParameters->tp_gmt_offset + aTimeParameters->tp_dst_offset) / 60;
if (totalOffsetMinutes != 0) {
char sign = totalOffsetMinutes < 0 ? '-' : '+';
int32_t hours = abs(totalOffsetMinutes) / 60;
int32_t minutes = abs(totalOffsetMinutes) % 60;
timeZoneID.AppendPrintf("%c%02d:%02d", sign, hours, minutes);
}
dateTimeFormat = udat_open(timeStyle, dateStyle, mLocale->get(), reinterpret_cast<const UChar*>(timeZoneID.BeginReading()), timeZoneID.Length(), nullptr, -1, &status);
} else {
dateTimeFormat = udat_open(timeStyle, dateStyle, mLocale->get(), nullptr, -1, nullptr, -1, &status);
}
if (U_SUCCESS(status) && dateTimeFormat) {
aStringOut.SetLength(DATETIME_FORMAT_INITIAL_LEN);
dateTimeLen = udat_format(dateTimeFormat, timeUDate, reinterpret_cast<UChar*>(aStringOut.BeginWriting()), DATETIME_FORMAT_INITIAL_LEN, nullptr, &status);
dateTimeLen = udat_format(dateTimeFormat, aUDateTime, reinterpret_cast<UChar*>(aStringOut.BeginWriting()), DATETIME_FORMAT_INITIAL_LEN, nullptr, &status);
aStringOut.SetLength(dateTimeLen);
if (status == U_BUFFER_OVERFLOW_ERROR) {
status = U_ZERO_ERROR;
udat_format(dateTimeFormat, timeUDate, reinterpret_cast<UChar*>(aStringOut.BeginWriting()), dateTimeLen, nullptr, &status);
udat_format(dateTimeFormat, aUDateTime, reinterpret_cast<UChar*>(aStringOut.BeginWriting()), dateTimeLen, nullptr, &status);
}
}
@ -140,16 +173,6 @@ DateTimeFormat::FormatPRTime(const nsDateFormatSelector aDateFormatSelector,
return rv;
}
// performs a locale sensitive date formatting operation on the PRExplodedTime parameter
/*static*/ nsresult
DateTimeFormat::FormatPRExplodedTime(const nsDateFormatSelector aDateFormatSelector,
const nsTimeFormatSelector aTimeFormatSelector,
const PRExplodedTime* aExplodedTime,
nsAString& aStringOut)
{
return FormatPRTime(aDateFormatSelector, aTimeFormatSelector, PR_ImplodeTime(aExplodedTime), aStringOut);
}
/*static*/ void
DateTimeFormat::Shutdown()
{

Просмотреть файл

@ -0,0 +1,49 @@
#include "gtest/gtest.h"
#include "DateTimeFormat.h"
namespace mozilla {
TEST(DateTimeFormat, FormatPRExplodedTime) {
PRTime prTime = 0;
PRExplodedTime prExplodedTime;
PR_ExplodeTime(prTime, PR_GMTParameters, &prExplodedTime);
mozilla::DateTimeFormat::mLocale = new nsCString("en-US");
nsAutoString formattedTime;
nsresult rv = mozilla::DateTimeFormat::FormatPRExplodedTime(kDateFormatLong, kTimeFormatSeconds, &prExplodedTime, formattedTime);
ASSERT_TRUE(NS_SUCCEEDED(rv));
ASSERT_STREQ("January 1, 1970 at 12:00:00 AM", NS_ConvertUTF16toUTF8(formattedTime).get());
prExplodedTime = { 0, 0, 19, 0, 1, 0, 1970, 4, 0, { (19 * 60), 0 } };
rv = mozilla::DateTimeFormat::FormatPRExplodedTime(kDateFormatLong, kTimeFormatSeconds, &prExplodedTime, formattedTime);
ASSERT_TRUE(NS_SUCCEEDED(rv));
ASSERT_STREQ("January 1, 1970 at 12:19:00 AM", NS_ConvertUTF16toUTF8(formattedTime).get());
prExplodedTime = { 0, 0, 0, 7, 1, 0, 1970, 4, 0, { (6 * 60 * 60), (1 * 60 * 60) } };
rv = mozilla::DateTimeFormat::FormatPRExplodedTime(kDateFormatLong, kTimeFormatSeconds, &prExplodedTime, formattedTime);
ASSERT_TRUE(NS_SUCCEEDED(rv));
ASSERT_STREQ("January 1, 1970 at 7:00:00 AM", NS_ConvertUTF16toUTF8(formattedTime).get());
prExplodedTime = { 0, 0, 29, 11, 1, 0, 1970, 4, 0, { (10 * 60 * 60) + (29 * 60), (1 * 60 * 60) } };
rv = mozilla::DateTimeFormat::FormatPRExplodedTime(kDateFormatLong, kTimeFormatSeconds, &prExplodedTime, formattedTime);
ASSERT_TRUE(NS_SUCCEEDED(rv));
ASSERT_STREQ("January 1, 1970 at 11:29:00 AM", NS_ConvertUTF16toUTF8(formattedTime).get());
prExplodedTime = { 0, 0, 37, 23, 31, 11, 1969, 3, 364, { -(23 * 60), 0 } };
rv = mozilla::DateTimeFormat::FormatPRExplodedTime(kDateFormatLong, kTimeFormatSeconds, &prExplodedTime, formattedTime);
ASSERT_TRUE(NS_SUCCEEDED(rv));
ASSERT_STREQ("December 31, 1969 at 11:37:00 PM", NS_ConvertUTF16toUTF8(formattedTime).get());
prExplodedTime = { 0, 0, 0, 17, 31, 11, 1969, 3, 364, { -(7 * 60 * 60), 0 } };
rv = mozilla::DateTimeFormat::FormatPRExplodedTime(kDateFormatLong, kTimeFormatSeconds, &prExplodedTime, formattedTime);
ASSERT_TRUE(NS_SUCCEEDED(rv));
ASSERT_STREQ("December 31, 1969 at 5:00:00 PM", NS_ConvertUTF16toUTF8(formattedTime).get());
prExplodedTime = { 0, 0, 47, 14, 31, 11, 1969, 3, 364, { -((10 * 60 * 60) + (13 * 60)), (1 * 60 * 60) } };
rv = mozilla::DateTimeFormat::FormatPRExplodedTime(kDateFormatLong, kTimeFormatSeconds, &prExplodedTime, formattedTime);
ASSERT_TRUE(NS_SUCCEEDED(rv));
ASSERT_STREQ("December 31, 1969 at 2:47:00 PM", NS_ConvertUTF16toUTF8(formattedTime).get());
}
}

Просмотреть файл

@ -9,7 +9,10 @@ UNIFIED_SOURCES += [
]
if CONFIG['ENABLE_INTL_API']:
UNIFIED_SOURCES += ['TestOSPreferences.cpp']
UNIFIED_SOURCES += [
'TestDateTimeFormat.cpp',
'TestOSPreferences.cpp',
]
LOCAL_INCLUDES += [
'/intl/locale',

Просмотреть файл

@ -20,12 +20,12 @@
#endif
#include "jswrapper.h"
#include "jit/AtomicOperations.h"
#include "js/Conversions.h"
#include "vm/ArrayBufferObject.h"
#include "vm/GlobalObject.h"
#include "vm/Interpreter.h"
#include "vm/SharedMem.h"
#include "vm/TypedArrayCommon.h"
#include "vm/WrapperObject.h"
#include "gc/Nursery-inl.h"

Просмотреть файл

@ -3304,7 +3304,7 @@ function Intl_getDisplayNames(locales, options) {
for (let i = 0; i < len; i++) {
// a. Let processedKey be ? ToString(? Get(keys, i)).
// b. Perform ? CreateDataPropertyOrThrow(processedKeys, i, processedKey).
callFunction(std_Array_push, processedKeys, ToString(keys[i]));
_DefineDataProperty(processedKeys, i, ToString(keys[i]));
}
// 16. Let names be ? ComputeDisplayNames(r.[[locale]], style, processedKeys).

Просмотреть файл

@ -23,6 +23,7 @@
#include "jsprf.h"
#include "builtin/TypedObject.h"
#include "jit/AtomicOperations.h"
#include "jit/InlinableNatives.h"
#include "js/GCAPI.h"
#include "js/Value.h"

Просмотреть файл

@ -44,6 +44,7 @@
#include "ctypes/Library.h"
#include "gc/Policy.h"
#include "gc/Zone.h"
#include "jit/AtomicOperations.h"
#include "js/Vector.h"
#include "jsatominlines.h"

Просмотреть файл

@ -102,7 +102,7 @@ class BackgroundDecommitTask : public GCParallelTask
void run() override;
private:
UnprotectedData<ChunkVector> toDecommit;
ActiveThreadOrGCTaskData<ChunkVector> toDecommit;
};
/*
@ -120,14 +120,14 @@ class GCSchedulingTunables
UnprotectedData<size_t> gcMaxBytes_;
/* Maximum nursery size for each zone group. */
UnprotectedData<size_t> gcMaxNurseryBytes_;
ActiveThreadData<size_t> gcMaxNurseryBytes_;
/*
* The base value used to compute zone->trigger.gcBytes(). When
* usage.gcBytes() surpasses threshold.gcBytes() for a zone, the zone may
* be scheduled for a GC, depending on the exact circumstances.
*/
UnprotectedData<size_t> gcZoneAllocThresholdBase_;
ActiveThreadOrGCTaskData<size_t> gcZoneAllocThresholdBase_;
/* Fraction of threshold.gcBytes() which triggers an incremental GC. */
UnprotectedData<double> zoneAllocThresholdFactor_;
@ -142,38 +142,38 @@ class GCSchedulingTunables
* Totally disables |highFrequencyGC|, the HeapGrowthFactor, and other
* tunables that make GC non-deterministic.
*/
UnprotectedData<bool> dynamicHeapGrowthEnabled_;
ActiveThreadData<bool> dynamicHeapGrowthEnabled_;
/*
* We enter high-frequency mode if we GC a twice within this many
* microseconds. This value is stored directly in microseconds.
*/
UnprotectedData<uint64_t> highFrequencyThresholdUsec_;
ActiveThreadData<uint64_t> highFrequencyThresholdUsec_;
/*
* When in the |highFrequencyGC| mode, these parameterize the per-zone
* "HeapGrowthFactor" computation.
*/
UnprotectedData<uint64_t> highFrequencyLowLimitBytes_;
UnprotectedData<uint64_t> highFrequencyHighLimitBytes_;
UnprotectedData<double> highFrequencyHeapGrowthMax_;
UnprotectedData<double> highFrequencyHeapGrowthMin_;
ActiveThreadData<uint64_t> highFrequencyLowLimitBytes_;
ActiveThreadData<uint64_t> highFrequencyHighLimitBytes_;
ActiveThreadData<double> highFrequencyHeapGrowthMax_;
ActiveThreadData<double> highFrequencyHeapGrowthMin_;
/*
* When not in |highFrequencyGC| mode, this is the global (stored per-zone)
* "HeapGrowthFactor".
*/
UnprotectedData<double> lowFrequencyHeapGrowth_;
ActiveThreadData<double> lowFrequencyHeapGrowth_;
/*
* Doubles the length of IGC slices when in the |highFrequencyGC| mode.
*/
UnprotectedData<bool> dynamicMarkSliceEnabled_;
ActiveThreadData<bool> dynamicMarkSliceEnabled_;
/*
* Controls whether painting can trigger IGC slices.
*/
UnprotectedData<bool> refreshFrameSlicesEnabled_;
ActiveThreadData<bool> refreshFrameSlicesEnabled_;
/*
* Controls the number of empty chunks reserved for future allocation.
@ -526,7 +526,7 @@ class GCSchedulingState
* growth factor is a measure of how large (as a percentage of the last GC)
* the heap is allowed to grow before we try to schedule another GC.
*/
UnprotectedData<bool> inHighFrequencyGCMode_;
ActiveThreadData<bool> inHighFrequencyGCMode_;
public:
GCSchedulingState()
@ -545,8 +545,8 @@ class GCSchedulingState
template<typename F>
struct Callback {
UnprotectedData<F> op;
UnprotectedData<void*> data;
ActiveThreadData<F> op;
ActiveThreadData<void*> data;
Callback()
: op(nullptr), data(nullptr)
@ -557,7 +557,7 @@ struct Callback {
};
template<typename F>
using CallbackVector = UnprotectedData<Vector<Callback<F>, 4, SystemAllocPolicy>>;
using CallbackVector = ActiveThreadData<Vector<Callback<F>, 4, SystemAllocPolicy>>;
template <typename T, typename Iter0, typename Iter1>
class ChainedIter
@ -979,7 +979,7 @@ class GCRuntime
UnprotectedData<JS::Zone*> systemZone;
// List of all zone groups (protected by the GC lock).
UnprotectedData<ZoneGroupVector> groups;
ActiveThreadData<ZoneGroupVector> groups;
// The unique atoms zone, which has no zone group.
WriteOnceData<Zone*> atomsZone;
@ -1023,9 +1023,9 @@ class GCRuntime
// so as to reduce the cost of operations on the available lists.
UnprotectedData<ChunkPool> fullChunks_;
UnprotectedData<RootedValueMap> rootsHash;
ActiveThreadData<RootedValueMap> rootsHash;
UnprotectedData<size_t> maxMallocBytes;
ActiveThreadData<size_t> maxMallocBytes;
// An incrementing id used to assign unique ids to cells that require one.
mozilla::Atomic<uint64_t, mozilla::ReleaseAcquire> nextCellUniqueId_;
@ -1034,18 +1034,18 @@ class GCRuntime
* Number of the committed arenas in all GC chunks including empty chunks.
*/
mozilla::Atomic<uint32_t, mozilla::ReleaseAcquire> numArenasFreeCommitted;
UnprotectedData<VerifyPreTracer*> verifyPreData;
ActiveThreadData<VerifyPreTracer*> verifyPreData;
private:
UnprotectedData<bool> chunkAllocationSinceLastGC;
UnprotectedData<int64_t> lastGCTime;
ActiveThreadData<int64_t> lastGCTime;
UnprotectedData<JSGCMode> mode;
ActiveThreadData<JSGCMode> mode;
mozilla::Atomic<size_t, mozilla::ReleaseAcquire> numActiveZoneIters;
/* During shutdown, the GC needs to clean up every possible object. */
UnprotectedData<bool> cleanUpEverything;
ActiveThreadData<bool> cleanUpEverything;
// Gray marking must be done after all black marking is complete. However,
// we do not have write barriers on XPConnect roots. Therefore, XPConnect
@ -1058,7 +1058,7 @@ class GCRuntime
Okay,
Failed
};
UnprotectedData<GrayBufferState> grayBufferState;
ActiveThreadData<GrayBufferState> grayBufferState;
bool hasBufferedGrayRoots() const { return grayBufferState == GrayBufferState::Okay; }
// Clear each zone's gray buffers, but do not change the current state.
@ -1079,83 +1079,83 @@ class GCRuntime
mozilla::Atomic<JS::gcreason::Reason, mozilla::Relaxed> majorGCTriggerReason;
public:
UnprotectedData<JS::gcreason::Reason> minorGCTriggerReason;
ActiveThreadData<JS::gcreason::Reason> minorGCTriggerReason;
private:
/* Perform full GC if rt->keepAtoms() becomes false. */
UnprotectedData<bool> fullGCForAtomsRequested_;
ActiveThreadData<bool> fullGCForAtomsRequested_;
/* Incremented at the start of every minor GC. */
UnprotectedData<uint64_t> minorGCNumber;
ActiveThreadData<uint64_t> minorGCNumber;
/* Incremented at the start of every major GC. */
UnprotectedData<uint64_t> majorGCNumber;
ActiveThreadData<uint64_t> majorGCNumber;
/* The major GC number at which to release observed type information. */
UnprotectedData<uint64_t> jitReleaseNumber;
ActiveThreadData<uint64_t> jitReleaseNumber;
/* Incremented on every GC slice. */
UnprotectedData<uint64_t> number;
ActiveThreadData<uint64_t> number;
/* The number at the time of the most recent GC's first slice. */
UnprotectedData<uint64_t> startNumber;
ActiveThreadData<uint64_t> startNumber;
/* Whether the currently running GC can finish in multiple slices. */
UnprotectedData<bool> isIncremental;
ActiveThreadData<bool> isIncremental;
/* Whether all zones are being collected in first GC slice. */
UnprotectedData<bool> isFull;
ActiveThreadData<bool> isFull;
/* Whether the heap will be compacted at the end of GC. */
UnprotectedData<bool> isCompacting;
ActiveThreadData<bool> isCompacting;
/* The invocation kind of the current GC, taken from the first slice. */
UnprotectedData<JSGCInvocationKind> invocationKind;
ActiveThreadData<JSGCInvocationKind> invocationKind;
/* The initial GC reason, taken from the first slice. */
UnprotectedData<JS::gcreason::Reason> initialReason;
ActiveThreadData<JS::gcreason::Reason> initialReason;
/*
* The current incremental GC phase. This is also used internally in
* non-incremental GC.
*/
UnprotectedData<State> incrementalState;
ActiveThreadOrGCTaskData<State> incrementalState;
/* Indicates that the last incremental slice exhausted the mark stack. */
UnprotectedData<bool> lastMarkSlice;
ActiveThreadData<bool> lastMarkSlice;
/* Whether any sweeping will take place in the separate GC helper thread. */
UnprotectedData<bool> sweepOnBackgroundThread;
ActiveThreadData<bool> sweepOnBackgroundThread;
/* Whether observed type information is being released in the current GC. */
UnprotectedData<bool> releaseObservedTypes;
ActiveThreadData<bool> releaseObservedTypes;
/* Whether any black->gray edges were found during marking. */
UnprotectedData<BlackGrayEdgeVector> foundBlackGrayEdges;
ActiveThreadData<BlackGrayEdgeVector> foundBlackGrayEdges;
/* Singly linked list of zones to be swept in the background. */
UnprotectedData<ZoneList> backgroundSweepZones;
ActiveThreadOrGCTaskData<ZoneList> backgroundSweepZones;
/*
* Free LIFO blocks are transferred to this allocator before being freed on
* the background GC thread after sweeping.
*/
UnprotectedData<LifoAlloc> blocksToFreeAfterSweeping;
ActiveThreadOrGCTaskData<LifoAlloc> blocksToFreeAfterSweeping;
private:
/* Index of current zone group (for stats). */
UnprotectedData<unsigned> zoneGroupIndex;
ActiveThreadData<unsigned> zoneGroupIndex;
/*
* Incremental sweep state.
*/
UnprotectedData<JS::Zone*> zoneGroups;
UnprotectedData<JS::Zone*> currentZoneGroup;
UnprotectedData<bool> sweepingTypes;
UnprotectedData<unsigned> finalizePhase;
UnprotectedData<JS::Zone*> sweepZone;
UnprotectedData<AllocKind> sweepKind;
UnprotectedData<bool> abortSweepAfterCurrentGroup;
ActiveThreadData<JS::Zone*> zoneGroups;
ActiveThreadOrGCTaskData<JS::Zone*> currentZoneGroup;
ActiveThreadData<bool> sweepingTypes;
ActiveThreadData<unsigned> finalizePhase;
ActiveThreadData<JS::Zone*> sweepZone;
ActiveThreadData<AllocKind> sweepKind;
ActiveThreadData<bool> abortSweepAfterCurrentGroup;
/*
* Concurrent sweep infrastructure.
@ -1166,17 +1166,17 @@ class GCRuntime
/*
* List head of arenas allocated during the sweep phase.
*/
UnprotectedData<Arena*> arenasAllocatedDuringSweep;
ActiveThreadData<Arena*> arenasAllocatedDuringSweep;
/*
* Incremental compacting state.
*/
UnprotectedData<bool> startedCompacting;
UnprotectedData<ZoneList> zonesToMaybeCompact;
UnprotectedData<Arena*> relocatedArenasToRelease;
ActiveThreadData<bool> startedCompacting;
ActiveThreadData<ZoneList> zonesToMaybeCompact;
ActiveThreadData<Arena*> relocatedArenasToRelease;
#ifdef JS_GC_ZEAL
UnprotectedData<MarkingValidator*> markingValidator;
ActiveThreadData<MarkingValidator*> markingValidator;
#endif
/*
@ -1184,23 +1184,23 @@ class GCRuntime
* frame, rather than at the beginning. In this case, the next slice will be
* delayed so that we don't get back-to-back slices.
*/
UnprotectedData<bool> interFrameGC;
ActiveThreadData<bool> interFrameGC;
/* Default budget for incremental GC slice. See js/SliceBudget.h. */
UnprotectedData<int64_t> defaultTimeBudget_;
ActiveThreadData<int64_t> defaultTimeBudget_;
/*
* We disable incremental GC if we encounter a Class with a trace hook
* that does not implement write barriers.
*/
UnprotectedData<bool> incrementalAllowed;
ActiveThreadData<bool> incrementalAllowed;
/*
* Whether compacting GC can is enabled globally.
*/
UnprotectedData<bool> compactingEnabled;
ActiveThreadData<bool> compactingEnabled;
UnprotectedData<bool> poked;
ActiveThreadData<bool> poked;
/*
* These options control the zealousness of the GC. At every allocation,
@ -1227,16 +1227,16 @@ class GCRuntime
* zeal_ value 14 performs periodic shrinking collections.
*/
#ifdef JS_GC_ZEAL
UnprotectedData<uint32_t> zealModeBits;
UnprotectedData<int> zealFrequency;
UnprotectedData<int> nextScheduled;
UnprotectedData<bool> deterministicOnly;
UnprotectedData<int> incrementalLimit;
ActiveThreadData<uint32_t> zealModeBits;
ActiveThreadData<int> zealFrequency;
ActiveThreadData<int> nextScheduled;
ActiveThreadData<bool> deterministicOnly;
ActiveThreadData<int> incrementalLimit;
UnprotectedData<Vector<JSObject*, 0, SystemAllocPolicy>> selectedForMarking;
ActiveThreadData<Vector<JSObject*, 0, SystemAllocPolicy>> selectedForMarking;
#endif
UnprotectedData<bool> fullCompartmentChecks;
ActiveThreadData<bool> fullCompartmentChecks;
Callback<JSGCCallback> gcCallback;
Callback<JS::DoCycleCollectionCallback> gcDoCycleCollectionCallback;
@ -1267,10 +1267,10 @@ class GCRuntime
Callback<JSTraceDataOp> grayRootTracer;
/* Always preserve JIT code during GCs, for testing. */
UnprotectedData<bool> alwaysPreserveCode;
ActiveThreadData<bool> alwaysPreserveCode;
#ifdef DEBUG
UnprotectedData<bool> arenasEmptyAtShutdown;
ActiveThreadData<bool> arenasEmptyAtShutdown;
#endif
/* Synchronize GC heap access among GC helper threads and main threads. */
@ -1286,7 +1286,7 @@ class GCRuntime
* During incremental sweeping, this field temporarily holds the arenas of
* the current AllocKind being swept in order of increasing free space.
*/
UnprotectedData<SortedArenaList> incrementalSweepList;
ActiveThreadData<SortedArenaList> incrementalSweepList;
friend class js::GCHelperState;
friend class MarkingValidator;

Просмотреть файл

@ -57,13 +57,13 @@ class MarkStack
{
friend class GCMarker;
UnprotectedData<uintptr_t*> stack_;
UnprotectedData<uintptr_t*> tos_;
UnprotectedData<uintptr_t*> end_;
ActiveThreadData<uintptr_t*> stack_;
ActiveThreadData<uintptr_t*> tos_;
ActiveThreadData<uintptr_t*> end_;
// The capacity we start with and reset() to.
UnprotectedData<size_t> baseCapacity_;
UnprotectedData<size_t> maxCapacity_;
ActiveThreadData<size_t> baseCapacity_;
ActiveThreadData<size_t> maxCapacity_;
public:
explicit MarkStack(size_t maxCapacity)
@ -336,29 +336,29 @@ class GCMarker : public JSTracer
MarkStack stack;
/* The color is only applied to objects and functions. */
UnprotectedData<uint32_t> color;
ActiveThreadData<uint32_t> color;
/* Pointer to the top of the stack of arenas we are delaying marking on. */
UnprotectedData<js::gc::Arena*> unmarkedArenaStackTop;
ActiveThreadData<js::gc::Arena*> unmarkedArenaStackTop;
/*
* If the weakKeys table OOMs, disable the linear algorithm and fall back
* to iterating until the next GC.
*/
UnprotectedData<bool> linearWeakMarkingDisabled_;
ActiveThreadData<bool> linearWeakMarkingDisabled_;
#ifdef DEBUG
/* Count of arenas that are currently in the stack. */
UnprotectedData<size_t> markLaterArenas;
ActiveThreadData<size_t> markLaterArenas;
/* Assert that start and stop are called with correct ordering. */
UnprotectedData<bool> started;
ActiveThreadData<bool> started;
/*
* If this is true, all marked objects must belong to a compartment being
* GCed. This is used to look for compartment bugs.
*/
UnprotectedData<bool> strictCompartmentChecking;
ActiveThreadData<bool> strictCompartmentChecking;
#endif // DEBUG
};

Просмотреть файл

@ -341,7 +341,7 @@ struct Zone : public JS::shadow::Zone,
private:
// The set of compartments in this zone.
js::UnprotectedData<CompartmentVector> compartments_;
js::ActiveThreadOrGCTaskData<CompartmentVector> compartments_;
public:
CompartmentVector& compartments() { return compartments_.ref(); }
@ -410,7 +410,7 @@ struct Zone : public JS::shadow::Zone,
mozilla::Atomic<ptrdiff_t, mozilla::ReleaseAcquire> gcMallocBytes;
// GC trigger threshold for allocations on the C heap.
js::UnprotectedData<size_t> gcMaxMallocBytes;
js::ActiveThreadData<size_t> gcMaxMallocBytes;
// Whether a GC has been triggered as a result of gcMallocBytes falling
// below zero.
@ -582,7 +582,7 @@ struct Zone : public JS::shadow::Zone,
js::ZoneGroupData<js::jit::JitZone*> jitZone_;
js::UnprotectedData<GCState> gcState_;
js::UnprotectedData<bool> gcScheduled_;
js::ActiveThreadData<bool> gcScheduled_;
js::ZoneGroupData<bool> gcPreserveCode_;
js::ZoneGroupData<bool> jitUsingBarriers_;
js::ZoneGroupData<bool> keepShapeTables_;
@ -810,11 +810,11 @@ struct GCManagedDeletePolicy
{
void operator()(const T* ptr) {
if (ptr) {
JSContext* cx = TlsContext.get();
if (cx->runtime()->zoneGroupFromMainThread()->nursery().isEnabled()) {
JSRuntime* rt = TlsContext.get()->runtime();
if (CurrentThreadCanAccessRuntime(rt) && rt->zoneGroupFromMainThread()->nursery().isEnabled()) {
// The object may contain nursery pointers and must only be
// destroyed after a minor GC.
cx->runtime()->zoneGroupFromMainThread()->callAfterMinorGC(deletePtr, const_cast<T*>(ptr));
rt->zoneGroupFromMainThread()->callAfterMinorGC(deletePtr, const_cast<T*>(ptr));
} else {
// The object cannot contain nursery pointers so can be
// destroyed immediately.

Просмотреть файл

@ -17,7 +17,7 @@ ZoneGroup::ZoneGroup(JSRuntime* runtime)
context(TlsContext.get()),
enterCount(this, 1),
zones_(),
nursery_(this),
nursery_(this, this),
storeBuffer_(this, runtime, nursery()),
blocksToFreeAfterMinorGC((size_t) JSContext::TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE),
caches_(this),

Просмотреть файл

@ -54,7 +54,7 @@ class ZoneGroup
// All zones in the group.
private:
UnprotectedData<ZoneVector> zones_;
ActiveThreadOrGCTaskData<ZoneVector> zones_;
public:
ZoneVector& zones() { return zones_.ref(); }
@ -64,7 +64,7 @@ class ZoneGroup
bool init(size_t maxNurseryBytes);
private:
UnprotectedData<Nursery> nursery_;
ZoneGroupData<Nursery> nursery_;
ZoneGroupData<gc::StoreBuffer> storeBuffer_;
public:
Nursery& nursery() { return nursery_.ref(); }
@ -72,7 +72,7 @@ class ZoneGroup
// Free LIFO blocks are transferred to this allocator before being freed
// after minor GC.
UnprotectedData<LifoAlloc> blocksToFreeAfterMinorGC;
ActiveThreadData<LifoAlloc> blocksToFreeAfterMinorGC;
void minorGC(JS::gcreason::Reason reason,
gcstats::Phase phase = gcstats::PHASE_MINOR_GC) JS_HAZ_GC_CALL;

Просмотреть файл

@ -0,0 +1,11 @@
if (this.Intl) {
Object.defineProperty(Object.prototype, 0, {
set: function() {}
});
function checkDisplayNames(names, expected) {}
addIntlExtras(Intl);
let gDN = Intl.getDisplayNames;
checkDisplayNames(gDN('ar', {
keys: ['dates/fields/month', ]
}), {});
}

Просмотреть файл

@ -0,0 +1 @@
JSON.stringify(this);

Просмотреть файл

@ -0,0 +1,6 @@
if (!('oomTest' in this))
quit();
oomTest(function () {
offThreadCompileModule('');
finishOffThreadModule();
});

Просмотреть файл

@ -1,6 +1,8 @@
// |jit-test| exitstatus: 6;
// |jit-test| error: 42;
for (var x of [0]) {
timeout(0.001);
for (;;) {}
for (var i = 0; ; i++) {
if (i === 20000)
throw 42;
}
}

Просмотреть файл

@ -124,8 +124,11 @@ testBinary32('rem_u', 41, 8, 1);
testBinary32('and', 42, 6, 2);
testBinary32('or', 42, 6, 46);
testBinary32('xor', 42, 2, 40);
testBinary32('shl', 40, 0, 40);
testBinary32('shl', 40, 2, 160);
testBinary32('shr_s', -40, 0, -40);
testBinary32('shr_s', -40, 2, -10);
testBinary32('shr_u', -40, 0, -40);
testBinary32('shr_u', -40, 2, 1073741814);
testTrap32('div_s', 42, 0, /integer divide by zero/);
@ -221,13 +224,16 @@ assertEq(testTrunc(13.37), 1);
testBinary64('shl', 1, 63, "0x8000000000000000");
testBinary64('shl', 1, 64, 1);
testBinary64('shl', 40, 2, 160);
testBinary64('shl', 40, 0, 40);
testBinary64('shr_s', -40, 0, -40);
testBinary64('shr_s', -40, 2, -10);
testBinary64('shr_s', "0xff00ff0000000", 28, 0xff00ff);
testBinary64('shr_s', "0xff00ff0000000", 30, 0x3fc03f);
testBinary64('shr_s', "0xff00ff0000000", 31, 0x1fe01f);
testBinary64('shr_s', "0xff00ff0000000", 32, 0x0ff00f);
testBinary64('shr_u', -40, 0, -40);
testBinary64('shr_u', -40, 2, "0x3ffffffffffffff6");
testBinary64('shr_u', "0x8ffff00ff0000000", 30, "0x23fffc03f");
testBinary64('shr_u', "0x8ffff00ff0000000", 31, "0x11fffe01f");

Просмотреть файл

@ -0,0 +1,42 @@
load(libdir + "wasm.js");
// Bug 1337060 causes too much register pressure on x86 by requiring four int64
// values in registers at the same time.
setJitCompilerOption('wasm.test-mode', 1);
wasmFullPassI64(`
(module
(func (result i64)
i64.const 0x2800000033
i64.const 0x9900000044
i64.const 0x1000000012
i64.const 0x1000000013
i64.lt_s
select) (export "run" 0))`, createI64("0x2800000033"));
wasmFullPassI64(`
(module
(func (result i64)
i64.const 0x2800000033
i64.const 0x9900000044
i64.const 0x1000000013
i64.const 0x1000000012
i64.lt_s
select) (export "run" 0))`, createI64("0x9900000044"));
wasmFullPassI64(`
(module
(func (export "run") (result i64) (param f32)
i64.const 0x13100000001
i64.const 0x23370000002
i64.const 0x34480000003
i32.const 1
select
i32.const 1
select
i64.const 0x45590000004
i32.const 1
select
)
)`, createI64("0x13100000001"));

Просмотреть файл

@ -837,8 +837,12 @@ BacktrackingAllocator::go()
if (!processBundle(mir, item.bundle))
return false;
}
JitSpew(JitSpew_RegAlloc, "Main allocation loop complete");
if (!tryAllocatingRegistersForSpillBundles())
return false;
if (!pickStackSlots())
return false;
@ -1210,7 +1214,8 @@ BacktrackingAllocator::tryAllocateNonFixed(LiveBundle* bundle,
// Spill bundles which have no hint or register requirement.
if (requirement.kind() == Requirement::NONE && hint.kind() != Requirement::REGISTER) {
if (!spill(bundle))
JitSpew(JitSpew_RegAlloc, " postponed spill (no hint or register requirement)");
if (!spilledBundles.append(bundle))
return false;
*success = true;
return true;
@ -1230,7 +1235,8 @@ BacktrackingAllocator::tryAllocateNonFixed(LiveBundle* bundle,
// Spill bundles which have no register requirement if they didn't get
// allocated.
if (requirement.kind() == Requirement::NONE) {
if (!spill(bundle))
JitSpew(JitSpew_RegAlloc, " postponed spill (no register requirement)");
if (!spilledBundles.append(bundle))
return false;
*success = true;
return true;
@ -1588,6 +1594,38 @@ BacktrackingAllocator::spill(LiveBundle* bundle)
return bundle->spillSet()->addSpilledBundle(bundle);
}
bool
BacktrackingAllocator::tryAllocatingRegistersForSpillBundles()
{
for (auto it = spilledBundles.begin(); it != spilledBundles.end(); it++) {
LiveBundle* bundle = *it;
LiveBundleVector conflicting;
bool fixed = false;
bool success = false;
if (mir->shouldCancel("Backtracking Try Allocating Spilled Bundles"))
return false;
if (JitSpewEnabled(JitSpew_RegAlloc))
JitSpew(JitSpew_RegAlloc, "Spill or allocate %s", bundle->toString().get());
// Search for any available register which the bundle can be
// allocated to.
for (size_t i = 0; i < AnyRegister::Total; i++) {
if (!tryAllocateRegister(registers[i], bundle, &success, &fixed, conflicting))
return false;
if (success)
break;
}
// If the bundle still has no register, spill the bundle.
if (!success && !spill(bundle))
return false;
}
return true;
}
bool
BacktrackingAllocator::pickStackSlots()
{

Просмотреть файл

@ -672,6 +672,8 @@ class BacktrackingAllocator : protected RegisterAllocator
// All allocated slots of each width.
SpillSlotList normalSlots, doubleSlots, quadSlots;
Vector<LiveBundle*, 4, SystemAllocPolicy> spilledBundles;
public:
BacktrackingAllocator(MIRGenerator* mir, LIRGenerator* lir, LIRGraph& graph, bool testbed)
: RegisterAllocator(mir, lir, graph),
@ -720,6 +722,7 @@ class BacktrackingAllocator : protected RegisterAllocator
MOZ_MUST_USE bool splitAndRequeueBundles(LiveBundle* bundle,
const LiveBundleVector& newBundles);
MOZ_MUST_USE bool spill(LiveBundle* bundle);
MOZ_MUST_USE bool tryAllocatingRegistersForSpillBundles();
bool isReusedInput(LUse* use, LNode* ins, bool considerCopy);
bool isRegisterUse(UsePosition* use, LNode* ins, bool considerCopy = false);

Просмотреть файл

@ -32,7 +32,6 @@
#include "js/GCVector.h"
#include "vm/Opcodes.h"
#include "vm/SelfHosting.h"
#include "vm/TypedArrayCommon.h"
#include "vm/TypedArrayObject.h"
#include "jsboolinlines.h"

Просмотреть файл

@ -21,7 +21,7 @@
#include "jit/shared/Assembler-shared.h"
#include "js/TrackedOptimizationInfo.h"
#include "vm/TypedArrayCommon.h"
#include "vm/TypedArrayObject.h"
namespace js {
namespace jit {

Просмотреть файл

@ -87,10 +87,10 @@ class JitRuntime
// Executable allocator for all code except wasm code and Ion code with
// patchable backedges (see below).
UnprotectedData<ExecutableAllocator> execAlloc_;
ActiveThreadData<ExecutableAllocator> execAlloc_;
// Executable allocator for Ion scripts with patchable backedges.
UnprotectedData<ExecutableAllocator> backedgeExecAlloc_;
ActiveThreadData<ExecutableAllocator> backedgeExecAlloc_;
// Shared exception-handler tail.
ExclusiveAccessLockWriteOnceData<JitCode*> exceptionTail_;

Просмотреть файл

@ -4861,6 +4861,9 @@ LIRGenerator::visitBlock(MBasicBlock* block)
uint32_t position = block->positionInPhiSuccessor();
size_t lirIndex = 0;
for (MPhiIterator phi(successor->phisBegin()); phi != successor->phisEnd(); phi++) {
if (!gen->ensureBallast())
return false;
MDefinition* opd = phi->getOperand(position);
ensureDefined(opd);

Просмотреть файл

@ -30,7 +30,7 @@
#include "vm/ArrayObject.h"
#include "vm/EnvironmentObject.h"
#include "vm/SharedMem.h"
#include "vm/TypedArrayCommon.h"
#include "vm/TypedArrayObject.h"
#include "vm/UnboxedObject.h"
// Undo windows.h damage on Win64

Просмотреть файл

@ -15,7 +15,7 @@
#include "jit/MIRGenerator.h"
#include "jit/MIRGraph.h"
#include "js/Conversions.h"
#include "vm/TypedArrayCommon.h"
#include "vm/TypedArrayObject.h"
#include "jsopcodeinlines.h"

Просмотреть файл

@ -17,7 +17,7 @@
#include "jit/SharedICList.h"
#include "jit/SharedICRegisters.h"
#include "vm/ReceiverGuard.h"
#include "vm/TypedArrayCommon.h"
#include "vm/TypedArrayObject.h"
namespace js {
namespace jit {

Просмотреть файл

@ -670,9 +670,10 @@ void
MacroAssembler::lshift64(Imm32 imm, Register64 dest)
{
MOZ_ASSERT(0 <= imm.value && imm.value < 64);
if (imm.value == 0) {
if (imm.value == 0)
return;
} else if (imm.value < 32) {
if (imm.value < 32) {
as_mov(dest.high, lsl(dest.high, imm.value));
as_orr(dest.high, dest.high, lsr(dest.low, 32 - imm.value));
as_mov(dest.low, lsl(dest.low, imm.value));
@ -716,7 +717,8 @@ void
MacroAssembler::rshiftPtr(Imm32 imm, Register dest)
{
MOZ_ASSERT(0 <= imm.value && imm.value < 32);
ma_lsr(imm, dest, dest);
if (imm.value)
ma_lsr(imm, dest, dest);
}
void
@ -736,13 +738,16 @@ void
MacroAssembler::rshiftPtrArithmetic(Imm32 imm, Register dest)
{
MOZ_ASSERT(0 <= imm.value && imm.value < 32);
ma_asr(imm, dest, dest);
if (imm.value)
ma_asr(imm, dest, dest);
}
void
MacroAssembler::rshift64Arithmetic(Imm32 imm, Register64 dest)
{
MOZ_ASSERT(0 <= imm.value && imm.value < 64);
if (!imm.value)
return;
if (imm.value < 32) {
as_mov(dest.low, lsr(dest.low, imm.value));
@ -802,6 +807,9 @@ MacroAssembler::rshift64(Imm32 imm, Register64 dest)
{
MOZ_ASSERT(0 <= imm.value && imm.value < 64);
MOZ_ASSERT(0 <= imm.value && imm.value < 64);
if (!imm.value)
return;
if (imm.value < 32) {
as_mov(dest.low, lsr(dest.low, imm.value));
as_orr(dest.low, dest.low, lsl(dest.high, 32 - imm.value));

Просмотреть файл

@ -87,7 +87,6 @@
#include "vm/String.h"
#include "vm/StringBuffer.h"
#include "vm/Symbol.h"
#include "vm/TypedArrayCommon.h"
#include "vm/WrapperObject.h"
#include "vm/Xdr.h"
#include "wasm/AsmJS.h"

Просмотреть файл

@ -35,7 +35,7 @@
#include "vm/SelfHosting.h"
#include "vm/Shape.h"
#include "vm/StringBuffer.h"
#include "vm/TypedArrayCommon.h"
#include "vm/TypedArrayObject.h"
#include "vm/WrapperObject.h"
#include "jsatominlines.h"

Просмотреть файл

@ -7494,6 +7494,7 @@ static bool
ZoneGCHeapGrowthFactorGetter(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
AutoLockGC lock(cx->runtime());
args.rval().setNumber(cx->zone()->threshold.gcHeapGrowthFactor());
return true;
}

Просмотреть файл

@ -651,7 +651,7 @@ class ArenaLists
const BackgroundFinalizeState& backgroundFinalizeState(AllocKind i) const { return backgroundFinalizeState_.ref()[i]; }
/* For each arena kind, a list of arenas remaining to be swept. */
UnprotectedData<AllAllocKindArray<Arena*>> arenaListsToSweep_;
ActiveThreadOrGCTaskData<AllAllocKindArray<Arena*>> arenaListsToSweep_;
Arena*& arenaListsToSweep(AllocKind i) { return arenaListsToSweep_.ref()[i]; }
Arena* arenaListsToSweep(AllocKind i) const { return arenaListsToSweep_.ref()[i]; }
@ -877,7 +877,7 @@ class GCHelperState
js::ConditionVariable done;
// Activity for the helper to do, protected by the GC lock.
UnprotectedData<State> state_;
ActiveThreadOrGCTaskData<State> state_;
// Whether work is being performed on some thread.
GCLockData<bool> hasThread;
@ -949,7 +949,7 @@ class GCParallelTask
UnprotectedData<TaskState> state;
// Amount of time this task took to execute.
UnprotectedData<mozilla::TimeDuration> duration_;
ActiveThreadOrGCTaskData<mozilla::TimeDuration> duration_;
explicit GCParallelTask(const GCParallelTask&) = delete;

Просмотреть файл

@ -32,7 +32,7 @@
#include "vm/Interpreter.h"
#include "vm/Shape.h"
#include "vm/StopIterationObject.h"
#include "vm/TypedArrayCommon.h"
#include "vm/TypedArrayObject.h"
#include "jsscriptinlines.h"

Просмотреть файл

@ -56,6 +56,40 @@
# define HAVE_ARC4RANDOM
#endif
#if defined(__linux__)
# include <linux/random.h> // For GRND_NONBLOCK.
# include <sys/syscall.h> // For SYS_getrandom.
// Older glibc versions don't define SYS_getrandom, so we define it here if
// it's not available. See bug 995069.
# if defined(__x86_64__)
# define GETRANDOM_NR 318
# elif defined(__i386__)
# define GETRANDOM_NR 355
# elif defined(__arm__)
# define GETRANDOM_NR 384
# endif
# if defined(SYS_getrandom)
// We have SYS_getrandom. Use it to check GETRANDOM_NR. Only do this if we set
// GETRANDOM_NR so tier 3 platforms with recent glibc are not forced to define
// it for no good reason.
# if defined(GETRANDOM_NR)
static_assert(GETRANDOM_NR == SYS_getrandom,
"GETRANDOM_NR should match the actual SYS_getrandom value");
# endif
# else
# define SYS_getrandom GETRANDOM_NR
# endif
# if defined(GRND_NONBLOCK)
static_assert(GRND_NONBLOCK == 1, "If GRND_NONBLOCK is not 1 the #define below is wrong");
# else
# define GRND_NONBLOCK 1
# endif
#endif // defined(__linux__)
using namespace js;
using mozilla::Abs;
@ -686,17 +720,28 @@ js::GenerateRandomSeed()
#elif defined(HAVE_ARC4RANDOM)
seed = (static_cast<uint64_t>(arc4random()) << 32) | arc4random();
#elif defined(XP_UNIX)
int fd = open("/dev/urandom", O_RDONLY);
if (fd >= 0) {
mozilla::Unused << read(fd, static_cast<void*>(&seed), sizeof(seed));
close(fd);
bool done = false;
# if defined(__linux__)
// Try the relatively new getrandom syscall first. It's the preferred way
// on Linux as /dev/urandom may not work inside chroots and is harder to
// sandbox (see bug 995069).
int ret = syscall(SYS_getrandom, &seed, sizeof(seed), GRND_NONBLOCK);
done = (ret == sizeof(seed));
# endif
if (!done) {
int fd = open("/dev/urandom", O_RDONLY);
if (fd >= 0) {
mozilla::Unused << read(fd, static_cast<void*>(&seed), sizeof(seed));
close(fd);
}
}
#else
# error "Platform needs to implement GenerateRandomSeed()"
#endif
// Also mix in PRMJ_Now() in case we couldn't read random bits from the OS.
return seed ^ PRMJ_Now();
uint64_t timestamp = PRMJ_Now();
return seed ^ timestamp ^ (timestamp << 32);
}
void

Просмотреть файл

@ -53,7 +53,7 @@
#include "vm/ProxyObject.h"
#include "vm/RegExpStaticsObject.h"
#include "vm/Shape.h"
#include "vm/TypedArrayCommon.h"
#include "vm/TypedArrayObject.h"
#include "jsatominlines.h"
#include "jsboolinlines.h"

Просмотреть файл

@ -23,7 +23,7 @@
#include "vm/NumberObject.h"
#include "vm/Probes.h"
#include "vm/StringObject.h"
#include "vm/TypedArrayCommon.h"
#include "vm/TypedArrayObject.h"
#include "jsatominlines.h"
#include "jscompartmentinlines.h"

Просмотреть файл

@ -34,6 +34,27 @@ OnBackgroundThread()
return false;
}
template <AllowedBackgroundThread Background>
void
CheckActiveThread<Background>::check() const
{
// When interrupting a thread on Windows, changes are made to the runtime
// and active thread's state from another thread while the active thread is
// suspended. We need a way to mark these accesses as being tantamount to
// accesses by the active thread. See bug 1323066.
#ifndef XP_WIN
if (OnBackgroundThread<Background>())
return;
JSContext* cx = TlsContext.get();
MOZ_ASSERT(cx == cx->runtime()->activeContext);
#endif // XP_WIN
}
template class CheckActiveThread<AllowedBackgroundThread::None>;
template class CheckActiveThread<AllowedBackgroundThread::GCTask>;
template class CheckActiveThread<AllowedBackgroundThread::IonCompile>;
template <AllowedBackgroundThread Background>
void
CheckZoneGroup<Background>::check() const

Просмотреть файл

@ -201,6 +201,28 @@ enum class AllowedBackgroundThread
GCTaskOrIonCompile
};
template <AllowedBackgroundThread Background>
class CheckActiveThread
{
public:
void check() const;
};
// Data which may only be accessed by the runtime's cooperatively scheduled
// active thread.
template <typename T>
using ActiveThreadData =
ProtectedDataNoCheckArgs<CheckActiveThread<AllowedBackgroundThread::None>, T>;
// Data which may only be accessed by the runtime's cooperatively scheduled
// active thread, or by various helper thread tasks.
template <typename T>
using ActiveThreadOrGCTaskData =
ProtectedDataNoCheckArgs<CheckActiveThread<AllowedBackgroundThread::GCTask>, T>;
template <typename T>
using ActiveThreadOrIonCompileData =
ProtectedDataNoCheckArgs<CheckActiveThread<AllowedBackgroundThread::IonCompile>, T>;
template <AllowedBackgroundThread Background>
class CheckZoneGroup
{
@ -223,19 +245,13 @@ using ZoneGroupData =
ProtectedDataZoneGroupArg<CheckZoneGroup<AllowedBackgroundThread::None>, T>;
// Data which may only be accessed by threads with exclusive access to the
// associated zone group, or by GC helper thread tasks.
// associated zone group, or by various helper thread tasks.
template <typename T>
using ZoneGroupOrGCTaskData =
ProtectedDataZoneGroupArg<CheckZoneGroup<AllowedBackgroundThread::GCTask>, T>;
// Data which may only be accessed by threads with exclusive access to the
// associated zone group, or by Ion compilation helper thread tasks.
template <typename T>
using ZoneGroupOrIonCompileData =
ProtectedDataZoneGroupArg<CheckZoneGroup<AllowedBackgroundThread::IonCompile>, T>;
// Data which may only be accessed by threads with exclusive access to the
// associated zone group, or by either GC helper or Ion compilation tasks.
template <typename T>
using ZoneGroupOrGCTaskOrIonCompileData =
ProtectedDataZoneGroupArg<CheckZoneGroup<AllowedBackgroundThread::GCTaskOrIonCompile>, T>;

Просмотреть файл

@ -1183,10 +1183,10 @@ void
js::GCParallelTask::runFromHelperThread(AutoLockHelperThreadState& locked)
{
JSContext cx(runtime(), JS::ContextOptions());
gc::AutoSetThreadIsPerformingGC performingGC;
{
AutoUnlockHelperThreadState parallelSection(locked);
gc::AutoSetThreadIsPerformingGC performingGC;
mozilla::TimeStamp timeStart = mozilla::TimeStamp::Now();
cx.heapState = JS::HeapState::MajorCollecting;
run();

Просмотреть файл

@ -14,7 +14,7 @@
#include "gc/Marking.h"
#include "js/Value.h"
#include "vm/Debugger.h"
#include "vm/TypedArrayCommon.h"
#include "vm/TypedArrayObject.h"
#include "jsobjinlines.h"

Просмотреть файл

@ -95,6 +95,7 @@ JSRuntime::JSRuntime(JSRuntime* parentRuntime)
#ifdef DEBUG
updateChildRuntimeCount(parentRuntime),
#endif
activeContext(nullptr),
profilerSampleBufferGen_(0),
profilerSampleBufferLapCount_(1),
telemetryCallback(nullptr),
@ -191,6 +192,8 @@ JSRuntime::init(JSContext* cx, uint32_t maxbytes, uint32_t maxNurseryBytes)
if (CanUseExtraThreads() && !EnsureHelperThreadsInitialized())
return false;
activeContext = cx;
singletonContext = cx;
defaultFreeOp_ = js_new<js::FreeOp>(this);

Просмотреть файл

@ -297,6 +297,11 @@ struct JSRuntime : public js::MallocProvider<JSRuntime>
AutoUpdateChildRuntimeCount updateChildRuntimeCount;
#endif
// The context for the thread which currently has exclusive access to most
// contents of the runtime. When execution on the runtime is cooperatively
// scheduled, this is the thread which is currently running.
mozilla::Atomic<JSContext*, mozilla::ReleaseAcquire> activeContext;
/*
* The profiler sampler generation after the latest sample.
*
@ -354,7 +359,7 @@ struct JSRuntime : public js::MallocProvider<JSRuntime>
}
/* Call this to accumulate telemetry data. */
js::UnprotectedData<JSAccumulateTelemetryDataCallback> telemetryCallback;
js::ActiveThreadData<JSAccumulateTelemetryDataCallback> telemetryCallback;
public:
// Accumulates data for Firefox telemetry. |id| is the ID of a JS_TELEMETRY_*
// histogram. |key| provides an additional key to identify the histogram.
@ -364,14 +369,14 @@ struct JSRuntime : public js::MallocProvider<JSRuntime>
void setTelemetryCallback(JSRuntime* rt, JSAccumulateTelemetryDataCallback callback);
public:
js::UnprotectedData<JSGetIncumbentGlobalCallback> getIncumbentGlobalCallback;
js::UnprotectedData<JSEnqueuePromiseJobCallback> enqueuePromiseJobCallback;
js::UnprotectedData<void*> enqueuePromiseJobCallbackData;
js::ActiveThreadData<JSGetIncumbentGlobalCallback> getIncumbentGlobalCallback;
js::ActiveThreadData<JSEnqueuePromiseJobCallback> enqueuePromiseJobCallback;
js::ActiveThreadData<void*> enqueuePromiseJobCallbackData;
js::UnprotectedData<JSPromiseRejectionTrackerCallback> promiseRejectionTrackerCallback;
js::UnprotectedData<void*> promiseRejectionTrackerCallbackData;
js::ActiveThreadData<JSPromiseRejectionTrackerCallback> promiseRejectionTrackerCallback;
js::ActiveThreadData<void*> promiseRejectionTrackerCallbackData;
js::UnprotectedData<JS::StartAsyncTaskCallback> startAsyncTaskCallback;
js::ActiveThreadData<JS::StartAsyncTaskCallback> startAsyncTaskCallback;
js::UnprotectedData<JS::FinishAsyncTaskCallback> finishAsyncTaskCallback;
js::ExclusiveData<js::PromiseTaskPtrVector> promiseTasksToDestroy;
@ -388,35 +393,35 @@ struct JSRuntime : public js::MallocProvider<JSRuntime>
* Allow relazifying functions in compartments that are active. This is
* only used by the relazifyFunctions() testing function.
*/
js::UnprotectedData<bool> allowRelazificationForTesting;
js::ActiveThreadData<bool> allowRelazificationForTesting;
/* Compartment destroy callback. */
js::UnprotectedData<JSDestroyCompartmentCallback> destroyCompartmentCallback;
js::ActiveThreadData<JSDestroyCompartmentCallback> destroyCompartmentCallback;
/* Compartment memory reporting callback. */
js::UnprotectedData<JSSizeOfIncludingThisCompartmentCallback> sizeOfIncludingThisCompartmentCallback;
js::ActiveThreadData<JSSizeOfIncludingThisCompartmentCallback> sizeOfIncludingThisCompartmentCallback;
/* Zone destroy callback. */
js::UnprotectedData<JSZoneCallback> destroyZoneCallback;
js::ActiveThreadData<JSZoneCallback> destroyZoneCallback;
/* Zone sweep callback. */
js::UnprotectedData<JSZoneCallback> sweepZoneCallback;
js::ActiveThreadData<JSZoneCallback> sweepZoneCallback;
/* Call this to get the name of a compartment. */
js::UnprotectedData<JSCompartmentNameCallback> compartmentNameCallback;
js::ActiveThreadData<JSCompartmentNameCallback> compartmentNameCallback;
/* Callback for doing memory reporting on external strings. */
js::UnprotectedData<JSExternalStringSizeofCallback> externalStringSizeofCallback;
js::ActiveThreadData<JSExternalStringSizeofCallback> externalStringSizeofCallback;
js::UnprotectedData<mozilla::UniquePtr<js::SourceHook>> sourceHook;
js::ActiveThreadData<mozilla::UniquePtr<js::SourceHook>> sourceHook;
js::UnprotectedData<const JSSecurityCallbacks*> securityCallbacks;
js::UnprotectedData<const js::DOMCallbacks*> DOMcallbacks;
js::UnprotectedData<JSDestroyPrincipalsOp> destroyPrincipals;
js::UnprotectedData<JSReadPrincipalsOp> readPrincipals;
js::ActiveThreadData<const JSSecurityCallbacks*> securityCallbacks;
js::ActiveThreadData<const js::DOMCallbacks*> DOMcallbacks;
js::ActiveThreadData<JSDestroyPrincipalsOp> destroyPrincipals;
js::ActiveThreadData<JSReadPrincipalsOp> readPrincipals;
/* Optional warning reporter. */
js::UnprotectedData<JS::WarningReporter> warningReporter;
js::ActiveThreadData<JS::WarningReporter> warningReporter;
private:
/* Gecko profiling metadata */
@ -425,7 +430,7 @@ struct JSRuntime : public js::MallocProvider<JSRuntime>
js::GeckoProfiler& geckoProfiler() { return geckoProfiler_.ref(); }
// Heap GC roots for PersistentRooted pointers.
js::UnprotectedData<mozilla::EnumeratedArray<JS::RootKind, JS::RootKind::Limit,
js::ActiveThreadData<mozilla::EnumeratedArray<JS::RootKind, JS::RootKind::Limit,
mozilla::LinkedList<JS::PersistentRooted<void*>>>> heapRoots;
void tracePersistentRoots(JSTracer* trc);
@ -445,15 +450,15 @@ struct JSRuntime : public js::MallocProvider<JSRuntime>
void setTrustedPrincipals(const JSPrincipals* p) { trustedPrincipals_ = p; }
const JSPrincipals* trustedPrincipals() const { return trustedPrincipals_; }
js::UnprotectedData<const JSWrapObjectCallbacks*> wrapObjectCallbacks;
js::UnprotectedData<js::PreserveWrapperCallback> preserveWrapperCallback;
js::ActiveThreadData<const JSWrapObjectCallbacks*> wrapObjectCallbacks;
js::ActiveThreadData<js::PreserveWrapperCallback> preserveWrapperCallback;
js::UnprotectedData<js::ScriptEnvironmentPreparer*> scriptEnvironmentPreparer;
js::ActiveThreadData<js::ScriptEnvironmentPreparer*> scriptEnvironmentPreparer;
js::UnprotectedData<js::CTypesActivityCallback> ctypesActivityCallback;
js::ActiveThreadData<js::CTypesActivityCallback> ctypesActivityCallback;
private:
js::UnprotectedData<const js::Class*> windowProxyClass_;
js::WriteOnceData<const js::Class*> windowProxyClass_;
public:
const js::Class* maybeWindowProxyClass() const {
@ -468,7 +473,7 @@ struct JSRuntime : public js::MallocProvider<JSRuntime>
* Head of circular list of all enabled Debuggers that have
* onNewGlobalObject handler methods established.
*/
js::UnprotectedData<JSCList> onNewGlobalObjectWatchers_;
js::ActiveThreadData<JSCList> onNewGlobalObjectWatchers_;
public:
JSCList& onNewGlobalObjectWatchers() { return onNewGlobalObjectWatchers_.ref(); }
@ -508,16 +513,16 @@ struct JSRuntime : public js::MallocProvider<JSRuntime>
// How many compartments there are across all zones. This number includes
// off main thread context compartments, so it isn't necessarily equal to the
// number of compartments visited by CompartmentsIter.
js::UnprotectedData<size_t> numCompartments;
js::ActiveThreadData<size_t> numCompartments;
/* Locale-specific callbacks for string conversion. */
js::UnprotectedData<const JSLocaleCallbacks*> localeCallbacks;
js::ActiveThreadData<const JSLocaleCallbacks*> localeCallbacks;
/* Default locale for Internationalization API */
js::UnprotectedData<char*> defaultLocale;
js::ActiveThreadData<char*> defaultLocale;
/* Default JSVersion. */
js::UnprotectedData<JSVersion> defaultVersion_;
js::ActiveThreadData<JSVersion> defaultVersion_;
private:
/* Code coverage output. */
@ -780,7 +785,7 @@ struct JSRuntime : public js::MallocProvider<JSRuntime>
js::WriteOnceData<js::WellKnownSymbols*> wellKnownSymbols;
/* Shared Intl data for this runtime. */
js::UnprotectedData<js::SharedIntlData> sharedIntlData;
js::ActiveThreadData<js::SharedIntlData> sharedIntlData;
void traceSharedIntlData(JSTracer* trc);
@ -851,7 +856,7 @@ struct JSRuntime : public js::MallocProvider<JSRuntime>
mozilla::Atomic<bool> offthreadIonCompilationEnabled_;
mozilla::Atomic<bool> parallelParsingEnabled_;
js::UnprotectedData<bool> autoWritableJitCodeActive_;
js::ActiveThreadData<bool> autoWritableJitCodeActive_;
public:
@ -876,12 +881,12 @@ struct JSRuntime : public js::MallocProvider<JSRuntime>
}
/* See comment for JS::SetLargeAllocationFailureCallback in jsapi.h. */
js::UnprotectedData<JS::LargeAllocationFailureCallback> largeAllocationFailureCallback;
js::UnprotectedData<void*> largeAllocationFailureCallbackData;
js::ActiveThreadData<JS::LargeAllocationFailureCallback> largeAllocationFailureCallback;
js::ActiveThreadData<void*> largeAllocationFailureCallbackData;
/* See comment for JS::SetOutOfMemoryCallback in jsapi.h. */
js::UnprotectedData<JS::OutOfMemoryCallback> oomCallback;
js::UnprotectedData<void*> oomCallbackData;
js::ActiveThreadData<JS::OutOfMemoryCallback> oomCallback;
js::ActiveThreadData<void*> oomCallbackData;
/*
* These variations of malloc/calloc/realloc will call the
@ -919,13 +924,13 @@ struct JSRuntime : public js::MallocProvider<JSRuntime>
* Debugger.Memory functions like takeCensus use this embedding-provided
* function to assess the size of malloc'd blocks of memory.
*/
js::UnprotectedData<mozilla::MallocSizeOf> debuggerMallocSizeOf;
js::ActiveThreadData<mozilla::MallocSizeOf> debuggerMallocSizeOf;
/* Last time at which an animation was played for this runtime. */
mozilla::Atomic<int64_t> lastAnimationTime;
private:
js::UnprotectedData<js::PerformanceMonitoring> performanceMonitoring_;
js::ActiveThreadData<js::PerformanceMonitoring> performanceMonitoring_;
public:
js::PerformanceMonitoring& performanceMonitoring() { return performanceMonitoring_.ref(); }

Просмотреть файл

@ -45,7 +45,7 @@
#include "vm/RegExpObject.h"
#include "vm/String.h"
#include "vm/StringBuffer.h"
#include "vm/TypedArrayCommon.h"
#include "vm/TypedArrayObject.h"
#include "vm/WrapperObject.h"
#include "jsatominlines.h"

Просмотреть файл

@ -15,7 +15,7 @@
#include "gc/Allocator.h"
#include "vm/Interpreter.h"
#include "vm/TypedArrayCommon.h"
#include "vm/TypedArrayObject.h"
#include "jsatominlines.h"
#include "jscntxtinlines.h"

Просмотреть файл

@ -22,8 +22,8 @@
# include <valgrind/memcheck.h>
#endif
#include "jit/AtomicOperations.h"
#include "vm/SharedMem.h"
#include "vm/TypedArrayCommon.h"
#include "wasm/AsmJS.h"
#include "wasm/WasmTypes.h"

Просмотреть файл

@ -4,11 +4,13 @@
* 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/. */
#ifndef vm_TypedArrayCommon_h
#define vm_TypedArrayCommon_h
#ifndef vm_TypedArrayObject_inl_h
#define vm_TypedArrayObject_inl_h
/* Utilities and common inline code for TypedArray */
#include "vm/TypedArrayObject.h"
#include "mozilla/Assertions.h"
#include "mozilla/FloatingPoint.h"
#include "mozilla/PodOperations.h"
@ -23,7 +25,6 @@
#include "js/Value.h"
#include "vm/NativeObject.h"
#include "vm/TypedArrayObject.h"
namespace js {
@ -258,12 +259,9 @@ class UnsharedOps
}
};
template<class SpecificArray, typename Ops>
template<typename T, typename Ops>
class ElementSpecific
{
typedef typename SpecificArray::ElementType T;
typedef typename SpecificArray::SomeTypedArray SomeTypedArray;
public:
/*
* Copy |source|'s elements into |target|, starting at |target[offset]|.
@ -272,28 +270,23 @@ class ElementSpecific
*/
static bool
setFromTypedArray(JSContext* cx,
Handle<SomeTypedArray*> target, HandleObject source,
Handle<TypedArrayObject*> target, Handle<TypedArrayObject*> source,
uint32_t offset)
{
MOZ_ASSERT(SpecificArray::ArrayTypeID() == target->type(),
MOZ_ASSERT(TypeIDOfType<T>::id == target->type(),
"calling wrong setFromTypedArray specialization");
MOZ_ASSERT(offset <= target->length());
MOZ_ASSERT(source->as<TypedArrayObject>().length() <= target->length() - offset);
MOZ_ASSERT(source->length() <= target->length() - offset);
if (source->is<SomeTypedArray>()) {
Rooted<SomeTypedArray*> src(cx, source.as<SomeTypedArray>());
if (SomeTypedArray::sameBuffer(target, src))
return setFromOverlappingTypedArray(cx, target, src, offset);
}
if (TypedArrayObject::sameBuffer(target, source))
return setFromOverlappingTypedArray(cx, target, source, offset);
SharedMem<T*> dest =
target->template as<TypedArrayObject>().viewDataEither().template cast<T*>() + offset;
uint32_t count = source->as<TypedArrayObject>().length();
SharedMem<T*> dest = target->viewDataEither().template cast<T*>() + offset;
uint32_t count = source->length();
if (source->as<TypedArrayObject>().type() == target->type()) {
Ops::podCopy(dest, source->as<TypedArrayObject>().viewDataEither().template cast<T*>(),
count);
if (source->type() == target->type()) {
Ops::podCopy(dest, source->viewDataEither().template cast<T*>(), count);
return true;
}
@ -304,8 +297,8 @@ class ElementSpecific
# define JS_VOLATILE_ARM
#endif
SharedMem<void*> data = Ops::extract(source.as<TypedArrayObject>());
switch (source->as<TypedArrayObject>().type()) {
SharedMem<void*> data = Ops::extract(source);
switch (source->type()) {
case Scalar::Int8: {
SharedMem<JS_VOLATILE_ARM int8_t*> src = data.cast<JS_VOLATILE_ARM int8_t*>();
for (uint32_t i = 0; i < count; ++i)
@ -370,10 +363,10 @@ class ElementSpecific
* typed array.
*/
static bool
setFromNonTypedArray(JSContext* cx, Handle<SomeTypedArray*> target, HandleObject source,
setFromNonTypedArray(JSContext* cx, Handle<TypedArrayObject*> target, HandleObject source,
uint32_t len, uint32_t offset = 0)
{
MOZ_ASSERT(target->type() == SpecificArray::ArrayTypeID(),
MOZ_ASSERT(target->type() == TypeIDOfType<T>::id,
"target type and NativeType must match");
MOZ_ASSERT(!source->is<TypedArrayObject>(),
"use setFromTypedArray instead of this method");
@ -384,8 +377,7 @@ class ElementSpecific
// the first potentially side-effectful lookup or conversion.
uint32_t bound = Min(source->as<NativeObject>().getDenseInitializedLength(), len);
SharedMem<T*> dest =
target->template as<TypedArrayObject>().viewDataEither().template cast<T*>() + offset;
SharedMem<T*> dest = target->viewDataEither().template cast<T*>() + offset;
MOZ_ASSERT(!canConvertInfallibly(MagicValue(JS_ELEMENTS_HOLE)),
"the following loop must abort on holes");
@ -415,9 +407,7 @@ class ElementSpecific
break;
// Compute every iteration in case getElement/valueToNative is wacky.
SharedMem<T*> dest =
target->template as<TypedArrayObject>().viewDataEither().template cast<T*>() +
offset + i;
SharedMem<T*> dest = target->viewDataEither().template cast<T*>() + offset + i;
Ops::store(dest, n);
}
@ -428,10 +418,10 @@ class ElementSpecific
* Copy |source| into the typed array |target|.
*/
static bool
initFromIterablePackedArray(JSContext* cx, Handle<SomeTypedArray*> target,
initFromIterablePackedArray(JSContext* cx, Handle<TypedArrayObject*> target,
HandleArrayObject source)
{
MOZ_ASSERT(target->type() == SpecificArray::ArrayTypeID(),
MOZ_ASSERT(target->type() == TypeIDOfType<T>::id,
"target type and NativeType must match");
MOZ_ASSERT(IsPackedArray(source), "source array must be packed");
MOZ_ASSERT(source->getDenseInitializedLength() <= target->length());
@ -442,8 +432,7 @@ class ElementSpecific
// Attempt fast-path infallible conversion of dense elements up to the
// first potentially side-effectful conversion.
SharedMem<T*> dest =
target->template as<TypedArrayObject>().viewDataEither().template cast<T*>();
SharedMem<T*> dest = target->viewDataEither().template cast<T*>();
const Value* srcValues = source->getDenseElements();
for (; i < len; i++) {
@ -474,8 +463,7 @@ class ElementSpecific
MOZ_ASSERT(i < target->length());
// Compute every iteration in case GC moves the data.
SharedMem<T*> newDest =
target->template as<TypedArrayObject>().viewDataEither().template cast<T*>();
SharedMem<T*> newDest = target->viewDataEither().template cast<T*>();
Ops::store(newDest + i, n);
}
@ -485,26 +473,24 @@ class ElementSpecific
private:
static bool
setFromOverlappingTypedArray(JSContext* cx,
Handle<SomeTypedArray*> target,
Handle<SomeTypedArray*> source,
Handle<TypedArrayObject*> target,
Handle<TypedArrayObject*> source,
uint32_t offset)
{
MOZ_ASSERT(SpecificArray::ArrayTypeID() == target->type(),
MOZ_ASSERT(TypeIDOfType<T>::id == target->type(),
"calling wrong setFromTypedArray specialization");
MOZ_ASSERT(SomeTypedArray::sameBuffer(target, source),
MOZ_ASSERT(TypedArrayObject::sameBuffer(target, source),
"the provided arrays don't actually overlap, so it's "
"undesirable to use this method");
MOZ_ASSERT(offset <= target->length());
MOZ_ASSERT(source->length() <= target->length() - offset);
SharedMem<T*> dest =
target->template as<TypedArrayObject>().viewDataEither().template cast<T*>() + offset;
SharedMem<T*> dest = target->viewDataEither().template cast<T*>() + offset;
uint32_t len = source->length();
if (source->type() == target->type()) {
SharedMem<T*> src =
source->template as<TypedArrayObject>().viewDataEither().template cast<T*>();
SharedMem<T*> src = source->viewDataEither().template cast<T*>();
Ops::podMove(dest, src, len);
return true;
}
@ -515,7 +501,7 @@ class ElementSpecific
if (!data)
return false;
Ops::memcpy(SharedMem<void*>::unshared(data),
source->template as<TypedArrayObject>().viewDataEither(),
source->viewDataEither(),
sourceByteLen);
switch (source->type()) {
@ -633,7 +619,7 @@ class ElementSpecific
}
if (MOZ_UNLIKELY(mozilla::IsNaN(d)))
return T(0);
if (SpecificArray::ArrayTypeID() == Scalar::Uint8Clamped)
if (TypeIDOfType<T>::id == Scalar::Uint8Clamped)
return T(d);
if (TypeIsUnsigned<T>())
return T(JS::ToUint32(d));
@ -641,247 +627,6 @@ class ElementSpecific
}
};
template<typename SomeTypedArray>
class TypedArrayMethods
{
static_assert(mozilla::IsSame<SomeTypedArray, TypedArrayObject>::value,
"methods must be shared/unshared-specific, not "
"element-type-specific");
typedef typename SomeTypedArray::BufferType BufferType;
typedef typename SomeTypedArray::template OfType<int8_t>::Type Int8ArrayType;
typedef typename SomeTypedArray::template OfType<uint8_t>::Type Uint8ArrayType;
typedef typename SomeTypedArray::template OfType<int16_t>::Type Int16ArrayType;
typedef typename SomeTypedArray::template OfType<uint16_t>::Type Uint16ArrayType;
typedef typename SomeTypedArray::template OfType<int32_t>::Type Int32ArrayType;
typedef typename SomeTypedArray::template OfType<uint32_t>::Type Uint32ArrayType;
typedef typename SomeTypedArray::template OfType<float>::Type Float32ArrayType;
typedef typename SomeTypedArray::template OfType<double>::Type Float64ArrayType;
typedef typename SomeTypedArray::template OfType<uint8_clamped>::Type Uint8ClampedArrayType;
public:
/* set(array[, offset]) */
static bool
set(JSContext* cx, const CallArgs& args)
{
MOZ_ASSERT(SomeTypedArray::is(args.thisv()));
Rooted<SomeTypedArray*> target(cx, &args.thisv().toObject().as<SomeTypedArray>());
// The first argument must be either a typed array or arraylike.
if (args.length() == 0 || !args[0].isObject()) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
return false;
}
int32_t offset = 0;
if (args.length() > 1) {
if (!ToInt32(cx, args[1], &offset))
return false;
if (offset < 0 || uint32_t(offset) > target->length()) {
// the given offset is bogus
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_INDEX);
return false;
}
}
RootedObject arg0(cx, &args[0].toObject());
if (arg0->is<TypedArrayObject>()) {
if (arg0->as<TypedArrayObject>().length() > target->length() - offset) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_ARRAY_LENGTH);
return false;
}
if (!setFromTypedArray(cx, target, arg0, offset))
return false;
} else {
uint32_t len;
if (!GetLengthProperty(cx, arg0, &len))
return false;
if (uint32_t(offset) > target->length() || len > target->length() - offset) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_ARRAY_LENGTH);
return false;
}
if (!setFromNonTypedArray(cx, target, arg0, len, offset))
return false;
}
args.rval().setUndefined();
return true;
}
static bool
setFromTypedArray(JSContext* cx, Handle<SomeTypedArray*> target, HandleObject source,
uint32_t offset = 0)
{
MOZ_ASSERT(source->is<TypedArrayObject>(), "use setFromNonTypedArray");
bool isShared = target->isSharedMemory() || source->as<TypedArrayObject>().isSharedMemory();
switch (target->type()) {
case Scalar::Int8:
if (isShared)
return ElementSpecific<Int8ArrayType, SharedOps>::setFromTypedArray(cx, target, source, offset);
return ElementSpecific<Int8ArrayType, UnsharedOps>::setFromTypedArray(cx, target, source, offset);
case Scalar::Uint8:
if (isShared)
return ElementSpecific<Uint8ArrayType, SharedOps>::setFromTypedArray(cx, target, source, offset);
return ElementSpecific<Uint8ArrayType, UnsharedOps>::setFromTypedArray(cx, target, source, offset);
case Scalar::Int16:
if (isShared)
return ElementSpecific<Int16ArrayType, SharedOps>::setFromTypedArray(cx, target, source, offset);
return ElementSpecific<Int16ArrayType, UnsharedOps>::setFromTypedArray(cx, target, source, offset);
case Scalar::Uint16:
if (isShared)
return ElementSpecific<Uint16ArrayType, SharedOps>::setFromTypedArray(cx, target, source, offset);
return ElementSpecific<Uint16ArrayType, UnsharedOps>::setFromTypedArray(cx, target, source, offset);
case Scalar::Int32:
if (isShared)
return ElementSpecific<Int32ArrayType, SharedOps>::setFromTypedArray(cx, target, source, offset);
return ElementSpecific<Int32ArrayType, UnsharedOps>::setFromTypedArray(cx, target, source, offset);
case Scalar::Uint32:
if (isShared)
return ElementSpecific<Uint32ArrayType, SharedOps>::setFromTypedArray(cx, target, source, offset);
return ElementSpecific<Uint32ArrayType, UnsharedOps>::setFromTypedArray(cx, target, source, offset);
case Scalar::Float32:
if (isShared)
return ElementSpecific<Float32ArrayType, SharedOps>::setFromTypedArray(cx, target, source, offset);
return ElementSpecific<Float32ArrayType, UnsharedOps>::setFromTypedArray(cx, target, source, offset);
case Scalar::Float64:
if (isShared)
return ElementSpecific<Float64ArrayType, SharedOps>::setFromTypedArray(cx, target, source, offset);
return ElementSpecific<Float64ArrayType, UnsharedOps>::setFromTypedArray(cx, target, source, offset);
case Scalar::Uint8Clamped:
if (isShared)
return ElementSpecific<Uint8ClampedArrayType, SharedOps>::setFromTypedArray(cx, target, source, offset);
return ElementSpecific<Uint8ClampedArrayType, UnsharedOps>::setFromTypedArray(cx, target, source, offset);
case Scalar::Int64:
case Scalar::Float32x4:
case Scalar::Int8x16:
case Scalar::Int16x8:
case Scalar::Int32x4:
case Scalar::MaxTypedArrayViewType:
break;
}
MOZ_CRASH("nonsense target element type");
}
static bool
setFromNonTypedArray(JSContext* cx, Handle<SomeTypedArray*> target, HandleObject source,
uint32_t len, uint32_t offset = 0)
{
MOZ_ASSERT(!source->is<TypedArrayObject>(), "use setFromTypedArray");
bool isShared = target->isSharedMemory();
switch (target->type()) {
case Scalar::Int8:
if (isShared)
return ElementSpecific<Int8ArrayType, SharedOps>::setFromNonTypedArray(cx, target, source, len, offset);
return ElementSpecific<Int8ArrayType, UnsharedOps>::setFromNonTypedArray(cx, target, source, len, offset);
case Scalar::Uint8:
if (isShared)
return ElementSpecific<Uint8ArrayType, SharedOps>::setFromNonTypedArray(cx, target, source, len, offset);
return ElementSpecific<Uint8ArrayType, UnsharedOps>::setFromNonTypedArray(cx, target, source, len, offset);
case Scalar::Int16:
if (isShared)
return ElementSpecific<Int16ArrayType, SharedOps>::setFromNonTypedArray(cx, target, source, len, offset);
return ElementSpecific<Int16ArrayType, UnsharedOps>::setFromNonTypedArray(cx, target, source, len, offset);
case Scalar::Uint16:
if (isShared)
return ElementSpecific<Uint16ArrayType, SharedOps>::setFromNonTypedArray(cx, target, source, len, offset);
return ElementSpecific<Uint16ArrayType, UnsharedOps>::setFromNonTypedArray(cx, target, source, len, offset);
case Scalar::Int32:
if (isShared)
return ElementSpecific<Int32ArrayType, SharedOps>::setFromNonTypedArray(cx, target, source, len, offset);
return ElementSpecific<Int32ArrayType, UnsharedOps>::setFromNonTypedArray(cx, target, source, len, offset);
case Scalar::Uint32:
if (isShared)
return ElementSpecific<Uint32ArrayType, SharedOps>::setFromNonTypedArray(cx, target, source, len, offset);
return ElementSpecific<Uint32ArrayType, UnsharedOps>::setFromNonTypedArray(cx, target, source, len, offset);
case Scalar::Float32:
if (isShared)
return ElementSpecific<Float32ArrayType, SharedOps>::setFromNonTypedArray(cx, target, source, len, offset);
return ElementSpecific<Float32ArrayType, UnsharedOps>::setFromNonTypedArray(cx, target, source, len, offset);
case Scalar::Float64:
if (isShared)
return ElementSpecific<Float64ArrayType, SharedOps>::setFromNonTypedArray(cx, target, source, len, offset);
return ElementSpecific<Float64ArrayType, UnsharedOps>::setFromNonTypedArray(cx, target, source, len, offset);
case Scalar::Uint8Clamped:
if (isShared)
return ElementSpecific<Uint8ClampedArrayType, SharedOps>::setFromNonTypedArray(cx, target, source, len, offset);
return ElementSpecific<Uint8ClampedArrayType, UnsharedOps>::setFromNonTypedArray(cx, target, source, len, offset);
case Scalar::Int64:
case Scalar::Float32x4:
case Scalar::Int8x16:
case Scalar::Int16x8:
case Scalar::Int32x4:
case Scalar::MaxTypedArrayViewType:
break;
}
MOZ_CRASH("bad target array type");
}
static bool
initFromIterablePackedArray(JSContext* cx, Handle<SomeTypedArray*> target,
HandleArrayObject source)
{
bool isShared = target->isSharedMemory();
switch (target->type()) {
case Scalar::Int8:
if (isShared)
return ElementSpecific<Int8ArrayType, SharedOps>::initFromIterablePackedArray(cx, target, source);
return ElementSpecific<Int8ArrayType, UnsharedOps>::initFromIterablePackedArray(cx, target, source);
case Scalar::Uint8:
if (isShared)
return ElementSpecific<Uint8ArrayType, SharedOps>::initFromIterablePackedArray(cx, target, source);
return ElementSpecific<Uint8ArrayType, UnsharedOps>::initFromIterablePackedArray(cx, target, source);
case Scalar::Int16:
if (isShared)
return ElementSpecific<Int16ArrayType, SharedOps>::initFromIterablePackedArray(cx, target, source);
return ElementSpecific<Int16ArrayType, UnsharedOps>::initFromIterablePackedArray(cx, target, source);
case Scalar::Uint16:
if (isShared)
return ElementSpecific<Uint16ArrayType, SharedOps>::initFromIterablePackedArray(cx, target, source);
return ElementSpecific<Uint16ArrayType, UnsharedOps>::initFromIterablePackedArray(cx, target, source);
case Scalar::Int32:
if (isShared)
return ElementSpecific<Int32ArrayType, SharedOps>::initFromIterablePackedArray(cx, target, source);
return ElementSpecific<Int32ArrayType, UnsharedOps>::initFromIterablePackedArray(cx, target, source);
case Scalar::Uint32:
if (isShared)
return ElementSpecific<Uint32ArrayType, SharedOps>::initFromIterablePackedArray(cx, target, source);
return ElementSpecific<Uint32ArrayType, UnsharedOps>::initFromIterablePackedArray(cx, target, source);
case Scalar::Float32:
if (isShared)
return ElementSpecific<Float32ArrayType, SharedOps>::initFromIterablePackedArray(cx, target, source);
return ElementSpecific<Float32ArrayType, UnsharedOps>::initFromIterablePackedArray(cx, target, source);
case Scalar::Float64:
if (isShared)
return ElementSpecific<Float64ArrayType, SharedOps>::initFromIterablePackedArray(cx, target, source);
return ElementSpecific<Float64ArrayType, UnsharedOps>::initFromIterablePackedArray(cx, target, source);
case Scalar::Uint8Clamped:
if (isShared)
return ElementSpecific<Uint8ClampedArrayType, SharedOps>::initFromIterablePackedArray(cx, target, source);
return ElementSpecific<Uint8ClampedArrayType, UnsharedOps>::initFromIterablePackedArray(cx, target, source);
case Scalar::Int64:
case Scalar::Float32x4:
case Scalar::Int8x16:
case Scalar::Int16x8:
case Scalar::Int32x4:
case Scalar::MaxTypedArrayViewType:
break;
}
MOZ_CRASH("bad target array type");
}
};
} // namespace js
#endif // vm_TypedArrayCommon_h
#endif // vm_TypedArrayObject_inl_h

Просмотреть файл

@ -4,6 +4,7 @@
* 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/. */
#include "vm/TypedArrayObject-inl.h"
#include "vm/TypedArrayObject.h"
#include "mozilla/Alignment.h"
@ -41,7 +42,6 @@
#include "vm/PIC.h"
#include "vm/SelfHosting.h"
#include "vm/SharedMem.h"
#include "vm/TypedArrayCommon.h"
#include "vm/WrapperObject.h"
#include "jsatominlines.h"
@ -346,8 +346,6 @@ class TypedArrayObjectTemplate : public TypedArrayObject
friend class TypedArrayObject;
public:
typedef NativeType ElementType;
static constexpr Scalar::Type ArrayTypeID() { return TypeIDOfType<NativeType>::id; }
static bool ArrayTypeIsUnsigned() { return TypeIsUnsigned<NativeType>(); }
static bool ArrayTypeIsFloatingPoint() { return TypeIsFloatingPoint<NativeType>(); }
@ -1028,12 +1026,6 @@ JS_FOR_EACH_TYPED_ARRAY(CREATE_TYPED_ARRAY)
}
}
template<typename T>
struct TypedArrayObject::OfType
{
typedef TypedArrayObjectTemplate<T> Type;
};
// ES 2016 draft Mar 25, 2016 24.1.1.1.
// byteLength = count * unit
template<typename T>
@ -1280,8 +1272,14 @@ TypedArrayObjectTemplate<T>::fromTypedArray(JSContext* cx, HandleObject other, b
return nullptr;
// Step 18.d-g or 24.1.1.4 step 11.
if (!TypedArrayMethods<TypedArrayObject>::setFromTypedArray(cx, obj, srcArray))
return nullptr;
MOZ_ASSERT(!obj->isSharedMemory());
if (isShared) {
if (!ElementSpecific<T, SharedOps>::setFromTypedArray(cx, obj, srcArray, 0))
return nullptr;
} else {
if (!ElementSpecific<T, UnsharedOps>::setFromTypedArray(cx, obj, srcArray, 0))
return nullptr;
}
// Step 23.
return obj;
@ -1337,7 +1335,8 @@ TypedArrayObjectTemplate<T>::fromObject(JSContext* cx, HandleObject other, Handl
return nullptr;
// Steps 6.d-e.
if (!TypedArrayMethods<TypedArrayObject>::initFromIterablePackedArray(cx, obj, array))
MOZ_ASSERT(!obj->isSharedMemory());
if (!ElementSpecific<T, UnsharedOps>::initFromIterablePackedArray(cx, obj, array))
return nullptr;
// Step 6.f (The assertion isn't applicable for the fast path).
@ -1403,7 +1402,8 @@ TypedArrayObjectTemplate<T>::fromObject(JSContext* cx, HandleObject other, Handl
return nullptr;
// Steps 11-12.
if (!TypedArrayMethods<TypedArrayObject>::setFromNonTypedArray(cx, obj, arrayLike, len))
MOZ_ASSERT(!obj->isSharedMemory());
if (!ElementSpecific<T, UnsharedOps>::setFromNonTypedArray(cx, obj, arrayLike, len))
return nullptr;
// Step 13.
@ -1455,7 +1455,7 @@ JS_FOR_EACH_TYPED_ARRAY(CHECK_TYPED_ARRAY_CONSTRUCTOR)
static bool
TypedArray_lengthGetter(JSContext* cx, unsigned argc, Value* vp)
{
return TypedArrayObject::Getter<TypedArrayObject::lengthValue>(cx, argc, vp); \
return TypedArrayObject::Getter<TypedArrayObject::lengthValue>(cx, argc, vp);
}
static bool
@ -1498,12 +1498,105 @@ TypedArrayObject::protoAccessors[] = {
JS_PS_END
};
template<typename T>
static inline bool
SetFromTypedArray(JSContext* cx, Handle<TypedArrayObject*> target,
Handle<TypedArrayObject*> source, uint32_t offset)
{
if (target->isSharedMemory() || source->isSharedMemory())
return ElementSpecific<T, SharedOps>::setFromTypedArray(cx, target, source, offset);
return ElementSpecific<T, UnsharedOps>::setFromTypedArray(cx, target, source, offset);
}
template<typename T>
static inline bool
SetFromNonTypedArray(JSContext* cx, Handle<TypedArrayObject*> target, HandleObject source,
uint32_t len, uint32_t offset)
{
MOZ_ASSERT(!source->is<TypedArrayObject>(), "use SetFromTypedArray");
if (target->isSharedMemory())
return ElementSpecific<T, SharedOps>::setFromNonTypedArray(cx, target, source, len, offset);
return ElementSpecific<T, UnsharedOps>::setFromNonTypedArray(cx, target, source, len, offset);
}
/* set(array[, offset]) */
/* static */ bool
TypedArrayObject::set_impl(JSContext* cx, const CallArgs& args)
{
MOZ_ASSERT(TypedArrayObject::is(args.thisv()));
Rooted<TypedArrayObject*> target(cx, &args.thisv().toObject().as<TypedArrayObject>());
// The first argument must be either a typed array or arraylike.
if (args.length() == 0 || !args[0].isObject()) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
return false;
}
int32_t offset = 0;
if (args.length() > 1) {
if (!ToInt32(cx, args[1], &offset))
return false;
if (offset < 0 || uint32_t(offset) > target->length()) {
// the given offset is bogus
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_INDEX);
return false;
}
}
RootedObject arg0(cx, &args[0].toObject());
if (arg0->is<TypedArrayObject>()) {
Handle<TypedArrayObject*> source = arg0.as<TypedArrayObject>();
if (source->length() > target->length() - offset) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_ARRAY_LENGTH);
return false;
}
switch (target->type()) {
#define SET_FROM_TYPED_ARRAY(T, N) \
case Scalar::N: \
if (!SetFromTypedArray<T>(cx, target, source, offset)) \
return false; \
break;
JS_FOR_EACH_TYPED_ARRAY(SET_FROM_TYPED_ARRAY)
#undef SET_FROM_TYPED_ARRAY
default:
MOZ_CRASH("Unsupported TypedArray type");
}
} else {
uint32_t len;
if (!GetLengthProperty(cx, arg0, &len))
return false;
if (uint32_t(offset) > target->length() || len > target->length() - offset) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_ARRAY_LENGTH);
return false;
}
switch (target->type()) {
#define SET_FROM_NON_TYPED_ARRAY(T, N) \
case Scalar::N: \
if (!SetFromNonTypedArray<T>(cx, target, arg0, len, offset)) \
return false; \
break;
JS_FOR_EACH_TYPED_ARRAY(SET_FROM_NON_TYPED_ARRAY)
#undef SET_FROM_NON_TYPED_ARRAY
default:
MOZ_CRASH("Unsupported TypedArray type");
}
}
args.rval().setUndefined();
return true;
}
/* static */ bool
TypedArrayObject::set(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
return CallNonGenericMethod<TypedArrayObject::is,
TypedArrayMethods<TypedArrayObject>::set>(cx, args);
return CallNonGenericMethod<TypedArrayObject::is, TypedArrayObject::set_impl>(cx, args);
}
/* static */ const JSFunctionSpec

Просмотреть файл

@ -12,6 +12,7 @@
#include "jsobj.h"
#include "gc/Barrier.h"
#include "gc/Zone.h"
#include "js/Class.h"
#include "vm/ArrayBufferObject.h"
#include "vm/SharedArrayObject.h"
@ -80,11 +81,6 @@ class TypedArrayObject : public NativeObject
static_assert(js::detail::TypedArrayLengthSlot == LENGTH_SLOT,
"bad inlined constant in jsfriendapi.h");
typedef TypedArrayObject SomeTypedArray;
typedef ArrayBufferObject BufferType;
template<typename T> struct OfType;
static bool sameBuffer(Handle<TypedArrayObject*> a, Handle<TypedArrayObject*> b) {
// Inline buffers.
if (!a->hasBuffer() || !b->hasBuffer())
@ -307,6 +303,9 @@ class TypedArrayObject : public NativeObject
static bool is(HandleValue v);
static bool set(JSContext* cx, unsigned argc, Value* vp);
private:
static bool set_impl(JSContext* cx, const CallArgs& args);
};
MOZ_MUST_USE bool TypedArray_bufferGetter(JSContext* cx, unsigned argc, Value* vp);

Просмотреть файл

@ -33,6 +33,7 @@
#include "builtin/SIMD.h"
#include "frontend/Parser.h"
#include "gc/Policy.h"
#include "jit/AtomicOperations.h"
#include "js/MemoryMetrics.h"
#include "vm/SelfHosting.h"
#include "vm/StringBuffer.h"

Просмотреть файл

@ -6411,6 +6411,32 @@ BaseCompiler::emitSelect()
break;
}
case ValType::I64: {
#ifdef JS_CODEGEN_X86
// There may be as many as four Int64 values in registers at a time: two
// for the latent branch operands, and two for the true/false values we
// normally pop before executing the branch. On x86 this is one value
// too many, so we need to generate more complicated code here, and for
// simplicity's sake we do so even if the branch operands are not Int64.
// However, the resulting control flow diamond is complicated since the
// arms of the diamond will have to stay synchronized with respect to
// their evaluation stack and regalloc state. To simplify further, we
// use a double branch and a temporary boolean value for now.
RegI32 tmp = needI32();
loadConstI32(tmp, 0);
emitBranchPerform(&b);
loadConstI32(tmp, 1);
masm.bind(&done);
Label trueValue;
RegI64 r0, r1;
pop2xI64(&r0, &r1);
masm.branch32(Assembler::Equal, tmp, Imm32(0), &trueValue);
moveI64(r1, r0);
masm.bind(&trueValue);
freeI32(tmp);
freeI64(r1);
pushI64(r0);
#else
RegI64 r0, r1;
pop2xI64(&r0, &r1);
emitBranchPerform(&b);
@ -6418,6 +6444,7 @@ BaseCompiler::emitSelect()
masm.bind(&done);
freeI64(r1);
pushI64(r0);
#endif
break;
}
case ValType::F32: {

Просмотреть файл

@ -1502,7 +1502,7 @@ FontFaceSet::CheckLoadingStarted()
mStatus = FontFaceSetLoadStatus::Loading;
(new AsyncEventDispatcher(this, NS_LITERAL_STRING("loading"),
false))->RunDOMEventWhenSafe();
false))->PostDOMEvent();
if (PrefEnabled()) {
if (mReady) {
@ -1658,7 +1658,7 @@ FontFaceSet::DispatchLoadingFinishedEvent(
}
RefPtr<FontFaceSetLoadEvent> event =
FontFaceSetLoadEvent::Constructor(this, aType, init);
(new AsyncEventDispatcher(this, event))->RunDOMEventWhenSafe();
(new AsyncEventDispatcher(this, event))->PostDOMEvent();
}
// nsIDOMEventListener

Просмотреть файл

@ -36,10 +36,9 @@ support-files =
[test_acid3_test46.html]
[test_addSheet.html]
skip-if = stylo # bug 1290224
support-files = additional_sheets_helper.html
[test_additional_sheets.html]
skip-if = stylo # bug 1290224
skip-if = stylo # bug 1337258
support-files = additional_sheets_helper.html
[test_align_justify_computed_values.html]
[test_align_shorthand_serialization.html]
@ -141,7 +140,6 @@ support-files = bug732209-css.sjs
[test_bug795520.html]
[test_bug798567.html]
[test_bug798843_pref.html]
skip-if = stylo # 1332969
[test_bug829816.html]
[test_bug874919.html]
support-files = file_bug829816.css
@ -184,7 +182,6 @@ skip-if = toolkit == 'android' #bug 536603
[test_descriptor_storage.html]
[test_descriptor_syntax_errors.html]
[test_dont_use_document_colors.html]
skip-if = stylo # bug 1332969
[test_dynamic_change_causing_reflow.html]
[test_exposed_prop_accessors.html]
[test_extra_inherit_initial.html]
@ -227,7 +224,6 @@ skip-if = android_version == '18' #debug-only failure; timed out #Android 4.3 aw
[test_media_queries_dynamic_xbl.html]
[test_media_query_list.html]
[test_moz_device_pixel_ratio.html]
skip-if = stylo # bug 1332969
[test_namespace_rule.html]
[test_of_type_selectors.xhtml]
[test_page_parser.html]
@ -237,7 +233,6 @@ skip-if = stylo # bug 1332969
[test_parse_url.html]
[test_parser_diagnostics_unprintables.html]
[test_pixel_lengths.html]
skip-if = stylo # bug 1332969
[test_pointer-events.html]
[test_position_float_display.html]
[test_position_sticky.html]
@ -320,5 +315,4 @@ skip-if = (toolkit == 'android' || stylo) # TIMED_OUT for android, timeout bug 1
[test_visited_reftests.html]
skip-if = (toolkit == 'android' || stylo) # TIMED_OUT for android, timeout bug 1328511 for stylo
[test_webkit_device_pixel_ratio.html]
skip-if = stylo # bug 1332969
[test_webkit_flex_display.html]

Просмотреть файл

@ -1124,14 +1124,18 @@ function runTest() {
var p = Promise.resolve();
sources.forEach(function({ win, doc, what}, i) {
p = p.then(function() {
return setTimeoutZero(); // wait for any previous events to be dispatched
}).then(function() {
var events = [], face, face2;
doc.fonts.onloadingdone = function(e) {
events.push(e);
};
doc.fonts.onloadingerror = function(e) {
events.push(e);
};
var awaitEvents = new Promise(function(aResolve, aReject) {
doc.fonts.onloadingdone = doc.fonts.onloadingerror = function(e) {
events.push(e);
if (events.length == 2) {
aResolve();
}
};
});
is(doc.fonts.status, "loaded", "document.fonts.status should have status \"loaded\" (TEST 37) (" + what + ")");
@ -1151,6 +1155,8 @@ function runTest() {
is(doc.fonts.status, "loading", "document.fonts.status should have status \"loading\" after second font added (TEST 37) (" + what + ")");
return doc.fonts.ready;
}).then(function() {
return awaitEvents;
}).then(function() {
is(doc.fonts.status, "loaded", "document.fonts.status should have status \"loaded\" after second font loaded (TEST 37) (" + what + ")");
is(face2.status, "loaded", "second FontFace should have status \"loaded\" (TEST 37) (" + what + ")");
@ -1182,14 +1188,18 @@ function runTest() {
var p = Promise.resolve();
sources.forEach(function({ win, doc, what }) {
p = p.then(function() {
return setTimeoutZero(); // wait for any previous events to be dispatched
}).then(function() {
var events = [], face, face2;
doc.fonts.onloadingdone = function(e) {
events.push(e);
};
doc.fonts.onloadingerror = function(e) {
events.push(e);
};
var awaitEvents = new Promise(function(aResolve, aReject) {
doc.fonts.onloadingdone = doc.fonts.onloadingerror = function(e) {
events.push(e);
if (events.length == 4) {
aResolve();
}
};
});
is(doc.fonts.status, "loaded", "document.fonts.status should have status \"loaded\" (TEST 38) (" + what + ")");
@ -1209,6 +1219,8 @@ function runTest() {
is(doc.fonts.status, "loading", "document.fonts.status should have status \"loading\" after second font added (TEST 38) (" + what + ")");
return doc.fonts.ready;
}).then(function() {
return awaitEvents;
}).then(function() {
is(doc.fonts.status, "loaded", "document.fonts.status should have status \"loaded\" after second font failed to load (TEST 38) (" + what + ")");
is(face2.status, "error", "second FontFace should have status \"error\" (TEST 38) (" + what + ")");
@ -1243,29 +1255,35 @@ function runTest() {
// (TEST 39) Test that a FontFace for an @font-face rule only has one
// loadingdone event dispatched at the FontFaceSet containing it.
var style = document.querySelector("style");
var ruleText = "@font-face { font-family: test; src: url(BitPattern.woff?test39a); } " +
"@font-face { font-family: test2; src: url(BitPattern.woff?test39b); }";
var style, all, events, awaitEvents;
style.textContent = ruleText;
var all = Array.from(document.fonts);
var events = [];
document.fonts.onloadingdone = function(e) {
events.push(e);
};
document.fonts.onloadingerror = function(e) {
events.push(e);
};
is(document.fonts.status, "loaded", "document.fonts.status should have status \"loaded\" (TEST 39)");
all[0].load();
is(document.fonts.status, "loading", "document.fonts.status should have status \"loading\" after first font loading (TEST 39)");
return document.fonts.ready
return setTimeoutZero() // wait for any previous events to be dispatched
.then(function() {
style = document.querySelector("style");
var ruleText = "@font-face { font-family: test; src: url(BitPattern.woff?test39a); } " +
"@font-face { font-family: test2; src: url(BitPattern.woff?test39b); }";
style.textContent = ruleText;
all = Array.from(document.fonts);
events = [];
awaitEvents = new Promise(function(aResolve, aReject) {
document.fonts.onloadingdone = document.fonts.onloadingerror = function(e) {
events.push(e);
if (events.length == 2) {
aResolve();
}
};
});
is(document.fonts.status, "loaded", "document.fonts.status should have status \"loaded\" (TEST 39)");
all[0].load();
is(document.fonts.status, "loading", "document.fonts.status should have status \"loading\" after first font loading (TEST 39)");
return document.fonts.ready
}).then(function() {
is(document.fonts.status, "loaded", "document.fonts.status should have status \"loaded\" after first font loaded (TEST 39)");
is(all[0].status, "loaded", "first FontFace should have status \"loaded\" (TEST 39)");
is(all[1].status, "unloaded", "second FontFace should have status \"unloaded\" (TEST 39)");
@ -1274,6 +1292,8 @@ function runTest() {
is(document.fonts.status, "loading", "document.fonts.status should have status \"loading\" after second font loading (TEST 39)");
return document.fonts.ready;
}).then(function() {
return awaitEvents;
}).then(function() {
is(document.fonts.status, "loaded", "document.fonts.status should have status \"loaded\" after second font loaded (TEST 39)");
is(all[1].status, "loaded", "second FontFace should have status \"loaded\" (TEST 39)");

Просмотреть файл

@ -791,7 +791,9 @@ nsIOService::NewChannelFromURIWithProxyFlagsInternal(nsIURI* aURI,
// creating a new channel by calling NewChannel().
if (NS_FAILED(rv)) {
rv = handler->NewChannel(aURI, getter_AddRefs(channel));
NS_ENSURE_SUCCESS(rv, rv);
if (NS_FAILED(rv)) {
return rv;
}
// The protocol handler does not implement NewChannel2, so
// maybe we need to wrap the channel (see comment in MaybeWrap
// function).

Просмотреть файл

@ -177,7 +177,9 @@ NS_NewChannelInternal(nsIChannel **outChannel,
aSecurityFlags,
aContentPolicyType,
getter_AddRefs(channel));
NS_ENSURE_SUCCESS(rv, rv);
if (NS_FAILED(rv)) {
return rv;
}
if (aLoadGroup) {
rv = channel->SetLoadGroup(aLoadGroup);

Просмотреть файл

@ -7,6 +7,8 @@
// do_check_eq(a, b) to avoid outputting characters which confuse
// the console
"use strict";
var CC = Components.Constructor;
const BinaryInputStream = CC("@mozilla.org/binaryinputstream;1",
"nsIBinaryInputStream",
@ -34,6 +36,7 @@ function run_test()
let binaryStream = new BinaryInputStream(new_file_input_stream(binaryFile));
test_file_data = "";
let avail = 0;
while ((avail = binaryStream.available()) > 0) {
test_file_data += binaryStream.readBytes(avail);
}

Просмотреть файл

@ -17,6 +17,9 @@
// run_myipaddress_test();
// run_failed_script_test();
// run_isresolvable_test();
"use strict";
Cu.import("resource://gre/modules/NetUtil.jsm");
var ios = Components.classes["@mozilla.org/network/io-service;1"]
@ -166,7 +169,7 @@ resolveCallback.prototype = {
return this;
},
onProxyAvailable : function (req, uri, pi, status) {
onProxyAvailable : function (req, channel, pi, status) {
this.nextFunction(pi);
}
};
@ -496,14 +499,14 @@ TestResolveCallback.prototype = {
},
onProxyAvailable:
function TestResolveCallback_onProxyAvailable(req, uri, pi, status) {
dump("*** uri=" + uri.spec + ", status=" + status + "\n");
function TestResolveCallback_onProxyAvailable(req, channel, pi, status) {
dump("*** channelURI=" + channel.URI.spec + ", status=" + status + "\n");
if (this.type == null) {
do_check_eq(pi, null);
} else {
do_check_neq(req, null);
do_check_neq(uri, null);
do_check_neq(channel, null);
do_check_eq(status, 0);
do_check_neq(pi, null);
check_proxy(pi, this.type, "foopy", 8080, 0, -1, true);
@ -613,11 +616,11 @@ TestResolveCancelationCallback.prototype = {
},
onProxyAvailable:
function TestResolveCancelationCallback_onProxyAvailable(req, uri, pi, status) {
dump("*** uri=" + uri.spec + ", status=" + status + "\n");
function TestResolveCancelationCallback_onProxyAvailable(req, channel, pi, status) {
dump("*** channelURI=" + channel.URI.spec + ", status=" + status + "\n");
do_check_neq(req, null);
do_check_neq(uri, null);
do_check_neq(channel, null);
do_check_eq(status, Components.results.NS_ERROR_ABORT);
do_check_eq(pi, null);
@ -701,6 +704,7 @@ function host_filter_cb(proxy)
var uriStrUseProxyList;
var uriStrUseProxyList;
var hostFilterList;
var uriStrFilterList;
function run_proxy_host_filters_test() {
// Get prefs object from DOM

Просмотреть файл

@ -1,9 +1,15 @@
// This testcase verifies that channels can't be reopened
// See https://bugzilla.mozilla.org/show_bug.cgi?id=372486
"use strict";
Cu.import("resource://testing-common/httpd.js");
Cu.import("resource://gre/modules/NetUtil.jsm");
const BinaryInputStream = Components.Constructor(
"@mozilla.org/binaryinputstream;1", "nsIBinaryInputStream",
"setInputStream");
const NS_ERROR_IN_PROGRESS = 0x804b000f;
const NS_ERROR_ALREADY_OPENED = 0x804b0049;

Просмотреть файл

@ -250,6 +250,39 @@ DWORD RestrictedToken::AddAllSidsForDenyOnly(std::vector<Sid> *exceptions) {
return ERROR_SUCCESS;
}
DWORD RestrictedToken::AddDenyOnlySids(const std::vector<Sid>& deny_only_sids) {
DCHECK(init_);
if (!init_) {
return ERROR_NO_TOKEN;
}
DWORD error;
scoped_ptr<BYTE[]> buffer = GetTokenInfo(effective_token_, TokenGroups, &error);
if (!buffer) {
return error;
}
TOKEN_GROUPS* token_groups = reinterpret_cast<TOKEN_GROUPS*>(buffer.get());
// Build the list of the deny only group SIDs
for (unsigned int i = 0; i < token_groups->GroupCount ; ++i) {
if ((token_groups->Groups[i].Attributes & SE_GROUP_INTEGRITY) == 0 &&
(token_groups->Groups[i].Attributes & SE_GROUP_LOGON_ID) == 0) {
for (unsigned int j = 0; j < deny_only_sids.size(); ++j) {
if (::EqualSid(const_cast<SID*>(deny_only_sids[j].GetPSID()),
token_groups->Groups[i].Sid)) {
sids_for_deny_only_.push_back(
reinterpret_cast<SID*>(token_groups->Groups[i].Sid));
break;
}
}
}
}
return ERROR_SUCCESS;
}
DWORD RestrictedToken::AddSidForDenyOnly(const Sid &sid) {
DCHECK(init_);
if (!init_)

Просмотреть файл

@ -88,6 +88,17 @@ class RestrictedToken {
// access to any resource. It can only be used to deny access.
DWORD AddAllSidsForDenyOnly(std::vector<Sid> *exceptions);
// Lists all sids in the token and mark them as Deny Only if present in the
// deny_only_sids parameter.
//
// If the function succeeds, the return value is ERROR_SUCCESS. If the
// function fails, the return value is the win32 error code corresponding to
// the error.
//
// Note: A Sid marked for Deny Only in a token cannot be used to grant
// access to any resource. It can only be used to deny access.
DWORD AddDenyOnlySids(const std::vector<Sid>& deny_only_sids);
// Adds a user or group SID for Deny Only in the restricted token.
// Parameter: sid is the SID to add in the Deny Only list.
// The return value is always ERROR_SUCCESS.

Просмотреть файл

@ -27,6 +27,7 @@ DWORD CreateRestrictedToken(TokenLevel security_level,
std::vector<base::string16> privilege_exceptions;
std::vector<Sid> sid_exceptions;
std::vector<Sid> deny_only_sids;
bool deny_sids = true;
bool remove_privileges = true;
@ -48,10 +49,16 @@ DWORD CreateRestrictedToken(TokenLevel security_level,
break;
}
case USER_NON_ADMIN: {
sid_exceptions.push_back(WinBuiltinUsersSid);
sid_exceptions.push_back(WinWorldSid);
sid_exceptions.push_back(WinInteractiveSid);
sid_exceptions.push_back(WinAuthenticatedUserSid);
deny_sids = false;
deny_only_sids.push_back(WinBuiltinAdministratorsSid);
deny_only_sids.push_back(WinAccountAdministratorSid);
deny_only_sids.push_back(WinAccountDomainAdminsSid);
deny_only_sids.push_back(WinAccountCertAdminsSid);
deny_only_sids.push_back(WinAccountSchemaAdminsSid);
deny_only_sids.push_back(WinAccountEnterpriseAdminsSid);
deny_only_sids.push_back(WinAccountPolicyAdminsSid);
deny_only_sids.push_back(WinBuiltinHyperVAdminsSid);
deny_only_sids.push_back(WinLocalAccountAndAdministratorSid);
privilege_exceptions.push_back(SE_CHANGE_NOTIFY_NAME);
break;
}
@ -107,6 +114,11 @@ DWORD CreateRestrictedToken(TokenLevel security_level,
err_code = restricted_token.AddAllSidsForDenyOnly(&sid_exceptions);
if (ERROR_SUCCESS != err_code)
return err_code;
} else if (!deny_only_sids.empty()) {
err_code = restricted_token.AddDenyOnlySids(deny_only_sids);
if (ERROR_SUCCESS != err_code) {
return err_code;
}
}
if (remove_privileges) {

Просмотреть файл

@ -1,8 +1,9 @@
Please add a link to the bugzilla bug and patch name that should be re-applied.
Also, please update any existing links to their actual mozilla-central changeset.
https://bugzilla.mozilla.org/show_bug.cgi?id=1287426 bug1287426part5.patch
https://hg.mozilla.org/mozilla-central/rev/a05726163a79
https://hg.mozilla.org/mozilla-central/rev/7df8d6639971
https://bugzilla.mozilla.org/show_bug.cgi?id=1287426 bug1287426part7.patch
https://bugzilla.mozilla.org/show_bug.cgi?id=1273372 bug1273372part2.patch
https://bugzilla.mozilla.org/show_bug.cgi?id=1273372 bug1273372part3.patch
https://hg.mozilla.org/mozilla-central/rev/e834e810a3fa
https://hg.mozilla.org/mozilla-central/rev/c70d06fa5302
https://hg.mozilla.org/mozilla-central/rev/d24db55deb85
https://bugzilla.mozilla.org/show_bug.cgi?id=1321724 bug1321724.patch

Просмотреть файл

@ -92,6 +92,6 @@ def make_decision_task(params, symbol, arguments=[], head_rev=None):
task['taskGroupId'] = task_id
# set the schedulerId based on the level
task['schedulerId'] = 'gecko-level-{}-cron'.format(params['level'])
task['schedulerId'] = 'gecko-level-{}'.format(params['level'])
return (task_id, task)

Просмотреть файл

@ -829,3 +829,279 @@ class ChunkFinder(MachCommandBase):
os.remove(dump_tests)
if temp_dir:
shutil.rmtree(temp_dir)
@CommandProvider
class TestInfoCommand(MachCommandBase):
from datetime import date, timedelta
@Command('test-info', category='testing',
description='Display historical test result summary.')
@CommandArgument('test_name', nargs='?', metavar='N',
help='Test of interest.')
@CommandArgument('--branches',
default='mozilla-central,mozilla-inbound,autoland',
help='Report for named branches (default: mozilla-central,mozilla-inbound,autoland)')
@CommandArgument('--start',
default=(date.today() - timedelta(7)).strftime("%Y-%m-%d"),
help='Start date (YYYY-MM-DD)')
@CommandArgument('--end',
default=date.today().strftime("%Y-%m-%d"),
help='End date (YYYY-MM-DD)')
def test_info(self, **params):
import which
from mozbuild.base import MozbuildObject
self.test_name = params['test_name']
self.branches = params['branches']
self.start = params['start']
self.end = params['end']
if len(self.test_name) < 6:
print("'%s' is too short for a test name!" % self.test_name)
return
here = os.path.abspath(os.path.dirname(__file__))
build_obj = MozbuildObject.from_environment(cwd=here)
self._hg = None
if conditions.is_hg(build_obj):
if self._is_windows():
self._hg = which.which('hg.exe')
else:
self._hg = which.which('hg')
self._git = None
if conditions.is_git(build_obj):
if self._is_windows():
self._git = which.which('git.exe')
else:
self._git = which.which('git')
self.set_test_name()
self.report_test_results()
self.report_test_durations()
self.report_bugs()
def find_in_hg_or_git(self, test_name):
if self._hg:
cmd = [self._hg, 'files', '-I', test_name]
elif self._git:
cmd = [self._git, 'ls-files', test_name]
else:
return None
try:
out = subprocess.check_output(cmd).splitlines()
except subprocess.CalledProcessError:
out = None
return out
def set_test_name(self):
# Generating a unified report for a specific test is complicated
# by differences in the test name used in various data sources.
# Consider:
# - It is often convenient to request a report based only on
# a short file name, rather than the full path;
# - Bugs may be filed in bugzilla against a simple, short test
# name or the full path to the test;
# - In ActiveData, the full path is usually used, but sometimes
# also includes additional path components outside of the
# mercurial repo (common for reftests).
# This function attempts to find appropriate names for different
# queries based on the specified test name.
import re
# full_test_name is full path to file in hg (or git)
self.full_test_name = None
out = self.find_in_hg_or_git(self.test_name)
if out and len(out) == 1:
self.full_test_name = out[0]
elif out and len(out) > 1:
print("Ambiguous test name specified. Found:")
for line in out:
print(line)
else:
out = self.find_in_hg_or_git('**/%s*' % self.test_name)
if out and len(out) == 1:
self.full_test_name = out[0]
elif out and len(out) > 1:
print("Ambiguous test name. Found:")
for line in out:
print(line)
if self.full_test_name:
print("Found %s in source control." % self.full_test_name)
else:
print("Unable to validate test name '%s'!" % self.test_name)
self.full_test_name = self.test_name
# short_name is full_test_name without path
self.short_name = None
name_idx = self.full_test_name.rfind('/')
if name_idx > 0:
self.short_name = self.full_test_name[name_idx+1:]
# robo_name is short_name without ".java" - for robocop
self.robo_name = None
if self.short_name:
robo_idx = self.short_name.rfind('.java')
if robo_idx > 0:
self.robo_name = self.short_name[:robo_idx]
if self.short_name == self.test_name:
self.short_name = None
# activedata_test_name is name in ActiveData
self.activedata_test_name = None
simple_names = [
self.full_test_name,
self.test_name,
self.short_name,
self.robo_name
]
simple_names = [x for x in simple_names if x]
searches = [
{"in": {"result.test": simple_names}},
]
regex_names = [".*%s.*" % re.escape(x) for x in simple_names if x]
for r in regex_names:
searches.append({"regexp": {"result.test": r}})
query = {
"from": "unittest",
"format": "list",
"limit": 10,
"groupby": ["result.test"],
"where": {"and": [
{"or": searches},
{"in": {"build.branch": self.branches.split(',')}},
{"gt": {"run.timestamp": {"date": self.start}}},
{"lt": {"run.timestamp": {"date": self.end}}}
]}
}
print("Querying ActiveData...") # Following query can take a long time
data = self.submit(query)
if data and len(data) > 0:
self.activedata_test_name = [
d['result']['test']
for p in simple_names + regex_names
for d in data
if re.match(p+"$", d['result']['test'])
][0] # first match is best match
if self.activedata_test_name:
print("Found records matching '%s' in ActiveData." %
self.activedata_test_name)
else:
print("Unable to find matching records in ActiveData; using %s!" %
self.test_name)
self.activedata_test_name = self.test_name
def get_platform(self, record):
platform = record['build']['platform']
type = record['build']['type']
e10s = "-%s" % record['run']['type'] if 'run' in record else ""
return "%s/%s%s:" % (platform, type, e10s)
def submit(self, query):
import requests
response = requests.post("http://activedata.allizom.org/query",
data=json.dumps(query),
stream=True)
response.raise_for_status()
data = response.json()["data"]
return data
def report_test_results(self):
# Report test pass/fail summary from ActiveData
query = {
"from": "unittest",
"format": "list",
"limit": 100,
"groupby": ["build.platform", "build.type", "run.type"],
"select": [
{"aggregate": "count"},
{
"name": "failures",
"value": {"case": [
{"when": {"eq": {"result.ok": "F"}}, "then": 1}
]},
"aggregate": "sum",
"default": 0
}
],
"where": {"and": [
{"eq": {"result.test": self.activedata_test_name}},
{"in": {"build.branch": self.branches.split(',')}},
{"gt": {"run.timestamp": {"date": self.start}}},
{"lt": {"run.timestamp": {"date": self.end}}}
]}
}
print("\nTest results for %s on %s between %s and %s" %
(self.activedata_test_name, self.branches, self.start, self.end))
data = self.submit(query)
if data and len(data) > 0:
data.sort(key=self.get_platform)
for record in data:
platform = self.get_platform(record)
runs = record['count']
failures = record['failures']
print("%-30s %6d failures in %6d runs" % (
platform, failures, runs))
else:
print("No test result data found.")
def report_test_durations(self):
# Report test durations summary from ActiveData
query = {
"from": "unittest",
"format": "list",
"limit": 100,
"groupby": ["build.platform","build.type","run.type"],
"select": [
{"value":"result.duration","aggregate":"average","name":"average"},
{"value":"result.duration","aggregate":"min","name":"min"},
{"value":"result.duration","aggregate":"max","name":"max"},
{"aggregate":"count"}
],
"where": {"and": [
{"eq": {"result.ok": "T"}},
{"eq": {"result.test": self.activedata_test_name}},
{"in": {"build.branch": self.branches.split(',')}},
{"gt": {"run.timestamp": {"date": self.start}}},
{"lt": {"run.timestamp": {"date": self.end}}}
]}
}
data = self.submit(query)
print("\nTest durations for %s on %s between %s and %s" %
(self.activedata_test_name, self.branches, self.start, self.end))
if data and len(data) > 0:
data.sort(key=self.get_platform)
for record in data:
platform = self.get_platform(record)
print("%-30s %6.2f s (%.2f s - %.2f s over %d runs)" % (
platform, record['average'], record['min'],
record['max'], record['count']))
else:
print("No test durations found.")
def report_bugs(self):
# Report open bugs matching test name
import requests
search = self.full_test_name
if self.test_name:
search = '%s,%s' % (search, self.test_name)
if self.short_name:
search = '%s,%s' % (search, self.short_name)
if self.robo_name:
search = '%s,%s' % (search, self.robo_name)
payload = {'quicksearch': search,
'include_fields':'id,summary'}
response = requests.get('https://bugzilla.mozilla.org/rest/bug',
payload)
response.raise_for_status()
json_response = response.json()
print("\nBugzilla quick search for '%s':" % search)
if 'bugs' in json_response:
for bug in json_response['bugs']:
print("Bug %s: %s" % (bug['id'], bug['summary']))
else:
print("No bugs found.")

Просмотреть файл

@ -2,11 +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/. */
#if _WIN32_WINNT < 0x0600
#undef _WIN32_WINNT
#define _WIN32_WINNT 0x0600
#endif
#include <shlobj.h>
#include <stdio.h>

Просмотреть файл

@ -31,67 +31,50 @@ using mozilla::JSONWriter;
ProfileEntry::ProfileEntry()
: mTagData(nullptr)
, mTagName(0)
, mKind(Kind::INVALID)
{ }
// aTagData must not need release (i.e. be a string from the text segment)
ProfileEntry::ProfileEntry(char aTagName, const char *aTagData)
ProfileEntry::ProfileEntry(Kind aKind, const char *aTagData)
: mTagData(aTagData)
, mTagName(aTagName)
, mKind(aKind)
{ }
ProfileEntry::ProfileEntry(char aTagName, ProfilerMarker *aTagMarker)
ProfileEntry::ProfileEntry(Kind aKind, ProfilerMarker *aTagMarker)
: mTagMarker(aTagMarker)
, mTagName(aTagName)
, mKind(aKind)
{ }
ProfileEntry::ProfileEntry(char aTagName, void *aTagPtr)
ProfileEntry::ProfileEntry(Kind aKind, void *aTagPtr)
: mTagPtr(aTagPtr)
, mTagName(aTagName)
, mKind(aKind)
{ }
ProfileEntry::ProfileEntry(char aTagName, double aTagDouble)
ProfileEntry::ProfileEntry(Kind aKind, double aTagDouble)
: mTagDouble(aTagDouble)
, mTagName(aTagName)
, mKind(aKind)
{ }
ProfileEntry::ProfileEntry(char aTagName, uintptr_t aTagOffset)
ProfileEntry::ProfileEntry(Kind aKind, uintptr_t aTagOffset)
: mTagOffset(aTagOffset)
, mTagName(aTagName)
, mKind(aKind)
{ }
ProfileEntry::ProfileEntry(char aTagName, Address aTagAddress)
ProfileEntry::ProfileEntry(Kind aKind, Address aTagAddress)
: mTagAddress(aTagAddress)
, mTagName(aTagName)
, mKind(aKind)
{ }
ProfileEntry::ProfileEntry(char aTagName, int aTagInt)
ProfileEntry::ProfileEntry(Kind aKind, int aTagInt)
: mTagInt(aTagInt)
, mTagName(aTagName)
, mKind(aKind)
{ }
ProfileEntry::ProfileEntry(char aTagName, char aTagChar)
ProfileEntry::ProfileEntry(Kind aKind, char aTagChar)
: mTagChar(aTagChar)
, mTagName(aTagName)
, mKind(aKind)
{ }
bool ProfileEntry::is_ent_hint(char hintChar) {
return mTagName == 'h' && mTagChar == hintChar;
}
bool ProfileEntry::is_ent_hint() {
return mTagName == 'h';
}
bool ProfileEntry::is_ent(char tagChar) {
return mTagName == tagChar;
}
void* ProfileEntry::get_tagPtr() {
// No consistency checking. Oh well.
return mTagPtr;
}
// END ProfileEntry
////////////////////////////////////////////////////////////////////////
@ -607,40 +590,40 @@ void ProfileBuffer::StreamSamplesToJSON(SpliceableJSONWriter& aWriter, int aThre
while (readPos != mWritePos) {
ProfileEntry entry = mEntries[readPos];
if (entry.mTagName == 'T') {
if (entry.isThreadId()) {
currentThreadID = entry.mTagInt;
currentTime.reset();
int readAheadPos = (readPos + 1) % mEntrySize;
if (readAheadPos != mWritePos) {
ProfileEntry readAheadEntry = mEntries[readAheadPos];
if (readAheadEntry.mTagName == 't') {
if (readAheadEntry.isTime()) {
currentTime = Some(readAheadEntry.mTagDouble);
}
}
}
if (currentThreadID == aThreadId && (currentTime.isNothing() || *currentTime >= aSinceTime)) {
switch (entry.mTagName) {
case 'r':
switch (entry.kind()) {
case ProfileEntry::Kind::Responsiveness:
if (sample.isSome()) {
sample->mResponsiveness = Some(entry.mTagDouble);
}
break;
case 'R':
case ProfileEntry::Kind::ResidentMemory:
if (sample.isSome()) {
sample->mRSS = Some(entry.mTagDouble);
}
break;
case 'U':
case ProfileEntry::Kind::UnsharedMemory:
if (sample.isSome()) {
sample->mUSS = Some(entry.mTagDouble);
}
break;
case 'f':
case ProfileEntry::Kind::FrameNumber:
if (sample.isSome()) {
sample->mFrameNumber = Some(entry.mTagInt);
}
break;
case 's':
case ProfileEntry::Kind::Sample:
{
// end the previous sample if there was one
if (sample.isSome()) {
@ -660,49 +643,51 @@ void ProfileBuffer::StreamSamplesToJSON(SpliceableJSONWriter& aWriter, int aThre
int framePos = (readPos + 1) % mEntrySize;
ProfileEntry frame = mEntries[framePos];
while (framePos != mWritePos && frame.mTagName != 's' && frame.mTagName != 'T') {
while (framePos != mWritePos && !frame.isSample() && !frame.isThreadId()) {
int incBy = 1;
frame = mEntries[framePos];
// Read ahead to the next tag, if it's a 'd' tag process it now
// Read ahead to the next tag, if it's an EmbeddedString
// tag process it now
const char* tagStringData = frame.mTagData;
int readAheadPos = (framePos + 1) % mEntrySize;
// Make sure the string is always null terminated if it fills up
// DYNAMIC_MAX_STRING-2
tagBuff[DYNAMIC_MAX_STRING-1] = '\0';
if (readAheadPos != mWritePos && mEntries[readAheadPos].mTagName == 'd') {
if (readAheadPos != mWritePos && mEntries[readAheadPos].isEmbeddedString()) {
tagStringData = processDynamicTag(framePos, &incBy, tagBuff.get());
}
// Write one frame. It can have either
// 1. only location - 'l' containing a memory address
// 2. location and line number - 'c' followed by 'd's,
// an optional 'n' and an optional 'y'
// 3. a JIT return address - 'j' containing native code address
if (frame.mTagName == 'l') {
// 1. only location - a NativeLeafAddr containing a memory address
// 2. location and line number - a CodeLocation followed by
// EmbeddedStrings, an optional LineNumber and an
// optional Category
// 3. a JitReturnAddress containing a native code address
if (frame.isNativeLeafAddr()) {
// Bug 753041
// We need a double cast here to tell GCC that we don't want to sign
// extend 32-bit addresses starting with 0xFXXXXXX.
unsigned long long pc = (unsigned long long)(uintptr_t)frame.mTagPtr;
snprintf(tagBuff.get(), DYNAMIC_MAX_STRING, "%#llx", pc);
stack.AppendFrame(UniqueStacks::OnStackFrameKey(tagBuff.get()));
} else if (frame.mTagName == 'c') {
} else if (frame.isCodeLocation()) {
UniqueStacks::OnStackFrameKey frameKey(tagStringData);
readAheadPos = (framePos + incBy) % mEntrySize;
if (readAheadPos != mWritePos &&
mEntries[readAheadPos].mTagName == 'n') {
mEntries[readAheadPos].isLineNumber()) {
frameKey.mLine = Some((unsigned) mEntries[readAheadPos].mTagInt);
incBy++;
}
readAheadPos = (framePos + incBy) % mEntrySize;
if (readAheadPos != mWritePos &&
mEntries[readAheadPos].mTagName == 'y') {
mEntries[readAheadPos].isCategory()) {
frameKey.mCategory = Some((unsigned) mEntries[readAheadPos].mTagInt);
incBy++;
}
stack.AppendFrame(frameKey);
} else if (frame.mTagName == 'J') {
} else if (frame.isJitReturnAddr()) {
// A JIT frame may expand to multiple frames due to inlining.
void* pc = frame.mTagPtr;
unsigned depth = aUniqueStacks.LookupJITFrameDepth(pc);
@ -723,7 +708,9 @@ void ProfileBuffer::StreamSamplesToJSON(SpliceableJSONWriter& aWriter, int aThre
sample->mStack = stack.GetOrAddIndex();
break;
}
}
default:
break;
} /* switch (entry.kind()) */
}
readPos = (readPos + 1) % mEntrySize;
}
@ -739,9 +726,9 @@ void ProfileBuffer::StreamMarkersToJSON(SpliceableJSONWriter& aWriter, int aThre
int currentThreadID = -1;
while (readPos != mWritePos) {
ProfileEntry entry = mEntries[readPos];
if (entry.mTagName == 'T') {
if (entry.isThreadId()) {
currentThreadID = entry.mTagInt;
} else if (currentThreadID == aThreadId && entry.mTagName == 'm') {
} else if (currentThreadID == aThreadId && entry.isMarker()) {
const ProfilerMarker* marker = entry.getMarker();
if (marker->GetTime() >= aSinceTime) {
entry.getMarker()->StreamJSON(aWriter, aUniqueStacks);
@ -759,7 +746,7 @@ int ProfileBuffer::FindLastSampleOfThread(int aThreadId)
readPos != (mReadPos + mEntrySize - 1) % mEntrySize;
readPos = (readPos + mEntrySize - 1) % mEntrySize) {
ProfileEntry entry = mEntries[readPos];
if (entry.mTagName == 'T' && entry.mTagInt == aThreadId) {
if (entry.isThreadId() && entry.mTagInt == aThreadId) {
return readPos;
}
}
@ -774,7 +761,7 @@ void ProfileBuffer::DuplicateLastSample(int aThreadId)
return;
}
MOZ_ASSERT(mEntries[lastSampleStartPos].mTagName == 'T');
MOZ_ASSERT(mEntries[lastSampleStartPos].isThreadId());
addTag(mEntries[lastSampleStartPos]);
@ -782,20 +769,19 @@ void ProfileBuffer::DuplicateLastSample(int aThreadId)
for (int readPos = (lastSampleStartPos + 1) % mEntrySize;
readPos != mWritePos;
readPos = (readPos + 1) % mEntrySize) {
switch (mEntries[readPos].mTagName) {
case 'T':
switch (mEntries[readPos].kind()) {
case ProfileEntry::Kind::ThreadId:
// We're done.
return;
case 't':
case ProfileEntry::Kind::Time:
// Copy with new time
addTag(ProfileEntry('t', (mozilla::TimeStamp::Now() - sStartTime).ToMilliseconds()));
addTag(ProfileEntry::Time((mozilla::TimeStamp::Now() - sStartTime).ToMilliseconds()));
break;
case 'm':
case ProfileEntry::Kind::Marker:
// Don't copy markers
break;
// Copy anything else we don't know about
// L, B, S, c, s, d, l, f, h, r, t, p
default:
// Copy anything else we don't know about
addTag(mEntries[readPos]);
break;
}

Просмотреть файл

@ -25,6 +25,22 @@
#include "mozilla/HashFunctions.h"
#include "mozilla/UniquePtr.h"
#define PROFILE_ENTRY_KIND_LIST(_) \
_(Category, int) \
_(CodeLocation, const char *) \
_(EmbeddedString, void *) \
_(FrameNumber, int) \
_(JitReturnAddr, void *) \
_(LineNumber, int) \
_(NativeLeafAddr, void *) \
_(Marker, ProfilerMarker *) \
_(ResidentMemory, double) \
_(Responsiveness, double) \
_(Sample, const char *) \
_(ThreadId, int) \
_(Time, double) \
_(UnsharedMemory, double)
// NB: Packing this structure has been shown to cause SIGBUS issues on ARM.
#ifndef __arm__
#pragma pack(push, 1)
@ -33,28 +49,46 @@
class ProfileEntry
{
public:
enum class Kind : uint8_t {
INVALID = 0,
# define DEF_ENUM_(k, t) k,
PROFILE_ENTRY_KIND_LIST(DEF_ENUM_)
# undef DEF_ENUM_
LIMIT
};
ProfileEntry();
private:
// aTagData must not need release (i.e. be a string from the text segment)
ProfileEntry(char aTagName, const char *aTagData);
ProfileEntry(char aTagName, void *aTagPtr);
ProfileEntry(char aTagName, ProfilerMarker *aTagMarker);
ProfileEntry(char aTagName, double aTagDouble);
ProfileEntry(char aTagName, uintptr_t aTagOffset);
ProfileEntry(char aTagName, Address aTagAddress);
ProfileEntry(char aTagName, int aTagLine);
ProfileEntry(char aTagName, char aTagChar);
bool is_ent_hint(char hintChar);
bool is_ent_hint();
bool is_ent(char tagName);
void* get_tagPtr();
ProfileEntry(Kind aKind, const char *aTagData);
ProfileEntry(Kind aKind, void *aTagPtr);
ProfileEntry(Kind aKind, ProfilerMarker *aTagMarker);
ProfileEntry(Kind aKind, double aTagDouble);
ProfileEntry(Kind aKind, uintptr_t aTagOffset);
ProfileEntry(Kind aKind, Address aTagAddress);
ProfileEntry(Kind aKind, int aTagLine);
ProfileEntry(Kind aKind, char aTagChar);
public:
# define DEF_MAKE_(k, t) \
static ProfileEntry k(t val) { return ProfileEntry(Kind::k, val); }
PROFILE_ENTRY_KIND_LIST(DEF_MAKE_)
# undef DEF_MAKE_
Kind kind() const { return mKind; }
bool hasKind(Kind k) const { return kind() == k; }
# define DEF_METHODS_(k, t) \
bool is##k() const { return hasKind(Kind::k); }
PROFILE_ENTRY_KIND_LIST(DEF_METHODS_)
# undef DEF_METHODS_
const ProfilerMarker* getMarker() {
MOZ_ASSERT(mTagName == 'm');
MOZ_ASSERT(isMarker());
return mTagMarker;
}
char getTagName() const { return mTagName; }
private:
FRIEND_TEST(ThreadProfile, InsertOneTag);
FRIEND_TEST(ThreadProfile, InsertOneTagWithTinyBuffer);
@ -73,7 +107,7 @@ private:
int mTagInt;
char mTagChar;
};
char mTagName;
Kind mKind;
};
#ifndef __arm__

Просмотреть файл

@ -767,9 +767,9 @@ void PseudoStack::flushSamplerOnJSShutdown()
////////////////////////////////////////////////////////////////////////
static
void addDynamicTag(ThreadInfo& aInfo, char aTagName, const char* aStr)
void addDynamicCodeLocationTag(ThreadInfo& aInfo, const char* aStr)
{
aInfo.addTag(ProfileEntry(aTagName, ""));
aInfo.addTag(ProfileEntry::CodeLocation(""));
// Add one to store the null termination
size_t strLen = strlen(aStr) + 1;
for (size_t j = 0; j < strLen;) {
@ -782,7 +782,7 @@ void addDynamicTag(ThreadInfo& aInfo, char aTagName, const char* aStr)
memcpy(text, &aStr[j], len);
j += sizeof(void*)/sizeof(char);
// Cast to *((void**) to pass the text data to a void*
aInfo.addTag(ProfileEntry('d', *((void**)(&text[0]))));
aInfo.addTag(ProfileEntry::EmbeddedString(*((void**)(&text[0]))));
}
}
@ -797,14 +797,14 @@ void addPseudoEntry(volatile StackEntry& entry, ThreadInfo& aInfo,
int lineno = -1;
// First entry has tagName 's' (start)
// First entry has kind CodeLocation
// Check for magic pointer bit 1 to indicate copy
const char* sampleLabel = entry.label();
if (entry.isCopyLabel()) {
// Store the string using 1 or more 'd' (dynamic) tags
// Store the string using 1 or more EmbeddedString tags
// that will happen to the preceding tag
addDynamicTag(aInfo, 'c', sampleLabel);
addDynamicCodeLocationTag(aInfo, sampleLabel);
if (entry.isJs()) {
JSScript* script = entry.script();
if (script) {
@ -827,7 +827,7 @@ void addPseudoEntry(volatile StackEntry& entry, ThreadInfo& aInfo,
lineno = entry.line();
}
} else {
aInfo.addTag(ProfileEntry('c', sampleLabel));
aInfo.addTag(ProfileEntry::CodeLocation(sampleLabel));
// XXX: Bug 1010578. Don't assume a CPP entry and try to get the
// line for js entries as well.
@ -837,7 +837,7 @@ void addPseudoEntry(volatile StackEntry& entry, ThreadInfo& aInfo,
}
if (lineno != -1) {
aInfo.addTag(ProfileEntry('n', lineno));
aInfo.addTag(ProfileEntry::LineNumber(lineno));
}
uint32_t category = entry.category();
@ -845,7 +845,7 @@ void addPseudoEntry(volatile StackEntry& entry, ThreadInfo& aInfo,
MOZ_ASSERT(!(category & StackEntry::FRAME_LABEL_COPY));
if (category) {
aInfo.addTag(ProfileEntry('y', (int)category));
aInfo.addTag(ProfileEntry::Category((int)category));
}
}
@ -928,7 +928,7 @@ mergeStacksIntoProfile(ThreadInfo& aInfo, TickSample* aSample,
}
// Start the sample with a root entry.
aInfo.addTag(ProfileEntry('s', "(root)"));
aInfo.addTag(ProfileEntry::Sample("(root)"));
// While the pseudo-stack array is ordered oldest-to-youngest, the JS and
// native arrays are ordered youngest-to-oldest. We must add frames to
@ -1012,7 +1012,7 @@ mergeStacksIntoProfile(ThreadInfo& aInfo, TickSample* aSample,
// Stringifying non-wasm JIT frames is delayed until streaming
// time. To re-lookup the entry in the JitcodeGlobalTable, we need to
// store the JIT code address ('J') in the circular buffer.
// store the JIT code address (OptInfoAddr) in the circular buffer.
//
// Note that we cannot do this when we are sychronously sampling the
// current thread; that is, when called from profiler_get_backtrace. The
@ -1020,16 +1020,16 @@ mergeStacksIntoProfile(ThreadInfo& aInfo, TickSample* aSample,
// amount of time, such as in nsRefreshDriver. Problematically, the
// stored backtrace may be alive across a GC during which the profiler
// itself is disabled. In that case, the JS engine is free to discard
// its JIT code. This means that if we inserted such 'J' entries into
// the buffer, nsRefreshDriver would now be holding on to a backtrace
// with stale JIT code return addresses.
// its JIT code. This means that if we inserted such OptInfoAddr entries
// into the buffer, nsRefreshDriver would now be holding on to a
// backtrace with stale JIT code return addresses.
if (aSample->isSamplingCurrentThread ||
jsFrame.kind == JS::ProfilingFrameIterator::Frame_Wasm) {
addDynamicTag(aInfo, 'c', jsFrame.label);
addDynamicCodeLocationTag(aInfo, jsFrame.label);
} else {
MOZ_ASSERT(jsFrame.kind == JS::ProfilingFrameIterator::Frame_Ion ||
jsFrame.kind == JS::ProfilingFrameIterator::Frame_Baseline);
aInfo.addTag(ProfileEntry('J', jsFrames[jsIndex].returnAddress));
aInfo.addTag(ProfileEntry::JitReturnAddr(jsFrames[jsIndex].returnAddress));
}
jsIndex--;
@ -1041,7 +1041,7 @@ mergeStacksIntoProfile(ThreadInfo& aInfo, TickSample* aSample,
if (nativeStackAddr) {
MOZ_ASSERT(nativeIndex >= 0);
aInfo
.addTag(ProfileEntry('l', (void*)aNativeStack.pc_array[nativeIndex]));
.addTag(ProfileEntry::NativeLeafAddr((void*)aNativeStack.pc_array[nativeIndex]));
}
if (nativeIndex >= 0) {
nativeIndex--;
@ -1299,7 +1299,7 @@ doSampleStackTrace(ThreadInfo& aInfo, TickSample* aSample,
#ifdef ENABLE_LEAF_DATA
if (aSample && aAddLeafAddresses) {
aInfo.addTag(ProfileEntry('l', (void*)aSample->pc));
aInfo.addTag(ProfileEntry::NativeLeafAddr((void*)aSample->pc));
}
#endif
}
@ -1316,10 +1316,10 @@ Sampler::InplaceTick(TickSample* sample)
{
ThreadInfo& currThreadInfo = *sample->threadInfo;
currThreadInfo.addTag(ProfileEntry('T', currThreadInfo.ThreadId()));
currThreadInfo.addTag(ProfileEntry::ThreadId(currThreadInfo.ThreadId()));
mozilla::TimeDuration delta = sample->timestamp - sStartTime;
currThreadInfo.addTag(ProfileEntry('t', delta.ToMilliseconds()));
currThreadInfo.addTag(ProfileEntry::Time(delta.ToMilliseconds()));
PseudoStack* stack = currThreadInfo.Stack();
@ -1341,27 +1341,27 @@ Sampler::InplaceTick(TickSample* sample)
while (pendingMarkersList && pendingMarkersList->peek()) {
ProfilerMarker* marker = pendingMarkersList->popHead();
currThreadInfo.addStoredMarker(marker);
currThreadInfo.addTag(ProfileEntry('m', marker));
currThreadInfo.addTag(ProfileEntry::Marker(marker));
}
}
if (currThreadInfo.GetThreadResponsiveness()->HasData()) {
mozilla::TimeDuration delta = currThreadInfo.GetThreadResponsiveness()->GetUnresponsiveDuration(sample->timestamp);
currThreadInfo.addTag(ProfileEntry('r', delta.ToMilliseconds()));
currThreadInfo.addTag(ProfileEntry::Responsiveness(delta.ToMilliseconds()));
}
// rssMemory is equal to 0 when we are not recording.
if (sample->rssMemory != 0) {
currThreadInfo.addTag(ProfileEntry('R', static_cast<double>(sample->rssMemory)));
currThreadInfo.addTag(ProfileEntry::ResidentMemory(static_cast<double>(sample->rssMemory)));
}
// ussMemory is equal to 0 when we are not recording.
if (sample->ussMemory != 0) {
currThreadInfo.addTag(ProfileEntry('U', static_cast<double>(sample->ussMemory)));
currThreadInfo.addTag(ProfileEntry::UnsharedMemory(static_cast<double>(sample->ussMemory)));
}
if (sLastFrameNumber != sFrameNumber) {
currThreadInfo.addTag(ProfileEntry('f', sFrameNumber));
currThreadInfo.addTag(ProfileEntry::FrameNumber(sFrameNumber));
sLastFrameNumber = sFrameNumber;
}
}

Просмотреть файл

@ -23,9 +23,9 @@ TEST(ThreadProfile, InsertOneTag) {
Thread::tid_t tid = 1000;
ThreadInfo info("testThread", tid, true, stack, nullptr);
RefPtr<ProfileBuffer> pb = new ProfileBuffer(10);
pb->addTag(ProfileEntry('t', 123.1));
pb->addTag(ProfileEntry::Time(123.1));
ASSERT_TRUE(pb->mEntries != nullptr);
ASSERT_TRUE(pb->mEntries[pb->mReadPos].mTagName == 't');
ASSERT_TRUE(pb->mEntries[pb->mReadPos].kind() == ProfileEntry::Kind::Time);
ASSERT_TRUE(pb->mEntries[pb->mReadPos].mTagDouble == 123.1);
}
@ -37,13 +37,13 @@ TEST(ThreadProfile, InsertTagsNoWrap) {
RefPtr<ProfileBuffer> pb = new ProfileBuffer(100);
int test_size = 50;
for (int i = 0; i < test_size; i++) {
pb->addTag(ProfileEntry('t', i));
pb->addTag(ProfileEntry::Time(i));
}
ASSERT_TRUE(pb->mEntries != nullptr);
int readPos = pb->mReadPos;
while (readPos != pb->mWritePos) {
ASSERT_TRUE(pb->mEntries[readPos].mTagName == 't');
ASSERT_TRUE(pb->mEntries[readPos].mTagInt == readPos);
ASSERT_TRUE(pb->mEntries[readPos].kind() == ProfileEntry::Kind::Time);
ASSERT_TRUE(pb->mEntries[readPos].mTagDouble == readPos);
readPos = (readPos + 1) % pb->mEntrySize;
}
}
@ -59,15 +59,15 @@ TEST(ThreadProfile, InsertTagsWrap) {
RefPtr<ProfileBuffer> pb = new ProfileBuffer(buffer_size);
int test_size = 43;
for (int i = 0; i < test_size; i++) {
pb->addTag(ProfileEntry('t', i));
pb->addTag(ProfileEntry::Time(i));
}
ASSERT_TRUE(pb->mEntries != nullptr);
int readPos = pb->mReadPos;
int ctr = 0;
while (readPos != pb->mWritePos) {
ASSERT_TRUE(pb->mEntries[readPos].mTagName == 't');
ASSERT_TRUE(pb->mEntries[readPos].kind() == ProfileEntry::Kind::Time);
// the first few tags were discarded when we wrapped
ASSERT_TRUE(pb->mEntries[readPos].mTagInt == ctr + (test_size - tags));
ASSERT_TRUE(pb->mEntries[readPos].mTagDouble == ctr + (test_size - tags));
ctr++;
readPos = (readPos + 1) % pb->mEntrySize;
}

Просмотреть файл

@ -64,6 +64,19 @@ NS_IMETHODIMP nsDeviceContextSpecX::Init(nsIWidget *aWidget,
if (!settings)
return NS_ERROR_NO_INTERFACE;
bool toFile;
settings->GetPrintToFile(&toFile);
bool toPrinter = !toFile && !aIsPrintPreview;
if (!toPrinter) {
double width, height;
settings->GetEffectivePageSize(&width, &height);
width /= TWIPS_PER_POINT_FLOAT;
height /= TWIPS_PER_POINT_FLOAT;
settings->SetCocoaPaperSize(width, height);
}
mPrintSession = settings->GetPMPrintSession();
::PMRetain(mPrintSession);
mPageFormat = settings->GetPMPageFormat();

Просмотреть файл

@ -9,19 +9,6 @@
#include "nsPrintOptionsX.h"
#include "nsPrintSettingsX.h"
// The constants for paper orientation were renamed in 10.9. __MAC_10_9 is
// defined on OS X 10.9 and later. Although 10.8 and earlier are not supported
// at this time, this allows for building on those older OS versions. The
// values are consistent across OS versions so the rename does not affect
// runtime, just compilation.
#ifdef __MAC_10_9
#define NS_PAPER_ORIENTATION_PORTRAIT (NSPaperOrientationPortrait)
#define NS_PAPER_ORIENTATION_LANDSCAPE (NSPaperOrientationLandscape)
#else
#define NS_PAPER_ORIENTATION_PORTRAIT (NSPortraitOrientation)
#define NS_PAPER_ORIENTATION_LANDSCAPE (NSLandscapeOrientation)
#endif
using namespace mozilla::embedding;
nsPrintOptionsX::nsPrintOptionsX()

Просмотреть файл

@ -9,6 +9,19 @@
#include "nsPrintSettingsImpl.h"
#import <Cocoa/Cocoa.h>
// The constants for paper orientation were renamed in 10.9. __MAC_10_9 is
// defined on OS X 10.9 and later. Although 10.8 and earlier are not supported
// at this time, this allows for building on those older OS versions. The
// values are consistent across OS versions so the rename does not affect
// runtime, just compilation.
#ifdef __MAC_10_9
#define NS_PAPER_ORIENTATION_PORTRAIT (NSPaperOrientationPortrait)
#define NS_PAPER_ORIENTATION_LANDSCAPE (NSPaperOrientationLandscape)
#else
#define NS_PAPER_ORIENTATION_PORTRAIT (NSPortraitOrientation)
#define NS_PAPER_ORIENTATION_LANDSCAPE (NSLandscapeOrientation)
#endif
#define NS_PRINTSETTINGSX_IID \
{ 0x0DF2FDBD, 0x906D, 0x4726, \
{ 0x9E, 0x4D, 0xCF, 0xE0, 0x87, 0x8D, 0x70, 0x7C } }
@ -51,8 +64,22 @@ public:
void SetInchesScale(float aWidthScale, float aHeightScale);
void GetInchesScale(float *aWidthScale, float *aHeightScale);
NS_IMETHOD SetPaperSizeUnit(int16_t aPaperSizeUnit) override;
NS_IMETHOD SetScaling(double aScaling) override;
NS_IMETHOD SetToFileName(const char16_t * aToFileName) override;
NS_IMETHOD GetOrientation(int32_t *aOrientation) override;
NS_IMETHOD SetOrientation(int32_t aOrientation) override;
NS_IMETHOD SetUnwriteableMarginTop(double aUnwriteableMarginTop) override;
NS_IMETHOD SetUnwriteableMarginLeft(double aUnwriteableMarginLeft) override;
NS_IMETHOD SetUnwriteableMarginBottom(double aUnwriteableMarginBottom) override;
NS_IMETHOD SetUnwriteableMarginRight(double aUnwriteableMarginRight) override;
void SetAdjustedPaperSize(double aWidth, double aHeight);
void GetAdjustedPaperSize(double *aWidth, double *aHeight);
nsresult SetCocoaPaperSize(double aWidth, double aHeight);
protected:
virtual ~nsPrintSettingsX();
@ -63,6 +90,8 @@ protected:
nsresult _Clone(nsIPrintSettings **_retval) override;
nsresult _Assign(nsIPrintSettings *aPS) override;
int GetCocoaUnit(int16_t aGeckoUnit);
// The out param has a ref count of 1 on return so caller needs to PMRelase() when done.
OSStatus CreateDefaultPageFormat(PMPrintSession aSession, PMPageFormat& outFormat);
OSStatus CreateDefaultPrintSettings(PMPrintSession aSession, PMPrintSettings& outSettings);

Просмотреть файл

@ -254,8 +254,13 @@ NS_IMETHODIMP nsPrintSettingsX::SetPaperHeight(double aPaperHeight)
NS_IMETHODIMP
nsPrintSettingsX::GetEffectivePageSize(double *aWidth, double *aHeight)
{
*aWidth = NS_INCHES_TO_TWIPS(mAdjustedPaperWidth / mWidthScale);
*aHeight = NS_INCHES_TO_TWIPS(mAdjustedPaperHeight / mHeightScale);
if (kPaperSizeInches == GetCocoaUnit(mPaperSizeUnit)) {
*aWidth = NS_INCHES_TO_TWIPS(mAdjustedPaperWidth / mWidthScale);
*aHeight = NS_INCHES_TO_TWIPS(mAdjustedPaperHeight / mHeightScale);
} else {
*aWidth = NS_MILLIMETERS_TO_TWIPS(mAdjustedPaperWidth / mWidthScale);
*aHeight = NS_MILLIMETERS_TO_TWIPS(mAdjustedPaperHeight / mHeightScale);
}
return NS_OK;
}
@ -270,3 +275,221 @@ void nsPrintSettingsX::GetAdjustedPaperSize(double *aWidth, double *aHeight)
*aWidth = mAdjustedPaperWidth;
*aHeight = mAdjustedPaperHeight;
}
NS_IMETHODIMP
nsPrintSettingsX::SetPaperSizeUnit(int16_t aPaperSizeUnit)
{
mPaperSizeUnit = aPaperSizeUnit;
return NS_OK;
}
NS_IMETHODIMP
nsPrintSettingsX::SetScaling(double aScaling)
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
NSMutableDictionary* printInfoDict = [mPrintInfo dictionary];
[printInfoDict setObject: [NSNumber numberWithFloat: aScaling]
forKey: NSPrintScalingFactor];
NSPrintInfo* newPrintInfo =
[[NSPrintInfo alloc] initWithDictionary: printInfoDict];
if (NS_WARN_IF(!newPrintInfo)) {
return NS_ERROR_OUT_OF_MEMORY;
}
SetCocoaPrintInfo(newPrintInfo);
[newPrintInfo release];
return NS_OK;
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
}
NS_IMETHODIMP
nsPrintSettingsX::SetToFileName(const char16_t *aToFileName)
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
NSMutableDictionary* printInfoDict = [mPrintInfo dictionary];
nsString filename = nsDependentString(aToFileName);
NSURL* jobSavingURL =
[NSURL fileURLWithPath: nsCocoaUtils::ToNSString(filename)];
if (jobSavingURL) {
[printInfoDict setObject: NSPrintSaveJob forKey: NSPrintJobDisposition];
[printInfoDict setObject: jobSavingURL forKey: NSPrintJobSavingURL];
}
NSPrintInfo* newPrintInfo =
[[NSPrintInfo alloc] initWithDictionary: printInfoDict];
if (NS_WARN_IF(!newPrintInfo)) {
return NS_ERROR_OUT_OF_MEMORY;
}
SetCocoaPrintInfo(newPrintInfo);
[newPrintInfo release];
return NS_OK;
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
}
NS_IMETHODIMP
nsPrintSettingsX::GetOrientation(int32_t *aOrientation)
{
if ([mPrintInfo orientation] == NS_PAPER_ORIENTATION_PORTRAIT) {
*aOrientation = nsIPrintSettings::kPortraitOrientation;
} else {
*aOrientation = nsIPrintSettings::kLandscapeOrientation;
}
return NS_OK;
}
NS_IMETHODIMP
nsPrintSettingsX::SetOrientation(int32_t aOrientation)
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
NSMutableDictionary* printInfoDict = [mPrintInfo dictionary];
if (aOrientation == nsIPrintSettings::kPortraitOrientation) {
[printInfoDict setObject: [NSNumber numberWithInt: NS_PAPER_ORIENTATION_PORTRAIT]
forKey: NSPrintOrientation];
} else {
[printInfoDict setObject: [NSNumber numberWithInt: NS_PAPER_ORIENTATION_LANDSCAPE]
forKey: NSPrintOrientation];
}
NSPrintInfo* newPrintInfo =
[[NSPrintInfo alloc] initWithDictionary: printInfoDict];
if (NS_WARN_IF(!newPrintInfo)) {
return NS_ERROR_OUT_OF_MEMORY;
}
SetCocoaPrintInfo(newPrintInfo);
[newPrintInfo release];
return NS_OK;
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
}
NS_IMETHODIMP
nsPrintSettingsX::SetUnwriteableMarginTop(double aUnwriteableMarginTop)
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
nsPrintSettings::SetUnwriteableMarginTop(aUnwriteableMarginTop);
NSMutableDictionary* printInfoDict = [mPrintInfo dictionary];
[printInfoDict setObject : [NSNumber numberWithDouble: aUnwriteableMarginTop]
forKey : NSPrintTopMargin];
NSPrintInfo* newPrintInfo =
[[NSPrintInfo alloc] initWithDictionary: printInfoDict];
if (NS_WARN_IF(!newPrintInfo)) {
return NS_ERROR_OUT_OF_MEMORY;
}
SetCocoaPrintInfo(newPrintInfo);
[newPrintInfo release];
return NS_OK;
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
}
NS_IMETHODIMP
nsPrintSettingsX::SetUnwriteableMarginLeft(double aUnwriteableMarginLeft)
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
nsPrintSettings::SetUnwriteableMarginLeft(aUnwriteableMarginLeft);
NSMutableDictionary* printInfoDict = [mPrintInfo dictionary];
[printInfoDict setObject : [NSNumber numberWithDouble: aUnwriteableMarginLeft]
forKey : NSPrintLeftMargin];
NSPrintInfo* newPrintInfo =
[[NSPrintInfo alloc] initWithDictionary: printInfoDict];
if (NS_WARN_IF(!newPrintInfo)) {
return NS_ERROR_OUT_OF_MEMORY;
}
SetCocoaPrintInfo(newPrintInfo);
[newPrintInfo release];
return NS_OK;
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
}
NS_IMETHODIMP
nsPrintSettingsX::SetUnwriteableMarginBottom(double aUnwriteableMarginBottom)
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
nsPrintSettings::SetUnwriteableMarginBottom(aUnwriteableMarginBottom);
NSMutableDictionary* printInfoDict = [mPrintInfo dictionary];
[printInfoDict setObject : [NSNumber numberWithDouble: aUnwriteableMarginBottom]
forKey : NSPrintBottomMargin];
NSPrintInfo* newPrintInfo =
[[NSPrintInfo alloc] initWithDictionary: printInfoDict];
if (NS_WARN_IF(!newPrintInfo)) {
return NS_ERROR_OUT_OF_MEMORY;
}
SetCocoaPrintInfo(newPrintInfo);
[newPrintInfo release];
return NS_OK;
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
}
NS_IMETHODIMP
nsPrintSettingsX::SetUnwriteableMarginRight(double aUnwriteableMarginRight)
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
nsPrintSettings::SetUnwriteableMarginRight(aUnwriteableMarginRight);
NSMutableDictionary* printInfoDict = [mPrintInfo dictionary];
[printInfoDict setObject : [NSNumber numberWithDouble: aUnwriteableMarginRight]
forKey : NSPrintRightMargin];
NSPrintInfo* newPrintInfo =
[[NSPrintInfo alloc] initWithDictionary: printInfoDict];
if (NS_WARN_IF(!newPrintInfo)) {
return NS_ERROR_OUT_OF_MEMORY;
}
SetCocoaPrintInfo(newPrintInfo);
[newPrintInfo release];
return NS_OK;
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
}
int
nsPrintSettingsX::GetCocoaUnit(int16_t aGeckoUnit)
{
if (aGeckoUnit == kPaperSizeMillimeters)
return kPaperSizeMillimeters;
else
return kPaperSizeInches;
}
nsresult nsPrintSettingsX::SetCocoaPaperSize(double aWidth, double aHeight)
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
NSSize paperSize;
NSMutableDictionary* printInfoDict = [mPrintInfo dictionary];
if ([mPrintInfo orientation] == NS_PAPER_ORIENTATION_PORTRAIT) {
// switch widths and heights
paperSize = NSMakeSize(aWidth, aHeight);
[printInfoDict setObject: [NSValue valueWithSize: paperSize]
forKey: NSPrintPaperSize];
} else {
paperSize = NSMakeSize(aHeight, aWidth);
[printInfoDict setObject: [NSValue valueWithSize: paperSize]
forKey: NSPrintPaperSize];
}
NSPrintInfo* newPrintInfo =
[[NSPrintInfo alloc] initWithDictionary: printInfoDict];
if (NS_WARN_IF(!newPrintInfo)) {
return NS_ERROR_OUT_OF_MEMORY;
}
SetCocoaPrintInfo(newPrintInfo);
[newPrintInfo release];
return NS_OK;
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
}

Просмотреть файл

@ -11,11 +11,6 @@
* on machines with several LSPs.
*/
#if _WIN32_WINNT < 0x0600
// Redefining _WIN32_WINNT for some Vista APIs that we call
#undef _WIN32_WINNT
#define _WIN32_WINNT 0x0600
#endif
#include "nsICrashReporter.h"
#include "nsISupportsImpl.h"
#include "nsServiceManagerUtils.h"

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше