Merge m-c to birch

This commit is contained in:
Phil Ringnalda 2013-05-23 21:20:32 -07:00
commit fda0263af1
265 changed files with 6298 additions and 2968 deletions

View File

@ -17,6 +17,9 @@
#
# Modifying this file will now automatically clobber the buildbot machines \o/
#
Bug 854517: Integrate valgrind into B2G builds
clobber needed due to changes in configure.in for js engine and gecko
Bug 854517: Integrate valgrind into B2G builds
Bug 874640 touched webidl, so Windows needs to clobber
Alternative to clobber is to run ./config.status from the objdir and to
touch the CLOBBER file in the objdir.

View File

@ -116,6 +116,7 @@ this.AccessFu = {
Services.obs.addObserver(this, 'Accessibility:NextObject', false);
Services.obs.addObserver(this, 'Accessibility:PreviousObject', false);
Services.obs.addObserver(this, 'Accessibility:Focus', false);
Services.obs.addObserver(this, 'Accessibility:ActivateObject', false);
Utils.win.addEventListener('TabOpen', this);
Utils.win.addEventListener('TabClose', this);
Utils.win.addEventListener('TabSelect', this);
@ -157,6 +158,7 @@ this.AccessFu = {
Services.obs.removeObserver(this, 'Accessibility:NextObject');
Services.obs.removeObserver(this, 'Accessibility:PreviousObject');
Services.obs.removeObserver(this, 'Accessibility:Focus');
Services.obs.removeObserver(this, 'Accessibility:ActivateObject');
if (this.doneCallback) {
this.doneCallback();
@ -259,6 +261,9 @@ this.AccessFu = {
case 'Accessibility:PreviousObject':
this.Input.moveCursor('movePrevious', 'Simple', 'gesture');
break;
case 'Accessibility:ActivateObject':
this.Input.activateCurrent();
break;
case 'Accessibility:Focus':
this._focused = JSON.parse(aData);
if (this._focused) {

View File

@ -217,10 +217,19 @@ AndroidPresenter.prototype = {
androidEvents.push({eventType: this.ANDROID_VIEW_HOVER_EXIT, text: []});
}
let state = Utils.getStates(aContext.accessible)[0];
androidEvents.push({eventType: (isExploreByTouch) ?
this.ANDROID_VIEW_HOVER_ENTER : focusEventType,
text: UtteranceGenerator.genForContext(aContext),
bounds: aContext.bounds});
bounds: aContext.bounds,
clickable: aContext.accessible.actionCount > 0,
checkable: !!(state &
Ci.nsIAccessibleStates.STATE_CHECKABLE),
checked: !!(state &
Ci.nsIAccessibleStates.STATE_CHECKED)});
return {
type: this.type,
details: androidEvents
@ -228,11 +237,13 @@ AndroidPresenter.prototype = {
},
actionInvoked: function AndroidPresenter_actionInvoked(aObject, aActionName) {
let state = Utils.getStates(aObject)[0];
return {
type: this.type,
details: [{
eventType: this.ANDROID_VIEW_CLICKED,
text: UtteranceGenerator.genForAction(aObject, aActionName)
text: UtteranceGenerator.genForAction(aObject, aActionName),
checked: !!(state & Ci.nsIAccessibleStates.STATE_CHECKED)
}]
};
},

View File

@ -347,7 +347,11 @@ this.UtteranceGenerator = {
stateUtterances.push(gStringBundle.GetStringFromName('stateUnavailable'));
}
if (aStates.base & Ci.nsIAccessibleStates.STATE_CHECKABLE) {
// Don't utter this in Jelly Bean, we let TalkBack do it for us there.
// This is because we expose the checked information on the node itself.
// XXX: this means the checked state is always appended to the end, regardless
// of the utterance ordering preference.
if (Utils.AndroidSdkVersion < 16 && aStates.base & Ci.nsIAccessibleStates.STATE_CHECKABLE) {
let stateStr = (aStates.base & Ci.nsIAccessibleStates.STATE_CHECKED) ?
'stateChecked' : 'stateNotChecked';
stateUtterances.push(gStringBundle.GetStringFromName(stateStr));

View File

@ -237,15 +237,13 @@ pref("ui.dragThresholdY", 25);
#ifndef MOZ_WIDGET_GONK
pref("dom.ipc.tabs.disabled", true);
pref("layers.offmainthreadcomposition.enabled", false);
pref("layers.offmainthreadcomposition.animate-opacity", false);
pref("layers.offmainthreadcomposition.animate-transform", false);
pref("layers.offmainthreadcomposition.async-animations", false);
pref("layers.async-video.enabled", false);
#else
pref("dom.ipc.tabs.disabled", false);
pref("layers.offmainthreadcomposition.enabled", true);
pref("layers.acceleration.disabled", false);
pref("layers.offmainthreadcomposition.animate-opacity", true);
pref("layers.offmainthreadcomposition.animate-transform", true);
pref("layers.offmainthreadcomposition.async-animations", true);
pref("layers.async-video.enabled", true);
pref("layers.async-pan-zoom.enabled", true);
#endif

View File

@ -4,16 +4,11 @@
var kMaxChunkDuration = 30; // ms
var escape = document.createElement('textarea');
function escapeHTML(html) {
escape.innerHTML = html;
return escape.innerHTML;
}
function unescapeHTML(html) {
escape.innerHTML = html;
return escape.value;
var pre = document.createElementNS("http://www.w3.org/1999/xhtml", "pre");
var text = document.createTextNode(html);
pre.appendChild(text);
return pre.innerHTML;
}
RegExp.escape = function(text) {

View File

@ -36,6 +36,9 @@ XPCOMUtils.defineLazyModuleGetter(this, "devtools",
XPCOMUtils.defineLazyModuleGetter(this, "require",
"resource://gre/modules/devtools/Require.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "EventEmitter",
"resource:///modules/devtools/shared/event-emitter.js");
XPCOMUtils.defineLazyGetter(this, "prefBranch", function() {
let prefService = Components.classes["@mozilla.org/preferences-service;1"]
.getService(Components.interfaces.nsIPrefService);
@ -215,6 +218,8 @@ this.DeveloperToolbar = function DeveloperToolbar(aChromeWindow, aToolbarElement
this._errorCounterButton._defaultTooltipText =
this._errorCounterButton.getAttribute("tooltiptext");
EventEmitter.decorate(this);
try {
CmdCommands.refreshAutoCommands(aChromeWindow);
}
@ -675,6 +680,8 @@ function DT__updateErrorsCount(aChangedTabId)
btn.removeAttribute("error-count");
btn.setAttribute("tooltiptext", btn._defaultTooltipText);
}
this.emit("errors-counter-updated");
};
/**

View File

@ -10,8 +10,7 @@ this.EXPORTED_SYMBOLS = ["SplitView"];
/* this must be kept in sync with CSS (ie. splitview.css) */
const LANDSCAPE_MEDIA_QUERY = "(min-width: 551px)";
const BINDING_USERDATA = "splitview-binding";
let bindings = new WeakMap();
/**
* SplitView constructor
@ -115,7 +114,7 @@ SplitView.prototype = {
}
if (this._activeSummary) {
let binding = this._activeSummary.getUserData(BINDING_USERDATA);
let binding = bindings.get(this._activeSummary);
if (binding.onHide) {
binding.onHide(this._activeSummary, binding._details, binding.data);
@ -129,7 +128,7 @@ SplitView.prototype = {
return;
}
let binding = aSummary.getUserData(BINDING_USERDATA);
let binding = bindings.get(aSummary);
aSummary.classList.add("splitview-active");
binding._details.classList.add("splitview-active");
@ -147,7 +146,7 @@ SplitView.prototype = {
get activeDetails()
{
let summary = this.activeSummary;
return summary ? summary.getUserData(BINDING_USERDATA)._details : null;
return summary ? bindings.get(summary)._details : null;
},
/**
@ -193,7 +192,7 @@ SplitView.prototype = {
binding._summary = aSummary;
binding._details = aDetails;
aSummary.setUserData(BINDING_USERDATA, binding, null);
bindings.set(aSummary, binding);
this._nav.appendChild(aSummary);
@ -258,7 +257,7 @@ SplitView.prototype = {
this.activeSummary = null;
}
let binding = aSummary.getUserData(BINDING_USERDATA);
let binding = bindings.get(aSummary);
aSummary.parentNode.removeChild(aSummary);
binding._details.parentNode.removeChild(binding._details);
@ -289,7 +288,7 @@ SplitView.prototype = {
*/
setItemClassName: function ASV_setItemClassName(aSummary, aClassName)
{
let binding = aSummary.getUserData(BINDING_USERDATA);
let binding = bindings.get(aSummary);
let viewSpecific;
viewSpecific = aSummary.className.match(/(splitview\-[\w-]+)/g);

View File

@ -7,18 +7,23 @@ function test() {
const TEST_URI = "http://example.com/browser/browser/devtools/shared/test/" +
"browser_toolbar_webconsole_errors_count.html";
let imported = {};
Components.utils.import("resource:///modules/HUDService.jsm", imported);
let HUDService = imported.HUDService;
Components.utils.import("resource:///modules/devtools/gDevTools.jsm", imported);
let gDevTools = imported.gDevTools;
let HUDService = Cu.import("resource:///modules/HUDService.jsm",
{}).HUDService;
let gDevTools = Cu.import("resource:///modules/devtools/gDevTools.jsm",
{}).gDevTools;
let webconsole = document.getElementById("developer-toolbar-toolbox-button");
let tab1, tab2;
Services.prefs.setBoolPref("javascript.options.strict", true);
registerCleanupFunction(() => {
Services.prefs.clearUserPref("javascript.options.strict");
});
ignoreAllUncaughtExceptions();
addTab(TEST_URI, openToolbar);
function openToolbar(browser, tab) {
tab1 = tab;
ignoreAllUncaughtExceptions(false);
@ -33,47 +38,6 @@ function test() {
}
}
ignoreAllUncaughtExceptions();
addTab(TEST_URI, openToolbar);
function getErrorsCount() {
let count = webconsole.getAttribute("error-count");
return count ? count : "0";
}
function getTooltipValues() {
let matches = webconsole.getAttribute("tooltiptext")
.match(/(\d+) errors?, (\d+) warnings?/);
return matches ? [matches[1], matches[2]] : [0, 0];
}
function waitForButtonUpdate(aOptions)
{
aOptions.validator = function() {
let errors = getErrorsCount();
let tooltip = getTooltipValues();
let result = errors == aOptions.errors &&
tooltip[1] == aOptions.warnings;
if (result) {
is(errors, tooltip[0], "button error-count is the same as in the tooltip");
}
return result;
};
let originalFailure = aOptions.failure;
aOptions.failure = function() {
let tooltip = getTooltipValues();
info("expected " + aOptions.errors + " errors, " +
aOptions.warnings + " warnings");
info("got " + tooltip[0] + " errors, " + tooltip[1] + " warnings");
originalFailure();
};
waitForValue(aOptions);
}
function onOpenToolbar() {
ok(DeveloperToolbar.visible, "DeveloperToolbar is visible");
@ -81,8 +45,7 @@ function test() {
name: "web console button shows page errors",
errors: 3,
warnings: 0,
success: addErrors,
failure: finish,
callback: addErrors,
});
}
@ -100,11 +63,10 @@ function test() {
name: "button shows one more error after click in page",
errors: 4,
warnings: 1,
success: function() {
callback: () => {
ignoreAllUncaughtExceptions();
addTab(TEST_URI, onOpenSecondTab);
},
failure: finish,
});
}
@ -118,8 +80,7 @@ function test() {
name: "button shows correct number of errors after new tab is open",
errors: 3,
warnings: 0,
success: switchToTab1,
failure: finish,
callback: switchToTab1,
});
}
@ -129,28 +90,10 @@ function test() {
name: "button shows the page errors from tab 1",
errors: 4,
warnings: 1,
success: function() {
openWebConsole(tab1, onWebConsoleOpen);
},
failure: finish,
callback: openWebConsole.bind(null, tab1, onWebConsoleOpen),
});
}
function openWebConsole(tab, callback)
{
function _onWebConsoleOpen(subject)
{
subject.QueryInterface(Ci.nsISupportsString);
let hud = HUDService.getHudReferenceById(subject.data);
executeSoon(callback.bind(null, hud));
}
oneTimeObserve("web-console-created", _onWebConsoleOpen);
let target = TargetFactory.forTab(tab);
gDevTools.showToolbox(target, "webconsole");
}
function onWebConsoleOpen(hud) {
waitForValue({
name: "web console shows the page errors",
@ -185,10 +128,7 @@ function test() {
name: "button shows one more error after another click in page",
errors: 5,
warnings: 1, // warnings are not repeated by the js engine
success: function() {
waitForValue(waitForNewError);
},
failure: finish,
callback: () => waitForValue(waitForNewError),
});
let waitForNewError = {
@ -216,24 +156,23 @@ function test() {
}
function doPageReload(hud) {
tab1.linkedBrowser.addEventListener("load", function _onReload() {
tab1.linkedBrowser.removeEventListener("load", _onReload, true);
ignoreAllUncaughtExceptions(false);
expectUncaughtException();
}, true);
tab1.linkedBrowser.addEventListener("load", onReload, true);
ignoreAllUncaughtExceptions();
content.location.reload();
waitForButtonUpdate({
name: "the Web Console button count has been reset after page reload",
errors: 3,
warnings: 0,
success: function() {
waitForValue(waitForConsoleOutputAfterReload);
},
failure: finish,
});
function onReload() {
tab1.linkedBrowser.removeEventListener("load", onReload, true);
ignoreAllUncaughtExceptions(false);
expectUncaughtException();
waitForButtonUpdate({
name: "the Web Console button count has been reset after page reload",
errors: 3,
warnings: 0,
callback: waitForValue.bind(null, waitForConsoleOutputAfterReload),
});
}
let waitForConsoleOutputAfterReload = {
name: "the Web Console displays the correct number of errors after reload",
@ -256,16 +195,51 @@ function test() {
gDevTools.closeToolbox(target1);
gBrowser.removeTab(tab1);
gBrowser.removeTab(tab2);
Services.prefs.clearUserPref("javascript.options.strict");
finish();
}
function oneTimeObserve(name, callback) {
function _onObserve(aSubject, aTopic, aData) {
Services.obs.removeObserver(_onObserve, name);
callback(aSubject, aTopic, aData);
};
Services.obs.addObserver(_onObserve, name, false);
// Utility functions
function getErrorsCount() {
let count = webconsole.getAttribute("error-count");
return count ? count : "0";
}
function getTooltipValues() {
let matches = webconsole.getAttribute("tooltiptext")
.match(/(\d+) errors?, (\d+) warnings?/);
return matches ? [matches[1], matches[2]] : [0, 0];
}
function waitForButtonUpdate(options) {
function check() {
let errors = getErrorsCount();
let tooltip = getTooltipValues();
let result = errors == options.errors && tooltip[1] == options.warnings;
if (result) {
ok(true, options.name);
is(errors, tooltip[0], "button error-count is the same as in the tooltip");
// Get out of the toolbar event execution loop.
executeSoon(options.callback);
}
return result;
}
if (!check()) {
info("wait for: " + options.name);
DeveloperToolbar.on("errors-counter-updated", function onUpdate(event) {
if (check()) {
DeveloperToolbar.off(event, onUpdate);
}
});
}
}
function openWebConsole(tab, callback)
{
let target = TargetFactory.forTab(tab);
gDevTools.showToolbox(target, "webconsole").then((toolbox) =>
callback(toolbox.getCurrentPanel().hud));
}
}

View File

@ -127,11 +127,10 @@ this.log = function log()
* Selector string or DOMElement for the element(s) to wire up.
* @param object aDescriptor
* An object describing how to wire matching selector, supported properties
* are "events", "attributes" and "userData" taking objects themselves.
* Each key of properties above represents the name of the event, attribute
* or userData, with the value being a function used as an event handler,
* string to use as attribute value, or object to use as named userData
* respectively.
* are "events" and "attributes" taking objects themselves.
* Each key of properties above represents the name of the event or
* attribute, with the value being a function used as an event handler or
* string to use as attribute value.
* If aDescriptor is a function, the argument is equivalent to :
* {events: {'click': aDescriptor}}
*/
@ -157,7 +156,6 @@ this.wire = function wire(aRoot, aSelectorOrElement, aDescriptor)
element.addEventListener(aName, aHandler, false);
});
forEach(aDescriptor.attributes, element.setAttribute);
forEach(aDescriptor.userData, element.setUserData);
}
}

View File

@ -176,6 +176,7 @@ let Sync = {
Services.obs.addObserver(self._boundOnEngineSync, "weave:engine:sync:error", false);
Services.obs.addObserver(self._boundOnServiceSync, "weave:service:sync:finish", false);
Services.obs.addObserver(self._boundOnServiceSync, "weave:service:sync:error", false);
Services.obs.addObserver(self._boundOnServiceSync, "weave:service:login:error", false);
self.setupData = aCredentials;
self.connect();
},
@ -278,6 +279,7 @@ let Sync = {
Services.obs.removeObserver(this._boundOnEngineSync, "weave:engine:sync:error");
Services.obs.removeObserver(this._boundOnServiceSync, "weave:service:sync:finish");
Services.obs.removeObserver(this._boundOnServiceSync, "weave:service:sync:error");
Services.obs.removeObserver(this._boundOnServiceSync, "weave:service:login:error");
}
catch(e) {
// Observers weren't registered because we never got as far as onComplete.
@ -567,7 +569,7 @@ let Sync = {
let accountinfo = this._elements.accountinfo;
// Show what went wrong with login if necessary
if (aTopic == "weave:ui:login:error") {
if (aTopic == "weave:ui:login:error" || aTopic == "weave:service:login:error") {
this._loginError = true;
errormsg.textContent = Weave.Utils.getErrorString(Weave.Status.login);
errormsg.collapsed = false;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -287,15 +287,15 @@ documenttab[selected] .documenttab-selection {
#identity-icon {
margin: 0;
padding: 0 @metro_spacing_snormal@;
list-style-image: url(chrome://browser/skin/images/identity-icons-generic.png);
list-style-image: url("chrome://browser/skin/images/identity-icons-generic.png");
}
#identity-box-inner.verifiedDomain > #identity-icon {
list-style-image: url(chrome://browser/skin/images/locked-hdpi.png);
list-style-image: url("chrome://browser/skin/images/identity-icons-https.png");
}
#identity-box-inner.verifiedIdentity > #identity-icon {
list-style-image: url(chrome://browser/skin/images/locked-hdpi.png);
list-style-image: url("chrome://browser/skin/images/identity-icons-https-ev.png");
}
/* Main URL textbox */

Binary file not shown.

Before

Width:  |  Height:  |  Size: 520 B

After

Width:  |  Height:  |  Size: 233 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 500 B

After

Width:  |  Height:  |  Size: 248 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -67,8 +67,6 @@ chrome.jar:
skin/images/identity-default-hdpi.png (images/identity-default-hdpi.png)
skin/images/identity-ssl-hdpi.png (images/identity-ssl-hdpi.png)
skin/images/identity-ev-hdpi.png (images/identity-ev-hdpi.png)
skin/images/unlocked-hdpi.png (images/unlocked-hdpi.png)
skin/images/locked-hdpi.png (images/locked-hdpi.png)
skin/images/search-glass-30.png (images/search-glass-30.png)
skin/images/play-hdpi.png (images/play-hdpi.png)
skin/images/pause-hdpi.png (images/pause-hdpi.png)

View File

@ -6,6 +6,7 @@ parsing command lines into argv and making sure that no shell magic is being use
#TODO: ship pyprocessing?
import multiprocessing
import subprocess, shlex, re, logging, sys, traceback, os, imp, glob
from collections import deque
# XXXkhuey Work around http://bugs.python.org/issue1731717
subprocess._cleanup = lambda: None
import command, util
@ -439,7 +440,7 @@ class ParallelContext(object):
self.exit = False
self.processpool = multiprocessing.Pool(processes=jcount)
self.pending = [] # list of (cb, args, kwargs)
self.pending = deque() # deque of (cb, args, kwargs)
self.running = [] # list of (subprocess, cb)
self._allcontexts.add(self)
@ -452,7 +453,7 @@ class ParallelContext(object):
def run(self):
while len(self.pending) and len(self.running) < self.jcount:
cb, args, kwargs = self.pending.pop(0)
cb, args, kwargs = self.pending.popleft()
cb(*args, **kwargs)
def defer(self, cb, *args, **kwargs):

View File

@ -14,8 +14,7 @@ PARALLEL_DIRS_export = $(addsuffix _export,$(PARALLEL_DIRS))
###############
export_tier_%:
@$(ECHO) "$@"
@$(MAKE_TIER_SUBMAKEFILES)
$(foreach dir,$(tier_$*_dirs),$(call SUBMAKE,export,$(dir)))
$(foreach dir,$(tier_$*_dirs),$(call TIER_DIR_SUBMAKE,export,$(dir)))
#################
## Common targets

View File

@ -14,8 +14,7 @@ PARALLEL_DIRS_libs = $(addsuffix _libs,$(PARALLEL_DIRS))
###############
libs_tier_%:
@$(ECHO) "$@"
@$(MAKE_TIER_SUBMAKEFILES)
$(foreach dir,$(tier_$*_dirs),$(call SUBMAKE,libs,$(dir)))
$(foreach dir,$(tier_$*_dirs),$(call TIER_DIR_SUBMAKE,libs,$(dir)))
#################
## Common targets

View File

@ -14,8 +14,7 @@ PARALLEL_DIRS_tools = $(addsuffix _tools,$(PARALLEL_DIRS))
###############
tools_tier_%:
@$(ECHO) "$@"
@$(MAKE_TIER_SUBMAKEFILES)
$(foreach dir,$(tier_$*_dirs),$(call SUBMAKE,tools,$(dir)))
$(foreach dir,$(tier_$*_dirs),$(call TIER_DIR_SUBMAKE,tools,$(dir)))
#################
## Common targets

View File

@ -425,6 +425,14 @@ define SUBMAKE # $(call SUBMAKE,target,directory)
endef # The extra line is important here! don't delete it
define TIER_DIR_SUBMAKE
@echo "BUILDSTATUS TIERDIR_START $(2)"
$(call SUBMAKE,$(1),$(2))
@echo "BUILDSTATUS TIERDIR_FINISH $(2)"
endef # Ths empty line is important.
ifneq (,$(strip $(DIRS)))
LOOP_OVER_DIRS = \
$(foreach dir,$(DIRS),$(call SUBMAKE,$@,$(dir)))
@ -627,6 +635,16 @@ endif
# other rules for the default target or else it may not run in time.
ifndef MOZBUILD_BACKEND_CHECKED
# Since Makefile is listed as a global dependency, this has the
# unfortunate side-effect of invalidating all targets if it is executed.
# So e.g. if you are in /dom/bindings and /foo/moz.build changes,
# /dom/bindings will get invalidated. The upside is if the current
# Makefile/backend.mk is updated as a result of backend regeneration, we
# actually pick up the changes. This should reduce the amount of
# required clobbers and is thus the lesser evil.
Makefile: $(DEPTH)/backend.RecursiveMakeBackend.built
@$(TOUCH) $@
$(DEPTH)/backend.RecursiveMakeBackend.built:
@echo "Build configuration changed. Regenerating backend."
@cd $(DEPTH) && $(PYTHON) ./config.status
@ -650,6 +668,7 @@ SUBMAKEFILES += $(addsuffix /Makefile, $(DIRS) $(TOOL_DIRS) $(PARALLEL_DIRS))
ifndef SUPPRESS_DEFAULT_RULES
ifdef TIERS
default all alldep::
@echo "BUILDSTATUS TIERS $(TIERS)"
$(foreach tier,$(TIERS),$(call SUBMAKE,tier_$(tier)))
else
@ -679,14 +698,44 @@ ECHO := true
QUIET := -q
endif
MAKE_TIER_SUBMAKEFILES = +$(if $(tier_$*_dirs),$(MAKE) $(addsuffix /Makefile,$(tier_$*_dirs)))
# This function is called and evaluated to produce the rule to build the
# specified tier. Each tier begins by building the "static" directories.
# The BUILDSTATUS echo commands are used to faciliate easier parsing
# of build output. Build drivers are encouraged to filter these lines
# from the user.
define CREATE_TIER_RULE
tier_$(1)::
@echo "BUILDSTATUS TIER_START $(1)"
@printf "BUILDSTATUS SUBTIERS"
ifneq (,$(tier_$(1)_staticdirs))
@printf " static"
endif
ifneq (,$(tier_$(1)_dirs))
@printf " export libs tools"
endif
@printf "\n"
@echo "BUILDSTATUS STATICDIRS $$($$@_staticdirs)"
@echo "BUILDSTATUS DIRS $$($$@_dirs)"
ifneq (,$(tier_$(1)_staticdirs))
@echo "BUILDSTATUS SUBTIER_START $(1) static"
$$(foreach dir,$$($$@_staticdirs),$$(call TIER_DIR_SUBMAKE,,$$(dir)))
@echo "BUILDSTATUS SUBTIER_FINISH $(1) static"
endif
ifneq (,$(tier_$(1)_dirs))
@echo "BUILDSTATUS SUBTIER_START $(1) export"
$$(MAKE) export_$$@
@echo "BUILDSTATUS SUBTIER_FINISH $(1) export"
@echo "BUILDSTATUS SUBTIER_START $(1) libs"
$$(MAKE) libs_$$@
@echo "BUILDSTATUS SUBTIER_FINISH $(1) libs"
@echo "BUILDSTATUS SUBTIER_START $(1) tools"
$$(MAKE) tools_$$@
@echo "BUILDSTATUS SUBTIER_FINISH $(1) tools"
@echo "BUILDSTATUS TIER_FINISH $(1)"
endif
endef
$(foreach tier,$(TIERS),tier_$(tier))::
@$(ECHO) "$@: $($@_staticdirs) $($@_dirs)"
$(foreach dir,$($@_staticdirs),$(call SUBMAKE,,$(dir)))
$(MAKE) export_$@
$(MAKE) libs_$@
$(MAKE) tools_$@
$(foreach tier,$(TIERS),$(eval $(call CREATE_TIER_RULE,$(tier))))
# Do everything from scratch
everything::

View File

@ -1135,68 +1135,18 @@ WebSocket::UpdateURI()
return NS_OK;
}
NS_IMETHODIMP
WebSocket::RemoveEventListener(const nsAString& aType,
nsIDOMEventListener* aListener,
bool aUseCapture)
void
WebSocket::EventListenerAdded(nsIAtom* aType)
{
NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
nsresult rv = nsDOMEventTargetHelper::RemoveEventListener(aType,
aListener,
aUseCapture);
if (NS_SUCCEEDED(rv)) {
UpdateMustKeepAlive();
}
return rv;
UpdateMustKeepAlive();
}
void
WebSocket::RemoveEventListener(const nsAString& aType,
nsIDOMEventListener* aListener,
bool aUseCapture,
ErrorResult& aRv)
WebSocket::EventListenerRemoved(nsIAtom* aType)
{
NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
nsDOMEventTargetHelper::RemoveEventListener(aType, aListener,
aUseCapture, aRv);
if (!aRv.Failed()) {
UpdateMustKeepAlive();
}
UpdateMustKeepAlive();
}
NS_IMETHODIMP
WebSocket::AddEventListener(const nsAString& aType,
nsIDOMEventListener *aListener,
bool aUseCapture,
bool aWantsUntrusted,
uint8_t optional_argc)
{
NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
nsresult rv = nsDOMEventTargetHelper::AddEventListener(aType,
aListener,
aUseCapture,
aWantsUntrusted,
optional_argc);
if (NS_SUCCEEDED(rv)) {
UpdateMustKeepAlive();
}
return rv;
}
void
WebSocket::AddEventListener(const nsAString& aType,
nsIDOMEventListener* aListener,
bool aUseCapture,
const Nullable<bool>& aWantsUntrusted,
ErrorResult& aRv)
{
NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
nsDOMEventTargetHelper::AddEventListener(aType, aListener, aUseCapture,
aWantsUntrusted, aRv);
if (!aRv.Failed()) {
UpdateMustKeepAlive();
}
}
//-----------------------------------------------------------------------------
// WebSocket - methods
//-----------------------------------------------------------------------------

View File

@ -71,24 +71,9 @@ public:
NS_DECL_NSIOBSERVER
NS_DECL_NSIREQUEST
// nsIDOMEventTarget
NS_IMETHOD AddEventListener(const nsAString& aType,
nsIDOMEventListener *aListener,
bool aUseCapture,
bool aWantsUntrusted,
uint8_t optional_argc);
virtual void AddEventListener(const nsAString& aType,
nsIDOMEventListener* aListener,
bool aCapture,
const Nullable<bool>& aWantsUntrusted,
ErrorResult& aRv) MOZ_OVERRIDE;
NS_IMETHOD RemoveEventListener(const nsAString& aType,
nsIDOMEventListener* aListener,
bool aUseCapture);
virtual void RemoveEventListener(const nsAString& aType,
nsIDOMEventListener* aListener,
bool aUseCapture,
ErrorResult& aRv) MOZ_OVERRIDE;
// EventTarget
virtual void EventListenerAdded(nsIAtom* aType) MOZ_OVERRIDE;
virtual void EventListenerRemoved(nsIAtom* aType) MOZ_OVERRIDE;
virtual void DisconnectFromOwner();

View File

@ -1402,10 +1402,12 @@ nsFrameMessageManager*
nsFrameMessageManager::NewProcessMessageManager(mozilla::dom::ContentParent* aProcess)
{
if (!nsFrameMessageManager::sParentProcessManager) {
nsCOMPtr<nsIMessageBroadcaster> dummy;
NS_NewParentProcessMessageManager(getter_AddRefs(dummy));
nsCOMPtr<nsIMessageBroadcaster> dummy =
do_GetService("@mozilla.org/parentprocessmessagemanager;1");
}
MOZ_ASSERT(nsFrameMessageManager::sParentProcessManager,
"parent process manager not created");
nsFrameMessageManager* mm;
if (aProcess) {
mm = new nsFrameMessageManager(aProcess,

View File

@ -2145,7 +2145,7 @@ nsObjectLoadingContent::DestroyContent()
mFrameLoader = nullptr;
}
StopPluginInstance();
QueueCheckPluginStopEvent();
}
/* static */

View File

@ -60,6 +60,10 @@ public:
return SetEventHandler(type, aHandler, rv);
}
// Note, for an event 'foo' aType will be 'onfoo'.
virtual void EventListenerAdded(nsIAtom* aType) {}
virtual void EventListenerRemoved(nsIAtom* aType) {}
protected:
EventHandlerNonNull* GetEventHandler(nsIAtom* aType);
void SetEventHandler(nsIAtom* aType, EventHandlerNonNull* aHandler,

View File

@ -101,7 +101,7 @@ MutationBitForEventType(uint32_t aEventType)
uint32_t nsEventListenerManager::sCreatedCount = 0;
nsEventListenerManager::nsEventListenerManager(nsISupports* aTarget) :
nsEventListenerManager::nsEventListenerManager(EventTarget* aTarget) :
mMayHavePaintEventListener(false),
mMayHaveMutationListeners(false),
mMayHaveCapturingListeners(false),
@ -352,6 +352,9 @@ nsEventListenerManager::AddEventListenerInternal(
}
#endif
}
if (aTypeAtom && mTarget) {
mTarget->EventListenerAdded(aTypeAtom);
}
}
bool
@ -464,6 +467,9 @@ nsEventListenerManager::RemoveEventListenerInternal(
--count;
mNoListenerForEvent = NS_EVENT_TYPE_NULL;
mNoListenerForEventAtom = nullptr;
if (mTarget && aUserType) {
mTarget->EventListenerRemoved(aUserType);
}
if (!deviceType
#ifdef MOZ_B2G
@ -748,6 +754,9 @@ nsEventListenerManager::RemoveEventHandler(nsIAtom* aName)
mListeners.RemoveElementAt(uint32_t(ls - &mListeners.ElementAt(0)));
mNoListenerForEvent = NS_EVENT_TYPE_NULL;
mNoListenerForEventAtom = nullptr;
if (mTarget) {
mTarget->EventListenerRemoved(aName);
}
}
}

View File

@ -210,7 +210,7 @@ class nsEventListenerManager
{
public:
nsEventListenerManager(nsISupports* aTarget);
nsEventListenerManager(mozilla::dom::EventTarget* aTarget);
virtual ~nsEventListenerManager();
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(nsEventListenerManager)
@ -404,7 +404,7 @@ public:
void MarkForCC();
nsISupports* GetTarget() { return mTarget; }
mozilla::dom::EventTarget* GetTarget() { return mTarget; }
protected:
void HandleEventInternal(nsPresContext* aPresContext,
nsEvent* aEvent,
@ -533,7 +533,7 @@ protected:
uint32_t mNoListenerForEvent : 24;
nsAutoTObserverArray<nsListenerStruct, 2> mListeners;
nsISupports* mTarget; //WEAK
mozilla::dom::EventTarget* mTarget; //WEAK
nsCOMPtr<nsIAtom> mNoListenerForEventAtom;
static uint32_t mInstanceCount;

View File

@ -48,6 +48,7 @@ enum ButtonElementTypes {
enum InputElementTypes {
NS_FORM_INPUT_BUTTON = NS_FORM_INPUT_ELEMENT + 1,
NS_FORM_INPUT_CHECKBOX,
NS_FORM_INPUT_COLOR,
NS_FORM_INPUT_DATE,
NS_FORM_INPUT_EMAIL,
NS_FORM_INPUT_FILE,

View File

@ -133,6 +133,7 @@ UploadLastDir* HTMLInputElement::gUploadLastDir;
static const nsAttrValue::EnumTable kInputTypeTable[] = {
{ "button", NS_FORM_INPUT_BUTTON },
{ "checkbox", NS_FORM_INPUT_CHECKBOX },
{ "color", NS_FORM_INPUT_COLOR },
{ "date", NS_FORM_INPUT_DATE },
{ "email", NS_FORM_INPUT_EMAIL },
{ "file", NS_FORM_INPUT_FILE },
@ -153,7 +154,7 @@ static const nsAttrValue::EnumTable kInputTypeTable[] = {
};
// Default type is 'text'.
static const nsAttrValue::EnumTable* kInputDefaultType = &kInputTypeTable[15];
static const nsAttrValue::EnumTable* kInputDefaultType = &kInputTypeTable[16];
static const uint8_t NS_INPUT_AUTOCOMPLETE_OFF = 0;
static const uint8_t NS_INPUT_AUTOCOMPLETE_ON = 1;
@ -383,6 +384,24 @@ HTMLInputElement::AsyncClickHandler::AsyncClickHandler(HTMLInputElement* aInput)
NS_IMETHODIMP
HTMLInputElement::AsyncClickHandler::Run()
{
if (mInput->GetType() == NS_FORM_INPUT_FILE) {
return InitFilePicker();
} else if (mInput->GetType() == NS_FORM_INPUT_COLOR) {
return InitColorPicker();
}
return NS_ERROR_FAILURE;
}
nsresult
HTMLInputElement::AsyncClickHandler::InitColorPicker()
{
// TODO
return NS_OK;
}
nsresult
HTMLInputElement::AsyncClickHandler::InitFilePicker()
{
// Get parent nsPIDOMWindow object.
nsCOMPtr<nsIDocument> doc = mInput->OwnerDoc();
@ -3149,13 +3168,15 @@ HTMLInputElement::PostHandleEvent(nsEventChainPostVisitor& aVisitor)
PostHandleEventForRangeThumb(aVisitor);
}
// Open a file picker when we receive a click on a <input type='file'>.
// Open a file picker when we receive a click on a <input type='file'>, or
// open a color picker when we receive a click on a <input type='color'>.
// A click is handled in the following cases:
// - preventDefault() has not been called (or something similar);
// - it's the left mouse button.
// We do not prevent non-trusted click because authors can already use
// .click(). However, the file picker will follow the rules of popup-blocking.
if (mType == NS_FORM_INPUT_FILE && NS_IS_MOUSE_LEFT_CLICK(aVisitor.mEvent) &&
if ((mType == NS_FORM_INPUT_FILE || mType == NS_FORM_INPUT_COLOR) &&
NS_IS_MOUSE_LEFT_CLICK(aVisitor.mEvent) &&
!aVisitor.mEvent->mFlags.mDefaultPrevented) {
return FireAsyncClickHandler();
}
@ -3539,9 +3560,35 @@ HTMLInputElement::SanitizeValue(nsAString& aValue)
}
}
break;
case NS_FORM_INPUT_COLOR:
{
if (IsValidSimpleColor(aValue)) {
ToLowerCase(aValue);
} else {
// Set default (black) color, if aValue wasn't parsed correctly.
aValue.AssignLiteral("#000000");
}
}
break;
}
}
bool HTMLInputElement::IsValidSimpleColor(const nsAString& aValue) const
{
if (aValue.Length() != 7 || aValue.First() != '#') {
return false;
}
for (int i = 1; i < 7; ++i) {
if (!nsCRT::IsAsciiDigit(aValue[i]) &&
!(aValue[i] >= 'a' && aValue[i] <= 'f') &&
!(aValue[i] >= 'A' && aValue[i] <= 'F')) {
return false;
}
}
return true;
}
bool
HTMLInputElement::IsValidDate(const nsAString& aValue) const
{
@ -3747,7 +3794,9 @@ HTMLInputElement::ParseAttribute(int32_t aNamespaceID,
if ((IsExperimentalMobileType(newType) &&
!Preferences::GetBool("dom.experimental_forms", false)) ||
(newType == NS_FORM_INPUT_RANGE &&
!Preferences::GetBool("dom.experimental_forms_range", false))) {
!Preferences::GetBool("dom.experimental_forms_range", false)) ||
(newType == NS_FORM_INPUT_COLOR &&
!Preferences::GetBool("dom.forms.color", false))) {
newType = kInputDefaultType->value;
aResult.SetTo(newType, &aValue);
}
@ -4851,6 +4900,7 @@ HTMLInputElement::GetValueMode() const
case NS_FORM_INPUT_RANGE:
case NS_FORM_INPUT_DATE:
case NS_FORM_INPUT_TIME:
case NS_FORM_INPUT_COLOR:
return VALUE_MODE_VALUE;
default:
NS_NOTYETIMPLEMENTED("Unexpected input type in GetValueMode()");
@ -4884,8 +4934,7 @@ HTMLInputElement::DoesReadOnlyApply() const
case NS_FORM_INPUT_FILE:
case NS_FORM_INPUT_CHECKBOX:
case NS_FORM_INPUT_RANGE:
// TODO:
// case NS_FORM_INPUT_COLOR:
case NS_FORM_INPUT_COLOR:
return false;
#ifdef DEBUG
case NS_FORM_INPUT_TEXT:
@ -4919,8 +4968,7 @@ HTMLInputElement::DoesRequiredApply() const
case NS_FORM_INPUT_RESET:
case NS_FORM_INPUT_SUBMIT:
case NS_FORM_INPUT_RANGE:
// TODO:
// case NS_FORM_INPUT_COLOR:
case NS_FORM_INPUT_COLOR:
return false;
#ifdef DEBUG
case NS_FORM_INPUT_RADIO:
@ -4995,6 +5043,7 @@ HTMLInputElement::DoesMinMaxApply() const
case NS_FORM_INPUT_TEL:
case NS_FORM_INPUT_EMAIL:
case NS_FORM_INPUT_URL:
case NS_FORM_INPUT_COLOR:
return false;
default:
NS_NOTYETIMPLEMENTED("Unexpected input type in DoesRequiredApply()");

View File

@ -971,6 +971,14 @@ protected:
*/
bool ConvertNumberToString(Decimal aValue, nsAString& aResultString) const;
/**
* Parse a color string of the form #XXXXXX where X should be hexa characters
* @param the string to be parsed.
* @return whether the string is a valid simple color.
* Note : this function does not consider the empty string as valid.
*/
bool IsValidSimpleColor(const nsAString& aValue) const;
/**
* Parse a date string of the form yyyy-mm-dd
* @param the string to be parsed.
@ -1229,6 +1237,9 @@ private:
NS_IMETHOD Run();
protected:
nsresult InitFilePicker();
nsresult InitColorPicker();
nsRefPtr<HTMLInputElement> mInput;
PopupControlState mPopupControlState;
};

View File

@ -12,7 +12,7 @@
namespace mozilla {
namespace dom {
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(ValidityState)
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(ValidityState, mConstraintValidation)
NS_IMPL_CYCLE_COLLECTING_ADDREF(ValidityState)
NS_IMPL_CYCLE_COLLECTING_RELEASE(ValidityState)

View File

@ -74,16 +74,6 @@ public:
protected:
ValidityState(nsIConstraintValidation* aConstraintValidation);
/**
* This function should be called by nsIConstraintValidation
* to set mConstraintValidation to null to be sure
* it will not be used when the object is destroyed.
*/
inline void Disconnect()
{
mConstraintValidation = nullptr;
}
/**
* Helper function to get a validity state from constraint validation instance.
*/
@ -93,8 +83,7 @@ protected:
mConstraintValidation->GetValidityState(aState);
}
// Weak reference to owner which will call Disconnect() when being destroyed.
nsIConstraintValidation* mConstraintValidation;
nsCOMPtr<nsIConstraintValidation> mConstraintValidation;
};
} // namespace dom

View File

@ -171,6 +171,7 @@ ShouldBeInElements(nsIFormControl* aFormControl)
case NS_FORM_BUTTON_SUBMIT :
case NS_FORM_INPUT_BUTTON :
case NS_FORM_INPUT_CHECKBOX :
case NS_FORM_INPUT_COLOR :
case NS_FORM_INPUT_EMAIL :
case NS_FORM_INPUT_FILE :
case NS_FORM_INPUT_HIDDEN :

View File

@ -23,9 +23,6 @@ nsIConstraintValidation::nsIConstraintValidation()
nsIConstraintValidation::~nsIConstraintValidation()
{
if (mValidity) {
mValidity->Disconnect();
}
}
mozilla::dom::ValidityState*

View File

@ -61,6 +61,7 @@ MOCHITEST_FILES = \
test_input_file_picker.html \
test_input_event.html \
test_input_number_rounding.html \
test_valueAsDate_pref.html \
$(NULL)
include $(topsrcdir)/config/rules.mk

View File

@ -206,11 +206,10 @@ reflectLimitedEnumerated({
attribute: "type",
validValues: [ "hidden", "text", "search", "tel", "url", "email", "password",
"checkbox", "radio", "file", "submit", "image", "reset",
"button", "date", "time", "number", "range" ],
"button", "date", "time", "number", "range", "color" ],
invalidValues: [ "this-is-probably-a-wrong-type", "", "tulip" ],
defaultValue: "text",
unsupportedValues: [ "datetime", "month", "week", "datetime-local",
"color" ]
unsupportedValues: [ "datetime", "month", "week", "datetime-local" ]
});
// .defaultValue

View File

@ -42,12 +42,11 @@ var inputTypes =
[
"text", "password", "search", "tel", "hidden", "checkbox", "radio",
"submit", "image", "reset", "button", "email", "url", "number", "date",
"time", "range"
"time", "range", "color"
];
var todoTypes =
[
"color",
"month", "week", "datetime", "datetime-local",
];
@ -152,9 +151,7 @@ function sanitizeValue(aType, aValue)
ok(false);
return "";
case "color":
ok(false);
// TODO: write the sanitize algorithm.
return "";
return /^#[0-9A-Fa-f]{6}$/.exec(aValue) ? aValue.toLowerCase() : "#000000";
default:
return aValue;
}
@ -290,6 +287,17 @@ function checkSanitizing(element)
"13:37:42.",
"foo12:12",
"13:37:42.100000000000",
// For color
"#00ff00",
"#000000",
"red",
"#0f0",
"#FFFFAA",
"FFAABB",
"fFAaBb",
"FFAAZZ",
"ABCDEF",
"#7654321",
];
for (value of testData) {

View File

@ -170,7 +170,6 @@ function runTest()
{ type: 'month', todo: true },
{ type: 'datetime', todo: true },
{ type: 'datetime-local', todo: true },
{ type: 'color', todo: true },
];
for (test of data) {

View File

@ -35,7 +35,7 @@ var data = [
{ type: 'datetime-local', apply: true, todo: true },
{ type: 'number', apply: true },
{ type: 'range', apply: true },
{ type: 'color', apply: false, todo: true },
{ type: 'color', apply: false },
{ type: 'checkbox', apply: false },
{ type: 'radio', apply: false },
{ type: 'file', apply: false },
@ -125,6 +125,7 @@ for (var test of data) {
case 'reset':
case 'button':
case 'image':
case 'color':
input.max = '-1';
break;
case 'date':

View File

@ -35,7 +35,7 @@ var data = [
{ type: 'datetime-local', apply: true, todo: true },
{ type: 'number', apply: true },
{ type: 'range', apply: true },
{ type: 'color', apply: false, todo: true },
{ type: 'color', apply: false },
{ type: 'checkbox', apply: false },
{ type: 'radio', apply: false },
{ type: 'file', apply: false },
@ -124,6 +124,7 @@ for (var test of data) {
case 'reset':
case 'button':
case 'image':
case 'color':
input.min = '999';
break;
case 'date':
@ -156,6 +157,7 @@ for (var test of data) {
case 'button':
case 'submit':
case 'image':
case 'color':
input.value = '0';
checkValidity(input, true, apply, apply);
break;

View File

@ -51,6 +51,7 @@ var gInputTestData = [
['range', false],
['date', false],
['time', false],
['color', false],
];
/**
@ -59,7 +60,6 @@ var gInputTestData = [
*/
var gInputTodoData = [
/* type expected result */
['color', false],
['datetime', false],
['month', false],
['week', false],

View File

@ -261,8 +261,8 @@ var input = document.getElementById('i');
// and |invalidTypes| are the ones which do not accept it.
var validTypes = Array('text', 'password', 'search', 'tel', 'email', 'url');
var barredTypes = Array('hidden', 'reset', 'button', 'submit', 'image');
var invalidTypes = Array('checkbox', 'radio', 'file', 'number', 'range', 'date', 'time');
// TODO: 'datetime', 'month', 'week', 'datetime-local' and 'color'
var invalidTypes = Array('checkbox', 'radio', 'file', 'number', 'range', 'date', 'time', 'color');
// TODO: 'datetime', 'month', 'week', and 'datetime-local'
// do not accept the @pattern too but are not implemented yet.
for (type of validTypes) {

View File

@ -367,8 +367,7 @@ for (type of typeBarredFromConstraintValidation) {
}
// Then, checks for the types which do not use the required attribute.
// TODO: check 'color' when they will be implemented.
var typeRequireNotApply = ['range'];
var typeRequireNotApply = ['range', 'color'];
for (type of typeRequireNotApply) {
checkInputRequiredNotApply(type, false);
}

View File

@ -35,7 +35,7 @@ var data = [
{ type: 'datetime-local', apply: true, todo: true },
{ type: 'number', apply: true },
{ type: 'range', apply: true },
{ type: 'color', apply: false, todo: true },
{ type: 'color', apply: false },
{ type: 'checkbox', apply: false },
{ type: 'radio', apply: false },
{ type: 'file', apply: false },
@ -111,6 +111,7 @@ for (var test of data) {
case 'button':
case 'submit':
case 'image':
case 'color':
input.value = '0';
checkValidity(input, true, apply);
break;

View File

@ -50,8 +50,6 @@ function checkAvailability()
["range", true],
["date", true],
["time", true],
// The next types have not been implemented but will fallback to "text"
// which has the same value.
["color", false],
];

View File

@ -0,0 +1,46 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=874640
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 874640</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript">
/** Test for Bug 874640 **/
var states = [ 'true', 'false', 'end' ];
var pref = SpecialPowers.getBoolPref("dom.experimental_forms");
SimpleTest.waitForExplicitFinish();
function runTest(iframe) {
var state = states.shift();
if (state == 'end') {
SpecialPowers.setBoolPref("dom.experimental_forms", pref);
SimpleTest.finish();
return;
}
SpecialPowers.setBoolPref("dom.experimental_forms", state === 'true');
iframe.src = 'data:text/html,<script>' +
'parent.is("valueAsDate" in document.createElement("input"), ' +
state + ', "valueAsDate presence state should be ' + state + '");' +
'<\/script>'
}
</script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=874640">Mozilla Bug 874640</a>
<p id="display"></p>
<div id="content" style="display: none">
<iframe onload='runTest(this);'></iframe>
</div>
<pre id="test">
</pre>
</body>
</html>

View File

@ -44,8 +44,6 @@ var validTypes =
["range", false],
["date", true],
["time", true],
// The next types have not been implemented but will fallback to "text"
// which has the same value.
["color", false],
];

View File

@ -43,8 +43,6 @@ function checkAvailability()
["range", true],
["date", true],
["time", true],
// The next types have not been implemented but will fallback to "text"
// which has the same value.
["color", false],
];

View File

@ -38,14 +38,15 @@ var testData = [
[ "date", true ],
[ "time", true ],
[ "range", true ],
[ "color", true ],
// 'file' is treated separatly.
];
var todoTypes = [
"datetime", "month", "week", "datetime-local", "color"
"datetime", "month", "week", "datetime-local"
];
var nonTrivialSanitizing = [ 'number', 'date', 'time' ];
var nonTrivialSanitizing = [ 'number', 'date', 'time', 'color' ];
var length = testData.length;
for (var i=0; i<length; ++i) {
@ -60,9 +61,18 @@ for (var i=0; i<length; ++i) {
if (testData[j][0] == 'range' || testData[i][0] == 'range') {
if (testData[j][0] == 'date' || testData[j][0] == 'time') {
expectedValue = '';
} else if (testData[j][0] == 'color') {
expectedValue = '#000000';
} else {
expectedValue = '50';
}
} else if (testData[i][0] == 'color' || testData[j][0] == 'color') {
if (testData[j][0] == 'number' || testData[j][0] == 'date' ||
testData[j][0] == 'time') {
expectedValue = ''
} else {
expectedValue = '#000000';
}
} else if (nonTrivialSanitizing.indexOf(testData[i][0]) != -1 &&
nonTrivialSanitizing.indexOf(testData[j][0]) != -1) {
expectedValue = '';
@ -95,6 +105,9 @@ for (var data of testData) {
if (data[0] == 'range') {
is(e.value, '50', ".value should still return the same value after " +
"changing type from " + data[0] + " to 'file' then reverting to " + data[0]);
} else if (data[0] == 'color') {
is(e.value, '#000000', ".value should have been reset to the default color after " +
"changing type from " + data[0] + " to 'file' then reverting to " + data[0]);
} else if (data[1]) {
is(e.value, '', ".value should have been reset to the empty string after " +
"changing type from " + data[0] + " to 'file' then reverting to " + data[0]);

View File

@ -50,9 +50,9 @@ var types = [
[ "text", "email", "password", "url", "search", "tel" ],
// These types can't be too long.
[ "radio", "checkbox", "submit", "button", "reset", "image", "hidden",
'number', 'range', 'date', 'time' ],
'number', 'range', 'date', 'time', 'color' ],
// These types can't be too long but are not implemented yet.
[ "color", "datetime", "month", "week", 'datetime-local' ]
[ "datetime", "month", "week", 'datetime-local' ]
];
var input = document.createElement("input");

View File

@ -315,6 +315,8 @@ AudioNodeStream::ObtainInputBlock(AudioChunk& aTmpChunk, uint32_t aPortIndex)
return;
}
MOZ_ASSERT(outputChannelCount > 0, "How did this happen?");
AllocateAudioBlock(outputChannelCount, &aTmpChunk);
float silenceChannel[WEBAUDIO_BLOCK_SIZE] = {0.f};
// The static storage here should be 1KB, so it's fine

View File

@ -0,0 +1,15 @@
<script>
var Context0= new AudioContext()
var Panner0=Context0.createPanner();
var BufferSource3=Context0.createBufferSource();
Panner0.channelCount=0;
BufferSource3.connect(Panner0);
BufferSource3.buffer=function(){
var length=1;
var Buffer=Context0.createBuffer(1,length,'44200');
var bufferData= Buffer.getChannelData(0);
for (var i = 0; i < length; ++i) { bufferData[i] = 255;};
return Buffer;
}();
</script>

View File

@ -0,0 +1,24 @@
<script>
var Context0= new AudioContext()
var BufferSource6=Context0.createBufferSource();
setInterval(function(){
BufferSource6.buffer=function(){
var length=11283;
var Buffer=Context0.createBuffer(1,length,Context0.sampleRate);
var bufferData= Buffer.getChannelData(0);
for (var i = 0; i < length; ++i) { bufferData[i] = Math.sin(i*(624))};
return Buffer;
}();
},0)
BufferSource6.start(0.15831333969254047,0.23571860056836158,0.529235512483865);
BufferSource6.buffer=function(){
var length=48517;
var Buffer=Context0.createBuffer(1,length,Context0.sampleRate);
var bufferData= Buffer.getChannelData(0);
for (var i = 0; i < length; ++i) { bufferData[i] = Math.sin(i*(365))};
return Buffer;
}();
</script>

View File

@ -0,0 +1,23 @@
<script>
var Context0= new AudioContext()
var BufferSource0=Context0.createBufferSource();
BufferSource0.start(0.01932738965842873,0.33345631847623736,0.3893404237460345);
BufferSource0.buffer=function(){
var length=35887;
var Buffer=Context0.createBuffer(1,length,Context0.sampleRate);
var bufferData= Buffer.getChannelData(0);
for (var i = 0; i < length; ++i) { bufferData[i] = Math.sin(i*(0.39765272522345185))};
return Buffer;
}();
BufferSource0.buffer=function(){
var length=15952;
var Buffer=Context0.createBuffer(1,length,Context0.sampleRate);
var bufferData= Buffer.getChannelData(0);
for (var i = 0; i < length; ++i) { bufferData[i] = Math.sin(i*(85))};
return Buffer;
}();
BufferSource0.playbackRate.value=20.401213286832185;
</script>

View File

@ -15,3 +15,6 @@ skip-if(Android||B2G) load 789075-1.html # load failed, bug 833371 for B2G
load 844563.html
load 846612.html
load 852838.html
load 874869.html
load 874915.html
load 874934.html

View File

@ -541,6 +541,11 @@ AudioBufferSourceNode::SendOffsetAndDurationParametersToStream(AudioNodeStream*
length : std::min(aOffset + aDuration, length);
if (offset >= endOffset) {
// The offset falls past the end of the buffer. In this case, we need to
// stop the playback immediately if it's in progress. No need to check
// mStartCalled here, since Stop() does that for us.
ErrorResult rv;
Stop(0.0, rv);
return;
}

View File

@ -208,7 +208,7 @@ AudioContext::CreateScriptProcessor(uint32_t aBufferSize,
uint32_t aNumberOfOutputChannels,
ErrorResult& aRv)
{
if (aNumberOfInputChannels == 0 || aNumberOfOutputChannels == 0 ||
if ((aNumberOfInputChannels == 0 && aNumberOfOutputChannels == 0) ||
aNumberOfInputChannels > MAX_SCRIPT_PROCESSOR_CHANNELS ||
aNumberOfOutputChannels > MAX_SCRIPT_PROCESSOR_CHANNELS ||
!IsValidBufferSize(aBufferSize)) {

View File

@ -159,8 +159,12 @@ public:
virtual uint16_t NumberOfOutputs() const { return 1; }
uint32_t ChannelCount() const { return mChannelCount; }
void SetChannelCount(uint32_t aChannelCount)
void SetChannelCount(uint32_t aChannelCount, ErrorResult& aRv)
{
if (aChannelCount == 0) {
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
return;
}
mChannelCount = aChannelCount;
SendChannelMixingParametersToStream();
}

View File

@ -62,6 +62,7 @@ MOCHITEST_FILES := \
test_pannerNode.html \
test_scriptProcessorNode.html \
test_scriptProcessorNodeChannelCount.html \
test_scriptProcessorNodeZeroInputOutput.html \
test_singleSourceDest.html \
test_waveShaper.html \
test_waveShaperNoCurve.html \

View File

@ -0,0 +1,40 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test AudioBufferSourceNode</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="webaudio.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<pre id="test">
<script class="testbody" type="text/javascript">
SimpleTest.waitForExplicitFinish();
addLoadEvent(function() {
SpecialPowers.setBoolPref("media.webaudio.enabled", true);
var context = new AudioContext();
var sp = context.createScriptProcessor(2048, 0, 2);
sp.onaudioprocess = function(e) {
is(e.inputBuffer.numberOfChannels, 0, "Should have 0 input channels");
is(e.outputBuffer.numberOfChannels, 2, "Should have 2 output channels");
sp.onaudioprocess = null;
sp = context.createScriptProcessor(2048, 2, 0);
sp.onaudioprocess = function(e) {
is(e.inputBuffer.numberOfChannels, 2, "Should have 2 input channels");
is(e.outputBuffer.numberOfChannels, 0, "Should have 0 output channels");
sp.onaudioprocess = null;
SpecialPowers.clearUserPref("media.webaudio.enabled");
SimpleTest.finish();
};
};
});
</script>
</pre>
</body>
</html>

View File

@ -91,6 +91,10 @@ function createNode(context, buffer, destination) {
is(source.channelCountMode, "max", "Correct channelCountMode for the source node");
is(source.channelInterpretation, "speakers", "Correct channelCountInterpretation for the source node");
expectException(function() {
source.channelCount = 0;
}, DOMException.NOT_SUPPORTED_ERR);
source.buffer = buffer;
ok(source.buffer, "Source node should have a buffer now");

View File

@ -134,6 +134,16 @@ SVGTransformableElement::SetAnimateMotionTransform(const gfxMatrix* aMatrix)
}
mAnimateMotionTransform = aMatrix ? new gfxMatrix(*aMatrix) : nullptr;
DidAnimateTransformList();
nsIFrame* frame = GetPrimaryFrame();
if (frame) {
// If the result of this transform and any other transforms on this frame
// is the identity matrix, then DoApplyRenderingChangeToTree won't handle
// our nsChangeHint_UpdateTransformLayer hint since aFrame->IsTransformed()
// will return false. That's fine, but we still need to schedule a repaint,
// and that won't otherwise happen. Since it's cheap to call SchedulePaint,
// we don't bother to check IsTransformed().
frame->SchedulePaint();
}
}
nsSVGAnimatedTransformList*

View File

@ -36,6 +36,7 @@ interface AudioNode : EventTarget {
readonly attribute unsigned long numberOfOutputs;
// Channel up-mixing and down-mixing rules for all inputs.
[SetterThrows]
attribute unsigned long channelCount;
attribute ChannelCountMode channelCountMode;
attribute ChannelInterpretation channelInterpretation;

View File

@ -81,7 +81,7 @@ interface HTMLInputElement : HTMLElement {
attribute DOMString defaultValue;
[Pure, TreatNullAs=EmptyString, SetterThrows]
attribute DOMString value;
[Throws]
[Throws, Pref="dom.experimental_forms"]
attribute Date? valueAsDate;
[Pure, SetterThrows]
attribute unrestricted double valueAsNumber;

View File

@ -1687,7 +1687,7 @@ void nsWebBrowser::WindowLowered(nsIWidget* aWidget)
Deactivate();
}
bool nsWebBrowser::PaintWindow(nsIWidget* aWidget, nsIntRegion aRegion, uint32_t aFlags)
bool nsWebBrowser::PaintWindow(nsIWidget* aWidget, nsIntRegion aRegion)
{
LayerManager* layerManager = aWidget->GetLayerManager();
NS_ASSERTION(layerManager, "Must be in paint event");

View File

@ -124,7 +124,7 @@ protected:
// nsIWidgetListener
virtual void WindowRaised(nsIWidget* aWidget);
virtual void WindowLowered(nsIWidget* aWidget);
virtual bool PaintWindow(nsIWidget* aWidget, nsIntRegion aRegion, uint32_t aFlags) MOZ_OVERRIDE;
virtual bool PaintWindow(nsIWidget* aWidget, nsIntRegion aRegion) MOZ_OVERRIDE;
protected:
nsDocShellTreeOwner* mDocShellTreeOwner;

View File

@ -3252,6 +3252,7 @@ nsWebBrowserPersist::CloneNodeWithFixedUpAttributes(
case NS_FORM_INPUT_RANGE:
case NS_FORM_INPUT_DATE:
case NS_FORM_INPUT_TIME:
case NS_FORM_INPUT_COLOR:
nodeAsInput->GetValue(valueStr);
// Avoid superfluous value="" serialization
if (valueStr.IsEmpty())

View File

@ -46,7 +46,7 @@ enum TextureClientType
{
TEXTURE_CONTENT, // dynamically drawn content
TEXTURE_SHMEM, // shared memory
TEXTURE_YCBCR, // ShmemYCbCrImage
TEXTURE_YCBCR, // YCbCr in a shmem
TEXTURE_SHARED_GL, // GLContext::SharedTextureHandle
TEXTURE_SHARED_GL_EXTERNAL, // GLContext::SharedTextureHandle, the ownership of
// the SurfaceDescriptor passed to the texture

View File

@ -134,7 +134,6 @@ CPPSRCS += \
LayerTransactionChild.cpp \
LayerTransactionParent.cpp \
SharedPlanarYCbCrImage.cpp \
ShmemYCbCrImage.cpp \
SharedRGBImage.cpp \
TaskThrottler.cpp \
ImageClient.cpp \
@ -146,6 +145,7 @@ CPPSRCS += \
TextureHostOGL.cpp \
TiledContentClient.cpp \
TiledContentHost.cpp \
YCbCrImageDataSerializer.cpp \
$(NULL)
ifdef MOZ_X11 #{

View File

@ -3,7 +3,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "ShmemYCbCrImage.h"
#include "mozilla/layers/YCbCrImageDataSerializer.h"
#define MOZ_ALIGN_WORD(x) (((x) + 3) & ~3)
@ -14,11 +14,7 @@ namespace layers {
// The Data is layed out as follows:
//
// +-----------------+ -+ <-- Beginning of the Shmem
// | | |
// | ... | | offset
// | | |
// +-----------------+ -++ --+ --+
// +-----------------+ -++ --+ --+ <-- Beginning of the buffer
// | YCbCrBufferInfo | | | |
// +-----------------+ --+ | |
// | data | | | YCbCrBufferInfo->[mY/mCb/mCr]Offset
@ -44,69 +40,68 @@ struct YCbCrBufferInfo
uint32_t mCbCrHeight;
};
static YCbCrBufferInfo* GetYCbCrBufferInfo(Shmem& aShmem, size_t aOffset)
static YCbCrBufferInfo* GetYCbCrBufferInfo(uint8_t* aData)
{
return reinterpret_cast<YCbCrBufferInfo*>(aShmem.get<uint8_t>() + aOffset);
return reinterpret_cast<YCbCrBufferInfo*>(aData);
}
uint8_t* ShmemYCbCrImage::GetYData()
bool YCbCrImageDataDeserializerBase::IsValid()
{
YCbCrBufferInfo* info = GetYCbCrBufferInfo(mShmem, mOffset);
if (mData == nullptr) {
return false;
}
size_t bufferInfoSize = MOZ_ALIGN_WORD(sizeof(YCbCrBufferInfo));
return true;
}
uint8_t* YCbCrImageDataDeserializerBase::GetYData()
{
YCbCrBufferInfo* info = GetYCbCrBufferInfo(mData);
return reinterpret_cast<uint8_t*>(info) + info->mYOffset;
}
uint8_t* ShmemYCbCrImage::GetCbData()
uint8_t* YCbCrImageDataDeserializerBase::GetCbData()
{
YCbCrBufferInfo* info = GetYCbCrBufferInfo(mShmem, mOffset);
YCbCrBufferInfo* info = GetYCbCrBufferInfo(mData);
return reinterpret_cast<uint8_t*>(info) + info->mCbOffset;
}
uint8_t* ShmemYCbCrImage::GetCrData()
uint8_t* YCbCrImageDataDeserializerBase::GetCrData()
{
YCbCrBufferInfo* info = GetYCbCrBufferInfo(mShmem, mOffset);
YCbCrBufferInfo* info = GetYCbCrBufferInfo(mData);
return reinterpret_cast<uint8_t*>(info) + info->mCrOffset;
}
uint8_t* ShmemYCbCrImage::GetData()
uint8_t* YCbCrImageDataDeserializerBase::GetData()
{
YCbCrBufferInfo* info = GetYCbCrBufferInfo(mShmem, mOffset);
YCbCrBufferInfo* info = GetYCbCrBufferInfo(mData);
return (reinterpret_cast<uint8_t*>(info)) + MOZ_ALIGN_WORD(sizeof(YCbCrBufferInfo));
}
uint32_t ShmemYCbCrImage::GetYStride()
uint32_t YCbCrImageDataDeserializerBase::GetYStride()
{
YCbCrBufferInfo* info = GetYCbCrBufferInfo(mShmem, mOffset);
YCbCrBufferInfo* info = GetYCbCrBufferInfo(mData);
return info->mYWidth;
}
uint32_t ShmemYCbCrImage::GetCbCrStride()
uint32_t YCbCrImageDataDeserializerBase::GetCbCrStride()
{
YCbCrBufferInfo* info = GetYCbCrBufferInfo(mShmem, mOffset);
YCbCrBufferInfo* info = GetYCbCrBufferInfo(mData);
return info->mCbCrWidth;
}
gfxIntSize ShmemYCbCrImage::GetYSize()
gfxIntSize YCbCrImageDataDeserializerBase::GetYSize()
{
YCbCrBufferInfo* info = GetYCbCrBufferInfo(mShmem, mOffset);
YCbCrBufferInfo* info = GetYCbCrBufferInfo(mData);
return gfxIntSize(info->mYWidth, info->mYHeight);
}
gfxIntSize ShmemYCbCrImage::GetCbCrSize()
gfxIntSize YCbCrImageDataDeserializerBase::GetCbCrSize()
{
YCbCrBufferInfo* info = GetYCbCrBufferInfo(mShmem, mOffset);
YCbCrBufferInfo* info = GetYCbCrBufferInfo(mData);
return gfxIntSize(info->mCbCrWidth, info->mCbCrHeight);
}
bool ShmemYCbCrImage::Open(Shmem& aShmem, size_t aOffset)
{
mShmem = aShmem;
mOffset = aOffset;
return IsValid();
}
// Offset in bytes
static size_t ComputeOffset(uint32_t aHeight, uint32_t aStride)
{
@ -114,8 +109,9 @@ static size_t ComputeOffset(uint32_t aHeight, uint32_t aStride)
}
// Minimum required shmem size in bytes
size_t ShmemYCbCrImage::ComputeMinBufferSize(const gfxIntSize& aYSize,
const gfxIntSize& aCbCrSize)
size_t
YCbCrImageDataSerializer::ComputeMinBufferSize(const gfx::IntSize& aYSize,
const gfx::IntSize& aCbCrSize)
{
uint32_t yStride = aYSize.width;
uint32_t CbCrStride = aCbCrSize.width;
@ -125,6 +121,13 @@ size_t ShmemYCbCrImage::ComputeMinBufferSize(const gfxIntSize& aYSize,
+ MOZ_ALIGN_WORD(sizeof(YCbCrBufferInfo));
}
size_t
YCbCrImageDataSerializer::ComputeMinBufferSize(const gfxIntSize& aYSize,
const gfxIntSize& aCbCrSize)
{
return ComputeMinBufferSize(gfx::IntSize(aYSize.width, aYSize.height),
gfx::IntSize(aCbCrSize.width, aCbCrSize.height));
}
// Offset in bytes
static size_t ComputeOffset(uint32_t aSize)
{
@ -132,17 +135,17 @@ static size_t ComputeOffset(uint32_t aSize)
}
// Minimum required shmem size in bytes
size_t ShmemYCbCrImage::ComputeMinBufferSize(uint32_t aSize)
size_t
YCbCrImageDataSerializer::ComputeMinBufferSize(uint32_t aSize)
{
return ComputeOffset(aSize) + MOZ_ALIGN_WORD(sizeof(YCbCrBufferInfo));
}
void ShmemYCbCrImage::InitializeBufferInfo(uint8_t* aBuffer,
const gfxIntSize& aYSize,
const gfxIntSize& aCbCrSize)
void
YCbCrImageDataSerializer::InitializeBufferInfo(const gfx::IntSize& aYSize,
const gfx::IntSize& aCbCrSize)
{
YCbCrBufferInfo* info = reinterpret_cast<YCbCrBufferInfo*>(aBuffer);
YCbCrBufferInfo* info = GetYCbCrBufferInfo(mData);
info->mYOffset = MOZ_ALIGN_WORD(sizeof(YCbCrBufferInfo));
info->mCbOffset = info->mYOffset
+ MOZ_ALIGN_WORD(aYSize.width * aYSize.height);
@ -155,18 +158,12 @@ void ShmemYCbCrImage::InitializeBufferInfo(uint8_t* aBuffer,
info->mCbCrHeight = aCbCrSize.height;
}
bool ShmemYCbCrImage::IsValid()
void
YCbCrImageDataSerializer::InitializeBufferInfo(const gfxIntSize& aYSize,
const gfxIntSize& aCbCrSize)
{
if (mShmem == Shmem()) {
return false;
}
size_t bufferInfoSize = MOZ_ALIGN_WORD(sizeof(YCbCrBufferInfo));
if (mShmem.Size<uint8_t>() < bufferInfoSize ||
GetYCbCrBufferInfo(mShmem, mOffset)->mYOffset != bufferInfoSize ||
mShmem.Size<uint8_t>() < mOffset + ComputeMinBufferSize(GetYSize(),GetCbCrSize())) {
return false;
}
return true;
InitializeBufferInfo(gfx::IntSize(aYSize.width, aYSize.height),
gfx::IntSize(aCbCrSize.width, aCbCrSize.height));
}
static void CopyLineWithSkip(const uint8_t* src, uint8_t* dst, uint32_t len, uint32_t skip) {
@ -177,11 +174,12 @@ static void CopyLineWithSkip(const uint8_t* src, uint8_t* dst, uint32_t len, uin
}
}
bool ShmemYCbCrImage::CopyData(const uint8_t* aYData,
const uint8_t* aCbData, const uint8_t* aCrData,
gfxIntSize aYSize, uint32_t aYStride,
gfxIntSize aCbCrSize, uint32_t aCbCrStride,
uint32_t aYSkip, uint32_t aCbCrSkip)
bool
YCbCrImageDataSerializer::CopyData(const uint8_t* aYData,
const uint8_t* aCbData, const uint8_t* aCrData,
gfxIntSize aYSize, uint32_t aYStride,
gfxIntSize aCbCrSize, uint32_t aCbCrStride,
uint32_t aYSkip, uint32_t aCbCrSkip)
{
if (!IsValid() || GetYSize() != aYSize || GetCbCrSize() != aCbCrSize) {
return false;

View File

@ -3,8 +3,8 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef MOZILLA_LAYERS_SHMEMYCBCRIMAGE_H
#define MOZILLA_LAYERS_SHMEMYCBCRIMAGE_H
#ifndef MOZILLA_LAYERS_BLOBYCBCRSURFACE_H
#define MOZILLA_LAYERS_BLOBYCBCRSURFACE_H
#include "mozilla/DebugOnly.h"
@ -21,49 +21,13 @@ namespace layers {
class Image;
/**
* This class is a view on a YCbCrImage stored in a Shmem at a certain offset.
* It is only meant as a convenience to access the image data, and does not own
* the data. The instance can live on the stack and used as follows:
*
* const YCbCrImage& yuv = sharedImage.get_YCbCrImage();
* ShmemYCbCrImage shmImg(yuv.data(), yuv.offset());
* if (!shmImg.IsValid()) {
* // handle error
* }
* mYSize = shmImg.GetYSize(); // work with the data, etc...
* Convenience class to share code between YCbCrImageDataSerializer
* and YCbCrImageDataDeserializer.
* Do not use it.
*/
class ShmemYCbCrImage
class YCbCrImageDataDeserializerBase
{
public:
typedef mozilla::ipc::Shmem Shmem;
ShmemYCbCrImage() : mOffset(0) {}
ShmemYCbCrImage(Shmem& shm, size_t offset = 0) {
DebugOnly<bool> status = Open(shm,offset);
NS_ASSERTION(status, "Invalid data in the shmem");
}
/**
* This function is meant as a helper to know how much shared memory we need
* to allocate in a shmem in order to place a shared YCbCr image blob of
* given dimensions.
*/
static size_t ComputeMinBufferSize(const gfxIntSize& aYSize,
const gfxIntSize& aCbCrSize);
static size_t ComputeMinBufferSize(uint32_t aSize);
/**
* Write the image informations in a buffer for given dimensions.
* The provided pointer should point to the beginning of the (chunk of)
* buffer on which we want to store th image.
*/
static void InitializeBufferInfo(uint8_t* aBuffer,
const gfxIntSize& aYSize,
const gfxIntSize& aCbCrSize);
/**
* Returns true if the shmem's data blob contains a valid YCbCr image.
*/
bool IsValid();
/**
@ -102,21 +66,74 @@ public:
* Return a pointer to the begining of the data buffer.
*/
uint8_t* GetData();
protected:
YCbCrImageDataDeserializerBase(uint8_t* aData)
: mData (aData) {}
uint8_t* mData;
};
/**
* A view on a YCbCr image stored with its metadata in a blob of memory.
* It is only meant as a convenience to access the image data, and does not own
* the data. The instance can live on the stack and used as follows:
*
* const YCbCrImage& yuv = sharedImage.get_YCbCrImage();
* YCbCrImageDataDeserializer deserializer(yuv.data().get<uint8_t>());
* if (!deserializer.IsValid()) {
* // handle error
* }
* size = deserializer.GetYSize(); // work with the data, etc...
*/
class MOZ_STACK_CLASS YCbCrImageDataSerializer : public YCbCrImageDataDeserializerBase
{
public:
YCbCrImageDataSerializer(uint8_t* aData) : YCbCrImageDataDeserializerBase(aData) {}
/**
* Copies the data passed in parameter into the shmem.
* This function is meant as a helper to know how much shared memory we need
* to allocate in a shmem in order to place a shared YCbCr image blob of
* given dimensions.
*/
static size_t ComputeMinBufferSize(const gfx::IntSize& aYSize,
const gfx::IntSize& aCbCrSize);
static size_t ComputeMinBufferSize(const gfxIntSize& aYSize,
const gfxIntSize& aCbCrSize);
static size_t ComputeMinBufferSize(uint32_t aSize);
/**
* Write the image informations in the buffer for given dimensions.
* The provided pointer should point to the beginning of the (chunk of)
* buffer on which we want to store the image.
*/
void InitializeBufferInfo(const gfx::IntSize& aYSize,
const gfx::IntSize& aCbCrSize);
void InitializeBufferInfo(const gfxIntSize& aYSize,
const gfxIntSize& aCbCrSize);
bool CopyData(const uint8_t* aYData,
const uint8_t* aCbData, const uint8_t* aCrData,
gfxIntSize aYSize, uint32_t aYStride,
gfxIntSize aCbCrSize, uint32_t aCbCrStride,
uint32_t aYSkip, uint32_t aCbCrSkip);
};
private:
bool Open(Shmem& aShmem, size_t aOffset = 0);
ipc::Shmem mShmem;
size_t mOffset;
/**
* A view on a YCbCr image stored with its metadata in a blob of memory.
* It is only meant as a convenience to access the image data, and does not own
* the data. The instance can live on the stack and used as follows:
*
* const YCbCrImage& yuv = sharedImage.get_YCbCrImage();
* YCbCrImageDataDeserializer deserializer(yuv.data().get<uint8_t>());
* if (!deserializer.IsValid()) {
* // handle error
* }
* size = deserializer.GetYSize(); // work with the data, etc...
*/
class MOZ_STACK_CLASS YCbCrImageDataDeserializer : public YCbCrImageDataDeserializerBase
{
public:
YCbCrImageDataDeserializer(uint8_t* aData) : YCbCrImageDataDeserializerBase(aData) {}
};
} // namespace

View File

@ -13,9 +13,10 @@
#include "mozilla/layers/SharedPlanarYCbCrImage.h"
#include "GLContext.h"
#include "BasicLayers.h" // for PaintContext
#include "ShmemYCbCrImage.h"
#include "mozilla/layers/YCbCrImageDataSerializer.h"
#include "gfxReusableSurfaceWrapper.h"
#include "gfxPlatform.h"
#include "mozilla/StandardInteger.h"
using namespace mozilla::gl;
@ -277,8 +278,8 @@ AutoLockYCbCrClient::Update(PlanarYCbCrImage* aImage)
ipc::Shmem& shmem = mDescriptor->get_YCbCrImage().data();
ShmemYCbCrImage shmemImage(shmem);
if (!shmemImage.CopyData(data->mYChannel, data->mCbChannel, data->mCrChannel,
YCbCrImageDataSerializer serializer(shmem.get<uint8_t>());
if (!serializer.CopyData(data->mYChannel, data->mCbChannel, data->mCrChannel,
data->mYSize, data->mYStride,
data->mCbCrSize, data->mCbCrStride,
data->mYSkip, data->mCbSkip)) {
@ -306,9 +307,9 @@ bool AutoLockYCbCrClient::EnsureTextureClient(PlanarYCbCrImage* aImage)
needsAllocation = true;
} else {
ipc::Shmem& shmem = mDescriptor->get_YCbCrImage().data();
ShmemYCbCrImage shmemImage(shmem);
if (shmemImage.GetYSize() != data->mYSize ||
shmemImage.GetCbCrSize() != data->mCbCrSize) {
YCbCrImageDataSerializer serializer(shmem.get<uint8_t>());
if (serializer.GetYSize() != data->mYSize ||
serializer.GetCbCrSize() != data->mCbCrSize) {
needsAllocation = true;
}
}
@ -320,19 +321,18 @@ bool AutoLockYCbCrClient::EnsureTextureClient(PlanarYCbCrImage* aImage)
mTextureClient->ReleaseResources();
ipc::SharedMemory::SharedMemoryType shmType = OptimalShmemType();
size_t size = ShmemYCbCrImage::ComputeMinBufferSize(data->mYSize,
data->mCbCrSize);
size_t size = YCbCrImageDataSerializer::ComputeMinBufferSize(data->mYSize,
data->mCbCrSize);
ipc::Shmem shmem;
if (!mTextureClient->GetForwarder()->AllocUnsafeShmem(size, shmType, &shmem)) {
return false;
}
ShmemYCbCrImage::InitializeBufferInfo(shmem.get<uint8_t>(),
data->mYSize,
data->mCbCrSize);
YCbCrImageDataSerializer serializer(shmem.get<uint8_t>());
serializer.InitializeBufferInfo(data->mYSize,
data->mCbCrSize);
*mDescriptor = YCbCrImage(shmem, 0, 0);
*mDescriptor = YCbCrImage(shmem, 0);
return true;
}

View File

@ -9,7 +9,7 @@
#include "gfxImageSurface.h"
#include "Effects.h"
#include "ipc/AutoOpenSurface.h"
#include "ShmemYCbCrImage.h"
#include "mozilla/layers/YCbCrImageDataSerializer.h"
#include "gfxWindowsPlatform.h"
#include "gfxD2DSurface.h"
@ -460,30 +460,29 @@ TextureHostYCbCrD3D11::UpdateImpl(const SurfaceDescriptor& aImage,
{
MOZ_ASSERT(aImage.type() == SurfaceDescriptor::TYCbCrImage);
ShmemYCbCrImage shmemImage(aImage.get_YCbCrImage().data(),
aImage.get_YCbCrImage().offset());
YCbCrImageDataDeserializer yuvDeserializer(aImage.get_YCbCrImage().data().get<uint8_t>());
gfxIntSize gfxCbCrSize = shmemImage.GetCbCrSize();
gfxIntSize gfxCbCrSize = yuvDeserializer.GetCbCrSize();
gfxIntSize size = shmemImage.GetYSize();
gfxIntSize size = yuvDeserializer.GetYSize();
D3D11_SUBRESOURCE_DATA initData;
initData.pSysMem = shmemImage.GetYData();
initData.SysMemPitch = shmemImage.GetYStride();
initData.pSysMem = yuvDeserializer.GetYData();
initData.SysMemPitch = yuvDeserializer.GetYStride();
CD3D11_TEXTURE2D_DESC desc(DXGI_FORMAT_R8_UNORM, size.width, size.height,
1, 1, D3D11_BIND_SHADER_RESOURCE, D3D11_USAGE_IMMUTABLE);
mDevice->CreateTexture2D(&desc, &initData, byRef(mTextures[0]));
initData.pSysMem = shmemImage.GetCbData();
initData.SysMemPitch = shmemImage.GetCbCrStride();
desc.Width = shmemImage.GetCbCrSize().width;
desc.Height = shmemImage.GetCbCrSize().height;
initData.pSysMem = yuvDeserializer.GetCbData();
initData.SysMemPitch = yuvDeserializer.GetCbCrStride();
desc.Width = yuvDeserializer.GetCbCrSize().width;
desc.Height = yuvDeserializer.GetCbCrSize().height;
mDevice->CreateTexture2D(&desc, &initData, byRef(mTextures[1]));
initData.pSysMem = shmemImage.GetCrData();
initData.pSysMem = yuvDeserializer.GetCrData();
mDevice->CreateTexture2D(&desc, &initData, byRef(mTextures[2]));
mSize = IntSize(size.width, size.height);

View File

@ -71,7 +71,6 @@ struct SurfaceStreamDescriptor {
struct YCbCrImage {
Shmem data;
size_t offset;
uint64_t owner;
};

View File

@ -4,7 +4,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "SharedPlanarYCbCrImage.h"
#include "ShmemYCbCrImage.h"
#include "mozilla/layers/YCbCrImageDataSerializer.h"
#include "ISurfaceAllocator.h"
#include "mozilla/layers/LayersSurfaces.h"
@ -40,21 +40,21 @@ SharedPlanarYCbCrImage::SetData(const PlanarYCbCrImage::Data& aData)
// do not set mBuffer like in PlanarYCbCrImage because the later
// will try to manage this memory without knowing it belongs to a
// shmem.
mBufferSize = ShmemYCbCrImage::ComputeMinBufferSize(mData.mYSize,
mData.mCbCrSize);
mBufferSize = YCbCrImageDataSerializer::ComputeMinBufferSize(mData.mYSize,
mData.mCbCrSize);
mSize = mData.mPicSize;
ShmemYCbCrImage shmImg(mShmem);
YCbCrImageDataSerializer serializer(mShmem.get<uint8_t>());
MOZ_ASSERT(aData.mCbSkip == aData.mCrSkip);
if (!shmImg.CopyData(aData.mYChannel, aData.mCbChannel, aData.mCrChannel,
aData.mYSize, aData.mYStride,
aData.mCbCrSize, aData.mCbCrStride,
aData.mYSkip, aData.mCbSkip)) {
if (!serializer.CopyData(aData.mYChannel, aData.mCbChannel, aData.mCrChannel,
aData.mYSize, aData.mYStride,
aData.mCbCrSize, aData.mCbCrStride,
aData.mYSkip, aData.mCbSkip)) {
NS_WARNING("Failed to copy image data!");
}
mData.mYChannel = shmImg.GetYData();
mData.mCbChannel = shmImg.GetCbData();
mData.mCrChannel = shmImg.GetCrData();
mData.mYChannel = serializer.GetYData();
mData.mCbChannel = serializer.GetCbData();
mData.mCrChannel = serializer.GetCrData();
}
// needs to be overriden because the parent class sets mBuffer which we
@ -63,15 +63,15 @@ uint8_t*
SharedPlanarYCbCrImage::AllocateAndGetNewBuffer(uint32_t aSize)
{
NS_ABORT_IF_FALSE(!mAllocated, "This image already has allocated data");
size_t size = ShmemYCbCrImage::ComputeMinBufferSize(aSize);
size_t size = YCbCrImageDataSerializer::ComputeMinBufferSize(aSize);
// update buffer size
mBufferSize = size;
// get new buffer _without_ setting mBuffer.
AllocateBuffer(mBufferSize);
ShmemYCbCrImage shmImg(mShmem);
YCbCrImageDataSerializer serializer(mShmem.get<uint8_t>());
return shmImg.GetData();
return serializer.GetData();
}
@ -80,9 +80,9 @@ SharedPlanarYCbCrImage::SetDataNoCopy(const Data &aData)
{
mData = aData;
mSize = aData.mPicSize;
ShmemYCbCrImage::InitializeBufferInfo(mShmem.get<uint8_t>(),
aData.mYSize,
aData.mCbCrSize);
YCbCrImageDataSerializer serializer(mShmem.get<uint8_t>());
serializer.InitializeBufferInfo(aData.mYSize,
aData.mCbCrSize);
}
uint8_t*
@ -103,25 +103,24 @@ SharedPlanarYCbCrImage::Allocate(PlanarYCbCrImage::Data& aData)
{
NS_ABORT_IF_FALSE(!mAllocated, "This image already has allocated data");
size_t size = ShmemYCbCrImage::ComputeMinBufferSize(aData.mYSize,
aData.mCbCrSize);
size_t size = YCbCrImageDataSerializer::ComputeMinBufferSize(aData.mYSize,
aData.mCbCrSize);
if (AllocateBuffer(static_cast<uint32_t>(size)) == nullptr) {
return false;
}
ShmemYCbCrImage::InitializeBufferInfo(mShmem.get<uint8_t>(),
aData.mYSize,
aData.mCbCrSize);
ShmemYCbCrImage shmImg(mShmem);
if (!shmImg.IsValid() || mShmem.Size<uint8_t>() < size) {
YCbCrImageDataSerializer serializer(mShmem.get<uint8_t>());
serializer.InitializeBufferInfo(aData.mYSize,
aData.mCbCrSize);
if (!serializer.IsValid() || mShmem.Size<uint8_t>() < size) {
mSurfaceAllocator->DeallocShmem(mShmem);
return false;
}
aData.mYChannel = shmImg.GetYData();
aData.mCbChannel = shmImg.GetCbData();
aData.mCrChannel = shmImg.GetCrData();
aData.mYChannel = serializer.GetYData();
aData.mCbChannel = serializer.GetCbData();
aData.mCrChannel = serializer.GetCrData();
// copy some of aData's values in mData (most of them)
mData.mYChannel = aData.mYChannel;
@ -150,7 +149,7 @@ SharedPlanarYCbCrImage::ToSurfaceDescriptor(SurfaceDescriptor& aDesc) {
if (!mAllocated) {
return false;
}
aDesc = YCbCrImage(mShmem, 0, reinterpret_cast<uint64_t>(this));
aDesc = YCbCrImage(mShmem, reinterpret_cast<uint64_t>(this));
this->AddRef();
return true;
}
@ -160,7 +159,7 @@ SharedPlanarYCbCrImage::DropToSurfaceDescriptor(SurfaceDescriptor& aDesc) {
if (!mAllocated) {
return false;
}
aDesc = YCbCrImage(mShmem, 0, 0);
aDesc = YCbCrImage(mShmem, 0);
mShmem = Shmem();
mAllocated = false;
return true;

View File

@ -40,7 +40,6 @@ EXPORTS += [
'ReadbackLayer.h',
'ShadowLayersManager.h',
'SharedTextureImage.h',
'ShmemYCbCrImage.h',
'TexturePoolOGL.h',
]
@ -105,7 +104,6 @@ EXPORTS.mozilla.layers += [
'ShadowLayersManager.h',
'SharedPlanarYCbCrImage.h',
'SharedRGBImage.h',
'ShmemYCbCrImage.h',
'TaskThrottler.h',
'TextureClient.h',
'TextureClientOGL.h',
@ -113,6 +111,7 @@ EXPORTS.mozilla.layers += [
'TextureHostOGL.h',
'ThebesLayerComposite.h',
'TiledContentClient.h',
'YCbCrImageDataSerializer.h',
]
if CONFIG['MOZ_X11']:

View File

@ -6,7 +6,6 @@
#include "gfxSharedImageSurface.h"
#include "ImageContainer.h" // for PlanarYCBCRImage
#include "mozilla/layers/ShmemYCbCrImage.h"
#include "ipc/AutoOpenSurface.h"
#include "ImageLayerOGL.h"
#include "gfxImageSurface.h"

View File

@ -19,7 +19,7 @@ namespace layers {
class CairoImage;
class PlanarYCbCrImage;
class ShmemYCbCrImage;
class BlobYCbCrSurface;
/**
* This class wraps a GL texture. It includes a GLContext reference

View File

@ -6,7 +6,7 @@
#include "TextureHostOGL.h"
#include "ipc/AutoOpenSurface.h"
#include "gfx2DGlue.h"
#include "ShmemYCbCrImage.h"
#include "mozilla/layers/YCbCrImageDataSerializer.h"
#include "GLContext.h"
#include "gfxImageSurface.h"
#include "SurfaceStream.h"
@ -491,11 +491,10 @@ YCbCrTextureHostOGL::UpdateImpl(const SurfaceDescriptor& aImage,
}
NS_ASSERTION(aImage.type() == SurfaceDescriptor::TYCbCrImage, "SurfaceDescriptor mismatch");
ShmemYCbCrImage shmemImage(aImage.get_YCbCrImage().data(),
aImage.get_YCbCrImage().offset());
YCbCrImageDataDeserializer deserializer(aImage.get_YCbCrImage().data().get<uint8_t>());
gfxIntSize gfxSize = shmemImage.GetYSize();
gfxIntSize gfxCbCrSize = shmemImage.GetCbCrSize();
gfxIntSize gfxSize = deserializer.GetYSize();
gfxIntSize gfxCbCrSize = deserializer.GetCbCrSize();
if (!mYTexture->mTexImage || mYTexture->mTexImage->GetSize() != gfxSize) {
mYTexture->mTexImage = CreateBasicTextureImage(mGL,
@ -519,14 +518,14 @@ YCbCrTextureHostOGL::UpdateImpl(const SurfaceDescriptor& aImage,
FlagsToGLFlags(mFlags));
}
RefPtr<gfxImageSurface> tempY = new gfxImageSurface(shmemImage.GetYData(),
gfxSize, shmemImage.GetYStride(),
gfxASurface::ImageFormatA8);
RefPtr<gfxImageSurface> tempCb = new gfxImageSurface(shmemImage.GetCbData(),
gfxCbCrSize, shmemImage.GetCbCrStride(),
RefPtr<gfxImageSurface> tempY = new gfxImageSurface(deserializer.GetYData(),
gfxSize, deserializer.GetYStride(),
gfxASurface::ImageFormatA8);
RefPtr<gfxImageSurface> tempCr = new gfxImageSurface(shmemImage.GetCrData(),
gfxCbCrSize, shmemImage.GetCbCrStride(),
RefPtr<gfxImageSurface> tempCb = new gfxImageSurface(deserializer.GetCbData(),
gfxCbCrSize, deserializer.GetCbCrStride(),
gfxASurface::ImageFormatA8);
RefPtr<gfxImageSurface> tempCr = new gfxImageSurface(deserializer.GetCrData(),
gfxCbCrSize, deserializer.GetCbCrStride(),
gfxASurface::ImageFormatA8);
nsIntRegion yRegion(nsIntRect(0, 0, gfxSize.width, gfxSize.height));

View File

@ -215,6 +215,7 @@ CPPSRCS += MIR.cpp \
IonMacroAssembler.cpp \
IonSpewer.cpp \
JSONSpewer.cpp \
PerfSpewer.cpp \
LICM.cpp \
LinearScan.cpp \
LIR.cpp \

View File

@ -14,8 +14,7 @@ PARALLEL_DIRS_export = $(addsuffix _export,$(PARALLEL_DIRS))
###############
export_tier_%:
@$(ECHO) "$@"
@$(MAKE_TIER_SUBMAKEFILES)
$(foreach dir,$(tier_$*_dirs),$(call SUBMAKE,export,$(dir)))
$(foreach dir,$(tier_$*_dirs),$(call TIER_DIR_SUBMAKE,export,$(dir)))
#################
## Common targets

View File

@ -14,8 +14,7 @@ PARALLEL_DIRS_libs = $(addsuffix _libs,$(PARALLEL_DIRS))
###############
libs_tier_%:
@$(ECHO) "$@"
@$(MAKE_TIER_SUBMAKEFILES)
$(foreach dir,$(tier_$*_dirs),$(call SUBMAKE,libs,$(dir)))
$(foreach dir,$(tier_$*_dirs),$(call TIER_DIR_SUBMAKE,libs,$(dir)))
#################
## Common targets

View File

@ -14,8 +14,7 @@ PARALLEL_DIRS_tools = $(addsuffix _tools,$(PARALLEL_DIRS))
###############
tools_tier_%:
@$(ECHO) "$@"
@$(MAKE_TIER_SUBMAKEFILES)
$(foreach dir,$(tier_$*_dirs),$(call SUBMAKE,tools,$(dir)))
$(foreach dir,$(tier_$*_dirs),$(call TIER_DIR_SUBMAKE,tools,$(dir)))
#################
## Common targets

View File

@ -425,6 +425,14 @@ define SUBMAKE # $(call SUBMAKE,target,directory)
endef # The extra line is important here! don't delete it
define TIER_DIR_SUBMAKE
@echo "BUILDSTATUS TIERDIR_START $(2)"
$(call SUBMAKE,$(1),$(2))
@echo "BUILDSTATUS TIERDIR_FINISH $(2)"
endef # Ths empty line is important.
ifneq (,$(strip $(DIRS)))
LOOP_OVER_DIRS = \
$(foreach dir,$(DIRS),$(call SUBMAKE,$@,$(dir)))
@ -627,6 +635,16 @@ endif
# other rules for the default target or else it may not run in time.
ifndef MOZBUILD_BACKEND_CHECKED
# Since Makefile is listed as a global dependency, this has the
# unfortunate side-effect of invalidating all targets if it is executed.
# So e.g. if you are in /dom/bindings and /foo/moz.build changes,
# /dom/bindings will get invalidated. The upside is if the current
# Makefile/backend.mk is updated as a result of backend regeneration, we
# actually pick up the changes. This should reduce the amount of
# required clobbers and is thus the lesser evil.
Makefile: $(DEPTH)/backend.RecursiveMakeBackend.built
@$(TOUCH) $@
$(DEPTH)/backend.RecursiveMakeBackend.built:
@echo "Build configuration changed. Regenerating backend."
@cd $(DEPTH) && $(PYTHON) ./config.status
@ -650,6 +668,7 @@ SUBMAKEFILES += $(addsuffix /Makefile, $(DIRS) $(TOOL_DIRS) $(PARALLEL_DIRS))
ifndef SUPPRESS_DEFAULT_RULES
ifdef TIERS
default all alldep::
@echo "BUILDSTATUS TIERS $(TIERS)"
$(foreach tier,$(TIERS),$(call SUBMAKE,tier_$(tier)))
else
@ -679,14 +698,44 @@ ECHO := true
QUIET := -q
endif
MAKE_TIER_SUBMAKEFILES = +$(if $(tier_$*_dirs),$(MAKE) $(addsuffix /Makefile,$(tier_$*_dirs)))
# This function is called and evaluated to produce the rule to build the
# specified tier. Each tier begins by building the "static" directories.
# The BUILDSTATUS echo commands are used to faciliate easier parsing
# of build output. Build drivers are encouraged to filter these lines
# from the user.
define CREATE_TIER_RULE
tier_$(1)::
@echo "BUILDSTATUS TIER_START $(1)"
@printf "BUILDSTATUS SUBTIERS"
ifneq (,$(tier_$(1)_staticdirs))
@printf " static"
endif
ifneq (,$(tier_$(1)_dirs))
@printf " export libs tools"
endif
@printf "\n"
@echo "BUILDSTATUS STATICDIRS $$($$@_staticdirs)"
@echo "BUILDSTATUS DIRS $$($$@_dirs)"
ifneq (,$(tier_$(1)_staticdirs))
@echo "BUILDSTATUS SUBTIER_START $(1) static"
$$(foreach dir,$$($$@_staticdirs),$$(call TIER_DIR_SUBMAKE,,$$(dir)))
@echo "BUILDSTATUS SUBTIER_FINISH $(1) static"
endif
ifneq (,$(tier_$(1)_dirs))
@echo "BUILDSTATUS SUBTIER_START $(1) export"
$$(MAKE) export_$$@
@echo "BUILDSTATUS SUBTIER_FINISH $(1) export"
@echo "BUILDSTATUS SUBTIER_START $(1) libs"
$$(MAKE) libs_$$@
@echo "BUILDSTATUS SUBTIER_FINISH $(1) libs"
@echo "BUILDSTATUS SUBTIER_START $(1) tools"
$$(MAKE) tools_$$@
@echo "BUILDSTATUS SUBTIER_FINISH $(1) tools"
@echo "BUILDSTATUS TIER_FINISH $(1)"
endif
endef
$(foreach tier,$(TIERS),tier_$(tier))::
@$(ECHO) "$@: $($@_staticdirs) $($@_dirs)"
$(foreach dir,$($@_staticdirs),$(call SUBMAKE,,$(dir)))
$(MAKE) export_$@
$(MAKE) libs_$@
$(MAKE) tools_$@
$(foreach tier,$(TIERS),$(eval $(call CREATE_TIER_RULE,$(tier))))
# Do everything from scratch
everything::

View File

@ -3708,6 +3708,18 @@ if test -n "$JS_GC_ZEAL" -o -n "$MOZ_DEBUG"; then
AC_DEFINE(JS_GC_ZEAL)
fi
dnl ========================================================
dnl = Enable perf logging for ion.
dnl = Perf logging is OFF by default
dnl ========================================================
MOZ_ARG_ENABLE_BOOL(perf,
[ --enable-perf Enable Linux perf integration],
JS_ION_PERF=1,
JS_ION_PERF= )
if test -n "$JS_ION_PERF"; then
AC_DEFINE(JS_ION_PERF)
fi
dnl ========================================================
dnl JS opt-mode assertions and minidump instrumentation
dnl ========================================================

View File

@ -2478,6 +2478,22 @@ frontend::EmitFunctionScript(JSContext *cx, BytecodeEmitter *bce, ParseNode *bod
bce->switchToMain();
}
/*
* Emit a prologue for run-once scripts which will deoptimize JIT code if
* the script ends up running multiple times via foo.caller related
* shenanigans.
*/
bool runOnce = bce->parent &&
bce->parent->emittingRunOnceLambda &&
!funbox->argumentsHasLocalBinding() &&
!funbox->isGenerator();
if (runOnce) {
bce->switchToProlog();
if (!Emit1(cx, bce, JSOP_RUNONCE) < 0)
return false;
bce->switchToMain();
}
if (!EmitTree(cx, bce, body))
return false;
@ -2495,8 +2511,10 @@ frontend::EmitFunctionScript(JSContext *cx, BytecodeEmitter *bce, ParseNode *bod
* If this function is only expected to run once, mark the script so that
* initializers created within it may be given more precise types.
*/
if (bce->parent && bce->parent->emittingRunOnceLambda)
if (runOnce) {
bce->script->treatAsRunOnce = true;
JS_ASSERT(!bce->script->hasRunOnce);
}
/*
* Mark as singletons any function which will only be executed once, or

View File

@ -17,6 +17,7 @@ using namespace js;
using namespace js::frontend;
using namespace mozilla;
#include "ion/PerfSpewer.h"
#include "ion/CodeGenerator.h"
#include "ion/MIR.h"
#include "ion/MIRGraph.h"

View File

@ -295,6 +295,10 @@ ConvertFrames(JSContext *cx, IonActivation *activation, IonBailoutIterator &it)
while (true) {
IonSpew(IonSpew_Bailouts, " restoring frame");
fp->initFromBailout(cx, iter);
// If the IonScript wasn't compiled with SPS enabled, make sure that the StackFrame
// frame isn't marked as having a pushed SPS frame.
if (!it.ionScript()->hasSPSInstrumentation())
fp->unsetPushedSPSFrame();
if (!iter.moreFrames())
break;

View File

@ -443,8 +443,8 @@ struct BaselineStackBuilder
//
static bool
InitFromBailout(JSContext *cx, HandleScript caller, jsbytecode *callerPC,
HandleFunction fun, HandleScript script, SnapshotIterator &iter,
bool invalidate, BaselineStackBuilder &builder,
HandleFunction fun, HandleScript script, IonScript *ionScript,
SnapshotIterator &iter, bool invalidate, BaselineStackBuilder &builder,
MutableHandleFunction nextCallee, jsbytecode **callPC)
{
uint32_t exprStackSlots = iter.slots() - (script->nfixed + CountArgSlots(script, fun));
@ -503,7 +503,7 @@ InitFromBailout(JSContext *cx, HandleScript caller, jsbytecode *callerPC,
// If SPS Profiler is enabled, mark the frame as having pushed an SPS entry.
// This may be wrong for the last frame of ArgumentCheck bailout, but
// that will be fixed later.
if (cx->runtime->spsProfiler.enabled()) {
if (cx->runtime->spsProfiler.enabled() && ionScript->hasSPSInstrumentation()) {
IonSpew(IonSpew_BaselineBailouts, " Setting SPS flag on frame!");
flags |= BaselineFrame::HAS_PUSHED_SPS_FRAME;
}
@ -1080,8 +1080,8 @@ ion::BailoutIonToBaseline(JSContext *cx, IonActivation *activation, IonBailoutIt
IonSpew(IonSpew_BaselineBailouts, " FrameNo %d", frameNo);
jsbytecode *callPC = NULL;
RootedFunction nextCallee(cx, NULL);
if (!InitFromBailout(cx, caller, callerPC, fun, scr, snapIter, invalidate, builder,
&nextCallee, &callPC))
if (!InitFromBailout(cx, caller, callerPC, fun, scr, iter.ionScript(),
snapIter, invalidate, builder, &nextCallee, &callPC))
{
return BAILOUT_RETURN_FATAL_ERROR;
}

View File

@ -67,6 +67,9 @@ BaselineCompiler::compile()
IonSpew(IonSpew_BaselineScripts, "Baseline compiling script %s:%d (%p)",
script->filename(), script->lineno, script.get());
if (cx->typeInferenceEnabled() && !script->ensureHasBytecodeTypeMap(cx))
return Method_Error;
// Only need to analyze scripts which are marked |argumensHasVarBinding|, to
// compute |needsArgsObj| flag.
if (script->argumentsHasVarBinding()) {
@ -1666,14 +1669,22 @@ BaselineCompiler::emit_JSOP_DELPROP()
return true;
}
Address
BaselineCompiler::getScopeCoordinateAddress(Register reg)
void
BaselineCompiler::getScopeCoordinateObject(Register reg)
{
ScopeCoordinate sc(pc);
masm.loadPtr(frame.addressOfScopeChain(), reg);
for (unsigned i = sc.hops; i; i--)
masm.extractObject(Address(reg, ScopeObject::offsetOfEnclosingScope()), reg);
}
Address
BaselineCompiler::getScopeCoordinateAddress(Register reg)
{
getScopeCoordinateObject(reg);
ScopeCoordinate sc(pc);
Shape *shape = ScopeCoordinateToStaticScopeShape(cx, script, pc);
Address addr;
@ -1710,6 +1721,29 @@ BaselineCompiler::emit_JSOP_CALLALIASEDVAR()
bool
BaselineCompiler::emit_JSOP_SETALIASEDVAR()
{
JSScript *outerScript = ScopeCoordinateFunctionScript(cx, script, pc);
if (outerScript && outerScript->treatAsRunOnce) {
// Type updates for this operation might need to be tracked, so treat
// this as a SETPROP.
// Load rhs into R1.
frame.syncStack(1);
frame.popValue(R1);
// Load and box lhs into R0.
getScopeCoordinateObject(R2.scratchReg());
masm.tagValue(JSVAL_TYPE_OBJECT, R2.scratchReg(), R0);
// Call SETPROP IC.
ICSetProp_Fallback::Compiler compiler(cx);
if (!emitOpIC(compiler.getStub(&stubSpace_)))
return false;
// The IC will return the RHS value in R0, mark it as pushed value.
frame.push(R0);
return true;
}
// Sync everything except the top value, so that we can use R0 as scratch
// (storeValue does not touch it if the top value is in R0).
frame.syncStack(1);
@ -2435,6 +2469,23 @@ BaselineCompiler::emit_JSOP_ARGUMENTS()
return true;
}
typedef bool (*RunOnceScriptPrologueFn)(JSContext *, HandleScript);
static const VMFunction RunOnceScriptPrologueInfo =
FunctionInfo<RunOnceScriptPrologueFn>(js::RunOnceScriptPrologue);
bool
BaselineCompiler::emit_JSOP_RUNONCE()
{
frame.syncStack(0);
prepareVMCall();
masm.movePtr(ImmGCPtr(script), R0.scratchReg());
pushArg(R0.scratchReg());
return callVM(RunOnceScriptPrologueInfo);
}
bool
BaselineCompiler::emit_JSOP_REST()
{

View File

@ -152,6 +152,7 @@ namespace ion {
_(JSOP_EXCEPTION) \
_(JSOP_DEBUGGER) \
_(JSOP_ARGUMENTS) \
_(JSOP_RUNONCE) \
_(JSOP_REST) \
_(JSOP_TOID) \
_(JSOP_TABLESWITCH) \
@ -236,6 +237,7 @@ class BaselineCompiler : public BaselineCompilerSpecific
bool addPCMappingEntry(bool addIndexEntry);
void getScopeCoordinateObject(Register reg);
Address getScopeCoordinateAddress(Register reg);
};

View File

@ -6191,9 +6191,17 @@ DoSetPropFallback(JSContext *cx, BaselineFrame *frame, ICSetProp_Fallback *stub,
JSOp op = JSOp(*pc);
FallbackICSpew(cx, stub, "SetProp(%s)", js_CodeName[op]);
JS_ASSERT(op == JSOP_SETPROP || op == JSOP_SETNAME || op == JSOP_SETGNAME || op == JSOP_INITPROP);
JS_ASSERT(op == JSOP_SETPROP ||
op == JSOP_SETNAME ||
op == JSOP_SETGNAME ||
op == JSOP_INITPROP ||
op == JSOP_SETALIASEDVAR);
RootedPropertyName name(cx, script->getName(pc));
RootedPropertyName name(cx);
if (op == JSOP_SETALIASEDVAR)
name = ScopeCoordinateName(cx, script, pc);
else
name = script->getName(pc);
RootedId id(cx, NameToId(name));
RootedObject obj(cx, ToObjectFromStack(cx, lhs));
@ -6209,6 +6217,8 @@ DoSetPropFallback(JSContext *cx, BaselineFrame *frame, ICSetProp_Fallback *stub,
} else if (op == JSOP_SETNAME || op == JSOP_SETGNAME) {
if (!SetNameOperation(cx, script, pc, obj, rhs))
return false;
} else if (op == JSOP_SETALIASEDVAR) {
obj->asScope().setAliasedVar(cx, pc, name, rhs);
} else if (script->strict) {
if (!js::SetProperty<true>(cx, obj, id, rhs))
return false;

View File

@ -9,6 +9,7 @@
#include "mozilla/DebugOnly.h"
#include "mozilla/Util.h"
#include "PerfSpewer.h"
#include "CodeGenerator.h"
#include "IonLinker.h"
#include "IonSpewer.h"
@ -2501,6 +2502,9 @@ CodeGenerator::generateBody()
return false;
}
if (PerfBlockEnabled())
perfSpewer_.startBasicBlock(current->mir(), masm);
for (; iter != current->end(); iter++) {
IonSpew(IonSpew_Codegen, "instruction %s", iter->opName());
@ -2520,6 +2524,9 @@ CodeGenerator::generateBody()
}
if (masm.oom())
return false;
if (PerfBlockEnabled())
perfSpewer_.endBasicBlock(masm);
}
JS_ASSERT(pushedArgumentSlots_.empty());
@ -2799,7 +2806,7 @@ CodeGenerator::visitNewDeclEnvObject(LNewDeclEnvObject *lir)
return true;
}
typedef JSObject *(*NewCallObjectFn)(JSContext *, HandleShape,
typedef JSObject *(*NewCallObjectFn)(JSContext *, HandleScript, HandleShape,
HandleTypeObject, HeapSlot *);
static const VMFunction NewCallObjectInfo =
FunctionInfo<NewCallObjectFn>(NewCallObject);
@ -2815,25 +2822,33 @@ CodeGenerator::visitNewCallObject(LNewCallObject *lir)
OutOfLineCode *ool;
if (lir->slots()->isRegister()) {
ool = oolCallVM(NewCallObjectInfo, lir,
(ArgList(), ImmGCPtr(templateObj->lastProperty()),
ImmGCPtr(templateObj->type()),
(ArgList(), ImmGCPtr(lir->mir()->block()->info().script()),
ImmGCPtr(templateObj->lastProperty()),
ImmGCPtr(templateObj->hasLazyType() ? NULL : templateObj->type()),
ToRegister(lir->slots())),
StoreRegisterTo(obj));
} else {
ool = oolCallVM(NewCallObjectInfo, lir,
(ArgList(), ImmGCPtr(templateObj->lastProperty()),
ImmGCPtr(templateObj->type()),
(ArgList(), ImmGCPtr(lir->mir()->block()->info().script()),
ImmGCPtr(templateObj->lastProperty()),
ImmGCPtr(templateObj->hasLazyType() ? NULL : templateObj->type()),
ImmWord((void *)NULL)),
StoreRegisterTo(obj));
}
if (!ool)
return false;
masm.newGCThing(obj, templateObj, ool->entry());
masm.initGCThing(obj, templateObj);
if (lir->mir()->needsSingletonType()) {
// Objects can only be given singleton types in VM calls.
masm.jump(ool->entry());
} else {
masm.newGCThing(obj, templateObj, ool->entry());
masm.initGCThing(obj, templateObj);
if (lir->slots()->isRegister())
masm.storePtr(ToRegister(lir->slots()), Address(obj, JSObject::offsetOfSlots()));
}
if (lir->slots()->isRegister())
masm.storePtr(ToRegister(lir->slots()), Address(obj, JSObject::offsetOfSlots()));
masm.bind(ool->rejoin());
return true;
}
@ -5000,6 +5015,17 @@ CodeGenerator::visitGetArgument(LGetArgument *lir)
return true;
}
typedef bool (*RunOnceScriptPrologueFn)(JSContext *, HandleScript);
static const VMFunction RunOnceScriptPrologueInfo =
FunctionInfo<RunOnceScriptPrologueFn>(js::RunOnceScriptPrologue);
bool
CodeGenerator::visitRunOncePrologue(LRunOncePrologue *lir)
{
pushArg(ImmGCPtr(lir->mir()->block()->info().script()));
return callVM(RunOnceScriptPrologueInfo, lir);
}
bool
CodeGenerator::emitRest(LInstruction *lir, Register array, Register numActuals,
Register temp0, Register temp1, unsigned numFormals,
@ -5214,6 +5240,10 @@ CodeGenerator::link()
ionScript->setMethod(code);
ionScript->setSkipArgCheckEntryOffset(getSkipArgCheckEntryOffset());
// If SPS is enabled, mark IonScript as having been instrumented with SPS
if (sps_.enabled())
ionScript->setHasSPSInstrumentation();
SetIonScript(script, executionMode, ionScript);
if (!ionScript)
@ -5234,6 +5264,9 @@ CodeGenerator::link()
ionScript->setDeoptTable(deoptTable_);
if (PerfEnabled())
perfSpewer_.writeProfile(script, code, masm);
// for generating inline caches during the execution.
if (runtimeData_.length())
ionScript->copyRuntimeData(&runtimeData_[0]);
@ -5670,7 +5703,7 @@ CodeGenerator::visitBindNameIC(OutOfLineUpdateCache *ool, BindNameIC *ic)
}
typedef bool (*SetPropertyFn)(JSContext *, HandleObject,
HandlePropertyName, const HandleValue, bool, bool);
HandlePropertyName, const HandleValue, bool, int);
static const VMFunction SetPropertyInfo =
FunctionInfo<SetPropertyFn>(SetProperty);
@ -5680,10 +5713,9 @@ CodeGenerator::visitCallSetProperty(LCallSetProperty *ins)
ConstantOrRegister value = TypedOrValueRegister(ToValue(ins, LCallSetProperty::Value));
const Register objReg = ToRegister(ins->getOperand(0));
jsbytecode *pc = ins->mir()->resumePoint()->pc();
bool isSetName = JSOp(*pc) == JSOP_SETNAME || JSOp(*pc) == JSOP_SETGNAME;
JSOp op = JSOp(*ins->mir()->resumePoint()->pc());
pushArg(Imm32(isSetName));
pushArg(Imm32(op));
pushArg(Imm32(ins->mir()->strict()));
pushArg(value);

View File

@ -215,6 +215,7 @@ class CodeGenerator : public CodeGeneratorSpecific
bool visitIteratorEnd(LIteratorEnd *lir);
bool visitArgumentsLength(LArgumentsLength *lir);
bool visitGetArgument(LGetArgument *lir);
bool visitRunOncePrologue(LRunOncePrologue *lir);
bool emitRest(LInstruction *lir, Register array, Register numActuals,
Register temp0, Register temp1, unsigned numFormals,
JSObject *templateObject, const VMFunction &f);
@ -335,6 +336,8 @@ class CodeGenerator : public CodeGeneratorSpecific
// Script counts created when compiling code with no associated JSScript.
IonScriptCounts *unassociatedScriptCounts_;
PerfSpewer perfSpewer_;
};
} // namespace ion

View File

@ -24,6 +24,7 @@
#include "vm/ThreadPool.h"
#include "vm/ForkJoin.h"
#include "IonCompartment.h"
#include "PerfSpewer.h"
#include "CodeGenerator.h"
#include "jsworkers.h"
#include "BacktrackingAllocator.h"
@ -158,6 +159,7 @@ ion::InitializeIon()
}
#endif
CheckLogging();
CheckPerf();
return true;
}
@ -494,6 +496,11 @@ IonCode::finalize(FreeOp *fop)
// Buffer can be freed at any time hereafter. Catch use-after-free bugs.
JS_POISON(code_, JS_FREE_PATTERN, bufferSize_);
// Horrible hack: if we are using perf integration, we don't
// want to reuse code addresses, so we just leak the memory instead.
if (PerfEnabled())
return;
// Code buffers are stored inside JSC pools.
// Pools are refcounted. Releasing the pool may free it.
if (pool_)
@ -560,6 +567,7 @@ IonScript::IonScript()
invalidateEpilogueDataOffset_(0),
numBailouts_(0),
hasInvalidatedCallTarget_(false),
hasSPSInstrumentation_(false),
runtimeData_(0),
runtimeSize_(0),
cacheIndex_(0),
@ -1476,8 +1484,13 @@ CheckFrame(AbstractFramePtr fp)
}
static bool
CheckScript(JSScript *script, bool osr)
CheckScript(JSContext *cx, JSScript *script, bool osr)
{
if (!script->analyzedArgsUsage() && !script->ensureRanAnalysis(cx)) {
IonSpew(IonSpew_Abort, "OOM under ensureRanAnalysis");
return false;
}
if (osr && script->needsArgsObj()) {
// OSR-ing into functions with arguments objects is not supported.
IonSpew(IonSpew_Abort, "OSR script has argsobj");
@ -1538,7 +1551,7 @@ SequentialCompileContext::checkScriptSize(JSContext *cx, JSScript *script)
bool
CanIonCompileScript(JSContext *cx, HandleScript script, bool osr)
{
if (!script->canIonCompile() || !CheckScript(script, osr))
if (!script->canIonCompile() || !CheckScript(cx, script, osr))
return false;
SequentialCompileContext compileContext;
@ -1568,7 +1581,7 @@ Compile(JSContext *cx, HandleScript script, AbstractFramePtr fp, jsbytecode *osr
return Method_CantCompile;
}
if (!CheckScript(script, bool(osrPc))) {
if (!CheckScript(cx, script, bool(osrPc))) {
IonSpew(IonSpew_Abort, "Aborted compilation of %s:%d", script->filename(), script->lineno);
return Method_CantCompile;
}

View File

@ -1191,6 +1191,9 @@ IonBuilder::inspectOpcode(JSOp op)
case JSOP_ARGUMENTS:
return jsop_arguments();
case JSOP_RUNONCE:
return jsop_runonce();
case JSOP_REST:
return jsop_rest();
@ -1302,7 +1305,8 @@ IonBuilder::inspectOpcode(JSOp op)
case JSOP_CALLGNAME:
{
RootedPropertyName name(cx, info().getAtom(pc)->asPropertyName());
return jsop_getgname(name);
RootedObject obj(cx, &script()->global());
return getStaticName(obj, name);
}
case JSOP_BINDGNAME:
@ -1311,7 +1315,8 @@ IonBuilder::inspectOpcode(JSOp op)
case JSOP_SETGNAME:
{
RootedPropertyName name(cx, info().getAtom(pc)->asPropertyName());
return jsop_setgname(name);
RootedObject obj(cx, &script()->global());
return setStaticName(obj, name);
}
case JSOP_NAME:
@ -4279,8 +4284,9 @@ IonBuilder::createCallObject(MDefinition *callee, MDefinition *scope)
// Allocate the actual object. It is important that no intervening
// instructions could potentially bailout, thus leaking the dynamic slots
// pointer.
MInstruction *callObj = MNewCallObject::New(templateObj, slots);
// pointer. Run-once scripts need a singleton type, so always do a VM call
// in such cases.
MInstruction *callObj = MNewCallObject::New(templateObj, script()->treatAsRunOnce, slots);
current->add(callObj);
// Initialize the object's reserved slots. No post barrier is needed here,
@ -5900,44 +5906,45 @@ IonBuilder::pushTypeBarrier(MInstruction *ins, types::StackTypeSet *observed, bo
}
bool
IonBuilder::jsop_getgname(HandlePropertyName name)
IonBuilder::getStaticName(HandleObject staticObject, HandlePropertyName name)
{
// Optimize undefined, NaN, and Infinity.
if (name == cx->names().undefined)
return pushConstant(UndefinedValue());
if (name == cx->names().NaN)
return pushConstant(cx->runtime->NaNValue);
if (name == cx->names().Infinity)
return pushConstant(cx->runtime->positiveInfinityValue);
JS_ASSERT(staticObject->isGlobal() || staticObject->isCall());
RootedObject globalObj(cx, &script()->global());
JS_ASSERT(globalObj->isNative());
if (staticObject->isGlobal()) {
// Optimize undefined, NaN, and Infinity.
if (name == cx->names().undefined)
return pushConstant(UndefinedValue());
if (name == cx->names().NaN)
return pushConstant(cx->runtime->NaNValue);
if (name == cx->names().Infinity)
return pushConstant(cx->runtime->positiveInfinityValue);
}
RootedId id(cx, NameToId(name));
// For the fastest path, the property must be found, and it must be found
// as a normal data property on exactly the global object.
RootedShape shape(cx, globalObj->nativeLookup(cx, id));
RootedShape shape(cx, staticObject->nativeLookup(cx, id));
if (!shape || !shape->hasDefaultGetter() || !shape->hasSlot())
return jsop_getname(name);
types::TypeObject *globalType = globalObj->getType(cx);
if (!globalType)
types::TypeObject *staticType = staticObject->getType(cx);
if (!staticType)
return false;
types::HeapTypeSet *propertyTypes = NULL;
if (!globalType->unknownProperties()) {
propertyTypes = globalType->getProperty(cx, id, false);
if (!staticType->unknownProperties()) {
propertyTypes = staticType->getProperty(cx, id, false);
if (!propertyTypes)
return false;
}
if (propertyTypes && propertyTypes->isOwnProperty(cx, globalType, true)) {
if (propertyTypes && propertyTypes->isOwnProperty(cx, staticType, true)) {
// The property has been reconfigured as non-configurable, non-enumerable
// or non-writable.
return jsop_getname(name);
}
types::StackTypeSet *types = types::TypeScript::BytecodeTypes(script(), pc);
bool barrier = PropertyReadNeedsTypeBarrier(cx, globalType, name, types);
bool barrier = PropertyReadNeedsTypeBarrier(cx, staticType, name, types);
// If the property is permanent, a shape guard isn't necessary.
@ -5948,7 +5955,7 @@ IonBuilder::jsop_getgname(HandlePropertyName name)
if (singleton) {
// Try to inline a known constant value.
bool isKnownConstant;
if (!TestSingletonProperty(cx, globalObj, singleton, id, &isKnownConstant))
if (!TestSingletonProperty(cx, staticObject, singleton, id, &isKnownConstant))
return false;
if (isKnownConstant)
return pushConstant(ObjectValue(*singleton));
@ -5959,27 +5966,19 @@ IonBuilder::jsop_getgname(HandlePropertyName name)
return pushConstant(NullValue());
}
MInstruction *global = MConstant::New(ObjectValue(*globalObj));
current->add(global);
MInstruction *obj = MConstant::New(ObjectValue(*staticObject));
current->add(obj);
// If we have a property typeset, the isOwnProperty call will trigger recompilation if
// the property is deleted or reconfigured.
if (!propertyTypes && shape->configurable())
global = addShapeGuard(global, globalObj->lastProperty(), Bailout_ShapeGuard);
obj = addShapeGuard(obj, staticObject->lastProperty(), Bailout_ShapeGuard);
JS_ASSERT(shape->slot() >= globalObj->numFixedSlots());
MIRType rvalType = MIRTypeFromValueType(types->getKnownTypeTag());
if (barrier)
rvalType = MIRType_Value;
MSlots *slots = MSlots::New(global);
current->add(slots);
MLoadSlot *load = MLoadSlot::New(slots, shape->slot() - globalObj->numFixedSlots());
current->add(load);
// Slot loads can be typed, if they have a single, known, definitive type.
if (knownType != JSVAL_TYPE_UNKNOWN && !barrier)
load->setResultType(MIRTypeFromValueType(knownType));
current->push(load);
return pushTypeBarrier(load, types, barrier);
return loadSlot(obj, shape, rvalType, barrier, types);
}
// Whether 'types' includes all possible values represented by input/inputTypes.
@ -6016,34 +6015,33 @@ ion::NeedsPostBarrier(CompileInfo &info, MDefinition *value)
}
bool
IonBuilder::jsop_setgname(HandlePropertyName name)
IonBuilder::setStaticName(HandleObject staticObject, HandlePropertyName name)
{
RootedObject globalObj(cx, &script()->global());
RootedId id(cx, NameToId(name));
JS_ASSERT(globalObj->isNative());
JS_ASSERT(staticObject->isGlobal() || staticObject->isCall());
MDefinition *value = current->peek(-1);
if (globalObj->watched())
if (staticObject->watched())
return jsop_setprop(name);
// For the fastest path, the property must be found, and it must be found
// as a normal data property on exactly the global object.
RootedShape shape(cx, globalObj->nativeLookup(cx, id));
RootedShape shape(cx, staticObject->nativeLookup(cx, id));
if (!shape || !shape->hasDefaultSetter() || !shape->writable() || !shape->hasSlot())
return jsop_setprop(name);
types::TypeObject *globalType = globalObj->getType(cx);
if (!globalType)
types::TypeObject *staticType = staticObject->getType(cx);
if (!staticType)
return false;
types::HeapTypeSet *propertyTypes = NULL;
if (!globalType->unknownProperties()) {
propertyTypes = globalType->getProperty(cx, id, false);
if (!staticType->unknownProperties()) {
propertyTypes = staticType->getProperty(cx, id, false);
if (!propertyTypes)
return false;
}
if (!propertyTypes || propertyTypes->isOwnProperty(cx, globalType, true)) {
if (!propertyTypes || propertyTypes->isOwnProperty(cx, staticType, true)) {
// The property has been reconfigured as non-configurable, non-enumerable
// or non-writable.
return jsop_setprop(name);
@ -6051,48 +6049,36 @@ IonBuilder::jsop_setgname(HandlePropertyName name)
if (!TypeSetIncludes(propertyTypes, value->type(), value->resultTypeSet()))
return jsop_setprop(name);
MInstruction *global = MConstant::New(ObjectValue(*globalObj));
current->add(global);
current->pop();
// Pop the bound object on the stack.
MDefinition *obj = current->pop();
JS_ASSERT(&obj->toConstant()->value().toObject() == staticObject);
// If we have a property type set, the isOwnProperty call will trigger recompilation
// if the property is deleted or reconfigured. Without TI, we always need a shape guard
// to guard against the property being reconfigured as non-writable.
if (!propertyTypes)
global = addShapeGuard(global, globalObj->lastProperty(), Bailout_ShapeGuard);
JS_ASSERT(shape->slot() >= globalObj->numFixedSlots());
MSlots *slots = MSlots::New(global);
current->add(slots);
obj = addShapeGuard(obj, staticObject->lastProperty(), Bailout_ShapeGuard);
// Note: we do not use a post barrier when writing to the global object.
// Slots in the global object will be treated as roots during a minor GC.
current->pop();
MStoreSlot *store = MStoreSlot::New(slots, shape->slot() - globalObj->numFixedSlots(), value);
current->add(store);
// Determine whether write barrier is required.
if (!propertyTypes || propertyTypes->needsBarrier(cx))
store->setNeedsBarrier();
// Pop the global object pushed by bindgname.
DebugOnly<MDefinition *> pushedGlobal = current->pop();
JS_ASSERT(&pushedGlobal->toConstant()->value().toObject() == globalObj);
if (!staticObject->isGlobal() && NeedsPostBarrier(info(), value))
current->add(MPostWriteBarrier::New(obj, value));
// If the property has a known type, we may be able to optimize typed stores by not
// storing the type tag. This only works if the property does not have its initial
// |undefined| value; if |undefined| is assigned at a later point, it will be added
// to the type set.
if (propertyTypes && !globalObj->getSlot(shape->slot()).isUndefined()) {
MIRType slotType = MIRType_None;
if (propertyTypes && !staticObject->getSlot(shape->slot()).isUndefined()) {
JSValueType knownType = propertyTypes->getKnownTypeTag(cx);
if (knownType != JSVAL_TYPE_UNKNOWN)
store->setSlotType(MIRTypeFromValueType(knownType));
slotType = MIRTypeFromValueType(knownType);
}
JS_ASSERT_IF(store->needsBarrier(), store->slotType() != MIRType_None);
current->push(value);
return resumeAfter(store);
bool needsBarrier = !propertyTypes || propertyTypes->needsBarrier(cx);
return storeSlot(obj, shape, value, needsBarrier, slotType);
}
bool
@ -7018,6 +7004,14 @@ GetDefiniteSlot(JSContext *cx, types::StackTypeSet *types, JSAtom *atom)
return propertyTypes;
}
bool
IonBuilder::jsop_runonce()
{
MRunOncePrologue *ins = MRunOncePrologue::New();
current->add(ins);
return resumeAfter(ins);
}
bool
IonBuilder::jsop_not()
{
@ -7364,7 +7358,8 @@ IonBuilder::loadSlot(MDefinition *obj, Shape *shape, MIRType rvalType,
}
bool
IonBuilder::storeSlot(MDefinition *obj, Shape *shape, MDefinition *value, bool needsBarrier)
IonBuilder::storeSlot(MDefinition *obj, Shape *shape, MDefinition *value, bool needsBarrier,
MIRType slotType /* = MIRType_None */)
{
JS_ASSERT(shape->hasDefaultSetter());
JS_ASSERT(shape->writable());
@ -7387,6 +7382,8 @@ IonBuilder::storeSlot(MDefinition *obj, Shape *shape, MDefinition *value, bool n
current->push(value);
if (needsBarrier)
store->setNeedsBarrier();
if (slotType != MIRType_None)
store->setSlotType(slotType);
return resumeAfter(store);
}
@ -8095,9 +8092,70 @@ IonBuilder::walkScopeChain(unsigned hops)
return scope;
}
bool
IonBuilder::hasStaticScopeObject(ScopeCoordinate sc, MutableHandleObject pcall)
{
JSScript *outerScript = ScopeCoordinateFunctionScript(cx, script(), pc);
if (!outerScript || !outerScript->treatAsRunOnce)
return false;
types::TypeObject *funType = outerScript->function()->getType(cx);
if (!funType)
return false;
if (types::HeapTypeSet::HasObjectFlags(cx, funType, types::OBJECT_FLAG_RUNONCE_INVALIDATED))
return false;
// The script this aliased var operation is accessing will run only once,
// so there will be only one call object and the aliased var access can be
// compiled in the same manner as a global access. We still need to find
// the call object though.
// Look for the call object on the current script's function's scope chain.
// If the current script is inner to the outer script and the function has
// singleton type then it should show up here.
MDefinition *scope = current->getSlot(info().scopeChainSlot());
scope->setFoldedUnchecked();
JSObject *environment = script()->function()->environment();
while (environment && !environment->isGlobal()) {
if (environment->isCall() &&
!environment->asCall().isForEval() &&
environment->asCall().callee().nonLazyScript() == outerScript)
{
JS_ASSERT(environment->hasSingletonType());
pcall.set(environment);
return true;
}
environment = environment->enclosingScope();
}
// Look for the call object on the current frame, if we are compiling the
// outer script itself. Don't do this if we are at entry to the outer
// script, as the call object we see will not be the real one --- after
// entering the Ion code a different call object will be created.
if (script() == outerScript && fp && info().osrPc()) {
JSObject *scope = fp.scopeChain();
if (scope->isCall() && scope->asCall().callee().nonLazyScript() == outerScript) {
JS_ASSERT(scope->hasSingletonType());
pcall.set(scope);
return true;
}
}
return true;
}
bool
IonBuilder::jsop_getaliasedvar(ScopeCoordinate sc)
{
RootedObject call(cx);
if (hasStaticScopeObject(sc, &call) && call) {
RootedPropertyName name(cx, ScopeCoordinateName(cx, script(), pc));
return getStaticName(call, name);
}
MDefinition *obj = walkScopeChain(sc.hops);
RootedShape shape(cx, ScopeCoordinateToStaticScopeShape(cx, script(), pc));
@ -8122,6 +8180,34 @@ IonBuilder::jsop_getaliasedvar(ScopeCoordinate sc)
bool
IonBuilder::jsop_setaliasedvar(ScopeCoordinate sc)
{
RootedObject call(cx);
if (hasStaticScopeObject(sc, &call)) {
uint32_t depth = current->stackDepth() + 1;
if (depth > current->nslots()) {
if (!current->increaseSlots(depth - current->nslots()))
return false;
}
MDefinition *value = current->pop();
RootedPropertyName name(cx, ScopeCoordinateName(cx, script(), pc));
if (call) {
// Push the object on the stack to match the bound object expected in
// the global and property set cases.
MInstruction *constant = MConstant::New(ObjectValue(*call));
current->add(constant);
current->push(constant);
current->push(value);
return setStaticName(call, name);
}
// The call object has type information we need to respect but we
// couldn't find it. Just do a normal property assign.
MDefinition *obj = walkScopeChain(sc.hops);
current->push(obj);
current->push(value);
return jsop_setprop(name);
}
MDefinition *rval = current->peek(-1);
MDefinition *obj = walkScopeChain(sc.hops);

Some files were not shown because too many files have changed in this diff Show More