author | Brindusan Cristian <cbrindusan@mozilla.com> |
Fri, 04 Oct 2019 12:46:05 +0300 | |
changeset 496421 | 81ebffadd73ab463785bacfbcd38644fa576bacd |
parent 496420 | 678d4d2c3c4dfe1dbb2edfdc26d9f0723acebdd2 (current diff) |
parent 496279 | d2706c5d06eafdc10bbd25fba3f332b6954e3bd3 (diff) |
child 496422 | 8d68e16d3d775740b85377b775eecb2173c6a03c |
push id | 97227 |
push user | ncsoregi@mozilla.com |
push date | Fri, 04 Oct 2019 21:43:23 +0000 |
treeherder | autoland@02bc638506ec [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | merge |
milestone | 71.0a1 |
first release with | nightly linux32
81ebffadd73a
/
71.0a1
/
20191004094656
/
files
nightly linux64
81ebffadd73a
/
71.0a1
/
20191004094656
/
files
nightly mac
81ebffadd73a
/
71.0a1
/
20191004094656
/
files
nightly win32
81ebffadd73a
/
71.0a1
/
20191004094656
/
files
nightly win64
81ebffadd73a
/
71.0a1
/
20191004094656
/
files
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
releases | nightly linux32
71.0a1
/
20191004094656
/
pushlog to previous
nightly linux64
71.0a1
/
20191004094656
/
pushlog to previous
nightly mac
71.0a1
/
20191004094656
/
pushlog to previous
nightly win32
71.0a1
/
20191004094656
/
pushlog to previous
nightly win64
71.0a1
/
20191004094656
/
pushlog to previous
|
--- a/browser/components/customizableui/test/browser_PanelMultiView_keyboard.js +++ b/browser/components/customizableui/test/browser_PanelMultiView_keyboard.js @@ -103,17 +103,17 @@ add_task(async function setup() { gMainMenulist.appendChild(menuPopup); let item = document.createXULElement("menuitem"); item.setAttribute("value", "1"); item.setAttribute("selected", "true"); menuPopup.appendChild(item); item = document.createXULElement("menuitem"); item.setAttribute("value", "2"); menuPopup.appendChild(item); - gMainTextbox = document.createXULElement("textbox"); + gMainTextbox = document.createElement("input"); gMainTextbox.id = "gMainTextbox"; gMainView.appendChild(gMainTextbox); gMainTextbox.setAttribute("value", "value"); gMainButton2 = document.createXULElement("button"); gMainButton2.id = "gMainButton2"; gMainView.appendChild(gMainButton2); gMainButton3 = document.createXULElement("button"); gMainButton3.id = "gMainButton3";
--- a/dom/tests/mochitest/chrome/focus_window2.xul +++ b/dom/tests/mochitest/chrome/focus_window2.xul @@ -16,11 +16,11 @@ function focused() } SimpleTest.waitForFocus(focused); ]]> </script> <button id="other" label="OK"/> -<textbox id="other-textbox" value="test"/> +<input xmlns="http://www.w3.org/1999/xhtml" id="other-input" value="test"/> </window>
--- a/dom/tests/mochitest/chrome/window_focus.xul +++ b/dom/tests/mochitest/chrome/window_focus.xul @@ -298,17 +298,17 @@ function mouseWillTriggerFocus(element) } return false; } function mouseOnElement(element, expectedElement, focusChanged, testid) { var expectedWindow = (element.ownerGlobal == gChildWindow) ? gChildWindow : window; - // on Mac, form elements are not focused when clicking, except for lists and textboxes. + // on Mac, form elements are not focused when clicking, except for lists and inputs. var noFocusOnMouse = !mouseWillTriggerFocus(element) if (noFocusOnMouse) { // no focus so the last focus method will be 0 gLastFocusMethod = 0; expectFocusShift(() => synthesizeMouse(element, 4, 4, { }, element.ownerGlobal), expectedWindow, null, true, testid); gLastFocusMethod = fm.FLAG_BYMOUSE; @@ -365,17 +365,17 @@ function startTest() synthesizeMouse(getById("image"), 4, 4, { type: "mousemove" }, gChildWindow); initEvents(window); is(fm.activeWindow, window, "activeWindow"); is(gChildWindow.document.hasFocus(), false, " child document hasFocus"); // test to see if the Mac Full Keyboard Access setting is set. If t3 is - // focused after tab is pressed, then it is set to textboxes and lists only. + // focused after tab is pressed, then it is set to inputs and lists only. // Otherwise, all elements are in the tab order. pressTab(); if (fm.focusedElement.id == "t3") gPartialTabbing = true; else is(fm.focusedElement.id, "t1", "initial tab key"); @@ -424,20 +424,20 @@ function startTest() var t19 = getById("t19"); is(t19.selectionStart, 0, "input focused from tab key selectionStart"); is(t19.selectionEnd, 5, "input focused from tab key selectionEnd"); t19.setSelectionRange(0, 0); gLastFocusMethod = 0; var selectFired = false; function selectListener() { selectFired = true; } - t19.addEventListener("select", selectListener, false); + t19.addEventListener("select", selectListener, false); expectFocusShift(() => t19.select(), null, getById("t" + 19), true, "input.select()"); - t19.removeEventListener("select", selectListener, false); + t19.removeEventListener("select", selectListener, false); ok(selectFired, "select event fires for input"); // mouse clicking gLastFocusMethod = fm.FLAG_BYMOUSE; for (idx = kTabbableSteps; idx >= 1; idx--) { // skip the document root and the overflow element if (idx == kChildDocumentRootIndex || idx == kOverflowElementIndex) continue; @@ -455,17 +455,17 @@ function startTest() navigator.platform.indexOf("Mac") == 0) { // after focusing a listbox on Mac, clear the focus before continuing. setFocusTo(null, window); } } ok(t19.selectionStart == t19.selectionEnd, "input focused from mouse selection"); - // mouse clicking on elements that are not tabbable + // mouse clicking on elements that are not tabbable for (idx = 1; idx <= kFocusSteps; idx++) { var element = getById("o" + (idx % 2 ? idx : idx - 1)); mouseOnElement(element, element, idx % 2, "mouse on non-tabbable element o" + idx); } // mouse clicking on elements that are not tabbable and have user-focus: none @@ -497,17 +497,17 @@ function startTest() $("t1").focus(); ok(gEvents === "", "focusing element that is already focused"); $("t2").blur(); $("t7").blur(); ok(gEvents === "", "blurring element that is not focused"); is(document.activeElement, $("t1"), "old element still focused after blur() on another element"); - // focus() method on elements that are not tabbable + // focus() method on elements that are not tabbable for (idx = 1; idx <= kFocusSteps; idx++) { var expected = getById("o" + (idx % 2 ? idx : idx - 1)); expectFocusShift(() => getById("o" + idx).focus(), expected.ownerGlobal, expected, idx % 2, "focus method on non-tabbable element o" + idx); } // focus() method on elements that are not tabbable and have user-focus: none @@ -700,17 +700,17 @@ function startTest() element.removeEventListener("focus", eventListener, false); } fm.clearFocus(window); gEvents = ""; // next, check cases where the focus is adjusted during the focus event - // switch focus to an element in the same document + // switch focus to an element in the same document trapFocus(o5, shiftFocusParentDocument); compareEvents("commandupdate: cu focus: o5 commandupdate: cu blur: o5 commandupdate: cu focus: o9", window, o9, "change focus to sibling during element focus"); // similar, but the new element (t17) is in a child document trapFocus(o5, shiftFocusChildDocument); compareEvents("commandupdate: cu blur: o9 " + "commandupdate: cu focus: o5 commandupdate: cu blur: o5 " + @@ -782,41 +782,41 @@ function startTest() inscroll.parentNode.scrollTop = 0; fm.setFocus(inscroll, fm.FLAG_NOSCROLL); is(inscroll.parentNode.scrollTop, 0, "scroll position after noscroll focus"); getById("t9").focus(); getById("inpopup1").focus(); is(fm.focusedElement, getById("t9"), "focus in closed popup"); - // ---- tests to check if tabbing out of a textbox works + // ---- tests to check if tabbing out of a input works setFocusTo("t1", window); - var textbox1 = document.createXULElement("textbox"); - $("innerbox").appendChild(textbox1); + var input1 = document.createElement("input"); + $("innerbox").appendChild(input1); - var textbox2 = document.createXULElement("textbox"); - $("innerbox").appendChild(textbox2); + var input2 = document.createElement("input"); + $("innerbox").appendChild(input2); gLastFocusMethod = 0; - expectFocusShift(() => textbox2.focus(), - null, textbox2.inputField, true, "focus on textbox"); + expectFocusShift(() => input2.focus(), + null, input2, true, "focus on input"); gLastFocusMethod = fm.FLAG_BYKEY; expectFocusShift(() => synthesizeKey("KEY_Tab", {shiftKey: true}), - null, textbox1.inputField, true, "shift+tab on textbox"); + null, input1, true, "shift+tab on input"); - textbox1.tabIndex = 2; - textbox2.tabIndex = 2; + input1.tabIndex = 2; + input2.tabIndex = 2; gLastFocusMethod = 0; - expectFocusShift(() => textbox2.focus(), - null, textbox2.inputField, true, "focus on textbox with tabindex set"); + expectFocusShift(() => input2.focus(), + null, input2, true, "focus on input with tabindex set"); gLastFocusMethod = fm.FLAG_BYKEY; expectFocusShift(() => synthesizeKey("KEY_Tab", {shiftKey: true}), - null, textbox1.inputField, true, "shift+tab on textbox with tabindex set"); + null, input1, true, "shift+tab on input with tabindex set"); // ---- test for bug 618907 which ensures that canceling the mousedown event still focuses the // right frame var childContentFrame = document.getElementById("ifa") childContentFrame.style.MozUserFocus = ""; var frab = childContentFrame.contentDocument.getElementById("fra-b"); @@ -1061,25 +1061,25 @@ function testMoveFocus() // cases with selection in an <input> var t19 = getById("t19"); t19.setSelectionRange(0, 0); setFocusTo("t18", gChildWindow); gLastFocusMethod = fm.FLAG_BYMOVEFOCUS; expectFocusShift(() => newFocus = fm.moveFocus(null, null, fm.MOVEFOCUS_FORWARD, 0), - gChildWindow, t19, true, "moveFocus to next textbox"); + gChildWindow, t19, true, "moveFocus to next input"); is(t19.selectionStart, 0, "input focused after moveFocus selectionStart"); is(t19.selectionEnd, 5, "input focused after moveFocus selectionEnd"); t19.setSelectionRange(0, 0); setFocusTo("t18", gChildWindow); gLastFocusMethod = fm.FLAG_BYKEY; expectFocusShift(() => newFocus = fm.moveFocus(null, null, fm.MOVEFOCUS_FORWARD, fm.FLAG_BYKEY), - gChildWindow, t19, true, "moveFocus to next textbox by key"); + gChildWindow, t19, true, "moveFocus to next input by key"); is(t19.selectionStart, 0, "input focused after moveFocus by key selectionStart"); is(t19.selectionEnd, 5, "input focused after moveFocus by key selectionEnd"); } function otherWindowFocused(otherWindow) { var expectedElement = getById("t9"); @@ -1324,55 +1324,55 @@ function switchWindowTest(otherWindow, f gNewExpectedWindow = otherWindow; expectFocusShift(() => fm.setFocus(otherElement, fm.FLAG_RAISE), gNewExpectedWindow, getById("other"), true, "switch to window with raise"); getTopWindow(framesetWindow).document.commandDispatcher.focusedWindow = gOldExpectedWindow; is(fm.activeWindow, gNewExpectedWindow, "setting commandDispatcher focusedWindow doesn't raise window"); fm.moveFocus(otherWindow, null, fm.MOVEFOCUS_FORWARD, 0); - var otherTextbox = otherWindow.document.getElementById("other-textbox"); - otherTextbox.setSelectionRange(2, 3); + var otherInput = otherWindow.document.getElementById("other-input"); + otherInput.setSelectionRange(2, 3); fm.activeWindow = topWindow; fm.activeWindow = otherWindow; - is(otherTextbox.selectionStart, 2, "selectionStart after textbox focus and window raise"); - is(otherTextbox.selectionEnd, 3, "selectionEnd after textbox focus and window raise"); - is(fm.getLastFocusMethod(null), fm.FLAG_BYMOVEFOCUS, "last focus method after textbox focus and window raise"); + is(otherInput.selectionStart, 2, "selectionStart after input focus and window raise"); + is(otherInput.selectionEnd, 3, "selectionEnd after input focus and window raise"); + is(fm.getLastFocusMethod(null), fm.FLAG_BYMOVEFOCUS, "last focus method after input focus and window raise"); fm.clearFocus(otherWindow); // test to ensure that a synthetic event won't move focus var synevent = new FocusEvent("focus", {}); - otherTextbox.inputField.dispatchEvent(synevent); + otherInput.dispatchEvent(synevent); is(synevent.type, "focus", "event.type after synthetic focus event"); - is(synevent.target, otherTextbox, "event.target after synthetic focus event"); + is(synevent.target, otherInput, "event.target after synthetic focus event"); is(fm.focusedElement, null, "focusedElement after synthetic focus event"); is(otherWindow.document.activeElement, otherWindow.document.documentElement, "document.activeElement after synthetic focus event"); // check accessing a focus event after the event has finishing firing function continueTest(event) { is(event.type, "focus", "event.type after accessing focus event in timeout"); - is(event.target, otherTextbox, "event.target after accessing focus event in timeout"); + is(event.target, otherInput, "event.target after accessing focus event in timeout"); gOldExpectedWindow = null; gNewExpectedWindow = null; otherWindow.close(); framesetWindow.close(); SimpleTest.waitForFocus(doWindowNoRootTest); } - function textboxFocused(event) { - otherTextbox.removeEventListener("focus", textboxFocused, true); + function inputFocused(event) { + otherInput.removeEventListener("focus", inputFocused, true); setTimeout(continueTest, 0, event); } - otherTextbox.addEventListener("focus", textboxFocused, true); - otherTextbox.focus(); + otherInput.addEventListener("focus", inputFocused, true); + otherInput.focus(); } // open a window with no root element var noRootWindow = null; function doWindowNoRootTest() { addEventListener("focus", doFrameSwitchingTests, true); noRootWindow = window.open("window_focus_inner.xul", "_blank", "chrome,width=100,height=100"); @@ -1444,17 +1444,17 @@ function doFrameSwitchingTests() gExpectedEvents = [[inputa, "blur", null, framea.contentWindow, window, framea], [framea.contentDocument, "blur", null, null, window, null], [framea.contentWindow, "blur", null, null, window, null], [frameb.contentDocument, "focus", null, frameb.contentWindow, window, frameb], [frameb.contentWindow, "focus", null, frameb.contentWindow, window, frameb], [inputb, "focus", inputb, frameb.contentWindow, window, frameb]]; inputb.focus(); ok(gEventMatched && gExpectedEvents.length == 0, "frame switch from input to sibling frame"); - is(fm.getFocusedElementForWindow(framea.contentWindow, false, {}), inputa, + is(fm.getFocusedElementForWindow(framea.contentWindow, false, {}), inputa, "blurred frame still has input as focus"); // focus a descendant in a sibling var inputd = framed.contentDocument.body.firstChild; gEventMatched = true; gExpectedEvents = [[inputb, "blur", null, frameb.contentWindow, window, frameb], [frameb.contentDocument, "blur", null, null, window, null], [frameb.contentWindow, "blur", null, null, window, null], @@ -1689,17 +1689,17 @@ SimpleTest.waitForFocus(startTest); <button id="nohtab2" tabindex="7"/> <checkbox id="htab2" tabindex="0"/> </tabpanel> </tabpanels> </tabbox> <hbox> <panel> <button id="inpopup1" label="One"/> - <textbox label="Two"/> + <input xmlns="http://www.w3.org/1999/xhtml" label="Two"/> </panel> <description label="o" accesskey="v"/> <button id="t38"/> <!-- The 't' element tests end here so it doesn't matter that these elements are tabbable --> <label id="aj" value="j" accesskey="j" control="o9"/> <label id="ak" accesskey="k" control="n4">k</label> <checkbox id="o5"/><checkbox id="o7"/><hbox><checkbox id="o9"/></hbox> <checkbox id="o13"/><checkbox id="o15"/><checkbox id="o17"/><checkbox id="o19"/><checkbox id="o21"/><checkbox id="o23"/><checkbox id="o25"/>
--- a/gfx/wr/webrender/src/batch.rs +++ b/gfx/wr/webrender/src/batch.rs @@ -1199,42 +1199,52 @@ impl BatchBuilder { .map(&local_tile_clip_rect) .expect("bug: unable to map clip rect"); let device_clip_rect = (world_clip_rect * ctx.global_device_pixel_scale).round(); let z_id = composite_config.z_generator.next(); for key in &tile_cache.tiles_to_draw { let tile = &tile_cache.tiles[key]; let device_rect = (tile.world_rect * ctx.global_device_pixel_scale).round(); let surface = tile.surface.as_ref().expect("no tile surface set!"); - let (surface, is_opaque) = match surface { + match surface { TileSurface::Color { color } => { - (CompositeTileSurface::Color { color: *color }, true) + composite_config.opaque_tiles.push(CompositeTile { + surface: CompositeTileSurface::Color { color: *color }, + rect: device_rect, + clip_rect: device_clip_rect, + z_id, + }); + } + TileSurface::Clear => { + composite_config.clear_tiles.push(CompositeTile { + surface: CompositeTileSurface::Clear, + rect: device_rect, + clip_rect: device_clip_rect, + z_id, + }); } TileSurface::Texture { handle, .. } => { let cache_item = ctx.resource_cache.texture_cache.get(handle); - ( - CompositeTileSurface::Texture { + let composite_tile = CompositeTile { + surface: CompositeTileSurface::Texture { texture_id: cache_item.texture_id, texture_layer: cache_item.texture_layer, }, - tile.is_opaque || tile_cache.is_opaque(), - ) + rect: device_rect, + clip_rect: device_clip_rect, + z_id, + }; + + if tile.is_opaque || tile_cache.is_opaque() { + composite_config.opaque_tiles.push(composite_tile); + } else { + composite_config.alpha_tiles.push(composite_tile); + } } - }; - let composite_tile = CompositeTile { - surface, - rect: device_rect, - clip_rect: device_clip_rect, - z_id, - }; - if is_opaque { - composite_config.opaque_tiles.push(composite_tile); - } else { - composite_config.alpha_tiles.push(composite_tile); } } } PictureCompositeMode::Filter(ref filter) => { assert!(filter.is_visible()); match filter { Filter::Blur(..) => { let kind = BatchKind::Brush(
--- a/gfx/wr/webrender/src/composite.rs +++ b/gfx/wr/webrender/src/composite.rs @@ -18,16 +18,17 @@ use crate::internal_types::TextureSource pub enum CompositeTileSurface { Texture { texture_id: TextureSource, texture_layer: i32, }, Color { color: ColorF, }, + Clear, } /// Describes the geometry and surface of a tile to be composited #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] pub struct CompositeTile { pub surface: CompositeTileSurface, pub rect: DeviceRect, @@ -36,20 +37,22 @@ pub struct CompositeTile { } /// The list of tiles to be drawn this frame #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] pub struct CompositeConfig { pub opaque_tiles: Vec<CompositeTile>, pub alpha_tiles: Vec<CompositeTile>, + pub clear_tiles: Vec<CompositeTile>, pub z_generator: ZBufferIdGenerator, } impl CompositeConfig { pub fn new() -> Self { CompositeConfig { opaque_tiles: Vec::new(), alpha_tiles: Vec::new(), + clear_tiles: Vec::new(), z_generator: ZBufferIdGenerator::new(0), } } }
--- a/gfx/wr/webrender/src/picture.rs +++ b/gfx/wr/webrender/src/picture.rs @@ -374,23 +374,25 @@ pub enum TileSurface { /// Handle to the texture cache entry which gets drawn to. handle: TextureCacheHandle, /// Bitfield specifying the dirty region(s) that are relevant to this tile. visibility_mask: PrimitiveVisibilityMask, }, Color { color: ColorF, }, + Clear, } impl TileSurface { fn kind(&self) -> &'static str { match *self { TileSurface::Color { .. } => "Color", TileSurface::Texture { .. } => "Texture", + TileSurface::Clear => "Clear", } } } /// Information about a cached tile. pub struct Tile { /// The current world rect of this tile. pub world_rect: WorldRect, @@ -650,36 +652,43 @@ impl Tile { self.root.maybe_merge_or_split( 0, &self.current_descriptor.prims, max_split_level, ); // See if this tile is a simple color, in which case we can just draw // it as a rect, and avoid allocating a texture surface and drawing it. - let is_solid_color = self.current_descriptor.prims.len() == 1 && self.is_opaque; + let is_simple_prim = self.current_descriptor.prims.len() == 1 && self.is_opaque; // Set up the backing surface for this tile. - let mut surface = if is_solid_color { + let mut surface = if is_simple_prim { // If we determine the tile can be represented by a color, set the // surface unconditionally (this will drop any previously used // texture cache backing surface). - TileSurface::Color { - color: ctx.backdrop.color, + match ctx.backdrop.kind { + BackdropKind::Color { color } => { + TileSurface::Color { + color, + } + } + BackdropKind::Clear => { + TileSurface::Clear + } } } else { // If this tile will be backed by a surface, we want to retain // the texture handle from the previous frame, if possible. If // the tile was previously a color, or not set, then just set // up a new texture cache handle. match self.surface.take() { Some(old_surface @ TileSurface::Texture { .. }) => { old_surface } - Some(TileSurface::Color { .. }) | None => { + Some(TileSurface::Color { .. }) | Some(TileSurface::Clear) | None => { TileSurface::Texture { handle: TextureCacheHandle::invalid(), visibility_mask: PrimitiveVisibilityMask::empty(), } } } }; @@ -1062,32 +1071,42 @@ impl ::std::fmt::Display for RecordedDir } impl ::std::fmt::Debug for RecordedDirtyRegion { fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { ::std::fmt::Display::fmt(self, f) } } +#[derive(Debug, Copy, Clone)] +enum BackdropKind { + Color { + color: ColorF, + }, + Clear, +} + /// Stores information about the calculated opaque backdrop of this slice. #[derive(Debug, Copy, Clone)] struct BackdropInfo { /// The picture space rectangle that is known to be opaque. This is used /// to determine where subpixel AA can be used, and where alpha blending /// can be disabled. rect: PictureRect, - /// Color of the backdrop. - color: ColorF, + /// Kind of the backdrop + kind: BackdropKind, } impl BackdropInfo { fn empty() -> Self { BackdropInfo { rect: PictureRect::zero(), - color: ColorF::BLACK, + kind: BackdropKind::Color { + color: ColorF::BLACK, + }, } } } /// Represents a cache of tiles that make up a picture primitives. pub struct TileCacheInstance { /// Index of the tile cache / slice for this frame builder. It's determined /// by the setup_picture_caching method during flattening, which splits the @@ -1614,17 +1633,19 @@ impl TileCacheInstance { prim_spatial_node.coordinate_system_id == surface_spatial_node.coordinate_system_id }; if let Some(ref clip_chain) = prim_clip_chain { if prim_is_opaque && same_coord_system && !clip_chain.needs_mask && on_picture_surface { if clip_chain.pic_clip_rect.contains_rect(&self.backdrop.rect) { self.backdrop = BackdropInfo { rect: clip_chain.pic_clip_rect, - color, + kind: BackdropKind::Color { + color, + }, }; } } }; } else { let opacity_binding = &opacity_binding_store[opacity_binding_index]; for binding in &opacity_binding.bindings { prim_info.opacity_bindings.push(OpacityBinding::from(*binding)); @@ -1680,18 +1701,25 @@ impl TileCacheInstance { if on_picture_surface && subpx_requested { if !self.backdrop.rect.contains_rect(&prim_info.prim_clip_rect) { self.subpixel_mode = SubpixelMode::Deny; } } } } + PrimitiveInstanceKind::Clear { .. } => { + if let Some(ref clip_chain) = prim_clip_chain { + self.backdrop = BackdropInfo { + rect: clip_chain.pic_clip_rect, + kind: BackdropKind::Clear, + }; + } + } PrimitiveInstanceKind::LineDecoration { .. } | - PrimitiveInstanceKind::Clear { .. } | PrimitiveInstanceKind::NormalBorder { .. } | PrimitiveInstanceKind::LinearGradient { .. } | PrimitiveInstanceKind::RadialGradient { .. } | PrimitiveInstanceKind::Backdrop { .. } => { // These don't contribute dependencies } }; @@ -2282,16 +2310,18 @@ bitflags! { /// Is a backdrop-filter cluster that requires special handling during post_update. const IS_BACKDROP_FILTER = 8; /// Force creation of a picture caching slice before this cluster. const CREATE_PICTURE_CACHE_PRE = 16; /// Force creation of a picture caching slice after this cluster. const CREATE_PICTURE_CACHE_POST = 32; /// If set, this cluster represents a scroll bar container. const SCROLLBAR_CONTAINER = 64; + /// If set, this cluster contains clear rectangle primitives. + const IS_CLEAR_PRIMITIVE = 128; } } /// Descriptor for a cluster of primitives. For now, this is quite basic but will be /// extended to handle more spatial clustering of primitives. #[cfg_attr(feature = "capture", derive(Serialize))] pub struct PrimitiveCluster { /// The positioning node for this cluster. @@ -2395,16 +2425,19 @@ impl PrimitiveList { // iterate all pictures in a given primitive list. match prim_instance.kind { PrimitiveInstanceKind::Picture { .. } => { flags.insert(ClusterFlags::IS_PICTURE); } PrimitiveInstanceKind::Backdrop { .. } => { flags.insert(ClusterFlags::IS_BACKDROP_FILTER); } + PrimitiveInstanceKind::Clear { .. } => { + flags.insert(ClusterFlags::IS_CLEAR_PRIMITIVE); + } _ => {} } if prim_flags.contains(PrimitiveFlags::IS_BACKFACE_VISIBLE) { flags.insert(ClusterFlags::IS_BACKFACE_VISIBLE); } if prim_flags.contains(PrimitiveFlags::IS_SCROLLBAR_CONTAINER) {
--- a/gfx/wr/webrender/src/renderer.rs +++ b/gfx/wr/webrender/src/renderer.rs @@ -3844,16 +3844,19 @@ impl Renderer { let mut instances = Vec::new(); for tile in tiles_iter { // Work out the draw params based on the tile surface let (texture, layer, color) = match tile.surface { CompositeTileSurface::Color { color } => { (TextureSource::Dummy, 0.0, color) } + CompositeTileSurface::Clear => { + (TextureSource::Dummy, 0.0, ColorF::BLACK) + } CompositeTileSurface::Texture { texture_id, texture_layer } => { (texture_id, texture_layer as f32, ColorF::WHITE) } }; let textures = BatchTextures::color(texture); // Flush this batch if the textures aren't compatible if !current_textures.is_compatible_with(&textures) { @@ -3920,16 +3923,28 @@ impl Renderer { self.set_blend(false, FramebufferKind::Main); self.draw_tile_list( composite_config.opaque_tiles.iter().rev(), stats, ); self.gpu_profile.finish_sampler(opaque_sampler); } + if !composite_config.clear_tiles.is_empty() { + let transparent_sampler = self.gpu_profile.start_sampler(GPU_SAMPLER_TAG_TRANSPARENT); + self.device.disable_depth_write(); + self.set_blend(true, FramebufferKind::Main); + self.device.set_blend_mode_premultiplied_dest_out(); + self.draw_tile_list( + composite_config.clear_tiles.iter(), + stats, + ); + self.gpu_profile.finish_sampler(transparent_sampler); + } + // Draw alpha tiles if !composite_config.alpha_tiles.is_empty() { let transparent_sampler = self.gpu_profile.start_sampler(GPU_SAMPLER_TAG_TRANSPARENT); self.device.disable_depth_write(); self.set_blend(true, FramebufferKind::Main); self.set_blend_mode_premultiplied_alpha(FramebufferKind::Main); self.draw_tile_list( composite_config.alpha_tiles.iter(),
--- a/gfx/wr/webrender/src/scene_building.rs +++ b/gfx/wr/webrender/src/scene_building.rs @@ -506,17 +506,19 @@ impl<'a> SceneBuilder<'a> { // If true, the cache is out of date and needs to be rebuilt. let mut update_shared_clips = true; // The last prim clip chain we build prim_clips for. let mut last_prim_clip_chain_id = ClipChainId::NONE; // Walk the supplied top level of clusters, slicing into slices as appropriate for cluster in main_prim_list.clusters.drain(..) { // Check if this cluster requires a new slice - create_slice |= cluster.flags.contains(ClusterFlags::CREATE_PICTURE_CACHE_PRE); + create_slice |= cluster.flags.intersects( + ClusterFlags::CREATE_PICTURE_CACHE_PRE | ClusterFlags::IS_CLEAR_PRIMITIVE + ); if create_slice { // When creating a slice, close off any open clip chains on prev slice. if let Some(prev_slice) = slices.last_mut() { prev_slice.pop_clip_instances(&clip_chain_instance_stack); } let mut slice = Slice { @@ -603,17 +605,19 @@ impl<'a> SceneBuilder<'a> { *shared_clips = Some(prim_clips.clone()); } } update_shared_clips = false; } // If this cluster creates a slice after, then note that for next cluster - create_slice |= cluster.flags.contains(ClusterFlags::CREATE_PICTURE_CACHE_POST); + create_slice |= cluster.flags.intersects( + ClusterFlags::CREATE_PICTURE_CACHE_POST | ClusterFlags::IS_CLEAR_PRIMITIVE + ); // Finally, add this cluster to the current slice slices.last_mut().unwrap().prim_list.add_cluster(cluster); } // Close off any open clip chains on prev slice. if let Some(prev_slice) = slices.last_mut() { prev_slice.pop_clip_instances(&clip_chain_instance_stack);
--- a/js/public/GCAPI.h +++ b/js/public/GCAPI.h @@ -79,17 +79,17 @@ typedef enum JSGCParamKey { JSGC_MAX_BYTES = 0, /** * Maximum size of the generational GC nurseries. * * This will be rounded to the nearest gc::ChunkSize. * * Pref: javascript.options.mem.nursery.max_kb - * Default: JS::DefaultNurseryBytes + * Default: JS::DefaultNurseryMaxBytes */ JSGC_MAX_NURSERY_BYTES = 2, /** Amount of bytes allocated by the GC. */ JSGC_BYTES = 3, /** Number of times GC has been invoked. Includes both major and minor GC. */ JSGC_NUMBER = 4,
--- a/js/public/HeapAPI.h +++ b/js/public/HeapAPI.h @@ -113,21 +113,21 @@ namespace JS { enum StackKind { StackForSystemCode, // C++, such as the GC, running on behalf of the VM. StackForTrustedScript, // Script running with trusted principals. StackForUntrustedScript, // Script running with untrusted principals. StackKindCount }; /* - * Default size for the generational nursery in bytes. - * This is the initial nursery size, when running in the browser this is - * updated by JS_SetGCParameter(). + * Default maximum size for the generational nursery in bytes. This is the + * initial value. In the browser this configured by the + * javascript.options.mem.nursery.max_kb pref. */ -const uint32_t DefaultNurseryBytes = 16 * js::gc::ChunkSize; +const uint32_t DefaultNurseryMaxBytes = 16 * js::gc::ChunkSize; /* Default maximum heap size in bytes to pass to JS_NewContext(). */ const uint32_t DefaultHeapMaxBytes = 32 * 1024 * 1024; namespace shadow { struct Zone { enum GCState : uint8_t {
--- a/js/rust/src/rust.rs +++ b/js/rust/src/rust.rs @@ -132,17 +132,17 @@ impl Runtime { let is_debug_mozjs = cfg!(feature = "debugmozjs"); let diagnostic = JS::detail::InitWithFailureDiagnostic(is_debug_mozjs); if !diagnostic.is_null() { panic!("JS::detail::InitWithFailureDiagnostic failed: {}", ffi::CStr::from_ptr(diagnostic).to_string_lossy()); } let context = JS_NewContext( - DEFAULT_HEAPSIZE, ChunkSize as u32, ptr::null_mut()); + DEFAULT_HEAPSIZE, ptr::null_mut()); assert!(!context.is_null()); JS::InitSelfHostedCode(context); PARENT.set(context); // The last JSRuntime child died, resume the execution by destroying the parent. rx.recv().unwrap(); let cx = PARENT.get(); JS_DestroyContext(cx); @@ -155,17 +155,16 @@ impl Runtime { while PARENT.get().is_null() { thread::yield_now(); } }); assert_eq!(IsDebugBuild(), cfg!(feature = "debugmozjs")); let js_context = JS_NewContext(DEFAULT_HEAPSIZE, - ChunkSize as u32, JS_GetParentRuntime(PARENT.get())); assert!(!js_context.is_null()); // Unconstrain the runtime's threshold on nominal heap size, to avoid // triggering GC too often if operating continuously near an arbitrary // finite threshold. This leaves the maximum-JS_malloc-bytes threshold // still in effect to cause periodical, and we hope hygienic, // last-ditch GCs from within the GC's allocator. @@ -554,22 +553,16 @@ impl Default for jsid { impl Default for JS::Value { fn default() -> JS::Value { jsval::UndefinedValue() } } impl Default for JS::RealmOptions { fn default() -> Self { unsafe { ::std::mem::zeroed() } } } -const ChunkShift: usize = 20; -const ChunkSize: usize = 1 << ChunkShift; - -#[cfg(target_pointer_width = "32")] -const ChunkLocationOffset: usize = ChunkSize - 2 * 4 - 8; - pub trait GCMethods { unsafe fn initial() -> Self; unsafe fn write_barriers(v: *mut Self, prev: Self, next: Self); } impl GCMethods for jsid { unsafe fn initial() -> jsid { Default::default() } unsafe fn write_barriers(_: *mut jsid, _: jsid, _: jsid) {}
--- a/js/src/gc/GC.cpp +++ b/js/src/gc/GC.cpp @@ -1197,25 +1197,23 @@ void js::gc::DumpArenaInfo() { fprintf(stderr, "%25s %8zu %8zu %8zu\n", AllocKindName(kind), Arena::thingSize(kind), Arena::thingsPerArena(kind), Arena::firstThingOffset(kind) - ArenaHeaderSize); } } #endif // JS_GC_ZEAL -bool GCRuntime::init(uint32_t maxbytes, uint32_t maxNurseryBytes) { +bool GCRuntime::init(uint32_t maxbytes) { MOZ_ASSERT(SystemPageSize()); { AutoLockGCBgAlloc lock(rt); MOZ_ALWAYS_TRUE(tunables.setParameter(JSGC_MAX_BYTES, maxbytes, lock)); - MOZ_ALWAYS_TRUE( - tunables.setParameter(JSGC_MAX_NURSERY_BYTES, maxNurseryBytes, lock)); const char* size = getenv("JSGC_MARK_STACK_LIMIT"); if (size) { setMarkStackLimit(atoi(size), lock); } if (!nursery().init(lock)) { return false;
--- a/js/src/gc/GCRuntime.h +++ b/js/src/gc/GCRuntime.h @@ -235,17 +235,17 @@ class ZoneList { ZoneList& operator=(const ZoneList& other) = delete; }; class GCRuntime { friend GCMarker::MarkQueueProgress GCMarker::processMarkQueue(); public: explicit GCRuntime(JSRuntime* rt); - MOZ_MUST_USE bool init(uint32_t maxbytes, uint32_t maxNurseryBytes); + MOZ_MUST_USE bool init(uint32_t maxbytes); void finishRoots(); void finish(); inline bool hasZealMode(ZealMode mode); inline void clearZealMode(ZealMode mode); inline bool upcomingZealousGC(); inline bool needZealousGC(); inline bool hasIncrementalTwoSliceZealMode();
--- a/js/src/gc/Scheduling.cpp +++ b/js/src/gc/Scheduling.cpp @@ -33,17 +33,17 @@ static constexpr float LowFrequencyEager */ static constexpr float MinHeapGrowthFactor = 1.0f / Min(HighFrequencyEagerAllocTriggerFactor, LowFrequencyEagerAllocTriggerFactor); GCSchedulingTunables::GCSchedulingTunables() : gcMaxBytes_(0), gcMinNurseryBytes_(TuningDefaults::GCMinNurseryBytes), - gcMaxNurseryBytes_(0), + gcMaxNurseryBytes_(JS::DefaultNurseryMaxBytes), gcZoneAllocThresholdBase_(TuningDefaults::GCZoneAllocThresholdBase), nonIncrementalFactor_(TuningDefaults::NonIncrementalFactor), avoidInterruptFactor_(TuningDefaults::AvoidInterruptFactor), zoneAllocDelayBytes_(TuningDefaults::ZoneAllocDelayBytes), dynamicHeapGrowthEnabled_(TuningDefaults::DynamicHeapGrowthEnabled), highFrequencyThreshold_( TimeDuration::FromSeconds(TuningDefaults::HighFrequencyThreshold)), highFrequencyLowLimitBytes_(TuningDefaults::HighFrequencyLowLimitBytes), @@ -272,17 +272,17 @@ void GCSchedulingTunables::resetParamete switch (key) { case JSGC_MAX_BYTES: gcMaxBytes_ = 0xffffffff; break; case JSGC_MIN_NURSERY_BYTES: case JSGC_MAX_NURSERY_BYTES: // Reset these togeather to maintain their min <= max invariant. gcMinNurseryBytes_ = TuningDefaults::GCMinNurseryBytes; - gcMaxNurseryBytes_ = JS::DefaultNurseryBytes; + gcMaxNurseryBytes_ = JS::DefaultNurseryMaxBytes; break; case JSGC_HIGH_FREQUENCY_TIME_LIMIT: highFrequencyThreshold_ = TimeDuration::FromSeconds(TuningDefaults::HighFrequencyThreshold); break; case JSGC_HIGH_FREQUENCY_LOW_LIMIT: setHighFrequencyLowLimit(TuningDefaults::HighFrequencyLowLimitBytes); break;
--- a/js/src/jsapi-tests/testGCOutOfMemory.cpp +++ b/js/src/jsapi-tests/testGCOutOfMemory.cpp @@ -59,19 +59,20 @@ BEGIN_TEST(testGCOutOfMemory) { virtual JSContext* createContext() override { // Note that the max nursery size must be less than the whole heap size, or // the test will fail because 'max' (the number of allocations required for // OOM) will be based on the nursery size, and that will overflow the // tenured heap, which will cause the second pass with max/4 allocations to // OOM. (Actually, this only happens with nursery zeal, because normally // the nursery will start out with only a single chunk before triggering a // major GC.) - JSContext* cx = JS_NewContext(1024 * 1024, js::gc::ChunkSize); + JSContext* cx = JS_NewContext(1024 * 1024); if (!cx) { return nullptr; } + JS_SetGCParameter(cx, JSGC_MAX_NURSERY_BYTES, js::gc::ChunkSize); setNativeStackQuota(cx); return cx; } virtual void destroyContext() override { JS_DestroyContext(cx); } END_TEST(testGCOutOfMemory)
--- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -360,27 +360,26 @@ JS_PUBLIC_API bool JS_IsFunctionBound(JS JS_PUBLIC_API JSObject* JS_GetBoundFunctionTarget(JSFunction* fun) { return fun->isBoundFunction() ? fun->getBoundFunctionTarget() : nullptr; } /************************************************************************/ JS_PUBLIC_API JSContext* JS_NewContext(uint32_t maxbytes, - uint32_t maxNurseryBytes, JSRuntime* parentRuntime) { MOZ_ASSERT(JS::detail::libraryInitState == JS::detail::InitState::Running, "must call JS_Init prior to creating any JSContexts"); // Make sure that all parent runtimes are the topmost parent. while (parentRuntime && parentRuntime->parentRuntime) { parentRuntime = parentRuntime->parentRuntime; } - return NewContext(maxbytes, maxNurseryBytes, parentRuntime); + return NewContext(maxbytes, parentRuntime); } JS_PUBLIC_API JSContext* JS_NewCooperativeContext(JSContext* siblingContext) { MOZ_CRASH("Cooperative scheduling is unsupported"); } JS_PUBLIC_API void JS_YieldCooperativeContext(JSContext* cx) { MOZ_CRASH("Cooperative scheduling is unsupported");
--- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -333,18 +333,17 @@ extern JS_PUBLIC_API bool JS_IsBuiltinFu * be created, in a single-threaded fashion. Otherwise the behavior of the * library is undefined. * See: * https://developer.mozilla.org/en-US/docs/Mozilla/Projects/SpiderMonkey/JSAPI_reference */ // Create a new context (and runtime) for this thread. extern JS_PUBLIC_API JSContext* JS_NewContext( - uint32_t maxbytes, uint32_t maxNurseryBytes = JS::DefaultNurseryBytes, - JSRuntime* parentRuntime = nullptr); + uint32_t maxbytes, JSRuntime* parentRuntime = nullptr); // The methods below for controlling the active context in a cooperatively // multithreaded runtime are not threadsafe, and the caller must ensure they // are called serially if there is a chance for contention between threads. // Called from the active context for a runtime, yield execution so that // this context is no longer active and can no longer use the API. extern JS_PUBLIC_API void JS_YieldCooperativeContext(JSContext* cx);
--- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -4019,22 +4019,23 @@ static void DestroyShellCompartmentPriva } static void SetWorkerContextOptions(JSContext* cx); static bool ShellBuildId(JS::BuildIdCharVector* buildId); static void WorkerMain(WorkerInput* input) { MOZ_ASSERT(input->parentRuntime); - JSContext* cx = JS_NewContext(8L * 1024L * 1024L, 2L * 1024L * 1024L, - input->parentRuntime); + JSContext* cx = JS_NewContext(8L * 1024L * 1024L, input->parentRuntime); if (!cx) { return; } + JS_SetGCParameter(cx, JSGC_MAX_NURSERY_BYTES, 2L * 1024L * 1024L); + ShellContext* sc = js_new<ShellContext>(cx); if (!sc) { return; } auto guard = mozilla::MakeScopeExit([&] { CancelOffThreadJobsForContext(cx); sc->markObservers.reset(); @@ -11254,17 +11255,18 @@ int main(int argc, char** argv, char** e !op.addBoolOption('\0', "mips-sim-icache-checks", "Enable icache flush checks in the MIPS " "simulator.") || !op.addIntOption('\0', "mips-sim-stop-at", "NUMBER", "Stop the MIPS simulator after the given " "NUMBER of instructions.", -1) || !op.addIntOption('\0', "nursery-size", "SIZE-MB", - "Set the maximum nursery size in MB", 16) || + "Set the maximum nursery size in MB", + JS::DefaultNurseryMaxBytes / 1024 / 1024) || #ifdef JS_GC_ZEAL !op.addStringOption('z', "gc-zeal", "LEVEL(;LEVEL)*[,N]", gc::ZealModeHelpText) || #else !op.addStringOption('z', "gc-zeal", "LEVEL(;LEVEL)*[,N]", "option ignored in non-gc-zeal builds") || #endif !op.addStringOption('\0', "module-load-path", "DIR", @@ -11380,24 +11382,25 @@ int main(int argc, char** argv, char** e int32_t cpuCount = op.getIntOption("cpu-count"); // What we're really setting if (cpuCount < 0) { cpuCount = op.getIntOption("thread-count"); // Legacy name } if (cpuCount >= 0 && !SetFakeCPUCount(cpuCount)) { return 1; } - size_t nurseryBytes = JS::DefaultNurseryBytes; - nurseryBytes = op.getIntOption("nursery-size") * 1024L * 1024L; - /* Use the same parameters as the browser in xpcjsruntime.cpp. */ - JSContext* const cx = JS_NewContext(JS::DefaultHeapMaxBytes, nurseryBytes); + JSContext* const cx = JS_NewContext(JS::DefaultHeapMaxBytes); if (!cx) { return 1; } + + size_t nurseryBytes = op.getIntOption("nursery-size") * 1024L * 1024L; + JS_SetGCParameter(cx, JSGC_MAX_NURSERY_BYTES, nurseryBytes); + auto destroyCx = MakeScopeExit([cx] { JS_DestroyContext(cx); }); UniquePtr<ShellContext> sc = MakeUnique<ShellContext>(cx); if (!sc) { return 1; } auto destroyShellContext = MakeScopeExit([cx, &sc] { // Must clear out some of sc's pointer containers before JS_DestroyContext.
--- a/js/src/vm/JSContext.cpp +++ b/js/src/vm/JSContext.cpp @@ -130,18 +130,17 @@ bool JSContext::init(ContextKind kind) { // Set the ContextKind last, so that ProtectedData checks will allow us to // initialize this context before it becomes the runtime's active context. kind_ = kind; return true; } -JSContext* js::NewContext(uint32_t maxBytes, uint32_t maxNurseryBytes, - JSRuntime* parentRuntime) { +JSContext* js::NewContext(uint32_t maxBytes, JSRuntime* parentRuntime) { AutoNoteSingleThreadedRegion anstr; MOZ_RELEASE_ASSERT(!TlsContext.get()); #if defined(DEBUG) || defined(JS_OOM_BREAKPOINT) js::oom::SetThreadType(!parentRuntime ? js::THREAD_TYPE_MAIN : js::THREAD_TYPE_WORKER); #endif @@ -158,17 +157,17 @@ JSContext* js::NewContext(uint32_t maxBy } if (!cx->init(ContextKind::MainThread)) { js_delete(cx); js_delete(runtime); return nullptr; } - if (!runtime->init(cx, maxBytes, maxNurseryBytes)) { + if (!runtime->init(cx, maxBytes)) { runtime->destroyRuntime(); js_delete(cx); js_delete(runtime); return nullptr; } return cx; }
--- a/js/src/vm/JSContext.h +++ b/js/src/vm/JSContext.h @@ -1044,18 +1044,17 @@ struct MOZ_RAII AutoResolving { AutoResolving* const link; MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER }; /* * Create and destroy functions for JSContext, which is manually allocated * and exclusively owned. */ -extern JSContext* NewContext(uint32_t maxBytes, uint32_t maxNurseryBytes, - JSRuntime* parentRuntime); +extern JSContext* NewContext(uint32_t maxBytes, JSRuntime* parentRuntime); extern void DestroyContext(JSContext* cx); enum ErrorArgumentsType { ArgumentsAreUnicode, ArgumentsAreASCII, ArgumentsAreLatin1, ArgumentsAreUTF8
--- a/js/src/vm/Runtime.cpp +++ b/js/src/vm/Runtime.cpp @@ -188,32 +188,31 @@ JSRuntime::~JSRuntime() { MOZ_ASSERT(offThreadParsesRunning_ == 0); MOZ_ASSERT(!offThreadParsingBlocked_); MOZ_ASSERT(numRealms == 0); MOZ_ASSERT(numDebuggeeRealms_ == 0); MOZ_ASSERT(numDebuggeeRealmsObservingCoverage_ == 0); } -bool JSRuntime::init(JSContext* cx, uint32_t maxbytes, - uint32_t maxNurseryBytes) { +bool JSRuntime::init(JSContext* cx, uint32_t maxbytes) { #ifdef DEBUG MOZ_ASSERT(!initialized_); initialized_ = true; #endif if (CanUseExtraThreads() && !EnsureHelperThreadsInitialized()) { return false; } mainContext_ = cx; defaultFreeOp_ = cx->defaultFreeOp(); - if (!gc.init(maxbytes, maxNurseryBytes)) { + if (!gc.init(maxbytes)) { return false; } UniquePtr<Zone> atomsZone = MakeUnique<Zone>(this); if (!atomsZone || !atomsZone->init(true)) { return false; }
--- a/js/src/vm/Runtime.h +++ b/js/src/vm/Runtime.h @@ -844,17 +844,17 @@ struct JSRuntime { explicit JSRuntime(JSRuntime* parentRuntime); ~JSRuntime(); // destroyRuntime is used instead of a destructor, to ensure the downcast // to JSContext remains valid. The final GC triggered here depends on this. void destroyRuntime(); - bool init(JSContext* cx, uint32_t maxbytes, uint32_t maxNurseryBytes); + bool init(JSContext* cx, uint32_t maxbytes); JSRuntime* thisFromCtor() { return this; } public: void reportAllocationOverflow() { js::ReportAllocationOverflow(nullptr); } /* * This should be called after system malloc/calloc/realloc returns nullptr
--- a/js/xpconnect/src/XPCJSContext.cpp +++ b/js/xpconnect/src/XPCJSContext.cpp @@ -1095,17 +1095,17 @@ CycleCollectedJSRuntime* XPCJSContext::C } nsresult XPCJSContext::Initialize(XPCJSContext* aPrimaryContext) { nsresult rv; if (aPrimaryContext) { rv = CycleCollectedJSContext::InitializeNonPrimary(aPrimaryContext); } else { rv = CycleCollectedJSContext::Initialize(nullptr, JS::DefaultHeapMaxBytes, - JS::DefaultNurseryBytes); + JS::DefaultNurseryMaxBytes); } if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } MOZ_ASSERT(Context()); JSContext* cx = Context();
--- a/xpcom/base/CycleCollectedJSContext.cpp +++ b/xpcom/base/CycleCollectedJSContext.cpp @@ -150,21 +150,23 @@ void CycleCollectedJSContext::Initialize } nsresult CycleCollectedJSContext::Initialize(JSRuntime* aParentRuntime, uint32_t aMaxBytes, uint32_t aMaxNurseryBytes) { MOZ_ASSERT(!mJSContext); mozilla::dom::InitScriptSettings(); - mJSContext = JS_NewContext(aMaxBytes, aMaxNurseryBytes, aParentRuntime); + mJSContext = JS_NewContext(aMaxBytes, aParentRuntime); if (!mJSContext) { return NS_ERROR_OUT_OF_MEMORY; } + JS_SetGCParameter(mJSContext, JSGC_MAX_NURSERY_BYTES, aMaxNurseryBytes); + mRuntime = CreateRuntime(mJSContext); InitializeCommon(); nsCycleCollector_registerJSContext(this); return NS_OK; }