mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
merge mozilla-inbound to mozilla-central a=merge
This commit is contained in:
commit
d80c849001
@ -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();
|
||||
|
@ -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
|
||||
}
|
||||
]
|
||||
|
@ -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
|
||||
}
|
||||
]
|
||||
|
@ -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
|
||||
}
|
||||
]
|
||||
|
@ -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
|
||||
}
|
||||
]
|
||||
|
@ -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
|
||||
}
|
||||
]
|
||||
|
@ -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
|
||||
}
|
||||
]
|
||||
|
@ -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
|
||||
}
|
||||
]
|
||||
|
@ -7,8 +7,8 @@
|
||||
"unpack": true
|
||||
},
|
||||
{
|
||||
"size": 11179576,
|
||||
"digest": "91567ce8e2bb8ab0ebc60c31e90731d88a1ea889fb71bcf55c735746a60fa7610b7e040ea3d8f727b6f692ae3ee703d6f3b30cdbd76fdf5617f77d9c38aa20ed",
|
||||
"size": 11189216,
|
||||
"digest": "18bc52b0599b1308b667e282abb45f47597bfc98a5140cfcab8da71dacf89dd76d0dee22a04ce26fe7ad1f04e2d6596991f9e5b01fd2aaaab5542965f596b0e6",
|
||||
"algorithm": "sha512",
|
||||
"filename": "gtk3.tar.xz",
|
||||
"setup": "setup.sh",
|
||||
|
@ -7,8 +7,8 @@
|
||||
"unpack": true
|
||||
},
|
||||
{
|
||||
"size": 12057960,
|
||||
"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e",
|
||||
"size": 12072532,
|
||||
"digest": "3915f8ec396c56a8a92e6f9695b70f09ce9d1582359d1258e37e3fd43a143bc974410e4cfc27f500e095f34a8956206e0ebf799b7287f0f38def0d5e34ed71c9",
|
||||
"algorithm": "sha512",
|
||||
"filename": "gtk3.tar.xz",
|
||||
"setup": "setup.sh",
|
||||
|
@ -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");
|
||||
|
||||
|
@ -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");
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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'] += [
|
||||
|
@ -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
|
||||
},
|
||||
{
|
||||
|
@ -10,8 +10,8 @@
|
||||
"unpack": true
|
||||
},
|
||||
{
|
||||
"size": 12057960,
|
||||
"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e",
|
||||
"size": 12072532,
|
||||
"digest": "3915f8ec396c56a8a92e6f9695b70f09ce9d1582359d1258e37e3fd43a143bc974410e4cfc27f500e095f34a8956206e0ebf799b7287f0f38def0d5e34ed71c9",
|
||||
"algorithm": "sha512",
|
||||
"filename": "gtk3.tar.xz",
|
||||
"setup": "setup.sh",
|
||||
|
@ -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
|
||||
},
|
||||
{
|
||||
|
@ -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
|
||||
}
|
||||
]
|
||||
|
@ -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
|
||||
},
|
||||
{
|
||||
|
@ -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
|
||||
}
|
||||
]
|
||||
|
@ -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())
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -226,7 +226,7 @@ this.AppsUtils = {
|
||||
deferred.resolve(file);
|
||||
}
|
||||
});
|
||||
aRequestChannel.asyncOpen(listener, null);
|
||||
aRequestChannel.asyncOpen2(listener);
|
||||
|
||||
return deferred.promise;
|
||||
},
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -219,7 +219,7 @@ ShadowRoot::RemoveFromIdTable(Element* aElement, nsIAtom* aId)
|
||||
if (entry) {
|
||||
entry->RemoveIdElement(aElement);
|
||||
if (entry->IsEmpty()) {
|
||||
mIdentifierMap.RawRemoveEntry(entry);
|
||||
mIdentifierMap.RemoveEntry(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -3003,7 +3003,7 @@ nsDocument::RemoveFromIdTable(Element *aElement, nsIAtom* aId)
|
||||
++mExpandoAndGeneration.generation;
|
||||
}
|
||||
if (entry->IsEmpty()) {
|
||||
mIdentifierMap.RawRemoveEntry(entry);
|
||||
mIdentifierMap.RemoveEntry(entry);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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")
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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,6 +12411,7 @@ class CGDictionary(CGThing):
|
||||
methods.append(self.initFromJSONMethod())
|
||||
try:
|
||||
methods.append(self.toObjectInternalMethod())
|
||||
if self.dictionarySafeToJSONify(self.dictionary):
|
||||
methods.append(self.toJSONMethod())
|
||||
except MethodNotNewObjectError:
|
||||
# If we can't have a ToObjectInternal() because one of our members
|
||||
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
// This simply returns null if there is no principal available
|
||||
// for the requested uri. This is an acceptable fallback when
|
||||
// calling newChannelFromURI2.
|
||||
principal =
|
||||
let referrer = Services.io.newURI(_options.referrer, null, null);
|
||||
let 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;
|
||||
},
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
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) {
|
||||
createHandlerWithTypeCheck(eventInfo.legacy_name, function(e) {
|
||||
is(e, eventSentToTarget,
|
||||
"Same event object should bubble, " +
|
||||
"despite difference in type");
|
||||
"Same event object should bubble, despite difference in type");
|
||||
didEventFireOnParent = true;
|
||||
}));
|
||||
|
||||
grandparent.addEventListener(eventInfo.modern_name,
|
||||
createHandlerWithTypeCheck(eventInfo.modern_name,
|
||||
function(e) {
|
||||
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);
|
||||
"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) {
|
||||
|
@ -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 });
|
||||
|
@ -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;
|
||||
|
@ -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:,
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -45,6 +45,9 @@ AllocPBackgroundIndexedDBUtilsParent();
|
||||
bool
|
||||
DeallocPBackgroundIndexedDBUtilsParent(PBackgroundIndexedDBUtilsParent* aActor);
|
||||
|
||||
bool
|
||||
RecvFlushPendingFileDeletions();
|
||||
|
||||
PIndexedDBPermissionRequestParent*
|
||||
AllocPIndexedDBPermissionRequestParent(Element* aOwnerElement,
|
||||
nsIPrincipal* aPrincipal);
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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]
|
||||
|
@ -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()
|
||||
{
|
||||
|
@ -1045,9 +1045,6 @@ private:
|
||||
virtual bool
|
||||
DeallocPFileDescriptorSetParent(PFileDescriptorSetParent*) override;
|
||||
|
||||
virtual bool
|
||||
RecvFlushPendingFileDeletions() override;
|
||||
|
||||
virtual PWebrtcGlobalParent* AllocPWebrtcGlobalParent() override;
|
||||
virtual bool DeallocPWebrtcGlobalParent(PWebrtcGlobalParent *aActor) override;
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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();
|
||||
});
|
||||
});
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
if (mThread) {
|
||||
mThread->Shutdown();
|
||||
mThread = nullptr;
|
||||
}
|
||||
|
||||
if (mDecoder) {
|
||||
mDecoder->Stop();
|
||||
mDecoder->Release();
|
||||
mDecoder = nullptr;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -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();
|
||||
|
73
dom/media/test/external/mach_commands.py
vendored
Normal file
73
dom/media/test/external/mach_commands.py
vendored
Normal 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)
|
6
dom/media/test/external/requirements.txt
vendored
6
dom/media/test/external/requirements.txt
vendored
@ -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
|
||||
./
|
||||
|
6
dom/media/test/external/setup.py
vendored
6
dom/media/test/external/setup.py
vendored
@ -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',
|
||||
|
@ -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();
|
||||
});
|
||||
});
|
||||
|
32
dom/media/webspeech/synth/crashtests/1230428.html
Normal file
32
dom/media/webspeech/synth/crashtests/1230428.html
Normal 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>
|
1
dom/media/webspeech/synth/crashtests/crashtests.list
Normal file
1
dom/media/webspeech/synth/crashtests/crashtests.list
Normal file
@ -0,0 +1 @@
|
||||
skip-if(!cocoaWidget) pref(media.webspeech.synth.enabled,true) load 1230428.html # bug 1230428
|
@ -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:
|
||||
|
@ -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)
|
||||
|
@ -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?!");
|
||||
|
||||
|
@ -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)));
|
||||
|
||||
|
@ -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,55 +37,59 @@ 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,
|
||||
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();
|
||||
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);
|
||||
return NS_OK;
|
||||
@ -92,11 +98,18 @@ RegisterWorkerDebugger(WorkerPrivate* aWorkerPrivate)
|
||||
inline nsresult
|
||||
UnregisterWorkerDebugger(WorkerPrivate* aWorkerPrivate)
|
||||
{
|
||||
RefPtr<WorkerDebuggerManager> manager =
|
||||
WorkerDebuggerManager::GetOrCreateService();
|
||||
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);
|
||||
return NS_OK;
|
||||
|
@ -1832,7 +1832,7 @@ XULDocument::RemoveElementFromRefMap(Element* aElement)
|
||||
if (!entry)
|
||||
return;
|
||||
if (entry->RemoveElement(aElement)) {
|
||||
mRefMap.RawRemoveEntry(entry);
|
||||
mRefMap.RemoveEntry(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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()
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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]
|
||||
|
231
gfx/layers/apz/test/mochitest/test_frame_reconstruction.html
Normal file
231
gfx/layers/apz/test/mochitest/test_frame_reconstruction.html
Normal 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>
|
@ -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]
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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*
|
||||
|
@ -58,6 +58,9 @@ protected:
|
||||
PBackgroundIndexedDBUtilsParent* aActor)
|
||||
override;
|
||||
|
||||
virtual bool
|
||||
RecvFlushPendingFileDeletions() override;
|
||||
|
||||
virtual PBlobParent*
|
||||
AllocPBlobParent(const BlobConstructorParams& aParams) override;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -66,6 +66,9 @@ parent:
|
||||
|
||||
async PBackgroundIndexedDBUtils();
|
||||
|
||||
// Use only for testing!
|
||||
async FlushPendingFileDeletions();
|
||||
|
||||
async PVsync();
|
||||
|
||||
async PCameras();
|
||||
|
@ -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) \
|
||||
|
@ -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.
|
||||
|
@ -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(§ionStart))
|
||||
return Fail(cx, d, "expected data section byte size");
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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_; }
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user