Merge mozilla-central to autoland. a=merge CLOSED TREE

This commit is contained in:
Csoregi Natalia 2018-02-01 20:13:43 +02:00
Родитель 3ebdbe2a5b 5a9ee59e75
Коммит d8b0109aae
95 изменённых файлов: 1254 добавлений и 491 удалений

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

@ -1106,14 +1106,12 @@ pref("security.sandbox.content.read_path_whitelist", "");
pref("security.sandbox.content.syscall_whitelist", "");
#endif
#if defined(XP_MACOSX) || defined(XP_WIN)
#if defined(MOZ_SANDBOX) && defined(MOZ_CONTENT_SANDBOX)
// ID (a UUID when set by gecko) that is used to form the name of a
// sandbox-writable temporary directory to be used by content processes
// when a temporary writable file is required in a level 1 sandbox.
pref("security.sandbox.content.tempDirSuffix", "");
#endif
#endif
#if defined(MOZ_SANDBOX)
// This pref determines if messages relevant to sandbox violations are

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

@ -5,7 +5,7 @@ code, and optionally help with indentation.
# Upgrade
Currently used version is 5.33.0. To upgrade: download a new version of
Currently used version is 5.34.0. To upgrade: download a new version of
CodeMirror from the project's page [1] and replace all JavaScript and
CSS files inside the codemirror directory [2].

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

@ -129,8 +129,8 @@
else
curType = "skip";
} else if (identical && cur.ch > 1 && triples.indexOf(ch) >= 0 &&
cm.getRange(Pos(cur.line, cur.ch - 2), cur) == ch + ch &&
(cur.ch <= 2 || cm.getRange(Pos(cur.line, cur.ch - 3), Pos(cur.line, cur.ch - 2)) != ch)) {
cm.getRange(Pos(cur.line, cur.ch - 2), cur) == ch + ch) {
if (cur.ch > 2 && /\bstring/.test(cm.getTokenTypeAt(Pos(cur.line, cur.ch - 2)))) return CodeMirror.Pass;
curType = "addFour";
} else if (identical) {
var prev = cur.ch == 0 ? " " : cm.getRange(Pos(cur.line, cur.ch - 1), cur)

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

@ -102,18 +102,23 @@
}
}
var currentlyHighlighted = null;
function doMatchBrackets(cm) {
cm.operation(function() {
if (currentlyHighlighted) {currentlyHighlighted(); currentlyHighlighted = null;}
currentlyHighlighted = matchBrackets(cm, false, cm.state.matchBrackets);
if (cm.state.matchBrackets.currentlyHighlighted) {
cm.state.matchBrackets.currentlyHighlighted();
cm.state.matchBrackets.currentlyHighlighted = null;
}
cm.state.matchBrackets.currentlyHighlighted = matchBrackets(cm, false, cm.state.matchBrackets);
});
}
CodeMirror.defineOption("matchBrackets", false, function(cm, val, old) {
if (old && old != CodeMirror.Init) {
cm.off("cursorActivity", doMatchBrackets);
if (currentlyHighlighted) {currentlyHighlighted(); currentlyHighlighted = null;}
if (cm.state.matchBrackets && cm.state.matchBrackets.currentlyHighlighted) {
cm.state.matchBrackets.currentlyHighlighted();
cm.state.matchBrackets.currentlyHighlighted = null;
}
}
if (val) {
cm.state.matchBrackets = typeof val == "object" ? val : {};

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

@ -138,7 +138,7 @@
var iter = new Iter(cm, start.line, 0);
for (;;) {
var openTag = toNextTag(iter), end;
if (!openTag || iter.line != start.line || !(end = toTagEnd(iter))) return;
if (!openTag || !(end = toTagEnd(iter)) || iter.line != start.line) return;
if (!openTag[1] && end != "selfClose") {
var startPos = Pos(iter.line, iter.ch);
var endPos = findMatchingClose(iter, openTag[2]);

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

@ -6815,11 +6815,11 @@ var CodeMirror =
}
var keyNames = {
3: "Enter", 8: "Backspace", 9: "Tab", 13: "Enter", 16: "Shift", 17: "Ctrl", 18: "Alt",
3: "Pause", 8: "Backspace", 9: "Tab", 13: "Enter", 16: "Shift", 17: "Ctrl", 18: "Alt",
19: "Pause", 20: "CapsLock", 27: "Esc", 32: "Space", 33: "PageUp", 34: "PageDown", 35: "End",
36: "Home", 37: "Left", 38: "Up", 39: "Right", 40: "Down", 44: "PrintScrn", 45: "Insert",
46: "Delete", 59: ";", 61: "=", 91: "Mod", 92: "Mod", 93: "Mod",
106: "*", 107: "=", 109: "-", 110: ".", 111: "/", 127: "Delete",
106: "*", 107: "=", 109: "-", 110: ".", 111: "/", 127: "Delete", 145: "ScrollLock",
173: "-", 186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\",
221: "]", 222: "'", 63232: "Up", 63233: "Down", 63234: "Left", 63235: "Right", 63272: "Delete",
63273: "Home", 63275: "End", 63276: "PageUp", 63277: "PageDown", 63302: "Insert"
@ -6966,6 +6966,9 @@ var CodeMirror =
if (presto && event.keyCode == 34 && event["char"]) { return false }
var name = keyNames[event.keyCode]
if (name == null || event.altGraphKey) { return false }
// Ctrl-ScrollLock has keyCode 3, same as Ctrl-Pause,
// so we'll use event.code when available (Chrome 48+, FF 38+, Safari 10.1+)
if (event.keyCode == 3 && event.code) { name = event.code }
return addModifierNames(name, event, noShift)
}
@ -8255,7 +8258,7 @@ var CodeMirror =
var paste = cm.state.pasteIncoming || origin == "paste"
var textLines = splitLinesAuto(inserted), multiPaste = null
// When pasing N lines into N selections, insert one line per selection
// When pasting N lines into N selections, insert one line per selection
if (paste && sel.ranges.length > 1) {
if (lastCopied && lastCopied.text.join("\n") == inserted) {
if (sel.ranges.length % lastCopied.text.length == 0) {
@ -9889,7 +9892,7 @@ var CodeMirror =
addLegacyProps(CodeMirror)
CodeMirror.version = "5.33.0"
CodeMirror.version = "5.34.0"
return CodeMirror;
@ -10571,18 +10574,23 @@ var CodeMirror =
}
}
var currentlyHighlighted = null;
function doMatchBrackets(cm) {
cm.operation(function() {
if (currentlyHighlighted) {currentlyHighlighted(); currentlyHighlighted = null;}
currentlyHighlighted = matchBrackets(cm, false, cm.state.matchBrackets);
if (cm.state.matchBrackets.currentlyHighlighted) {
cm.state.matchBrackets.currentlyHighlighted();
cm.state.matchBrackets.currentlyHighlighted = null;
}
cm.state.matchBrackets.currentlyHighlighted = matchBrackets(cm, false, cm.state.matchBrackets);
});
}
CodeMirror.defineOption("matchBrackets", false, function(cm, val, old) {
if (old && old != CodeMirror.Init) {
cm.off("cursorActivity", doMatchBrackets);
if (currentlyHighlighted) {currentlyHighlighted(); currentlyHighlighted = null;}
if (cm.state.matchBrackets && cm.state.matchBrackets.currentlyHighlighted) {
cm.state.matchBrackets.currentlyHighlighted();
cm.state.matchBrackets.currentlyHighlighted = null;
}
}
if (val) {
cm.state.matchBrackets = typeof val == "object" ? val : {};
@ -10744,8 +10752,8 @@ var CodeMirror =
else
curType = "skip";
} else if (identical && cur.ch > 1 && triples.indexOf(ch) >= 0 &&
cm.getRange(Pos(cur.line, cur.ch - 2), cur) == ch + ch &&
(cur.ch <= 2 || cm.getRange(Pos(cur.line, cur.ch - 3), Pos(cur.line, cur.ch - 2)) != ch)) {
cm.getRange(Pos(cur.line, cur.ch - 2), cur) == ch + ch) {
if (cur.ch > 2 && /\bstring/.test(cm.getTokenTypeAt(Pos(cur.line, cur.ch - 2)))) return CodeMirror.Pass;
curType = "addFour";
} else if (identical) {
var prev = cur.ch == 0 ? " " : cm.getRange(Pos(cur.line, cur.ch - 1), cur)
@ -11375,15 +11383,14 @@ var CodeMirror =
if (type == "for") return cont(pushlex("form"), forspec, statement, poplex);
if (type == "class" || (isTS && value == "interface")) { cx.marked = "keyword"; return cont(pushlex("form"), className, poplex); }
if (type == "variable") {
if (isTS && value == "type") {
cx.marked = "keyword"
return cont(typeexpr, expect("operator"), typeexpr, expect(";"));
} else if (isTS && value == "declare") {
if (isTS && value == "declare") {
cx.marked = "keyword"
return cont(statement)
} else if (isTS && (value == "module" || value == "enum") && cx.stream.match(/^\s*\w/, false)) {
} else if (isTS && (value == "module" || value == "enum" || value == "type") && cx.stream.match(/^\s*\w/, false)) {
cx.marked = "keyword"
return cont(pushlex("form"), pattern, expect("{"), pushlex("}"), block, poplex, poplex)
if (value == "enum") return cont(enumdef);
else if (value == "type") return cont(typeexpr, expect("operator"), typeexpr, expect(";"));
else return cont(pushlex("form"), pattern, expect("{"), pushlex("}"), block, poplex, poplex)
} else if (isTS && value == "namespace") {
cx.marked = "keyword"
return cont(pushlex("form"), expression, block, poplex)
@ -11638,7 +11645,8 @@ var CodeMirror =
function maybeTypeDefault(_, value) {
if (value == "=") return cont(typeexpr)
}
function vardef() {
function vardef(_, value) {
if (value == "enum") {cx.marked = "keyword"; return cont(enumdef)}
return pass(pattern, maybetype, maybeAssign, vardefCont);
}
function pattern(type, value) {
@ -11710,8 +11718,10 @@ var CodeMirror =
}
function classNameAfter(type, value) {
if (value == "<") return cont(pushlex(">"), commasep(typeparam, ">"), poplex, classNameAfter)
if (value == "extends" || value == "implements" || (isTS && type == ","))
if (value == "extends" || value == "implements" || (isTS && type == ",")) {
if (value == "implements") cx.marked = "keyword";
return cont(isTS ? typeexpr : expression, classNameAfter);
}
if (type == "{") return cont(pushlex("}"), classBody, poplex);
}
function classBody(type, value) {
@ -11775,6 +11785,12 @@ var CodeMirror =
if (type == "]") return cont();
return pass(commasep(expressionNoComma, "]"));
}
function enumdef() {
return pass(pushlex("form"), pattern, expect("{"), pushlex("}"), commasep(enummember, "}"), poplex, poplex)
}
function enummember() {
return pass(pattern, maybeAssign);
}
function isContinuedStatement(state, textAfter) {
return state.lastType == "operator" || state.lastType == "," ||
@ -14643,7 +14659,7 @@ var CodeMirror =
intendSwitch: false,
indentStatements: false,
multiLineStrings: true,
number: /^(?:0x[a-f\d_]+|0b[01_]+|(?:[\d_]+\.?\d*|\.\d+)(?:e[-+]?[\d_]+)?)(u|ll?|l|f)?/i,
number: /^(?:0x[a-f\d_]+|0b[01_]+|(?:[\d_]+(\.\d+)?|\.\d+)(?:e[-+]?[\d_]+)?)(u|ll?|l|f)?/i,
blockKeywords: words("catch class do else finally for if where try while enum"),
defKeywords: words("class val var object interface fun"),
atoms: words("true false null this"),
@ -21198,7 +21214,7 @@ var CodeMirror =
var marks = cm.state.sublimeBookmarks || (cm.state.sublimeBookmarks = []);
for (var i = 0; i < ranges.length; i++) {
var from = ranges[i].from(), to = ranges[i].to();
var found = cm.findMarks(from, to);
var found = ranges[i].empty() ? cm.findMarksAt(from) : cm.findMarks(from, to);
for (var j = 0; j < found.length; j++) {
if (found[j].sublimeBookmark) {
found[j].clear();
@ -21979,7 +21995,7 @@ var CodeMirror =
var iter = new Iter(cm, start.line, 0);
for (;;) {
var openTag = toNextTag(iter), end;
if (!openTag || iter.line != start.line || !(end = toTagEnd(iter))) return;
if (!openTag || !(end = toTagEnd(iter)) || iter.line != start.line) return;
if (!openTag[1] && end != "selfClose") {
var startPos = Pos(iter.line, iter.ch);
var endPos = findMatchingClose(iter, openTag[2]);

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

@ -382,7 +382,7 @@
var marks = cm.state.sublimeBookmarks || (cm.state.sublimeBookmarks = []);
for (var i = 0; i < ranges.length; i++) {
var from = ranges[i].from(), to = ranges[i].to();
var found = cm.findMarks(from, to);
var found = ranges[i].empty() ? cm.findMarksAt(from) : cm.findMarks(from, to);
for (var j = 0; j < found.length; j++) {
if (found[j].sublimeBookmark) {
found[j].clear();

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

@ -6573,11 +6573,11 @@ function onResize(cm) {
}
var keyNames = {
3: "Enter", 8: "Backspace", 9: "Tab", 13: "Enter", 16: "Shift", 17: "Ctrl", 18: "Alt",
3: "Pause", 8: "Backspace", 9: "Tab", 13: "Enter", 16: "Shift", 17: "Ctrl", 18: "Alt",
19: "Pause", 20: "CapsLock", 27: "Esc", 32: "Space", 33: "PageUp", 34: "PageDown", 35: "End",
36: "Home", 37: "Left", 38: "Up", 39: "Right", 40: "Down", 44: "PrintScrn", 45: "Insert",
46: "Delete", 59: ";", 61: "=", 91: "Mod", 92: "Mod", 93: "Mod",
106: "*", 107: "=", 109: "-", 110: ".", 111: "/", 127: "Delete",
106: "*", 107: "=", 109: "-", 110: ".", 111: "/", 127: "Delete", 145: "ScrollLock",
173: "-", 186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\",
221: "]", 222: "'", 63232: "Up", 63233: "Down", 63234: "Left", 63235: "Right", 63272: "Delete",
63273: "Home", 63275: "End", 63276: "PageUp", 63277: "PageDown", 63302: "Insert"
@ -6724,6 +6724,9 @@ function keyName(event, noShift) {
if (presto && event.keyCode == 34 && event["char"]) { return false }
var name = keyNames[event.keyCode]
if (name == null || event.altGraphKey) { return false }
// Ctrl-ScrollLock has keyCode 3, same as Ctrl-Pause,
// so we'll use event.code when available (Chrome 48+, FF 38+, Safari 10.1+)
if (event.keyCode == 3 && event.code) { name = event.code }
return addModifierNames(name, event, noShift)
}
@ -8013,7 +8016,7 @@ function applyTextInput(cm, inserted, deleted, sel, origin) {
var paste = cm.state.pasteIncoming || origin == "paste"
var textLines = splitLinesAuto(inserted), multiPaste = null
// When pasing N lines into N selections, insert one line per selection
// When pasting N lines into N selections, insert one line per selection
if (paste && sel.ranges.length > 1) {
if (lastCopied && lastCopied.text.join("\n") == inserted) {
if (sel.ranges.length % lastCopied.text.length == 0) {
@ -9647,7 +9650,7 @@ CodeMirror.fromTextArea = fromTextArea
addLegacyProps(CodeMirror)
CodeMirror.version = "5.33.0"
CodeMirror.version = "5.34.0"
return CodeMirror;

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

@ -617,7 +617,7 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
intendSwitch: false,
indentStatements: false,
multiLineStrings: true,
number: /^(?:0x[a-f\d_]+|0b[01_]+|(?:[\d_]+\.?\d*|\.\d+)(?:e[-+]?[\d_]+)?)(u|ll?|l|f)?/i,
number: /^(?:0x[a-f\d_]+|0b[01_]+|(?:[\d_]+(\.\d+)?|\.\d+)(?:e[-+]?[\d_]+)?)(u|ll?|l|f)?/i,
blockKeywords: words("catch class do else finally for if where try while enum"),
defKeywords: words("class val var object interface fun"),
atoms: words("true false null this"),

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

@ -345,15 +345,14 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
if (type == "for") return cont(pushlex("form"), forspec, statement, poplex);
if (type == "class" || (isTS && value == "interface")) { cx.marked = "keyword"; return cont(pushlex("form"), className, poplex); }
if (type == "variable") {
if (isTS && value == "type") {
cx.marked = "keyword"
return cont(typeexpr, expect("operator"), typeexpr, expect(";"));
} else if (isTS && value == "declare") {
if (isTS && value == "declare") {
cx.marked = "keyword"
return cont(statement)
} else if (isTS && (value == "module" || value == "enum") && cx.stream.match(/^\s*\w/, false)) {
} else if (isTS && (value == "module" || value == "enum" || value == "type") && cx.stream.match(/^\s*\w/, false)) {
cx.marked = "keyword"
return cont(pushlex("form"), pattern, expect("{"), pushlex("}"), block, poplex, poplex)
if (value == "enum") return cont(enumdef);
else if (value == "type") return cont(typeexpr, expect("operator"), typeexpr, expect(";"));
else return cont(pushlex("form"), pattern, expect("{"), pushlex("}"), block, poplex, poplex)
} else if (isTS && value == "namespace") {
cx.marked = "keyword"
return cont(pushlex("form"), expression, block, poplex)
@ -608,7 +607,8 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
function maybeTypeDefault(_, value) {
if (value == "=") return cont(typeexpr)
}
function vardef() {
function vardef(_, value) {
if (value == "enum") {cx.marked = "keyword"; return cont(enumdef)}
return pass(pattern, maybetype, maybeAssign, vardefCont);
}
function pattern(type, value) {
@ -680,8 +680,10 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
}
function classNameAfter(type, value) {
if (value == "<") return cont(pushlex(">"), commasep(typeparam, ">"), poplex, classNameAfter)
if (value == "extends" || value == "implements" || (isTS && type == ","))
if (value == "extends" || value == "implements" || (isTS && type == ",")) {
if (value == "implements") cx.marked = "keyword";
return cont(isTS ? typeexpr : expression, classNameAfter);
}
if (type == "{") return cont(pushlex("}"), classBody, poplex);
}
function classBody(type, value) {
@ -745,6 +747,12 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
if (type == "]") return cont();
return pass(commasep(expressionNoComma, "]"));
}
function enumdef() {
return pass(pushlex("form"), pattern, expect("{"), pushlex("}"), commasep(enummember, "}"), poplex, poplex)
}
function enummember() {
return pass(pattern, maybeAssign);
}
function isContinuedStatement(state, textAfter) {
return state.lastType == "operator" || state.lastType == "," ||

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

@ -383,6 +383,16 @@
" }",
"}")
TS("type as variable",
"[variable type] [operator =] [variable x] [keyword as] [type Bar];");
TS("enum body",
"[keyword export] [keyword const] [keyword enum] [def CodeInspectionResultType] {",
" [def ERROR] [operator =] [string 'problem_type_error'],",
" [def WARNING] [operator =] [string 'problem_type_warning'],",
" [def META],",
"}")
var jsonld_mode = CodeMirror.getMode(
{indentUnit: 2},
{name: "javascript", jsonld: true}

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

@ -726,7 +726,10 @@ _cairo_ft_unscaled_font_lock_face (cairo_ft_unscaled_font_t *unscaled)
}
if (unscaled->var_coords) {
typedef FT_UInt (*SetCoordsFunc)(FT_Face, FT_UInt, FT_Fixed*);
#if MOZ_TREE_FREETYPE
FT_Set_Var_Design_Coordinates(face, unscaled->num_var_coords, unscaled->var_coords);
#else
typedef FT_Error (*SetCoordsFunc)(FT_Face, FT_UInt, FT_Fixed*);
static SetCoordsFunc setCoords;
static cairo_bool_t firstTime = TRUE;
if (firstTime) {
@ -736,6 +739,7 @@ _cairo_ft_unscaled_font_lock_face (cairo_ft_unscaled_font_t *unscaled)
if (setCoords) {
(*setCoords)(face, unscaled->num_var_coords, unscaled->var_coords);
}
#endif
}
unscaled->face = face;

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

@ -139,6 +139,8 @@ public:
#endif // defined(MOZ_WIDGET_ANDROID)
};
bool CreateConfig(EGLConfig* config, int32_t depth, bool enableDepthBuffer);
} // namespace gl
} // namespace mozilla

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

@ -84,9 +84,6 @@ using namespace mozilla::widget;
static bool
CreateConfig(EGLConfig* aConfig, bool aEnableDepthBuffer);
static bool
CreateConfig(EGLConfig* aConfig, int32_t depth, bool aEnableDepthBuffer);
// append three zeros at the end of attribs list to work around
// EGL implementation bugs that iterate until they find 0, instead of
// EGL_NONE. See bug 948406.
@ -634,7 +631,7 @@ static const EGLint kEGLConfigAttribsRGBA32[] = {
EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS
};
static bool
bool
CreateConfig(EGLConfig* aConfig, int32_t depth, bool aEnableDepthBuffer)
{
EGLConfig configs[64];

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

@ -53,6 +53,12 @@
#define LOCAL_EGL_PLATFORM_ANGLE_DEVICE_TYPE_REFERENCE_ANGLE 0x320C
#define LOCAL_EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE 0x320F
// EGL_ANGLE_d3d_texture_client_buffer
#define LOCAL_EGL_D3D_TEXTURE_ANGLE 0x33A3
// EGL_ANGLE_flexible_surface_compatibility
#define LOCAL_EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE 0x33A6
// EGL_ANGLE_experimental_present_path
#define LOCAL_EGL_EXPERIMENTAL_PRESENT_PATH_ANGLE 0x33A4
#define LOCAL_EGL_EXPERIMENTAL_PRESENT_PATH_FAST_ANGLE 0x33A9

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

@ -137,13 +137,10 @@ PaintThread::CalculatePaintWorkerCount()
int32_t workerCount = gfxPrefs::LayersOMTPPaintWorkers();
// If not manually specified, default to (cpuCores * 3) / 4
// If not manually specified, default to (cpuCores * 3) / 4, and clamp
// between 1 and 4. If a user wants more, they can manually specify it
if (workerCount < 1) {
workerCount = std::max((cpuCores * 3) / 4, 1);
if (workerCount > 32) {
workerCount = 32;
}
workerCount = std::min(std::max((cpuCores * 3) / 4, 1), 4);
}
return workerCount;

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

@ -420,6 +420,13 @@ D3D11Checks::DoesNV12Work(ID3D11Device* device)
return false;
}
HRESULT hr;
UINT formatSupport;
hr = device->CheckFormatSupport(DXGI_FORMAT_NV12, &formatSupport);
if (FAILED(hr) || !(formatSupport & D3D11_FORMAT_SUPPORT_TEXTURE2D)) {
return false;
}
nsString version;
nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
if (gfxInfo) {

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

@ -226,7 +226,10 @@ gfxFT2FontBase::InitMetrics()
if (!mStyle.variationSettings.IsEmpty()) {
SetupVarCoords(face, mStyle.variationSettings, &mCoords);
if (!mCoords.IsEmpty()) {
typedef FT_UInt (*SetCoordsFunc)(FT_Face, FT_UInt, FT_Fixed*);
#if MOZ_TREE_FREETYPE
FT_Set_Var_Design_Coordinates(face, mCoords.Length(), mCoords.Elements());
#else
typedef FT_Error (*SetCoordsFunc)(FT_Face, FT_UInt, FT_Fixed*);
static SetCoordsFunc setCoords;
static bool firstTime = true;
if (firstTime) {
@ -237,6 +240,7 @@ gfxFT2FontBase::InitMetrics()
if (setCoords) {
(*setCoords)(face, mCoords.Length(), mCoords.Elements());
}
#endif
}
}
@ -625,8 +629,12 @@ gfxFT2FontBase::SetupVarCoords(FT_Face aFace,
aCoords->TruncateLength(0);
if (aFace->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS) {
typedef FT_Error (*GetVarFunc)(FT_Face, FT_MM_Var**);
static GetVarFunc getVar;
typedef FT_Error (*DoneVarFunc)(FT_Library, FT_MM_Var*);
#if MOZ_TREE_FREETYPE
GetVarFunc getVar = &FT_Get_MM_Var;
DoneVarFunc doneVar = &FT_Done_MM_Var;
#else
static GetVarFunc getVar;
static DoneVarFunc doneVar;
static bool firstTime = true;
if (firstTime) {
@ -634,6 +642,7 @@ gfxFT2FontBase::SetupVarCoords(FT_Face aFace,
getVar = (GetVarFunc)dlsym(RTLD_DEFAULT, "FT_Get_MM_Var");
doneVar = (DoneVarFunc)dlsym(RTLD_DEFAULT, "FT_Done_MM_Var");
}
#endif
FT_MM_Var* ftVar;
if (getVar && FT_Err_Ok == (*getVar)(aFace, &ftVar)) {
for (unsigned i = 0; i < ftVar->num_axis; ++i) {

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

@ -23,10 +23,12 @@
#include FT_FREETYPE_H
#include FT_TRUETYPE_TAGS_H
#include FT_TRUETYPE_TABLES_H
#include FT_MULTIPLE_MASTERS_H
#include "cairo-ft.h"
#include "gfxFT2FontList.h"
#include "gfxFT2Fonts.h"
#include "gfxFT2Utils.h"
#include "gfxUserFontSet.h"
#include "gfxFontUtils.h"
@ -105,7 +107,7 @@ public:
cursor.Copy(&bufSize);
NS_ASSERTION(bufSize == item->RealSize(),
"error reading bundled font");
mDataLength = bufSize;
mFace = Factory::NewFTFaceFromData(nullptr, mFontDataBuf, bufSize, aFontEntry->mFTFontIndex);
if (!mFace) {
NS_WARNING("failed to create freetype face");
@ -144,6 +146,7 @@ public:
}
const uint8_t* FontData() const { return mFontDataBuf; }
uint32_t DataLength() const { return mDataLength; }
private:
FT_Face mFace;
@ -151,6 +154,7 @@ private:
// or null for fonts instantiated from a file.
// If non-null, this must survive as long as the
// FT_Face.
uint32_t mDataLength; // Size of mFontDataBuf, if present.
bool mOwnsFace;
};
@ -167,7 +171,7 @@ private:
cairo_scaled_font_t *
FT2FontEntry::CreateScaledFont(const gfxFontStyle *aStyle)
{
cairo_font_face_t *cairoFace = CairoFontFace();
cairo_font_face_t *cairoFace = CairoFontFace(aStyle);
if (!cairoFace) {
return nullptr;
}
@ -274,7 +278,7 @@ FT2FontEntry::CreateFontEntry(const nsAString& aFontName,
// as it's not guaranteed that the face has valid names (bug 737315)
FT2FontEntry* fe =
FT2FontEntry::CreateFontEntry(face, nullptr, 0, aFontName,
aFontData);
aFontData, aLength);
if (fe) {
fe->mStyle = aStyle;
fe->mWeight = aWeight;
@ -286,8 +290,8 @@ FT2FontEntry::CreateFontEntry(const nsAString& aFontName,
class FTUserFontData {
public:
FTUserFontData(FT_Face aFace, const uint8_t* aData)
: mFace(aFace), mFontData(aData)
FTUserFontData(FT_Face aFace, const uint8_t* aData, uint32_t aLength)
: mFace(aFace), mFontData(aData), mLength(aLength)
{
}
@ -300,10 +304,12 @@ public:
}
const uint8_t *FontData() const { return mFontData; }
uint32_t Length() const { return mLength; }
private:
FT_Face mFace;
const uint8_t *mFontData;
uint32_t mLength;
};
static void
@ -376,7 +382,8 @@ FT2FontEntry*
FT2FontEntry::CreateFontEntry(FT_Face aFace,
const char* aFilename, uint8_t aIndex,
const nsAString& aName,
const uint8_t* aFontData)
const uint8_t* aFontData,
uint32_t aLength)
{
FT2FontEntry *fe = new FT2FontEntry(aName);
fe->mStyle = (FTFaceIsItalic(aFace) ?
@ -391,7 +398,7 @@ FT2FontEntry::CreateFontEntry(FT_Face aFace,
FT_LOAD_DEFAULT :
(FT_LOAD_NO_AUTOHINT | FT_LOAD_NO_HINTING);
fe->mFontFace = cairo_ft_font_face_create_for_ft_face(aFace, flags, nullptr, 0);
FTUserFontData *userFontData = new FTUserFontData(aFace, aFontData);
FTUserFontData *userFontData = new FTUserFontData(aFace, aFontData, aLength);
cairo_font_face_set_user_data(fe->mFontFace, &sFTUserFontDataKey,
userFontData, FTFontDestroyFunc);
}
@ -423,22 +430,67 @@ gfxFT2Font::GetFontEntry()
}
cairo_font_face_t *
FT2FontEntry::CairoFontFace()
FT2FontEntry::CairoFontFace(const gfxFontStyle* aStyle)
{
// Create our basic (no-variations) mFontFace if not already present;
// this also ensures we have mFTFace available.
if (!mFontFace) {
AutoFTFace face(this);
if (!face) {
return nullptr;
}
mFTFace = face.forget();
int flags = gfxPlatform::GetPlatform()->FontHintingEnabled() ?
FT_LOAD_DEFAULT :
(FT_LOAD_NO_AUTOHINT | FT_LOAD_NO_HINTING);
mFontFace = cairo_ft_font_face_create_for_ft_face(face, flags, nullptr, 0);
FTUserFontData *userFontData = new FTUserFontData(face, face.FontData());
mFontFace = cairo_ft_font_face_create_for_ft_face(face, flags,
nullptr, 0);
auto userFontData = new FTUserFontData(face, face.FontData(),
face.DataLength());
cairo_font_face_set_user_data(mFontFace, &sFTUserFontDataKey,
userFontData, FTFontDestroyFunc);
mFTFace = face.forget();
}
// If aStyle includes variations, we will not use our cached mFontFace
// but always create a new cairo_font_face_t with the requested variation
// settings.
if (aStyle && !aStyle->variationSettings.IsEmpty() &&
mFTFace->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS) {
int flags = gfxPlatform::GetPlatform()->FontHintingEnabled() ?
FT_LOAD_DEFAULT :
(FT_LOAD_NO_AUTOHINT | FT_LOAD_NO_HINTING);
AutoTArray<FT_Fixed,8> coords;
gfxFT2FontBase::SetupVarCoords(mFTFace, aStyle->variationSettings,
&coords);
// Create a separate FT_Face because we need to apply custom
// variation settings to it.
FT_Face ftFace;
if (!mFilename.IsEmpty()) {
ftFace = Factory::NewFTFace(nullptr, mFilename.get(), mFTFontIndex);
} else {
auto ufd = reinterpret_cast<FTUserFontData*>(
cairo_font_face_get_user_data(mFontFace, &sFTUserFontDataKey));
ftFace = Factory::NewFTFaceFromData(nullptr, ufd->FontData(),
ufd->Length(), mFTFontIndex);
}
FT_Set_Var_Design_Coordinates(ftFace, coords.Length(), coords.Elements());
cairo_font_face_t* cairoFace =
cairo_ft_font_face_create_for_ft_face(ftFace, flags,
coords.Elements(),
coords.Length());
// Set up user data to properly release the FT_Face when the cairo face
// is deleted.
static cairo_user_data_key_t sDestroyFaceKey;
if (cairo_font_face_set_user_data(cairoFace, &sDestroyFaceKey, ftFace,
(cairo_destroy_func_t)&Factory::ReleaseFTFace)) {
// set_user_data failed! discard, and fall back to default face
cairo_font_face_destroy(cairoFace);
FT_Done_Face(ftFace);
} else {
return cairoFace;
}
}
return mFontFace;
}

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

@ -58,19 +58,23 @@ public:
// Create a font entry for a given freetype face; if it is an installed font,
// also record the filename and index.
// aFontData (if non-nullptr) is NS_Malloc'ed data that aFace depends on,
// to be freed after the face is destroyed
// to be freed after the face is destroyed.
// aLength is the length of aFontData.
static FT2FontEntry*
CreateFontEntry(FT_Face aFace,
const char *aFilename, uint8_t aIndex,
const nsAString& aName,
const uint8_t* aFontData = nullptr);
const uint8_t* aFontData = nullptr,
uint32_t aLength = 0);
virtual gfxFont *CreateFontInstance(const gfxFontStyle *aFontStyle,
bool aNeedsBold) override;
// Create (if necessary) and return the cairo_font_face for this font.
// This may fail and return null, so caller must be prepared to handle this.
cairo_font_face_t *CairoFontFace();
// If a style is passed, any variationSettings in the style will be applied
// to the resulting font face.
cairo_font_face_t *CairoFontFace(const gfxFontStyle *aStyle = nullptr);
// Create a cairo_scaled_font for this face, with the given style.
// This may fail and return null, so caller must be prepared to handle this.

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

@ -373,8 +373,13 @@ InitializeVarFuncs()
return;
}
sInitializedVarFuncs = true;
#if MOZ_TREE_FREETYPE
sGetVar = &FT_Get_MM_Var;
sDoneVar = &FT_Done_MM_Var;
#else
sGetVar = (GetVarFunc)dlsym(RTLD_DEFAULT, "FT_Get_MM_Var");
sDoneVar = (DoneVarFunc)dlsym(RTLD_DEFAULT, "FT_Done_MM_Var");
#endif
}
gfxFontconfigFontEntry::~gfxFontconfigFontEntry()

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

@ -43,7 +43,7 @@ public:
virtual bool UseANGLE() const { return false; }
virtual LayoutDeviceIntSize GetClientSize() = 0;
virtual LayoutDeviceIntSize GetBufferSize() = 0;
widget::CompositorWidget* GetWidget() const { return mWidget; }

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

@ -13,8 +13,11 @@
#include "mozilla/layers/HelpersD3D11.h"
#include "mozilla/layers/SyncObject.h"
#include "mozilla/widget/CompositorWidget.h"
#include "mozilla/widget/WinCompositorWidget.h"
#include "mozilla/WindowsVersion.h"
#include <d3d11.h>
#include <dxgi1_2.h>
namespace mozilla {
namespace wr {
@ -31,6 +34,8 @@ RenderCompositorANGLE::Create(RefPtr<widget::CompositorWidget>&& aWidget)
RenderCompositorANGLE::RenderCompositorANGLE(RefPtr<widget::CompositorWidget>&& aWidget)
: RenderCompositor(Move(aWidget))
, mEGLConfig(nullptr)
, mEGLSurface(nullptr)
{
}
@ -53,6 +58,74 @@ RenderCompositorANGLE::Initialize()
return false;
}
HWND hwnd = mWidget->AsWindows()->GetHwnd();
RefPtr<IDXGIDevice> dxgiDevice;
mDevice->QueryInterface((IDXGIDevice**)getter_AddRefs(dxgiDevice));
RefPtr<IDXGIFactory> dxgiFactory;
{
RefPtr<IDXGIAdapter> adapter;
dxgiDevice->GetAdapter(getter_AddRefs(adapter));
adapter->GetParent(IID_PPV_ARGS((IDXGIFactory**)getter_AddRefs(dxgiFactory)));
}
RefPtr<IDXGIFactory2> dxgiFactory2;
if (SUCCEEDED(dxgiFactory->QueryInterface((IDXGIFactory2**)getter_AddRefs(dxgiFactory2))) &&
dxgiFactory2 &&
IsWin8OrLater())
{
RefPtr<IDXGISwapChain1> swapChain1;
DXGI_SWAP_CHAIN_DESC1 desc{};
desc.Width = 0;
desc.Height = 0;
desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
desc.BufferCount = 2;
desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
desc.Scaling = DXGI_SCALING_NONE;
desc.Flags = 0;
HRESULT hr = dxgiFactory2->CreateSwapChainForHwnd(mDevice, hwnd, &desc,
nullptr, nullptr,
getter_AddRefs(swapChain1));
if (SUCCEEDED(hr) && swapChain1) {
DXGI_RGBA color = { 1.0f, 1.0f, 1.0f, 1.0f };
swapChain1->SetBackgroundColor(&color);
mSwapChain = swapChain1;
}
}
if (!mSwapChain) {
DXGI_SWAP_CHAIN_DESC swapDesc{};
swapDesc.BufferDesc.Width = 0;
swapDesc.BufferDesc.Height = 0;
swapDesc.BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
swapDesc.BufferDesc.RefreshRate.Numerator = 60;
swapDesc.BufferDesc.RefreshRate.Denominator = 1;
swapDesc.SampleDesc.Count = 1;
swapDesc.SampleDesc.Quality = 0;
swapDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapDesc.BufferCount = 1;
swapDesc.OutputWindow = hwnd;
swapDesc.Windowed = TRUE;
swapDesc.Flags = 0;
swapDesc.SwapEffect = DXGI_SWAP_EFFECT_SEQUENTIAL;
HRESULT hr = dxgiFactory->CreateSwapChain(dxgiDevice, &swapDesc, getter_AddRefs(mSwapChain));
if (FAILED(hr)) {
gfxCriticalNote << "Could not create swap chain: " << gfx::hexa(hr);
return false;
}
}
// We need this because we don't want DXGI to respond to Alt+Enter.
dxgiFactory->MakeWindowAssociation(hwnd, DXGI_MWA_NO_WINDOW_CHANGES);
mSyncObject = layers::SyncObjectHost::CreateSyncObjectHost(mDevice);
if (!mSyncObject->Init()) {
// Some errors occur. Clear the mSyncObject here.
@ -60,28 +133,49 @@ RenderCompositorANGLE::Initialize()
return false;
}
mGL = gl::GLContextProviderEGL::CreateForCompositorWidget(mWidget, true);
const auto flags = gl::CreateContextFlags::PREFER_ES3;
// Create GLContext with dummy EGLSurface, the EGLSurface is not used.
// Instread we override it with EGLSurface of SwapChain's back buffer.
nsCString discardFailureId;
mGL = gl::GLContextProviderEGL::CreateHeadless(flags, &discardFailureId);
if (!mGL || !mGL->IsANGLE()) {
gfxCriticalNote << "Failed ANGLE GL context creation for WebRender: " << gfx::hexa(mGL.get());
return false;
}
if (!mGL->MakeCurrent()) {
gfxCriticalNote << "Failed GL context creation for WebRender: " << gfx::hexa(mGL.get());
return false;
}
// Force enable alpha channel to make sure ANGLE use correct framebuffer formart
if (!gl::CreateConfig(&mEGLConfig, /* bpp */ 32, /* enableDepthBuffer */ true)) {
gfxCriticalNote << "Failed to create EGLConfig for WebRender";
}
MOZ_ASSERT(mEGLConfig);
if (!ResizeBufferIfNeeded()) {
return false;
}
return true;
}
bool
RenderCompositorANGLE::Destroy()
{
DestroyEGLSurface();
return true;
}
bool
RenderCompositorANGLE::BeginFrame()
{
if (!ResizeBufferIfNeeded()) {
return false;
}
if (!mGL->MakeCurrent()) {
gfxCriticalNote << "Failed to make render context current, can't draw.";
return false;
@ -99,7 +193,7 @@ RenderCompositorANGLE::EndFrame()
{
InsertPresentWaitQuery();
mGL->SwapBuffers();
mSwapChain->Present(0, 0);
// Note: this waits on the query we inserted in the previous frame,
// not the one we just inserted now. Example:
@ -117,6 +211,94 @@ RenderCompositorANGLE::EndFrame()
WaitForPreviousPresentQuery();
}
bool
RenderCompositorANGLE::ResizeBufferIfNeeded()
{
MOZ_ASSERT(mSwapChain);
LayoutDeviceIntSize size = mWidget->GetClientSize();
// Set size to non negative.
size.width = std::max(size.width, 0);
size.height = std::max(size.height, 0);
if (mBufferSize.isSome() && mBufferSize.ref() == size) {
MOZ_ASSERT(mEGLSurface);
return true;
}
HRESULT hr;
RefPtr<ID3D11Texture2D> backBuf;
// Release EGLSurface of back buffer before calling ResizeBuffers().
DestroyEGLSurface();
// Reset buffer size
mBufferSize.reset();
// Resize swap chain
DXGI_SWAP_CHAIN_DESC desc;
hr = mSwapChain->GetDesc(&desc);
if (FAILED(hr)) {
gfxCriticalNote << "Failed to read swap chain description: " << gfx::hexa(hr) << " Size : " << size;
return false;
}
hr = mSwapChain->ResizeBuffers(desc.BufferCount, size.width, size.height, DXGI_FORMAT_B8G8R8A8_UNORM, 0);
if (FAILED(hr)) {
gfxCriticalNote << "Failed to resize swap chain buffers: " << gfx::hexa(hr) << " Size : " << size;
return false;
}
hr = mSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)getter_AddRefs(backBuf));
if (hr == DXGI_ERROR_INVALID_CALL) {
// This happens on some GPUs/drivers when there's a TDR.
if (mDevice->GetDeviceRemovedReason() != S_OK) {
gfxCriticalError() << "GetBuffer returned invalid call: " << gfx::hexa(hr) << " Size : " << size;
return false;
}
}
const auto& egl = &gl::sEGLLibrary;
const EGLint pbuffer_attribs[]{
LOCAL_EGL_WIDTH, size.width,
LOCAL_EGL_HEIGHT, size.height,
LOCAL_EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE, LOCAL_EGL_TRUE,
LOCAL_EGL_NONE};
const auto buffer = reinterpret_cast<EGLClientBuffer>(backBuf.get());
const EGLSurface surface = egl->fCreatePbufferFromClientBuffer(
egl->Display(), LOCAL_EGL_D3D_TEXTURE_ANGLE, buffer, mEGLConfig,
pbuffer_attribs);
EGLint err = egl->fGetError();
if (err != LOCAL_EGL_SUCCESS) {
gfxCriticalError() << "Failed to create Pbuffer of back buffer error: " << gfx::hexa(err) << " Size : " << size;
return false;
}
gl::GLContextEGL::Cast(mGL)->SetEGLSurfaceOverride(surface);
mEGLSurface = surface;
mBufferSize = Some(size);
return true;
}
void
RenderCompositorANGLE::DestroyEGLSurface()
{
const auto& egl = &gl::sEGLLibrary;
// Release EGLSurface of back buffer before calling ResizeBuffers().
if (mEGLSurface) {
gl::GLContextEGL::Cast(mGL)->SetEGLSurfaceOverride(EGL_NO_SURFACE);
egl->fDestroySurface(egl->Display(), mEGLSurface);
mEGLSurface = nullptr;
}
}
void
RenderCompositorANGLE::Pause()
{
@ -129,9 +311,13 @@ RenderCompositorANGLE::Resume()
}
LayoutDeviceIntSize
RenderCompositorANGLE::GetClientSize()
RenderCompositorANGLE::GetBufferSize()
{
return mWidget->GetClientSize();
MOZ_ASSERT(mBufferSize.isSome());
if (mBufferSize.isNothing()) {
return LayoutDeviceIntSize();
}
return mBufferSize.ref();
}
void

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

@ -7,11 +7,13 @@
#ifndef MOZILLA_GFX_RENDERCOMPOSITOR_ANGLE_H
#define MOZILLA_GFX_RENDERCOMPOSITOR_ANGLE_H
#include "mozilla/Maybe.h"
#include "mozilla/webrender/RenderCompositor.h"
struct ID3D11DeviceContext;
struct ID3D11Device;
struct ID3D11Query;
struct IDXGISwapChain;
namespace mozilla {
@ -36,20 +38,26 @@ public:
bool UseANGLE() const override { return true; }
LayoutDeviceIntSize GetClientSize() override;
LayoutDeviceIntSize GetBufferSize() override;
protected:
void InsertPresentWaitQuery();
void WaitForPreviousPresentQuery();
bool ResizeBufferIfNeeded();
void DestroyEGLSurface();
RefPtr<gl::GLContext> mGL;
EGLConfig mEGLConfig;
EGLSurface mEGLSurface;
RefPtr<ID3D11Device> mDevice;
RefPtr<ID3D11DeviceContext> mCtx;
RefPtr<IDXGISwapChain> mSwapChain;
RefPtr<ID3D11Query> mWaitForPresentQuery;
RefPtr<ID3D11Query> mNextWaitForPresentQuery;
Maybe<LayoutDeviceIntSize> mBufferSize;
};
} // namespace wr

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

@ -86,7 +86,7 @@ RenderCompositorOGL::Resume()
}
LayoutDeviceIntSize
RenderCompositorOGL::GetClientSize()
RenderCompositorOGL::GetBufferSize()
{
return mWidget->GetClientSize();
}

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

@ -32,7 +32,7 @@ public:
bool UseANGLE() const override { return false; }
LayoutDeviceIntSize GetClientSize() override;
LayoutDeviceIntSize GetBufferSize() override;
protected:
RefPtr<gl::GLContext> mGL;

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

@ -113,7 +113,7 @@ RendererOGL::UpdateAndRender()
wr_renderer_update(mRenderer);
auto size = mCompositor->GetClientSize();
auto size = mCompositor->GetBufferSize();
if (!wr_renderer_render(mRenderer, size.width, size.height)) {
NotifyWebRenderError(WebRenderError::RENDER);

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

@ -25,10 +25,8 @@
#if defined(MOZ_CONTENT_SANDBOX)
#include "mozilla/SandboxSettings.h"
#if defined(XP_MACOSX)
#include "nsAppDirectoryServiceDefs.h"
#endif
#endif
#include "nsExceptionHandler.h"
@ -280,6 +278,18 @@ GeckoChildProcessHost::PrepareLaunch()
mEnableSandboxLogging = mEnableSandboxLogging
|| !!PR_GetEnv("MOZ_SANDBOX_LOGGING");
#endif
#elif defined(XP_LINUX)
#if defined(MOZ_CONTENT_SANDBOX)
// Get and remember the path to the per-content-process tmpdir
if (ShouldHaveDirectoryService()) {
nsCOMPtr<nsIFile> contentTempDir;
nsresult rv = NS_GetSpecialDirectory(NS_APP_CONTENT_PROCESS_TEMP_DIR,
getter_AddRefs(contentTempDir));
if (NS_SUCCEEDED(rv)) {
contentTempDir->GetNativePath(mTmpDirName);
}
}
#endif
#endif
}
@ -506,6 +516,18 @@ GeckoChildProcessHost::PerformAsyncLaunch(std::vector<std::string> aExtraOpts)
= ENVIRONMENT_STRING(childRustLog);
}
#if defined(XP_LINUX) && defined(MOZ_CONTENT_SANDBOX)
if (!mTmpDirName.IsEmpty()) {
// Point a bunch of things that might want to write from content to our
// shiny new content-process specific tmpdir
mLaunchOptions->env_map[ENVIRONMENT_LITERAL("TMPDIR")] =
ENVIRONMENT_STRING(mTmpDirName);
// Partial fix for bug 1380051 (not persistent - should be)
mLaunchOptions->env_map[ENVIRONMENT_LITERAL("MESA_GLSL_CACHE_DIR")] =
ENVIRONMENT_STRING(mTmpDirName);
}
#endif
return PerformAsyncLaunchInternal(aExtraOpts);
}

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

@ -193,6 +193,11 @@ private:
// FIXME/cjones: this strongly indicates bad design. Shame on us.
std::queue<IPC::Message> mQueue;
// Set this up before we're called from a different thread.
#if defined(OS_LINUX)
nsCString mTmpDirName;
#endif
static uint32_t sNextUniqueID;
static bool sRunSelfAsContentProc;

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

@ -1606,7 +1606,7 @@ OutlineTypedObject::obj_trace(JSTracer* trc, JSObject* object)
{
OutlineTypedObject& typedObj = object->as<OutlineTypedObject>();
TraceEdge(trc, &typedObj.shape_, "OutlineTypedObject_shape");
TraceEdge(trc, typedObj.shapePtr(), "OutlineTypedObject_shape");
if (!typedObj.owner_)
return;
@ -2118,7 +2118,7 @@ InlineTypedObject::obj_trace(JSTracer* trc, JSObject* object)
{
InlineTypedObject& typedObj = object->as<InlineTypedObject>();
TraceEdge(trc, &typedObj.shape_, "InlineTypedObject_shape");
TraceEdge(trc, typedObj.shapePtr(), "InlineTypedObject_shape");
// Inline transparent objects do not have references and do not need more
// tracing. If there is an entry in the compartment's LazyArrayBufferTable,

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

@ -592,7 +592,9 @@ class TypedObject : public ShapedObject
static MOZ_MUST_USE bool GetBuffer(JSContext* cx, unsigned argc, Value* vp);
static MOZ_MUST_USE bool GetByteOffset(JSContext* cx, unsigned argc, Value* vp);
Shape** addressOfShapeFromGC() { return shape_.unsafeUnbarrieredForTracing(); }
Shape** addressOfShapeFromGC() {
return shapeRef().unsafeUnbarrieredForTracing();
}
};
typedef Handle<TypedObject*> HandleTypedObject;

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

@ -266,13 +266,9 @@ class ArenaLists
ZoneGroupData<Arena*> gcScriptArenasToUpdate;
ZoneGroupData<Arena*> gcObjectGroupArenasToUpdate;
// While sweeping type information, these lists save the arenas for the
// objects which have already been finalized in the foreground (which must
// happen at the beginning of the GC), so that type sweeping can determine
// which of the object pointers are marked.
ZoneGroupData<ObjectAllocKindArray<ArenaList>> savedObjectArenas_;
ArenaList& savedObjectArenas(AllocKind i) { return savedObjectArenas_.ref()[i]; }
ZoneGroupData<Arena*> savedEmptyObjectArenas;
// The list of empty arenas which are collected during sweep phase and released at the end of
// sweeping every sweep group.
ZoneGroupData<Arena*> savedEmptyArenas;
public:
explicit ArenaLists(JSRuntime* rt, ZoneGroup* group);
@ -322,7 +318,7 @@ class ArenaLists
void queueForegroundObjectsForSweep(FreeOp* fop);
void queueForegroundThingsForSweep(FreeOp* fop);
void mergeForegroundSweptObjectArenas();
void releaseForegroundSweptEmptyArenas();
bool foregroundFinalize(FreeOp* fop, AllocKind thingKind, js::SliceBudget& sliceBudget,
SortedArenaList& sweepList);
@ -340,7 +336,6 @@ class ArenaLists
inline void queueForBackgroundSweep(FreeOp* fop, const FinalizePhase& phase);
inline void queueForForegroundSweep(FreeOp* fop, AllocKind thingKind);
inline void queueForBackgroundSweep(FreeOp* fop, AllocKind thingKind);
inline void mergeSweptArenas(AllocKind thingKind);
TenuredCell* allocateFromArena(JS::Zone* zone, AllocKind thingKind,
ShouldCheckThresholds checkThresholds);

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

@ -283,7 +283,8 @@ class GCMarker : public JSTracer
void setGCMode(JSGCMode mode) { stack.setGCMode(mode); }
size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf,
const AutoLockForExclusiveAccess& lock) const;
#ifdef DEBUG

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

@ -1115,7 +1115,7 @@ class GCRuntime
IncrementalProgress endSweepingSweepGroup(FreeOp* fop, SliceBudget& budget);
IncrementalProgress performSweepActions(SliceBudget& sliceBudget, AutoLockForExclusiveAccess& lock);
IncrementalProgress sweepTypeInformation(FreeOp* fop, SliceBudget& budget, Zone* zone);
IncrementalProgress mergeSweptObjectArenas(FreeOp* fop, SliceBudget& budget, Zone* zone);
IncrementalProgress releaseSweptEmptyArenas(FreeOp* fop, SliceBudget& budget, Zone* zone);
void startSweepingAtomsTable();
IncrementalProgress sweepAtomsTable(FreeOp* fop, SliceBudget& budget);
IncrementalProgress sweepWeakCaches(FreeOp* fop, SliceBudget& budget);

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

@ -2634,7 +2634,8 @@ GCMarker::checkZone(void* p)
#endif
size_t
GCMarker::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const
GCMarker::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf,
const AutoLockForExclusiveAccess& lock) const
{
size_t size = stack.sizeOfExcludingThis(mallocSizeOf);
for (ZonesIter zone(runtime(), WithAtoms); !zone.done(); zone.next())

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

@ -1626,10 +1626,9 @@ CreateDependentString::generate(MacroAssembler& masm, const JSAtomState& names,
// Watch for undepended strings, which have a base pointer but don't
// actually share their characters with it.
Label noBase;
masm.branchTest32(Assembler::Zero, Address(base, JSString::offsetOfFlags()),
Imm32(JSString::HAS_BASE_BIT), &noBase);
masm.branchTest32(Assembler::NonZero, Address(base, JSString::offsetOfFlags()),
Imm32(JSString::FLAT_BIT), &noBase);
masm.load32(Address(base, JSString::offsetOfFlags()), temp1);
masm.and32(Imm32(JSString::TYPE_FLAGS_MASK), temp1);
masm.branch32(Assembler::NotEqual, temp1, Imm32(JSString::DEPENDENT_FLAGS), &noBase);
masm.loadPtr(Address(base, JSDependentString::offsetOfBase()), temp1);
masm.storePtr(temp1, Address(string, JSDependentString::offsetOfBase()));
masm.bind(&noBase);
@ -8032,7 +8031,7 @@ JitCompartment::generateStringConcatStub(JSContext* cx)
// Store rope length and flags. temp1 still holds the result of AND'ing the
// lhs and rhs flags, so we just have to clear the other flags to get our
// rope flags (Latin1 if both lhs and rhs are Latin1).
static_assert(JSString::ROPE_FLAGS == 0, "Rope flags must be 0");
static_assert(JSString::INIT_ROPE_FLAGS == 0, "Rope type flags must be 0");
masm.and32(Imm32(JSString::LATIN1_CHARS_BIT), temp1);
masm.store32(temp1, Address(output, JSString::offsetOfFlags()));
masm.store32(temp2, Address(output, JSString::offsetOfLength()));

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

@ -397,8 +397,7 @@ void
MacroAssembler::branchIfRope(Register str, Label* label)
{
Address flags(str, JSString::offsetOfFlags());
static_assert(JSString::ROPE_FLAGS == 0, "Rope type flags must be 0");
branchTest32(Assembler::Zero, flags, Imm32(JSString::TYPE_FLAGS_MASK), label);
branchTest32(Assembler::Zero, flags, Imm32(JSString::LINEAR_BIT), label);
}
void
@ -408,8 +407,7 @@ MacroAssembler::branchIfRopeOrExternal(Register str, Register temp, Label* label
move32(Imm32(JSString::TYPE_FLAGS_MASK), temp);
and32(flags, temp);
static_assert(JSString::ROPE_FLAGS == 0, "Rope type flags must be 0");
branchTest32(Assembler::Zero, temp, temp, label);
branchTest32(Assembler::Zero, temp, Imm32(JSString::LINEAR_BIT), label);
branch32(Assembler::Equal, temp, Imm32(JSString::EXTERNAL_FLAGS), label);
}
@ -418,8 +416,7 @@ void
MacroAssembler::branchIfNotRope(Register str, Label* label)
{
Address flags(str, JSString::offsetOfFlags());
static_assert(JSString::ROPE_FLAGS == 0, "Rope type flags must be 0");
branchTest32(Assembler::NonZero, flags, Imm32(JSString::TYPE_FLAGS_MASK), label);
branchTest32(Assembler::NonZero, flags, Imm32(JSString::LINEAR_BIT), label);
}
void

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

@ -1264,20 +1264,20 @@ MacroAssemblerMIPSCompat::testUndefinedSet(Condition cond, const ValueOperand& v
// unboxing code
void
MacroAssemblerMIPSCompat::unboxNonDouble(const ValueOperand& operand, Register dest)
MacroAssemblerMIPSCompat::unboxNonDouble(const ValueOperand& operand, Register dest, JSValueType)
{
if (operand.payloadReg() != dest)
ma_move(dest, operand.payloadReg());
}
void
MacroAssemblerMIPSCompat::unboxNonDouble(const Address& src, Register dest)
MacroAssemblerMIPSCompat::unboxNonDouble(const Address& src, Register dest, JSValueType)
{
ma_lw(dest, Address(src.base, src.offset + PAYLOAD_OFFSET));
}
void
MacroAssemblerMIPSCompat::unboxNonDouble(const BaseIndex& src, Register dest)
MacroAssemblerMIPSCompat::unboxNonDouble(const BaseIndex& src, Register dest, JSValueType)
{
computeScaledAddress(src, SecondScratchReg);
ma_lw(dest, Address(SecondScratchReg, src.offset + PAYLOAD_OFFSET));
@ -1348,7 +1348,7 @@ MacroAssemblerMIPSCompat::unboxObject(const Address& src, Register dest)
}
void
MacroAssemblerMIPSCompat::unboxValue(const ValueOperand& src, AnyRegister dest)
MacroAssemblerMIPSCompat::unboxValue(const ValueOperand& src, AnyRegister dest, JSValueType)
{
if (dest.isFloat()) {
Label notInt32, end;

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

@ -333,9 +333,9 @@ class MacroAssemblerMIPSCompat : public MacroAssemblerMIPS
}
// unboxing code
void unboxNonDouble(const ValueOperand& operand, Register dest);
void unboxNonDouble(const Address& src, Register dest);
void unboxNonDouble(const BaseIndex& src, Register dest);
void unboxNonDouble(const ValueOperand& operand, Register dest, JSValueType);
void unboxNonDouble(const Address& src, Register dest, JSValueType);
void unboxNonDouble(const BaseIndex& src, Register dest, JSValueType);
void unboxInt32(const ValueOperand& operand, Register dest);
void unboxInt32(const Address& src, Register dest);
void unboxBoolean(const ValueOperand& operand, Register dest);
@ -346,10 +346,18 @@ class MacroAssemblerMIPSCompat : public MacroAssemblerMIPS
void unboxString(const Address& src, Register dest);
void unboxObject(const ValueOperand& src, Register dest);
void unboxObject(const Address& src, Register dest);
void unboxObject(const BaseIndex& src, Register dest) { unboxNonDouble(src, dest); }
void unboxValue(const ValueOperand& src, AnyRegister dest);
void unboxObject(const BaseIndex& src, Register dest)
{
unboxNonDouble(src, dest, JSVAL_TYPE_OBJECT);
}
void unboxValue(const ValueOperand& src, AnyRegister dest, JSValueType);
void unboxPrivate(const ValueOperand& src, Register dest);
void unboxGCThingForPreBarrierTrampoline(const Address& src, Register dest)
{
unboxObject(src, dest);
}
void notBoolean(const ValueOperand& val) {
as_xori(val.payloadReg(), val.payloadReg(), 1);
}
@ -365,6 +373,12 @@ class MacroAssemblerMIPSCompat : public MacroAssemblerMIPS
Register extractObject(const ValueOperand& value, Register scratch) {
return value.payloadReg();
}
Register extractString(const ValueOperand& value, Register scratch) {
return value.payloadReg();
}
Register extractSymbol(const ValueOperand& value, Register scratch) {
return value.payloadReg();
}
Register extractInt32(const ValueOperand& value, Register scratch) {
return value.payloadReg();
}
@ -437,7 +451,7 @@ class MacroAssemblerMIPSCompat : public MacroAssemblerMIPS
MIRType slotType);
template <typename T>
void storeUnboxedPayload(ValueOperand value, T address, size_t nbytes) {
void storeUnboxedPayload(ValueOperand value, T address, size_t nbytes, JSValueType) {
switch (nbytes) {
case 4:
store32(value.payloadReg(), address);

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

@ -1432,28 +1432,6 @@ MacroAssemblerMIPS64Compat::testUndefinedSet(Condition cond, const ValueOperand&
ma_cmp_set(dest, SecondScratchReg, ImmTag(JSVAL_TAG_UNDEFINED), cond);
}
// unboxing code
void
MacroAssemblerMIPS64Compat::unboxNonDouble(const ValueOperand& operand, Register dest)
{
ma_dext(dest, operand.valueReg(), Imm32(0), Imm32(JSVAL_TAG_SHIFT));
}
void
MacroAssemblerMIPS64Compat::unboxNonDouble(const Address& src, Register dest)
{
loadPtr(Address(src.base, src.offset), dest);
ma_dext(dest, dest, Imm32(0), Imm32(JSVAL_TAG_SHIFT));
}
void
MacroAssemblerMIPS64Compat::unboxNonDouble(const BaseIndex& src, Register dest)
{
computeScaledAddress(src, SecondScratchReg);
loadPtr(Address(SecondScratchReg, src.offset), dest);
ma_dext(dest, dest, Imm32(0), Imm32(JSVAL_TAG_SHIFT));
}
void
MacroAssemblerMIPS64Compat::unboxInt32(const ValueOperand& operand, Register dest)
{
@ -1519,53 +1497,59 @@ MacroAssemblerMIPS64Compat::unboxDouble(const Address& src, FloatRegister dest)
void
MacroAssemblerMIPS64Compat::unboxString(const ValueOperand& operand, Register dest)
{
unboxNonDouble(operand, dest);
unboxNonDouble(operand, dest, JSVAL_TYPE_STRING);
}
void
MacroAssemblerMIPS64Compat::unboxString(Register src, Register dest)
{
ma_dext(dest, src, Imm32(0), Imm32(JSVAL_TAG_SHIFT));
unboxNonDouble(src, dest, JSVAL_TYPE_STRING);
}
void
MacroAssemblerMIPS64Compat::unboxString(const Address& src, Register dest)
{
unboxNonDouble(src, dest);
unboxNonDouble(src, dest, JSVAL_TYPE_STRING);
}
void
MacroAssemblerMIPS64Compat::unboxSymbol(const ValueOperand& operand, Register dest)
{
unboxNonDouble(operand, dest, JSVAL_TYPE_SYMBOL);
}
void
MacroAssemblerMIPS64Compat::unboxSymbol(Register src, Register dest)
{
ma_dext(dest, src, Imm32(0), Imm32(JSVAL_TAG_SHIFT));
unboxNonDouble(src, dest, JSVAL_TYPE_SYMBOL);
}
void
MacroAssemblerMIPS64Compat::unboxSymbol(const Address& src, Register dest)
{
unboxNonDouble(src, dest);
unboxNonDouble(src, dest, JSVAL_TYPE_SYMBOL);
}
void
MacroAssemblerMIPS64Compat::unboxObject(const ValueOperand& src, Register dest)
{
unboxNonDouble(src, dest);
unboxNonDouble(src, dest, JSVAL_TYPE_OBJECT);
}
void
MacroAssemblerMIPS64Compat::unboxObject(Register src, Register dest)
{
ma_dext(dest, src, Imm32(0), Imm32(JSVAL_TAG_SHIFT));
unboxNonDouble(src, dest, JSVAL_TYPE_OBJECT);
}
void
MacroAssemblerMIPS64Compat::unboxObject(const Address& src, Register dest)
{
unboxNonDouble(src, dest);
unboxNonDouble(src, dest, JSVAL_TYPE_OBJECT);
}
void
MacroAssemblerMIPS64Compat::unboxValue(const ValueOperand& src, AnyRegister dest)
MacroAssemblerMIPS64Compat::unboxValue(const ValueOperand& src, AnyRegister dest, JSValueType type)
{
if (dest.isFloat()) {
Label notInt32, end;
@ -1576,7 +1560,7 @@ MacroAssemblerMIPS64Compat::unboxValue(const ValueOperand& src, AnyRegister dest
unboxDouble(src, dest.fpu());
bind(&end);
} else {
unboxNonDouble(src, dest.gpr());
unboxNonDouble(src, dest.gpr(), type);
}
}

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

@ -362,9 +362,44 @@ class MacroAssemblerMIPS64Compat : public MacroAssemblerMIPS64
}
// unboxing code
void unboxNonDouble(const ValueOperand& operand, Register dest);
void unboxNonDouble(const Address& src, Register dest);
void unboxNonDouble(const BaseIndex& src, Register dest);
void unboxNonDouble(const ValueOperand& operand, Register dest, JSValueType type) {
unboxNonDouble(operand.valueReg(), dest, type);
}
template <typename T>
void unboxNonDouble(T src, Register dest, JSValueType type) {
MOZ_ASSERT(type != JSVAL_TYPE_DOUBLE);
if (type == JSVAL_TYPE_INT32 || type == JSVAL_TYPE_BOOLEAN) {
load32(src, dest);
return;
}
loadPtr(src, dest);
unboxNonDouble(dest, dest, type);
}
void unboxNonDouble(Register src, Register dest, JSValueType type) {
MOZ_ASSERT(type != JSVAL_TYPE_DOUBLE);
if (type == JSVAL_TYPE_INT32 || type == JSVAL_TYPE_BOOLEAN) {
ma_sll(dest, src, Imm32(0));
return;
}
MOZ_ASSERT(ScratchRegister != src);
mov(ImmWord(JSVAL_TYPE_TO_SHIFTED_TAG(type)), ScratchRegister);
as_xor(dest, src, ScratchRegister);
}
template <typename T>
void unboxObjectOrNull(const T& src, Register dest) {
unboxNonDouble(src, dest, JSVAL_TYPE_OBJECT);
JS_STATIC_ASSERT(JSVAL_OBJECT_OR_NULL_BIT == (uint64_t(0x8) << JSVAL_TAG_SHIFT));
ma_dins(dest, zero, Imm32(JSVAL_TAG_SHIFT + 3), Imm32(1));
}
void unboxGCThingForPreBarrierTrampoline(const Address& src, Register dest) {
loadPtr(src, dest);
ma_dext(dest, dest, Imm32(0), Imm32(JSVAL_TAG_SHIFT));
}
void unboxInt32(const ValueOperand& operand, Register dest);
void unboxInt32(Register src, Register dest);
void unboxInt32(const Address& src, Register dest);
@ -385,8 +420,8 @@ class MacroAssemblerMIPS64Compat : public MacroAssemblerMIPS64
void unboxObject(const ValueOperand& src, Register dest);
void unboxObject(Register src, Register dest);
void unboxObject(const Address& src, Register dest);
void unboxObject(const BaseIndex& src, Register dest) { unboxNonDouble(src, dest); }
void unboxValue(const ValueOperand& src, AnyRegister dest);
void unboxObject(const BaseIndex& src, Register dest) { unboxNonDouble(src, dest, JSVAL_TYPE_OBJECT); }
void unboxValue(const ValueOperand& src, AnyRegister dest, JSValueType type);
void unboxPrivate(const ValueOperand& src, Register dest);
void notBoolean(const ValueOperand& val) {
@ -405,6 +440,14 @@ class MacroAssemblerMIPS64Compat : public MacroAssemblerMIPS64
unboxObject(value, scratch);
return scratch;
}
Register extractString(const ValueOperand& value, Register scratch) {
unboxString(value, scratch);
return scratch;
}
Register extractSymbol(const ValueOperand& value, Register scratch) {
unboxSymbol(value, scratch);
return scratch;
}
Register extractInt32(const ValueOperand& value, Register scratch) {
unboxInt32(value, scratch);
return scratch;
@ -449,20 +492,40 @@ class MacroAssemblerMIPS64Compat : public MacroAssemblerMIPS64
void loadUnboxedValue(const T& address, MIRType type, AnyRegister dest) {
if (dest.isFloat())
loadInt32OrDouble(address, dest.fpu());
else if (type == MIRType::Int32)
unboxInt32(address, dest.gpr());
else if (type == MIRType::Boolean)
unboxBoolean(address, dest.gpr());
else if (type == MIRType::ObjectOrNull)
unboxObjectOrNull(address, dest.gpr());
else
unboxNonDouble(address, dest.gpr());
unboxNonDouble(address, dest.gpr(), ValueTypeFromMIRType(type));
}
template <typename T>
void storeUnboxedPayload(ValueOperand value, T address, size_t nbytes) {
void storeUnboxedPayload(ValueOperand value, BaseIndex address, size_t nbytes, JSValueType type) {
switch (nbytes) {
case 8:
unboxNonDouble(value, ScratchRegister);
storePtr(ScratchRegister, address);
if (type == JSVAL_TYPE_OBJECT)
unboxObjectOrNull(value, SecondScratchReg);
else
unboxNonDouble(value, SecondScratchReg, type);
computeEffectiveAddress(address, ScratchRegister);
as_sd(SecondScratchReg, ScratchRegister, 0);
return;
case 4:
store32(value.valueReg(), address);
return;
case 1:
store8(value.valueReg(), address);
return;
default: MOZ_CRASH("Bad payload width");
}
}
void storeUnboxedPayload(ValueOperand value, Address address, size_t nbytes, JSValueType type) {
switch (nbytes) {
case 8:
if (type == JSVAL_TYPE_OBJECT)
unboxObjectOrNull(value, SecondScratchReg);
else
unboxNonDouble(value, SecondScratchReg, type);
storePtr(SecondScratchReg, address);
return;
case 4:
store32(value.valueReg(), address);

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

@ -72,6 +72,7 @@ struct HelperThread;
using JobQueue = GCVector<JSObject*, 0, SystemAllocPolicy>;
class AutoLockForExclusiveAccess;
class AutoLockScriptData;
void ReportOverRecursed(JSContext* cx, unsigned errorNumber);
@ -264,7 +265,7 @@ struct JSContext : public JS::RootingContext,
js::SymbolRegistry& symbolRegistry(js::AutoLockForExclusiveAccess& lock) {
return runtime_->symbolRegistry(lock);
}
js::ScriptDataTable& scriptDataTable(js::AutoLockForExclusiveAccess& lock) {
js::ScriptDataTable& scriptDataTable(js::AutoLockScriptData& lock) {
return runtime_->scriptDataTable(lock);
}
@ -1218,6 +1219,37 @@ class MOZ_RAII AutoLockForExclusiveAccess
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
};
class MOZ_RAII AutoLockScriptData
{
JSRuntime* runtime;
public:
explicit AutoLockScriptData(JSRuntime* rt MOZ_GUARD_OBJECT_NOTIFIER_PARAM) {
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
runtime = rt;
if (runtime->hasHelperThreadZones()) {
runtime->scriptDataLock.lock();
} else {
MOZ_ASSERT(!runtime->activeThreadHasScriptDataAccess);
#ifdef DEBUG
runtime->activeThreadHasScriptDataAccess = true;
#endif
}
}
~AutoLockScriptData() {
if (runtime->hasHelperThreadZones()) {
runtime->scriptDataLock.unlock();
} else {
MOZ_ASSERT(runtime->activeThreadHasScriptDataAccess);
#ifdef DEBUG
runtime->activeThreadHasScriptDataAccess = false;
#endif
}
}
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
};
class MOZ_RAII AutoKeepAtoms
{
JSContext* cx;

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

@ -612,10 +612,10 @@ struct Function {
struct String
{
static const uint32_t LINEAR_BIT = JS_BIT(0);
static const uint32_t INLINE_CHARS_BIT = JS_BIT(2);
static const uint32_t LATIN1_CHARS_BIT = JS_BIT(6);
static const uint32_t ROPE_FLAGS = 0;
static const uint32_t EXTERNAL_FLAGS = JS_BIT(5);
static const uint32_t EXTERNAL_FLAGS = JS_BIT(0) | JS_BIT(5);
static const uint32_t TYPE_FLAGS_MASK = JS_BIT(6) - 1;
uint32_t flags;
uint32_t length;
@ -904,7 +904,7 @@ StringToLinearString(JSContext* cx, JSString* str)
{
using shadow::String;
String* s = reinterpret_cast<String*>(str);
if (MOZ_UNLIKELY((s->flags & String::TYPE_FLAGS_MASK) == String::ROPE_FLAGS))
if (MOZ_UNLIKELY(!(s->flags & String::LINEAR_BIT)))
return StringToLinearStringSlow(cx, str);
return reinterpret_cast<JSLinearString*>(str);
}

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

@ -2941,8 +2941,7 @@ ArenaLists::ArenaLists(JSRuntime* rt, ZoneGroup* group)
gcAccessorShapeArenasToUpdate(group, nullptr),
gcScriptArenasToUpdate(group, nullptr),
gcObjectGroupArenasToUpdate(group, nullptr),
savedObjectArenas_(group),
savedEmptyObjectArenas(group, nullptr)
savedEmptyArenas(group, nullptr)
{
for (auto i : AllAllocKinds())
freeLists(i) = &placeholder;
@ -2976,9 +2975,7 @@ ArenaLists::~ArenaLists()
}
ReleaseArenaList(runtime_, incrementalSweptArenas.ref().head(), lock);
for (auto i : ObjectAllocKinds())
ReleaseArenaList(runtime_, savedObjectArenas(i).head(), lock);
ReleaseArenaList(runtime_, savedEmptyObjectArenas, lock);
ReleaseArenaList(runtime_, savedEmptyArenas, lock);
}
void
@ -3073,28 +3070,11 @@ ArenaLists::backgroundFinalize(FreeOp* fop, Arena* listHead, Arena** empty)
}
void
ArenaLists::mergeForegroundSweptObjectArenas()
ArenaLists::releaseForegroundSweptEmptyArenas()
{
AutoLockGC lock(runtime_);
ReleaseArenaList(runtime_, savedEmptyObjectArenas, lock);
savedEmptyObjectArenas = nullptr;
mergeSweptArenas(AllocKind::OBJECT0);
mergeSweptArenas(AllocKind::OBJECT2);
mergeSweptArenas(AllocKind::OBJECT4);
mergeSweptArenas(AllocKind::OBJECT8);
mergeSweptArenas(AllocKind::OBJECT12);
mergeSweptArenas(AllocKind::OBJECT16);
}
inline void
ArenaLists::mergeSweptArenas(AllocKind thingKind)
{
ArenaList* al = &arenaLists(thingKind);
ArenaList* saved = &savedObjectArenas(thingKind);
*al = saved->insertListWithCursorAtEnd(*al);
saved->clear();
ReleaseArenaList(runtime_, savedEmptyArenas, lock);
savedEmptyArenas = nullptr;
}
void
@ -3834,27 +3814,33 @@ FOR_EACH_ALLOCKIND(MAKE_CASE)
bool
ArenaLists::checkEmptyArenaList(AllocKind kind)
{
size_t num_live = 0;
bool isEmpty = true;
#ifdef DEBUG
size_t numLive = 0;
if (!arenaLists(kind).isEmpty()) {
size_t max_cells = 20;
isEmpty = false;
size_t maxCells = 20;
char *env = getenv("JS_GC_MAX_LIVE_CELLS");
if (env && *env)
max_cells = atol(env);
maxCells = atol(env);
for (Arena* current = arenaLists(kind).head(); current; current = current->next) {
for (ArenaCellIterUnderGC i(current); !i.done(); i.next()) {
TenuredCell* t = i.getCell();
MOZ_ASSERT(t->isMarkedAny(), "unmarked cells should have been finalized");
if (++num_live <= max_cells) {
if (++numLive <= maxCells) {
fprintf(stderr, "ERROR: GC found live Cell %p of kind %s at shutdown\n",
t, AllocKindToAscii(kind));
}
}
}
fprintf(stderr, "ERROR: GC found %zu live Cells at shutdown\n", num_live);
if (numLive > 0) {
fprintf(stderr, "ERROR: GC found %zu live Cells at shutdown\n", numLive);
} else {
fprintf(stderr, "ERROR: GC found empty Arenas at shutdown\n");
}
}
#endif // DEBUG
return num_live == 0;
return isEmpty;
}
class MOZ_RAII js::gc::AutoRunParallelTask : public GCParallelTask
@ -5722,12 +5708,13 @@ bool
ArenaLists::foregroundFinalize(FreeOp* fop, AllocKind thingKind, SliceBudget& sliceBudget,
SortedArenaList& sweepList)
{
MOZ_ASSERT_IF(IsObjectAllocKind(thingKind), savedObjectArenas(thingKind).isEmpty());
if (!arenaListsToSweep(thingKind) && incrementalSweptArenas.ref().isEmpty())
return true;
// Empty object arenas are not released until all foreground GC things have
// been swept.
KeepArenasEnum keepArenas = IsObjectAllocKind(thingKind) ? KEEP_ARENAS : RELEASE_ARENAS;
if (!FinalizeArenas(fop, &arenaListsToSweep(thingKind), sweepList,
thingKind, sliceBudget, keepArenas))
{
@ -5739,16 +5726,11 @@ ArenaLists::foregroundFinalize(FreeOp* fop, AllocKind thingKind, SliceBudget& sl
// Clear any previous incremental sweep state we may have saved.
incrementalSweptArenas.ref().clear();
if (IsObjectAllocKind(thingKind)) {
// Delay releasing of object arenas until types have been swept.
sweepList.extractEmpty(&savedEmptyObjectArenas.ref());
savedObjectArenas(thingKind) = sweepList.toArenaList();
} else {
// Join |arenaLists[thingKind]| and |sweepList| into a single list.
ArenaList finalized = sweepList.toArenaList();
arenaLists(thingKind) =
finalized.insertListWithCursorAtEnd(arenaLists(thingKind));
}
if (IsObjectAllocKind(thingKind))
sweepList.extractEmpty(&savedEmptyArenas.ref());
ArenaList finalized = sweepList.toArenaList();
arenaLists(thingKind) = finalized.insertListWithCursorAtEnd(arenaLists(thingKind));
return true;
}
@ -5832,14 +5814,13 @@ GCRuntime::sweepTypeInformation(FreeOp* fop, SliceBudget& budget, Zone* zone)
}
IncrementalProgress
GCRuntime::mergeSweptObjectArenas(FreeOp* fop, SliceBudget& budget,
Zone* zone)
GCRuntime::releaseSweptEmptyArenas(FreeOp* fop, SliceBudget& budget, Zone* zone)
{
// Foreground finalized objects have already been finalized, and now their
// arenas can be reclaimed by freeing empty ones and making non-empty ones
// available for allocation.
zone->arenas.mergeForegroundSweptObjectArenas();
zone->arenas.releaseForegroundSweptEmptyArenas();
return Finished;
}
@ -6381,18 +6362,15 @@ GCRuntime::initSweepActions()
#endif
Call(&GCRuntime::sweepAtomsTable),
Call(&GCRuntime::sweepWeakCaches),
ForEachZoneInSweepGroup(rt,
ForEachAllocKind(ForegroundObjectFinalizePhase.kinds,
Call(&GCRuntime::finalizeAllocKind))),
ForEachZoneInSweepGroup(rt,
Sequence(
Call(&GCRuntime::sweepTypeInformation),
Call(&GCRuntime::mergeSweptObjectArenas))),
ForEachZoneInSweepGroup(rt,
ForEachAllocKind(ForegroundNonObjectFinalizePhase.kinds,
Call(&GCRuntime::finalizeAllocKind))),
ForEachZoneInSweepGroup(rt,
Call(&GCRuntime::sweepShapeTree)),
ForEachAllocKind(ForegroundObjectFinalizePhase.kinds,
Call(&GCRuntime::finalizeAllocKind)),
ForEachAllocKind(ForegroundNonObjectFinalizePhase.kinds,
Call(&GCRuntime::finalizeAllocKind)),
Call(&GCRuntime::sweepShapeTree),
Call(&GCRuntime::releaseSweptEmptyArenas))),
Call(&GCRuntime::endSweepingSweepGroup)));
return sweepActions != nullptr;
@ -6473,7 +6451,7 @@ GCRuntime::endSweepPhase(bool destroyingRuntime, AutoLockForExclusiveAccess& loc
* script and calls rt->destroyScriptHook, the hook can still access the
* script's filename. See bug 323267.
*/
SweepScriptData(rt, lock);
SweepScriptData(rt);
/* Clear out any small pools that we're hanging on to. */
if (rt->hasJitRuntime()) {

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

@ -1533,10 +1533,10 @@ NativeObject::fillInAfterSwap(JSContext* cx, HandleNativeObject obj,
// Make sure the shape's numFixedSlots() is correct.
size_t nfixed = gc::GetGCKindSlots(obj->asTenured().getAllocKind(), obj->getClass());
if (nfixed != obj->shape_->numFixedSlots()) {
if (nfixed != obj->shape()->numFixedSlots()) {
if (!NativeObject::generateOwnShape(cx, obj))
return false;
obj->shape_->setNumFixedSlots(nfixed);
obj->shape()->setNumFixedSlots(nfixed);
}
if (obj->hasPrivate())
@ -1566,7 +1566,7 @@ JSObject::fixDictionaryShapeAfterSwap()
// Dictionary shapes can point back to their containing objects, so after
// swapping the guts of those objects fix the pointers up.
if (isNative() && as<NativeObject>().inDictionaryMode())
as<NativeObject>().shape_->listp = &as<NativeObject>().shape_;
as<NativeObject>().shape()->listp = as<NativeObject>().shapePtr();
}
static MOZ_MUST_USE bool

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

@ -7,15 +7,6 @@
#ifndef jsobj_h
#define jsobj_h
/*
* JS object definitions.
*
* A JS object consists of a possibly-shared object descriptor containing
* ordered property names, called the map; and a dense vector of property
* values, called slots. The map/slot pointer pair is GC'ed, while the map
* is reference counted and the slot vector is malloc'ed.
*/
#include "mozilla/MemoryReporting.h"
#include "gc/Barrier.h"
@ -62,23 +53,48 @@ bool SetImmutablePrototype(JSContext* cx, JS::HandleObject obj, bool* succeeded)
} /* namespace js */
/*
* A JavaScript object. The members common to all objects are as follows:
* A JavaScript object.
*
* This is the base class for all objects exposed to JS script (as well as some
* objects that are only accessed indirectly). Subclasses add additional fields
* and execution semantics. The runtime class of an arbitrary JSObject is
* identified by JSObject::getClass().
*
* The members common to all objects are as follows:
*
* - The |group_| member stores the group of the object, which contains its
* prototype object, its class and the possible types of its properties.
*
* Subclasses of JSObject --- mainly NativeObject and JSFunction --- add more
* members. Notable among these is the object's shape, which stores flags and
* some other state, and, for native objects, the layout of all its properties.
* The second word of a JSObject generally stores its shape; if the second word
* stores anything else, the value stored cannot be a valid Shape* pointer, so
* that shape guards can be performed on objects without regard to the specific
* layout in use.
* - The |shapeOrExpando_| member points to (an optional) guard object that JIT
* may use to optimize. The pointed-to object dictates the constraints
* imposed on the JSObject:
* nullptr
* - Safe value if this field is not needed.
* js::Shape
* - All objects that might point |shapeOrExpando_| to a js::Shape
* must follow the rules specified on js::ShapedObject.
* JSObject
* - Implies nothing about the current object or target object. Either
* of which may mutate in place. Store a JSObject* only to save
* space, not to guard on.
*
* NOTE: The JIT may check |shapeOrExpando_| pointer value without ever
* inspecting |group_| or the class.
*
* NOTE: Some operations can change the contents of an object (including class)
* in-place so avoid assuming an object with same pointer has same class
* as before.
* - JSObject::swap()
* - UnboxedPlainObject::convertToNative()
*
* NOTE: UnboxedObjects may change class without changing |group_|.
* - js::TryConvertToUnboxedLayout
*/
class JSObject : public js::gc::Cell
{
protected:
js::GCPtrObjectGroup group_;
void* shapeOrExpando_;
private:
friend class js::Shape;
@ -533,7 +549,12 @@ class JSObject : public js::gc::Cell
/* JIT Accessors */
static size_t offsetOfGroup() { return offsetof(JSObject, group_); }
static constexpr size_t offsetOfGroup() {
return offsetof(JSObject, group_);
}
static constexpr size_t offsetOfShapeOrExpando() {
return offsetof(JSObject, shapeOrExpando_);
}
// Maximum size in bytes of a JSObject.
static const size_t MAX_BYTE_SIZE = 4 * sizeof(void*) + 16 * sizeof(JS::Value);
@ -582,12 +603,12 @@ operator!=(const JSObject& lhs, const JSObject& rhs)
}
// Size of the various GC thing allocation sizes used for objects.
struct JSObject_Slots0 : JSObject { void* data[3]; };
struct JSObject_Slots2 : JSObject { void* data[3]; js::Value fslots[2]; };
struct JSObject_Slots4 : JSObject { void* data[3]; js::Value fslots[4]; };
struct JSObject_Slots8 : JSObject { void* data[3]; js::Value fslots[8]; };
struct JSObject_Slots12 : JSObject { void* data[3]; js::Value fslots[12]; };
struct JSObject_Slots16 : JSObject { void* data[3]; js::Value fslots[16]; };
struct JSObject_Slots0 : JSObject { void* data[2]; };
struct JSObject_Slots2 : JSObject { void* data[2]; js::Value fslots[2]; };
struct JSObject_Slots4 : JSObject { void* data[2]; js::Value fslots[4]; };
struct JSObject_Slots8 : JSObject { void* data[2]; js::Value fslots[8]; };
struct JSObject_Slots12 : JSObject { void* data[2]; js::Value fslots[12]; };
struct JSObject_Slots16 : JSObject { void* data[2]; js::Value fslots[16]; };
/* static */ MOZ_ALWAYS_INLINE void
JSObject::readBarrier(JSObject* obj)

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

@ -139,8 +139,8 @@ js::NativeObject::sweepDictionaryListPointer()
// unreachable shapes may be marked whose listp points into this object. In
// case this happens, null out the shape's pointer so that a moving GC will
// not try to access the dead object.
if (shape_->listp == &shape_)
shape_->listp = nullptr;
if (shape()->listp == shapePtr())
shape()->listp = nullptr;
}
MOZ_ALWAYS_INLINE void
@ -150,8 +150,8 @@ js::NativeObject::updateDictionaryListPointerAfterMinorGC(NativeObject* old)
// Dictionary objects can be allocated in the nursery and when they are
// tenured the shape's pointer into the object needs to be updated.
if (shape_->listp == &old->shape_)
shape_->listp = &shape_;
if (shape()->listp == old->shapePtr())
shape()->listp = shapePtr();
}
inline void

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

@ -2512,7 +2512,7 @@ JSScript::shareScriptData(JSContext* cx)
MOZ_ASSERT(ssd);
MOZ_ASSERT(ssd->refCount() == 1);
AutoLockForExclusiveAccess lock(cx);
AutoLockScriptData lock(cx->runtime());
ScriptDataTable::AddPtr p = cx->scriptDataTable(lock).lookupForAdd(*ssd);
if (p) {
@ -2535,11 +2535,12 @@ JSScript::shareScriptData(JSContext* cx)
}
void
js::SweepScriptData(JSRuntime* rt, AutoLockForExclusiveAccess& lock)
js::SweepScriptData(JSRuntime* rt)
{
// Entries are removed from the table when their reference count is one,
// i.e. when the only reference to them is from the table entry.
AutoLockScriptData lock(rt);
ScriptDataTable& table = rt->scriptDataTable(lock);
for (ScriptDataTable::Enum e(table); !e.empty(); e.popFront()) {
@ -2552,8 +2553,10 @@ js::SweepScriptData(JSRuntime* rt, AutoLockForExclusiveAccess& lock)
}
void
js::FreeScriptData(JSRuntime* rt, AutoLockForExclusiveAccess& lock)
js::FreeScriptData(JSRuntime* rt)
{
AutoLockScriptData lock(rt);
ScriptDataTable& table = rt->scriptDataTable(lock);
if (!table.initialized())
return;

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

@ -868,15 +868,17 @@ struct ScriptBytecodeHasher
}
};
typedef HashSet<SharedScriptData*,
ScriptBytecodeHasher,
SystemAllocPolicy> ScriptDataTable;
class AutoLockScriptData;
using ScriptDataTable = HashSet<SharedScriptData*,
ScriptBytecodeHasher,
SystemAllocPolicy>;
extern void
SweepScriptData(JSRuntime* rt, AutoLockForExclusiveAccess& lock);
SweepScriptData(JSRuntime* rt);
extern void
FreeScriptData(JSRuntime* rt, AutoLockForExclusiveAccess& lock);
FreeScriptData(JSRuntime* rt);
} /* namespace js */

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

@ -686,7 +686,7 @@ ProxyObject::trace(JSTracer* trc, JSObject* obj)
{
ProxyObject* proxy = &obj->as<ProxyObject>();
TraceEdge(trc, &proxy->shape_, "ProxyObject_shape");
TraceEdge(trc, proxy->shapePtr(), "ProxyObject_shape");
#ifdef DEBUG
if (TlsContext.get()->isStrictProxyCheckingEnabled() && proxy->is<WrapperObject>()) {

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

@ -123,6 +123,9 @@ CheckGlobalLock<Lock, Helper>::check() const
case GlobalLock::ExclusiveAccessLock:
MOZ_ASSERT(TlsContext.get()->runtime()->currentThreadHasExclusiveAccess());
break;
case GlobalLock::ScriptDataLock:
MOZ_ASSERT(TlsContext.get()->runtime()->currentThreadHasScriptDataAccess());
break;
case GlobalLock::HelperThreadLock:
MOZ_ASSERT(HelperThreadState().isLockedByCurrentThread());
break;
@ -132,6 +135,7 @@ CheckGlobalLock<Lock, Helper>::check() const
template class CheckGlobalLock<GlobalLock::GCLock, AllowedHelperThread::None>;
template class CheckGlobalLock<GlobalLock::ExclusiveAccessLock, AllowedHelperThread::None>;
template class CheckGlobalLock<GlobalLock::ExclusiveAccessLock, AllowedHelperThread::GCTask>;
template class CheckGlobalLock<GlobalLock::ScriptDataLock, AllowedHelperThread::None>;
template class CheckGlobalLock<GlobalLock::HelperThreadLock, AllowedHelperThread::None>;
#endif // JS_HAS_PROTECTED_DATA_CHECKS

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

@ -258,6 +258,7 @@ enum class GlobalLock
{
GCLock,
ExclusiveAccessLock,
ScriptDataLock,
HelperThreadLock
};
@ -287,6 +288,11 @@ template <typename T>
using ExclusiveAccessLockOrGCTaskData =
ProtectedDataNoCheckArgs<CheckGlobalLock<GlobalLock::ExclusiveAccessLock, AllowedHelperThread::GCTask>, T>;
// Data which may only be accessed while holding the script data lock.
template <typename T>
using ScriptDataLockData =
ProtectedDataNoCheckArgs<CheckGlobalLock<GlobalLock::ScriptDataLock, AllowedHelperThread::None>, T>;
// Data which may only be accessed while holding the helper thread lock.
template <typename T>
using HelperThreadLockData =

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

@ -214,8 +214,10 @@ class NewObjectCache
static void copyCachedToObject(NativeObject* dst, NativeObject* src, gc::AllocKind kind) {
js_memcpy(dst, src, gc::Arena::thingSize(kind));
Shape::writeBarrierPost(&dst->shape_, nullptr, dst->shape_);
ObjectGroup::writeBarrierPost(&dst->group_, nullptr, dst->group_);
// Initialize with barriers
dst->initGroup(src->group());
dst->initShape(src->shape());
}
};

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

@ -86,10 +86,10 @@ ClampDefaultCPUCount(size_t cpuCount)
static size_t
ThreadCountForCPUCount(size_t cpuCount)
{
// Create additional threads on top of the number of cores available, to
// provide some excess capacity in case threads pause each other.
static const uint32_t EXCESS_THREADS = 4;
return cpuCount + EXCESS_THREADS;
// We need at least two threads for tier-2 wasm compilations, because
// there's a master task that holds a thread while other threads do the
// compilation.
return Max<size_t>(cpuCount, 2);
}
void

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

@ -10,6 +10,9 @@
#include "threading/Mutex.h"
// Central definition point for mutex ordering.
//
// Mutexes can only be acquired in increasing order. This prevents the
// possibility of deadlock.
#define FOR_EACH_MUTEX(_) \
_(TestMutex, 100) \
@ -49,7 +52,8 @@
_(WasmCodeStreamEnd, 500) \
_(WasmTailBytesPtr, 500) \
_(WasmStreamStatus, 500) \
_(SharedArrayGrow, 500) \
_(SharedArrayGrow, 500) \
_(RuntimeScriptData, 500) \
\
_(ThreadId, 600) \
_(WasmCodeSegmentMap, 600) \

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

@ -513,9 +513,9 @@ NativeObject::setSlotWithType(JSContext* cx, Shape* shape,
inline void
NativeObject::updateShapeAfterMovingGC()
{
Shape* shape = shape_;
Shape* shape = this->shape();
if (IsForwarded(shape))
shape_.unsafeSet(Forwarded(shape));
shapeRef().unsafeSet(Forwarded(shape));
}
inline bool
@ -664,14 +664,14 @@ NativeObject::setLastProperty(JSContext* cx, Shape* shape)
size_t newSpan = shape->slotSpan();
if (oldSpan == newSpan) {
shape_ = shape;
setShape(shape);
return true;
}
if (MOZ_UNLIKELY(!updateSlotsForSpan(cx, oldSpan, newSpan)))
return false;
shape_ = shape;
setShape(shape);
return true;
}

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

@ -190,7 +190,7 @@ js::NativeObject::checkShapeConsistency()
shape->slot() < slotSpan());
if (!prev) {
MOZ_ASSERT(lastProperty() == shape);
MOZ_ASSERT(shape->listp == &shape_);
MOZ_ASSERT(shape->listp == &shapeRef());
} else {
MOZ_ASSERT(shape->listp == &prev->parent);
}
@ -326,7 +326,7 @@ NativeObject::setLastPropertyShrinkFixedSlots(Shape* shape)
MOZ_ASSERT(dynamicSlotsCount(oldFixed, shape->slotSpan(), getClass()) == 0);
MOZ_ASSERT(dynamicSlotsCount(newFixed, shape->slotSpan(), getClass()) == 0);
shape_ = shape;
setShape(shape);
}
void
@ -345,7 +345,7 @@ NativeObject::setLastPropertyMakeNonNative(Shape* shape)
slots_ = nullptr;
}
shape_ = shape;
setShape(shape);
}
void
@ -358,7 +358,7 @@ NativeObject::setLastPropertyMakeNative(JSContext* cx, Shape* shape)
// This method is used to convert unboxed objects into native objects. In
// this case, the shape_ field was previously used to store other data and
// this should be treated as an initialization.
shape_.init(shape);
initShape(shape);
slots_ = nullptr;
elements_ = emptyObjectElements;

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

@ -413,7 +413,7 @@ enum class ShouldUpdateTypes {
/*
* NativeObject specifies the internal implementation of a native object.
*
* Native objects use ShapedObject::shape_ to record property information. Two
* Native objects use ShapedObject::shape to record property information. Two
* native objects with the same shape are guaranteed to have the same number of
* fixed slots.
*
@ -476,8 +476,8 @@ class NativeObject : public ShapedObject
public:
Shape* lastProperty() const {
MOZ_ASSERT(shape_);
return shape_;
MOZ_ASSERT(shape());
return shape();
}
uint32_t propertyCount() const {
@ -741,7 +741,7 @@ class NativeObject : public ShapedObject
*/
bool hasAllFlags(js::BaseShape::Flag flags) const {
MOZ_ASSERT(flags);
return shape_->hasAllObjectFlags(flags);
return shape()->hasAllObjectFlags(flags);
}
bool nonProxyIsExtensible() const {
return !hasAllFlags(js::BaseShape::NOT_EXTENSIBLE);

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

@ -135,6 +135,10 @@ JSRuntime::JSRuntime(JSRuntime* parentRuntime)
exclusiveAccessLock(mutexid::RuntimeExclusiveAccess),
#ifdef DEBUG
activeThreadHasExclusiveAccess(false),
#endif
scriptDataLock(mutexid::RuntimeScriptData),
#ifdef DEBUG
activeThreadHasScriptDataAccess(false),
#endif
numActiveHelperThreadZones(0),
numCompartments(0),
@ -322,13 +326,12 @@ JSRuntime::destroyRuntime()
AutoNoteSingleThreadedRegion anstr;
MOZ_ASSERT(!hasHelperThreadZones());
AutoLockForExclusiveAccess lock(this);
/*
* Even though all objects in the compartment are dead, we may have keep
* some filenames around because of gcKeepAtoms.
*/
FreeScriptData(this, lock);
FreeScriptData(this);
#if !EXPOSE_INTL_API
FinishRuntimeNumberState(this);
@ -459,11 +462,13 @@ JSRuntime::setUseCounterCallback(JSRuntime* rt, JSSetUseCounterCallback callback
void
JSRuntime::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, JS::RuntimeSizes* rtSizes)
{
// Several tables in the runtime enumerated below can be used off thread.
AutoLockForExclusiveAccess lock(this);
rtSizes->object += mallocSizeOf(this);
rtSizes->atomsTable += atoms(lock).sizeOfIncludingThis(mallocSizeOf);
{
AutoLockForExclusiveAccess lock(this);
rtSizes->atomsTable += atoms(lock).sizeOfIncludingThis(mallocSizeOf);
rtSizes->gc.marker += gc.marker.sizeOfExcludingThis(mallocSizeOf, lock);
}
if (!parentRuntime) {
rtSizes->atomsTable += mallocSizeOf(staticStrings);
@ -500,16 +505,17 @@ JSRuntime::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, JS::Runtim
rtSizes->sharedIntlData += sharedIntlData.ref().sizeOfExcludingThis(mallocSizeOf);
rtSizes->scriptData += scriptDataTable(lock).sizeOfExcludingThis(mallocSizeOf);
for (ScriptDataTable::Range r = scriptDataTable(lock).all(); !r.empty(); r.popFront())
rtSizes->scriptData += mallocSizeOf(r.front());
{
AutoLockScriptData lock(this);
rtSizes->scriptData += scriptDataTable(lock).sizeOfExcludingThis(mallocSizeOf);
for (ScriptDataTable::Range r = scriptDataTable(lock).all(); !r.empty(); r.popFront())
rtSizes->scriptData += mallocSizeOf(r.front());
}
if (jitRuntime_) {
jitRuntime_->execAlloc().addSizeOfCode(&rtSizes->code);
jitRuntime_->backedgeExecAlloc().addSizeOfCode(&rtSizes->code);
}
rtSizes->gc.marker += gc.marker.sizeOfExcludingThis(mallocSizeOf);
}
static bool

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

@ -234,6 +234,7 @@ void DisableExtraThreads();
using ScriptAndCountsVector = GCVector<ScriptAndCounts, 0, SystemAllocPolicy>;
class AutoLockForExclusiveAccess;
class AutoLockScriptData;
} // namespace js
@ -564,10 +565,26 @@ struct JSRuntime : public js::MallocProvider<JSRuntime>
bool activeThreadHasExclusiveAccess;
#endif
/* Number of zones which may be operated on by non-cooperating helper threads. */
/*
* Lock used to protect the script data table, which can be used by
* off-thread parsing.
*
* Locking this only occurs if there is actually a thread other than the
* active thread which could access this.
*/
js::Mutex scriptDataLock;
#ifdef DEBUG
bool activeThreadHasScriptDataAccess;
#endif
/*
* Number of zones which may be operated on by non-cooperating helper
* threads.
*/
js::UnprotectedData<size_t> numActiveHelperThreadZones;
friend class js::AutoLockForExclusiveAccess;
friend class js::AutoLockScriptData;
public:
void setUsedByHelperThread(JS::Zone* zone);
@ -582,6 +599,11 @@ struct JSRuntime : public js::MallocProvider<JSRuntime>
return (!hasHelperThreadZones() && activeThreadHasExclusiveAccess) ||
exclusiveAccessLock.ownedByCurrentThread();
}
bool currentThreadHasScriptDataAccess() const {
return (!hasHelperThreadZones() && activeThreadHasScriptDataAccess) ||
scriptDataLock.ownedByCurrentThread();
}
#endif
// How many compartments there are across all zones. This number includes
@ -868,9 +890,9 @@ struct JSRuntime : public js::MallocProvider<JSRuntime>
// within the runtime. This may be modified by threads using
// AutoLockForExclusiveAccess.
private:
js::ExclusiveAccessLockData<js::ScriptDataTable> scriptDataTable_;
js::ScriptDataLockData<js::ScriptDataTable> scriptDataTable_;
public:
js::ScriptDataTable& scriptDataTable(js::AutoLockForExclusiveAccess& lock) {
js::ScriptDataTable& scriptDataTable(const js::AutoLockScriptData& lock) {
return scriptDataTable_.ref();
}

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

@ -83,15 +83,15 @@ Shape::removeFromDictionary(NativeObject* obj)
MOZ_ASSERT(obj->inDictionaryMode());
MOZ_ASSERT(listp);
MOZ_ASSERT(obj->shape_->inDictionary());
MOZ_ASSERT(obj->shape_->listp == &obj->shape_);
MOZ_ASSERT(obj->shape()->inDictionary());
MOZ_ASSERT(obj->shape()->listp == obj->shapePtr());
if (parent)
parent->listp = listp;
*listp = parent;
listp = nullptr;
obj->shape_->clearCachedBigEnoughForShapeTable();
obj->shape()->clearCachedBigEnoughForShapeTable();
}
void
@ -341,7 +341,7 @@ NativeObject::getChildDataProperty(JSContext* cx,
return nullptr;
}
}
shape->initDictionaryShape(child, obj->numFixedSlots(), &obj->shape_);
shape->initDictionaryShape(child, obj->numFixedSlots(), obj->shapePtr());
return shape;
}
@ -372,7 +372,7 @@ NativeObject::getChildAccessorProperty(JSContext* cx,
Shape* shape = Allocate<AccessorShape>(cx);
if (!shape)
return nullptr;
shape->initDictionaryShape(child, obj->numFixedSlots(), &obj->shape_);
shape->initDictionaryShape(child, obj->numFixedSlots(), obj->shapePtr());
return shape;
}
@ -437,8 +437,8 @@ js::NativeObject::toDictionaryMode(JSContext* cx, HandleNativeObject obj)
}
MOZ_ASSERT(root->listp == nullptr);
root->listp = &obj->shape_;
obj->shape_ = root;
root->listp = obj->shapePtr();
obj->setShape(root);
MOZ_ASSERT(obj->inDictionaryMode());
root->base()->setSlotSpan(span);
@ -739,7 +739,7 @@ NativeObject::addEnumerableDataProperty(JSContext* cx, HandleNativeObject obj, H
return nullptr;
}
}
shape->initDictionaryShape(child, obj->numFixedSlots(), &obj->shape_);
shape->initDictionaryShape(child, obj->numFixedSlots(), obj->shapePtr());
} else {
uint32_t slot = obj->slotSpan();
MOZ_ASSERT(slot >= JSSLOT_FREE(obj->getClass()));
@ -1231,7 +1231,7 @@ NativeObject::clear(JSContext* cx, HandleNativeObject obj)
MOZ_ASSERT(shape->isEmptyShape());
if (obj->inDictionaryMode())
shape->listp = &obj->shape_;
shape->listp = obj->shapePtr();
JS_ALWAYS_TRUE(obj->setLastProperty(cx, shape));
@ -1814,7 +1814,7 @@ Shape::fixupDictionaryShapeAfterMovingGC()
// listp points to the shape_ field of an object.
JSObject* last = reinterpret_cast<JSObject*>(uintptr_t(listp) - ShapedObject::offsetOfShape());
if (gc::IsForwarded(last))
listp = &gc::Forwarded(last)->as<NativeObject>().shape_;
listp = gc::Forwarded(last)->as<NativeObject>().shapePtr();
}
}

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

@ -12,43 +12,48 @@
namespace js {
/*
* Shaped objects extend the base implementation of an object with a shape
* field. Subclasses of ShapedObject ascribe meaning to this field.
* Shaped objects are a variant of JSObject that use a GCPtrShape for their
* |shapeOrExpando_| field. All objects that point to a js::Shape as their
* |shapeOrExpando_| field should use this as their subclass.
*
* ShapedObject is only created as the base class of some other class. It's
* never created as a most-derived class.
* NOTE: shape()->getObjectClass() must equal getClass().
*/
class ShapedObject : public JSObject
{
protected:
// Property layout description and other state.
GCPtrShape shape_;
// ShapedObjects treat the |shapeOrExpando_| field as a GCPtrShape to
// ensure barriers are called. Use these instead of accessing
// |shapeOrExpando_| directly.
MOZ_ALWAYS_INLINE const GCPtrShape& shapeRef() const {
return *reinterpret_cast<const GCPtrShape*>(&(this->shapeOrExpando_));
}
MOZ_ALWAYS_INLINE GCPtrShape& shapeRef() {
return *reinterpret_cast<GCPtrShape*>(&(this->shapeOrExpando_));
}
// Used for GC tracing and Shape::listp
MOZ_ALWAYS_INLINE GCPtrShape* shapePtr() {
return reinterpret_cast<GCPtrShape*>(&(this->shapeOrExpando_));
}
public:
// Set the shape of an object. This pointer is valid for native objects and
// some non-native objects. After creating an object, the objects for which
// the shape pointer is invalid need to overwrite this pointer before a GC
// can occur.
void initShape(Shape* shape) {
this->shape_.init(shape);
}
void initShape(Shape* shape) { shapeRef().init(shape); }
void setShape(Shape* shape) {
this->shape_ = shape;
}
Shape* shape() const { return this->shape_; }
void setShape(Shape* shape) { shapeRef() = shape; }
Shape* shape() const { return shapeRef(); }
void traceShape(JSTracer* trc) {
TraceEdge(trc, &shape_, "shape");
TraceEdge(trc, shapePtr(), "shape");
}
static size_t offsetOfShape() { return offsetof(ShapedObject, shape_); }
private:
static void staticAsserts() {
static_assert(offsetof(ShapedObject, shape_) == offsetof(shadow::Object, shape),
static constexpr size_t offsetOfShape() {
static_assert(offsetOfShapeOrExpando() == offsetof(shadow::Object, shape),
"shadow shape must match actual shape");
return offsetOfShapeOrExpando();
}
};

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

@ -109,7 +109,7 @@ MOZ_ALWAYS_INLINE void
JSRope::init(JSContext* cx, JSString* left, JSString* right, size_t length)
{
d.u1.length = length;
d.u1.flags = ROPE_FLAGS;
d.u1.flags = INIT_ROPE_FLAGS;
if (left->hasLatin1Chars() && right->hasLatin1Chars())
d.u1.flags |= LATIN1_CHARS_BIT;
d.s.u2.left = left;
@ -206,7 +206,7 @@ MOZ_ALWAYS_INLINE void
JSFlatString::init(const char16_t* chars, size_t length)
{
d.u1.length = length;
d.u1.flags = FLAT_BIT;
d.u1.flags = LINEAR_BIT;
d.s.u2.nonInlineCharsTwoByte = chars;
}
@ -214,7 +214,7 @@ MOZ_ALWAYS_INLINE void
JSFlatString::init(const JS::Latin1Char* chars, size_t length)
{
d.u1.length = length;
d.u1.flags = FLAT_BIT | LATIN1_CHARS_BIT;
d.u1.flags = LINEAR_BIT | LATIN1_CHARS_BIT;
d.s.u2.nonInlineCharsLatin1 = chars;
}

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

@ -205,7 +205,7 @@ JSString::dumpRepresentationHeader(js::GenericPrinter& out, int indent, const ch
// Print the string's address as an actual C++ expression, to facilitate
// copy-and-paste into a debugger.
out.printf("((%s*) %p) length: %zu flags: 0x%x", subclass, this, length(), flags);
if (flags & FLAT_BIT) out.put(" FLAT");
if (flags & LINEAR_BIT) out.put(" LINEAR");
if (flags & HAS_BASE_BIT) out.put(" HAS_BASE");
if (flags & INLINE_CHARS_BIT) out.put(" INLINE_CHARS");
if (flags & ATOM_BIT) out.put(" ATOM");
@ -497,8 +497,10 @@ JSRope::flattenInternal(JSContext* maybecx)
wholeCapacity = capacity;
wholeChars = const_cast<CharT*>(left.nonInlineChars<CharT>(nogc));
pos = wholeChars + left.d.u1.length;
JS_STATIC_ASSERT(!(EXTENSIBLE_FLAGS & DEPENDENT_FLAGS));
left.d.u1.flags ^= (EXTENSIBLE_FLAGS | DEPENDENT_FLAGS);
if (IsSame<CharT, char16_t>::value)
left.d.u1.flags = DEPENDENT_FLAGS;
else
left.d.u1.flags = DEPENDENT_FLAGS | LATIN1_CHARS_BIT;
left.d.s.u3.base = (JSLinearString*)this; /* will be true on exit */
StringWriteBarrierPostRemove(maybecx, &left.d.s.u2.left);
StringWriteBarrierPost(maybecx, (JSString**)&left.d.s.u3.base);
@ -1102,7 +1104,7 @@ JSExternalString::ensureFlat(JSContext* cx)
// Transform the string into a non-external, flat string.
setNonInlineChars<char16_t>(s);
d.u1.flags = FLAT_BIT;
d.u1.flags = LINEAR_BIT;
return &this->asFlat();
}

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

@ -220,13 +220,13 @@ class JSString : public js::gc::TenuredCell
* String Instance Subtype
* type encoding predicate
* ------------------------------------
* Rope 000000 000000
* Linear - !000000
* Rope 000000 xxxxx0
* Linear - xxxxx1
* HasBase - xxxx1x
* Dependent 000010 000010
* External 100000 100000
* Flat - xxxxx1
* Undepended 000011 000011
* Dependent 000011 000011
* External 100001 100001
* Flat - Linear && !Dependent && !External
* Undepended 010011 010011
* Extensible 010001 010001
* Inline 000101 xxx1xx
* FatInline 010101 x1x1xx
@ -238,7 +238,7 @@ class JSString : public js::gc::TenuredCell
* Note that the first 4 flag bits (from right to left in the previous table)
* have the following meaning and can be used for some hot queries:
*
* Bit 0: IsFlat
* Bit 0: IsLinear
* Bit 1: HasBase (Dependent, Undepended)
* Bit 2: IsInline (Inline, FatInline)
* Bit 3: IsAtom (Atom, PermanentAtom)
@ -253,23 +253,23 @@ class JSString : public js::gc::TenuredCell
* index.
*/
static const uint32_t FLAT_BIT = JS_BIT(0);
static const uint32_t LINEAR_BIT = JS_BIT(0);
static const uint32_t HAS_BASE_BIT = JS_BIT(1);
static const uint32_t INLINE_CHARS_BIT = JS_BIT(2);
static const uint32_t ATOM_BIT = JS_BIT(3);
static const uint32_t ROPE_FLAGS = 0;
static const uint32_t DEPENDENT_FLAGS = HAS_BASE_BIT;
static const uint32_t UNDEPENDED_FLAGS = FLAT_BIT | HAS_BASE_BIT;
static const uint32_t EXTENSIBLE_FLAGS = FLAT_BIT | JS_BIT(4);
static const uint32_t EXTERNAL_FLAGS = JS_BIT(5);
static const uint32_t DEPENDENT_FLAGS = LINEAR_BIT | HAS_BASE_BIT;
static const uint32_t UNDEPENDED_FLAGS = LINEAR_BIT | HAS_BASE_BIT | JS_BIT(4);
static const uint32_t EXTENSIBLE_FLAGS = LINEAR_BIT | JS_BIT(4);
static const uint32_t EXTERNAL_FLAGS = LINEAR_BIT | JS_BIT(5);
static const uint32_t FAT_INLINE_MASK = INLINE_CHARS_BIT | JS_BIT(4);
static const uint32_t PERMANENT_ATOM_MASK = ATOM_BIT | JS_BIT(5);
/* Initial flags for thin inline and fat inline strings. */
static const uint32_t INIT_THIN_INLINE_FLAGS = FLAT_BIT | INLINE_CHARS_BIT;
static const uint32_t INIT_FAT_INLINE_FLAGS = FLAT_BIT | FAT_INLINE_MASK;
static const uint32_t INIT_THIN_INLINE_FLAGS = LINEAR_BIT | INLINE_CHARS_BIT;
static const uint32_t INIT_FAT_INLINE_FLAGS = LINEAR_BIT | FAT_INLINE_MASK;
static const uint32_t INIT_ROPE_FLAGS = 0;
static const uint32_t TYPE_FLAGS_MASK = JS_BIT(6) - 1;
@ -316,14 +316,14 @@ class JSString : public js::gc::TenuredCell
"shadow::String inlineStorage offset must match JSString");
static_assert(offsetof(JSString, d.inlineStorageTwoByte) == offsetof(String, inlineStorageTwoByte),
"shadow::String inlineStorage offset must match JSString");
static_assert(LINEAR_BIT == String::LINEAR_BIT,
"shadow::String::LINEAR_BIT must match JSString::LINEAR_BIT");
static_assert(INLINE_CHARS_BIT == String::INLINE_CHARS_BIT,
"shadow::String::INLINE_CHARS_BIT must match JSString::INLINE_CHARS_BIT");
static_assert(LATIN1_CHARS_BIT == String::LATIN1_CHARS_BIT,
"shadow::String::LATIN1_CHARS_BIT must match JSString::LATIN1_CHARS_BIT");
static_assert(TYPE_FLAGS_MASK == String::TYPE_FLAGS_MASK,
"shadow::String::TYPE_FLAGS_MASK must match JSString::TYPE_FLAGS_MASK");
static_assert(ROPE_FLAGS == String::ROPE_FLAGS,
"shadow::String::ROPE_FLAGS must match JSString::ROPE_FLAGS");
static_assert(EXTERNAL_FLAGS == String::EXTERNAL_FLAGS,
"shadow::String::EXTERNAL_FLAGS must match JSString::EXTERNAL_FLAGS");
}
@ -384,7 +384,7 @@ class JSString : public js::gc::TenuredCell
MOZ_ALWAYS_INLINE
bool isRope() const {
return (d.u1.flags & TYPE_FLAGS_MASK) == ROPE_FLAGS;
return !(d.u1.flags & LINEAR_BIT);
}
MOZ_ALWAYS_INLINE
@ -395,7 +395,7 @@ class JSString : public js::gc::TenuredCell
MOZ_ALWAYS_INLINE
bool isLinear() const {
return !isRope();
return d.u1.flags & LINEAR_BIT;
}
MOZ_ALWAYS_INLINE
@ -417,7 +417,7 @@ class JSString : public js::gc::TenuredCell
MOZ_ALWAYS_INLINE
bool isFlat() const {
return d.u1.flags & FLAT_BIT;
return isLinear() && !isDependent() && !isExternal();
}
MOZ_ALWAYS_INLINE

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

@ -299,18 +299,17 @@ UnboxedPlainObject::getValue(const UnboxedLayout::Property& property,
void
UnboxedPlainObject::trace(JSTracer* trc, JSObject* obj)
{
if (obj->as<UnboxedPlainObject>().expando_) {
TraceManuallyBarrieredEdge(trc,
reinterpret_cast<NativeObject**>(&obj->as<UnboxedPlainObject>().expando_),
"unboxed_expando");
}
UnboxedPlainObject* uobj = &obj->as<UnboxedPlainObject>();
const UnboxedLayout& layout = obj->as<UnboxedPlainObject>().layoutDontCheckGeneration();
if (uobj->maybeExpando())
TraceManuallyBarrieredEdge(trc, uobj->addressOfExpando(), "unboxed_expando");
const UnboxedLayout& layout = uobj->layoutDontCheckGeneration();
const int32_t* list = layout.traceList();
if (!list)
return;
uint8_t* data = obj->as<UnboxedPlainObject>().data();
uint8_t* data = uobj->data();
while (*list != -1) {
GCPtrString* heap = reinterpret_cast<GCPtrString*>(data + *list);
TraceEdge(trc, heap, "unboxed_string");
@ -330,8 +329,8 @@ UnboxedPlainObject::trace(JSTracer* trc, JSObject* obj)
/* static */ UnboxedExpandoObject*
UnboxedPlainObject::ensureExpando(JSContext* cx, Handle<UnboxedPlainObject*> obj)
{
if (obj->expando_)
return obj->expando_;
if (obj->maybeExpando())
return obj->maybeExpando();
UnboxedExpandoObject* expando =
NewObjectWithGivenProto<UnboxedExpandoObject>(cx, nullptr, gc::AllocKind::OBJECT4);
@ -356,7 +355,7 @@ UnboxedPlainObject::ensureExpando(JSContext* cx, Handle<UnboxedPlainObject*> obj
if (IsInsideNursery(expando) && !IsInsideNursery(obj))
cx->zone()->group()->storeBuffer().putWholeCell(obj);
obj->expando_ = expando;
obj->setExpandoUnsafe(expando);
return expando;
}

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

@ -225,10 +225,13 @@ class UnboxedExpandoObject : public NativeObject
// how their properties are stored.
class UnboxedPlainObject : public UnboxedObject
{
// Optional object which stores extra properties on this object. This is
// not automatically barriered to avoid problems if the object is converted
// to a native. See ensureExpando().
UnboxedExpandoObject* expando_;
// The |JSObject::shapeOrExpando_| field can optionally refer to an object
// which stores extra properties on this object. This is not automatically
// barriered to avoid problems if the object is converted to a native. See
// ensureExpando(). This object must be an UnboxedExpandoObject.
//
// NOTE: The JIT should not assume that seeing the same expando pointer
// means the object is even an UnboxedObject. Always check |group_|.
// Start of the inline data, which immediately follows the group and extra properties.
uint8_t data_[1];
@ -272,16 +275,20 @@ class UnboxedPlainObject : public UnboxedObject
}
UnboxedExpandoObject* maybeExpando() const {
return expando_;
return static_cast<UnboxedExpandoObject*>(shapeOrExpando_);
}
void setExpandoUnsafe(UnboxedExpandoObject* expando) {
shapeOrExpando_ = expando;
}
void initExpando() {
expando_ = nullptr;
shapeOrExpando_ = nullptr;
}
// For use during GC.
JSObject** addressOfExpando() {
return reinterpret_cast<JSObject**>(&expando_);
return reinterpret_cast<JSObject**>(&shapeOrExpando_);
}
bool containsUnboxedOrExpandoProperty(JSContext* cx, jsid id) const;
@ -303,7 +310,7 @@ class UnboxedPlainObject : public UnboxedObject
static void trace(JSTracer* trc, JSObject* object);
static size_t offsetOfExpando() {
return offsetof(UnboxedPlainObject, expando_);
return offsetOfShapeOrExpando();
}
static size_t offsetOfData() {

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

@ -1,13 +1,4 @@
[
{
"version": "Android NDK r15c + LLVM",
"size": 403602514,
"visibility": "internal",
"digest": "8515b8f615935e9ee81c1ada55ec46a9ebd46ca095b33bf2bf34d794b7737ffa8f32b4e3f410d3f63e2f2510fef7a5836a72c34b942a0687af8ca5a5d50efdb6",
"algorithm": "sha512",
"filename": "android-ndk.tar.bz2",
"unpack": true
},
{
"size": 6856444,
"visibility": "public",

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

@ -1,13 +1,4 @@
[
{
"version": "Android NDK r15c + LLVM",
"size": 403602514,
"visibility": "internal",
"digest": "8515b8f615935e9ee81c1ada55ec46a9ebd46ca095b33bf2bf34d794b7737ffa8f32b4e3f410d3f63e2f2510fef7a5836a72c34b942a0687af8ca5a5d50efdb6",
"algorithm": "sha512",
"filename": "android-ndk.tar.bz2",
"unpack": true
},
{
"size": 6856444,
"visibility": "public",

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

@ -2048,7 +2048,8 @@
if ( FT_NEW( face->blend ) )
goto Exit;
num_axes = fvar_head.axisCount;
num_axes = fvar_head.axisCount;
face->blend->num_axis = num_axes;
}
else
num_axes = face->blend->num_axis;

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

@ -5935,5 +5935,9 @@ pref("layers.omtp.enabled", true);
#else
pref("layers.omtp.enabled", false);
#endif
pref("layers.omtp.release-capture-on-main-thread", false);
#if defined(XP_MACOSX)
pref("layers.omtp.paint-workers", -1);
#else
pref("layers.omtp.paint-workers", 1);
#endif
pref("layers.omtp.release-capture-on-main-thread", false);

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

@ -11,6 +11,11 @@ import stat
import subprocess
import sys
# We need the NDK version in multiple different places, and it's inconvenient
# to pass down the NDK version to all relevant places, so we have this global
# variable.
NDK_VERSION = 'r15c'
ANDROID_NDK_EXISTS = '''
Looks like you have the Android NDK installed at:
%s
@ -137,7 +142,7 @@ def get_paths(os_name):
sdk_path = os.environ.get('ANDROID_SDK_HOME',
os.path.join(mozbuild_path, 'android-sdk-{0}'.format(os_name)))
ndk_path = os.environ.get('ANDROID_NDK_HOME',
os.path.join(mozbuild_path, 'android-ndk-r15c'))
os.path.join(mozbuild_path, 'android-ndk-{0}'.format(NDK_VERSION)))
return (mozbuild_path, sdk_path, ndk_path)
@ -151,7 +156,7 @@ def ensure_dir(dir):
raise
def ensure_android(os_name, artifact_mode=False, no_interactive=False):
def ensure_android(os_name, artifact_mode=False, ndk_only=False, no_interactive=False):
'''
Ensure the Android SDK (and NDK, if `artifact_mode` is falsy) are
installed. If not, fetch and unpack the SDK and/or NDK from the
@ -172,7 +177,11 @@ def ensure_android(os_name, artifact_mode=False, no_interactive=False):
ensure_android_sdk_and_ndk(mozbuild_path, os_name,
sdk_path=sdk_path, sdk_url=sdk_url,
ndk_path=ndk_path, ndk_url=ndk_url,
artifact_mode=artifact_mode)
artifact_mode=artifact_mode,
ndk_only=ndk_only)
if ndk_only:
return
# We expect the |sdkmanager| tool to be at
# ~/.mozbuild/android-sdk-$OS_NAME/tools/bin/sdkmanager.
@ -181,7 +190,7 @@ def ensure_android(os_name, artifact_mode=False, no_interactive=False):
def ensure_android_sdk_and_ndk(mozbuild_path, os_name, sdk_path, sdk_url, ndk_path, ndk_url,
artifact_mode):
artifact_mode, ndk_only):
'''
Ensure the Android SDK and NDK are found at the given paths. If not, fetch
and unpack the SDK and/or NDK from the given URLs into
@ -199,6 +208,9 @@ def ensure_android_sdk_and_ndk(mozbuild_path, os_name, sdk_path, sdk_url, ndk_pa
# The NDK archive unpacks into a top-level android-ndk-$VER directory.
install_mobile_android_sdk_or_ndk(ndk_url, mozbuild_path)
if ndk_only:
return
# We don't want to blindly overwrite, since we use the
# |sdkmanager| tool to install additional parts of the Android
# toolchain. If we overwrite, we lose whatever Android packages
@ -260,7 +272,7 @@ def suggest_mozconfig(os_name, artifact_mode=False):
print(MOBILE_ANDROID_MOZCONFIG_TEMPLATE % (sdk_path, ndk_path))
def android_ndk_url(os_name, ver='r15c'):
def android_ndk_url(os_name, ver=NDK_VERSION):
# Produce a URL like
# 'https://dl.google.com/android/repository/android-ndk-$VER-linux-x86_64.zip
base_url = 'https://dl.google.com/android/repository/android-ndk'
@ -284,11 +296,16 @@ def main(argv):
parser = optparse.OptionParser()
parser.add_option('-a', '--artifact-mode', dest='artifact_mode', action='store_true',
help='If true, install only the Android SDK (and not the Android NDK).')
parser.add_option('--ndk-only', dest='ndk_only', action='store_true',
help='If true, install only the Android NDK (and not the Android SDK).')
parser.add_option('--no-interactive', dest='no_interactive', action='store_true',
help='Accept the Android SDK licenses without user interaction.')
options, _ = parser.parse_args(argv)
if options.artifact_mode and options.ndk_only:
raise NotImplementedError('Use no options to install the NDK and the SDK.')
os_name = None
if platform.system() == 'Darwin':
os_name = 'macosx'
@ -301,6 +318,7 @@ def main(argv):
"NDK) on {0} yet!".format(platform.system()))
ensure_android(os_name, artifact_mode=options.artifact_mode,
ndk_only=options.ndk_only,
no_interactive=options.no_interactive)
suggest_mozconfig(os_name, options.artifact_mode)

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

@ -65,6 +65,9 @@ ContentSignatureVerifier::VerifyContentSignature(
if (rv == NS_ERROR_INVALID_SIGNATURE) {
return NS_OK;
}
// This failure can have many different reasons but we don't treat it as
// invalid signature.
Accumulate(Telemetry::CONTENT_SIGNATURE_VERIFICATION_STATUS, 3);
return rv;
}
@ -191,7 +194,17 @@ ContentSignatureVerifier::CreateContextInternal(const nsACString& aData,
return NS_ERROR_FAILURE;
}
// otherwise, assume the signature was invalid
CSVerifier_LOG(("CSVerifier: The supplied chain is bad\n"));
if (result == mozilla::pkix::Result::ERROR_EXPIRED_CERTIFICATE) {
Accumulate(Telemetry::CONTENT_SIGNATURE_VERIFICATION_STATUS, 4);
} else if (result ==
mozilla::pkix::Result::ERROR_NOT_YET_VALID_CERTIFICATE) {
Accumulate(Telemetry::CONTENT_SIGNATURE_VERIFICATION_STATUS, 5);
} else {
// Building cert chain failed for some other reason.
Accumulate(Telemetry::CONTENT_SIGNATURE_VERIFICATION_STATUS, 6);
}
CSVerifier_LOG(("CSVerifier: The supplied chain is bad (%s)\n",
MapResultToName(result)));
return NS_ERROR_INVALID_SIGNATURE;
}
@ -208,6 +221,8 @@ ContentSignatureVerifier::CreateContextInternal(const nsACString& aData,
BRNameMatchingPolicy nameMatchingPolicy(BRNameMatchingPolicy::Mode::Enforce);
result = CheckCertHostname(certDER, hostnameInput, nameMatchingPolicy);
if (result != Success) {
// EE cert isnot valid for the given host name.
Accumulate(Telemetry::CONTENT_SIGNATURE_VERIFICATION_STATUS, 7);
return NS_ERROR_INVALID_SIGNATURE;
}
@ -215,6 +230,7 @@ ContentSignatureVerifier::CreateContextInternal(const nsACString& aData,
// in case we were not able to extract a key
if (!mKey) {
Accumulate(Telemetry::CONTENT_SIGNATURE_VERIFICATION_STATUS, 8);
CSVerifier_LOG(("CSVerifier: unable to extract a key\n"));
return NS_ERROR_INVALID_SIGNATURE;
}
@ -253,10 +269,14 @@ ContentSignatureVerifier::CreateContextInternal(const nsACString& aData,
mCx = UniqueVFYContext(
VFY_CreateContext(mKey.get(), &signatureItem, oid, nullptr));
if (!mCx) {
// Creating context failed.
Accumulate(Telemetry::CONTENT_SIGNATURE_VERIFICATION_STATUS, 9);
return NS_ERROR_INVALID_SIGNATURE;
}
if (VFY_Begin(mCx.get()) != SECSuccess) {
// Creating context failed.
Accumulate(Telemetry::CONTENT_SIGNATURE_VERIFICATION_STATUS, 9);
return NS_ERROR_INVALID_SIGNATURE;
}
@ -423,13 +443,20 @@ ContentSignatureVerifier::End(bool* _retval)
// If we didn't create the context yet, bail!
if (!mHasCertChain) {
Accumulate(Telemetry::CONTENT_SIGNATURE_VERIFICATION_STATUS, 2);
MOZ_ASSERT_UNREACHABLE(
"Someone called ContentSignatureVerifier::End before "
"downloading the cert chain.");
return NS_ERROR_FAILURE;
}
*_retval = (VFY_End(mCx.get()) == SECSuccess);
bool result = (VFY_End(mCx.get()) == SECSuccess);
if (result) {
Accumulate(Telemetry::CONTENT_SIGNATURE_VERIFICATION_STATUS, 0);
} else {
Accumulate(Telemetry::CONTENT_SIGNATURE_VERIFICATION_STATUS, 1);
}
*_retval = result;
return NS_OK;
}

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

@ -13,6 +13,8 @@ const TEST_DATA_DIR = "test_content_signing/";
const ONECRL_NAME = "oneCRL-signer.mozilla.org";
const ABOUT_NEWTAB_NAME = "remotenewtab.content-signature.mozilla.org";
var VERIFICATION_HISTOGRAM = Services.telemetry
.getHistogramById("CONTENT_SIGNATURE_VERIFICATION_STATUS");
function getSignatureVerifier() {
return Cc["@mozilla.org/security/contentsignatureverifier;1"]
@ -33,6 +35,19 @@ function loadChain(prefix, names) {
return chain;
}
function check_telemetry(expected_index, expected) {
for (let i = 0; i < 10; i++) {
let expected_value = 0;
if (i == expected_index) {
expected_value = expected;
}
equal(VERIFICATION_HISTOGRAM.snapshot().counts[i], expected_value,
"count " + i + ": " + VERIFICATION_HISTOGRAM.snapshot().counts[i] +
" expected " + expected_value);
}
VERIFICATION_HISTOGRAM.clear();
}
function run_test() {
// set up some data
const DATA = readFile(do_get_file(TEST_DATA_DIR + "test.txt"));
@ -56,11 +71,21 @@ function run_test() {
let noSANChain = loadChain(TEST_DATA_DIR + "content_signing",
["onecrl_no_SAN_ee", "int", "root"]);
let expiredOneCRLChain = loadChain(TEST_DATA_DIR + "content_signing",
["onecrl_ee_expired", "int", "root"]);
let notValidYetOneCRLChain = loadChain(TEST_DATA_DIR + "content_signing",
["onecrl_ee_not_valid_yet", "int",
"root"]);
// Check signature verification works without error before the root is set
VERIFICATION_HISTOGRAM.clear();
let chain1 = oneCRLChain.join("\n");
let verifier = getSignatureVerifier();
ok(!verifier.verifyContentSignature(DATA, GOOD_SIGNATURE, chain1, ONECRL_NAME),
"Before the root is set, signatures should fail to verify but not throw.");
// Check for generic chain building error.
check_telemetry(6, 1);
setRoot(TEST_DATA_DIR + "content_signing_root.pem");
@ -73,12 +98,16 @@ function run_test() {
ok(verifier.verifyContentSignature(DATA, GOOD_SIGNATURE, chain2,
ABOUT_NEWTAB_NAME),
"A newtab signature should verify with the newtab chain");
// Check for valid signature
check_telemetry(0, 2);
// Check a bad signature when a good chain is provided
chain1 = oneCRLChain.join("\n");
verifier = getSignatureVerifier();
ok(!verifier.verifyContentSignature(DATA, BAD_SIGNATURE, chain1, ONECRL_NAME),
"A bad signature should not verify");
// Check for invalid signature
check_telemetry(1, 1);
// Check a good signature from cert with good SAN but a different key than the
// one used to create the signature
@ -87,6 +116,8 @@ function run_test() {
ok(!verifier.verifyContentSignature(DATA, GOOD_SIGNATURE, badKeyChain,
ONECRL_NAME),
"A signature should not verify if the signing key is wrong");
// Check for wrong key in cert.
check_telemetry(9, 1);
// Check a good signature from cert with good SAN but a different key than the
// one used to create the signature (this time, an RSA key)
@ -95,6 +126,8 @@ function run_test() {
ok(!verifier.verifyContentSignature(DATA, GOOD_SIGNATURE, rsaKeyChain,
ONECRL_NAME),
"A signature should not verify if the signing key is wrong (RSA)");
// Check for wrong key in cert.
check_telemetry(9, 1);
// Check a good signature from cert with good SAN but with chain missing root
let missingRoot = [oneCRLChain[0], oneCRLChain[1]].join("\n");
@ -102,6 +135,8 @@ function run_test() {
ok(!verifier.verifyContentSignature(DATA, GOOD_SIGNATURE, missingRoot,
ONECRL_NAME),
"A signature should not verify if the chain is incomplete (missing root)");
// Check for generic chain building error.
check_telemetry(6, 1);
// Check a good signature from cert with good SAN but with no path to root
let missingInt = [oneCRLChain[0], oneCRLChain[2]].join("\n");
@ -109,6 +144,8 @@ function run_test() {
ok(!verifier.verifyContentSignature(DATA, GOOD_SIGNATURE, missingInt,
ONECRL_NAME),
"A signature should not verify if the chain is incomplete (missing int)");
// Check for generic chain building error.
check_telemetry(6, 1);
// Check good signatures from good certificates with the wrong SANs
chain1 = oneCRLChain.join("\n");
@ -116,17 +153,39 @@ function run_test() {
ok(!verifier.verifyContentSignature(DATA, GOOD_SIGNATURE, chain1,
ABOUT_NEWTAB_NAME),
"A OneCRL signature should not verify if we require the newtab SAN");
// Check for invalid EE cert.
check_telemetry(7, 1);
chain2 = remoteNewTabChain.join("\n");
verifier = getSignatureVerifier();
ok(!verifier.verifyContentSignature(DATA, GOOD_SIGNATURE, chain2,
ONECRL_NAME),
"A newtab signature should not verify if we require the OneCRL SAN");
// Check for invalid EE cert.
check_telemetry(7, 1);
// Check good signatures with good chains with some other invalid names
verifier = getSignatureVerifier();
ok(!verifier.verifyContentSignature(DATA, GOOD_SIGNATURE, chain1, ""),
"A signature should not verify if the SANs do not match an empty name");
// Check for invalid EE cert.
check_telemetry(7, 1);
// Test expired certificate.
let chainExpired = expiredOneCRLChain.join("\n");
verifier = getSignatureVerifier();
ok(!verifier.verifyContentSignature(DATA, GOOD_SIGNATURE, chainExpired, ""),
"A signature should not verify if the signing certificate is expired");
// Check for expired cert.
check_telemetry(4, 1);
// Test not valid yet certificate.
let chainNotValidYet = notValidYetOneCRLChain.join("\n");
verifier = getSignatureVerifier();
ok(!verifier.verifyContentSignature(DATA, GOOD_SIGNATURE, chainNotValidYet, ""),
"A signature should not verify if the signing certificate is not valid yet");
// Check for not yet valid cert.
check_telemetry(5, 1);
let relatedName = "subdomain." + ONECRL_NAME;
verifier = getSignatureVerifier();

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

@ -0,0 +1,15 @@
-----BEGIN CERTIFICATE-----
MIICTjCCATagAwIBAgIUOQNrYQz01j0SirgoHMLKbtGL9RowDQYJKoZIhvcNAQEL
BQAwETEPMA0GA1UEAwwGaW50LUNBMCIYDzIwMTMwMTAxMDAwMDAwWhgPMjAxNDAx
MDEwMDAwMDBaMBwxGjAYBgNVBAMMEWVlLWludC1DQS1leHBpcmVkMHYwEAYHKoZI
zj0CAQYFK4EEACIDYgAEoWhyQzYrXHsYifN5FUYVocc/tI3uhj4CKRXbYI4lLeS3
Ey2ozpjoMVNOapwMCwnI1jmt6DIG5bqBNHOhH6Mw4F2oyW5Dg/4nhz2pcQO+KIjP
8ALwWvcaH93Mg3SqbqnOoz0wOzATBgNVHSUEDDAKBggrBgEFBQcDAzAkBgNVHREE
HTAbghlvbmVDUkwtc2lnbmVyLm1vemlsbGEub3JnMA0GCSqGSIb3DQEBCwUAA4IB
AQBZJPo4llgMe5588+BnRLnFguspIiwMWmTeqCfi8VQBx/tUwRiTizbU7J2Yh9bo
yZEPKfPSP2o8J0eSUgvXdVOxU1fNRuocsVfXUlveq5x10ddjXBT9X4AY1mtR7HJw
hl/7269N8b4itfrfvZmCBToJayjv0I2N84bqjpOnXJ/iB5YVdk8oZIJDXWi4SR3B
E9IejwA1fikpt++RjpJSZ1BSNU7FfiyGGUonxHDoP/29znaOJnpAqaH5LVJCRkfN
H12vePBbunZd+ay5r+mMJPaXR+V2sY8OaOfcrPSHQLa8Eb/EEhBuITMKkOucohjx
zqvM6S2iOI9GbwHClybEHRO7
-----END CERTIFICATE-----

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

@ -0,0 +1,6 @@
issuer:int-CA
subject:ee-int-CA-expired
subjectKey:secp384r1
validity:20130101-20140101
extension:extKeyUsage:codeSigning
extension:subjectAlternativeName:oneCRL-signer.mozilla.org

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

@ -0,0 +1,15 @@
-----BEGIN CERTIFICATE-----
MIICVDCCATygAwIBAgIUbV+rBAfhGRv/bU22A92xneoAy3owDQYJKoZIhvcNAQEL
BQAwETEPMA0GA1UEAwwGaW50LUNBMCIYDzIwNTAwMTAxMDAwMDAwWhgPMjA1MTAx
MDEwMDAwMDBaMCIxIDAeBgNVBAMMF2VlLWludC1DQS1ub3QteWV0LXZhbGlkMHYw
EAYHKoZIzj0CAQYFK4EEACIDYgAEoWhyQzYrXHsYifN5FUYVocc/tI3uhj4CKRXb
YI4lLeS3Ey2ozpjoMVNOapwMCwnI1jmt6DIG5bqBNHOhH6Mw4F2oyW5Dg/4nhz2p
cQO+KIjP8ALwWvcaH93Mg3SqbqnOoz0wOzATBgNVHSUEDDAKBggrBgEFBQcDAzAk
BgNVHREEHTAbghlvbmVDUkwtc2lnbmVyLm1vemlsbGEub3JnMA0GCSqGSIb3DQEB
CwUAA4IBAQAjXmLNn2kLa/FzNp7F3PqcSXuAO2jT31Y2g4pZnVqCDfMqplsl2ZFn
oam3wyQnepm3q9DD4BOAW9JFYR3wqnl9cBRNHlSGyjGM4qBpuSD6WxAz7EdFcRO6
fcA50245fAuB45UJeYJ58QvIBv7AwoBGnqAI7ZDN3eIGopZIL56jiH7vO9WyQPWj
XZAWrXTG68rEf0RxXRtjUv9coFiuInT8+oyXB3NwK2EbaI5IeR+x3qIDEgNKk+t+
PlE3NrtaAiK19p0s9RtQQilBKNmo+5irrUq/OD2H1aurDaAXpLTM5vLUpfyN3/qD
HzuZujaUIeMsRiXsIRDNql1S+nq4oNRy
-----END CERTIFICATE-----

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

@ -0,0 +1,6 @@
issuer:int-CA
subject:ee-int-CA-not-yet-valid
subjectKey:secp384r1
validity:20500101-20510101
extension:extKeyUsage:codeSigning
extension:subjectAlternativeName:oneCRL-signer.mozilla.org

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

@ -9,6 +9,8 @@
# 'content_signing_int.pem',
# 'content_signing_onecrl_RSA_ee.pem',
# 'content_signing_onecrl_ee.pem',
# 'content_signing_onecrl_ee_expired.pem',
# 'content_signing_onecrl_ee_not_valid_yet.pem',
# 'content_signing_onecrl_no_SAN_ee.pem',
# 'content_signing_onecrl_wrong_key_ee.pem',
# 'content_signing_remote_newtab_ee.pem',

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

@ -28,10 +28,16 @@
#include "mozilla/NullPtr.h"
#include "mozilla/Sprintf.h"
#include "mozilla/ipc/FileDescriptor.h"
#include "nsDirectoryServiceDefs.h"
#include "nsAppDirectoryServiceDefs.h"
#include "SpecialSystemDirectory.h"
#include "sandbox/linux/system_headers/linux_syscalls.h"
namespace mozilla {
// Default/fallback temporary directory
static const nsLiteralCString tempDirPrefix("/tmp");
// This constructor signals failure by setting mFileDesc and aClientFd to -1.
SandboxBroker::SandboxBroker(UniquePtr<const Policy> aPolicy, int aChildPid,
int& aClientFd)
@ -515,6 +521,40 @@ SandboxBroker::ConvertToRealPath(char* aPath, size_t aBufSize, size_t aPathLen)
return aPathLen;
}
size_t
SandboxBroker::RemapTempDirs(char* aPath, size_t aBufSize, size_t aPathLen)
{
nsAutoCString path(aPath);
size_t prefixLen = 0;
if (!mTempPath.IsEmpty() && StringBeginsWith(path, mTempPath)) {
prefixLen = mTempPath.Length();
} else if (StringBeginsWith(path, tempDirPrefix)) {
prefixLen = tempDirPrefix.Length();
}
if (prefixLen) {
const nsDependentCSubstring cutPath =
Substring(path, prefixLen, path.Length() - prefixLen);
// Only now try to get the content process temp dir
nsCOMPtr<nsIFile> tmpDir;
nsresult rv = NS_GetSpecialDirectory(NS_APP_CONTENT_PROCESS_TEMP_DIR,
getter_AddRefs(tmpDir));
if (NS_SUCCEEDED(rv)) {
nsAutoCString tmpPath;
rv = tmpDir->GetNativePath(tmpPath);
if (NS_SUCCEEDED(rv)) {
tmpPath.Append(cutPath);
base::strlcpy(aPath, tmpPath.get(), aBufSize);
return strlen(aPath);
}
}
}
return aPathLen;
}
nsCString
SandboxBroker::ReverseSymlinks(const nsACString& aPath)
{
@ -585,6 +625,36 @@ SandboxBroker::ThreadMain(void)
// before the main thread loop starts
bool permissive = SandboxInfo::Get().Test(SandboxInfo::kPermissive);
// Find the current temporary directory
nsCOMPtr<nsIFile> tmpDir;
nsresult rv = GetSpecialSystemDirectory(OS_TemporaryDirectory,
getter_AddRefs(tmpDir));
if (NS_SUCCEEDED(rv)) {
rv = tmpDir->GetNativePath(mTempPath);
if (NS_SUCCEEDED(rv)) {
// Make sure there's no terminating /
if (mTempPath.Last() == '/') {
mTempPath.Truncate(mTempPath.Length() - 1);
}
}
}
// If we can't find it, we aren't bothered much: we will
// always try /tmp anyway in the substitution code
if (NS_FAILED(rv) || mTempPath.IsEmpty()) {
if (SandboxInfo::Get().Test(SandboxInfo::kVerbose)) {
SANDBOX_LOG_ERROR("Tempdir: /tmp");
}
} else {
if (SandboxInfo::Get().Test(SandboxInfo::kVerbose)) {
SANDBOX_LOG_ERROR("Tempdir: %s", mTempPath.get());
}
// If it's /tmp, clear it here so we don't compare against
// it twice. Just let the fallback code do the work.
if (mTempPath.Equals(tempDirPrefix)) {
mTempPath.Truncate();
}
}
while (true) {
struct iovec ios[2];
// We will receive the path strings in 1 buffer and split them back up.
@ -678,14 +748,19 @@ SandboxBroker::ThreadMain(void)
perms = mPolicy->Lookup(nsDependentCString(pathBuf, pathLen));
// We don't have read permissions on the requested dir.
// Did we arrive from a symlink in a path that is not writable?
// Then try to figure out the original path and see if that is readable.
if (!(perms & MAY_READ)) {
// Work on the original path,
// this reverses ConvertToRealPath above.
int symlinkPerms = SymlinkPermissions(recvBuf, first_len);
if (symlinkPerms > 0) {
perms = symlinkPerms;
// Was it a tempdir that we can remap?
pathLen = RemapTempDirs(pathBuf, sizeof(pathBuf), pathLen);
perms = mPolicy->Lookup(nsDependentCString(pathBuf, pathLen));
if (!(perms & MAY_READ)) {
// Did we arrive from a symlink in a path that is not writable?
// Then try to figure out the original path and see if that is
// readable. Work on the original path, this reverses
// ConvertToRealPath above.
int symlinkPerms = SymlinkPermissions(recvBuf, first_len);
if (symlinkPerms > 0) {
perms = symlinkPerms;
}
}
}

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

@ -132,6 +132,7 @@ class SandboxBroker final
int mFileDesc;
const int mChildPid;
const UniquePtr<const Policy> mPolicy;
nsCString mTempPath;
typedef nsDataHashtable<nsCStringHashKey, nsCString> PathMap;
PathMap mSymlinkMap;
@ -143,6 +144,8 @@ class SandboxBroker final
void AuditDenial(int aOp, int aFlags, int aPerms, const char* aPath);
// Remap relative paths to absolute paths.
size_t ConvertToRealPath(char* aPath, size_t aBufSize, size_t aPathLen);
// Remap references to /tmp and friends to the content process tempdir
size_t RemapTempDirs(char* aPath, size_t aBufSize, size_t aPathLen);
nsCString ReverseSymlinks(const nsACString& aPath);
// Retrieves permissions for the path the original symlink sits in.
int SymlinkPermissions(const char* aPath, const size_t aPathLen);

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

@ -188,25 +188,6 @@ SandboxBrokerPolicyFactory::SandboxBrokerPolicyFactory()
policy->AddDir(rdwrcr, "/dev/shm");
// Write permssions
//
// Add write permissions on the temporary directory. This can come
// from various environment variables (TMPDIR,TMP,TEMP,...) so
// make sure to use the full logic.
nsCOMPtr<nsIFile> tmpDir;
nsresult rv = GetSpecialSystemDirectory(OS_TemporaryDirectory,
getter_AddRefs(tmpDir));
if (NS_SUCCEEDED(rv)) {
nsAutoCString tmpPath;
rv = tmpDir->GetNativePath(tmpPath);
if (NS_SUCCEEDED(rv)) {
policy->AddDir(rdwrcr, tmpPath.get());
}
}
// If the above fails at any point, fall back to a very good guess.
if (NS_FAILED(rv)) {
policy->AddDir(rdwrcr, "/tmp");
}
// Bug 1308851: NVIDIA proprietary driver when using WebGL
policy->AddFilePrefix(rdwr, "/dev", "nvidia");
@ -227,8 +208,6 @@ SandboxBrokerPolicyFactory::SandboxBrokerPolicyFactory()
policy->AddDir(rdonly, "/etc");
policy->AddDir(rdonly, "/usr/share");
policy->AddDir(rdonly, "/usr/local/share");
policy->AddDir(rdonly, "/usr/tmp");
policy->AddDir(rdonly, "/var/tmp");
// Various places where fonts reside
policy->AddDir(rdonly, "/usr/X11R6/lib/X11/fonts");
policy->AddDir(rdonly, "/nix/store");
@ -276,7 +255,8 @@ SandboxBrokerPolicyFactory::SandboxBrokerPolicyFactory()
};
nsCOMPtr<nsIFile> homeDir;
rv = GetSpecialSystemDirectory(Unix_HomeDirectory, getter_AddRefs(homeDir));
nsresult rv = GetSpecialSystemDirectory(Unix_HomeDirectory,
getter_AddRefs(homeDir));
if (NS_SUCCEEDED(rv)) {
nsCOMPtr<nsIFile> confDir;
@ -374,6 +354,22 @@ SandboxBrokerPolicyFactory::SandboxBrokerPolicyFactory()
}
}
#ifdef DEBUG
char *bloatLog = PR_GetEnv("XPCOM_MEM_BLOAT_LOG");
// XPCOM_MEM_BLOAT_LOG has the format
// /tmp/tmpd0YzFZ.mozrunner/runtests_leaks.log
// but stores into /tmp/tmpd0YzFZ.mozrunner/runtests_leaks_tab_pid3411.log
// So cut the .log part and whitelist the prefix.
if (bloatLog != nullptr) {
size_t bloatLen = strlen(bloatLog);
if (bloatLen >= 4) {
nsAutoCString bloatStr(bloatLog);
bloatStr.Truncate(bloatLen - 4);
policy->AddPrefix(rdwrcr, bloatStr.get());
}
}
#endif
mCommonContentPolicy.reset(policy);
#endif
}
@ -433,25 +429,34 @@ SandboxBrokerPolicyFactory::GetContentPolicy(int aPid, bool aFileProcess)
// to get_mempolicy if this fails
policy->AddPath(rdonly, nsPrintfCString("/proc/%d/status", aPid).get());
// Add write permissions on the content process specific temporary dir.
nsCOMPtr<nsIFile> tmpDir;
nsresult rv = NS_GetSpecialDirectory(NS_APP_CONTENT_PROCESS_TEMP_DIR,
getter_AddRefs(tmpDir));
if (NS_SUCCEEDED(rv)) {
nsAutoCString tmpPath;
rv = tmpDir->GetNativePath(tmpPath);
if (NS_SUCCEEDED(rv)) {
policy->AddDir(rdwrcr, tmpPath.get());
}
}
// userContent.css and the extensions dir sit in the profile, which is
// normally blocked and we can't get the profile dir earlier in startup,
// so this must happen here.
nsCOMPtr<nsIFile> profileDir;
nsresult rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
getter_AddRefs(profileDir));
rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
getter_AddRefs(profileDir));
if (NS_SUCCEEDED(rv)) {
nsCOMPtr<nsIFile> workDir;
rv = profileDir->Clone(getter_AddRefs(workDir));
if (NS_SUCCEEDED(rv)) {
rv = workDir->AppendNative(NS_LITERAL_CSTRING("chrome"));
if (NS_SUCCEEDED(rv)) {
rv = workDir->AppendNative(NS_LITERAL_CSTRING("userContent.css"));
nsAutoCString tmpPath;
rv = workDir->GetNativePath(tmpPath);
if (NS_SUCCEEDED(rv)) {
nsAutoCString tmpPath;
rv = workDir->GetNativePath(tmpPath);
if (NS_SUCCEEDED(rv)) {
policy->AddPath(rdonly, tmpPath.get());
}
policy->AddDir(rdonly, tmpPath.get());
}
}
}

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

@ -161,9 +161,7 @@ function minHomeReadSandboxLevel(level) {
// content process--expected to fail.
//
// Tests attempting to write to a file in the content temp directory
// from the content process--expected to succeed. On Mac and Windows,
// use "ContentTmpD", but on Linux use "TmpD" until Linux uses the
// content temp dir key.
// from the content process--expected to succeed. Uses "ContentTmpD".
//
// Tests reading various files and directories from file and web
// content processes.
@ -180,9 +178,6 @@ add_task(async function() {
let prefExists = true;
// Read the security.sandbox.content.level pref.
// If the pref isn't set and we're running on Linux on !isNightly(),
// exit without failing. The Linux content sandbox is only enabled
// on Nightly at this time.
// eslint-disable-next-line mozilla/use-default-preference-values
try {
level = Services.prefs.getIntPref("security.sandbox.content.level");
@ -285,20 +280,15 @@ async function testFileAccess() {
// that will be read from either a web or file process.
let tests = [];
// The Linux test runners create the temporary profile in the same
// system temp dir we give write access to, so this gives a false
// positive.
let profileDir = GetProfileDir();
if (!isLinux()) {
tests.push({
desc: "profile dir", // description
ok: false, // expected to succeed?
browser: webBrowser, // browser to run test in
file: profileDir, // nsIFile object
minLevel: minProfileReadSandboxLevel(), // min level to enable test
func: readDir,
});
}
tests.push({
desc: "profile dir", // description
ok: false, // expected to succeed?
browser: webBrowser, // browser to run test in
file: profileDir, // nsIFile object
minLevel: minProfileReadSandboxLevel(), // min level to enable test
func: readDir,
});
if (fileContentProcessEnabled) {
tests.push({
desc: "profile dir",
@ -560,18 +550,14 @@ async function testFileAccess() {
let cookiesFile = GetProfileEntry("cookies.sqlite");
if (cookiesFile.exists() && !cookiesFile.isDirectory()) {
// On Linux, the temporary profile used for tests is in the system
// temp dir which content has read access to, so this test fails.
if (!isLinux()) {
tests.push({
desc: "cookies file",
ok: false,
browser: webBrowser,
file: cookiesFile,
minLevel: minProfileReadSandboxLevel(),
func: readFile,
});
}
tests.push({
desc: "cookies file",
ok: false,
browser: webBrowser,
file: cookiesFile,
minLevel: minProfileReadSandboxLevel(),
func: readFile,
});
if (fileContentProcessEnabled) {
tests.push({
desc: "cookies file",

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

@ -41,10 +41,6 @@ function fileInHomeDir() {
// Returns a file object for a new file in the content temp dir (.../<UUID>).
function fileInTempDir() {
let contentTempKey = "ContentTmpD";
if (Services.appinfo.OS == "Linux") {
// Linux builds don't use the content-specific temp key
contentTempKey = "TmpD";
}
// get the content temp dir, make sure it exists
let ctmp = Services.dirsvc.get(contentTempKey, Ci.nsIFile);

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

@ -39,6 +39,7 @@ android-api-16/debug:
tooltool-downloads: internal
toolchains:
- android-gradle-dependencies
- android-ndk-linux
- android-sdk-linux
- linux64-clang
- linux64-rust-android
@ -91,6 +92,7 @@ android-x86/opt:
tooltool-downloads: internal
toolchains:
- android-gradle-dependencies
- android-ndk-linux
- android-sdk-linux
- linux64-clang
- linux64-rust-android
@ -149,6 +151,7 @@ android-x86-nightly/opt:
tooltool-downloads: internal
toolchains:
- android-gradle-dependencies
- android-ndk-linux
- android-sdk-linux
- linux64-clang
- linux64-rust-android
@ -196,6 +199,7 @@ android-api-16/opt:
tooltool-downloads: internal
toolchains:
- android-gradle-dependencies
- android-ndk-linux
- android-sdk-linux
- linux64-clang
- linux64-rust-android
@ -298,6 +302,7 @@ android-api-16-nightly/opt:
tooltool-downloads: internal
toolchains:
- android-gradle-dependencies
- android-ndk-linux
- android-sdk-linux
- linux64-clang
- linux64-rust-android
@ -351,6 +356,7 @@ android-x86-old-id/opt:
run-on-projects: ['mozilla-central']
toolchains:
- android-gradle-dependencies
- android-ndk-linux
- android-sdk-linux
- linux64-clang
- linux64-rust-android
@ -408,6 +414,7 @@ android-x86-old-id-nightly/opt:
run-on-projects: ['mozilla-central']
toolchains:
- android-gradle-dependencies
- android-ndk-linux
- android-sdk-linux
- linux64-clang
- linux64-rust-android
@ -456,6 +463,7 @@ android-api-16-old-id/opt:
run-on-projects: ['mozilla-central']
toolchains:
- android-gradle-dependencies
- android-ndk-linux
- android-sdk-linux
- linux64-clang
- linux64-rust-android
@ -508,6 +516,7 @@ android-api-16-old-id-nightly/opt:
run-on-projects: ['mozilla-central']
toolchains:
- android-gradle-dependencies
- android-ndk-linux
- android-sdk-linux
- linux64-clang
- linux64-rust-android
@ -554,6 +563,7 @@ android-api-16-gradle/opt:
custom-build-variant-cfg: api-16-gradle
tooltool-downloads: internal
toolchains:
- android-ndk-linux
- android-sdk-linux
- linux64-clang
- linux64-rust-android
@ -601,6 +611,7 @@ android-aarch64/opt:
tooltool-downloads: internal
toolchains:
- android-gradle-dependencies
- android-ndk-linux
- android-sdk-linux
- linux64-clang
- linux64-rust-android
@ -654,6 +665,7 @@ android-aarch64-nightly/opt:
tooltool-downloads: internal
toolchains:
- android-gradle-dependencies
- android-ndk-linux
- android-sdk-linux
- linux64-clang
- linux64-rust-android

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

@ -23,7 +23,6 @@ job-defaults:
requires-signed-builds:
by-test-platform:
windows10-64-asan/opt: false # No XPCShell on ASAN yet
windows10-64-ccov/debug: false # TODO: Sign build.
windows.*: true
default: false

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

@ -301,6 +301,29 @@ linux64-android-sdk-linux-repack:
toolchain-artifact: project/gecko/android-sdk/android-sdk-linux.tar.xz
toolchain-alias: android-sdk-linux
linux64-android-ndk-linux-repack:
description: "Android NDK (Linux) repack toolchain build"
treeherder:
kind: build
platform: toolchains/opt
symbol: TL(android-ndk-linux)
tier: 1
worker-type: aws-provisioner-v1/gecko-{level}-b-linux
worker:
docker-image: {in-tree: android-build}
max-run-time: 1800
artifacts:
- name: project/gecko/android-ndk
path: /builds/worker/project/gecko/android-ndk/
type: directory
run:
using: toolchain-script
script: repack-android-ndk-linux.sh
resources:
- 'python/mozboot/**/*android*'
toolchain-artifact: project/gecko/android-ndk/android-ndk.tar.xz
toolchain-alias: android-ndk-linux
linux64-android-gradle-dependencies:
description: "Android Gradle dependencies toolchain task"
treeherder:

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

@ -0,0 +1,20 @@
#!/bin/bash
set -x -e -v
# This script is for fetching and repacking the Android NDK (for
# Linux), the tools required to produce native Android programs.
WORKSPACE=$HOME/workspace
UPLOAD_DIR=$HOME/project/gecko/android-ndk
mkdir -p $HOME/artifacts $UPLOAD_DIR
# Populate /builds/worker/.mozbuild/android-ndk-$VER.
cd /builds/worker/workspace/build/src
./mach python python/mozboot/mozboot/android.py --ndk-only --no-interactive
# Don't generate a tarball with a versioned NDK directory.
mv $HOME/.mozbuild/android-ndk-* $HOME/.mozbuild/android-ndk
tar cf - -C /builds/worker/.mozbuild android-ndk | xz > $UPLOAD_DIR/android-ndk.tar.xz
ls -al $UPLOAD_DIR

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

@ -12,6 +12,7 @@ LABELS_WHICH_SHOULD_SIGN_CI_BUILDS = (
'build-win32/debug', 'build-win32/opt', 'build-win32/pgo',
'build-win64/debug', 'build-win64/opt', 'build-win64/pgo',
'build-win32-devedition/opt', 'build-win64-devedition/opt',
'build-win64-ccov/debug',
'release-source-linux64-source/opt',
'release-source-linux64-fennec-source/opt',
'release-source-linux64-devedition-source/opt',

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

@ -111,7 +111,7 @@ def make_task_description(config, jobs):
dep_th_platform, build_platform, build_type
))
treeherder.setdefault('tier', 1)
treeherder.setdefault('tier', 1 if '-ccov' not in build_platform else 2)
treeherder.setdefault('kind', 'build')
label = job['label']
@ -155,7 +155,12 @@ def make_task_description(config, jobs):
def _generate_treeherder_platform(dep_th_platform, build_platform, build_type):
actual_build_type = 'pgo' if '-pgo' in build_platform else build_type
if '-pgo' in build_platform:
actual_build_type = 'pgo'
elif '-ccov' in build_platform:
actual_build_type = 'ccov'
else:
actual_build_type = build_type
return '{}/{}'.format(dep_th_platform, actual_build_type)

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

@ -10341,6 +10341,15 @@
"n_values": 10,
"description": "How often would blocked mixed content be allowed if HSTS upgrades were allowed? 0=display/no-HSTS, 1=display/HSTS, 2=active/no-HSTS, 3=active/HSTS"
},
"CONTENT_SIGNATURE_VERIFICATION_STATUS": {
"record_in_processes": ["main", "content"],
"alert_emails": ["seceng-telemetry@mozilla.com", "fkiefer@mozilla.com"],
"expires_in_version": "never",
"kind": "enumerated",
"n_values": 20,
"bug_numbers": [1258647],
"description": "What was the result of the content signature verification? 0=valid, 1=invalid, 2=noCertChain, 3=createContextFailedWithOtherError, 4=expiredCert, 5=certNotValidYet, 6=buildCertChainFailed, 7=eeCertForWrongHost, 8=extractKeyError, 9=vfyContextError"
},
"HSTS_UPGRADE_SOURCE": {
"record_in_processes": [ "main" ],
"alert_emails": ["seceng-telemetry@mozilla.com"],

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

@ -7,7 +7,6 @@
[DEFAULT]
tags = appupdate
head = head_update.js
fail-if = os == 'win' && ccov
[bootstrapSvc.js]
run-sequentially = Uses the Mozilla Maintenance Service.

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

@ -66,14 +66,12 @@
#if defined(MOZ_CONTENT_SANDBOX)
#include "mozilla/SandboxSettings.h"
#if (defined(XP_WIN) || defined(XP_MACOSX))
#include "nsIUUIDGenerator.h"
#include "mozilla/Unused.h"
#if defined(XP_WIN)
#include "WinUtils.h"
#endif
#endif
#endif
#if defined(XP_MACOSX)
#define APP_REGISTRY_NAME "Application Registry"
@ -85,7 +83,7 @@
#define PREF_OVERRIDE_DIRNAME "preferences"
#if (defined(XP_WIN) || defined(XP_MACOSX)) && defined(MOZ_CONTENT_SANDBOX)
#if defined(MOZ_CONTENT_SANDBOX)
static already_AddRefed<nsIFile> GetContentProcessSandboxTempDir();
static nsresult DeleteDirIfExists(nsIFile *dir);
static bool IsContentSandboxDisabled();
@ -499,7 +497,7 @@ nsXREDirProvider::GetFile(const char* aProperty, bool* aPersistent,
bool unused;
rv = dirsvc->GetFile("XCurProcD", &unused, getter_AddRefs(file));
}
#if (defined(XP_WIN) || defined(XP_MACOSX)) && defined(MOZ_CONTENT_SANDBOX)
#if defined(MOZ_CONTENT_SANDBOX)
else if (!strcmp(aProperty, NS_APP_CONTENT_PROCESS_TEMP_DIR)) {
if (!mContentTempDir && NS_FAILED((rv = LoadContentProcessTempDir()))) {
return rv;
@ -659,7 +657,7 @@ nsXREDirProvider::GetFiles(const char* aProperty, nsISimpleEnumerator** aResult)
return NS_SUCCESS_AGGREGATE_RESULT;
}
#if (defined(XP_WIN) || defined(XP_MACOSX)) && defined(MOZ_CONTENT_SANDBOX)
#if defined(MOZ_CONTENT_SANDBOX)
static const char*
GetContentProcessTempBaseDirKey()
@ -781,11 +779,16 @@ CreateContentProcessSandboxTempDir()
char uuidChars[NSID_LENGTH];
uuid.ToProvidedString(uuidChars);
tempDirSuffix.AssignASCII(uuidChars);
tempDirSuffix.AssignASCII(uuidChars, NSID_LENGTH);
#ifdef XP_UNIX
// Braces in a path are somewhat annoying to deal with
// and pretty alien on Unix
tempDirSuffix.StripChars(u"{}");
#endif
// Save the pref
rv = Preferences::SetCString("security.sandbox.content.tempDirSuffix",
uuidChars);
rv = Preferences::SetString("security.sandbox.content.tempDirSuffix",
tempDirSuffix);
if (NS_WARN_IF(NS_FAILED(rv))) {
// If we fail to save the pref we don't want to create the temp dir,
// because we won't be able to clean it up later.
@ -842,8 +845,7 @@ DeleteDirIfExists(nsIFile* dir)
return NS_OK;
}
#endif // (defined(XP_WIN) || defined(XP_MACOSX)) &&
// defined(MOZ_CONTENT_SANDBOX)
#endif // defined(MOZ_CONTENT_SANDBOX)
static const char *const kAppendPrefDir[] = { "defaults", "preferences", nullptr };
@ -1067,7 +1069,7 @@ nsXREDirProvider::DoStartup()
obsSvc->NotifyObservers(nullptr, "profile-initial-state", nullptr);
#if (defined(XP_WIN) || defined(XP_MACOSX)) && defined(MOZ_CONTENT_SANDBOX)
#if defined(MOZ_CONTENT_SANDBOX)
// Makes sure the content temp dir has been loaded if it hasn't been
// already. In the parent this ensures it has been created before we attempt
// to start any content processes.
@ -1107,7 +1109,7 @@ nsXREDirProvider::DoShutdown()
mProfileNotified = false;
}
#if (defined(XP_WIN) || defined(XP_MACOSX)) && defined(MOZ_CONTENT_SANDBOX)
#if defined(MOZ_CONTENT_SANDBOX)
if (XRE_IsParentProcess()) {
Unused << DeleteDirIfExists(mContentProcessSandboxTempDir);
}

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

@ -125,7 +125,7 @@ protected:
// delimiters.
static inline nsresult AppendProfileString(nsIFile* aFile, const char* aPath);
#if (defined(XP_WIN) || defined(XP_MACOSX)) && defined(MOZ_CONTENT_SANDBOX)
#if defined(MOZ_CONTENT_SANDBOX)
// Load the temp directory for sandboxed content processes
nsresult LoadContentProcessTempDir();
#endif
@ -143,7 +143,7 @@ protected:
nsCOMPtr<nsIFile> mProfileLocalDir;
bool mProfileNotified;
bool mPrefsInitialized = false;
#if (defined(XP_WIN) || defined(XP_MACOSX)) && defined(MOZ_CONTENT_SANDBOX)
#if defined(MOZ_CONTENT_SANDBOX)
nsCOMPtr<nsIFile> mContentTempDir;
nsCOMPtr<nsIFile> mContentProcessSandboxTempDir;
#endif

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

@ -76,7 +76,7 @@
#define NS_APP_PERMISSION_PARENT_DIR "permissionDBPDir"
#if (defined(XP_WIN) || defined(XP_MACOSX)) && defined(MOZ_CONTENT_SANDBOX)
#if defined(MOZ_CONTENT_SANDBOX)
//
// NS_APP_CONTENT_PROCESS_TEMP_DIR refers to a directory that is read and
// write accessible from a sandboxed content process. The key may be used in