merge mozilla-inbound to mozilla-central a=merge

This commit is contained in:
Carsten "Tomcat" Book 2016-02-11 11:52:01 +01:00
commit d80c849001
226 changed files with 3209 additions and 1358 deletions

View File

@ -99,7 +99,7 @@
////////////////////////////////////////////////////////////////////////////
// Testing
//gA11yEventDumpToConsole = true; // debug
gA11yEventDumpToConsole = true; // debug
var gQueue = null;
function doTests()
@ -107,7 +107,7 @@
testRelation(browserDocument(), RELATION_EMBEDS,
getAccessible(currentTabDocument()));
//enableLogging("docload");
enableLogging("docload");
gQueue = new eventQueue();
gQueue.push(new loadURI("about:about"));
@ -115,7 +115,7 @@
gQueue.onFinish = function()
{
//disableLogging();
disableLogging();
closeBrowserWindow();
}
gQueue.invoke();

View File

@ -7,10 +7,11 @@
"unpack": true
},
{
"size": 12057960,
"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e",
"size": 12072532,
"digest": "3915f8ec396c56a8a92e6f9695b70f09ce9d1582359d1258e37e3fd43a143bc974410e4cfc27f500e095f34a8956206e0ebf799b7287f0f38def0d5e34ed71c9",
"algorithm": "sha512",
"filename": "gtk3.tar.xz",
"setup": "setup.sh",
"unpack": true
}
]

View File

@ -7,10 +7,11 @@
"unpack": true
},
{
"size": 12057960,
"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e",
"size": 12072532,
"digest": "3915f8ec396c56a8a92e6f9695b70f09ce9d1582359d1258e37e3fd43a143bc974410e4cfc27f500e095f34a8956206e0ebf799b7287f0f38def0d5e34ed71c9",
"algorithm": "sha512",
"filename": "gtk3.tar.xz",
"setup": "setup.sh",
"unpack": true
}
]

View File

@ -7,10 +7,11 @@
"unpack": true
},
{
"size": 12057960,
"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e",
"size": 12072532,
"digest": "3915f8ec396c56a8a92e6f9695b70f09ce9d1582359d1258e37e3fd43a143bc974410e4cfc27f500e095f34a8956206e0ebf799b7287f0f38def0d5e34ed71c9",
"algorithm": "sha512",
"filename": "gtk3.tar.xz",
"setup": "setup.sh",
"unpack": true
}
]

View File

@ -7,10 +7,11 @@
"unpack": true
},
{
"size": 12057960,
"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e",
"size": 12072532,
"digest": "3915f8ec396c56a8a92e6f9695b70f09ce9d1582359d1258e37e3fd43a143bc974410e4cfc27f500e095f34a8956206e0ebf799b7287f0f38def0d5e34ed71c9",
"algorithm": "sha512",
"filename": "gtk3.tar.xz",
"setup": "setup.sh",
"unpack": true
}
]

View File

@ -7,10 +7,11 @@
"unpack": true
},
{
"size": 12057960,
"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e",
"size": 12072532,
"digest": "3915f8ec396c56a8a92e6f9695b70f09ce9d1582359d1258e37e3fd43a143bc974410e4cfc27f500e095f34a8956206e0ebf799b7287f0f38def0d5e34ed71c9",
"algorithm": "sha512",
"filename": "gtk3.tar.xz",
"setup": "setup.sh",
"unpack": true
}
]

View File

@ -7,10 +7,11 @@
"unpack": true
},
{
"size": 12057960,
"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e",
"size": 12072532,
"digest": "3915f8ec396c56a8a92e6f9695b70f09ce9d1582359d1258e37e3fd43a143bc974410e4cfc27f500e095f34a8956206e0ebf799b7287f0f38def0d5e34ed71c9",
"algorithm": "sha512",
"filename": "gtk3.tar.xz",
"setup": "setup.sh",
"unpack": true
}
]

View File

@ -7,10 +7,11 @@
"unpack": true
},
{
"size": 12057960,
"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e",
"size": 12072532,
"digest": "3915f8ec396c56a8a92e6f9695b70f09ce9d1582359d1258e37e3fd43a143bc974410e4cfc27f500e095f34a8956206e0ebf799b7287f0f38def0d5e34ed71c9",
"algorithm": "sha512",
"filename": "gtk3.tar.xz",
"setup": "setup.sh",
"unpack": true
}
]

View File

@ -7,8 +7,8 @@
"unpack": true
},
{
"size": 11179576,
"digest": "91567ce8e2bb8ab0ebc60c31e90731d88a1ea889fb71bcf55c735746a60fa7610b7e040ea3d8f727b6f692ae3ee703d6f3b30cdbd76fdf5617f77d9c38aa20ed",
"size": 11189216,
"digest": "18bc52b0599b1308b667e282abb45f47597bfc98a5140cfcab8da71dacf89dd76d0dee22a04ce26fe7ad1f04e2d6596991f9e5b01fd2aaaab5542965f596b0e6",
"algorithm": "sha512",
"filename": "gtk3.tar.xz",
"setup": "setup.sh",

View File

@ -7,8 +7,8 @@
"unpack": true
},
{
"size": 12057960,
"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e",
"size": 12072532,
"digest": "3915f8ec396c56a8a92e6f9695b70f09ce9d1582359d1258e37e3fd43a143bc974410e4cfc27f500e095f34a8956206e0ebf799b7287f0f38def0d5e34ed71c9",
"algorithm": "sha512",
"filename": "gtk3.tar.xz",
"setup": "setup.sh",

View File

@ -30,9 +30,6 @@ pref("network.predictor.enabled", true);
// No AccessibleCaret
pref("layout.accessiblecaret.enabled", false);
pref("gfx.vsync.hw-vsync.enabled", true);
pref("gfx.vsync.compositor", true);
// To be removed once bug 942756 is fixed.
pref("devtools.debugger.unix-domain-socket", "6000");

View File

@ -62,6 +62,12 @@ pref("extensions.blocklist.url", "https://blocklist.addons.mozilla.org/blocklist
pref("extensions.blocklist.detailsURL", "https://www.mozilla.org/%LOCALE%/blocklist/");
pref("extensions.blocklist.itemURL", "https://blocklist.addons.mozilla.org/%LOCALE%/%APP%/blocked/%blockID%");
// Kinto blocklist preferences
pref("services.kinto.base", "https://firefox.settings.services.mozilla.com/v1");
pref("services.kinto.bucket", "blocklists");
pref("services.kinto.onecrl.collection", "certificates");
pref("services.kinto.onecrl.checked", 0);
pref("extensions.update.autoUpdateDefault", true);
pref("extensions.hotfix.id", "firefox-hotfix@mozilla.org");

View File

@ -11,4 +11,5 @@ ac_add_options --enable-verify-mar
mk_add_options MOZ_PGO=1
. "$topsrcdir/build/mozconfig.rust"
. "$topsrcdir/build/mozconfig.common.override"

View File

@ -18,4 +18,5 @@ mk_add_options MOZ_PGO=1
# defines.sh during the beta cycle
export BUILDING_RELEASE=1
. "$topsrcdir/build/mozconfig.rust"
. "$topsrcdir/build/mozconfig.common.override"

View File

@ -10,5 +10,6 @@ fi
ac_add_options --enable-official-branding
ac_add_options --enable-verify-mar
. "$topsrcdir/build/mozconfig.rust"
. "$topsrcdir/build/mozconfig.common.override"
. "$topsrcdir/build/mozconfig.cache"

View File

@ -16,5 +16,6 @@ ac_add_options --enable-verify-mar
# defines.sh during the beta cycle
export BUILDING_RELEASE=1
. "$topsrcdir/build/mozconfig.rust"
. "$topsrcdir/build/mozconfig.common.override"
. "$topsrcdir/build/mozconfig.cache"

View File

@ -40,7 +40,6 @@ whitelist['nightly']['linux64'] += [
'STRIP_FLAGS="--strip-debug"',
'ac_add_options --with-ccache=/usr/bin/ccache',
'. "$topsrcdir/build/mozconfig.cache"',
'. "$topsrcdir/build/mozconfig.rust"',
]
whitelist['nightly']['macosx-universal'] += [
@ -53,7 +52,6 @@ whitelist['nightly']['macosx-universal'] += [
'ac_add_options --disable-install-strip',
'ac_add_options --enable-instruments',
'ac_add_options --enable-dtrace',
'. "$topsrcdir/build/mozconfig.rust"',
]
whitelist['nightly']['win32'] += [

View File

@ -7,10 +7,11 @@
"unpack": true
},
{
"size": 11179576,
"digest": "91567ce8e2bb8ab0ebc60c31e90731d88a1ea889fb71bcf55c735746a60fa7610b7e040ea3d8f727b6f692ae3ee703d6f3b30cdbd76fdf5617f77d9c38aa20ed",
"size": 11189216,
"digest": "18bc52b0599b1308b667e282abb45f47597bfc98a5140cfcab8da71dacf89dd76d0dee22a04ce26fe7ad1f04e2d6596991f9e5b01fd2aaaab5542965f596b0e6",
"algorithm": "sha512",
"filename": "gtk3.tar.xz",
"setup": "setup.sh",
"unpack": true
},
{

View File

@ -10,8 +10,8 @@
"unpack": true
},
{
"size": 12057960,
"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e",
"size": 12072532,
"digest": "3915f8ec396c56a8a92e6f9695b70f09ce9d1582359d1258e37e3fd43a143bc974410e4cfc27f500e095f34a8956206e0ebf799b7287f0f38def0d5e34ed71c9",
"algorithm": "sha512",
"filename": "gtk3.tar.xz",
"setup": "setup.sh",

View File

@ -10,10 +10,11 @@
"unpack": true
},
{
"size": 12057960,
"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e",
"size": 12072532,
"digest": "3915f8ec396c56a8a92e6f9695b70f09ce9d1582359d1258e37e3fd43a143bc974410e4cfc27f500e095f34a8956206e0ebf799b7287f0f38def0d5e34ed71c9",
"algorithm": "sha512",
"filename": "gtk3.tar.xz",
"setup": "setup.sh",
"unpack": true
},
{

View File

@ -10,10 +10,11 @@
"unpack": true
},
{
"size": 12057960,
"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e",
"size": 12072532,
"digest": "3915f8ec396c56a8a92e6f9695b70f09ce9d1582359d1258e37e3fd43a143bc974410e4cfc27f500e095f34a8956206e0ebf799b7287f0f38def0d5e34ed71c9",
"algorithm": "sha512",
"filename": "gtk3.tar.xz",
"setup": "setup.sh",
"unpack": true
}
]

View File

@ -7,10 +7,11 @@
"unpack": true
},
{
"size": 12057960,
"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e",
"size": 12072532,
"digest": "3915f8ec396c56a8a92e6f9695b70f09ce9d1582359d1258e37e3fd43a143bc974410e4cfc27f500e095f34a8956206e0ebf799b7287f0f38def0d5e34ed71c9",
"algorithm": "sha512",
"filename": "gtk3.tar.xz",
"setup": "setup.sh",
"unpack": true
},
{

View File

@ -10,10 +10,11 @@
"unpack": true
},
{
"size": 12057960,
"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e",
"size": 12072532,
"digest": "3915f8ec396c56a8a92e6f9695b70f09ce9d1582359d1258e37e3fd43a143bc974410e4cfc27f500e095f34a8956206e0ebf799b7287f0f38def0d5e34ed71c9",
"algorithm": "sha512",
"filename": "gtk3.tar.xz",
"setup": "setup.sh",
"unpack": true
}
]

View File

@ -5,10 +5,13 @@
from __future__ import print_function, unicode_literals
import errno
import json
import os
import platform
import random
import sys
import time
import uuid
import __builtin__
from types import ModuleType
@ -67,6 +70,7 @@ SEARCH_PATHS = [
'config',
'dom/bindings',
'dom/bindings/parser',
'dom/media/test/external',
'layout/tools/reftest',
'other-licenses/ply',
'testing',
@ -109,6 +113,7 @@ MACH_MODULES = [
'addon-sdk/mach_commands.py',
'build/valgrind/mach_commands.py',
'dom/bindings/mach_commands.py',
'dom/media/test/external/mach_commands.py',
'layout/tools/reftest/mach_commands.py',
'python/mach_commands.py',
'python/mach/mach/commands/commandinfo.py',
@ -181,6 +186,14 @@ CATEGORIES = {
}
# Server to which to submit telemetry data
BUILD_TELEMETRY_SERVER = 'http://52.88.27.118/build-metrics-dev'
# We submit data to telemetry approximately every this many mach invocations
TELEMETRY_SUBMISSION_FREQUENCY = 10
def get_state_dir():
"""Obtain the path to a directory to hold state.
@ -222,6 +235,47 @@ def bootstrap(topsrcdir, mozilla_dir=None):
sys.path[0:0] = [os.path.join(mozilla_dir, path) for path in SEARCH_PATHS]
import mach.main
def telemetry_handler(context, data):
# We have not opted-in to telemetry
if 'BUILD_SYSTEM_TELEMETRY' not in os.environ:
return
telemetry_dir = os.path.join(get_state_dir()[0], 'telemetry')
try:
os.mkdir(telemetry_dir)
except OSError as e:
if e.errno != errno.EEXIST:
raise
outgoing_dir = os.path.join(telemetry_dir, 'outgoing')
try:
os.mkdir(outgoing_dir)
except OSError as e:
if e.errno != errno.EEXIST:
raise
# Add common metadata to help submit sorted data later on.
# For now, we'll just record the mach command that was invoked.
data['argv'] = sys.argv
with open(os.path.join(outgoing_dir, str(uuid.uuid4()) + '.json'),
'w') as f:
json.dump(data, f, sort_keys=True)
def should_skip_dispatch(context, handler):
# The user is performing a maintenance command.
if handler.name in ('bootstrap', 'doctor', 'mach-commands', 'mercurial-setup'):
return True
# We are running in automation.
if 'MOZ_AUTOMATION' in os.environ or 'TASK_ID' in os.environ:
return True
# The environment is likely a machine invocation.
if sys.stdin.closed or not sys.stdin.isatty():
return True
return False
def pre_dispatch_handler(context, handler, args):
"""Perform global checks before command dispatch.
@ -230,13 +284,7 @@ def bootstrap(topsrcdir, mozilla_dir=None):
tools are up to date.
"""
# Don't do anything when...
# The user is performing a maintenance command.
if handler.name in ('bootstrap', 'doctor', 'mach-commands', 'mercurial-setup'):
return
# We are running in automation.
if 'MOZ_AUTOMATION' in os.environ or 'TASK_ID' in os.environ:
if should_skip_dispatch(context, handler):
return
# User has disabled first run check.
@ -245,10 +293,6 @@ def bootstrap(topsrcdir, mozilla_dir=None):
if 'NO_MERCURIAL_SETUP_CHECK' in os.environ:
return
# The environment is likely a machine invocation.
if sys.stdin.closed or not sys.stdin.isatty():
return
# Mercurial isn't managing this source checkout.
if not os.path.exists(os.path.join(topsrcdir, '.hg')):
return
@ -269,6 +313,68 @@ def bootstrap(topsrcdir, mozilla_dir=None):
print(NO_MERCURIAL_SETUP.format(mach=sys.argv[0]), file=sys.stderr)
sys.exit(2)
def post_dispatch_handler(context, handler, args):
"""Perform global operations after command dispatch.
For now, we will use this to handle build system telemetry.
"""
# Don't do anything when...
if should_skip_dispatch(context, handler):
return
# We have not opted-in to telemetry
if 'BUILD_SYSTEM_TELEMETRY' not in os.environ:
return
# Every n-th operation
if random.randint(1, TELEMETRY_SUBMISSION_FREQUENCY) != 1:
return
# No data to work with anyway
outgoing = os.path.join(get_state_dir()[0], 'telemetry', 'outgoing')
if not os.path.isdir(outgoing):
return
# We can't import requests until after it has been added during the
# bootstrapping below.
import requests
submitted = os.path.join(get_state_dir()[0], 'telemetry', 'submitted')
try:
os.mkdir(submitted)
except OSError as e:
if e.errno != errno.EEXIST:
raise
session = requests.Session()
for filename in os.listdir(outgoing):
path = os.path.join(outgoing, filename)
if os.path.isdir(path) or not path.endswith('.json'):
continue
with open(path, 'r') as f:
data = f.read()
r = session.post(BUILD_TELEMETRY_SERVER, data=data,
headers={'Content-Type': 'application/json'})
# TODO: some of these errors are likely not recoverable, as
# written, we'll retry indefinitely
if r.status_code != 200:
print('Error posting to telemetry: %s %s' %
(r.status_code, r.text))
continue
os.rename(os.path.join(outgoing, filename),
os.path.join(submitted, filename))
session.close()
# Discard submitted data that is >= 30 days old
now = time.time()
for filename in os.listdir(submitted):
ctime = os.stat(os.path.join(submitted, filename)).st_ctime
if now - ctime >= 60*60*24*30:
os.remove(os.path.join(submitted, filename))
def populate_context(context, key=None):
if key is None:
return
@ -305,6 +411,12 @@ def bootstrap(topsrcdir, mozilla_dir=None):
if key == 'pre_dispatch_handler':
return pre_dispatch_handler
if key == 'telemetry_handler':
return telemetry_handler
if key == 'post_dispatch_handler':
return post_dispatch_handler
raise AttributeError(key)
mach = mach.main.Mach(os.getcwd())

View File

@ -13,7 +13,7 @@ import subprocess
import sys
from automation import Automation
from devicemanager import DMError, DeviceManager
from mozdevice import DMError, DeviceManager
from mozlog import get_default_logger
import mozcrash

View File

@ -118,18 +118,20 @@ cat <<EOF > $root_dir/gtk3/setup.sh
#!/bin/sh
cd \$(dirname \$0)
HERE=\$(pwd)
# pango expects absolute paths in pango.modules, and TOOLTOOL_DIR may vary...
LD_LIBRARY_PATH=./usr/local/lib \
PANGO_SYSCONFDIR=./usr/local/etc \
PANGO_LIBDIR=./usr/local/lib \
./usr/local/bin/pango-querymodules > ./usr/local/etc/pango/pango.modules
LD_LIBRARY_PATH=\$HERE/usr/local/lib \
PANGO_SYSCONFDIR=\$HERE/usr/local/etc \
PANGO_LIBDIR=\$HERE/usr/local/lib \
\$HERE/usr/local/bin/pango-querymodules > \$HERE/usr/local/etc/pango/pango.modules
# same with gdb-pixbuf and loaders.cache
LD_LIBRARY_PATH=./usr/local/lib \
GDK_PIXBUF_MODULE_FILE=./usr/local/lib/gdk-pixbuf-2.0/2.10.0/loaders.cache \
GDK_PIXBUF_MODULEDIR=./usr/local/lib/gdk-pixbuf-2.0/2.10.0/loaders \
./usr/local/bin/gdk-pixbuf-query-loaders > ./usr/local/lib/gdk-pixbuf-2.0/2.10.0/loaders.cache
LD_LIBRARY_PATH=\$HERE/usr/local/lib \
GDK_PIXBUF_MODULE_FILE=\$HERE/usr/local/lib/gdk-pixbuf-2.0/2.10.0/loaders.cache \
GDK_PIXBUF_MODULEDIR=\$HERE/usr/local/lib/gdk-pixbuf-2.0/2.10.0/loaders \
\$HERE/usr/local/bin/gdk-pixbuf-query-loaders > \
\$HERE/usr/local/lib/gdk-pixbuf-2.0/2.10.0/loaders.cache
# The fontconfig version in the tooltool package has known uses of
# uninitialized memory when creating its cache, and while most users
@ -137,7 +139,9 @@ GDK_PIXBUF_MODULEDIR=./usr/local/lib/gdk-pixbuf-2.0/2.10.0/loaders \
# will create it. Combined with valgrind, this generates irrelevant
# errors.
# So create the fontconfig cache beforehand.
./usr/local/bin/fc-cache
FONTCONFIG_PATH=\$HERE/usr/local/etc/fonts \
LD_LIBRARY_PATH=\$HERE/usr/local/lib \
\$HERE/usr/local/bin/fc-cache
EOF
chmod +x $root_dir/gtk3/setup.sh

View File

@ -24,6 +24,3 @@ mk_add_options "export PANGO_LIBDIR=$TOOLTOOL_DIR/gtk3/usr/local/lib"
mk_add_options "export GDK_PIXBUF_MODULE_FILE=$TOOLTOOL_DIR/gtk3/usr/local/lib/gdk-pixbuf-2.0/2.10.0/loaders.cache"
mk_add_options "export GDK_PIXBUF_MODULEDIR=$TOOLTOOL_DIR/gtk3/usr/local/lib/gdk-pixbuf-2.0/2.10.0/loaders"
mk_add_options "export LD_LIBRARY_PATH=$TOOLTOOL_DIR/gtk3/usr/local/lib"
# Until a tooltool with bug 1188571 landed is available everywhere
$TOOLTOOL_DIR/gtk3/setup.sh

View File

@ -41,6 +41,8 @@ reAfterArg = "(?=[,)])"
reMatchArg = re.compile(reBeforeArg + reArgType + reArgName + reArgDefault + reAfterArg)
def get_normalized_signatures(signature, fileAnnot = None):
# Remove static
signature = signature.replace('static', '')
# Remove semicolon.
signature = signature.replace(';', ' ')
# Normalize spaces.

View File

@ -226,7 +226,7 @@ this.AppsUtils = {
deferred.resolve(file);
}
});
aRequestChannel.asyncOpen(listener, null);
aRequestChannel.asyncOpen2(listener);
return deferred.promise;
},

View File

@ -3490,21 +3490,15 @@ this.DOMApplicationRegistry = {
let requestChannel;
let appURI = NetUtil.newURI(aNewApp.origin, null, null);
let principal =
Services.scriptSecurityManager.createCodebasePrincipal(appURI,
{appId: aNewApp.localId});
if (aIsLocalFileInstall) {
requestChannel = NetUtil.newChannel({
uri: aFullPackagePath,
loadingPrincipal: principal,
contentPolicyType: Ci.nsIContentPolicy.TYPE_OTHER}
loadUsingSystemPrincipal: true}
).QueryInterface(Ci.nsIFileChannel);
} else {
requestChannel = NetUtil.newChannel({
uri: aFullPackagePath,
loadingPrincipal: principal,
contentPolicyType: Ci.nsIContentPolicy.TYPE_OTHER}
loadUsingSystemPrincipal: true}
).QueryInterface(Ci.nsIHttpChannel);
requestChannel.loadFlags |= Ci.nsIRequest.INHIBIT_CACHING;
}

View File

@ -219,7 +219,7 @@ ShadowRoot::RemoveFromIdTable(Element* aElement, nsIAtom* aId)
if (entry) {
entry->RemoveIdElement(aElement);
if (entry->IsEmpty()) {
mIdentifierMap.RawRemoveEntry(entry);
mIdentifierMap.RemoveEntry(entry);
}
}
}

View File

@ -7270,13 +7270,13 @@ nsContentUtils::GetInnerWindowID(nsIRequest* aRequest)
return inner ? inner->WindowID() : 0;
}
void
nsresult
nsContentUtils::GetHostOrIPv6WithBrackets(nsIURI* aURI, nsCString& aHost)
{
aHost.Truncate();
nsresult rv = aURI->GetHost(aHost);
if (NS_FAILED(rv)) { // Some URIs do not have a host
return;
return rv;
}
if (aHost.FindChar(':') != -1) { // Escape IPv6 address
@ -7285,14 +7285,20 @@ nsContentUtils::GetHostOrIPv6WithBrackets(nsIURI* aURI, nsCString& aHost)
aHost.Insert('[', 0);
aHost.Append(']');
}
return NS_OK;
}
void
nsresult
nsContentUtils::GetHostOrIPv6WithBrackets(nsIURI* aURI, nsAString& aHost)
{
nsAutoCString hostname;
GetHostOrIPv6WithBrackets(aURI, hostname);
nsresult rv = GetHostOrIPv6WithBrackets(aURI, hostname);
if (NS_FAILED(rv)) {
return rv;
}
CopyUTF8toUTF16(hostname, aHost);
return NS_OK;
}
void

View File

@ -2402,8 +2402,8 @@ public:
* If the hostname for aURI is an IPv6 it encloses it in brackets,
* otherwise it just outputs the hostname in aHost.
*/
static void GetHostOrIPv6WithBrackets(nsIURI* aURI, nsAString& aHost);
static void GetHostOrIPv6WithBrackets(nsIURI* aURI, nsCString& aHost);
static nsresult GetHostOrIPv6WithBrackets(nsIURI* aURI, nsAString& aHost);
static nsresult GetHostOrIPv6WithBrackets(nsIURI* aURI, nsCString& aHost);
/*
* Call the given callback on all remote children of the given top-level

View File

@ -3003,7 +3003,7 @@ nsDocument::RemoveFromIdTable(Element *aElement, nsIAtom* aId)
++mExpandoAndGeneration.generation;
}
if (entry->IsEmpty()) {
mIdentifierMap.RawRemoveEntry(entry);
mIdentifierMap.RemoveEntry(entry);
}
}

View File

@ -1438,7 +1438,7 @@ nsHTMLCopyEncoder::SetSelection(nsISelection* aSelection)
mIsTextWidget = true;
break;
}
#ifdef MOZ_THUNDERBIRD
#if defined(MOZ_THUNDERBIRD) || defined(MOZ_SUITE)
else if (selContent->IsHTMLElement(nsGkAtoms::body)) {
// Currently, setting mIsTextWidget to 'true' will result in the selection
// being encoded/copied as pre-formatted plain text.

View File

@ -104,7 +104,6 @@ GK_ATOM(applet, "applet")
GK_ATOM(applyImports, "apply-imports")
GK_ATOM(applyTemplates, "apply-templates")
GK_ATOM(mozapptype, "mozapptype")
GK_ATOM(apz, "apz")
GK_ATOM(archive, "archive")
GK_ATOM(area, "area")
GK_ATOM(arrow, "arrow")
@ -2270,13 +2269,20 @@ GK_ATOM(SendMail, "SendMail")
GK_ATOM(ForwardMail, "ForwardMail")
GK_ATOM(ReplyToMail, "ReplyToMail")
// Smooth scroll events origins
// Scroll origins (these are used in various scrolling functions in
// nsIScrollableFrame and ScrollFrameHelper). These are divided into two lists
// - origins in the first one have smooth-scrolling prefs associated with them,
// under the "general.smoothScroll.<origin>.*" pref branch. Origins in the
// second one do not.
GK_ATOM(mouseWheel, "mouseWheel") // For discrete wheel events (e.g. not OSX magic mouse)
GK_ATOM(pixels, "pixels")
GK_ATOM(lines, "lines")
GK_ATOM(pages, "pages")
GK_ATOM(scrollbars, "scrollbars")
GK_ATOM(other, "other")
// Scroll origins without smooth-scrolling prefs
GK_ATOM(apz, "apz")
GK_ATOM(restore, "restore")
#ifdef ACCESSIBILITY
GK_ATOM(alert, "alert")

View File

@ -40,7 +40,7 @@ protected:
JS::MutableHandle<JS::Value> aVal);
bool StringifyToJSON(JSContext* aCx,
JS::MutableHandle<JS::Value> aValue,
JS::Handle<JSObject*> aObj,
nsAString& aJSON) const;
// Struct used as a way to force a dictionary constructor to not init the

View File

@ -45,8 +45,9 @@
#include "mozilla/dom/HTMLAppletElementBinding.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/ResolveSystemBinding.h"
#include "mozilla/dom/WorkerPrivate.h"
#include "mozilla/dom/WorkerScope.h"
#include "mozilla/jsipc/CrossProcessObjectWrappers.h"
#include "WorkerPrivate.h"
#include "nsDOMClassInfo.h"
#include "ipc/ErrorIPCUtils.h"
#include "mozilla/UseCounter.h"
@ -1867,11 +1868,10 @@ DictionaryBase::ParseJSON(JSContext* aCx,
bool
DictionaryBase::StringifyToJSON(JSContext* aCx,
JS::MutableHandle<JS::Value> aValue,
JS::Handle<JSObject*> aObj,
nsAString& aJSON) const
{
return JS_Stringify(aCx, aValue, nullptr, JS::NullHandleValue,
AppendJSONToString, &aJSON);
return JS::ToJSONMaybeSafely(aCx, aObj, AppendJSONToString, &aJSON);
}
/* static */
@ -3239,5 +3239,18 @@ DeprecationWarning(JSContext* aCx, JSObject* aObject,
}
}
namespace binding_detail {
JSObject*
UnprivilegedJunkScopeOrWorkerGlobal()
{
if (NS_IsMainThread()) {
return xpc::UnprivilegedJunkScope();
}
return workers::GetCurrentThreadWorkerPrivate()->
GlobalScope()->GetGlobalJSObject();
}
} // namespace binding_detail
} // namespace dom
} // namespace mozilla

View File

@ -3327,6 +3327,26 @@ DeprecationWarning(JSContext* aCx, JSObject* aObject,
JSString*
InterfaceObjectToString(JSContext* aCx, JS::Handle<JSObject*> aObject,
unsigned /* indent */);
namespace binding_detail {
// Get a JS global object that can be used for some temporary allocations. The
// idea is that this should be used for situations when you need to operate in
// _some_ compartment but don't care which one. A typical example is when you
// have non-JS input, non-JS output, but have to go through some sort of JS
// representation in the middle, so need a compartment to allocate things in.
//
// It's VERY important that any consumers of this function only do things that
// are guaranteed to be side-effect-free, even in the face of a script
// environment controlled by a hostile adversary. This is because in the worker
// case the global is in fact the worker global, so it and its standard objects
// are controlled by the worker script. This is why this function is in the
// binding_detail namespace. Any use of this function MUST be very carefully
// reviewed by someone who is sufficiently devious and has a very good
// understanding of all the code that will run while we're using the return
// value, including the SpiderMonkey parts.
JSObject* UnprivilegedJunkScopeOrWorkerGlobal();
} // namespace binding_detail
} // namespace dom
} // namespace mozilla

View File

@ -12257,13 +12257,21 @@ class CGDictionary(CGThing):
"ToJSON", "bool",
[Argument('nsAString&', 'aJSON')],
body=dedent("""
MOZ_ASSERT(NS_IsMainThread());
AutoJSAPI jsapi;
jsapi.Init();
JSContext *cx = jsapi.cx();
JSAutoCompartment ac(cx, xpc::UnprivilegedJunkScope()); // Usage approved by bholley
JS::Rooted<JS::Value> obj(cx);
return ToObjectInternal(cx, &obj) && StringifyToJSON(cx, &obj, aJSON);
// It's safe to use UnprivilegedJunkScopeOrWorkerGlobal here
// because we'll only be creating objects, in ways that have no
// side-effects, followed by a call to JS::ToJSONMaybeSafely,
// which likewise guarantees no side-effects for the sorts of
// things we will pass it.
JSAutoCompartment ac(cx, binding_detail::UnprivilegedJunkScopeOrWorkerGlobal());
JS::Rooted<JS::Value> val(cx);
if (!ToObjectInternal(cx, &val)) {
return false;
}
JS::Rooted<JSObject*> obj(cx, &val.toObject());
return StringifyToJSON(cx, obj, aJSON);
"""), const=True)
def toObjectInternalMethod(self):
@ -12403,7 +12411,8 @@ class CGDictionary(CGThing):
methods.append(self.initFromJSONMethod())
try:
methods.append(self.toObjectInternalMethod())
methods.append(self.toJSONMethod())
if self.dictionarySafeToJSONify(self.dictionary):
methods.append(self.toJSONMethod())
except MethodNotNewObjectError:
# If we can't have a ToObjectInternal() because one of our members
# can only be returned from [NewObject] methods, then just skip
@ -12710,6 +12719,52 @@ class CGDictionary(CGThing):
return False
return all(isTypeCopyConstructible(m.type) for m in dictionary.members)
@staticmethod
def typeSafeToJSONify(type):
"""
Determine whether the given type is safe to convert to JSON. The
restriction is that this needs to be safe while in a global controlled
by an adversary, and "safe" means no side-effects when the JS
representation of this type is converted to JSON. That means that we
have to be pretty restrictive about what things we can allow. For
example, "object" is out, because it may have accessor properties on it.
"""
if type.nullable():
# Converting null to JSON is always OK.
return CGDictionary.typeSafeToJSONify(type.inner)
if type.isSequence():
# Sequences are arrays we create ourselves, with no holes. They
# should be safe if their contents are safe, as long as we suppress
# invocation of .toJSON on objects.
return CGDictionary.typeSafeToJSONify(type.inner)
if type.isUnion():
# OK if everything in it is ok.
return all(CGDictionary.typeSafeToJSONify(t)
for t in type.flatMemberTypes)
if type.isDictionary():
# OK if the dictionary is OK
return CGDictionary.dictionarySafeToJSONify(type.inner)
if type.isString() or type.isEnum():
# Strings are always OK.
return True
if type.isPrimitive():
# Primitives (numbers and booleans) are ok, as long as
# they're not unrestricted float/double.
return not type.isFloat() or not type.isUnrestricted()
return False
@staticmethod
def dictionarySafeToJSONify(dictionary):
# The dictionary itself is OK, so we're good if all our types are.
return all(CGDictionary.typeSafeToJSONify(m.type)
for m in dictionary.members)
class CGRegisterWorkerBindings(CGAbstractMethod):
def __init__(self, config):
@ -13191,7 +13246,6 @@ class CGBindingRoot(CGThing):
bindingHeaders["WrapperFactory.h"] = descriptors
bindingHeaders["mozilla/dom/DOMJSClass.h"] = descriptors
bindingHeaders["mozilla/dom/ScriptSettings.h"] = dictionaries # AutoJSAPI
bindingHeaders["xpcpublic.h"] = dictionaries # xpc::UnprivilegedJunkScope
# Ensure we see our enums in the generated .cpp file, for the ToJSValue
# method body. Also ensure that we see jsapi.h.
if enums:
@ -15637,7 +15691,10 @@ class CGMaplikeOrSetlikeHelperFunctionGenerator(CallbackMember):
jsapi.Init();
jsapi.TakeOwnershipOfErrorReporting();
JSContext* cx = jsapi.cx();
JSAutoCompartment tempCompartment(cx, xpc::UnprivilegedJunkScope());
// It's safe to use UnprivilegedJunkScopeOrWorkerGlobal here because
// all we want is to wrap into _some_ scope and then unwrap to find
// the reflector, and wrapping has no side-effects.
JSAutoCompartment tempCompartment(cx, binding_detail::UnprivilegedJunkScopeOrWorkerGlobal());
JS::Rooted<JS::Value> v(cx);
if(!ToJSValue(cx, self, &v)) {
aRv.Throw(NS_ERROR_UNEXPECTED);

View File

@ -15,6 +15,7 @@ var Cr = Components.results;
*/
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/NetUtil.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/BrowserElementPromptService.jsm");
@ -1001,36 +1002,17 @@ BrowserElementParent.prototype = {
Ci.nsIRequestObserver])
};
// If we have a URI we'll use it to get the triggering principal to use,
// if not available a null principal is acceptable.
let referrer = null;
let principal = null;
if (_options.referrer) {
// newURI can throw on malformed URIs.
try {
referrer = Services.io.newURI(_options.referrer, null, null);
}
catch(e) {
debug('Malformed referrer -- ' + e);
}
let referrer = Services.io.newURI(_options.referrer, null, null);
let principal =
Services.scriptSecurityManager.createCodebasePrincipal(
referrer, this._frameLoader.loadContext.originAttributes);
// This simply returns null if there is no principal available
// for the requested uri. This is an acceptable fallback when
// calling newChannelFromURI2.
principal =
Services.scriptSecurityManager.createCodebasePrincipal(
referrer, this._frameLoader.loadContext.originAttributes);
}
debug('Using principal? ' + !!principal);
let channel =
Services.io.newChannelFromURI2(url,
null, // No document.
principal, // Loading principal
principal, // Triggering principal
Ci.nsILoadInfo.SEC_NORMAL,
Ci.nsIContentPolicy.TYPE_OTHER);
let channel = NetUtil.newChannel({
uri: url,
loadingPrincipal: principal,
securityFlags: SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS,
contentPolicyType: Ci.nsIContentPolicy.TYPE_OTHER
});
// XXX We would set private browsing information prior to calling this.
channel.notificationCallbacks = interfaceRequestor;
@ -1055,7 +1037,7 @@ BrowserElementParent.prototype = {
}
// Set-up complete, let's get things started.
channel.asyncOpen(new DownloadListener(), null);
channel.asyncOpen2(new DownloadListener());
return req;
},

View File

@ -48,6 +48,7 @@
#include "nsPIDOMWindow.h"
#include "nsSandboxFlags.h"
#include "xpcpublic.h"
#include "nsIFrame.h"
namespace mozilla {
@ -416,10 +417,7 @@ EventListenerManager::AddEventListenerInternal(
}
if (IsApzAwareEvent(aTypeAtom)) {
nsCOMPtr<nsINode> node = do_QueryInterface(mTarget);
if (node) {
node->SetMayHaveApzAwareListeners();
}
ProcessApzAwareEventListenerAdd();
}
if (aTypeAtom && mTarget) {
@ -432,6 +430,44 @@ EventListenerManager::AddEventListenerInternal(
}
}
void
EventListenerManager::ProcessApzAwareEventListenerAdd()
{
// Mark the node as having apz aware listeners
nsCOMPtr<nsINode> node = do_QueryInterface(mTarget);
if (node) {
node->SetMayHaveApzAwareListeners();
}
// Schedule a paint so event regions on the layer tree gets updated
nsIDocument* doc = nullptr;
if (node) {
doc = node->OwnerDoc();
}
if (!doc) {
if (nsCOMPtr<nsPIDOMWindowInner> window = GetTargetAsInnerWindow()) {
doc = window->GetExtantDoc();
}
}
if (!doc) {
if (nsCOMPtr<DOMEventTargetHelper> helper = do_QueryInterface(mTarget)) {
if (nsPIDOMWindowInner* window = helper->GetOwner()) {
doc = window->GetExtantDoc();
}
}
}
if (doc) {
nsIPresShell* ps = doc->GetShell();
if (ps) {
nsIFrame* f = ps->GetRootFrame();
if (f) {
f->SchedulePaint();
}
}
}
}
bool
EventListenerManager::IsDeviceType(EventMessage aEventMessage)
{

View File

@ -467,6 +467,8 @@ protected:
nsIDocShell* GetDocShellForTarget();
void ProcessApzAwareEventListenerAdd();
/**
* Compile the "inline" event listener for aListener. The
* body of the listener can be provided in aBody; if this is null we

View File

@ -187,7 +187,7 @@ function mpTestModernBeatsLegacy(eventInfo) {
// Test that an event which bubbles may fire listeners of different flavors
// (modern vs. legacy) at each bubbling level, depending on what's registered
// at that level.
function mpTestAncestorsWithDiffListeners(eventInfo) {
function mpTestDiffListenersEventBubbling(eventInfo) {
return new Promise(
function(resolve, reject) {
var grandparent = createChildDiv();
@ -198,35 +198,81 @@ function mpTestAncestorsWithDiffListeners(eventInfo) {
var eventSentToTarget;
target.addEventListener(eventInfo.modern_name,
createHandlerWithTypeCheck(eventInfo.modern_name,
function(e) {
ok(e.bubbles, "Expecting event to bubble");
eventSentToTarget = e;
didEventFireOnTarget = true;
}));
createHandlerWithTypeCheck(eventInfo.modern_name, function(e) {
ok(e.bubbles, "Expecting event to bubble");
eventSentToTarget = e;
didEventFireOnTarget = true;
}));
parent.addEventListener(eventInfo.legacy_name,
createHandlerWithTypeCheck(eventInfo.legacy_name,
function(e) {
is(e, eventSentToTarget,
"Same event object should bubble, " +
"despite difference in type");
didEventFireOnParent = true;
}));
createHandlerWithTypeCheck(eventInfo.legacy_name, function(e) {
is(e, eventSentToTarget,
"Same event object should bubble, despite difference in type");
didEventFireOnParent = true;
}));
grandparent.addEventListener(eventInfo.modern_name,
createHandlerWithTypeCheck(eventInfo.modern_name,
function(e) {
ok(didEventFireOnTarget,
"Event should have fired on child");
ok(didEventFireOnParent,
"Event should have fired on parent");
is(e, eventSentToTarget,
"Same event object should bubble, " +
"despite difference in type");
parent.removeChild(target);
resolve();
}));
createHandlerWithTypeCheck(eventInfo.modern_name, function(e) {
ok(didEventFireOnTarget,
"Event should have fired on child");
ok(didEventFireOnParent,
"Event should have fired on parent");
is(e, eventSentToTarget,
"Same event object should bubble, despite difference in type");
// Clean up.
grandparent.parentNode.removeChild(grandparent);
resolve();
}));
eventInfo.trigger_event(target);
}
);
}
// Test that an event in the capture phase may fire listeners of different
// flavors (modern vs. legacy) at each level, depending on what's registered
// at that level.
function mpTestDiffListenersEventCapturing(eventInfo) {
return new Promise(
function(resolve, reject) {
var grandparent = createChildDiv();
var parent = createChildDiv(grandparent);
var target = createChildDiv(parent);
var didEventFireOnTarget = false;
var didEventFireOnParent = false;
var didEventFireOnGrandparent = false;
var eventSentToGrandparent;
grandparent.addEventListener(eventInfo.modern_name,
createHandlerWithTypeCheck(eventInfo.modern_name, function(e) {
eventSentToGrandparent = e;
didEventFireOnGrandparent = true;
}), true);
parent.addEventListener(eventInfo.legacy_name,
createHandlerWithTypeCheck(eventInfo.legacy_name, function(e) {
is(e.eventPhase, Event.CAPTURING_PHASE,
"event should be in capturing phase");
is(e, eventSentToGrandparent,
"Same event object should capture, despite difference in type");
ok(didEventFireOnGrandparent,
"Event should have fired on grandparent");
didEventFireOnParent = true;
}), true);
target.addEventListener(eventInfo.modern_name,
createHandlerWithTypeCheck(eventInfo.modern_name, function(e) {
is(e.eventPhase, Event.AT_TARGET,
"event should be at target phase");
is(e, eventSentToGrandparent,
"Same event object should capture, despite difference in type");
ok(didEventFireOnParent,
"Event should have fired on parent");
// Clean up.
grandparent.parentNode.removeChild(grandparent);
resolve();
}), true);
eventInfo.trigger_event(target);
}
);
@ -239,7 +285,9 @@ function main() {
}).then(function() {
return Promise.all(gLegacyEventInfo.map(mpTestModernBeatsLegacy));
}).then(function() {
return Promise.all(gLegacyEventInfo.map(mpTestAncestorsWithDiffListeners));
return Promise.all(gLegacyEventInfo.map(mpTestDiffListenersEventCapturing));
}).then(function() {
return Promise.all(gLegacyEventInfo.map(mpTestDiffListenersEventBubbling));
}).then(function() {
SimpleTest.finish();
}).catch(function(reason) {

View File

@ -4,6 +4,7 @@
<title>Test for MozMousePixelScroll events</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/paint_listener.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<style>
.scrollable {
@ -63,6 +64,8 @@ function* prepareScrollUnits()
}
window.addEventListener("MozMousePixelScroll", handler, true);
yield waitForAllPaints(function () { setTimeout(runTest, 0); });
yield synthesizeWheel(gScrollable128, 10, 10,
{ deltaMode: WheelEvent.DOM_DELTA_LINE,
deltaY: 1.0, lineOrPageDeltaY: 1 });

View File

@ -24,7 +24,7 @@ NS_NewHTMLDetailsElement(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
namespace mozilla {
namespace dom {
bool
/* static */ bool
HTMLDetailsElement::IsDetailsEnabled()
{
static bool isDetailsEnabled = false;

View File

@ -891,8 +891,8 @@ nsHTMLDocument::GetDomain(nsAString& aDomain)
}
nsAutoCString hostName;
if (NS_SUCCEEDED(uri->GetHost(hostName))) {
nsresult rv = nsContentUtils::GetHostOrIPv6WithBrackets(uri, hostName);
if (NS_SUCCEEDED(rv)) {
CopyUTF8toUTF16(hostName, aDomain);
} else {
// If we can't get the host from the URI (e.g. about:, javascript:,

View File

@ -8566,6 +8566,16 @@ private:
NS_DECL_NSIRUNNABLE
};
class FlushPendingFileDeletionsRunnable final
: public nsRunnable
{
private:
~FlushPendingFileDeletionsRunnable()
{ }
NS_DECL_NSIRUNNABLE
};
class PermissionRequestHelper final
: public PermissionRequestBase
, public PIndexedDBPermissionRequestParent
@ -9568,6 +9578,19 @@ DeallocPBackgroundIndexedDBUtilsParent(PBackgroundIndexedDBUtilsParent* aActor)
return true;
}
bool
RecvFlushPendingFileDeletions()
{
AssertIsOnBackgroundThread();
RefPtr<FlushPendingFileDeletionsRunnable> runnable =
new FlushPendingFileDeletionsRunnable();
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(runnable)));
return true;
}
PIndexedDBPermissionRequestParent*
AllocPIndexedDBPermissionRequestParent(Element* aOwnerElement,
nsIPrincipal* aPrincipal)
@ -27062,6 +27085,24 @@ GetFileReferencesHelper::Run()
return NS_OK;
}
NS_IMETHODIMP
FlushPendingFileDeletionsRunnable::Run()
{
MOZ_ASSERT(NS_IsMainThread());
RefPtr<IndexedDatabaseManager> mgr = IndexedDatabaseManager::Get();
if (NS_WARN_IF(!mgr)) {
return NS_ERROR_FAILURE;
}
nsresult rv = mgr->FlushPendingFileDeletions();
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
return NS_OK;
}
void
PermissionRequestHelper::OnPromptComplete(PermissionValue aPermissionValue)
{

View File

@ -45,6 +45,9 @@ AllocPBackgroundIndexedDBUtilsParent();
bool
DeallocPBackgroundIndexedDBUtilsParent(PBackgroundIndexedDBUtilsParent* aActor);
bool
RecvFlushPendingFileDeletions();
PIndexedDBPermissionRequestParent*
AllocPIndexedDBPermissionRequestParent(Element* aOwnerElement,
nsIPrincipal* aPrincipal);

View File

@ -22,7 +22,6 @@
#include "mozilla/EventDispatcher.h"
#include "mozilla/Preferences.h"
#include "mozilla/Services.h"
#include "mozilla/dom/ContentChild.h"
#include "mozilla/dom/DOMError.h"
#include "mozilla/dom/ErrorEvent.h"
#include "mozilla/dom/ErrorEventBinding.h"
@ -934,12 +933,12 @@ IndexedDatabaseManager::FlushPendingFileDeletions()
return rv;
}
} else {
ContentChild* contentChild = ContentChild::GetSingleton();
if (NS_WARN_IF(!contentChild)) {
PBackgroundChild* bgActor = BackgroundChild::GetForCurrentThread();
if (NS_WARN_IF(!bgActor)) {
return NS_ERROR_FAILURE;
}
if (!contentChild->SendFlushPendingFileDeletions()) {
if (!bgActor->SendFlushPendingFileDeletions()) {
return NS_ERROR_FAILURE;
}
}

View File

@ -182,7 +182,7 @@ skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
[test_file_delete.html]
skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
[test_file_os_delete.html]
skip-if = e10s || (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116, Bug 1183959 for e10s
skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
[test_file_put_get_object.html]
skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
[test_file_put_get_values.html]

View File

@ -64,7 +64,6 @@
#include "mozilla/dom/cellbroadcast/CellBroadcastParent.h"
#include "mozilla/dom/devicestorage/DeviceStorageRequestParent.h"
#include "mozilla/dom/icc/IccParent.h"
#include "mozilla/dom/indexedDB/IndexedDatabaseManager.h"
#include "mozilla/dom/mobileconnection/MobileConnectionParent.h"
#include "mozilla/dom/mobilemessage/SmsParent.h"
#include "mozilla/dom/power/PowerManagerService.h"
@ -291,7 +290,6 @@ using namespace mozilla::dom::bluetooth;
using namespace mozilla::dom::cellbroadcast;
using namespace mozilla::dom::devicestorage;
using namespace mozilla::dom::icc;
using namespace mozilla::dom::indexedDB;
using namespace mozilla::dom::power;
using namespace mozilla::dom::mobileconnection;
using namespace mozilla::dom::mobilemessage;
@ -5109,26 +5107,6 @@ ContentParent::DeallocPFileDescriptorSetParent(PFileDescriptorSetParent* aActor)
return true;
}
bool
ContentParent::RecvFlushPendingFileDeletions()
{
RefPtr<IndexedDatabaseManager> mgr = IndexedDatabaseManager::Get();
if (NS_WARN_IF(!mgr)) {
return false;
}
if (NS_WARN_IF(!mgr->IsMainProcess())) {
return false;
}
nsresult rv = mgr->FlushPendingFileDeletions();
if (NS_WARN_IF(NS_FAILED(rv))) {
return false;
}
return true;
}
bool
ContentParent::IgnoreIPCPrincipal()
{

View File

@ -1045,9 +1045,6 @@ private:
virtual bool
DeallocPFileDescriptorSetParent(PFileDescriptorSetParent*) override;
virtual bool
RecvFlushPendingFileDeletions() override;
virtual PWebrtcGlobalParent* AllocPWebrtcGlobalParent() override;
virtual bool DeallocPWebrtcGlobalParent(PWebrtcGlobalParent *aActor) override;

View File

@ -1055,9 +1055,6 @@ parent:
sync KeygenProvideContent()
returns (nsString aAttribute, nsString[] aContent);
// Use only for testing!
async FlushPendingFileDeletions();
/**
* Tell the chrome process there is an creation of PBrowser.
* return a system-wise unique Id.

View File

@ -2631,6 +2631,9 @@ MediaManager::Shutdown()
GetActiveWindows()->Clear();
mActiveCallbacks.Clear();
mCallIds.Clear();
#ifdef MOZ_WEBRTC
StopWebRtcLog();
#endif
// Because mMediaThread is not an nsThread, we must dispatch to it so it can
// clean up BackgroundChild. Continue stopping thread once this is done.

View File

@ -53,8 +53,8 @@ function range(start, end) {
function once(target, name, cb) {
var p = new Promise(function(resolve, reject) {
target.addEventListener(name, function() {
target.removeEventListener(name, arguments.callee);
target.addEventListener(name, function onceEvent() {
target.removeEventListener(name, onceEvent);
resolve();
});
});

View File

@ -740,7 +740,7 @@ MediaCodecDataDecoder::Shutdown()
{
MonitorAutoLock lock(mMonitor);
if (!mThread || State() == kStopping) {
if (State() == kStopping) {
// Already shutdown or in the process of doing so
return NS_OK;
}
@ -748,15 +748,20 @@ MediaCodecDataDecoder::Shutdown()
State(kStopping);
lock.Notify();
while (State() == kStopping) {
while (mThread && State() == kStopping) {
lock.Wait();
}
mThread->Shutdown();
mThread = nullptr;
if (mThread) {
mThread->Shutdown();
mThread = nullptr;
}
mDecoder->Stop();
mDecoder->Release();
if (mDecoder) {
mDecoder->Stop();
mDecoder->Release();
mDecoder = nullptr;
}
return NS_OK;
}

View File

@ -40,8 +40,8 @@ FFmpegLibWrapper::Link()
uint32_t version = avcodec_version();
mVersion = (version >> 16) & 0xff;
uint32_t micro = version & 0xff;
if (mVersion == 57 && micro != 100) {
// a micro version of 100 indicates that it's FFmpeg (as opposed to LibAV).
if (mVersion == 57 && micro < 100) {
// a micro version >= 100 indicates that it's FFmpeg (as opposed to LibAV).
// Due to current AVCodecContext binary incompatibility we can only
// support FFmpeg 57 at this stage.
Unlink();

View File

@ -0,0 +1,73 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
from __future__ import absolute_import, unicode_literals
import os
import sys
from mozbuild.base import (
MachCommandBase,
MachCommandConditions as conditions,
)
from mach.decorators import (
CommandProvider,
Command,
)
def setup_argument_parser():
from external_media_harness.runtests import MediaTestArguments
return MediaTestArguments()
def run_external_media_test(tests, testtype=None, topsrcdir=None, **kwargs):
from external_media_harness.runtests import (
FirefoxMediaHarness,
MediaTestArguments,
MediaTestRunner,
mn_cli,
)
from mozlog.structured import commandline
parser = MediaTestArguments()
commandline.add_logging_group(parser)
args = parser.parse_args()
if not tests:
tests = [os.path.join(topsrcdir,
'dom/media/test/external/external_media_tests/manifest.ini')]
args.tests = tests
if not args.binary:
args.binary = kwargs['binary']
for k, v in kwargs.iteritems():
setattr(args, k, v)
parser.verify_usage(args)
args.logger = commandline.setup_logging("Firefox External Media Tests",
args,
{"mach": sys.stdout})
failed = mn_cli(MediaTestRunner, MediaTestArguments, FirefoxMediaHarness,
args=args)
if failed > 0:
return 1
else:
return 0
@CommandProvider
class MachCommands(MachCommandBase):
@Command('external-media-tests', category='testing',
description='Run Firefox external media tests.',
conditions=[conditions.is_firefox],
parser=setup_argument_parser,
)
def run_external_media_test(self, tests, **kwargs):
kwargs['binary'] = self.get_binary_path('app')
return run_external_media_test(tests, topsrcdir=self.topsrcdir, **kwargs)

View File

@ -15,9 +15,9 @@ mozrunner==6.11
moztest==0.7
mozversion==1.4
wptserve==1.3.0
marionette-client==2.1.0
marionette-driver==1.2.0
firefox-puppeteer==3.1.0
marionette-client == 2.2.0
marionette-driver == 1.3.0
firefox-puppeteer==3.2.0
# Install the firefox media tests package
./

View File

@ -7,11 +7,11 @@ from setuptools import setup, find_packages
PACKAGE_VERSION = '1.0'
deps = [
'marionette-client == 2.1.0',
'marionette-driver == 1.2.0',
'marionette-client == 2.2.0',
'marionette-driver == 1.3.0',
'mozlog == 3.1',
'manifestparser == 1.1',
'firefox-puppeteer >= 3.1.0, <4.0.0',
'firefox-puppeteer >= 3.2.0, <4.0.0',
]
setup(name='external-media-tests',

View File

@ -1357,8 +1357,8 @@ function removeNodeAndSource(n) {
function once(target, name, cb) {
var p = new Promise(function(resolve, reject) {
target.addEventListener(name, function() {
target.removeEventListener(name, cb);
target.addEventListener(name, function onceEvent() {
target.removeEventListener(name, onceEvent);
resolve();
});
});

View File

@ -0,0 +1,32 @@
<!DOCTYPE html>
<html class="reftest-wait">
<head>
<meta charset="utf-8">
<script type="application/javascript">
function f()
{
if (speechSynthesis.getVoices().length == 0) {
// No synthesis backend to test this
document.documentElement.removeAttribute('class');
return;
}
var s = new SpeechSynthesisUtterance("hello world");
s.onerror = () => {
// No synthesis backend to test this
document.documentElement.removeAttribute('class');
return;
}
s.onend = () => {
document.documentElement.removeAttribute('class');
};
speechSynthesis.speak(s);
speechSynthesis.cancel();
speechSynthesis.pause();
speechSynthesis.resume();
}
</script>
</head>
<body onload="f();">
</body>
</html>

View File

@ -0,0 +1 @@
skip-if(!cocoaWidget) pref(media.webspeech.synth.enabled,true) load 1230428.html # bug 1230428

View File

@ -58,9 +58,16 @@ public:
switch (event) {
case EVENT_FINISHED:
{
nsCOMPtr<nsIRunnable> runnable =
if (!mStarted) {
mStarted = true;
nsCOMPtr<nsIRunnable> startRunnable =
NS_NewRunnableMethod(this, &SynthStreamListener::DoNotifyStarted);
aGraph->DispatchToMainThreadAfterStreamStateUpdate(startRunnable.forget());
}
nsCOMPtr<nsIRunnable> endRunnable =
NS_NewRunnableMethod(this, &SynthStreamListener::DoNotifyFinished);
aGraph->DispatchToMainThreadAfterStreamStateUpdate(runnable.forget());
aGraph->DispatchToMainThreadAfterStreamStateUpdate(endRunnable.forget());
}
break;
case EVENT_REMOVED:

View File

@ -24,6 +24,7 @@
#endif
#include "mozilla/X11Util.h"
static void plug_added_cb(GtkWidget *widget, gpointer data);
static gboolean plug_removed_cb (GtkWidget *widget, gpointer data);
static void socket_unrealize_cb (GtkWidget *widget, gpointer data);
@ -163,6 +164,9 @@ nsresult nsPluginNativeWindowGtk::CreateXEmbedWindow(bool aEnableXtFocus) {
// see plugin_window_filter_func() for details
g_object_set_data(G_OBJECT(mSocketWidget), "enable-xt-focus", (void *)aEnableXtFocus);
g_signal_connect(mSocketWidget, "plug_added",
G_CALLBACK(plug_added_cb), nullptr);
// Make sure to handle the plug_removed signal. If we don't the
// socket will automatically be destroyed when the plug is
// removed, which means we're destroying it more than once.
@ -278,6 +282,32 @@ nsresult nsPluginNativeWindowGtk::CreateXtWindow() {
}
#endif
static void
plug_window_finalize_cb(gpointer socket, GObject* plug_window)
{
g_object_unref(socket);
}
static void
plug_added_cb(GtkWidget *socket, gpointer data)
{
// The plug window has been embedded, and gtk_socket_add_window() has added
// a filter to the socket's plug_window, passing the socket as data for the
// filter, so the socket must live as long as events may be received on the
// plug window.
//
// https://git.gnome.org/browse/gtk+/tree/gtk/gtksocket.c?h=3.18.7#n1124
g_object_ref(socket);
// When the socket is unrealized, perhaps during gtk_widget_destroy() from
// ~nsPluginNativeWindowGtk, the plug is removed. The plug in the child
// process then destroys its widget and window. When the browser process
// receives the DestroyNotify event for the plug window, GDK releases its
// reference to plugWindow. This is typically the last reference and so the
// weak ref callback triggers release of the socket.
GdkWindow* plugWindow = gtk_socket_get_plug_window(GTK_SOCKET(socket));
g_object_weak_ref(G_OBJECT(plugWindow), plug_window_finalize_cb, socket);
}
/* static */
gboolean
plug_removed_cb (GtkWidget *widget, gpointer data)

View File

@ -1974,12 +1974,6 @@ RuntimeService::Shutdown()
// That's it, no more workers.
mShuttingDown = true;
// Remove all listeners from the worker debugger manager to ensure that it
// gets properly destroyed.
if (NS_FAILED(ClearWorkerDebuggerManagerListeners())) {
NS_WARNING("Failed to clear worker debugger manager listeners!");
}
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
NS_WARN_IF_FALSE(obs, "Failed to get observer service?!");

View File

@ -8,22 +8,23 @@
#include "nsISimpleEnumerator.h"
#include "mozilla/ClearOnShutdown.h"
#include "WorkerPrivate.h"
USING_WORKERS_NAMESPACE
namespace {
class RegisterDebuggerMainThreadRunnable final : public nsRunnable
{
RefPtr<WorkerDebuggerManager> mManager;
WorkerPrivate* mWorkerPrivate;
bool mNotifyListeners;
public:
RegisterDebuggerMainThreadRunnable(WorkerDebuggerManager* aManager,
WorkerPrivate* aWorkerPrivate,
RegisterDebuggerMainThreadRunnable(WorkerPrivate* aWorkerPrivate,
bool aNotifyListeners)
: mManager(aManager),
mWorkerPrivate(aWorkerPrivate),
: mWorkerPrivate(aWorkerPrivate),
mNotifyListeners(aNotifyListeners)
{ }
@ -34,21 +35,21 @@ private:
NS_IMETHOD
Run() override
{
mManager->RegisterDebuggerMainThread(mWorkerPrivate, mNotifyListeners);
WorkerDebuggerManager* manager = WorkerDebuggerManager::Get();
MOZ_ASSERT(manager);
manager->RegisterDebuggerMainThread(mWorkerPrivate, mNotifyListeners);
return NS_OK;
}
};
class UnregisterDebuggerMainThreadRunnable final : public nsRunnable
{
RefPtr<WorkerDebuggerManager> mManager;
WorkerPrivate* mWorkerPrivate;
public:
UnregisterDebuggerMainThreadRunnable(WorkerDebuggerManager* aManager,
WorkerPrivate* aWorkerPrivate)
: mManager(aManager), mWorkerPrivate(aWorkerPrivate)
explicit UnregisterDebuggerMainThreadRunnable(WorkerPrivate* aWorkerPrivate)
: mWorkerPrivate(aWorkerPrivate)
{ }
private:
@ -58,12 +59,19 @@ private:
NS_IMETHOD
Run() override
{
mManager->UnregisterDebuggerMainThread(mWorkerPrivate);
WorkerDebuggerManager* manager = WorkerDebuggerManager::Get();
MOZ_ASSERT(manager);
manager->UnregisterDebuggerMainThread(mWorkerPrivate);
return NS_OK;
}
};
// Does not hold an owning reference.
static WorkerDebuggerManager* gWorkerDebuggerManager;
} /* anonymous namespace */
BEGIN_WORKERS_NAMESPACE
class WorkerDebuggerEnumerator final : public nsISimpleEnumerator
@ -116,7 +124,54 @@ WorkerDebuggerManager::~WorkerDebuggerManager()
AssertIsOnMainThread();
}
NS_IMPL_ISUPPORTS(WorkerDebuggerManager, nsIWorkerDebuggerManager);
// static
already_AddRefed<WorkerDebuggerManager>
WorkerDebuggerManager::GetInstance()
{
RefPtr<WorkerDebuggerManager> manager = WorkerDebuggerManager::GetOrCreate();
return manager.forget();
}
// static
WorkerDebuggerManager*
WorkerDebuggerManager::GetOrCreate()
{
AssertIsOnMainThread();
if (!gWorkerDebuggerManager) {
// The observer service now owns us until shutdown.
gWorkerDebuggerManager = new WorkerDebuggerManager();
if (NS_FAILED(gWorkerDebuggerManager->Init())) {
NS_WARNING("Failed to initialize worker debugger manager!");
gWorkerDebuggerManager = nullptr;
return nullptr;
}
}
return gWorkerDebuggerManager;
}
WorkerDebuggerManager*
WorkerDebuggerManager::Get()
{
MOZ_ASSERT(gWorkerDebuggerManager);
return gWorkerDebuggerManager;
}
NS_IMPL_ISUPPORTS(WorkerDebuggerManager, nsIObserver, nsIWorkerDebuggerManager);
NS_IMETHODIMP
WorkerDebuggerManager::Observe(nsISupports* aSubject, const char* aTopic,
const char16_t* aData)
{
if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
Shutdown();
return NS_OK;
}
NS_NOTREACHED("Unknown observer topic!");
return NS_OK;
}
NS_IMETHODIMP
WorkerDebuggerManager::GetWorkerDebuggerEnumerator(
@ -161,8 +216,20 @@ WorkerDebuggerManager::RemoveListener(
return NS_OK;
}
nsresult
WorkerDebuggerManager::Init()
{
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
NS_ENSURE_TRUE(obs, NS_ERROR_FAILURE);
nsresult rv = obs->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
void
WorkerDebuggerManager::ClearListeners()
WorkerDebuggerManager::Shutdown()
{
AssertIsOnMainThread();
@ -205,8 +272,7 @@ WorkerDebuggerManager::RegisterDebugger(WorkerPrivate* aWorkerPrivate)
}
nsCOMPtr<nsIRunnable> runnable =
new RegisterDebuggerMainThreadRunnable(this, aWorkerPrivate,
hasListeners);
new RegisterDebuggerMainThreadRunnable(aWorkerPrivate, hasListeners);
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
NS_DispatchToMainThread(runnable, NS_DISPATCH_NORMAL)));
@ -225,7 +291,7 @@ WorkerDebuggerManager::UnregisterDebugger(WorkerPrivate* aWorkerPrivate)
UnregisterDebuggerMainThread(aWorkerPrivate);
} else {
nsCOMPtr<nsIRunnable> runnable =
new UnregisterDebuggerMainThreadRunnable(this, aWorkerPrivate);
new UnregisterDebuggerMainThreadRunnable(aWorkerPrivate);
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
NS_DispatchToMainThread(runnable, NS_DISPATCH_NORMAL)));

View File

@ -9,6 +9,7 @@
#include "Workers.h"
#include "nsIObserver.h"
#include "nsIWorkerDebuggerManager.h"
#include "nsServiceManagerUtils.h"
@ -24,7 +25,8 @@ BEGIN_WORKERS_NAMESPACE
class WorkerDebugger;
class WorkerDebuggerManager final : public nsIWorkerDebuggerManager
class WorkerDebuggerManager final : public nsIObserver,
public nsIWorkerDebuggerManager
{
Mutex mMutex;
@ -35,54 +37,58 @@ class WorkerDebuggerManager final : public nsIWorkerDebuggerManager
nsTArray<RefPtr<WorkerDebugger>> mDebuggers;
public:
static already_AddRefed<WorkerDebuggerManager>
GetInstance();
static WorkerDebuggerManager*
GetOrCreateService()
{
nsCOMPtr<nsIWorkerDebuggerManager> manager =
do_GetService(WORKERDEBUGGERMANAGER_CONTRACTID);
return static_cast<WorkerDebuggerManager*>(manager.get());
}
GetOrCreate();
static WorkerDebuggerManager*
Get();
WorkerDebuggerManager();
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_ISUPPORTS
NS_DECL_NSIOBSERVER
NS_DECL_NSIWORKERDEBUGGERMANAGER
void ClearListeners();
nsresult
Init();
void RegisterDebugger(WorkerPrivate* aWorkerPrivate);
void
Shutdown();
void UnregisterDebugger(WorkerPrivate* aWorkerPrivate);
void
RegisterDebugger(WorkerPrivate* aWorkerPrivate);
void RegisterDebuggerMainThread(WorkerPrivate* aWorkerPrivate,
bool aNotifyListeners);
void
RegisterDebuggerMainThread(WorkerPrivate* aWorkerPrivate,
bool aNotifyListeners);
void UnregisterDebuggerMainThread(WorkerPrivate* aWorkerPrivate);
void
UnregisterDebugger(WorkerPrivate* aWorkerPrivate);
void
UnregisterDebuggerMainThread(WorkerPrivate* aWorkerPrivate);
private:
virtual ~WorkerDebuggerManager();
};
inline nsresult
ClearWorkerDebuggerManagerListeners()
{
RefPtr<WorkerDebuggerManager> manager =
WorkerDebuggerManager::GetOrCreateService();
if (!manager) {
return NS_ERROR_FAILURE;
}
manager->ClearListeners();
return NS_OK;
}
inline nsresult
RegisterWorkerDebugger(WorkerPrivate* aWorkerPrivate)
{
RefPtr<WorkerDebuggerManager> manager =
WorkerDebuggerManager::GetOrCreateService();
if (!manager) {
return NS_ERROR_FAILURE;
WorkerDebuggerManager* manager;
if (NS_IsMainThread()) {
manager = WorkerDebuggerManager::GetOrCreate();
if (!manager) {
NS_WARNING("Failed to create worker debugger manager!");
return NS_ERROR_FAILURE;
}
}
else {
manager = WorkerDebuggerManager::Get();
}
manager->RegisterDebugger(aWorkerPrivate);
@ -92,10 +98,17 @@ RegisterWorkerDebugger(WorkerPrivate* aWorkerPrivate)
inline nsresult
UnregisterWorkerDebugger(WorkerPrivate* aWorkerPrivate)
{
RefPtr<WorkerDebuggerManager> manager =
WorkerDebuggerManager::GetOrCreateService();
if (!manager) {
return NS_ERROR_FAILURE;
WorkerDebuggerManager* manager;
if (NS_IsMainThread()) {
manager = WorkerDebuggerManager::GetOrCreate();
if (!manager) {
NS_WARNING("Failed to create worker debugger manager!");
return NS_ERROR_FAILURE;
}
}
else {
manager = WorkerDebuggerManager::Get();
}
manager->UnregisterDebugger(aWorkerPrivate);

View File

@ -1832,7 +1832,7 @@ XULDocument::RemoveElementFromRefMap(Element* aElement)
if (!entry)
return;
if (entry->RemoveElement(aElement)) {
mRefMap.RawRemoveEntry(entry);
mRefMap.RemoveEntry(entry);
}
}
}

View File

@ -1571,7 +1571,7 @@ nsPermissionManager::AddInternal(nsIPrincipal* aPrincipal,
PermissionHashKey* entry = mPermissionTable.PutEntry(key);
if (!entry) return NS_ERROR_FAILURE;
if (!entry->GetKey()) {
mPermissionTable.RawRemoveEntry(entry);
mPermissionTable.RemoveEntry(entry);
return NS_ERROR_OUT_OF_MEMORY;
}
@ -1694,7 +1694,7 @@ nsPermissionManager::AddInternal(nsIPrincipal* aPrincipal,
// If there are no more permissions stored for that entry, clear it.
if (entry->GetPermissions().IsEmpty()) {
mPermissionTable.RawRemoveEntry(entry);
mPermissionTable.RemoveEntry(entry);
}
break;

View File

@ -238,7 +238,7 @@ uint16 Face::getGlyphMetric(uint16 gid, uint8 metric) const
case kgmetAscent : return m_ascent;
case kgmetDescent : return m_descent;
default:
if (gid > glyphs().numGlyphs()) return 0;
if (gid >= glyphs().numGlyphs()) return 0;
return glyphs().glyph(gid)->getMetric(metric);
}
}

View File

@ -60,8 +60,12 @@ FileFace::FileFace(const char *filename)
if (!TtfUtil::GetTableDirInfo(_header_tbl, tbl_offset, tbl_len)) return;
_table_dir = (TtfUtil::Sfnt::OffsetSubTable::Entry*)gralloc<char>(tbl_len);
if (fseek(_file, tbl_offset, SEEK_SET)) return;
if (_table_dir)
if (fread(_table_dir, 1, tbl_len, _file) != tbl_len) return;
if (_table_dir && fread(_table_dir, 1, tbl_len, _file) != tbl_len)
{
free(_table_dir);
_table_dir = NULL;
}
return;
}
FileFace::~FileFace()

View File

@ -100,7 +100,9 @@ bool Pass::readPass(const byte * const pass_start, size_t pass_length, size_t su
if (e.test(pass_length < 40, E_BADPASSLENGTH)) return face.error(e);
// Read in basic values
const byte flags = be::read<byte>(p);
if (e.test((flags & 0x1f) && pt < PASS_TYPE_POSITIONING, E_BADCOLLISIONPASS))
if (e.test((flags & 0x1f) &&
(pt < PASS_TYPE_POSITIONING || !m_silf->aCollision() || !face.glyphs().hasBoxes()),
E_BADCOLLISIONPASS))
return face.error(e);
m_numCollRuns = flags & 0x7;
m_kernColls = (flags >> 3) & 0x3;

View File

@ -112,6 +112,7 @@ public:
const SlantBox & getSubBoundingSlantBox(unsigned short glyphid, uint8 subindex) const;
const BBox & getSubBoundingBBox(unsigned short glyphid, uint8 subindex) const;
bool check(unsigned short glyphid) const;
bool hasBoxes() const { return _boxes != 0; }
CLASS_NEW_DELETE;

View File

@ -31,3 +31,4 @@ skip-if = (os == 'android') || (os == 'b2g') || (buildapp == 'mulet') # wheel ev
skip-if = (os == 'android') || (os == 'b2g') || (buildapp == 'mulet') # wheel events not supported on mobile; see bug 1164274 for mulet
[test_scroll_subframe_scrollbar.html]
skip-if = (os == 'android') || (os == 'b2g') || (buildapp == 'mulet') # wheel events not supported on mobile; see bug 1164274 for mulet
[test_frame_reconstruction.html]

View File

@ -0,0 +1,231 @@
<!DOCTYPE html>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1235899
-->
<head>
<title>Test for bug 1235899</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/paint_listener.js"></script>
<script type="application/javascript" src="apz_test_utils.js"></script>
<script type="application/javascript" src="apz_test_native_event_utils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<style>
.outer {
height: 400px;
width: 415px;
overflow: hidden;
position: relative;
}
.inner {
height: 100%;
outline: none;
overflow-x: hidden;
overflow-y: scroll;
position: relative;
scroll-behavior: smooth;
}
.outer.contentBefore::before {
top: 0;
content: '';
display: block;
height: 2px;
position: absolute;
width: 100%;
z-index: 99;
}
</style>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1235899">Mozilla Bug 1235899</a>
<p id="display"></p>
<div id="content">
<p>You should be able to fling this list without it stopping abruptly</p>
<div class="outer">
<div class="inner">
<ol>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
<li>Some text</li>
</ol>
</div>
</div>
</div>
<pre id="test">
<script type="application/javascript;version=1.7">
function* runTest() {
var elm = document.getElementsByClassName('inner')[0];
elm.scrollTop = 0;
yield flushApzRepaints(driveTest);
// Take over control of the refresh driver and compositor
var utils = SpecialPowers.DOMWindowUtils;
utils.advanceTimeAndRefresh(0);
// Kick off an APZ smooth-scroll to 0,200
elm.scrollTo(0, 200);
yield waitForAllPaints(function() { setTimeout(driveTest, 0); });
// Let's do a couple of frames of the animation, and make sure it's going
utils.advanceTimeAndRefresh(16);
utils.advanceTimeAndRefresh(16);
yield flushApzRepaints(driveTest);
ok(elm.scrollTop > 0, "APZ animation in progress", "scrollTop is now " + elm.scrollTop);
ok(elm.scrollTop < 200, "APZ animation not yet completed", "scrollTop is now " + elm.scrollTop);
var frameReconstructionTriggered = 0;
// Register the listener that triggers the frame reconstruction
elm.onscroll = function() {
// Do the reconstruction
elm.parentNode.classList.add('contentBefore');
frameReconstructionTriggered++;
// schedule a thing to undo the changes above
setTimeout(function() {
elm.parentNode.classList.remove('contentBefore');
}, 0);
}
// and do a few more frames of the animation, this should trigger the listener
// and the frame reconstruction
utils.advanceTimeAndRefresh(16);
utils.advanceTimeAndRefresh(16);
yield flushApzRepaints(driveTest);
ok(elm.scrollTop < 200, "APZ animation not yet completed", "scrollTop is now " + elm.scrollTop);
ok(frameReconstructionTriggered > 0, "Frame reconstruction triggered", "reconstruction triggered " + frameReconstructionTriggered + " times");
// and now run to completion
for (var i = 0; i < 100; i++) {
utils.advanceTimeAndRefresh(16);
}
utils.restoreNormalRefresh();
yield waitForAllPaints(function() { setTimeout(driveTest, 0); });
yield flushApzRepaints(driveTest);
is(elm.scrollTop, 200, "Element should have scrolled by 200px");
}
var gTestContinuation = null;
function driveTest() {
if (!gTestContinuation) {
gTestContinuation = runTest();
}
var ret = gTestContinuation.next();
if (ret.done) {
SimpleTest.finish();
}
}
SimpleTest.waitForExplicitFinish();
var apzEnabled = SpecialPowers.getDOMWindowUtils(window).asyncPanZoomEnabled;
if (!apzEnabled) {
ok(true, "APZ not enabled, skipping test");
SimpleTest.finish();
} else {
SimpleTest.expectAssertions(0, 1); // this test triggers an assertion, see bug 1247050
SimpleTest.waitForFocus(driveTest, window);
}
</script>
</body>
</html>

View File

@ -61,12 +61,6 @@
SimpleTest.finish();
}
var hwVsyncEnabled = SpecialPowers.getBoolPref("gfx.vsync.hw-vsync.enabled");
if (!hwVsyncEnabled) {
SimpleTest.ok(true, "Hardware vsync not enabled, skipping test");
SimpleTest.finish();
}
SpecialPowers.pushPrefEnv({
"set" : [
[testPref, true]

View File

@ -92,11 +92,11 @@ ScrollFrameTo(nsIScrollableFrame* aFrame, const CSSPoint& aPoint, bool& aSuccess
// If the scrollable frame is currently in the middle of an async or smooth
// scroll then we don't want to interrupt it (see bug 961280).
// Also if the scrollable frame got a scroll request from something other than us
// Also if the scrollable frame got a scroll request from a higher priority origin
// since the last layers update, then we don't want to push our scroll request
// because we'll clobber that one, which is bad.
bool scrollInProgress = aFrame->IsProcessingAsyncScroll()
|| (aFrame->LastScrollOrigin() && aFrame->LastScrollOrigin() != nsGkAtoms::apz)
|| nsLayoutUtils::CanScrollOriginClobberApz(aFrame->LastScrollOrigin())
|| aFrame->LastSmoothScrollOrigin();
if (!scrollInProgress) {
aFrame->ScrollToCSSPixelsApproximate(targetScrollPosition, nsGkAtoms::apz);

View File

@ -564,8 +564,8 @@ RenderLayers(ContainerT* aContainer,
if (layerToRender->HasLayerBeenComposited()) {
// Composer2D will compose this layer so skip GPU composition
// this time & reset composition flag for next composition phase
layerToRender->SetLayerComposited(false);
// this time. The flag will be reset for the next composition phase
// at the beginning of LayerManagerComposite::Rener().
gfx::IntRect clearRect = layerToRender->GetClearRect();
if (!clearRect.IsEmpty()) {
// Clear layer's visible rect on FrameBuffer with transparent pixels

View File

@ -762,6 +762,21 @@ LayerManagerComposite::PopGroupForLayerEffects(RefPtr<CompositingRenderTarget> a
Matrix4x4());
}
// Used to clear the 'mLayerComposited' flag at the beginning of each Render().
static void
ClearLayerFlags(Layer* aLayer) {
if (!aLayer) {
return;
}
if (aLayer->AsLayerComposite()) {
aLayer->AsLayerComposite()->SetLayerComposited(false);
}
for (Layer* child = aLayer->GetFirstChild(); child;
child = child->GetNextSibling()) {
ClearLayerFlags(child);
}
}
void
LayerManagerComposite::Render(const nsIntRegion& aInvalidRegion)
{
@ -773,6 +788,8 @@ LayerManagerComposite::Render(const nsIntRegion& aInvalidRegion)
return;
}
ClearLayerFlags(mRoot);
// At this time, it doesn't really matter if these preferences change
// during the execution of the function; we should be safe in all
// permutations. However, may as well just get the values onces and

View File

@ -58,6 +58,37 @@ using namespace mozilla::media;
typedef std::vector<CompositableOperation> OpVector;
typedef nsTArray<OpDestroy> OpDestroyVector;
namespace {
class ImageBridgeThread : public Thread {
public:
ImageBridgeThread() : Thread("ImageBridgeChild") {
}
protected:
void Init() {
#ifdef MOZ_ENABLE_PROFILER_SPS
mPseudoStackHack = mozilla_get_pseudo_stack();
#endif
}
void CleanUp() {
#ifdef MOZ_ENABLE_PROFILER_SPS
mPseudoStackHack = nullptr;
#endif
}
private:
#ifdef MOZ_ENABLE_PROFILER_SPS
// This is needed to avoid a spurious leak report. There's no other
// use for it. See bug 1239504 and bug 1215265.
PseudoStack* mPseudoStackHack;
#endif
};
}
struct CompositableTransaction
{
CompositableTransaction()
@ -376,7 +407,7 @@ bool ImageBridgeChild::IsCreated()
void ImageBridgeChild::StartUp()
{
NS_ASSERTION(NS_IsMainThread(), "Should be on the main Thread!");
ImageBridgeChild::StartUpOnThread(new Thread("ImageBridgeChild"));
ImageBridgeChild::StartUpOnThread(new ImageBridgeThread());
}
#ifdef MOZ_NUWA_PROCESS
@ -709,7 +740,7 @@ ImageBridgeChild::StartUpInChildProcess(Transport* aTransport,
gfxPlatform::GetPlatform();
sImageBridgeChildThread = new Thread("ImageBridgeChild");
sImageBridgeChildThread = new ImageBridgeThread();
if (!sImageBridgeChildThread->Start()) {
return nullptr;
}

View File

@ -590,11 +590,12 @@ ShareTableAndGetBlob(nsTArray<uint8_t>&& aTable,
Clear();
// adopts elements of aTable
mSharedBlobData = new FontTableBlobData(Move(aTable));
mBlob = hb_blob_create(mSharedBlobData->GetTable(),
mSharedBlobData->GetTableLength(),
HB_MEMORY_MODE_READONLY,
mSharedBlobData, DeleteFontTableBlobData);
if (!mSharedBlobData) {
if (mBlob == hb_blob_get_empty() ) {
// The FontTableBlobData was destroyed during hb_blob_create().
// The (empty) blob is still be held in the hashtable with a strong
// reference.

View File

@ -617,13 +617,13 @@ gfxFontconfigUtils::UpdateFontListInternal(bool aForce)
bool added = entry->AddFont(font);
if (!entry->mKey) {
// The reference to the font pattern keeps the pointer to
// string for the key valid. If adding the font failed
// then the entry must be removed.
// The reference to the font pattern keeps the pointer
// to string for the key valid. If adding the font
// failed then the entry must be removed.
if (added) {
entry->mKey = family;
} else {
mFontsByFamily.RawRemoveEntry(entry);
mFontsByFamily.RemoveEntry(entry);
}
}
}

View File

@ -217,6 +217,15 @@ BackgroundParentImpl::DeallocPBackgroundIndexedDBUtilsParent(
mozilla::dom::indexedDB::DeallocPBackgroundIndexedDBUtilsParent(aActor);
}
bool
BackgroundParentImpl::RecvFlushPendingFileDeletions()
{
AssertIsInMainProcess();
AssertIsOnBackgroundThread();
return mozilla::dom::indexedDB::RecvFlushPendingFileDeletions();
}
auto
BackgroundParentImpl::AllocPBlobParent(const BlobConstructorParams& aParams)
-> PBlobParent*

View File

@ -58,6 +58,9 @@ protected:
PBackgroundIndexedDBUtilsParent* aActor)
override;
virtual bool
RecvFlushPendingFileDeletions() override;
virtual PBlobParent*
AllocPBlobParent(const BlobConstructorParams& aParams) override;

View File

@ -157,6 +157,7 @@ public:
MOZ_RELEASE_ASSERT(aOther.mMessageName);
mMessageName = aOther.mMessageName;
aOther.mMessageName = nullptr;
mMoved = aOther.mMoved;
aOther.mMoved = true;
mMessageRoutingId = aOther.mMessageRoutingId;

View File

@ -66,6 +66,9 @@ parent:
async PBackgroundIndexedDBUtils();
// Use only for testing!
async FlushPendingFileDeletions();
async PVsync();
async PCameras();

View File

@ -468,7 +468,6 @@ struct RuntimeSizes
macro(_, MallocHeap, object) \
macro(_, MallocHeap, atomsTable) \
macro(_, MallocHeap, contexts) \
macro(_, MallocHeap, dtoa) \
macro(_, MallocHeap, temporary) \
macro(_, MallocHeap, interpreterStack) \
macro(_, MallocHeap, mathCache) \

View File

@ -934,7 +934,7 @@ MutableHandle<T>::MutableHandle(PersistentRooted<T>* root)
* These roots can be used in heap-allocated data structures, so they are not
* associated with any particular JSContext or stack. They are registered with
* the JSRuntime itself, without locking, so they require a full JSContext to be
* initialized, not one of its more restricted superclasses. Initialization may
* initialized, not one of its more restricted superclasses. Initialization may
* take place on construction, or in two phases if the no-argument constructor
* is called followed by init().
*
@ -1048,9 +1048,10 @@ class PersistentRooted : public js::PersistentRootedBase<T>,
}
private:
void set(T value) {
template <typename U>
void set(U&& value) {
MOZ_ASSERT(initialized());
ptr = value;
ptr = mozilla::Forward<U>(value);
}
// See the comment above Rooted::ptr.

View File

@ -30,6 +30,8 @@
using namespace js;
using namespace js::wasm;
using mozilla::IsNaN;
typedef Handle<WasmModuleObject*> HandleWasmModule;
typedef MutableHandle<WasmModuleObject*> MutableHandleWasmModule;
@ -952,6 +954,9 @@ DecodeDataSection(JSContext* cx, Decoder& d, Handle<ArrayBufferObject*> heap)
if (!d.readCStringIf(DataSection))
return true;
if (!heap)
return Fail(cx, d, "data section requires a memory section");
uint32_t sectionStart;
if (!d.startSection(&sectionStart))
return Fail(cx, d, "expected data section byte size");

View File

@ -96,6 +96,7 @@ FrameIterator::settle()
case CodeRange::ImportJitExit:
case CodeRange::ImportInterpExit:
case CodeRange::Inline:
case CodeRange::CallThunk:
MOZ_CRASH("Should not encounter an exit during iteration");
}
}
@ -491,6 +492,7 @@ ProfilingFrameIterator::initFromFP(const WasmActivation& activation)
case CodeRange::ImportJitExit:
case CodeRange::ImportInterpExit:
case CodeRange::Inline:
case CodeRange::CallThunk:
MOZ_CRASH("Unexpected CodeRange kind");
}
@ -541,6 +543,7 @@ ProfilingFrameIterator::ProfilingFrameIterator(const WasmActivation& activation,
const CodeRange* codeRange = module_->lookupCodeRange(state.pc);
switch (codeRange->kind()) {
case CodeRange::Function:
case CodeRange::CallThunk:
case CodeRange::ImportJitExit:
case CodeRange::ImportInterpExit: {
// When the pc is inside the prologue/epilogue, the innermost
@ -557,7 +560,7 @@ ProfilingFrameIterator::ProfilingFrameIterator(const WasmActivation& activation,
uint32_t offsetInCodeRange = offsetInModule - codeRange->begin();
void** sp = (void**)state.sp;
#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
if (offsetInCodeRange < PushedRetAddr) {
if (offsetInCodeRange < PushedRetAddr || codeRange->kind() == CodeRange::CallThunk) {
// First instruction of the ARM/MIPS function; the return address is
// still in lr and fp still holds the caller's fp.
callerPC_ = state.lr;
@ -571,7 +574,9 @@ ProfilingFrameIterator::ProfilingFrameIterator(const WasmActivation& activation,
AssertMatchesCallSite(*module_, callerPC_, callerFP_, sp);
} else
#endif
if (offsetInCodeRange < PushedFP || offsetInModule == codeRange->profilingReturn()) {
if (offsetInCodeRange < PushedFP || offsetInModule == codeRange->profilingReturn() ||
codeRange->kind() == CodeRange::CallThunk)
{
// The return address has been pushed on the stack but not fp; fp
// still points to the caller's fp.
callerPC_ = *sp;
@ -655,6 +660,7 @@ ProfilingFrameIterator::operator++()
case CodeRange::ImportJitExit:
case CodeRange::ImportInterpExit:
case CodeRange::Inline:
case CodeRange::CallThunk:
stackAddress_ = callerFP_;
callerPC_ = ReturnAddressFromFP(callerFP_);
AssertMatchesCallSite(*module_, callerPC_, CallerFPFromFP(callerFP_), callerFP_);
@ -696,6 +702,7 @@ ProfilingFrameIterator::label() const
case CodeRange::ImportJitExit: return importJitDescription;
case CodeRange::ImportInterpExit: return importInterpDescription;
case CodeRange::Inline: return "inline stub (in asm.js)";
case CodeRange::CallThunk: return "call thunk (in asm.js)";
}
MOZ_CRASH("bad code range kind");
@ -771,6 +778,14 @@ wasm::EnableProfilingPrologue(const Module& module, const CallSite& callSite, bo
#endif
}
void
wasm::EnableProfilingThunk(const Module& module, const CallThunk& callThunk, bool enabled)
{
const CodeRange& cr = module.codeRanges()[callThunk.u.codeRangeIndex];
uint32_t calleeOffset = enabled ? cr.funcProfilingEntry() : cr.funcNonProfilingEntry();
MacroAssembler::repatchThunk(module.code(), callThunk.offset, calleeOffset);
}
// Replace all the nops in all the epilogues of asm.js functions with jumps
// to the profiling epilogues.
void

View File

@ -33,6 +33,7 @@ namespace wasm {
class CallSite;
class CodeRange;
class Module;
struct CallThunk;
struct FuncOffsets;
struct ProfilingOffsets;
@ -112,6 +113,9 @@ GenerateFunctionEpilogue(jit::MacroAssembler& masm, unsigned framePushed, FuncOf
void
EnableProfilingPrologue(const Module& module, const CallSite& callSite, bool enabled);
void
EnableProfilingThunk(const Module& module, const CallThunk& callThunk, bool enabled);
void
EnableProfilingEpilogue(const Module& module, const CodeRange& codeRange, bool enabled);

View File

@ -18,6 +18,8 @@
#include "asmjs/WasmGenerator.h"
#include "mozilla/EnumeratedRange.h"
#include "asmjs/WasmStubs.h"
#include "jit/MacroAssembler-inl.h"
@ -26,6 +28,8 @@ using namespace js;
using namespace js::jit;
using namespace js::wasm;
using mozilla::MakeEnumeratedRange;
// ****************************************************************************
// ModuleGenerator
@ -41,6 +45,8 @@ ModuleGenerator::ModuleGenerator(ExclusiveContext* cx)
alloc_(&lifo_),
masm_(MacroAssembler::AsmJSToken(), alloc_),
funcIndexToExport_(cx),
lastPatchedCallsite_(0),
startOfUnpatchedBranches_(0),
parallel_(false),
outstanding_(0),
tasks_(cx),
@ -173,13 +179,111 @@ ModuleGenerator::finishOutstandingTask()
return finishTask(task);
}
static const uint32_t BadEntry = UINT32_MAX;
static const uint32_t BadCodeRange = UINT32_MAX;
bool
ModuleGenerator::funcIsDefined(uint32_t funcIndex) const
{
return funcIndex < funcEntryOffsets_.length() &&
funcEntryOffsets_[funcIndex] != BadEntry;
return funcIndex < funcIndexToCodeRange_.length() &&
funcIndexToCodeRange_[funcIndex] != BadCodeRange;
}
uint32_t
ModuleGenerator::funcEntry(uint32_t funcIndex) const
{
MOZ_ASSERT(funcIsDefined(funcIndex));
return module_->codeRanges[funcIndexToCodeRange_[funcIndex]].funcNonProfilingEntry();
}
static uint32_t
JumpRange()
{
return Min(JitOptions.jumpThreshold, JumpImmediateRange);
}
typedef HashMap<uint32_t, uint32_t> OffsetMap;
bool
ModuleGenerator::convertOutOfRangeBranchesToThunks()
{
masm_.haltingAlign(CodeAlignment);
// Create thunks for callsites that have gone out of range. Use a map to
// create one thunk for each callee since there is often high reuse.
OffsetMap alreadyThunked(cx_);
if (!alreadyThunked.init())
return false;
for (; lastPatchedCallsite_ < masm_.callSites().length(); lastPatchedCallsite_++) {
const CallSiteAndTarget& cs = masm_.callSites()[lastPatchedCallsite_];
if (!cs.isInternal())
continue;
uint32_t callerOffset = cs.returnAddressOffset();
MOZ_RELEASE_ASSERT(callerOffset < INT32_MAX);
if (funcIsDefined(cs.targetIndex())) {
uint32_t calleeOffset = funcEntry(cs.targetIndex());
MOZ_RELEASE_ASSERT(calleeOffset < INT32_MAX);
if (uint32_t(abs(int32_t(calleeOffset) - int32_t(callerOffset))) < JumpRange()) {
masm_.patchCall(callerOffset, calleeOffset);
continue;
}
}
OffsetMap::AddPtr p = alreadyThunked.lookupForAdd(cs.targetIndex());
if (!p) {
Offsets offsets;
offsets.begin = masm_.currentOffset();
uint32_t thunkOffset = masm_.thunkWithPatch().offset();
if (masm_.oom())
return false;
offsets.end = masm_.currentOffset();
if (!module_->codeRanges.emplaceBack(CodeRange::CallThunk, offsets))
return false;
if (!module_->callThunks.emplaceBack(thunkOffset, cs.targetIndex()))
return false;
if (!alreadyThunked.add(p, cs.targetIndex(), offsets.begin))
return false;
}
masm_.patchCall(callerOffset, p->value());
}
// Create thunks for jumps to stubs. Stubs are always generated at the end
// so unconditionally thunk all existing jump sites.
for (JumpTarget target : MakeEnumeratedRange(JumpTarget::Limit)) {
if (masm_.jumpSites()[target].empty())
continue;
for (uint32_t jumpSite : masm_.jumpSites()[target]) {
RepatchLabel label;
label.use(jumpSite);
masm_.bind(&label);
}
Offsets offsets;
offsets.begin = masm_.currentOffset();
uint32_t thunkOffset = masm_.thunkWithPatch().offset();
if (masm_.oom())
return false;
offsets.end = masm_.currentOffset();
if (!module_->codeRanges.emplaceBack(CodeRange::Inline, offsets))
return false;
if (!jumpThunks_[target].append(thunkOffset))
return false;
}
// Unlike callsites, which need to be persisted in the Module, we can simply
// flush jump sites after each patching pass.
masm_.clearJumpSites();
return true;
}
bool
@ -188,19 +292,33 @@ ModuleGenerator::finishTask(IonCompileTask* task)
const FuncBytecode& func = task->func();
FuncCompileResults& results = task->results();
// Before merging in the new function's code, if jumps/calls in a previous
// function's body might go out of range, patch these to thunks which have
// full range.
if ((masm_.size() - startOfUnpatchedBranches_) + results.masm().size() > JumpRange()) {
startOfUnpatchedBranches_ = masm_.size();
if (!convertOutOfRangeBranchesToThunks())
return false;
}
// Offset the recorded FuncOffsets by the offset of the function in the
// whole module's code segment.
uint32_t offsetInWhole = masm_.size();
results.offsets().offsetBy(offsetInWhole);
// Record the non-profiling entry for whole-module linking later.
// Cannot simply append because funcIndex order is nonlinear.
if (func.index() >= funcEntryOffsets_.length()) {
if (!funcEntryOffsets_.appendN(BadEntry, func.index() - funcEntryOffsets_.length() + 1))
// Add the CodeRange for this function.
uint32_t funcCodeRangeIndex = module_->codeRanges.length();
if (!module_->codeRanges.emplaceBack(func.index(), func.lineOrBytecode(), results.offsets()))
return false;
// Maintain a mapping from function index to CodeRange index.
if (func.index() >= funcIndexToCodeRange_.length()) {
uint32_t n = func.index() - funcIndexToCodeRange_.length() + 1;
if (!funcIndexToCodeRange_.appendN(BadCodeRange, n))
return false;
}
MOZ_ASSERT(!funcIsDefined(func.index()));
funcEntryOffsets_[func.index()] = results.offsets().nonProfilingEntry;
funcIndexToCodeRange_[func.index()] = funcCodeRangeIndex;
// Merge the compiled results into the whole-module masm.
DebugOnly<size_t> sizeBefore = masm_.size();
@ -208,10 +326,6 @@ ModuleGenerator::finishTask(IonCompileTask* task)
return false;
MOZ_ASSERT(masm_.size() == offsetInWhole + results.masm().size());
// Add the CodeRange for this function.
if (!module_->codeRanges.emplaceBack(func.index(), func.lineOrBytecode(), results.offsets()))
return false;
// Keep a record of slow functions for printing in the final console message.
unsigned totalTime = func.generateTime() + results.compileTime();
if (totalTime >= SlowFunction::msThreshold) {
@ -223,6 +337,113 @@ ModuleGenerator::finishTask(IonCompileTask* task)
return true;
}
bool
ModuleGenerator::finishCodegen()
{
uint32_t offsetInWhole = masm_.size();
// Generate stubs in a separate MacroAssembler since, otherwise, for modules
// larger than the JumpImmediateRange, even local uses of Label will fail
// due to the large absolute offsets temporarily stored by Label::bind().
Vector<Offsets> entries(cx_);
Vector<ProfilingOffsets> interpExits(cx_);
Vector<ProfilingOffsets> jitExits(cx_);
EnumeratedArray<JumpTarget, JumpTarget::Limit, Offsets> jumpTargets;
Offsets interruptExit;
{
TempAllocator alloc(&lifo_);
MacroAssembler masm(MacroAssembler::AsmJSToken(), alloc);
if (!entries.resize(numExports()))
return false;
for (uint32_t i = 0; i < numExports(); i++) {
uint32_t target = exportMap_->exportFuncIndices[i];
const Sig& sig = module_->exports[i].sig();
entries[i] = GenerateEntry(masm, target, sig, usesHeap());
}
if (!interpExits.resize(numImports()))
return false;
if (!jitExits.resize(numImports()))
return false;
for (uint32_t i = 0; i < numImports(); i++) {
interpExits[i] = GenerateInterpExit(masm, module_->imports[i], i);
jitExits[i] = GenerateJitExit(masm, module_->imports[i], usesHeap());
}
for (JumpTarget target : MakeEnumeratedRange(JumpTarget::Limit))
jumpTargets[target] = GenerateJumpTarget(masm, target);
interruptExit = GenerateInterruptStub(masm);
if (masm.oom() || !masm_.asmMergeWith(masm))
return false;
}
// Adjust each of the resulting Offsets (to account for being merged into
// masm_) and then create code ranges for all the stubs.
for (uint32_t i = 0; i < numExports(); i++) {
entries[i].offsetBy(offsetInWhole);
module_->exports[i].initStubOffset(entries[i].begin);
if (!module_->codeRanges.emplaceBack(CodeRange::Entry, entries[i]))
return false;
}
for (uint32_t i = 0; i < numImports(); i++) {
interpExits[i].offsetBy(offsetInWhole);
module_->imports[i].initInterpExitOffset(interpExits[i].begin);
if (!module_->codeRanges.emplaceBack(CodeRange::ImportInterpExit, interpExits[i]))
return false;
jitExits[i].offsetBy(offsetInWhole);
module_->imports[i].initJitExitOffset(jitExits[i].begin);
if (!module_->codeRanges.emplaceBack(CodeRange::ImportJitExit, jitExits[i]))
return false;
}
for (JumpTarget target : MakeEnumeratedRange(JumpTarget::Limit)) {
jumpTargets[target].offsetBy(offsetInWhole);
if (!module_->codeRanges.emplaceBack(CodeRange::Inline, jumpTargets[target]))
return false;
}
interruptExit.offsetBy(offsetInWhole);
if (!module_->codeRanges.emplaceBack(CodeRange::Inline, interruptExit))
return false;
// The signal handler redirects PC to the out-of-bounds and interrupt stubs.
link_->pod.outOfBoundsOffset = jumpTargets[JumpTarget::OutOfBounds].begin;
link_->pod.interruptOffset = interruptExit.begin;
// Only call convertOutOfRangeBranchesToThunks after all other codegen that may
// emit new jumps to JumpTargets has finished.
if (!convertOutOfRangeBranchesToThunks())
return false;
// Now that all thunks have been generated, patch all the thunks.
for (CallThunk& callThunk : module_->callThunks) {
uint32_t funcIndex = callThunk.u.funcIndex;
callThunk.u.codeRangeIndex = funcIndexToCodeRange_[funcIndex];
masm_.patchThunk(callThunk.offset, funcEntry(funcIndex));
}
for (JumpTarget target : MakeEnumeratedRange(JumpTarget::Limit)) {
for (uint32_t thunkOffset : jumpThunks_[target])
masm_.patchThunk(thunkOffset, jumpTargets[target].begin);
}
// Code-generation is complete!
masm_.finish();
return !masm_.oom();
}
bool
ModuleGenerator::addImport(const Sig& sig, uint32_t globalDataOffset)
{
@ -335,11 +556,12 @@ ModuleGenerator::funcSig(uint32_t funcIndex) const
bool
ModuleGenerator::initImport(uint32_t importIndex, uint32_t sigIndex)
{
MOZ_ASSERT(isAsmJS());
uint32_t globalDataOffset;
if (!allocateGlobalBytes(Module::SizeOfImportExit, sizeof(void*), &globalDataOffset))
return false;
MOZ_ASSERT(isAsmJS());
MOZ_ASSERT(importIndex == module_->imports.length());
if (!addImport(sig(sigIndex), globalDataOffset))
return false;
@ -364,16 +586,6 @@ ModuleGenerator::import(uint32_t index) const
return shared_->imports[index];
}
bool
ModuleGenerator::defineImport(uint32_t index, ProfilingOffsets interpExit, ProfilingOffsets jitExit)
{
Import& import = module_->imports[index];
import.initInterpExitOffset(interpExit.begin);
import.initJitExitOffset(jitExit.begin);
return module_->codeRanges.emplaceBack(CodeRange::ImportInterpExit, interpExit) &&
module_->codeRanges.emplaceBack(CodeRange::ImportJitExit, jitExit);
}
bool
ModuleGenerator::declareExport(UniqueChars fieldName, uint32_t funcIndex, uint32_t* exportIndex)
{
@ -403,39 +615,12 @@ ModuleGenerator::declareExport(UniqueChars fieldName, uint32_t funcIndex, uint32
exportMap_->exportFuncIndices.append(funcIndex);
}
uint32_t
ModuleGenerator::exportFuncIndex(uint32_t index) const
{
return exportMap_->exportFuncIndices[index];
}
uint32_t
ModuleGenerator::exportEntryOffset(uint32_t index) const
{
uint32_t funcIndex = exportMap_->exportFuncIndices[index];
MOZ_ASSERT(funcIsDefined(funcIndex));
return funcEntryOffsets_[funcIndex];
}
const Sig&
ModuleGenerator::exportSig(uint32_t index) const
{
return module_->exports[index].sig();
}
uint32_t
ModuleGenerator::numExports() const
{
return module_->exports.length();
}
bool
ModuleGenerator::defineExport(uint32_t index, Offsets offsets)
{
module_->exports[index].initStubOffset(offsets.begin);
return module_->codeRanges.emplaceBack(CodeRange::Entry, offsets);
}
bool
ModuleGenerator::addMemoryExport(UniqueChars fieldName)
{
@ -561,24 +746,9 @@ ModuleGenerator::finishFuncDefs()
return false;
}
for (uint32_t funcIndex = 0; funcIndex < funcEntryOffsets_.length(); funcIndex++)
for (uint32_t funcIndex = 0; funcIndex < funcIndexToCodeRange_.length(); funcIndex++)
MOZ_ASSERT(funcIsDefined(funcIndex));
// During codegen, all wasm->wasm (internal) calls use AsmJSInternalCallee
// as the call target, which contains the function-index of the target.
// These get recorded in a CallSiteAndTargetVector in the MacroAssembler
// so that we can patch them now that all the function entry offsets are
// known.
for (CallSiteAndTarget& cs : masm_.callSites()) {
if (!cs.isInternal())
continue;
MOZ_ASSERT(cs.kind() == CallSiteDesc::Relative);
uint32_t callerOffset = cs.returnAddressOffset();
uint32_t calleeOffset = funcEntryOffsets_[cs.targetIndex()];
masm_.patchCall(callerOffset, calleeOffset);
}
module_->functionBytes = masm_.size();
finishedFuncs_ = true;
return true;
@ -628,31 +798,10 @@ ModuleGenerator::defineFuncPtrTable(uint32_t index, const Vector<uint32_t>& elem
for (size_t i = 0; i < elemFuncIndices.length(); i++) {
uint32_t funcIndex = elemFuncIndices[i];
MOZ_ASSERT(funcIsDefined(funcIndex));
table.elemOffsets[i] = funcEntryOffsets_[funcIndex];
table.elemOffsets[i] = funcEntry(funcIndex);
}
}
bool
ModuleGenerator::defineInlineStub(Offsets offsets)
{
MOZ_ASSERT(finishedFuncs_);
return module_->codeRanges.emplaceBack(CodeRange::Inline, offsets);
}
void
ModuleGenerator::defineInterruptExit(uint32_t offset)
{
MOZ_ASSERT(finishedFuncs_);
link_->pod.interruptOffset = offset;
}
void
ModuleGenerator::defineOutOfBoundsExit(uint32_t offset)
{
MOZ_ASSERT(finishedFuncs_);
link_->pod.outOfBoundsOffset = offset;
}
bool
ModuleGenerator::finish(CacheableCharsVector&& prettyFuncNames,
UniqueModuleData* module,
@ -663,15 +812,11 @@ ModuleGenerator::finish(CacheableCharsVector&& prettyFuncNames,
MOZ_ASSERT(!activeFunc_);
MOZ_ASSERT(finishedFuncs_);
if (!finishCodegen())
return false;
module_->prettyFuncNames = Move(prettyFuncNames);
if (!GenerateStubs(*this))
return false;
masm_.finish();
if (masm_.oom())
return false;
// Start global data on a new page so JIT code may be given independent
// protection flags. Note assumption that global data starts right after
// code below.

View File

@ -142,8 +142,11 @@ class MOZ_STACK_CLASS ModuleGenerator
LifoAlloc lifo_;
jit::TempAllocator alloc_;
jit::MacroAssembler masm_;
Uint32Vector funcEntryOffsets_;
Uint32Vector funcIndexToCodeRange_;
FuncIndexMap funcIndexToExport_;
uint32_t lastPatchedCallsite_;
uint32_t startOfUnpatchedBranches_;
JumpSiteArray jumpThunks_;
// Parallel compilation
bool parallel_;
@ -158,7 +161,10 @@ class MOZ_STACK_CLASS ModuleGenerator
bool finishOutstandingTask();
bool funcIsDefined(uint32_t funcIndex) const;
uint32_t funcEntry(uint32_t funcIndex) const;
bool convertOutOfRangeBranchesToThunks();
bool finishTask(IonCompileTask* task);
bool finishCodegen();
bool addImport(const Sig& sig, uint32_t globalDataOffset);
bool startedFuncDefs() const { return !!threadView_; }
bool allocateGlobalBytes(uint32_t bytes, uint32_t align, uint32_t* globalDataOffset);
@ -195,15 +201,10 @@ class MOZ_STACK_CLASS ModuleGenerator
bool initImport(uint32_t importIndex, uint32_t sigIndex);
uint32_t numImports() const;
const ModuleImportGeneratorData& import(uint32_t index) const;
bool defineImport(uint32_t index, ProfilingOffsets interpExit, ProfilingOffsets jitExit);
// Exports:
bool declareExport(UniqueChars fieldName, uint32_t funcIndex, uint32_t* exportIndex = nullptr);
uint32_t numExports() const;
uint32_t exportFuncIndex(uint32_t index) const;
uint32_t exportEntryOffset(uint32_t index) const;
const Sig& exportSig(uint32_t index) const;
bool defineExport(uint32_t index, Offsets offsets);
bool addMemoryExport(UniqueChars fieldName);
// Function definitions:
@ -217,11 +218,6 @@ class MOZ_STACK_CLASS ModuleGenerator
uint32_t funcPtrTableGlobalDataOffset(uint32_t index) const;
void defineFuncPtrTable(uint32_t index, const Vector<uint32_t>& elemFuncIndices);
// Stubs:
bool defineInlineStub(Offsets offsets);
void defineInterruptExit(uint32_t offset);
void defineOutOfBoundsExit(uint32_t offset);
// Return a ModuleData object which may be used to construct a Module, the
// StaticLinkData required to call Module::staticallyLink, and the list of
// functions that took a long time to compile.

View File

@ -360,7 +360,7 @@ CodeRange::CodeRange(Kind kind, Offsets offsets)
u.kind_ = kind;
MOZ_ASSERT(begin_ <= end_);
MOZ_ASSERT(u.kind_ == Entry || u.kind_ == Inline);
MOZ_ASSERT(u.kind_ == Entry || u.kind_ == Inline || u.kind_ == CallThunk);
}
CodeRange::CodeRange(Kind kind, ProfilingOffsets offsets)
@ -508,6 +508,7 @@ ModuleData::serializedSize() const
SerializedPodVectorSize(heapAccesses) +
SerializedPodVectorSize(codeRanges) +
SerializedPodVectorSize(callSites) +
SerializedPodVectorSize(callThunks) +
SerializedVectorSize(prettyFuncNames) +
filename.serializedSize();
}
@ -522,6 +523,7 @@ ModuleData::serialize(uint8_t* cursor) const
cursor = SerializePodVector(cursor, heapAccesses);
cursor = SerializePodVector(cursor, codeRanges);
cursor = SerializePodVector(cursor, callSites);
cursor = SerializePodVector(cursor, callThunks);
cursor = SerializeVector(cursor, prettyFuncNames);
cursor = filename.serialize(cursor);
return cursor;
@ -542,6 +544,7 @@ ModuleData::deserialize(ExclusiveContext* cx, const uint8_t* cursor)
(cursor = DeserializePodVector(cx, cursor, &heapAccesses)) &&
(cursor = DeserializePodVector(cx, cursor, &codeRanges)) &&
(cursor = DeserializePodVector(cx, cursor, &callSites)) &&
(cursor = DeserializePodVector(cx, cursor, &callThunks)) &&
(cursor = DeserializeVector(cx, cursor, &prettyFuncNames)) &&
(cursor = filename.deserialize(cx, cursor));
return cursor;
@ -562,6 +565,7 @@ ModuleData::clone(JSContext* cx, ModuleData* out) const
ClonePodVector(cx, heapAccesses, &out->heapAccesses) &&
ClonePodVector(cx, codeRanges, &out->codeRanges) &&
ClonePodVector(cx, callSites, &out->callSites) &&
ClonePodVector(cx, callThunks, &out->callThunks) &&
CloneVector(cx, prettyFuncNames, &out->prettyFuncNames) &&
filename.clone(cx, &out->filename);
}
@ -575,6 +579,7 @@ ModuleData::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const
heapAccesses.sizeOfExcludingThis(mallocSizeOf) +
codeRanges.sizeOfExcludingThis(mallocSizeOf) +
callSites.sizeOfExcludingThis(mallocSizeOf) +
callThunks.sizeOfExcludingThis(mallocSizeOf) +
prettyFuncNames.sizeOfExcludingThis(mallocSizeOf) +
filename.sizeOfExcludingThis(mallocSizeOf);
}
@ -792,6 +797,9 @@ Module::setProfilingEnabled(JSContext* cx, bool enabled)
for (const CallSite& callSite : module_->callSites)
EnableProfilingPrologue(*this, callSite, enabled);
for (const CallThunk& callThunk : module_->callThunks)
EnableProfilingThunk(*this, callThunk, enabled);
for (const CodeRange& codeRange : module_->codeRanges)
EnableProfilingEpilogue(*this, codeRange, enabled);
}

View File

@ -67,9 +67,7 @@ struct StaticLinkData
typedef Vector<InternalLink, 0, SystemAllocPolicy> InternalLinkVector;
typedef Vector<uint32_t, 0, SystemAllocPolicy> OffsetVector;
struct SymbolicLinkArray : mozilla::EnumeratedArray<SymbolicAddress,
SymbolicAddress::Limit,
OffsetVector> {
struct SymbolicLinkArray : EnumeratedArray<SymbolicAddress, SymbolicAddress::Limit, OffsetVector> {
WASM_DECLARE_SERIALIZABLE(SymbolicLinkArray)
};
@ -213,7 +211,7 @@ class CodeRange
void assertValid();
public:
enum Kind { Function, Entry, ImportJitExit, ImportInterpExit, Inline };
enum Kind { Function, Entry, ImportJitExit, ImportInterpExit, Inline, CallThunk };
CodeRange() = default;
CodeRange(Kind kind, Offsets offsets);
@ -237,7 +235,7 @@ class CodeRange
// which is used for asynchronous profiling to determine the frame pointer.
uint32_t profilingReturn() const {
MOZ_ASSERT(kind() != Entry && kind() != Inline);
MOZ_ASSERT(isFunction() || isImportExit());
return profilingReturn_;
}
@ -247,6 +245,9 @@ class CodeRange
bool isFunction() const {
return kind() == Function;
}
bool isImportExit() const {
return kind() == ImportJitExit || kind() == ImportInterpExit;
}
uint32_t funcProfilingEntry() const {
MOZ_ASSERT(isFunction());
return begin();
@ -288,6 +289,25 @@ class CodeRange
typedef Vector<CodeRange, 0, SystemAllocPolicy> CodeRangeVector;
// A CallThunk describes the offset and target of thunks so that they may be
// patched at runtime when profiling is toggled. Thunks are emitted to connect
// callsites that are too far away from callees to fit in a single call
// instruction's relative offset.
struct CallThunk
{
uint32_t offset;
union {
uint32_t funcIndex;
uint32_t codeRangeIndex;
} u;
CallThunk(uint32_t offset, uint32_t funcIndex) : offset(offset) { u.funcIndex = funcIndex; }
CallThunk() = default;
};
typedef Vector<CallThunk, 0, SystemAllocPolicy> CallThunkVector;
// CacheableChars is used to cacheably store UniqueChars.
struct CacheableChars : UniqueChars
@ -389,6 +409,7 @@ struct ModuleData : ModuleCacheablePod
HeapAccessVector heapAccesses;
CodeRangeVector codeRanges;
CallSiteVector callSites;
CallThunkVector callThunks;
CacheableCharsVector prettyFuncNames;
CacheableChars filename;
bool loadedFromCache;
@ -496,6 +517,7 @@ class Module
CompileArgs compileArgs() const { return module_->compileArgs; }
const ImportVector& imports() const { return module_->imports; }
const ExportVector& exports() const { return module_->exports; }
const CodeRangeVector& codeRanges() const { return module_->codeRanges; }
const char* filename() const { return module_->filename.get(); }
bool loadedFromCache() const { return module_->loadedFromCache; }
bool staticallyLinked() const { return staticallyLinked_; }

View File

@ -19,7 +19,6 @@
#include "asmjs/WasmStubs.h"
#include "mozilla/ArrayUtils.h"
#include "mozilla/EnumeratedRange.h"
#include "jit/MacroAssembler-inl.h"
@ -28,7 +27,6 @@ using namespace js::jit;
using namespace js::wasm;
using mozilla::ArrayLength;
using mozilla::MakeEnumeratedRange;
static void
AssertStackAlignment(MacroAssembler& masm, uint32_t alignment, uint32_t addBeforeAssert = 0)
@ -94,12 +92,9 @@ static const unsigned FramePushedForEntrySP = FramePushedAfterSave + sizeof(void
// The signature of the entry point is Module::CodePtr. The exported wasm
// function has an ABI derived from its specific signature, so this function
// must map from the ABI of CodePtr to the export's signature's ABI.
static bool
GenerateEntry(ModuleGenerator& mg, unsigned exportIndex)
Offsets
wasm::GenerateEntry(MacroAssembler& masm, unsigned target, const Sig& sig, bool usesHeap)
{
MacroAssembler& masm = mg.masm();
const Sig& sig = mg.exportSig(exportIndex);
masm.haltingAlign(CodeAlignment);
Offsets offsets;
@ -131,7 +126,7 @@ GenerateEntry(ModuleGenerator& mg, unsigned exportIndex)
// ARM, MIPS/MIPS64 and x64 have a globally-pinned HeapReg (x86 uses immediates in
// effective addresses). Loading the heap register depends on the global
// register already having been loaded.
if (mg.usesHeap())
if (usesHeap)
masm.loadAsmJSHeapRegisterFromGlobalData();
// Put the 'argv' argument into a non-argument/return register so that we
@ -235,9 +230,7 @@ GenerateEntry(ModuleGenerator& mg, unsigned exportIndex)
// Call into the real function.
masm.assertStackAlignment(AsmJSStackAlignment);
Label target;
target.bind(mg.exportEntryOffset(exportIndex));
masm.call(CallSiteDesc(CallSiteDesc::Relative), &target);
masm.call(CallSiteDesc(CallSiteDesc::Relative), AsmJSInternalCallee(target));
// Recover the stack pointer value before dynamic alignment.
masm.loadWasmActivation(scratch);
@ -283,11 +276,8 @@ GenerateEntry(ModuleGenerator& mg, unsigned exportIndex)
masm.move32(Imm32(true), ReturnReg);
masm.ret();
if (masm.oom())
return false;
offsets.end = masm.currentOffset();
return mg.defineExport(exportIndex, offsets);
return offsets;
}
static void
@ -333,11 +323,10 @@ FillArgumentArray(MacroAssembler& masm, const ValTypeVector& args, unsigned argO
// Generate a stub that is called via the internal ABI derived from the
// signature of the import and calls into an appropriate InvokeImport C++
// function, having boxed all the ABI arguments into a homogeneous Value array.
static bool
GenerateInterpExitStub(ModuleGenerator& mg, unsigned importIndex, ProfilingOffsets* offsets)
ProfilingOffsets
wasm::GenerateInterpExit(MacroAssembler& masm, const Import& import, uint32_t importIndex)
{
MacroAssembler& masm = mg.masm();
const Sig& sig = *mg.import(importIndex).sig;
const Sig& sig = import.sig();
masm.setFramePushed(0);
@ -356,7 +345,8 @@ GenerateInterpExitStub(ModuleGenerator& mg, unsigned importIndex, ProfilingOffse
unsigned argBytes = Max<size_t>(1, sig.args().length()) * sizeof(Value);
unsigned framePushed = StackDecrementForCall(masm, ABIStackAlignment, argOffset + argBytes);
GenerateExitPrologue(masm, framePushed, ExitReason::ImportInterp, offsets);
ProfilingOffsets offsets;
GenerateExitPrologue(masm, framePushed, ExitReason::ImportInterp, &offsets);
// Fill the argument array.
unsigned offsetToCallerStackArgs = sizeof(AsmJSFrame) + masm.framePushed();
@ -407,7 +397,6 @@ GenerateInterpExitStub(ModuleGenerator& mg, unsigned importIndex, ProfilingOffse
case ExprType::I64:
MOZ_CRASH("no int64 in asm.js");
case ExprType::F32:
MOZ_ASSERT(!mg.isAsmJS(), "import can't return float32 in asm.js");
masm.call(SymbolicAddress::InvokeImport_F64);
masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, JumpTarget::Throw);
masm.loadDouble(argv, ReturnDoubleReg);
@ -426,13 +415,10 @@ GenerateInterpExitStub(ModuleGenerator& mg, unsigned importIndex, ProfilingOffse
MOZ_CRASH("Limit");
}
GenerateExitEpilogue(masm, framePushed, ExitReason::ImportInterp, offsets);
GenerateExitEpilogue(masm, framePushed, ExitReason::ImportInterp, &offsets);
if (masm.oom())
return false;
offsets->end = masm.currentOffset();
return true;
offsets.end = masm.currentOffset();
return offsets;
}
#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
@ -444,11 +430,10 @@ static const unsigned MaybeSavedGlobalReg = 0;
// Generate a stub that is called via the internal ABI derived from the
// signature of the import and calls into a compatible JIT function,
// having boxed all the ABI arguments into the JIT stack frame layout.
static bool
GenerateJitExitStub(ModuleGenerator& mg, unsigned importIndex, ProfilingOffsets* offsets)
ProfilingOffsets
wasm::GenerateJitExit(MacroAssembler& masm, const Import& import, bool usesHeap)
{
MacroAssembler& masm = mg.masm();
const Sig& sig = *mg.import(importIndex).sig;
const Sig& sig = import.sig();
masm.setFramePushed(0);
@ -465,7 +450,8 @@ GenerateJitExitStub(ModuleGenerator& mg, unsigned importIndex, ProfilingOffsets*
unsigned jitFramePushed = StackDecrementForCall(masm, JitStackAlignment, totalJitFrameBytes) -
sizeOfRetAddr;
GenerateExitPrologue(masm, jitFramePushed, ExitReason::ImportJit, offsets);
ProfilingOffsets offsets;
GenerateExitPrologue(masm, jitFramePushed, ExitReason::ImportJit, &offsets);
// 1. Descriptor
size_t argOffset = 0;
@ -479,7 +465,7 @@ GenerateJitExitStub(ModuleGenerator& mg, unsigned importIndex, ProfilingOffsets*
Register scratch = ABIArgGenerator::NonArgReturnReg1; // repeatedly clobbered
// 2.1. Get ExitDatum
unsigned globalDataOffset = mg.import(importIndex).globalDataOffset;
uint32_t globalDataOffset = import.exitGlobalDataOffset();
#if defined(JS_CODEGEN_X64)
masm.append(AsmJSGlobalAccess(masm.leaRipRelative(callee), globalDataOffset));
#elif defined(JS_CODEGEN_X86)
@ -663,7 +649,6 @@ GenerateJitExitStub(ModuleGenerator& mg, unsigned importIndex, ProfilingOffsets*
case ExprType::I64:
MOZ_CRASH("no int64 in asm.js");
case ExprType::F32:
MOZ_ASSERT(!mg.isAsmJS(), "import can't return float32 in asm.js");
masm.convertValueToFloat(JSReturnOperand, ReturnFloat32Reg, &oolConvert);
break;
case ExprType::F64:
@ -682,10 +667,10 @@ GenerateJitExitStub(ModuleGenerator& mg, unsigned importIndex, ProfilingOffsets*
// Ion code does not respect system callee-saved register conventions so
// reload the heap register.
if (mg.usesHeap())
if (usesHeap)
masm.loadAsmJSHeapRegisterFromGlobalData();
GenerateExitEpilogue(masm, masm.framePushed(), ExitReason::ImportJit, offsets);
GenerateExitEpilogue(masm, masm.framePushed(), ExitReason::ImportJit, &offsets);
if (oolConvert.used()) {
masm.bind(&oolConvert);
@ -728,7 +713,6 @@ GenerateJitExitStub(ModuleGenerator& mg, unsigned importIndex, ProfilingOffsets*
masm.loadDouble(Address(masm.getStackPointer(), offsetToCoerceArgv), ReturnDoubleReg);
break;
case ExprType::F32:
MOZ_ASSERT(!mg.isAsmJS(), "import can't return float32 in asm.js");
masm.call(SymbolicAddress::CoerceInPlace_ToNumber);
masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, JumpTarget::Throw);
masm.loadDouble(Address(masm.getStackPointer(), offsetToCoerceArgv), ReturnDoubleReg);
@ -744,37 +728,18 @@ GenerateJitExitStub(ModuleGenerator& mg, unsigned importIndex, ProfilingOffsets*
MOZ_ASSERT(masm.framePushed() == 0);
if (masm.oom())
return false;
offsets->end = masm.currentOffset();
return true;
}
static void
BindJumps(MacroAssembler& masm, JumpTarget target)
{
for (uint32_t offset : masm.jumpSites()[target]) {
RepatchLabel label;
label.use(offset);
masm.bind(&label);
}
offsets.end = masm.currentOffset();
return offsets;
}
// Generate a stub that is called immediately after the prologue when there is a
// stack overflow. This stub calls a C++ function to report the error and then
// jumps to the throw stub to pop the activation.
static bool
GenerateStackOverflowStub(ModuleGenerator& mg)
static Offsets
GenerateStackOverflow(MacroAssembler& masm)
{
MacroAssembler& masm = mg.masm();
masm.haltingAlign(CodeAlignment);
if (masm.jumpSites()[JumpTarget::StackOverflow].empty())
return true;
BindJumps(masm, JumpTarget::StackOverflow);
Offsets offsets;
offsets.begin = masm.currentOffset();
@ -797,27 +762,18 @@ GenerateStackOverflowStub(ModuleGenerator& mg)
masm.call(SymbolicAddress::ReportOverRecursed);
masm.jump(JumpTarget::Throw);
if (masm.oom())
return false;
offsets.end = masm.currentOffset();
return mg.defineInlineStub(offsets);
return offsets;
}
// Generate a stub that is jumped to from an out-of-bounds heap access when
// there are throwing semantics. This stub calls a C++ function to report an
// error and then jumps to the throw stub to pop the activation.
static bool
GenerateConversionErrorStub(ModuleGenerator& mg)
static Offsets
GenerateConversionError(MacroAssembler& masm)
{
MacroAssembler& masm = mg.masm();
masm.haltingAlign(CodeAlignment);
if (masm.jumpSites()[JumpTarget::ConversionError].empty())
return true;
BindJumps(masm, JumpTarget::ConversionError);
Offsets offsets;
offsets.begin = masm.currentOffset();
@ -830,28 +786,18 @@ GenerateConversionErrorStub(ModuleGenerator& mg)
masm.call(SymbolicAddress::OnImpreciseConversion);
masm.jump(JumpTarget::Throw);
if (masm.oom())
return false;
offsets.end = masm.currentOffset();
return mg.defineInlineStub(offsets);
return offsets;
}
// Generate a stub that is jumped to from an out-of-bounds heap access when
// there are throwing semantics. This stub calls a C++ function to report an
// error and then jumps to the throw stub to pop the activation.
static bool
GenerateOutOfBoundsStub(ModuleGenerator& mg)
static Offsets
GenerateOutOfBounds(MacroAssembler& masm)
{
MacroAssembler& masm = mg.masm();
masm.haltingAlign(CodeAlignment);
// Generate the out-of-bounds stub unconditionally since it may always be
// used by the signal handler.
mg.defineOutOfBoundsExit(masm.currentOffset());
BindJumps(masm, JumpTarget::OutOfBounds);
Offsets offsets;
offsets.begin = masm.currentOffset();
@ -864,11 +810,54 @@ GenerateOutOfBoundsStub(ModuleGenerator& mg)
masm.call(SymbolicAddress::OnOutOfBounds);
masm.jump(JumpTarget::Throw);
if (masm.oom())
return false;
offsets.end = masm.currentOffset();
return offsets;
}
// If an exception is thrown, simply pop all frames (since asm.js does not
// contain try/catch). To do this:
// 1. Restore 'sp' to it's value right after the PushRegsInMask in GenerateEntry.
// 2. PopRegsInMask to restore the caller's non-volatile registers.
// 3. Return (to CallAsmJS).
static Offsets
GenerateThrow(MacroAssembler& masm)
{
masm.haltingAlign(CodeAlignment);
Offsets offsets;
offsets.begin = masm.currentOffset();
// We are about to pop all frames in this WasmActivation. Set fp to null to
// maintain the invariant that fp is either null or pointing to a valid
// frame.
Register scratch = ABIArgGenerator::NonArgReturnReg0;
masm.loadWasmActivation(scratch);
masm.storePtr(ImmWord(0), Address(scratch, WasmActivation::offsetOfFP()));
masm.setFramePushed(FramePushedForEntrySP);
masm.loadStackPtr(Address(scratch, WasmActivation::offsetOfEntrySP()));
masm.Pop(scratch);
masm.PopRegsInMask(NonVolatileRegs);
MOZ_ASSERT(masm.framePushed() == 0);
masm.mov(ImmWord(0), ReturnReg);
masm.ret();
offsets.end = masm.currentOffset();
return mg.defineInlineStub(offsets);
return offsets;
}
Offsets
wasm::GenerateJumpTarget(MacroAssembler& masm, JumpTarget target)
{
switch (target) {
case JumpTarget::StackOverflow: return GenerateStackOverflow(masm);
case JumpTarget::ConversionError: return GenerateConversionError(masm);
case JumpTarget::OutOfBounds: return GenerateOutOfBounds(masm);
case JumpTarget::Throw: return GenerateThrow(masm);
case JumpTarget::Limit: break;
}
MOZ_CRASH("bad JumpTarget");
}
static const LiveRegisterSet AllRegsExceptSP(
@ -884,16 +873,11 @@ static const LiveRegisterSet AllRegsExceptSP(
// Unfortunately, loading this requires a scratch register which we don't have
// after restoring all registers. To hack around this, push the resumePC on the
// stack so that it can be popped directly into PC.
static bool
GenerateInterruptStub(ModuleGenerator& mg)
Offsets
wasm::GenerateInterruptStub(MacroAssembler& masm)
{
MacroAssembler& masm = mg.masm();
masm.haltingAlign(CodeAlignment);
// Generate the interrupt stub unconditionally since it may always be used
// by the signal handler.
mg.defineInterruptExit(masm.currentOffset());
Offsets offsets;
offsets.begin = masm.currentOffset();
@ -1040,89 +1024,6 @@ GenerateInterruptStub(ModuleGenerator& mg)
# error "Unknown architecture!"
#endif
if (masm.oom())
return false;
offsets.end = masm.currentOffset();
return mg.defineInlineStub(offsets);
return offsets;
}
// If an exception is thrown, simply pop all frames (since asm.js does not
// contain try/catch). To do this:
// 1. Restore 'sp' to it's value right after the PushRegsInMask in GenerateEntry.
// 2. PopRegsInMask to restore the caller's non-volatile registers.
// 3. Return (to CallAsmJS).
static bool
GenerateThrowStub(ModuleGenerator& mg)
{
MacroAssembler& masm = mg.masm();
masm.haltingAlign(CodeAlignment);
if (masm.jumpSites()[JumpTarget::Throw].empty())
return true;
BindJumps(masm, JumpTarget::Throw);
Offsets offsets;
offsets.begin = masm.currentOffset();
// We are about to pop all frames in this WasmActivation. Set fp to null to
// maintain the invariant that fp is either null or pointing to a valid
// frame.
Register scratch = ABIArgGenerator::NonArgReturnReg0;
masm.loadWasmActivation(scratch);
masm.storePtr(ImmWord(0), Address(scratch, WasmActivation::offsetOfFP()));
masm.setFramePushed(FramePushedForEntrySP);
masm.loadStackPtr(Address(scratch, WasmActivation::offsetOfEntrySP()));
masm.Pop(scratch);
masm.PopRegsInMask(NonVolatileRegs);
MOZ_ASSERT(masm.framePushed() == 0);
masm.mov(ImmWord(0), ReturnReg);
masm.ret();
if (masm.oom())
return false;
offsets.end = masm.currentOffset();
return mg.defineInlineStub(offsets);
}
bool
wasm::GenerateStubs(ModuleGenerator& mg)
{
for (unsigned i = 0; i < mg.numExports(); i++) {
if (!GenerateEntry(mg, i))
return false;
}
for (size_t i = 0; i < mg.numImports(); i++) {
ProfilingOffsets interp;
if (!GenerateInterpExitStub(mg, i, &interp))
return false;
ProfilingOffsets jit;
if (!GenerateJitExitStub(mg, i, &jit))
return false;
if (!mg.defineImport(i, interp, jit))
return false;
}
if (!GenerateStackOverflowStub(mg))
return false;
if (!GenerateConversionErrorStub(mg))
return false;
if (!GenerateOutOfBoundsStub(mg))
return false;
if (!GenerateInterruptStub(mg))
return false;
// The throw stub must go last since the other stubs use it.
return GenerateThrowStub(mg);
}

View File

@ -24,8 +24,20 @@
namespace js {
namespace wasm {
bool
GenerateStubs(ModuleGenerator& mg);
extern Offsets
GenerateEntry(jit::MacroAssembler& masm, uint32_t target, const Sig& sig, bool usesHeap);
extern ProfilingOffsets
GenerateInterpExit(jit::MacroAssembler& masm, const Import& import, uint32_t importIndex);
extern ProfilingOffsets
GenerateJitExit(jit::MacroAssembler& masm, const Import& import, bool usesHeap);
extern Offsets
GenerateJumpTarget(jit::MacroAssembler& masm, JumpTarget target);
extern Offsets
GenerateInterruptStub(jit::MacroAssembler& masm);
} // namespace wasm
} // namespace js

View File

@ -38,6 +38,7 @@ class PropertyName;
namespace wasm {
using mozilla::EnumeratedArray;
using mozilla::Move;
using mozilla::DebugOnly;
using mozilla::MallocSizeOf;
@ -266,7 +267,7 @@ typedef Vector<const DeclaredSig*, 0, SystemAllocPolicy> DeclaredSigPtrVector;
struct Offsets
{
MOZ_IMPLICIT Offsets(uint32_t begin = 0, uint32_t end = 0)
explicit Offsets(uint32_t begin = 0, uint32_t end = 0)
: begin(begin), end(end)
{}
@ -571,7 +572,7 @@ enum class JumpTarget
Limit
};
typedef mozilla::EnumeratedArray<JumpTarget, JumpTarget::Limit, Uint32Vector> JumpSiteArray;
typedef EnumeratedArray<JumpTarget, JumpTarget::Limit, Uint32Vector> JumpSiteArray;
// The CompileArgs struct captures global parameters that affect all wasm code
// generation. It also currently is the single source of truth for whether or

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