mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-15 14:25:52 +00:00
Merge mozilla-central to autoland. a=merge CLOSED TREE
This commit is contained in:
commit
d8b0109aae
@ -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:
|
||||
|
20
taskcluster/scripts/misc/repack-android-ndk-linux.sh
Executable file
20
taskcluster/scripts/misc/repack-android-ndk-linux.sh
Executable file
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user