merge mozilla-inbound to mozilla-central a=merge

This commit is contained in:
Carsten "Tomcat" Book 2016-08-02 17:09:31 +02:00
Родитель f470e82ee2 02adb43791
Коммит bd81ddd0b0
2214 изменённых файлов: 27832 добавлений и 6351 удалений

Просмотреть файл

@ -10,8 +10,6 @@ var testData = [
[ 'http://example.com/search?oe=utf-8', 'q', 'http://example.com/search?oe=utf-8&q=%s' ],
];
var mm = gBrowser.selectedBrowser.messageManager;
add_task(function*() {
yield BrowserTestUtils.withNewTab({
gBrowser,
@ -23,6 +21,8 @@ add_task(function*() {
doc.head.appendChild(base);
});
var mm = browser.messageManager;
for (let [baseURI, fieldName, expected] of testData) {
let popupShownPromise = BrowserTestUtils.waitForEvent(document.getElementById("contentAreaContextMenu"),
"popupshown");

Просмотреть файл

@ -8,14 +8,32 @@ var testPage3 = "<html id='html3'><body id='body3'><button id='button3'>Tab 3</b
const fm = Services.focus;
function EventStore() {
this["main-window"] = [];
this["window1"] = [];
this["window2"] = [];
};
EventStore.prototype = {
"push": function (event) {
if (event.indexOf("1") > -1) {
this["window1"].push(event);
} else if (event.indexOf("2") > -1) {
this["window2"].push(event);
} else {
this["main-window"].push(event);
}
}
}
var tab1 = null;
var tab2 = null;
var browser1 = null;
var browser2 = null;
var _browser_tabfocus_test_lastfocus;
var _browser_tabfocus_test_lastfocuswindow = null;
var actualEvents = [];
var expectedEvents = [];
var _lastfocus;
var _lastfocuswindow = null;
var actualEvents = new EventStore();
var expectedEvents = new EventStore();
var currentTestName = "";
var _expectedElement = null;
var _expectedWindow = null;
@ -138,8 +156,8 @@ add_task(function*() {
});
}
_browser_tabfocus_test_lastfocus = "urlbar";
_browser_tabfocus_test_lastfocuswindow = "main-window";
_lastfocus = "urlbar";
_lastfocuswindow = "main-window";
window.addEventListener("focus", _browser_tabfocus_test_eventOccured, true);
window.addEventListener("blur", _browser_tabfocus_test_eventOccured, true);
@ -329,9 +347,9 @@ add_task(function*() {
// Document navigation with F6 does not yet work in mutli-process browsers.
if (!gMultiProcessBrowser) {
gURLBar.focus();
actualEvents = [];
_browser_tabfocus_test_lastfocus = "urlbar";
_browser_tabfocus_test_lastfocuswindow = "main-window";
actualEvents = new EventStore();
_lastfocus = "urlbar";
_lastfocuswindow = "main-window";
yield expectFocusShift(() => EventUtils.synthesizeKey("VK_F6", { }),
"window1", "html1",
@ -416,26 +434,19 @@ function compareFocusResults()
if (!currentPromiseResolver)
return;
if (actualEvents.length < expectedEvents.length)
return;
let winIds = ["main-window", "window1", "window2"];
for (let e = 0; e < expectedEvents.length; e++) {
// When remote browsers are used, the child process events can occur before or after the
// browser focusing. Allow either order.
if (gMultiProcessBrowser && actualEvents[e] != expectedEvents[e] &&
actualEvents[e].startsWith("focus: browser")) {
// Ensure that this event is expected later, and remove the later expected event and
// reinsert it at the current index.
let foundLaterIndex = expectedEvents.indexOf(actualEvents[e], e + 1);
if (foundLaterIndex > e) {
expectedEvents.splice(e, 0, expectedEvents.splice(foundLaterIndex, 1)[0]);
}
}
is(actualEvents[e], expectedEvents[e], currentTestName + " events [event " + e + "]");
for (let winId of winIds) {
if (actualEvents[winId].length < expectedEvents[winId].length)
return;
}
for (let winId of winIds) {
for (let e = 0; e < expectedEvents.length; e++) {
is(actualEvents[winId][e], expectedEvents[winId][e], currentTestName + " events [event " + e + "]");
}
actualEvents[winId] = [];
}
actualEvents = [];
// Use executeSoon as this will be called during a focus/blur event handler
executeSoon(() => {
@ -480,7 +491,7 @@ function* expectFocusShift(callback, expectedWindow, expectedElement, focusChang
currentPromiseResolver = null;
currentTestName = testid;
expectedEvents = [];
expectedEvents = new EventStore();
if (focusChanged) {
_expectedElement = expectedElement;
@ -498,34 +509,34 @@ function* expectFocusShift(callback, expectedWindow, expectedElement, focusChang
_expectedWindow = "main-window";
}
if (gMultiProcessBrowser && _browser_tabfocus_test_lastfocuswindow != "main-window" &&
_browser_tabfocus_test_lastfocuswindow != expectedWindow) {
let browserid = _browser_tabfocus_test_lastfocuswindow == "window1" ? "browser1" : "browser2";
if (gMultiProcessBrowser && _lastfocuswindow != "main-window" &&
_lastfocuswindow != expectedWindow) {
let browserid = _lastfocuswindow == "window1" ? "browser1" : "browser2";
expectedEvents.push("blur: " + browserid);
}
var newElementIsFocused = (expectedElement && !expectedElement.startsWith("html"));
if (newElementIsFocused && gMultiProcessBrowser &&
_browser_tabfocus_test_lastfocuswindow != "main-window" &&
_lastfocuswindow != "main-window" &&
expectedWindow == "main-window") {
// When switching from a child to a chrome element, the focus on the element will arrive first.
expectedEvents.push("focus: " + expectedElement);
newElementIsFocused = false;
}
if (_browser_tabfocus_test_lastfocus && _browser_tabfocus_test_lastfocus != _expectedElement)
expectedEvents.push("blur: " + _browser_tabfocus_test_lastfocus);
if (_lastfocus && _lastfocus != _expectedElement)
expectedEvents.push("blur: " + _lastfocus);
if (_browser_tabfocus_test_lastfocuswindow &&
_browser_tabfocus_test_lastfocuswindow != expectedWindow) {
if (_lastfocuswindow &&
_lastfocuswindow != expectedWindow) {
if (!gMultiProcessBrowser || _browser_tabfocus_test_lastfocuswindow != "main-window") {
expectedEvents.push("blur: " + _browser_tabfocus_test_lastfocuswindow + "-document");
expectedEvents.push("blur: " + _browser_tabfocus_test_lastfocuswindow + "-window");
if (!gMultiProcessBrowser || _lastfocuswindow != "main-window") {
expectedEvents.push("blur: " + _lastfocuswindow + "-document");
expectedEvents.push("blur: " + _lastfocuswindow + "-window");
}
}
if (expectedWindow && _browser_tabfocus_test_lastfocuswindow != expectedWindow) {
if (expectedWindow && _lastfocuswindow != expectedWindow) {
if (gMultiProcessBrowser && expectedWindow != "main-window") {
let browserid = expectedWindow == "window1" ? "browser1" : "browser2";
expectedEvents.push("focus: " + browserid);
@ -541,8 +552,8 @@ function* expectFocusShift(callback, expectedWindow, expectedElement, focusChang
expectedEvents.push("focus: " + expectedElement);
}
_browser_tabfocus_test_lastfocus = expectedElement;
_browser_tabfocus_test_lastfocuswindow = expectedWindow;
_lastfocus = expectedElement;
_lastfocuswindow = expectedWindow;
}
return new Promise((resolve, reject) => {
@ -550,7 +561,7 @@ function* expectFocusShift(callback, expectedWindow, expectedElement, focusChang
callback();
// No events are expected, so resolve the promise immediately.
if (!expectedEvents.length) {
if (expectedEvents["main-window"].length + expectedEvents["window1"].length + expectedEvents["window2"].length == 0) {
currentPromiseResolver();
currentPromiseResolver = null;
}

Просмотреть файл

@ -8,10 +8,14 @@ requestLongerTimeout(10);
const PAGE_1 = "data:text/html,<html><body>A%20regular,%20everyday,%20normal%20page.";
const PAGE_2 = "data:text/html,<html><body>Another%20regular,%20everyday,%20normal%20page.";
// Turn off tab animations for testing
Services.prefs.setBoolPref("browser.tabs.animate", false);
registerCleanupFunction(() => {
Services.prefs.clearUserPref("browser.tabs.animate");
// Turn off tab animations for testing and use a single content process
// for these tests since we want to test tabs within the crashing process here.
add_task(function* test_initialize() {
yield SpecialPowers.pushPrefEnv({
set: [
[ "dom.ipc.processCount", 1 ],
[ "browser.tabs.animate", false]
] });
});
// Allow tabs to restore on demand so we can test pending states

Просмотреть файл

@ -30,8 +30,8 @@
},
{
"version": "Visual Studio 2015 Update 2 / SDK 10.0.10586.0/212",
"size": 332343834,
"digest": "55814aaabcd4aa51fe85918ec02a8c29bc067d41ee79ddcfd628daaba5a06d4241a73a51bf5a8bc69cc762b52551009f44b05e65682c45b4684c17fb2d017c2c",
"size": 332442800,
"digest": "995394a4a515c7cb0f8595f26f5395361a638870dd0bbfcc22193fe1d98a0c47126057d5999cc494f3f3eac5cb49160e79757c468f83ee5797298e286ef6252c",
"algorithm": "sha512",
"filename": "vs2015u2.zip",
"unpack": true

Просмотреть файл

@ -31,8 +31,8 @@
},
{
"version": "Visual Studio 2015 Update 2 / SDK 10.0.10586.0/212",
"size": 332343834,
"digest": "55814aaabcd4aa51fe85918ec02a8c29bc067d41ee79ddcfd628daaba5a06d4241a73a51bf5a8bc69cc762b52551009f44b05e65682c45b4684c17fb2d017c2c",
"size": 332442800,
"digest": "995394a4a515c7cb0f8595f26f5395361a638870dd0bbfcc22193fe1d98a0c47126057d5999cc494f3f3eac5cb49160e79757c468f83ee5797298e286ef6252c",
"algorithm": "sha512",
"filename": "vs2015u2.zip",
"unpack": true

Просмотреть файл

@ -25,7 +25,6 @@ case "$target" in
if test -z "$CXX"; then CXX=cl; fi
if test -z "$CPP"; then CPP="$CC -E -nologo"; fi
if test -z "$CXXCPP"; then CXXCPP="$CXX -TP -E -nologo"; ac_cv_prog_CXXCPP="$CXXCPP"; fi
if test -z "$LD"; then LD=link; fi
if test -z "$AS"; then
case "${target_cpu}" in
i*86)

Просмотреть файл

@ -61,6 +61,49 @@ def is_absolute_or_relative(path):
def normsep(path):
return mozpath.normsep(path)
@imports('ctypes')
@imports(_from='ctypes', _import='wintypes')
def get_GetShortPathNameW():
GetShortPathNameW = ctypes.windll.kernel32.GetShortPathNameW
GetShortPathNameW.argtypes = [wintypes.LPCWSTR, wintypes.LPWSTR,
wintypes.DWORD]
GetShortPathNameW.restype = wintypes.DWORD
return GetShortPathNameW
@template
@imports('ctypes')
@imports('platform')
@imports(_from='mozbuild.shellutil', _import='quote')
def normalize_path():
# Until the build system can properly handle programs that need quoting,
# transform those paths into their short version on Windows (e.g.
# c:\PROGRA~1...).
if platform.system() == 'Windows':
GetShortPathNameW = get_GetShortPathNameW()
def normalize_path(path):
path = normsep(path)
if quote(path) == path:
return path
size = 0
while True:
out = ctypes.create_unicode_buffer(size)
needed = GetShortPathNameW(path, out, size)
if size >= needed:
return normsep(out.value)
size = needed
else:
def normalize_path(path):
return normsep(path)
return normalize_path
normalize_path = normalize_path()
# Locates the given program using which, or returns the given path if it
# exists.
# The `paths` parameter may be passed to search the given paths instead of
@ -72,15 +115,15 @@ def normsep(path):
def find_program(file, paths=None):
try:
if is_absolute_or_relative(file):
return normsep(which(os.path.basename(file),
[os.path.dirname(file)]))
return normalize_path(which(os.path.basename(file),
[os.path.dirname(file)]))
if paths:
if not isinstance(paths, (list, tuple)):
die("Paths provided to find_program must be a list of strings, "
"not %r", paths)
paths = list(itertools.chain(
*(p.split(pathsep) for p in paths if p)))
return normsep(which(file, path=paths))
return normalize_path(which(file, path=paths))
except WhichError:
return None

Просмотреть файл

@ -50,31 +50,48 @@ def windows_sdk_dir(value, host):
# The Windows SDK 8.1 and 10 have different layouts. The former has
# $SDK/include/$subdir, while the latter has $SDK/include/$version/$subdir.
# The vcvars* scripts don't actually care about the version, they just take
# the last.
# the last alphanumerically.
# The $SDK/lib directories always have version subdirectories, but while the
# versions match the one in $SDK/include for SDK 10, it's "winv6.3" for SDK
# 8.1.
@imports('os')
@imports('re')
@imports(_from='__builtin__', _import='sorted')
@imports(_from='__builtin__', _import='WindowsError')
def get_include_dir(sdk, subdir):
base = os.path.join(sdk, 'include')
try:
subdirs = [d for d in os.listdir(base)
if os.path.isdir(os.path.join(base, d))]
except WindowsError:
subdirs = []
if not subdirs:
return None
if subdir in subdirs:
return os.path.join(base, subdir)
# At this point, either we have an incomplete or invalid SDK directory,
# or we exclusively have version numbers in subdirs.
versions = sorted((Version(d) for d in subdirs), reverse=True)
# Version('non-number').major is 0, so if the biggest version we have is
# 0, we have a problem.
if versions[0].major == 0:
return None
path = os.path.join(base, str(versions[0]), subdir)
return path if os.path.isdir(path) else None
def get_sdk_dirs(sdk, subdir):
def get_dirs_containing(sdk, stem, subdir):
base = os.path.join(sdk, stem)
try:
subdirs = [d for d in os.listdir(base)
if os.path.isdir(os.path.join(base, d))]
except WindowsError:
subdirs = []
if not subdirs:
return ()
if subdir in subdirs:
return (base,)
# At this point, either we have an incomplete or invalid SDK directory,
# or we exclusively have version numbers in subdirs.
return tuple(os.path.join(base, s) for s in subdirs
if os.path.isdir(os.path.join(base, s, subdir)))
def categorize(dirs):
return {os.path.basename(d): d for d in dirs}
include_dirs = categorize(get_dirs_containing(sdk, 'include', subdir))
lib_dirs = categorize(get_dirs_containing(sdk, 'lib', subdir))
if 'include' in include_dirs:
include_dirs['winv6.3'] = include_dirs['include']
del include_dirs['include']
valid_versions = sorted(set(include_dirs) & set(lib_dirs), reverse=True)
if valid_versions:
return namespace(
path=sdk,
lib=lib_dirs[valid_versions[0]],
include=include_dirs[valid_versions[0]],
)
@imports(_from='mozbuild.shellutil', _import='quote')
@ -93,13 +110,14 @@ def valid_windows_sdk_dir(compiler, windows_sdk_dir, target_version,
windows_sdk_dir_env = windows_sdk_dir_env[0]
sdks = {}
for d in windows_sdk_dir:
um_dir = get_include_dir(d, 'um')
shared_dir = get_include_dir(d, 'shared')
if um_dir and shared_dir:
sdk = get_sdk_dirs(d, 'um')
if sdk:
check = dedent('''\
#include <winsdkver.h>
WINVER_MAXVER
''')
um_dir = os.path.join(sdk.include, 'um')
shared_dir = os.path.join(sdk.include, 'shared')
result = try_preprocess(compiler.wrapper + [compiler.compiler] +
compiler.flags +
['-I', um_dir, '-I', shared_dir], 'C',
@ -111,7 +129,7 @@ def valid_windows_sdk_dir(compiler, windows_sdk_dir, target_version,
except:
pass
else:
sdks[d] = maxver
sdks[d] = maxver, sdk
continue
if d == windows_sdk_dir_env:
raise FatalCheckError(
@ -119,9 +137,9 @@ def valid_windows_sdk_dir(compiler, windows_sdk_dir, target_version,
'WINDOWSSDKDIR (%s). Please verify it contains a valid and '
'complete SDK installation.' % windows_sdk_dir_env)
valid_sdks = sorted(sdks, key=lambda x: sdks[x], reverse=True)
valid_sdks = sorted(sdks, key=lambda x: sdks[x][0], reverse=True)
if valid_sdks:
biggest_version = sdks[valid_sdks[0]]
biggest_version, sdk = sdks[valid_sdks[0]]
if not valid_sdks or biggest_version < target_version:
if windows_sdk_dir_env:
raise FatalCheckError(
@ -137,7 +155,9 @@ def valid_windows_sdk_dir(compiler, windows_sdk_dir, target_version,
'Cannot find a Windows SDK for version >= 0x%04x.' % target_version)
return namespace(
path=valid_sdks[0],
path=sdk.path,
include=sdk.include,
lib=sdk.lib,
version=biggest_version,
)
@ -151,6 +171,166 @@ add_old_configure_assignment(
lambda x: '0x%04X0000' % x.version if x else None))
@imports(_from='mozbuild.shellutil', _import='quote')
def valid_ucrt_sdk_dir_result(value):
if value:
return '%s in %s' % (value.version, quote(value.path))
@depends_win(windows_sdk_dir, 'WINDOWSSDKDIR')
@checking('for Universal CRT SDK', valid_ucrt_sdk_dir_result)
@imports(_from='__builtin__', _import='sorted')
def valid_ucrt_sdk_dir(windows_sdk_dir, windows_sdk_dir_env):
if windows_sdk_dir_env:
windows_sdk_dir_env = windows_sdk_dir_env[0]
sdks = {}
for d in windows_sdk_dir:
sdk = get_sdk_dirs(d, 'ucrt')
if sdk:
version = os.path.basename(sdk.include)
# We're supposed to always find a version in the directory, because
# the 8.1 SDK, which doesn't have a version in the directory, doesn't
# contain the Universal CRT SDK. When the main SDK is 8.1, there
# is, however, supposed to be a reduced install of the SDK 10
# with the UCRT.
if version != 'include':
sdks[d] = Version(version), sdk
continue
if d == windows_sdk_dir_env:
raise FatalCheckError(
'The SDK in WINDOWSSDKDIR (%s) does not contain the Universal '
'CRT.' % windows_sdk_dir_env)
valid_sdks = sorted(sdks, key=lambda x: sdks[x][0], reverse=True)
if not valid_sdks:
raise FatalCheckError('Cannot find the Universal CRT SDK. '
'Please install it.')
version, sdk = sdks[valid_sdks[0]]
return namespace(
path=sdk.path,
include=sdk.include,
lib=sdk.lib,
version=version,
)
@depends_win(c_compiler)
@imports('os')
def vc_path(c_compiler):
if c_compiler.type != 'msvc':
return
# Normally, we'd start from c_compiler.compiler, but for now, it's not the
# ideal full path to the compiler. At least, we're guaranteed find_program
# will get us the one we found in toolchain.configure.
cl = find_program(c_compiler.compiler)
result = os.path.dirname(cl)
while True:
next, p = os.path.split(result)
if next == result:
die('Cannot determine the Visual C++ directory the compiler (%s) '
'is in' % cl)
result = next
if p.lower() == 'bin':
break
return result
@depends_win(vc_path)
@checking('for the Debug Interface Access SDK', lambda x: x or 'not found')
def dia_sdk_dir(vc_path):
if vc_path:
path = os.path.join(os.path.dirname(vc_path), 'DIA SDK')
if os.path.isdir(path):
return path
@depends_win(vc_path, valid_windows_sdk_dir, valid_ucrt_sdk_dir, dia_sdk_dir)
@imports('os')
def include_path(vc_path, windows_sdk_dir, ucrt_sdk_dir, dia_sdk_dir):
if not vc_path:
return
atlmfc_dir = os.path.join(vc_path, 'atlmfc', 'include')
if not os.path.isdir(atlmfc_dir):
die('Cannot find the ATL/MFC headers in the Visual C++ directory (%s). '
'Please install them.' % vc_path)
winrt_dir = os.path.join(windows_sdk_dir.include, 'winrt')
if not os.path.isdir(winrt_dir):
die('Cannot find the WinRT headers in the Windows SDK directory (%s). '
'Please install them.' % windows_sdk_dir.path)
includes = []
include_env = os.environ.get('INCLUDE')
if include_env:
includes.append(include_env)
includes.extend((
os.path.join(vc_path, 'include'),
atlmfc_dir,
os.path.join(windows_sdk_dir.include, 'shared'),
os.path.join(windows_sdk_dir.include, 'um'),
winrt_dir,
os.path.join(ucrt_sdk_dir.include, 'ucrt'),
))
if dia_sdk_dir:
includes.append(os.path.join(dia_sdk_dir, 'include'))
# Set in the environment for old-configure
includes = os.pathsep.join(includes)
os.environ['INCLUDE'] = includes
return includes
set_config('INCLUDE', include_path)
@depends_win(target, vc_path, valid_windows_sdk_dir, valid_ucrt_sdk_dir, dia_sdk_dir)
@imports('os')
def lib_path(target, vc_path, windows_sdk_dir, ucrt_sdk_dir, dia_sdk_dir):
if not vc_path:
return
vc_target = {
'x86': '',
'x86_64': 'amd64',
'arm': 'arm',
}.get(target.cpu)
if vc_target is None:
return
# As vc_target can be '', and os.path.join will happily use the empty
# string, leading to a string ending with a backslash, that Make will
# interpret as a "string continues on next line" indicator, use variable
# args.
vc_target = (vc_target,) if vc_target else ()
sdk_target = {
'x86': 'x86',
'x86_64': 'x64',
'arm': 'arm',
}.get(target.cpu)
atlmfc_dir = os.path.join(vc_path, 'atlmfc', 'lib', *vc_target)
if not os.path.isdir(atlmfc_dir):
die('Cannot find the ATL/MFC libraries in the Visual C++ directory (%s). '
'Please install them.' % vc_path)
libs = []
lib_env = os.environ.get('LIB')
if lib_env:
libs.append(lib_env)
libs.extend((
os.path.join(vc_path, 'lib', *vc_target),
atlmfc_dir,
os.path.join(windows_sdk_dir.lib, 'um', sdk_target),
os.path.join(ucrt_sdk_dir.lib, 'ucrt', sdk_target),
))
if dia_sdk_dir:
libs.append(os.path.join(dia_sdk_dir, 'lib', *vc_target))
# Set in the environment for old-configure
libs = os.pathsep.join(libs)
os.environ['LIB'] = libs
return libs
set_config('LIB', lib_path)
option(env='MT', nargs=1, help='Path to the Microsoft Manifest Tool')
@depends_win(valid_windows_sdk_dir)
@ -175,10 +355,8 @@ def sdk_bin_path(valid_windows_sdk_dir):
return result
# Normally, we'd use `MT` instead of `_MT`, but for now, we want MT to only contain
# mt.exe.
mt = check_prog('_MT', depends_win()(lambda: ('mt.exe',)), what='mt',
input='MT', paths=sdk_bin_path)
mt = check_prog('MT', depends_win()(lambda: ('mt.exe',)), input='MT',
paths=sdk_bin_path)
# Check that MT is not something unexpected like "magnetic tape manipulation
@ -198,10 +376,19 @@ def valid_mt(path):
raise FatalCheckError('%s is not Microsoft Manifest Tool')
set_config('MT', depends_if(valid_mt)(lambda x: os.path.basename(x)))
set_config('MSMANIFEST_TOOL', depends(valid_mt)(lambda x: bool(x)))
# Ultimately, this will move to toolchain.configure and be turned into a
# cross-platform check.
option(env='LD', nargs=1, help='Path to the linker')
link = check_prog('LINK', depends_win()(lambda: ('link.exe',)), input='LD',
paths=vc_compiler_path)
add_old_configure_assignment('LD', depends_win(link)(lambda x: x))
# Normally, we'd just have CC, etc. set to absolute paths, but the build system
# doesn't currently handle properly the case where the paths contain spaces.
# Additionally, there's the issue described in toolchain.configure, in

Просмотреть файл

@ -1,21 +1,23 @@
if [ -z "${VSPATH}" ]; then
TOOLTOOL_DIR=${TOOLTOOL_DIR:-$topsrcdir}
VSPATH="$(cd ${TOOLTOOL_DIR} && pwd)/vs2015u2"
VSWINPATH="$(cd ${TOOLTOOL_DIR} && pwd -W)/vs2015u2"
fi
VSWINPATH="$(cd ${VSPATH} && pwd -W)"
export WINDOWSSDKDIR="${VSWINPATH}/SDK"
export WIN32_REDIST_DIR="${VSPATH}/VC/redist/x86/Microsoft.VC140.CRT"
export WIN_UCRT_REDIST_DIR="${VSPATH}/SDK/Redist/ucrt/DLLs/x86"
export PATH="${VSPATH}/VC/bin/amd64_x86:${VSPATH}/VC/bin/amd64:${VSPATH}/VC/bin:${VSPATH}/SDK/bin/x86:${VSPATH}/SDK/bin/x64:${VSPATH}/DIASDK/bin:${PATH}"
export PATH="${VSPATH}/VC/bin/amd64_x86:${VSPATH}/VC/bin/amd64:${VSPATH}/VC/bin:${VSPATH}/SDK/bin/x86:${VSPATH}/SDK/bin/x64:${VSPATH}/DIA SDK/bin:${PATH}"
export PATH="${VSPATH}/VC/redist/x86/Microsoft.VC140.CRT:${VSPATH}/VC/redist/x64/Microsoft.VC140.CRT:${VSPATH}/SDK/Redist/ucrt/DLLs/x86:${VSPATH}/SDK/Redist/ucrt/DLLs/x64:${PATH}"
export INCLUDE="${VSPATH}/VC/include:${VSPATH}/VC/atlmfc/include:${VSPATH}/SDK/Include/ucrt:${VSPATH}/SDK/Include/shared:${VSPATH}/SDK/Include/um:${VSPATH}/SDK/Include/winrt:${VSPATH}/DIASDK/include"
export LIB="${VSPATH}/VC/lib:${VSPATH}/VC/atlmfc/lib:${VSPATH}/SDK/lib/ucrt/x86:${VSPATH}/SDK/lib/um/x86:${VSPATH}/DIASDK/lib"
export INCLUDE="${VSPATH}/VC/include:${VSPATH}/VC/atlmfc/include:${VSPATH}/SDK/Include/10.0.10586.0/ucrt:${VSPATH}/SDK/Include/10.0.10586.0/shared:${VSPATH}/SDK/Include/10.0.10586.0/um:${VSPATH}/SDK/Include/10.0.10586.0/winrt:${VSPATH}/DIA SDK/include"
export LIB="${VSPATH}/VC/lib:${VSPATH}/VC/atlmfc/lib:${VSPATH}/SDK/lib/10.0.10586.0/ucrt/x86:${VSPATH}/SDK/lib/10.0.10586.0/um/x86:${VSPATH}/DIA SDK/lib"
. $topsrcdir/build/mozconfig.vs-common
mk_export_correct_style WINDOWSSDKDIR
mk_export_correct_style INCLUDE
mk_export_correct_style LIB
mk_export_correct_style PATH

Просмотреть файл

@ -1,20 +1,22 @@
if [ -z "${VSPATH}" ]; then
TOOLTOOL_DIR=${TOOLTOOL_DIR:-$topsrcdir}
VSPATH="$(cd ${TOOLTOOL_DIR} && pwd)/vs2015u2"
VSWINPATH="$(cd ${TOOLTOOL_DIR} && pwd -W)/vs2015u2"
fi
VSWINPATH="$(cd ${VSPATH} && pwd -W)"
export WINDOWSSDKDIR="${VSWINPATH}/SDK"
export WIN32_REDIST_DIR=${VSPATH}/VC/redist/x64/Microsoft.VC140.CRT
export WIN_UCRT_REDIST_DIR="${VSPATH}/SDK/Redist/ucrt/DLLs/x64"
export PATH="${VSPATH}/VC/bin/amd64:${VSPATH}/VC/bin:${VSPATH}/SDK/bin/x64:${VSPATH}/VC/redist/x64/Microsoft.VC140.CRT:${VSPATH}/SDK/Redist/ucrt/DLLs/x64:${VSPATH}/DIASDK/bin/amd64:${PATH}"
export PATH="${VSPATH}/VC/bin/amd64:${VSPATH}/VC/bin:${VSPATH}/SDK/bin/x64:${VSPATH}/VC/redist/x64/Microsoft.VC140.CRT:${VSPATH}/SDK/Redist/ucrt/DLLs/x64:${VSPATH}/DIA SDK/bin/amd64:${PATH}"
export INCLUDE="${VSPATH}/VC/include:${VSPATH}/VC/atlmfc/include:${VSPATH}/SDK/Include/ucrt:${VSPATH}/SDK/Include/shared:${VSPATH}/SDK/Include/um:${VSPATH}/SDK/Include/winrt:${VSPATH}/DIASDK/include"
export LIB="${VSPATH}/VC/lib/amd64:${VSPATH}/VC/atlmfc/lib/amd64:${VSPATH}/SDK/lib/ucrt/x64:${VSPATH}/SDK/lib/um/x64:${VSPATH}/DIASDK/lib/amd64"
export INCLUDE="${VSPATH}/VC/include:${VSPATH}/VC/atlmfc/include:${VSPATH}/SDK/Include/10.0.10586.0/ucrt:${VSPATH}/SDK/Include/10.0.10586.0/shared:${VSPATH}/SDK/Include/10.0.10586.0/um:${VSPATH}/SDK/Include/10.0.10586.0/winrt:${VSPATH}/DIA SDK/include"
export LIB="${VSPATH}/VC/lib/amd64:${VSPATH}/VC/atlmfc/lib/amd64:${VSPATH}/SDK/lib/10.0.10586.0/ucrt/x64:${VSPATH}/SDK/lib/10.0.10586.0/um/x64:${VSPATH}/DIA SDK/lib/amd64"
. $topsrcdir/build/mozconfig.vs-common
mk_export_correct_style WINDOWSSDKDIR
mk_export_correct_style INCLUDE
mk_export_correct_style LIB
mk_export_correct_style PATH

Просмотреть файл

@ -29,23 +29,18 @@ import mozpack.path as mozpath
VS_PATTERNS = [
{
'pattern': 'DIA SDK/bin/**',
# Various tools don't like spaces in filenames. So remove it.
'rewrite': [('DIA SDK/', 'DIASDK/')],
'ignore': (
'DIA SDK/bin/arm/**',
),
},
{
'pattern': 'DIA SDK/idl/**',
'rewrite': [('DIA SDK/', 'DIASDK/')],
},
{
'pattern': 'DIA SDK/include/**',
'rewrite': [('DIA SDK/', 'DIASDK/')],
},
{
'pattern': 'DIA SDK/lib/**',
'rewrite': [('DIA SDK/', 'DIASDK/')],
'ignore': (
'DIA SDK/lib/arm/**',
),
@ -160,18 +155,12 @@ def resolve_files():
for p, f in finder.find(entry['pattern']):
assert p.startswith(('VC/', 'DIA SDK/'))
for source, dest in entry.get('rewrite', []):
p = p.replace(source, dest)
yield p.encode('utf-8'), f
for entry in SDK_PATTERNS:
finder = FileFinder(sdk_path, find_executables=False,
ignore=entry.get('ignore', []))
for p, f in finder.find(entry['pattern']):
# We remove the SDK version from the path so we don't have
# to update other configs when we change the SDK version.
p = p.replace('/%s/' % SDK_RELEASE, '/')
relpath = 'SDK/%s' % p
yield relpath.encode('utf-8'), f

Просмотреть файл

@ -358,6 +358,18 @@ ifdef MACOSX_DEPLOYMENT_TARGET
export MACOSX_DEPLOYMENT_TARGET
endif # MACOSX_DEPLOYMENT_TARGET
# Export to propagate to cl and submake for third-party code.
# Eventually, we'll want to just use -I.
ifdef INCLUDE
export INCLUDE
endif
# Export to propagate to link.exe and submake for third-party code.
# Eventually, we'll want to just use -LIBPATH.
ifdef LIB
export LIB
endif
ifdef MOZ_USING_CCACHE
ifdef CLANG_CXX
export CCACHE_CPP2=1

Просмотреть файл

@ -8089,7 +8089,8 @@ nsContentUtils::SendMouseEvent(nsCOMPtr<nsIPresShell> aPresShell,
unsigned short aInputSourceArg,
bool aToWindow,
bool *aPreventDefault,
bool aIsSynthesized)
bool aIsDOMEventSynthesized,
bool aIsWidgetEventSynthesized)
{
nsPoint offset;
nsCOMPtr<nsIWidget> widget = GetWidget(aPresShell, &offset);
@ -8123,7 +8124,10 @@ nsContentUtils::SendMouseEvent(nsCOMPtr<nsIPresShell> aPresShell,
aInputSourceArg = nsIDOMMouseEvent::MOZ_SOURCE_MOUSE;
}
WidgetMouseEvent event(true, msg, widget, WidgetMouseEvent::eReal,
WidgetMouseEvent event(true, msg, widget,
aIsWidgetEventSynthesized ?
WidgetMouseEvent::eSynthesized :
WidgetMouseEvent::eReal,
contextMenuKey ? WidgetMouseEvent::eContextMenuKey :
WidgetMouseEvent::eNormal);
event.mModifiers = GetWidgetModifiers(aModifiers);
@ -8133,7 +8137,7 @@ nsContentUtils::SendMouseEvent(nsCOMPtr<nsIPresShell> aPresShell,
event.inputSource = aInputSourceArg;
event.mClickCount = aClickCount;
event.mTime = PR_IntervalNow();
event.mFlags.mIsSynthesizedForTests = aIsSynthesized;
event.mFlags.mIsSynthesizedForTests = aIsDOMEventSynthesized;
nsPresContext* presContext = aPresShell->GetPresContext();
if (!presContext)

Просмотреть файл

@ -2552,7 +2552,8 @@ public:
unsigned short aInputSourceArg,
bool aToWindow,
bool *aPreventDefault,
bool aIsSynthesized);
bool aIsDOMEventSynthesized,
bool aIsWidgetEventSynthesized);
static void FirePageShowEvent(nsIDocShellTreeItem* aItem,
mozilla::dom::EventTarget* aChromeEventHandler,

Просмотреть файл

@ -648,14 +648,18 @@ nsDOMWindowUtils::SendMouseEvent(const nsAString& aType,
bool aIgnoreRootScrollFrame,
float aPressure,
unsigned short aInputSourceArg,
bool aIsSynthesized,
bool aIsDOMEventSynthesized,
bool aIsWidgetEventSynthesized,
uint8_t aOptionalArgCount,
bool *aPreventDefault)
{
return SendMouseEventCommon(aType, aX, aY, aButton, aClickCount, aModifiers,
aIgnoreRootScrollFrame, aPressure,
aInputSourceArg, false, aPreventDefault,
aOptionalArgCount >= 4 ? aIsSynthesized : true);
aOptionalArgCount >= 4 ?
aIsDOMEventSynthesized : true,
aOptionalArgCount >= 5 ?
aIsWidgetEventSynthesized : false);
}
NS_IMETHODIMP
@ -668,7 +672,8 @@ nsDOMWindowUtils::SendMouseEventToWindow(const nsAString& aType,
bool aIgnoreRootScrollFrame,
float aPressure,
unsigned short aInputSourceArg,
bool aIsSynthesized,
bool aIsDOMEventSynthesized,
bool aIsWidgetEventSynthesized,
uint8_t aOptionalArgCount)
{
PROFILER_LABEL("nsDOMWindowUtils", "SendMouseEventToWindow",
@ -677,7 +682,10 @@ nsDOMWindowUtils::SendMouseEventToWindow(const nsAString& aType,
return SendMouseEventCommon(aType, aX, aY, aButton, aClickCount, aModifiers,
aIgnoreRootScrollFrame, aPressure,
aInputSourceArg, true, nullptr,
aOptionalArgCount >= 4 ? aIsSynthesized : true);
aOptionalArgCount >= 4 ?
aIsDOMEventSynthesized : true,
aOptionalArgCount >= 5 ?
aIsWidgetEventSynthesized : false);
}
NS_IMETHODIMP
@ -692,12 +700,14 @@ nsDOMWindowUtils::SendMouseEventCommon(const nsAString& aType,
unsigned short aInputSourceArg,
bool aToWindow,
bool *aPreventDefault,
bool aIsSynthesized)
bool aIsDOMEventSynthesized,
bool aIsWidgetEventSynthesized)
{
nsCOMPtr<nsIPresShell> presShell = GetPresShell();
return nsContentUtils::SendMouseEvent(presShell, aType, aX, aY, aButton,
aClickCount, aModifiers, aIgnoreRootScrollFrame, aPressure,
aInputSourceArg, aToWindow, aPreventDefault, aIsSynthesized);
aInputSourceArg, aToWindow, aPreventDefault, aIsDOMEventSynthesized,
aIsWidgetEventSynthesized);
}
NS_IMETHODIMP

Просмотреть файл

@ -93,7 +93,8 @@ protected:
unsigned short aInputSourceArg,
bool aToWindow,
bool *aPreventDefault,
bool aIsSynthesized);
bool aIsDOMEventSynthesized,
bool aIsWidgetEventSynthesized);
NS_IMETHOD SendPointerEventCommon(const nsAString& aType,
float aX,

Просмотреть файл

@ -3704,6 +3704,38 @@ nsPIDOMWindow<T>::MaybeCreateDoc()
}
}
void
nsPIDOMWindowOuter::SetInitialKeyboardIndicators(
UIStateChangeType aShowAccelerators, UIStateChangeType aShowFocusRings)
{
MOZ_ASSERT(IsOuterWindow());
MOZ_ASSERT(!GetCurrentInnerWindow());
nsPIDOMWindowOuter* piWin = GetPrivateRoot();
if (!piWin) {
return;
}
MOZ_ASSERT(piWin == AsOuter());
// only change the flags that have been modified
nsCOMPtr<nsPIWindowRoot> windowRoot = do_QueryInterface(mChromeEventHandler);
if (!windowRoot) {
return;
}
if (aShowAccelerators != UIStateChangeType_NoChange) {
windowRoot->SetShowAccelerators(aShowAccelerators == UIStateChangeType_Set);
}
if (aShowFocusRings != UIStateChangeType_NoChange) {
windowRoot->SetShowFocusRings(aShowFocusRings == UIStateChangeType_Set);
}
nsContentUtils::SetKeyboardIndicatorsOnRemoteChildren(GetOuterWindow(),
aShowAccelerators,
aShowFocusRings);
}
Element*
nsPIDOMWindowOuter::GetFrameElementInternal() const
{

Просмотреть файл

@ -848,6 +848,12 @@ public:
return GetCurrentInnerWindow();
}
/**
* Set initial keyboard indicator state for accelerators and focus rings.
*/
void SetInitialKeyboardIndicators(UIStateChangeType aShowAccelerators,
UIStateChangeType aShowFocusRings);
// Internal getter/setter for the frame element, this version of the
// getter crosses chrome boundaries whereas the public scriptable
// one doesn't for security reasons.

Просмотреть файл

@ -1,6 +1,7 @@
dump('loaded child cpow test\n');
var Cu = Components.utils;
var Ci = Components.interfaces;
(function start() {
[is_remote] = sendRpcMessage("cpows:is_remote");
@ -20,6 +21,7 @@ var Cu = Components.utils;
lifetime_test,
cancel_test,
cancel_test2,
dead_test,
unsafe_test,
];
@ -355,3 +357,23 @@ function unsafe_test(finish)
addMessageListener("cpows:safe_done", finish);
});
}
function dead_test(finish)
{
if (!is_remote) {
// Only run this test when running out-of-process.
finish();
return;
}
{
let thing = { value: "Gonna croak" };
sendAsyncMessage("cpows:dead", null, { thing });
}
// Force the GC to dead-ify the thing.
content.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils)
.garbageCollect();
addMessageListener("cpows:dead_done", finish);
}

Просмотреть файл

@ -417,6 +417,17 @@
msg.target.messageManager.sendAsyncMessage("cpows:safe_done");
}
function recvDead(msg) {
try {
msg.objects.thing.value;
ok(false, "Should have been a dead CPOW");
} catch(e if /dead CPOW/.test(String(e))) {
ok(true, "Got the expected dead CPOW");
ok(e.stack, "The exception has a stack");
}
msg.target.messageManager.sendAsyncMessage("cpows:dead_done");
}
function run_tests(type) {
info("Running tests: " + type);
var node = document.getElementById('cpowbrowser_' + type);
@ -458,6 +469,7 @@
mm.addMessageListener("cpows:cancel_test2", recvCancelTest2);
mm.addMessageListener("cpows:unsafe", recvUnsafe);
mm.addMessageListener("cpows:safe", recvSafe);
mm.addMessageListener("cpows:dead", recvDead);
mm.loadFrameScript("chrome://mochitests/content/chrome/dom/base/test/chrome/cpows_child.js", true);
}

Просмотреть файл

@ -101,34 +101,43 @@ WebGLContext::InitWebGL2(FailureReason* const out_failReason)
{
MOZ_ASSERT(IsWebGL2(), "WebGLContext is not a WebGL 2 context!");
// check OpenGL features
if (!gl->IsSupported(gl::GLFeature::occlusion_query) &&
!gl->IsSupported(gl::GLFeature::occlusion_query_boolean))
{
// On desktop, we fake occlusion_query_boolean with occlusion_query if
// necessary. (See WebGL2ContextQueries.cpp)
*out_failReason = FailureReason("FEATURE_FAILURE_WEBGL2_OCCL",
"WebGL 2 requires occlusion query support.");
return false;
}
std::vector<gl::GLFeature> missingList;
for (size_t i = 0; i < ArrayLength(kRequiredFeatures); i++) {
if (!gl->IsSupported(kRequiredFeatures[i])) {
missingList.push_back(kRequiredFeatures[i]);
const auto fnGatherMissing = [&](gl::GLFeature cur) {
if (!gl->IsSupported(cur)) {
missingList.push_back(cur);
}
};
const auto fnGatherMissing2 = [&](gl::GLFeature main, gl::GLFeature alt) {
if (!gl->IsSupported(main) && !gl->IsSupported(alt)) {
missingList.push_back(main);
}
};
////
for (const auto& cur : kRequiredFeatures) {
fnGatherMissing(cur);
}
// On desktop, we fake occlusion_query_boolean with occlusion_query if
// necessary. (See WebGL2ContextQueries.cpp)
fnGatherMissing2(gl::GLFeature::occlusion_query_boolean,
gl::GLFeature::occlusion_query);
#ifdef XP_MACOSX
// On OSX, GL core profile is used. This requires texture swizzle
// support to emulate legacy texture formats: ALPHA, LUMINANCE,
// and LUMINANCE_ALPHA.
if (!gl->IsSupported(gl::GLFeature::texture_swizzle)) {
missingList.push_back(gl::GLFeature::texture_swizzle);
}
fnGatherMissing(gl::GLFeature::texture_swizzle);
#endif
fnGatherMissing2(gl::GLFeature::prim_restart_fixed,
gl::GLFeature::prim_restart);
////
if (missingList.size()) {
nsAutoCString exts;
for (auto itr = missingList.begin(); itr != missingList.end(); ++itr) {
@ -155,13 +164,21 @@ WebGLContext::InitWebGL2(FailureReason* const out_failReason)
mDefaultTransformFeedback = new WebGLTransformFeedback(this, 0);
mBoundTransformFeedback = mDefaultTransformFeedback;
////
if (!gl->IsGLES()) {
// Desktop OpenGL requires the following to be enabled in order to
// support sRGB operations on framebuffers.
gl->MakeCurrent();
gl->fEnable(LOCAL_GL_FRAMEBUFFER_SRGB_EXT);
}
if (gl->IsSupported(gl::GLFeature::prim_restart_fixed)) {
gl->fEnable(LOCAL_GL_PRIMITIVE_RESTART_FIXED_INDEX);
} else {
MOZ_ASSERT(gl->IsSupported(gl::GLFeature::prim_restart));
gl->fEnable(LOCAL_GL_PRIMITIVE_RESTART);
}
//////
static const GLenum kWebGL2_CompressedFormats[] = {

Просмотреть файл

@ -919,6 +919,8 @@ protected:
// -----------------------------------------------------------------------------
// Vertices Feature (WebGLContextVertices.cpp)
GLenum mPrimRestartTypeBytes;
public:
void DrawArrays(GLenum mode, GLint first, GLsizei count);
void DrawArraysInstanced(GLenum mode, GLint first, GLsizei count,

Просмотреть файл

@ -258,6 +258,16 @@ WebGLContext::DrawArrays_check(GLint first, GLsizei count, GLsizei primcount,
return false;
}
if (IsWebGL2() && !gl->IsSupported(gl::GLFeature::prim_restart_fixed)) {
MOZ_ASSERT(gl->IsSupported(gl::GLFeature::prim_restart));
if (mPrimRestartTypeBytes != 4) {
mPrimRestartTypeBytes = 4;
// OSX has issues leaving this as 0.
gl->fPrimitiveRestartIndex(UINT32_MAX);
}
}
// If count is 0, there's nothing to do.
if (count == 0 || primcount == 0) {
return false;
@ -414,6 +424,20 @@ WebGLContext::DrawElements_check(GLsizei count, GLenum type,
return false;
}
////
if (IsWebGL2() && !gl->IsSupported(gl::GLFeature::prim_restart_fixed)) {
MOZ_ASSERT(gl->IsSupported(gl::GLFeature::prim_restart));
if (mPrimRestartTypeBytes != bytesPerElem) {
mPrimRestartTypeBytes = bytesPerElem;
const uint32_t ones = UINT32_MAX >> (4 - mPrimRestartTypeBytes);
gl->fPrimitiveRestartIndex(ones);
}
}
////
const GLsizei first = byteOffset / bytesPerElem;
const CheckedUint32 checked_byteCount = bytesPerElem * CheckedUint32(count);

Просмотреть файл

@ -1001,6 +1001,8 @@ WebGLContext::InitAndValidateGL(FailureReason* const out_failReason)
mPixelStore_PackSkipPixels = 0;
mPixelStore_PackAlignment = 4;
mPrimRestartTypeBytes = 0;
return true;
}

Просмотреть файл

@ -5778,7 +5778,7 @@ skip-if = (os == 'android' || os == 'linux' || (os == 'win' && os_version == '5.
[generated/test_2_conformance__rendering__multisample-corruption.html]
skip-if = (os == 'android' || os == 'linux' || (os == 'win' && os_version == '5.1') || (os == 'win' && os_version == '6.2'))
[generated/test_2_conformance__rendering__negative-one-index.html]
fail-if = (os == 'mac') || (os == 'win')
fail-if = (os == 'mac')
skip-if = (os == 'android' || os == 'linux' || (os == 'win' && os_version == '5.1') || (os == 'win' && os_version == '6.2'))
[generated/test_2_conformance__rendering__point-no-attributes.html]
skip-if = (os == 'android' || os == 'linux' || (os == 'win' && os_version == '5.1') || (os == 'win' && os_version == '6.2'))

Просмотреть файл

@ -151,7 +151,7 @@ fail-if = (os == 'mac') || (os == 'win')
[generated/test_2_conformance2__vertex_arrays__vertex-array-object.html]
fail-if = (os == 'mac') || (os == 'win')
[generated/test_2_conformance__rendering__negative-one-index.html]
fail-if = (os == 'mac') || (os == 'win')
fail-if = (os == 'mac')
[generated/test_conformance__extensions__oes-texture-half-float.html]
fail-if = (os == 'mac') || (os == 'win') || (os == 'android') || (os == 'linux')
[generated/test_2_conformance2__reading__read-pixels-pack-parameters.html]

Просмотреть файл

@ -147,7 +147,7 @@ SimpleTest.waitForExplicitFinish();
try {
var prefArrArr = [
['webgl.force-enabled', true],
['webgl.enable-prototype-webgl2', true],
['webgl.enable-webgl2', true],
];
var prefEnv = {'set': prefArrArr};
SpecialPowers.pushPrefEnv(prefEnv, run);

Просмотреть файл

@ -5,8 +5,8 @@
<link rel="stylesheet" href="/tests/SimpleTest/test.css">
<script src="driver-info.js"></script>
<script src="webgl-util.js"></script>
<script id="vs" type="x-shader/x-vertex">
#version 300 es
<script id="vs" type="x-shader/x-vertex"
>#version 300 es
in vec2 aTexCoord;
out vec2 vTexCoord;
@ -17,8 +17,8 @@ void main() {
vTexCoord = aTexCoord;
}
</script>
<script id="fs" type="x-shader/x-fragment">
#version 300 es
<script id="fs" type="x-shader/x-fragment"
>#version 300 es
precision mediump float;
in vec2 vTexCoord;

Просмотреть файл

@ -10,7 +10,7 @@
function ShouldExpose() {
try {
return SpecialPowers.getBoolPref('webgl.enable-prototype-webgl2');
return SpecialPowers.getBoolPref('webgl.enable-webgl2');
} catch (e) {}
return false;

Просмотреть файл

@ -86,9 +86,7 @@ WebGLUtil = (function() {
try {
var prefArrArr = [
['webgl.force-enabled', true],
['webgl.disable-angle', true],
['webgl.bypass-shader-validation', true],
['webgl.enable-prototype-webgl2', true],
['webgl.enable-webgl2', true],
];
var prefEnv = {'set': prefArrArr};
SpecialPowers.pushPrefEnv(prefEnv, run);

Просмотреть файл

@ -124,6 +124,6 @@ support-files =
pointerevent_touch-action-span-test_touch-manual.html
pointerevent_touch-action-svg-test_touch-manual.html
pointerevent_touch-action-table-test_touch-manual.html
[test_bug1285128.html]
[test_empty_file.html]
disabled = disabled # Bug 1150091 - Issue with support-files

Просмотреть файл

@ -0,0 +1,48 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1285128
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 1285128</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1285128">Mozilla Bug 1285128</a>
<p id="display"></p>
<div id="target0" style="width: 200px; height: 200px; background: green"></div>
<script type="text/javascript">
/** Test for Bug 1285128 **/
SimpleTest.waitForExplicitFinish();
function runTests() {
let target0 = window.document.getElementById("target0");
let pointerEventsList = ["pointerover", "pointerenter", "pointerdown",
"pointerup", "pointerleave", "pointerout"];
let receivedPointerEvents = false;
pointerEventsList.forEach((elem, index, arr) => {
target0.addEventListener(elem, (event) => {
ok(false, "receiving event " + event.type);
receivedPointerEvents = true;
}, false);
});
target0.addEventListener("mouseenter", () => {
ok(!receivedPointerEvents, "synthesized mousemove should not trigger any pointer events");
SimpleTest.finish();
});
synthesizeMouseAtCenter(target0, { type: "mousemove",
inputSource: SpecialPowers.Ci.nsIDOMMouseEvent.MOZ_SOURCE_MOUSE,
isWidgetEventSynthesized: true });
}
SpecialPowers.pushPrefEnv({"set": [["dom.w3c_pointer_events.enabled", true]]}, runTests);
</script>
</body>
</html>

Просмотреть файл

@ -797,6 +797,17 @@ HTMLMediaElement::MozDumpDebugInfo()
}
}
void
HTMLMediaElement::SetVisible(bool aVisible)
{
if (!mDecoder) {
return;
}
mDecoder->NotifyOwnerActivityChanged(aVisible);
}
already_AddRefed<DOMMediaStream>
HTMLMediaElement::GetSrcObject() const
{

Просмотреть файл

@ -606,6 +606,8 @@ public:
void MozDumpDebugInfo();
void SetVisible(bool aVisible);
already_AddRefed<DOMMediaStream> GetSrcObject() const;
void SetSrcObject(DOMMediaStream& aValue);
void SetSrcObject(DOMMediaStream* aValue);

Просмотреть файл

@ -312,9 +312,11 @@ interface nsIDOMWindowUtils : nsISupports {
* @param aPressure touch input pressure: 0.0 -> 1.0
* @param aInputSourceArg input source, see nsIDOMMouseEvent for values,
* defaults to mouse input.
* @param aIsSynthesized controls nsIDOMEvent.isSynthesized value
* that helps identifying test related events,
* defaults to true
* @param aIsDOMEventSynthesized controls nsIDOMEvent.isSynthesized value
* that helps identifying test related events,
* defaults to true
* @param aIsWidgetEventSynthesized controls WidgetMouseEvent.mReason value
* defaults to false (WidgetMouseEvent::eReal)
*
* returns true if the page called prevent default on this event
*/
@ -328,7 +330,8 @@ interface nsIDOMWindowUtils : nsISupports {
[optional] in boolean aIgnoreRootScrollFrame,
[optional] in float aPressure,
[optional] in unsigned short aInputSourceArg,
[optional] in boolean aIsSynthesized);
[optional] in boolean aIsDOMEventSynthesized,
[optional] in boolean aIsWidgetEventSynthesized);
/** Synthesize a pointer event. The event types supported are:
@ -447,7 +450,8 @@ interface nsIDOMWindowUtils : nsISupports {
[optional] in boolean aIgnoreRootScrollFrame,
[optional] in float aPressure,
[optional] in unsigned short aInputSourceArg,
[optional] in boolean aIsSynthesized);
[optional] in boolean aIsDOMEventSynthesized,
[optional] in boolean aIsWidgetEventSynthesized);
/** The same as sendPointerEvent but ensures that the event
* is dispatched to this DOM window or one of its children.

Просмотреть файл

@ -54,6 +54,11 @@ interface nsITabParent : nsISupports
readonly attribute uint64_t tabId;
/**
* The OS level process Id of the related child process.
*/
readonly attribute int32_t osPid;
/**
* Navigate by key. If aForDocumentNavigation is true, navigate by document.
* If aForDocumentNavigation is false, navigate by element.

Просмотреть файл

@ -62,6 +62,11 @@ public:
{
return mIsForBrowser;
}
virtual int32_t Pid() const override
{
// XXX: do we need this for ContentBridgeParent?
return -1;
}
protected:
virtual ~ContentBridgeParent();

Просмотреть файл

@ -386,8 +386,6 @@ public:
return mSubprocess;
}
int32_t Pid() const;
ContentParent* Opener() const
{
return mOpener;
@ -591,6 +589,8 @@ public:
virtual bool
RecvUnstoreAndBroadcastBlobURLUnregistration(const nsCString& aURI) override;
virtual int32_t Pid() const override;
protected:
void OnChannelConnected(int32_t pid) override;

Просмотреть файл

@ -842,7 +842,12 @@ TabChild::Init()
do_QueryInterface(window->GetChromeEventHandler());
docShell->SetChromeEventHandler(chromeHandler);
window->SetKeyboardIndicators(ShowAccelerators(), ShowFocusRings());
if (window->GetCurrentInnerWindow()) {
window->SetKeyboardIndicators(ShowAccelerators(), ShowFocusRings());
} else {
// Skip ShouldShowFocusRing check if no inner window is available
window->SetInitialKeyboardIndicators(ShowAccelerators(), ShowFocusRings());
}
// Set prerender flag if necessary.
if (mIsPrerendered) {

Просмотреть файл

@ -2943,6 +2943,13 @@ TabParent::GetTabId(uint64_t* aId)
return NS_OK;
}
NS_IMETHODIMP
TabParent::GetOsPid(int32_t* aId)
{
*aId = Manager()->Pid();
return NS_OK;
}
NS_IMETHODIMP
TabParent::GetHasContentOpener(bool* aResult)
{

Просмотреть файл

@ -82,6 +82,8 @@ public:
ContentBridgeParent* AsContentBridgeParent();
virtual int32_t Pid() const = 0;
protected: // methods
bool CanOpenBrowser(const IPCTabContext& aContext);

Просмотреть файл

@ -317,6 +317,11 @@ public:
return &mIsSuspended;
}
// Switch the video decoder to BlankDecoderModule. It might takes effective
// since a few samples later depends on how much demuxed samples are already
// queued in the original video decoder.
virtual void SetVideoBlankDecode(bool aIsBlankDecode) {}
protected:
virtual ~MediaDecoderReader();

Просмотреть файл

@ -410,4 +410,14 @@ MediaDecoderReaderWrapper::OnMetadataRead(MetadataHolder* aMetadata)
}
}
void
MediaDecoderReaderWrapper::SetVideoBlankDecode(bool aIsBlankDecode)
{
MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
nsCOMPtr<nsIRunnable> r =
NewRunnableMethod<bool>(mReader, &MediaDecoderReader::SetVideoBlankDecode,
aIsBlankDecode);
mReader->OwnerThread()->Dispatch(r.forget());
}
} // namespace mozilla

Просмотреть файл

@ -121,6 +121,8 @@ public:
void SetCDMProxy(CDMProxy* aProxy) { mReader->SetCDMProxy(aProxy); }
#endif
void SetVideoBlankDecode(bool aIsBlankDecode);
private:
~MediaDecoderReaderWrapper();

Просмотреть файл

@ -1362,6 +1362,7 @@ void MediaDecoderStateMachine::VisibilityChanged()
if (mVideoDecodeSuspended) {
mVideoDecodeSuspended = false;
mReader->SetVideoBlankDecode(false);
if (mIsReaderSuspended) {
return;
@ -2640,7 +2641,7 @@ bool MediaDecoderStateMachine::IsStateMachineScheduled() const
bool MediaDecoderStateMachine::IsVideoDecodeSuspended() const
{
MOZ_ASSERT(OnTaskQueue());
return mVideoDecodeSuspended || mIsReaderSuspended;
return mIsReaderSuspended;
}
void
@ -2932,6 +2933,7 @@ MediaDecoderStateMachine::OnSuspendTimerResolved()
DECODER_LOG("OnSuspendTimerResolved");
mVideoDecodeSuspendTimer.CompleteRequest();
mVideoDecodeSuspended = true;
mReader->SetVideoBlankDecode(true);
}
void

Просмотреть файл

@ -418,7 +418,8 @@ MediaFormatReader::EnsureDecoderCreated(TrackType aTrack)
decoder.mInfo ? *decoder.mInfo->GetAsAudioInfo() : mInfo.mAudio,
decoder.mTaskQueue,
decoder.mCallback.get(),
mCrashHelper
mCrashHelper,
decoder.mIsBlankDecode
});
break;
}
@ -432,7 +433,8 @@ MediaFormatReader::EnsureDecoderCreated(TrackType aTrack)
decoder.mCallback.get(),
mLayersBackendType,
GetImageContainer(),
mCrashHelper
mCrashHelper,
decoder.mIsBlankDecode
});
break;
}
@ -2056,4 +2058,32 @@ MediaFormatReader::GetMozDebugReaderData(nsAString& aString)
aString += NS_ConvertUTF8toUTF16(result);
}
void
MediaFormatReader::SetVideoBlankDecode(bool aIsBlankDecode)
{
MOZ_ASSERT(OnTaskQueue());
return SetBlankDecode(TrackType::kVideoTrack, aIsBlankDecode);
}
void
MediaFormatReader::SetBlankDecode(TrackType aTrack, bool aIsBlankDecode)
{
MOZ_ASSERT(OnTaskQueue());
auto& decoder = GetDecoderData(aTrack);
LOG("%s, decoder.mIsBlankDecode = %d => aIsBlankDecode = %d",
TrackTypeToStr(aTrack), decoder.mIsBlankDecode, aIsBlankDecode);
if (decoder.mIsBlankDecode == aIsBlankDecode) {
return;
}
decoder.mIsBlankDecode = aIsBlankDecode;
decoder.Flush();
decoder.ShutdownDecoder();
NotifyDecodingRequested(TrackInfo::kVideoTrack); // Calls ScheduleUpdate().
return;
}
} // namespace mozilla

Просмотреть файл

@ -101,6 +101,8 @@ public:
// Used for debugging purposes.
void GetMozDebugReaderData(nsAString& aString);
void SetVideoBlankDecode(bool aIsBlankDecode) override;
private:
bool HasVideo() { return mVideo.mTrackDemuxer; }
@ -253,6 +255,7 @@ private:
, mSizeOfQueue(0)
, mIsHardwareAccelerated(false)
, mLastStreamSourceID(UINT32_MAX)
, mIsBlankDecode(false)
{}
MediaFormatReader* mOwner;
@ -427,6 +430,9 @@ private:
Maybe<media::TimeUnit> mLastTimeRangesEnd;
RefPtr<SharedTrackInfo> mInfo;
Maybe<media::TimeUnit> mFirstDemuxedSampleTime;
// Use BlankDecoderModule or not.
bool mIsBlankDecode;
};
class DecoderDataWithPromise : public DecoderData {
@ -571,6 +577,8 @@ private:
RefPtr<CDMProxy> mCDMProxy;
#endif
RefPtr<GMPCrashHelper> mCrashHelper;
void SetBlankDecode(TrackType aTrack, bool aIsBlankDecode);
};
} // namespace mozilla

Просмотреть файл

@ -1401,8 +1401,7 @@ FullBox::FullBox(const nsACString& aType, uint8_t aVersion, uint32_t aFlags,
ISOControl* aControl)
: Box(aType, aControl)
{
// Cast to uint64_t due to VC2010 bug.
std::bitset<24> tmp_flags((uint64_t)aFlags);
std::bitset<24> tmp_flags(aFlags);
version = aVersion;
flags = tmp_flags;
size += sizeof(version) + flags.size() / CHAR_BIT;

Просмотреть файл

@ -81,6 +81,7 @@ PDMFactory::PDMFactory()
{
EnsureInit();
CreatePDMs();
CreateBlankPDM();
}
PDMFactory::~PDMFactory()
@ -120,6 +121,11 @@ PDMFactory::EnsureInit() const
already_AddRefed<MediaDataDecoder>
PDMFactory::CreateDecoder(const CreateDecoderParams& aParams)
{
if (aParams.mUseBlankDecoder) {
MOZ_ASSERT(mBlankPDM);
return CreateDecoderWithPDM(mBlankPDM, aParams);
}
const TrackInfo& config = aParams.mConfig;
bool isEncrypted = mEMEPDM && config.mCrypto.mValid;
@ -287,6 +293,13 @@ PDMFactory::CreatePDMs()
}
}
void
PDMFactory::CreateBlankPDM()
{
mBlankPDM = CreateBlankDecoderModule();
MOZ_ASSERT(mBlankPDM && NS_SUCCEEDED(mBlankPDM->Startup()));
}
bool
PDMFactory::StartupPDM(PlatformDecoderModule* aPDM)
{

Просмотреть файл

@ -47,6 +47,7 @@ public:
private:
virtual ~PDMFactory();
void CreatePDMs();
void CreateBlankPDM();
// Startup the provided PDM and add it to our list if successful.
bool StartupPDM(PlatformDecoderModule* aPDM);
// Returns the first PDM in our list supporting the mimetype.
@ -60,6 +61,7 @@ private:
nsTArray<RefPtr<PlatformDecoderModule>> mCurrentPDMs;
RefPtr<PlatformDecoderModule> mEMEPDM;
RefPtr<PlatformDecoderModule> mBlankPDM;
bool mWMFFailedToLoad = false;
bool mFFmpegFailedToLoad = false;

Просмотреть файл

@ -64,6 +64,7 @@ struct CreateDecoderParams {
layers::ImageContainer* mImageContainer = nullptr;
layers::LayersBackend mLayersBackend = layers::LayersBackend::LAYERS_NONE;
RefPtr<GMPCrashHelper> mCrashHelper;
bool mUseBlankDecoder = false;
private:
void Set(TaskQueue* aTaskQueue) { mTaskQueue = aTaskQueue; }
@ -72,6 +73,7 @@ private:
void Set(layers::ImageContainer* aImageContainer) { mImageContainer = aImageContainer; }
void Set(layers::LayersBackend aLayersBackend) { mLayersBackend = aLayersBackend; }
void Set(GMPCrashHelper* aCrashHelper) { mCrashHelper = aCrashHelper; }
void Set(bool aUseBlankDecoder) { mUseBlankDecoder = aUseBlankDecoder; }
template <typename T1, typename T2, typename... Ts>
void Set(T1&& a1, T2&& a2, Ts&&... args)
{

Просмотреть файл

@ -4,6 +4,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "H264Converter.h"
#include "ImageContainer.h"
#include "MediaDecoderReader.h"
#include "MediaInfo.h"
@ -11,9 +12,11 @@
#include "mozilla/mozalloc.h" // for operator new, and new (fallible)
#include "mozilla/RefPtr.h"
#include "mozilla/TaskQueue.h"
#include "mp4_demuxer/H264.h"
#include "nsAutoPtr.h"
#include "nsRect.h"
#include "PlatformDecoderModule.h"
#include "ReorderQueue.h"
#include "TimeUnits.h"
#include "VideoUtils.h"
@ -29,6 +32,10 @@ public:
const CreateDecoderParams& aParams)
: mCreator(aCreator)
, mCallback(aParams.mCallback)
, mMaxRefFrames(aParams.mConfig.GetType() == TrackInfo::kVideoTrack &&
H264Converter::IsH264(aParams.mConfig)
? mp4_demuxer::H264::ComputeMaxRefFrames(aParams.VideoConfig().mExtraData)
: 0)
, mType(aParams.mConfig.GetType())
{
}
@ -47,19 +54,25 @@ public:
mCreator->Create(media::TimeUnit::FromMicroseconds(aSample->mTime),
media::TimeUnit::FromMicroseconds(aSample->mDuration),
aSample->mOffset);
if (!data) {
mCallback->Error(MediaDataDecoderError::FATAL_ERROR);
} else {
mCallback->Output(data);
OutputFrame(data);
return NS_OK;
}
nsresult Flush() override
{
mReorderQueue.Clear();
return NS_OK;
}
nsresult Drain() override
{
while (!mReorderQueue.IsEmpty()) {
mCallback->Output(mReorderQueue.Pop().get());
}
return NS_OK;
}
nsresult Flush() override {
return NS_OK;
}
nsresult Drain() override {
mCallback->DrainComplete();
return NS_OK;
}
@ -69,9 +82,32 @@ public:
return "blank media data decoder";
}
private:
void OutputFrame(MediaData* aData)
{
if (!aData) {
mCallback->Error(MediaDataDecoderError::FATAL_ERROR);
return;
}
// Frames come out in DTS order but we need to output them in PTS order.
mReorderQueue.Push(aData);
while (mReorderQueue.Length() > mMaxRefFrames) {
mCallback->Output(mReorderQueue.Pop().get());
}
if (mReorderQueue.Length() <= mMaxRefFrames) {
mCallback->InputExhausted();
}
}
private:
nsAutoPtr<BlankMediaDataCreator> mCreator;
MediaDataDecoderCallback* mCallback;
const uint32_t mMaxRefFrames;
ReorderQueue mReorderQueue;
TrackInfo::TrackType mType;
};
@ -93,10 +129,10 @@ public:
{
// Create a fake YUV buffer in a 420 format. That is, an 8bpp Y plane,
// with a U and V plane that are half the size of the Y plane, i.e 8 bit,
// 2x2 subsampled. Have the data pointers of each frame point to the
// first plane, they'll always be zero'd memory anyway.
auto frame = MakeUnique<uint8_t[]>(mFrameWidth * mFrameHeight);
memset(frame.get(), 0, mFrameWidth * mFrameHeight);
// 2x2 subsampled.
const int sizeY = mFrameWidth * mFrameHeight;
const int sizeCbCr = ((mFrameWidth + 1) / 2) * ((mFrameHeight + 1) / 2);
auto frame = MakeUnique<uint8_t[]>(sizeY + sizeCbCr);
VideoData::YCbCrBuffer buffer;
// Y plane.
@ -108,7 +144,7 @@ public:
buffer.mPlanes[0].mSkip = 0;
// Cb plane.
buffer.mPlanes[1].mData = frame.get();
buffer.mPlanes[1].mData = frame.get() + sizeY;
buffer.mPlanes[1].mStride = mFrameWidth / 2;
buffer.mPlanes[1].mHeight = mFrameHeight / 2;
buffer.mPlanes[1].mWidth = mFrameWidth / 2;
@ -116,13 +152,17 @@ public:
buffer.mPlanes[1].mSkip = 0;
// Cr plane.
buffer.mPlanes[2].mData = frame.get();
buffer.mPlanes[2].mData = frame.get() + sizeY;
buffer.mPlanes[2].mStride = mFrameWidth / 2;
buffer.mPlanes[2].mHeight = mFrameHeight / 2;
buffer.mPlanes[2].mWidth = mFrameWidth / 2;
buffer.mPlanes[2].mOffset = 0;
buffer.mPlanes[2].mSkip = 0;
// Set to color white.
memset(buffer.mPlanes[0].mData, 255, sizeY);
memset(buffer.mPlanes[1].mData, 128, sizeCbCr);
return VideoData::Create(mInfo,
mImageContainer,
nullptr,
@ -134,6 +174,7 @@ public:
aDTS.ToMicroseconds(),
mPicture);
}
private:
VideoInfo mInfo;
gfx::IntRect mPicture;
@ -142,7 +183,6 @@ private:
RefPtr<layers::ImageContainer> mImageContainer;
};
class BlankAudioDataCreator {
public:
BlankAudioDataCreator(uint32_t aChannelCount, uint32_t aSampleRate)
@ -229,7 +269,11 @@ public:
ConversionRequired
DecoderNeedsConversion(const TrackInfo& aConfig) const override
{
return kNeedNone;
if (aConfig.IsVideo() && H264Converter::IsH264(aConfig)) {
return kNeedAVCC;
} else {
return kNeedNone;
}
}
};

Просмотреть файл

@ -11,9 +11,9 @@
#include "AppleUtils.h"
#include "AppleVTDecoder.h"
#include "AppleVTLinker.h"
#include "mp4_demuxer/H264.h"
#include "MediaData.h"
#include "mozilla/ArrayUtils.h"
#include "mp4_demuxer/H264.h"
#include "nsAutoPtr.h"
#include "nsThreadUtils.h"
#include "mozilla/Logging.h"
@ -24,22 +24,6 @@
namespace mozilla {
static uint32_t ComputeMaxRefFrames(const MediaByteBuffer* aExtraData)
{
uint32_t maxRefFrames = 4;
// Retrieve video dimensions from H264 SPS NAL.
mp4_demuxer::SPSData spsdata;
if (mp4_demuxer::H264::DecodeSPSFromExtraData(aExtraData, spsdata)) {
// max_num_ref_frames determines the size of the sliding window
// we need to queue that many frames in order to guarantee proper
// pts frames ordering. Use a minimum of 4 to ensure proper playback of
// non compliant videos.
maxRefFrames =
std::min(std::max(maxRefFrames, spsdata.max_num_ref_frames + 1), 16u);
}
return maxRefFrames;
}
AppleVTDecoder::AppleVTDecoder(const VideoInfo& aConfig,
TaskQueue* aTaskQueue,
MediaDataDecoderCallback* aCallback,
@ -52,7 +36,7 @@ AppleVTDecoder::AppleVTDecoder(const VideoInfo& aConfig,
, mDisplayHeight(aConfig.mDisplay.height)
, mQueuedSamples(0)
, mTaskQueue(aTaskQueue)
, mMaxRefFrames(ComputeMaxRefFrames(aConfig.mExtraData))
, mMaxRefFrames(mp4_demuxer::H264::ComputeMaxRefFrames(aConfig.mExtraData))
, mImageContainer(aImageContainer)
, mInputIncoming(0)
, mIsShutDown(false)

Просмотреть файл

@ -106,7 +106,7 @@ MediaEngineDefaultVideoSource::Allocate(const dom::MediaTrackConstraints &aConst
mOpts.mHeight = c.mHeight.Get(aPrefs.mHeight ? aPrefs.mHeight :
MediaEngine::DEFAULT_43_VIDEO_HEIGHT);
mState = kAllocated;
aOutHandle = nullptr;
*aOutHandle = nullptr;
return NS_OK;
}
@ -415,7 +415,7 @@ MediaEngineDefaultAudioSource::Allocate(const dom::MediaTrackConstraints &aConst
// generate sine wave (default 1KHz)
mSineGenerator = new SineWaveGenerator(AUDIO_RATE,
static_cast<uint32_t>(aPrefs.mFreq ? aPrefs.mFreq : 1000));
aOutHandle = nullptr;
*aOutHandle = nullptr;
return NS_OK;
}

Просмотреть файл

@ -168,7 +168,7 @@ MediaEngineGonkVideoSource::Allocate(const dom::MediaTrackConstraints& aConstrai
}
}
aOutHandle = nullptr;
*aOutHandle = nullptr;
return NS_OK;
}

Просмотреть файл

@ -148,7 +148,7 @@ MediaEngineTabVideoSource::Allocate(const dom::MediaTrackConstraints& aConstrain
mWindowId = aConstraints.mBrowserWindow.WasPassed() ?
aConstraints.mBrowserWindow.Value() : -1;
aOutHandle = nullptr;
*aOutHandle = nullptr;
return Restart(nullptr, aConstraints, aPrefs, aDeviceId, aOutBadConstraint);
}

Просмотреть файл

@ -82,7 +82,7 @@ public:
const char** aOutBadConstraint) override
{
// Nothing to do here, everything is managed in MediaManager.cpp
aOutHandle = nullptr;
*aOutHandle = nullptr;
return NS_OK;
}
nsresult Deallocate(AllocationHandle* aHandle) override

Просмотреть файл

@ -106,7 +106,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=803225
testContent.appendChild(newscript);
// Test 7: mailto protocol
SpecialPowers.loadChromeScript(function launchHandler() {
let mm = SpecialPowers.loadChromeScript(function launchHandler() {
var { classes: Cc, interfaces: Ci } = Components;
var ioService = Cc["@mozilla.org/network/io-service;1"].
getService(Ci.nsIIOService);
@ -116,25 +116,36 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=803225
webHandler.name = "Web Handler";
webHandler.uriTemplate = "http://example.com/tests/dom/security/test/mixedcontentblocker/file_bug803225_test_mailto.html?s=%";
Components.utils.import("resource://gre/modules/Services.jsm");
Services.ppmm.addMessageListener("Test:content-ready", function contentReadyListener() {
Services.ppmm.removeMessageListener("Test:content-ready", contentReadyListener);
sendAsyncMessage("Test:content-ready-forward");
})
Services.ppmm.loadProcessScript("data:,new " + function () {
var os = Components.classes["@mozilla.org/observer-service;1"]
.getService(Components.interfaces.nsIObserverService);
var observer = {
observe: function(subject, topic, data) {
if (topic == "content-document-global-created" && data == "http://example.com") {
sendAsyncMessage("Test:content-ready");
os.removeObserver(observer, "content-document-global-created");
}
}
};
os.addObserver(observer, "content-document-global-created", false);
}, false);
var uri = ioService.newURI("mailto:foo@bar.com", null, null);
webHandler.launchWithURI(uri);
});
var mailto = false;
// listen for a messages from a new window
var os = SpecialPowers.Cc["@mozilla.org/observer-service;1"].
getService(SpecialPowers.Components.interfaces.nsIObserverService);
var observer = {
observe: function(subject, topic, data) {
if(topic == "content-document-global-created" && data =="http://example.com") {
parent.postMessage({"test": "mailto", "msg": "resource with mailto protocol loaded"}, "http://mochi.test:8888");
os.removeObserver(observer, "content-document-global-created");
mailto = true;
}
}
}
os.addObserver(observer, "content-document-global-created", false);
mm.addMessageListener("Test:content-ready-forward", function contentReadyListener() {
mm.removeMessageListener("Test:content-ready-forward", contentReadyListener);
mailto = true;
parent.postMessage({"test": "mailto", "msg": "resource with mailto protocol loaded"}, "http://mochi.test:8888");
});
function mailtoProtocolStatus() {
if(!mailto) {

Просмотреть файл

@ -214,3 +214,12 @@ partial interface HTMLMediaElement {
[Throws, Pref="media.seekToNextFrame.enabled"]
Promise<void> seekToNextFrame();
};
/*
* This is an API for simulating visibility changes to help debug and write
* tests about suspend-video-decoding.
*/
partial interface HTMLMediaElement {
[Pref="media.test.setVisible"]
void setVisible(boolean aVisible);
};

Просмотреть файл

@ -10,27 +10,27 @@
typedef long long GLint64; // Should this be int64?
typedef unsigned long long GLuint64;
[Pref="webgl.enable-prototype-webgl2"]
[Pref="webgl.enable-webgl2"]
interface WebGLQuery {
};
[Pref="webgl.enable-prototype-webgl2"]
[Pref="webgl.enable-webgl2"]
interface WebGLSampler {
};
[Pref="webgl.enable-prototype-webgl2"]
[Pref="webgl.enable-webgl2"]
interface WebGLSync {
};
[Pref="webgl.enable-prototype-webgl2"]
[Pref="webgl.enable-webgl2"]
interface WebGLTransformFeedback {
};
[Pref="webgl.enable-prototype-webgl2"]
[Pref="webgl.enable-webgl2"]
interface WebGLVertexArrayObject {
};
[Pref="webgl.enable-prototype-webgl2"]
[Pref="webgl.enable-webgl2"]
interface WebGL2RenderingContext : WebGLRenderingContext
{
const GLenum READ_BUFFER = 0x0C02;

Просмотреть файл

@ -904,17 +904,6 @@ nsEditingSession::StartDocumentLoad(nsIWebProgress *aWebProgress,
NS_ENSURE_ARG_POINTER(aWebProgress);
// If we have an editor here, then we got a reload after making the editor.
// We need to blow it away and make a new one at the end of the load.
nsCOMPtr<mozIDOMWindowProxy> domWindow;
aWebProgress->GetDOMWindow(getter_AddRefs(domWindow));
if (domWindow)
{
nsIDocShell *docShell = nsPIDOMWindowOuter::From(domWindow)->GetDocShell();
NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE);
docShell->DetachEditorFromWindow();
}
if (aIsToBeMadeEditable)
mEditorStatus = eEditorCreationInProgress;

Просмотреть файл

@ -12,3 +12,4 @@ skip-if = buildapp == 'b2g' || os == 'android'
[test_bug1205983.html]
[test_bug1209414.html]
[test_bug1219928.html]
[test_bug1266815.html]

Просмотреть файл

@ -0,0 +1,82 @@
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SpawnTask.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
</head>
<body>
<p id="display"></p>
<script type="text/javascript">
const Cc = SpecialPowers.Cc;
const Ci = SpecialPowers.Ci;
const Cu = SpecialPowers.Cu;
const {XPCOMUtils} = Cu.import("resource://gre/modules/XPCOMUtils.jsm", {});
const HELPERAPP_DIALOG_CID =
SpecialPowers.wrap(SpecialPowers.Components)
.ID(Cc["@mozilla.org/helperapplauncherdialog;1"].number);
const HELPERAPP_DIALOG_CONTRACT_ID = "@mozilla.org/helperapplauncherdialog;1";
const MOCK_HELPERAPP_DIALOG_CID =
SpecialPowers.wrap(SpecialPowers.Components)
.ID("{391832c8-5232-4676-b838-cc8ad373f3d8}");
var registrar = SpecialPowers.wrap(Components).manager
.QueryInterface(Ci.nsIComponentRegistrar);
var helperAppDlgPromise = new Promise(function(resolve) {
var mockHelperAppService;
function HelperAppLauncherDialog() {
}
HelperAppLauncherDialog.prototype = {
show: function(aLauncher, aWindowContext, aReason) {
ok(true, "Whether showing Dialog");
resolve();
registrar.unregisterFactory(MOCK_HELPERAPP_DIALOG_CID,
mockHelperAppService);
},
QueryInterface: XPCOMUtils.generateQI([Ci.nsIHelperAppLauncherDialog])
};
mockHelperAppService = XPCOMUtils._getFactory(HelperAppLauncherDialog);
registrar.registerFactory(MOCK_HELPERAPP_DIALOG_CID, "",
HELPERAPP_DIALOG_CONTRACT_ID,
mockHelperAppService);
});
add_task(function*() {
let promise = new Promise(function(resolve) {
let iframe = document.createElement("iframe");
iframe.onload = function() {
is(iframe.contentDocument.getElementById("edit").innerText, "abc",
"load iframe source");
resolve();
};
iframe.id = "testframe";
iframe.src = "data:text/html,<div id=edit contenteditable=true>abc</div>";
document.body.appendChild(iframe);
});
yield promise;
let iframe = document.getElementById("testframe");
let docShell = SpecialPowers.wrap(iframe.contentWindow)
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell);
ok(docShell.hasEditingSession, "Should have editing session");
document.getElementById("testframe").src =
"data:application/octet-stream,TESTCONTENT";
yield helperAppDlgPromise;
ok(docShell.hasEditingSession, "Should have editing session");
});
</script>
</body>
</html>

Просмотреть файл

@ -273,6 +273,7 @@ const char *kWebBrowserPersistStringBundle =
"chrome://global/locale/nsWebBrowserPersist.properties";
nsWebBrowserPersist::nsWebBrowserPersist() :
mCurrentDataPathIsRelative(false),
mCurrentThingsToPersist(0),
mFirstAndOnlyUse(true),
mSavingDocument(false),

Просмотреть файл

@ -1671,6 +1671,7 @@ nsPermissionManager::AddInternal(nsIPrincipal* aPrincipal,
id = aID;
}
#ifdef MOZ_B2G
// When we do the initial addition of the permissions we don't want to
// inherit session specific permissions from other tabs or apps
// so we ignore them and set the permission to PROMPT_ACTION if it was
@ -1680,6 +1681,7 @@ nsPermissionManager::AddInternal(nsIPrincipal* aPrincipal,
aPermission = nsIPermissionManager::PROMPT_ACTION;
aExpireType = nsIPermissionManager::EXPIRE_NEVER;
}
#endif // MOZ_B2G
entry->GetPermissions().AppendElement(PermissionEntry(id, typeIndex, aPermission,
aExpireType, aExpireTime,

Просмотреть файл

@ -31,7 +31,7 @@ function run_test() {
case "TESTING:Stage2A":
// Permissions created after the child is present
do_check_eq(pm.testPermissionFromPrincipal(getPrincipalForURI("http://mozilla.org"), "cookie1"), pm.ALLOW_ACTION);
do_check_eq(pm.testPermissionFromPrincipal(getPrincipalForURI("http://mozilla.com"), "cookie2"), pm.PROMPT_ACTION);
do_check_eq(pm.testPermissionFromPrincipal(getPrincipalForURI("http://mozilla.com"), "cookie2"), pm.DENY_ACTION);
do_check_eq(pm.testPermissionFromPrincipal(getPrincipalForURI("http://mozilla.net"), "cookie3"), pm.ALLOW_ACTION);
do_check_eq(pm.testPermissionFromPrincipal(getPrincipalForURI("http://firefox.org"), "cookie1"), pm.ALLOW_ACTION);
do_check_eq(pm.testPermissionFromPrincipal(getPrincipalForURI("http://firefox.com"), "cookie2"), pm.DENY_ACTION);
@ -50,7 +50,7 @@ function run_test() {
// Permissions created before the child is present
var pm = Cc["@mozilla.org/permissionmanager;1"].getService(Ci.nsIPermissionManager);
do_check_eq(pm.testPermissionFromPrincipal(getPrincipalForURI("http://mozilla.org"), "cookie1"), pm.ALLOW_ACTION);
do_check_eq(pm.testPermissionFromPrincipal(getPrincipalForURI("http://mozilla.com"), "cookie2"), pm.PROMPT_ACTION);
do_check_eq(pm.testPermissionFromPrincipal(getPrincipalForURI("http://mozilla.com"), "cookie2"), pm.DENY_ACTION);
do_check_eq(pm.testPermissionFromPrincipal(getPrincipalForURI("http://mozilla.net"), "cookie3"), pm.ALLOW_ACTION);
mM.sendAsyncMessage("TESTING:Stage2");

Просмотреть файл

@ -163,6 +163,7 @@ static const char* const sExtensionNames[] = {
"GL_NV_geometry_program4",
"GL_NV_half_float",
"GL_NV_instanced_arrays",
"GL_NV_primitive_restart",
"GL_NV_texture_barrier",
"GL_NV_transform_feedback",
"GL_NV_transform_feedback2",
@ -1574,6 +1575,14 @@ GLContext::LoadMoreSymbols(const char* prefix, bool trygl)
fnLoadForFeature(symbols, GLFeature::invalidate_framebuffer);
}
if (IsSupported(GLFeature::prim_restart)) {
const SymLoadStruct symbols[] = {
{ (PRFuncPtr*) &mSymbols.fPrimitiveRestartIndex, { "PrimitiveRestartIndex", "PrimitiveRestartIndexNV", nullptr } },
END_SYMBOLS
};
fnLoadForFeature(symbols, GLFeature::prim_restart);
}
if (IsExtensionSupported(KHR_debug)) {
const SymLoadStruct symbols[] = {
{ (PRFuncPtr*) &mSymbols.fDebugMessageControl, { "DebugMessageControl", "DebugMessageControlKHR", nullptr } },

Просмотреть файл

@ -110,6 +110,8 @@ enum class GLFeature {
occlusion_query_boolean,
occlusion_query2,
packed_depth_stencil,
prim_restart,
prim_restart_fixed,
query_counter,
query_objects,
query_time_elapsed,
@ -477,6 +479,7 @@ public:
NV_geometry_program4,
NV_half_float,
NV_instanced_arrays,
NV_primitive_restart,
NV_texture_barrier,
NV_transform_feedback,
NV_transform_feedback2,
@ -3171,6 +3174,16 @@ public:
AFTER_GL_CALL;
}
// -----------------------------------------------------------------------------
// prim_restart
void fPrimitiveRestartIndex(GLuint index) {
BEFORE_GL_CALL;
ASSERT_SYMBOL_PRESENT(fPrimitiveRestartIndex);
mSymbols.fPrimitiveRestartIndex(index);
AFTER_GL_CALL;
}
// -----------------------------------------------------------------------------
// Constructor
protected:

Просмотреть файл

@ -439,6 +439,25 @@ static const FeatureInfo sFeatureInfoArr[] = {
GLContext::Extensions_End
}
},
{
"prim_restart",
GLVersion::GL3_1,
GLESVersion::NONE,
GLContext::Extension_None,
{
GLContext::NV_primitive_restart,
GLContext::Extensions_End
}
},
{
"prim_restart_fixed",
kGLCoreVersionForES3Compat,
GLESVersion::ES3,
GLContext::ARB_ES3_compatibility,
{
GLContext::Extensions_End
}
},
{
"query_counter",
GLVersion::GL3_3,

Просмотреть файл

@ -694,6 +694,9 @@ struct GLContextSymbols
// NV_texture_barrier
typedef void (GLAPIENTRY * PFNTEXTUREBARRIERPROC) (void);
PFNTEXTUREBARRIERPROC fTextureBarrier;
// NV_primitive_restart
void (GLAPIENTRY * fPrimitiveRestartIndex) (GLuint index);
};
} // namespace gl

Просмотреть файл

@ -499,7 +499,8 @@ APZCCallbackHelper::DispatchMouseEvent(const nsCOMPtr<nsIPresShell>& aPresShell,
bool defaultPrevented = false;
nsContentUtils::SendMouseEvent(aPresShell, aType, aPoint.x, aPoint.y,
aButton, aClickCount, aModifiers, aIgnoreRootScrollFrame, 0,
aInputSourceArg, false, &defaultPrevented, false);
aInputSourceArg, false, &defaultPrevented, false,
/* aIsWidgetEventSynthesized = */ false);
return defaultPrevented;
}

Просмотреть файл

@ -58,9 +58,6 @@ public:
for (uint32_t i = 0; i < children.Length(); i++) {
Layer* child = children.ElementAt(i);
if (!child->IsVisible()) {
continue;
}
ToClientLayer(child)->RenderLayerWithReadback(&readback);

Просмотреть файл

@ -1238,15 +1238,15 @@ CompositorD3D11::BeginFrame(const nsIntRegion& aInvalidRegion,
void
CompositorD3D11::EndFrame()
{
Compositor::EndFrame();
if (!mDefaultRT) {
Compositor::EndFrame();
return;
}
LayoutDeviceIntSize oldSize = mSize;
EnsureSize();
if (mSize.width <= 0 || mSize.height <= 0) {
Compositor::EndFrame();
return;
}
@ -1334,6 +1334,8 @@ CompositorD3D11::EndFrame()
// Store the query for this frame so we can flush it next time.
mQuery = query;
Compositor::EndFrame();
mCurrentRT = nullptr;
}

Просмотреть файл

@ -720,8 +720,6 @@ CompositorD3D9::BeginFrame(const nsIntRegion& aInvalidRegion,
void
CompositorD3D9::EndFrame()
{
Compositor::EndFrame();
if (mDeviceManager) {
device()->EndScene();
@ -736,6 +734,8 @@ CompositorD3D9::EndFrame()
}
}
Compositor::EndFrame();
mCurrentRT = nullptr;
mDefaultRT = nullptr;
}

Просмотреть файл

@ -1463,8 +1463,6 @@ CompositorOGL::EndFrame()
MOZ_ASSERT(mCurrentRenderTarget == mWindowRenderTarget, "Rendering target not properly restored");
Compositor::EndFrame();
#ifdef MOZ_DUMP_PAINTING
if (gfxEnv::DumpCompositorTextures()) {
LayoutDeviceIntSize size;
@ -1489,6 +1487,7 @@ CompositorOGL::EndFrame()
CopyToTarget(mTarget, mTargetBounds.TopLeft(), Matrix());
mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
mCurrentRenderTarget = nullptr;
Compositor::EndFrame();
return;
}
@ -1509,6 +1508,8 @@ CompositorOGL::EndFrame()
mGLContext->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, 0);
}
}
Compositor::EndFrame();
}
void

Просмотреть файл

@ -413,7 +413,6 @@ private:
DECL_GFX_PREF(Once, "image.mem.surfacecache.size_factor", ImageMemSurfaceCacheSizeFactor, uint32_t, 64);
DECL_GFX_PREF(Live, "image.mozsamplesize.enabled", ImageMozSampleSizeEnabled, bool, false);
DECL_GFX_PREF(Once, "image.multithreaded_decoding.limit", ImageMTDecodingLimit, int32_t, -1);
DECL_GFX_PREF(Live, "image.single-color-optimization.enabled", ImageSingleColorOptimizationEnabled, bool, true);
DECL_GFX_PREF(Once, "layers.acceleration.disabled", LayersAccelerationDisabledDoNotUseDirectly, bool, false);
DECL_GFX_PREF(Live, "layers.acceleration.draw-fps", LayersDrawFPS, bool, false);
@ -553,7 +552,7 @@ private:
DECL_GFX_PREF(Live, "webgl.enable-draft-extensions", WebGLDraftExtensionsEnabled, bool, false);
DECL_GFX_PREF(Live, "webgl.enable-privileged-extensions", WebGLPrivilegedExtensionsEnabled, bool, false);
DECL_GFX_PREF(Once, "webgl.enable-prototype-webgl2", WebGL2Enabled, bool, false);
DECL_GFX_PREF(Live, "webgl.enable-webgl2", WebGL2Enabled, bool, true);
DECL_GFX_PREF(Live, "webgl.force-enabled", WebGLForceEnabled, bool, false);
DECL_GFX_PREF(Once, "webgl.force-layers-readback", WebGLForceLayersReadback, bool, false);
DECL_GFX_PREF(Live, "webgl.lose-context-on-memory-pressure", WebGLLoseContextOnMemoryPressure, bool, false);

Просмотреть файл

@ -271,14 +271,16 @@ Decoder::AllocateFrame(uint32_t aFrameNum,
mCurrentFrame->GetImageData(&mImageData, &mImageDataLength);
mCurrentFrame->GetPaletteData(&mColormap, &mColormapSize);
if (aFrameNum + 1 == mFrameCount) {
// If we're past the first frame, PostIsAnimated() should've been called.
MOZ_ASSERT_IF(mFrameCount > 1, HasAnimation());
// We should now be on |aFrameNum|. (Note that we're comparing the frame
// number, which is zero-based, with the frame count, which is one-based.)
MOZ_ASSERT(aFrameNum + 1 == mFrameCount);
// Update our state to reflect the new frame
MOZ_ASSERT(!mInFrame, "Starting new frame but not done with old one!");
mInFrame = true;
}
// If we're past the first frame, PostIsAnimated() should've been called.
MOZ_ASSERT_IF(mFrameCount > 1, HasAnimation());
// Update our state to reflect the new frame.
MOZ_ASSERT(!mInFrame, "Starting new frame but not done with old one!");
mInFrame = true;
}
return mCurrentFrame ? NS_OK : NS_ERROR_FAILURE;

Просмотреть файл

@ -24,6 +24,12 @@ NotifyProgress(NotNull<Decoder*> aDecoder)
{
MOZ_ASSERT(aDecoder->HasProgress() && !aDecoder->IsMetadataDecode());
// Capture the decoder's state. If we need to notify asynchronously, it's
// important that we don't wait until the lambda actually runs to capture the
// state that we're going to notify. That would both introduce data races on
// the decoder's state and cause inconsistencies between the NotifyProgress()
// calls we make off-main-thread and the notifications that RasterImage
// actually receives, which would cause bugs.
Progress progress = aDecoder->TakeProgress();
IntRect invalidRect = aDecoder->TakeInvalidRect();
Maybe<uint32_t> frameCount = aDecoder->TakeCompleteFrameCount();

Просмотреть файл

@ -481,84 +481,6 @@ RasterImage::GetFirstFrameDelay()
return mAnimationState->FirstFrameTimeout().AsEncodedValueDeprecated();
}
already_AddRefed<SourceSurface>
RasterImage::CopyFrame(uint32_t aWhichFrame, uint32_t aFlags)
{
if (aWhichFrame > FRAME_MAX_VALUE) {
return nullptr;
}
if (mError) {
return nullptr;
}
// Get the frame. If it's not there, it's probably the caller's fault for
// not waiting for the data to be loaded from the network or not passing
// FLAG_SYNC_DECODE
DrawableFrameRef frameRef =
LookupFrame(GetRequestedFrameIndex(aWhichFrame), mSize, aFlags);
if (!frameRef) {
// The OS threw this frame away and we couldn't redecode it right now.
return nullptr;
}
// Create a 32-bit surface at the decoded size of the image. If
// FLAG_SYNC_DECODE was not passed, we may have substituted a downscaled
// version of the image we already had available, so this is not necessarily
// the intrinsic size of the image. We'll take the frame rect of the image
// into account when we draw, implicitly adding padding so that the caller
// doesn't need to worry about frame rects.
// XXX(seth): In bug 1247520 we'll remove support for frame rects, rendering
// this additional padding unnecessary.
RefPtr<DataSourceSurface> surf =
Factory::CreateDataSourceSurface(frameRef->GetImageSize(),
SurfaceFormat::B8G8R8A8,
/* aZero = */ true);
if (NS_WARN_IF(!surf)) {
return nullptr;
}
DataSourceSurface::MappedSurface mapping;
if (!surf->Map(DataSourceSurface::MapType::WRITE, &mapping)) {
gfxCriticalError() << "RasterImage::CopyFrame failed to map surface";
return nullptr;
}
RefPtr<DrawTarget> target =
Factory::CreateDrawTargetForData(BackendType::CAIRO,
mapping.mData,
frameRef->GetImageSize(),
mapping.mStride,
SurfaceFormat::B8G8R8A8);
if (!target) {
gfxWarning() << "RasterImage::CopyFrame failed in CreateDrawTargetForData";
return nullptr;
}
IntRect intFrameRect = frameRef->GetRect();
Rect rect(intFrameRect.x, intFrameRect.y,
intFrameRect.width, intFrameRect.height);
if (frameRef->IsSinglePixel()) {
target->FillRect(rect, ColorPattern(frameRef->SinglePixelColor()),
DrawOptions(1.0f, CompositionOp::OP_SOURCE));
} else {
RefPtr<SourceSurface> srcSurf = frameRef->GetSurface();
if (!srcSurf) {
RecoverFromInvalidFrames(mSize, aFlags);
return nullptr;
}
Rect srcRect(0, 0, intFrameRect.width, intFrameRect.height);
target->DrawSurface(srcSurf, srcRect, rect);
}
target->Flush();
surf->Unmap();
return surf.forget();
}
//******************************************************************************
NS_IMETHODIMP_(already_AddRefed<SourceSurface>)
RasterImage::GetFrame(uint32_t aWhichFrame,
uint32_t aFlags)
@ -603,21 +525,7 @@ RasterImage::GetFrameInternal(const IntSize& aSize,
return MakePair(DrawResult::TEMPORARY_ERROR, RefPtr<SourceSurface>());
}
// If this frame covers the entire image, we can just reuse its existing
// surface.
RefPtr<SourceSurface> frameSurf;
if (!frameRef->NeedsPadding() &&
frameRef->GetSize() == frameRef->GetImageSize()) {
frameSurf = frameRef->GetSurface();
}
// The image doesn't have a usable surface because it's been optimized away or
// because it's a partial update frame from an animation. Create one. (In this
// case we fall back to returning a surface at our intrinsic size, even if a
// different size was originally specified.)
if (!frameSurf) {
frameSurf = CopyFrame(aWhichFrame, aFlags);
}
RefPtr<SourceSurface> frameSurf = frameRef->GetSurface();
if (!frameRef->IsFinished()) {
return MakePair(DrawResult::INCOMPLETE, Move(frameSurf));
@ -1640,7 +1548,7 @@ RasterImage::NotifyProgress(Progress aProgress,
}
// We may have decoded new animation frames; update our animation state.
MOZ_ASSERT_IF(aFrameCount && *aFrameCount > 1, mAnimationState);
MOZ_ASSERT_IF(aFrameCount && *aFrameCount > 1, mAnimationState || mError);
if (mAnimationState && aFrameCount) {
mAnimationState->UpdateKnownFrameCount(*aFrameCount);
}

Просмотреть файл

@ -258,9 +258,6 @@ private:
gfx::SamplingFilter aSamplingFilter,
uint32_t aFlags);
already_AddRefed<gfx::SourceSurface> CopyFrame(uint32_t aWhichFrame,
uint32_t aFlags);
Pair<DrawResult, RefPtr<gfx::SourceSurface>>
GetFrameInternal(const gfx::IntSize& aSize,
uint32_t aWhichFrame,

Просмотреть файл

@ -172,7 +172,6 @@ imgFrame::imgFrame()
, mPalettedImageData(nullptr)
, mPaletteDepth(0)
, mNonPremult(false)
, mSinglePixel(false)
, mCompositingFailed(false)
{
}
@ -207,6 +206,19 @@ imgFrame::InitForDecoder(const nsIntSize& aImageSize,
mImageSize = aImageSize;
mFrameRect = aRect;
// We only allow a non-trivial frame rect (i.e., a frame rect that doesn't
// cover the entire image) for paletted animation frames. We never draw those
// frames directly; we just use FrameAnimator to composite them and produce a
// BGRA surface that we actually draw. We enforce this here to make sure that
// imgFrame::Draw(), which is responsible for drawing all other kinds of
// frames, never has to deal with a non-trivial frame rect.
if (aPaletteDepth == 0 &&
!mFrameRect.IsEqualEdges(IntRect(IntPoint(), mImageSize))) {
MOZ_ASSERT_UNREACHABLE("Creating a non-paletted imgFrame with a "
"non-trivial frame rect");
return NS_ERROR_FAILURE;
}
mFormat = aFormat;
mPaletteDepth = aPaletteDepth;
mNonPremult = aNonPremult;
@ -412,59 +424,16 @@ imgFrame::Optimize()
return NS_OK;
}
if (mPalettedImageData || mOptSurface || mSinglePixel) {
if (mPalettedImageData || mOptSurface) {
return NS_OK;
}
// Don't do single-color opts on non-premult data.
// Cairo doesn't support non-premult single-colors.
// XXX(seth): It's currently unclear if there's any reason why we can't
// optimize non-premult surfaces. We should look into removing this.
if (mNonPremult) {
return NS_OK;
}
/* Figure out if the entire image is a constant color */
if (gfxPrefs::ImageSingleColorOptimizationEnabled() &&
mImageSurface->Stride() == mFrameRect.width * 4) {
uint32_t* imgData = (uint32_t*) ((uint8_t*) mVBufPtr);
uint32_t firstPixel = * (uint32_t*) imgData;
uint32_t pixelCount = mFrameRect.Area() + 1;
while (--pixelCount && *imgData++ == firstPixel)
;
if (pixelCount == 0) {
// all pixels were the same
if (mFormat == SurfaceFormat::B8G8R8A8 ||
mFormat == SurfaceFormat::B8G8R8X8) {
mSinglePixel = true;
mSinglePixelColor.a = ((firstPixel >> 24) & 0xFF) * (1.0f / 255.0f);
mSinglePixelColor.r = ((firstPixel >> 16) & 0xFF) * (1.0f / 255.0f);
mSinglePixelColor.g = ((firstPixel >> 8) & 0xFF) * (1.0f / 255.0f);
mSinglePixelColor.b = ((firstPixel >> 0) & 0xFF) * (1.0f / 255.0f);
mSinglePixelColor.r /= mSinglePixelColor.a;
mSinglePixelColor.g /= mSinglePixelColor.a;
mSinglePixelColor.b /= mSinglePixelColor.a;
// blow away the older surfaces (if they exist), to release their memory
mVBuf = nullptr;
mVBufPtr = nullptr;
mImageSurface = nullptr;
mOptSurface = nullptr;
return NS_OK;
}
}
// if it's not RGB24/ARGB32, don't optimize, but we never hit this at the
// moment
}
const bool usedSingleColorOptimizationUsefully = mSinglePixel &&
mFrameRect.Area() > 1;
Telemetry::Accumulate(Telemetry::IMAGE_OPTIMIZE_TO_SINGLE_COLOR_USED,
usedSingleColorOptimizationUsefully);
#ifdef ANDROID
SurfaceFormat optFormat = gfxPlatform::GetPlatform()
->Optimal2DFormatForContent(gfxContentType::COLOR);
@ -559,63 +528,48 @@ imgFrame::SetRawAccessOnly()
imgFrame::SurfaceWithFormat
imgFrame::SurfaceForDrawing(bool aDoPadding,
bool aDoPartialDecode,
imgFrame::SurfaceForDrawing(bool aDoPartialDecode,
bool aDoTile,
gfxContext* aContext,
const nsIntMargin& aPadding,
gfxRect& aImageRect,
ImageRegion& aRegion,
SourceSurface* aSurface)
{
MOZ_ASSERT(NS_IsMainThread());
mMonitor.AssertCurrentThreadOwns();
IntSize size(int32_t(aImageRect.Width()), int32_t(aImageRect.Height()));
if (!aDoPadding && !aDoPartialDecode) {
NS_ASSERTION(!mSinglePixel, "This should already have been handled");
return SurfaceWithFormat(new gfxSurfaceDrawable(aSurface, size), mFormat);
if (!aDoPartialDecode) {
return SurfaceWithFormat(new gfxSurfaceDrawable(aSurface, mImageSize),
mFormat);
}
gfxRect available = gfxRect(mDecoded.x, mDecoded.y, mDecoded.width,
mDecoded.height);
if (aDoTile || mSinglePixel) {
if (aDoTile) {
// Create a temporary surface.
// Give this surface an alpha channel because there are
// transparent pixels in the padding or undecoded area
RefPtr<DrawTarget> target =
gfxPlatform::GetPlatform()->
CreateOffscreenContentDrawTarget(size, SurfaceFormat::B8G8R8A8);
CreateOffscreenContentDrawTarget(mImageSize, SurfaceFormat::B8G8R8A8);
if (!target) {
return SurfaceWithFormat();
}
// Fill 'available' with whatever we've got
if (mSinglePixel) {
target->FillRect(ToRect(aRegion.Intersect(available).Rect()),
ColorPattern(mSinglePixelColor),
DrawOptions(1.0f, CompositionOp::OP_SOURCE));
} else {
SurfacePattern pattern(aSurface,
aRegion.GetExtendMode(),
Matrix::Translation(mDecoded.x, mDecoded.y));
target->FillRect(ToRect(aRegion.Intersect(available).Rect()), pattern);
}
SurfacePattern pattern(aSurface,
aRegion.GetExtendMode(),
Matrix::Translation(mDecoded.x, mDecoded.y));
target->FillRect(ToRect(aRegion.Intersect(available).Rect()), pattern);
RefPtr<SourceSurface> newsurf = target->Snapshot();
return SurfaceWithFormat(new gfxSurfaceDrawable(newsurf, size),
return SurfaceWithFormat(new gfxSurfaceDrawable(newsurf, mImageSize),
target->GetFormat());
}
// Not tiling, and we have a surface, so we can account for
// padding and/or a partial decode just by twiddling parameters.
gfxPoint paddingTopLeft(aPadding.left, aPadding.top);
aRegion = aRegion.Intersect(available) - paddingTopLeft;
aContext->Multiply(gfxMatrix::Translation(paddingTopLeft));
aImageRect = gfxRect(0, 0, mFrameRect.width, mFrameRect.height);
// a partial decode just by twiddling parameters.
aRegion = aRegion.Intersect(available);
IntSize availableSize(mDecoded.width, mDecoded.height);
return SurfaceWithFormat(new gfxSurfaceDrawable(aSurface, availableSize),
mFormat);
}
@ -631,31 +585,20 @@ bool imgFrame::Draw(gfxContext* aContext, const ImageRegion& aRegion,
NS_ASSERTION(!aRegion.IsRestricted() ||
!aRegion.Rect().Intersect(aRegion.Restriction()).IsEmpty(),
"We must be allowed to sample *some* source pixels!");
NS_ASSERTION(!mPalettedImageData, "Directly drawing a paletted image!");
MOZ_ASSERT(mFrameRect.IsEqualEdges(IntRect(IntPoint(), mImageSize)),
"Directly drawing an image with a non-trivial frame rect!");
if (mPalettedImageData) {
MOZ_ASSERT_UNREACHABLE("Directly drawing a paletted image!");
return false;
}
MonitorAutoLock lock(mMonitor);
nsIntMargin padding(mFrameRect.y,
mImageSize.width - mFrameRect.XMost(),
mImageSize.height - mFrameRect.YMost(),
mFrameRect.x);
bool doPadding = padding != nsIntMargin(0,0,0,0);
bool doPartialDecode = !AreAllPixelsWritten();
if (mSinglePixel && !doPadding && !doPartialDecode) {
if (mSinglePixelColor.a == 0.0) {
return true;
}
RefPtr<DrawTarget> dt = aContext->GetDrawTarget();
dt->FillRect(ToRect(aRegion.Rect()),
ColorPattern(mSinglePixelColor),
DrawOptions(1.0f, aContext->CurrentOp()));
return true;
}
RefPtr<SourceSurface> surf = GetSurfaceInternal();
if (!surf && !mSinglePixel) {
if (!surf) {
return false;
}
@ -664,16 +607,8 @@ bool imgFrame::Draw(gfxContext* aContext, const ImageRegion& aRegion,
!(aImageFlags & imgIContainer::FLAG_CLAMP);
ImageRegion region(aRegion);
// SurfaceForDrawing changes the current transform, and we need it to still
// be changed when we call gfxUtils::DrawPixelSnapped. We still need to
// restore it before returning though.
// XXXjwatt In general having functions require someone further up the stack
// to undo transform changes that they make is bad practice. We should
// change how this code works.
gfxContextMatrixAutoSaveRestore autoSR(aContext);
SurfaceWithFormat surfaceResult =
SurfaceForDrawing(doPadding, doPartialDecode, doTile, aContext,
padding, imageRect, region, surf);
SurfaceForDrawing(doPartialDecode, doTile, region, surf);
if (surfaceResult.IsValid()) {
gfxUtils::DrawPixelSnapped(aContext, surfaceResult.mDrawable,
@ -921,20 +856,6 @@ imgFrame::SetOptimizable()
mOptimizable = true;
}
Color
imgFrame::SinglePixelColor() const
{
MOZ_ASSERT(NS_IsMainThread());
return mSinglePixelColor;
}
bool
imgFrame::IsSinglePixel() const
{
MOZ_ASSERT(NS_IsMainThread());
return mSinglePixel;
}
already_AddRefed<SourceSurface>
imgFrame::GetSurface()
{

Просмотреть файл

@ -321,7 +321,6 @@ public:
IntSize GetImageSize() const { return mImageSize; }
IntRect GetRect() const { return mFrameRect; }
IntSize GetSize() const { return mFrameRect.Size(); }
bool NeedsPadding() const { return mFrameRect.TopLeft() != IntPoint(0, 0); }
void GetImageData(uint8_t** aData, uint32_t* length) const;
uint8_t* GetImageData() const;
@ -337,9 +336,6 @@ public:
void SetOptimizable();
Color SinglePixelColor() const;
bool IsSinglePixel() const;
already_AddRefed<SourceSurface> GetSurface();
void AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf, size_t& aHeapSizeOut,
@ -379,12 +375,8 @@ private: // methods
bool IsValid() { return !!mDrawable; }
};
SurfaceWithFormat SurfaceForDrawing(bool aDoPadding,
bool aDoPartialDecode,
SurfaceWithFormat SurfaceForDrawing(bool aDoPartialDecode,
bool aDoTile,
gfxContext* aContext,
const nsIntMargin& aPadding,
gfxRect& aImageRect,
ImageRegion& aRegion,
SourceSurface* aSurface);
@ -445,10 +437,6 @@ private: // data
// Main-thread-only mutable data.
//////////////////////////////////////////////////////////////////////////////
// Note that the data stored in gfx::Color is *non-alpha-premultiplied*.
Color mSinglePixelColor;
bool mSinglePixel;
bool mCompositingFailed;
};

Просмотреть файл

@ -345,84 +345,6 @@ AnnotateSystemError()
nsPrintfCString("%lld", error));
}
}
void
AnnotateProcessInformation(base::ProcessId aPid)
{
#ifdef XP_WIN
ScopedProcessHandle processHandle(
OpenProcess(READ_CONTROL|PROCESS_QUERY_INFORMATION, FALSE, aPid));
if (!processHandle) {
CrashReporter::AnnotateCrashReport(
NS_LITERAL_CSTRING("IPCExtraSystemError"),
nsPrintfCString("Failed to get information of process %d, error(%d)",
aPid,
::GetLastError()));
return;
}
DWORD exitCode = 0;
if (!::GetExitCodeProcess(processHandle, &exitCode)) {
CrashReporter::AnnotateCrashReport(
NS_LITERAL_CSTRING("IPCExtraSystemError"),
nsPrintfCString("Failed to get exit information of process %d, error(%d)",
aPid,
::GetLastError()));
return;
}
if (exitCode != STILL_ACTIVE) {
CrashReporter::AnnotateCrashReport(
NS_LITERAL_CSTRING("IPCExtraSystemError"),
nsPrintfCString("Process %d is not alive. Exit code: %d",
aPid,
exitCode));
return;
}
ScopedPSecurityDescriptor secDesc(nullptr);
PSID ownerSid = nullptr;
DWORD rv = ::GetSecurityInfo(processHandle,
SE_KERNEL_OBJECT,
OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
&ownerSid,
nullptr,
nullptr,
nullptr,
&secDesc.rwget());
if (rv != ERROR_SUCCESS) {
// GetSecurityInfo() failed.
CrashReporter::AnnotateCrashReport(
NS_LITERAL_CSTRING("IPCExtraSystemError"),
nsPrintfCString("Failed to get security information of process %d,"
" error(%d)",
aPid,
rv));
return;
}
ScopedLPTStr ownerSidStr(nullptr);
nsString annotation{};
annotation.AppendLiteral("Owner: ");
if (::ConvertSidToStringSid(ownerSid, &ownerSidStr.rwget())) {
annotation.Append(ownerSidStr.get());
}
ScopedLPTStr secDescStr(nullptr);
annotation.AppendLiteral(", Security Descriptor: ");
if (::ConvertSecurityDescriptorToStringSecurityDescriptor(secDesc,
SDDL_REVISION_1,
DACL_SECURITY_INFORMATION,
&secDescStr.rwget(),
nullptr)) {
annotation.Append(secDescStr.get());
}
CrashReporter::AnnotateCrashReport(
NS_LITERAL_CSTRING("IPCExtraSystemError"),
NS_ConvertUTF16toUTF8(annotation));
#endif
}
#endif
void

Просмотреть файл

@ -439,10 +439,8 @@ DuplicateHandle(HANDLE aSourceHandle,
*/
#ifdef MOZ_CRASHREPORTER
void AnnotateSystemError();
void AnnotateProcessInformation(base::ProcessId aPid);
#else
#define AnnotateSystemError() do { } while (0)
#define AnnotateProcessInformation(...) do { } while (0)
#endif
/**

Просмотреть файл

@ -99,6 +99,10 @@ struct ReturnStopIteration
{
};
struct ReturnDeadCPOW
{
};
struct ReturnException
{
JSVariant exn;
@ -113,6 +117,7 @@ union ReturnStatus
{
ReturnSuccess;
ReturnStopIteration;
ReturnDeadCPOW;
ReturnException;
ReturnObjectOpResult;
};

Просмотреть файл

@ -73,6 +73,15 @@ WrapperAnswer::ok(ReturnStatus* rs, const JS::ObjectOpResult& result)
return true;
}
bool
WrapperAnswer::deadCPOW(AutoJSAPI& jsapi, ReturnStatus* rs)
{
JSContext* cx = jsapi.cx();
JS_ClearPendingException(cx);
*rs = ReturnStatus(ReturnDeadCPOW());
return true;
}
bool
WrapperAnswer::RecvPreventExtensions(const ObjectId& objId, ReturnStatus* rs)
{
@ -83,7 +92,7 @@ WrapperAnswer::RecvPreventExtensions(const ObjectId& objId, ReturnStatus* rs)
RootedObject obj(cx, findObjectById(cx, objId));
if (!obj)
return fail(jsapi, rs);
return deadCPOW(jsapi, rs);
ObjectOpResult success;
if (!JS_PreventExtensions(cx, obj, success))
@ -115,7 +124,7 @@ WrapperAnswer::RecvGetPropertyDescriptor(const ObjectId& objId, const JSIDVarian
RootedObject obj(cx, findObjectById(cx, objId));
if (!obj)
return fail(jsapi, rs);
return deadCPOW(jsapi, rs);
LOG("%s.getPropertyDescriptor(%s)", ReceiverObj(objId), Identifier(idVar));
@ -145,7 +154,7 @@ WrapperAnswer::RecvGetOwnPropertyDescriptor(const ObjectId& objId, const JSIDVar
RootedObject obj(cx, findObjectById(cx, objId));
if (!obj)
return fail(jsapi, rs);
return deadCPOW(jsapi, rs);
LOG("%s.getOwnPropertyDescriptor(%s)", ReceiverObj(objId), Identifier(idVar));
@ -174,7 +183,7 @@ WrapperAnswer::RecvDefineProperty(const ObjectId& objId, const JSIDVariant& idVa
RootedObject obj(cx, findObjectById(cx, objId));
if (!obj)
return fail(jsapi, rs);
return deadCPOW(jsapi, rs);
LOG("define %s[%s]", ReceiverObj(objId), Identifier(idVar));
@ -202,7 +211,7 @@ WrapperAnswer::RecvDelete(const ObjectId& objId, const JSIDVariant& idVar, Retur
RootedObject obj(cx, findObjectById(cx, objId));
if (!obj)
return fail(jsapi, rs);
return deadCPOW(jsapi, rs);
LOG("delete %s[%s]", ReceiverObj(objId), Identifier(idVar));
@ -228,7 +237,7 @@ WrapperAnswer::RecvHas(const ObjectId& objId, const JSIDVariant& idVar, ReturnSt
RootedObject obj(cx, findObjectById(cx, objId));
if (!obj)
return fail(jsapi, rs);
return deadCPOW(jsapi, rs);
LOG("%s.has(%s)", ReceiverObj(objId), Identifier(idVar));
@ -253,7 +262,7 @@ WrapperAnswer::RecvHasOwn(const ObjectId& objId, const JSIDVariant& idVar, Retur
RootedObject obj(cx, findObjectById(cx, objId));
if (!obj)
return fail(jsapi, rs);
return deadCPOW(jsapi, rs);
LOG("%s.hasOwn(%s)", ReceiverObj(objId), Identifier(idVar));
@ -281,7 +290,7 @@ WrapperAnswer::RecvGet(const ObjectId& objId, const JSVariant& receiverVar,
RootedObject obj(cx, findObjectById(cx, objId));
if (!obj)
return fail(aes, rs);
return deadCPOW(aes, rs);
RootedValue receiver(cx);
if (!fromVariant(cx, receiverVar, &receiver))
@ -314,7 +323,7 @@ WrapperAnswer::RecvSet(const ObjectId& objId, const JSIDVariant& idVar, const JS
RootedObject obj(cx, findObjectById(cx, objId));
if (!obj)
return fail(aes, rs);
return deadCPOW(aes, rs);
LOG("set %s[%s] = %s", ReceiverObj(objId), Identifier(idVar), InVariant(value));
@ -348,7 +357,7 @@ WrapperAnswer::RecvIsExtensible(const ObjectId& objId, ReturnStatus* rs, bool* r
RootedObject obj(cx, findObjectById(cx, objId));
if (!obj)
return fail(jsapi, rs);
return deadCPOW(jsapi, rs);
LOG("%s.isExtensible()", ReceiverObj(objId));
@ -378,7 +387,7 @@ WrapperAnswer::RecvCallOrConstruct(const ObjectId& objId,
RootedObject obj(cx, findObjectById(cx, objId));
if (!obj)
return fail(aes, rs);
return deadCPOW(aes, rs);
MOZ_ASSERT(argv.Length() >= 2);
@ -473,7 +482,7 @@ WrapperAnswer::RecvHasInstance(const ObjectId& objId, const JSVariant& vVar, Ret
RootedObject obj(cx, findObjectById(cx, objId));
if (!obj)
return fail(jsapi, rs);
return deadCPOW(jsapi, rs);
LOG("%s.hasInstance(%s)", ReceiverObj(objId), InVariant(vVar));
@ -500,7 +509,7 @@ WrapperAnswer::RecvGetBuiltinClass(const ObjectId& objId, ReturnStatus* rs,
RootedObject obj(cx, findObjectById(cx, objId));
if (!obj)
return fail(jsapi, rs);
return deadCPOW(jsapi, rs);
LOG("%s.getBuiltinClass()", ReceiverObj(objId));
@ -525,7 +534,7 @@ WrapperAnswer::RecvIsArray(const ObjectId& objId, ReturnStatus* rs,
RootedObject obj(cx, findObjectById(cx, objId));
if (!obj)
return fail(jsapi, rs);
return deadCPOW(jsapi, rs);
LOG("%s.isArray()", ReceiverObj(objId));
@ -570,7 +579,7 @@ WrapperAnswer::RecvGetPrototype(const ObjectId& objId, ReturnStatus* rs, ObjectO
RootedObject obj(cx, findObjectById(cx, objId));
if (!obj)
return fail(jsapi, rs);
return deadCPOW(jsapi, rs);
JS::RootedObject proto(cx);
if (!JS_GetPrototype(cx, obj, &proto))
@ -598,7 +607,7 @@ WrapperAnswer::RecvGetPrototypeIfOrdinary(const ObjectId& objId, ReturnStatus* r
RootedObject obj(cx, findObjectById(cx, objId));
if (!obj)
return fail(jsapi, rs);
return deadCPOW(jsapi, rs);
JS::RootedObject proto(cx);
if (!JS_GetPrototypeIfOrdinary(cx, obj, isOrdinary, &proto))
@ -623,7 +632,7 @@ WrapperAnswer::RecvRegExpToShared(const ObjectId& objId, ReturnStatus* rs,
RootedObject obj(cx, findObjectById(cx, objId));
if (!obj)
return fail(jsapi, rs);
return deadCPOW(jsapi, rs);
RootedString sourceJSStr(cx, JS_GetRegExpSource(cx, obj));
if (!sourceJSStr)
@ -649,7 +658,7 @@ WrapperAnswer::RecvGetPropertyKeys(const ObjectId& objId, const uint32_t& flags,
RootedObject obj(cx, findObjectById(cx, objId));
if (!obj)
return fail(jsapi, rs);
return deadCPOW(jsapi, rs);
LOG("%s.getPropertyKeys()", ReceiverObj(objId));
@ -681,7 +690,7 @@ WrapperAnswer::RecvInstanceOf(const ObjectId& objId, const JSIID& iid, ReturnSta
RootedObject obj(cx, findObjectById(cx, objId));
if (!obj)
return fail(jsapi, rs);
return deadCPOW(jsapi, rs);
LOG("%s.instanceOf()", ReceiverObj(objId));
@ -707,7 +716,7 @@ WrapperAnswer::RecvDOMInstanceOf(const ObjectId& objId, const int& prototypeID,
RootedObject obj(cx, findObjectById(cx, objId));
if (!obj)
return fail(jsapi, rs);
return deadCPOW(jsapi, rs);
LOG("%s.domInstanceOf()", ReceiverObj(objId));

Просмотреть файл

@ -73,6 +73,7 @@ class WrapperAnswer : public virtual JavaScriptShared
bool fail(dom::AutoJSAPI& jsapi, ReturnStatus* rs);
bool ok(ReturnStatus* rs);
bool ok(ReturnStatus* rs, const JS::ObjectOpResult& result);
bool deadCPOW(dom::AutoJSAPI& jsapi, ReturnStatus* rs);
};
} // namespace jsipc

Просмотреть файл

@ -1076,6 +1076,11 @@ WrapperOwner::ok(JSContext* cx, const ReturnStatus& status)
if (status.type() == ReturnStatus::TReturnStopIteration)
return JS_ThrowStopIteration(cx);
if (status.type() == ReturnStatus::TReturnDeadCPOW) {
JS_ReportError(cx, "operation not possible on dead CPOW");
return false;
}
RootedValue exn(cx);
if (!fromVariant(cx, status.get_ReturnException().exn(), &exn))
return false;

Просмотреть файл

@ -2554,44 +2554,90 @@ class BaseCompiler
{
AnyReg src;
RegI32 dest;
bool isAsmJS;
bool isUnsigned;
public:
OutOfLineTruncateF32OrF64ToI32(AnyReg src, RegI32 dest)
OutOfLineTruncateF32OrF64ToI32(AnyReg src, RegI32 dest, bool isAsmJS, bool isUnsigned)
: src(src),
dest(dest)
{}
dest(dest),
isAsmJS(isAsmJS),
isUnsigned(isUnsigned)
{
MOZ_ASSERT_IF(isAsmJS, !isUnsigned);
}
virtual void generate(MacroAssembler& masm) {
// isWasm must be true (for now), see bug 1279876 for related issues.
bool isWasm = true;
bool isFloat = src.tag == AnyReg::F32;
FloatRegister fsrc = isFloat ? src.f32().reg : src.f64().reg;
saveVolatileReturnGPR(masm);
masm.outOfLineTruncateSlow(fsrc, dest.reg, isFloat, isWasm);
restoreVolatileReturnGPR(masm);
masm.jump(rejoin());
if (isAsmJS) {
saveVolatileReturnGPR(masm);
masm.outOfLineTruncateSlow(fsrc, dest.reg, isFloat, /* isAsmJS */ true);
restoreVolatileReturnGPR(masm);
masm.jump(rejoin());
} else {
#if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
if (isFloat)
masm.outOfLineWasmTruncateFloat32ToInt32(fsrc, isUnsigned, rejoin());
else
masm.outOfLineWasmTruncateDoubleToInt32(fsrc, isUnsigned, rejoin());
#else
MOZ_CRASH("BaseCompiler platform hook: OutOfLineTruncateF32OrF64ToI32 wasm");
#endif
}
}
};
MOZ_MUST_USE
bool truncateF32ToI32(RegF32 src, RegI32 dest) {
OutOfLineCode* ool =
addOutOfLineCode(new (alloc_) OutOfLineTruncateF32OrF64ToI32(AnyReg(src),
dest));
if (!ool)
return false;
masm.branchTruncateFloat32ToInt32(src.reg, dest.reg, ool->entry());
bool truncateF32ToI32(RegF32 src, RegI32 dest, bool isUnsigned) {
OutOfLineCode* ool;
if (isCompilingAsmJS()) {
ool = new(alloc_) OutOfLineTruncateF32OrF64ToI32(AnyReg(src), dest, true, false);
ool = addOutOfLineCode(ool);
if (!ool)
return false;
masm.branchTruncateFloat32ToInt32(src.reg, dest.reg, ool->entry());
} else {
#if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
ool = new(alloc_) OutOfLineTruncateF32OrF64ToI32(AnyReg(src), dest, false, isUnsigned);
ool = addOutOfLineCode(ool);
if (!ool)
return false;
if (isUnsigned)
masm.wasmTruncateFloat32ToUInt32(src.reg, dest.reg, ool->entry());
else
masm.wasmTruncateFloat32ToInt32(src.reg, dest.reg, ool->entry());
#else
MOZ_CRASH("BaseCompiler platform hook: truncateF32ToI32 wasm");
#endif
}
masm.bind(ool->rejoin());
return true;
}
MOZ_MUST_USE
bool truncateF64ToI32(RegF64 src, RegI32 dest) {
OutOfLineCode* ool =
addOutOfLineCode(new (alloc_) OutOfLineTruncateF32OrF64ToI32(AnyReg(src),
dest));
if (!ool)
return false;
masm.branchTruncateDoubleToInt32(src.reg, dest.reg, ool->entry());
bool truncateF64ToI32(RegF64 src, RegI32 dest, bool isUnsigned) {
OutOfLineCode* ool;
if (isCompilingAsmJS()) {
ool = new(alloc_) OutOfLineTruncateF32OrF64ToI32(AnyReg(src), dest, true, false);
ool = addOutOfLineCode(ool);
if (!ool)
return false;
masm.branchTruncateDoubleToInt32(src.reg, dest.reg, ool->entry());
} else {
#if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
ool = new(alloc_) OutOfLineTruncateF32OrF64ToI32(AnyReg(src), dest, false, isUnsigned);
ool = addOutOfLineCode(ool);
if (!ool)
return false;
if (isUnsigned)
masm.wasmTruncateDoubleToUInt32(src.reg, dest.reg, ool->entry());
else
masm.wasmTruncateDoubleToInt32(src.reg, dest.reg, ool->entry());
#else
MOZ_CRASH("BaseCompiler platform hook: truncateF32ToI32 wasm");
#endif
}
masm.bind(ool->rejoin());
return true;
}
@ -2601,6 +2647,7 @@ class BaseCompiler
{
AnyReg src;
bool isUnsigned;
public:
OutOfLineTruncateCheckF32OrF64ToI64(AnyReg src, bool isUnsigned)
: src(src),
@ -2608,10 +2655,12 @@ class BaseCompiler
{}
virtual void generate(MacroAssembler& masm) {
bool isFloat = src.tag == AnyReg::F32;
FloatRegister fsrc = isFloat ? src.f32().reg : src.f64().reg;
masm.outOfLineWasmTruncateCheck(fsrc, isFloat ? MIRType::Float32 : MIRType::Double,
MIRType::Int64, isUnsigned, rejoin());
if (src.tag == AnyReg::F32)
masm.outOfLineWasmTruncateFloat32ToInt64(src.f32().reg, isUnsigned, rejoin());
else if (src.tag == AnyReg::F64)
masm.outOfLineWasmTruncateDoubleToInt64(src.f64().reg, isUnsigned, rejoin());
else
MOZ_CRASH("unexpected type");
}
};
#endif
@ -4276,7 +4325,7 @@ BaseCompiler::emitTruncateF32ToI32()
{
RegF32 r0 = popF32();
RegI32 i0 = needI32();
if (!truncateF32ToI32(r0, i0))
if (!truncateF32ToI32(r0, i0, isUnsigned))
return false;
freeF32(r0);
pushI32(i0);
@ -4309,7 +4358,7 @@ BaseCompiler::emitTruncateF64ToI32()
{
RegF64 r0 = popF64();
RegI32 i0 = needI32();
if (!truncateF64ToI32(r0, i0))
if (!truncateF64ToI32(r0, i0, isUnsigned))
return false;
freeF64(r0);
pushI32(i0);

Просмотреть файл

@ -96,6 +96,8 @@ class GeneratedSourceMap
void setTotalLines(uint32_t val) { totalLines_ = val; }
};
typedef UniquePtr<GeneratedSourceMap> UniqueGeneratedSourceMap;
// Translate the given binary representation of a wasm module into the module's textual
// representation.

Просмотреть файл

@ -31,6 +31,7 @@
#ifdef JS_ION_PERF
# include "jit/PerfSpewer.h"
#endif
#include "vm/StringBuffer.h"
#ifdef MOZ_VTUNE
# include "vtune/VTuneWrapper.h"
#endif
@ -79,8 +80,8 @@ static void
StaticallyLink(CodeSegment& cs, const LinkData& linkData, ExclusiveContext* cx)
{
for (LinkData::InternalLink link : linkData.internalLinks) {
uint8_t* patchAt = cs.code() + link.patchAtOffset;
void* target = cs.code() + link.targetOffset;
uint8_t* patchAt = cs.base() + link.patchAtOffset;
void* target = cs.base() + link.targetOffset;
if (link.isRawPointerPatch())
*(void**)(patchAt) = target;
else
@ -90,7 +91,7 @@ StaticallyLink(CodeSegment& cs, const LinkData& linkData, ExclusiveContext* cx)
for (auto imm : MakeEnumeratedRange(SymbolicAddress::Limit)) {
const Uint32Vector& offsets = linkData.symbolicLinks[imm];
for (size_t i = 0; i < offsets.length(); i++) {
uint8_t* patchAt = cs.code() + offsets[i];
uint8_t* patchAt = cs.base() + offsets[i];
void* target = AddressOf(imm, cx);
Assembler::PatchDataWithValueCheck(CodeLocationLabel(patchAt),
PatchedImmPtr(target),
@ -108,13 +109,13 @@ static void
SpecializeToMemory(CodeSegment& cs, const Metadata& metadata, HandleWasmMemoryObject memory)
{
for (const BoundsCheck& check : metadata.boundsChecks)
Assembler::UpdateBoundsCheck(check.patchAt(cs.code()), memory->buffer().byteLength());
Assembler::UpdateBoundsCheck(check.patchAt(cs.base()), memory->buffer().byteLength());
#if defined(JS_CODEGEN_X86)
uint8_t* base = memory->buffer().dataPointerEither().unwrap();
for (const MemoryAccess& access : metadata.memoryAccesses) {
// Patch memory pointer immediate.
void* addr = access.patchMemoryPtrImmAt(cs.code());
void* addr = access.patchMemoryPtrImmAt(cs.base());
uint32_t disp = reinterpret_cast<uint32_t>(X86Encoding::GetPointer(addr));
MOZ_ASSERT(disp <= INT32_MAX);
X86Encoding::SetPointer(addr, (void*)(base + disp));
@ -140,8 +141,8 @@ SendCodeRangesToProfiler(JSContext* cx, CodeSegment& cs, const Bytes& bytecode,
if (!codeRange.isFunction())
continue;
uintptr_t start = uintptr_t(cs.code() + codeRange.begin());
uintptr_t end = uintptr_t(cs.code() + codeRange.end());
uintptr_t start = uintptr_t(cs.base() + codeRange.begin());
uintptr_t end = uintptr_t(cs.base() + codeRange.end());
uintptr_t size = end - start;
TwoByteName name(cx);
@ -207,26 +208,28 @@ CodeSegment::create(JSContext* cx,
if (!cs->bytes_)
return nullptr;
uint8_t* codeBase = cs->base();
cs->functionCodeLength_ = linkData.functionCodeLength;
cs->codeLength_ = bytecode.length();
cs->globalDataLength_ = linkData.globalDataLength;
cs->interruptCode_ = cs->code() + linkData.interruptOffset;
cs->outOfBoundsCode_ = cs->code() + linkData.outOfBoundsOffset;
cs->unalignedAccessCode_ = cs->code() + linkData.unalignedAccessOffset;
cs->badIndirectCallCode_ = cs->code() + linkData.badIndirectCallOffset;
cs->interruptCode_ = codeBase + linkData.interruptOffset;
cs->outOfBoundsCode_ = codeBase + linkData.outOfBoundsOffset;
cs->unalignedAccessCode_ = codeBase + linkData.unalignedAccessOffset;
cs->badIndirectCallCode_ = codeBase + linkData.badIndirectCallOffset;
{
JitContext jcx(CompileRuntime::get(cx->compartment()->runtimeFromAnyThread()));
AutoFlushICache afc("CodeSegment::create");
AutoFlushICache::setRange(uintptr_t(cs->code()), cs->codeLength());
AutoFlushICache::setRange(uintptr_t(codeBase), cs->codeLength());
memcpy(cs->code(), bytecode.begin(), bytecode.length());
memcpy(codeBase, bytecode.begin(), bytecode.length());
StaticallyLink(*cs, linkData, cx);
if (memory)
SpecializeToMemory(*cs, metadata, memory);
}
if (!ExecutableAllocator::makeExecutable(cs->code(), cs->codeLength())) {
if (!ExecutableAllocator::makeExecutable(codeBase, cs->codeLength())) {
ReportOutOfMemory(cx);
return nullptr;
}
@ -551,3 +554,269 @@ Metadata::getFuncName(JSContext* cx, const Bytes* maybeBytecode, uint32_t funcIn
CopyAndInflateChars(name->begin(), chars.get(), name->length());
return true;
}
Code::Code(UniqueCodeSegment segment,
const Metadata& metadata,
const ShareableBytes* maybeBytecode)
: segment_(Move(segment)),
metadata_(&metadata),
maybeBytecode_(maybeBytecode),
profilingEnabled_(false)
{}
struct CallSiteRetAddrOffset
{
const CallSiteVector& callSites;
explicit CallSiteRetAddrOffset(const CallSiteVector& callSites) : callSites(callSites) {}
uint32_t operator[](size_t index) const {
return callSites[index].returnAddressOffset();
}
};
const CallSite*
Code::lookupCallSite(void* returnAddress) const
{
uint32_t target = ((uint8_t*)returnAddress) - segment_->base();
size_t lowerBound = 0;
size_t upperBound = metadata_->callSites.length();
size_t match;
if (!BinarySearch(CallSiteRetAddrOffset(metadata_->callSites), lowerBound, upperBound, target, &match))
return nullptr;
return &metadata_->callSites[match];
}
const CodeRange*
Code::lookupRange(void* pc) const
{
CodeRange::PC target((uint8_t*)pc - segment_->base());
size_t lowerBound = 0;
size_t upperBound = metadata_->codeRanges.length();
size_t match;
if (!BinarySearch(metadata_->codeRanges, lowerBound, upperBound, target, &match))
return nullptr;
return &metadata_->codeRanges[match];
}
#ifdef ASMJS_MAY_USE_SIGNAL_HANDLERS
struct MemoryAccessOffset
{
const MemoryAccessVector& accesses;
explicit MemoryAccessOffset(const MemoryAccessVector& accesses) : accesses(accesses) {}
uintptr_t operator[](size_t index) const {
return accesses[index].insnOffset();
}
};
const MemoryAccess*
Code::lookupMemoryAccess(void* pc) const
{
MOZ_ASSERT(segment_->containsFunctionPC(pc));
uint32_t target = ((uint8_t*)pc) - segment_->base();
size_t lowerBound = 0;
size_t upperBound = metadata_->memoryAccesses.length();
size_t match;
if (!BinarySearch(MemoryAccessOffset(metadata_->memoryAccesses), lowerBound, upperBound, target, &match))
return nullptr;
return &metadata_->memoryAccesses[match];
}
#endif // ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_OOB
bool
Code::getFuncName(JSContext* cx, uint32_t funcIndex, TwoByteName* name) const
{
const Bytes* maybeBytecode = maybeBytecode_ ? &maybeBytecode_.get()->bytes : nullptr;
return metadata_->getFuncName(cx, maybeBytecode, funcIndex, name);
}
JSAtom*
Code::getFuncAtom(JSContext* cx, uint32_t funcIndex) const
{
TwoByteName name(cx);
if (!getFuncName(cx, funcIndex, &name))
return nullptr;
return AtomizeChars(cx, name.begin(), name.length());
}
const char experimentalWarning[] =
"Temporary\n"
".--. .--. ____ .-'''-. ,---. ,---.\n"
"| |_ | | .' __ `. / _ \\| \\ / |\n"
"| _( )_ | |/ ' \\ \\ (`' )/`--'| , \\/ , |\n"
"|(_ o _) | ||___| / |(_ o _). | |\\_ /| |\n"
"| (_,_) \\ | | _.-` | (_,_). '. | _( )_/ | |\n"
"| |/ \\| |.' _ |.---. \\ :| (_ o _) | |\n"
"| ' /\\ ` || _( )_ |\\ `-' || (_,_) | |\n"
"| / \\ |\\ (_ o _) / \\ / | | | |\n"
"`---' `---` '.(_,_).' `-...-' '--' '--'\n"
"text support (Work In Progress):\n\n";
const size_t experimentalWarningLinesCount = 12;
const char enabledMessage[] =
"Restart with developer tools open to view WebAssembly source";
struct LineComparator
{
const uint32_t lineno;
explicit LineComparator(uint32_t lineno) : lineno(lineno) {}
int operator()(const ExprLoc& loc) const {
return lineno == loc.lineno ? 0 : lineno < loc.lineno ? -1 : 1;
}
};
JSString*
Code::createText(JSContext* cx)
{
StringBuffer buffer(cx);
if (maybeBytecode_) {
const Bytes& bytes = maybeBytecode_->bytes;
if (!buffer.append(experimentalWarning))
return nullptr;
maybeSourceMap_.reset(cx->runtime()->new_<GeneratedSourceMap>(cx));
if (!maybeSourceMap_)
return nullptr;
if (!BinaryToExperimentalText(cx, bytes.begin(), bytes.length(), buffer,
ExperimentalTextFormatting(), maybeSourceMap_.get())) {
return nullptr;
}
#if DEBUG
// Checking source map invariant: expression and function locations must be sorted
// by line number.
uint32_t lastLineno = 0;
for (const ExprLoc& loc : maybeSourceMap_->exprlocs()) {
MOZ_ASSERT(lastLineno <= loc.lineno);
lastLineno = loc.lineno;
}
lastLineno = 0;
for (const FunctionLoc& loc : maybeSourceMap_->functionlocs()) {
MOZ_ASSERT(lastLineno <= loc.startLineno);
MOZ_ASSERT(loc.startLineno <= loc.endLineno);
lastLineno = loc.endLineno + 1;
}
#endif
} else {
if (!buffer.append(enabledMessage))
return nullptr;
}
return buffer.finishString();
}
bool
Code::getLineOffsets(size_t lineno, Vector<uint32_t>& offsets) const
{
// TODO Ensure text was generated?
if (!maybeSourceMap_)
return false;
if (lineno < experimentalWarningLinesCount)
return true;
lineno -= experimentalWarningLinesCount;
ExprLocVector& exprlocs = maybeSourceMap_->exprlocs();
// Binary search for the expression with the specified line number and
// rewind to the first expression, if more than one expression on the same line.
size_t match;
if (!BinarySearchIf(exprlocs, 0, exprlocs.length(), LineComparator(lineno), &match))
return true;
while (match > 0 && exprlocs[match - 1].lineno == lineno)
match--;
// Return all expression offsets that were printed on the specified line.
for (size_t i = match; i < exprlocs.length() && exprlocs[i].lineno == lineno; i++) {
if (!offsets.append(exprlocs[i].offset))
return false;
}
return true;
}
bool
Code::ensureProfilingState(JSContext* cx, bool newProfilingEnabled)
{
if (profilingEnabled_ == newProfilingEnabled)
return true;
// When enabled, generate profiling labels for every name in funcNames_
// that is the name of some Function CodeRange. This involves malloc() so
// do it now since, once we start sampling, we'll be in a signal-handing
// context where we cannot malloc.
if (newProfilingEnabled) {
for (const CodeRange& codeRange : metadata_->codeRanges) {
if (!codeRange.isFunction())
continue;
TwoByteName name(cx);
if (!getFuncName(cx, codeRange.funcIndex(), &name))
return false;
if (!name.append('\0'))
return false;
UniqueChars label(JS_smprintf("%hs (%s:%u)",
name.begin(),
metadata_->filename.get(),
codeRange.funcLineOrBytecode()));
if (!label) {
ReportOutOfMemory(cx);
return false;
}
if (codeRange.funcIndex() >= funcLabels_.length()) {
if (!funcLabels_.resize(codeRange.funcIndex() + 1))
return false;
}
funcLabels_[codeRange.funcIndex()] = Move(label);
}
} else {
funcLabels_.clear();
}
// Only mutate the code after the fallible operations are complete to avoid
// the need to rollback.
profilingEnabled_ = newProfilingEnabled;
{
AutoWritableJitCode awjc(cx->runtime(), segment_->base(), segment_->codeLength());
AutoFlushICache afc("Code::ensureProfilingState");
AutoFlushICache::setRange(uintptr_t(segment_->base()), segment_->codeLength());
for (const CallSite& callSite : metadata_->callSites)
ToggleProfiling(*this, callSite, newProfilingEnabled);
for (const CallThunk& callThunk : metadata_->callThunks)
ToggleProfiling(*this, callThunk, newProfilingEnabled);
for (const CodeRange& codeRange : metadata_->codeRanges)
ToggleProfiling(*this, codeRange, newProfilingEnabled);
}
return true;
}
void
Code::addSizeOfMisc(MallocSizeOf mallocSizeOf,
Metadata::SeenSet* seenMetadata,
ShareableBytes::SeenSet* seenBytes,
size_t* code,
size_t* data) const
{
*code += segment_->codeLength();
*data += mallocSizeOf(this) +
segment_->globalDataLength() +
metadata_->sizeOfIncludingThisIfNotSeen(mallocSizeOf, seenMetadata);
if (maybeBytecode_)
*data += maybeBytecode_->sizeOfIncludingThisIfNotSeen(mallocSizeOf, seenBytes);
}

Просмотреть файл

@ -19,6 +19,7 @@
#ifndef wasm_code_h
#define wasm_code_h
#include "asmjs/WasmBinaryToExperimentalText.h"
#include "asmjs/WasmTypes.h"
namespace js {
@ -31,6 +32,9 @@ struct LinkData;
struct Metadata;
// A wasm CodeSegment owns the allocated executable code for a wasm module.
// This allocation also currently includes the global data segment, which allows
// RIP-relative access to global data on some architectures, but this will
// change in the future to give global data its own allocation.
class CodeSegment;
typedef UniquePtr<CodeSegment> UniqueCodeSegment;
@ -73,7 +77,7 @@ class CodeSegment
HandleWasmMemoryObject memory);
~CodeSegment();
uint8_t* code() const { return bytes_; }
uint8_t* base() const { return bytes_; }
uint8_t* globalData() const { return bytes_ + codeLength_; }
uint32_t codeLength() const { return codeLength_; }
uint32_t globalDataLength() const { return globalDataLength_; }
@ -90,11 +94,11 @@ class CodeSegment
// function code which, in turn, simplifies reasoning about how stubs
// enter/exit.
bool containsFunctionPC(void* pc) const {
return pc >= code() && pc < (code() + functionCodeLength_);
bool containsFunctionPC(const void* pc) const {
return pc >= base() && pc < (base() + functionCodeLength_);
}
bool containsCodePC(void* pc) const {
return pc >= code() && pc < (code() + codeLength_);
bool containsCodePC(const void* pc) const {
return pc >= base() && pc < (base() + codeLength_);
}
};
@ -512,6 +516,72 @@ struct Metadata : ShareableBase<Metadata>, MetadataCacheablePod
typedef RefPtr<Metadata> MutableMetadata;
typedef RefPtr<const Metadata> SharedMetadata;
// Code objects own executable code and the metadata that describes it. At the
// moment, Code objects are owned uniquely by instances since CodeSegments are
// not shareable. However, once this restriction is removed, a single Code
// object will be shared between a module and all its instances.
class Code
{
const UniqueCodeSegment segment_;
const SharedMetadata metadata_;
const SharedBytes maybeBytecode_;
UniqueGeneratedSourceMap maybeSourceMap_;
CacheableCharsVector funcLabels_;
bool profilingEnabled_;
public:
Code(UniqueCodeSegment segment,
const Metadata& metadata,
const ShareableBytes* maybeBytecode);
const CodeSegment& segment() const { return *segment_; }
const Metadata& metadata() const { return *metadata_; }
// Frame iterator support:
const CallSite* lookupCallSite(void* returnAddress) const;
const CodeRange* lookupRange(void* pc) const;
#ifdef ASMJS_MAY_USE_SIGNAL_HANDLERS
const MemoryAccess* lookupMemoryAccess(void* pc) const;
#endif
// Return the name associated with a given function index, or generate one
// if none was given by the module.
bool getFuncName(JSContext* cx, uint32_t funcIndex, TwoByteName* name) const;
JSAtom* getFuncAtom(JSContext* cx, uint32_t funcIndex) const;
// If the source bytecode was saved when this Code was constructed, this
// method will render the binary as text. Otherwise, a diagnostic string
// will be returned.
JSString* createText(JSContext* cx);
bool getLineOffsets(size_t lineno, Vector<uint32_t>& offsets) const;
// Each Code has a profiling mode that is updated to match the runtime's
// profiling mode when there are no other activations of the code live on
// the stack. Once in profiling mode, ProfilingFrameIterator can be used to
// asynchronously walk the stack. Otherwise, the ProfilingFrameIterator will
// skip any activations of this code.
MOZ_MUST_USE bool ensureProfilingState(JSContext* cx, bool enabled);
bool profilingEnabled() const { return profilingEnabled_; }
const char* profilingLabel(uint32_t funcIndex) const { return funcLabels_[funcIndex].get(); }
// about:memory reporting:
void addSizeOfMisc(MallocSizeOf mallocSizeOf,
Metadata::SeenSet* seenMetadata,
ShareableBytes::SeenSet* seenBytes,
size_t* code,
size_t* data) const;
WASM_DECLARE_SERIALIZABLE(Code);
};
typedef UniquePtr<Code> UniqueCode;
} // namespace wasm
} // namespace js

Просмотреть файл

@ -0,0 +1,186 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
*
* Copyright 2016 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "asmjs/WasmCompartment.h"
#include "jscompartment.h"
#include "asmjs/WasmInstance.h"
#include "vm/Debugger-inl.h"
using namespace js;
using namespace wasm;
Compartment::Compartment(Zone* zone)
: mutatingInstances_(false),
instanceObjects_(zone, InstanceObjectSet()),
activationCount_(0),
profilingEnabled_(false)
{}
Compartment::~Compartment()
{
MOZ_ASSERT(activationCount_ == 0);
MOZ_ASSERT(!instanceObjects_.initialized() || instanceObjects_.empty());
MOZ_ASSERT(instances_.empty());
MOZ_ASSERT(!mutatingInstances_);
}
struct InstanceComparator
{
const Instance& target;
explicit InstanceComparator(const Instance& target) : target(target) {}
int operator()(const Instance* instance) const {
if (instance == &target)
return 0;
MOZ_ASSERT(!target.codeSegment().containsCodePC(instance->codeBase()));
MOZ_ASSERT(!instance->codeSegment().containsCodePC(target.codeBase()));
return target.codeBase() < instance->codeBase() ? -1 : 1;
}
};
void
Compartment::trace(JSTracer* trc)
{
// A WasmInstanceObject that was initially reachable when called can become
// unreachable while executing on the stack. Since wasm does not otherwise
// scan the stack during GC to identify live instances, we mark all instance
// objects live if there is any running wasm in the compartment.
if (activationCount_)
instanceObjects_.get().trace(trc);
}
bool
Compartment::registerInstance(JSContext* cx, HandleWasmInstanceObject instanceObj)
{
Instance& instance = instanceObj->instance();
MOZ_ASSERT(this == &instance.compartment()->wasm);
if (!instance.ensureProfilingState(cx, profilingEnabled_))
return false;
if (!instanceObjects_.initialized() && !instanceObjects_.init()) {
ReportOutOfMemory(cx);
return false;
}
if (!instanceObjects_.putNew(instanceObj)) {
ReportOutOfMemory(cx);
return false;
}
size_t index;
if (BinarySearchIf(instances_, 0, instances_.length(), InstanceComparator(instance), &index))
MOZ_CRASH("duplicate registration");
{
AutoMutateInstances guard(*this);
if (!instances_.insert(instances_.begin() + index, &instance)) {
ReportOutOfMemory(cx);
return false;
}
}
Debugger::onNewWasmInstance(cx, instanceObj);
return true;
}
void
Compartment::unregisterInstance(Instance& instance)
{
size_t index;
if (!BinarySearchIf(instances_, 0, instances_.length(), InstanceComparator(instance), &index))
return;
AutoMutateInstances guard(*this);
instances_.erase(instances_.begin() + index);
}
struct PCComparator
{
const void* pc;
explicit PCComparator(const void* pc) : pc(pc) {}
int operator()(const Instance* instance) const {
if (instance->codeSegment().containsCodePC(pc))
return 0;
return pc < instance->codeBase() ? -1 : 1;
}
};
Code*
Compartment::lookupCode(const void* pc) const
{
Instance* instance = lookupInstanceDeprecated(pc);
return instance ? &instance->code() : nullptr;
}
Instance*
Compartment::lookupInstanceDeprecated(const void* pc) const
{
// See profilingEnabled().
MOZ_ASSERT(!mutatingInstances_);
size_t index;
if (!BinarySearchIf(instances_, 0, instances_.length(), PCComparator(pc), &index))
return nullptr;
return instances_[index];
}
bool
Compartment::ensureProfilingState(JSContext* cx)
{
bool newProfilingEnabled = cx->spsProfiler.enabled();
if (profilingEnabled_ == newProfilingEnabled)
return true;
// Since one Instance can call another Instance in the same compartment
// directly without calling through Instance::callExport(), when profiling
// is enabled, enable it for the entire compartment at once. It is only safe
// to enable profiling when the wasm is not on the stack, so delay enabling
// profiling until there are no live WasmActivations in this compartment.
if (activationCount_ > 0)
return true;
for (Instance* instance : instances_) {
if (!instance->ensureProfilingState(cx, newProfilingEnabled))
return false;
}
profilingEnabled_ = newProfilingEnabled;
return true;
}
bool
Compartment::profilingEnabled() const
{
// Profiling can asynchronously interrupt the mutation of the instances_
// vector which is used by lookupCode() during stack-walking. To handle
// this rare case, disable profiling during mutation.
return profilingEnabled_ && !mutatingInstances_;
}
void
Compartment::addSizeOfExcludingThis(MallocSizeOf mallocSizeOf, size_t* compartmentTables)
{
*compartmentTables += instanceObjects_.sizeOfExcludingThis(mallocSizeOf);
}

Просмотреть файл

@ -0,0 +1,112 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
*
* Copyright 2016 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef wasm_compartment_h
#define wasm_compartment_h
#include "asmjs/WasmJS.h"
namespace js {
class WasmActivation;
namespace wasm {
class Code;
// wasm::Compartment lives in JSCompartment and contains the wasm-related
// per-compartment state. wasm::Compartment tracks every live instance in the
// compartment and must be notified, via registerInstance(), of any new
// WasmInstanceObject.
class Compartment
{
using InstanceObjectSet = GCHashSet<ReadBarriered<WasmInstanceObject*>,
MovableCellHasher<ReadBarriered<WasmInstanceObject*>>,
SystemAllocPolicy>;
using WeakInstanceObjectSet = JS::WeakCache<InstanceObjectSet>;
using InstanceVector = Vector<Instance*, 0, SystemAllocPolicy>;
InstanceVector instances_;
volatile bool mutatingInstances_;
WeakInstanceObjectSet instanceObjects_;
size_t activationCount_;
bool profilingEnabled_;
friend class js::WasmActivation;
struct AutoMutateInstances {
Compartment &c;
explicit AutoMutateInstances(Compartment& c) : c(c) {
MOZ_ASSERT(!c.mutatingInstances_);
c.mutatingInstances_ = true;
}
~AutoMutateInstances() {
MOZ_ASSERT(c.mutatingInstances_);
c.mutatingInstances_ = false;
}
};
public:
explicit Compartment(Zone* zone);
~Compartment();
void trace(JSTracer* trc);
// Before a WasmInstanceObject can be considered fully constructed and
// valid, it must be registered with the Compartment. If this method fails,
// an error has been reported and the instance object must be abandoned.
// After a successful registration, an Instance must call
// unregisterInstance() before being destroyed.
bool registerInstance(JSContext* cx, HandleWasmInstanceObject instanceObj);
void unregisterInstance(Instance& instance);
// Return a weak set of all live instances in the compartment. Accessing
// objects of the set will trigger a read-barrier which will mark the
// object.
const WeakInstanceObjectSet& instanceObjects() const { return instanceObjects_; }
// This methods returns the wasm::Code containing the given pc, if any
// exists in the compartment.
Code* lookupCode(const void* pc) const;
// Currently, there is one Code per Instance so it is also possible to
// lookup a Instance given a pc. However, the goal is to share one Code
// between multiple Instances at which point in time this method will be
// removed.
Instance* lookupInstanceDeprecated(const void* pc) const;
// To ensure profiling is enabled (so that wasm frames are not lost in
// profiling callstacks), ensureProfilingState must be called before calling
// the first wasm function in a compartment.
bool ensureProfilingState(JSContext* cx);
bool profilingEnabled() const;
// about:memory reporting
void addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf, size_t* compartmentTables);
};
} // namespace wasm
} // namespace js
#endif // wasm_compartment_h

Просмотреть файл

@ -45,8 +45,8 @@ CallerFPFromFP(void* fp)
}
FrameIterator::FrameIterator()
: cx_(nullptr),
instance_(nullptr),
: activation_(nullptr),
code_(nullptr),
callsite_(nullptr),
codeRange_(nullptr),
fp_(nullptr),
@ -56,8 +56,8 @@ FrameIterator::FrameIterator()
}
FrameIterator::FrameIterator(const WasmActivation& activation)
: cx_(activation.cx()),
instance_(&activation.instance()),
: activation_(&activation),
code_(nullptr),
callsite_(nullptr),
codeRange_(nullptr),
fp_(activation.fp()),
@ -69,10 +69,15 @@ FrameIterator::FrameIterator(const WasmActivation& activation)
}
void* pc = activation.resumePC();
if (!pc)
if (!pc) {
MOZ_ASSERT(done());
return;
}
const CodeRange* codeRange = instance_->lookupCodeRange(pc);
code_ = activation_->compartment()->wasm.lookupCode(pc);
MOZ_ASSERT(code_);
const CodeRange* codeRange = code_->lookupRange(pc);
MOZ_ASSERT(codeRange);
if (codeRange->kind() == CodeRange::Function)
@ -86,9 +91,7 @@ FrameIterator::FrameIterator(const WasmActivation& activation)
bool
FrameIterator::done() const
{
return !fp_ &&
!codeRange_ &&
!missingFrameMessage_;
return !codeRange_ && !missingFrameMessage_;
}
void
@ -98,7 +101,7 @@ FrameIterator::operator++()
if (fp_) {
DebugOnly<uint8_t*> oldfp = fp_;
fp_ += callsite_->stackDepth();
MOZ_ASSERT_IF(instance_->profilingEnabled(), fp_ == CallerFPFromFP(oldfp));
MOZ_ASSERT_IF(code_->profilingEnabled(), fp_ == CallerFPFromFP(oldfp));
settle();
} else if (codeRange_) {
MOZ_ASSERT(codeRange_);
@ -115,17 +118,20 @@ FrameIterator::settle()
{
void* returnAddress = ReturnAddressFromFP(fp_);
const CodeRange* codeRange = instance_->lookupCodeRange(returnAddress);
MOZ_ASSERT(codeRange);
codeRange_ = codeRange;
code_ = activation_->compartment()->wasm.lookupCode(returnAddress);
MOZ_ASSERT(code_);
switch (codeRange->kind()) {
codeRange_ = code_->lookupRange(returnAddress);
MOZ_ASSERT(codeRange_);
switch (codeRange_->kind()) {
case CodeRange::Function:
callsite_ = instance_->lookupCallSite(returnAddress);
callsite_ = code_->lookupCallSite(returnAddress);
MOZ_ASSERT(callsite_);
break;
case CodeRange::Entry:
fp_ = nullptr;
code_ = nullptr;
codeRange_ = nullptr;
MOZ_ASSERT(done());
break;
@ -137,20 +143,41 @@ FrameIterator::settle()
}
}
const char*
FrameIterator::filename() const
{
MOZ_ASSERT(!done());
return code_->metadata().filename.get();
}
const char16_t*
FrameIterator::displayURL() const
{
MOZ_ASSERT(!done());
return code_->metadata().displayURL();
}
bool
FrameIterator::mutedErrors() const
{
MOZ_ASSERT(!done());
return code_->metadata().mutedErrors();
}
JSAtom*
FrameIterator::functionDisplayAtom() const
{
MOZ_ASSERT(!done());
UniqueChars owner;
JSContext* cx = activation_->cx();
if (missingFrameMessage_) {
const char* msg = "asm.js/wasm frames may be missing; enable the profiler before running "
"to see all frames";
JSAtom* atom = Atomize(cx_, msg, strlen(msg));
JSAtom* atom = Atomize(cx, msg, strlen(msg));
if (!atom) {
cx_->clearPendingException();
return cx_->names().empty;
cx->clearPendingException();
return cx->names().empty;
}
return atom;
@ -158,10 +185,10 @@ FrameIterator::functionDisplayAtom() const
MOZ_ASSERT(codeRange_);
JSAtom* atom = instance_->getFuncAtom(cx_, codeRange_->funcIndex());
JSAtom* atom = code_->getFuncAtom(cx, codeRange_->funcIndex());
if (!atom) {
cx_->clearPendingException();
return cx_->names().empty;
cx->clearPendingException();
return cx->names().empty;
}
return atom;
@ -172,8 +199,7 @@ FrameIterator::lineOrBytecode() const
{
MOZ_ASSERT(!done());
return callsite_ ? callsite_->lineOrBytecode()
: codeRange_ ? codeRange_->funcLineOrBytecode()
: 0;
: (codeRange_ ? codeRange_->funcLineOrBytecode() : 0);
}
/*****************************************************************************/
@ -187,19 +213,19 @@ FrameIterator::lineOrBytecode() const
static const unsigned PushedRetAddr = 0;
static const unsigned PostStorePrePopFP = 0;
# endif
static const unsigned PushedFP = 13;
static const unsigned StoredFP = 20;
static const unsigned PushedFP = 20;
static const unsigned StoredFP = 27;
#elif defined(JS_CODEGEN_X86)
# if defined(DEBUG)
static const unsigned PushedRetAddr = 0;
static const unsigned PostStorePrePopFP = 0;
# endif
static const unsigned PushedFP = 8;
static const unsigned StoredFP = 11;
static const unsigned PushedFP = 14;
static const unsigned StoredFP = 17;
#elif defined(JS_CODEGEN_ARM)
static const unsigned PushedRetAddr = 4;
static const unsigned PushedFP = 16;
static const unsigned StoredFP = 20;
static const unsigned PushedFP = 20;
static const unsigned StoredFP = 24;
static const unsigned PostStorePrePopFP = 4;
#elif defined(JS_CODEGEN_ARM64)
static const unsigned PushedRetAddr = 0;
@ -208,8 +234,8 @@ static const unsigned StoredFP = 0;
static const unsigned PostStorePrePopFP = 0;
#elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
static const unsigned PushedRetAddr = 8;
static const unsigned PushedFP = 24;
static const unsigned StoredFP = 28;
static const unsigned PushedFP = 28;
static const unsigned StoredFP = 32;
static const unsigned PostStorePrePopFP = 4;
#elif defined(JS_CODEGEN_NONE)
# if defined(DEBUG)
@ -250,7 +276,7 @@ GenerateProfilingPrologue(MacroAssembler& masm, unsigned framePushed, ExitReason
// randomly inserted between two instructions.
{
#if defined(JS_CODEGEN_ARM)
AutoForbidPools afp(&masm, /* number of instructions in scope = */ 5);
AutoForbidPools afp(&masm, /* number of instructions in scope = */ 6);
#endif
offsets->begin = masm.currentOffset();
@ -431,7 +457,8 @@ wasm::GenerateExitEpilogue(MacroAssembler& masm, unsigned framePushed, ExitReaso
// ProfilingFrameIterator
ProfilingFrameIterator::ProfilingFrameIterator()
: instance_(nullptr),
: activation_(nullptr),
code_(nullptr),
codeRange_(nullptr),
callerFP_(nullptr),
callerPC_(nullptr),
@ -442,7 +469,8 @@ ProfilingFrameIterator::ProfilingFrameIterator()
}
ProfilingFrameIterator::ProfilingFrameIterator(const WasmActivation& activation)
: instance_(&activation.instance()),
: activation_(&activation),
code_(nullptr),
codeRange_(nullptr),
callerFP_(nullptr),
callerPC_(nullptr),
@ -454,35 +482,41 @@ ProfilingFrameIterator::ProfilingFrameIterator(const WasmActivation& activation)
// happens if profiling is enabled while the instance is on the stack (in
// which case profiling will be enabled when the instance becomes inactive
// and gets called again).
if (!instance_->profilingEnabled()) {
if (!activation_->compartment()->wasm.profilingEnabled()) {
MOZ_ASSERT(done());
return;
}
initFromFP(activation);
initFromFP();
}
static inline void
AssertMatchesCallSite(const Instance& instance, void* callerPC, void* callerFP, void* fp)
AssertMatchesCallSite(const WasmActivation& activation, void* callerPC, void* callerFP, void* fp)
{
#ifdef DEBUG
const CodeRange* callerCodeRange = instance.lookupCodeRange(callerPC);
Code* code = activation.compartment()->wasm.lookupCode(callerPC);
MOZ_ASSERT(code);
const CodeRange* callerCodeRange = code->lookupRange(callerPC);
MOZ_ASSERT(callerCodeRange);
if (callerCodeRange->kind() == CodeRange::Entry) {
MOZ_ASSERT(callerFP == nullptr);
return;
}
const CallSite* callsite = instance.lookupCallSite(callerPC);
const CallSite* callsite = code->lookupCallSite(callerPC);
MOZ_ASSERT(callsite);
MOZ_ASSERT(callerFP == (uint8_t*)fp + callsite->stackDepth());
#endif
}
void
ProfilingFrameIterator::initFromFP(const WasmActivation& activation)
ProfilingFrameIterator::initFromFP()
{
uint8_t* fp = activation.fp();
uint8_t* fp = activation_->fp();
stackAddress_ = fp;
// If a signal was handled while entering an activation, the frame will
// still be null.
@ -491,6 +525,14 @@ ProfilingFrameIterator::initFromFP(const WasmActivation& activation)
return;
}
void* pc = ReturnAddressFromFP(fp);
code_ = activation_->compartment()->wasm.lookupCode(pc);
MOZ_ASSERT(code_);
codeRange_ = code_->lookupRange(pc);
MOZ_ASSERT(codeRange_);
// Since we don't have the pc for fp, start unwinding at the caller of fp
// (ReturnAddressFromFP(fp)). This means that the innermost frame is
// skipped. This is fine because:
@ -499,13 +541,7 @@ ProfilingFrameIterator::initFromFP(const WasmActivation& activation)
// - for Math and other builtin calls as well as interrupts, we note the absence
// of an exit reason and inject a fake "builtin" frame; and
// - for async interrupts, we just accept that we'll lose the innermost frame.
void* pc = ReturnAddressFromFP(fp);
const CodeRange* codeRange = instance_->lookupCodeRange(pc);
MOZ_ASSERT(codeRange);
codeRange_ = codeRange;
stackAddress_ = fp;
switch (codeRange->kind()) {
switch (codeRange_->kind()) {
case CodeRange::Entry:
callerPC_ = nullptr;
callerFP_ = nullptr;
@ -514,7 +550,7 @@ ProfilingFrameIterator::initFromFP(const WasmActivation& activation)
fp = CallerFPFromFP(fp);
callerPC_ = ReturnAddressFromFP(fp);
callerFP_ = CallerFPFromFP(fp);
AssertMatchesCallSite(*instance_, callerPC_, callerFP_, fp);
AssertMatchesCallSite(*activation_, callerPC_, callerFP_, fp);
break;
case CodeRange::ImportJitExit:
case CodeRange::ImportInterpExit:
@ -525,7 +561,7 @@ ProfilingFrameIterator::initFromFP(const WasmActivation& activation)
// The iterator inserts a pretend innermost frame for non-None ExitReasons.
// This allows the variety of exit reasons to show up in the callstack.
exitReason_ = activation.exitReason();
exitReason_ = activation_->exitReason();
// In the case of calls to builtins or asynchronous interrupts, no exit path
// is taken so the exitReason is None. Coerce these to the Native exit
@ -551,7 +587,8 @@ InThunk(const CodeRange& codeRange, uint32_t offsetInModule)
ProfilingFrameIterator::ProfilingFrameIterator(const WasmActivation& activation,
const RegisterState& state)
: instance_(&activation.instance()),
: activation_(&activation),
code_(nullptr),
codeRange_(nullptr),
callerFP_(nullptr),
callerPC_(nullptr),
@ -563,22 +600,23 @@ ProfilingFrameIterator::ProfilingFrameIterator(const WasmActivation& activation,
// happens if profiling is enabled while the instance is on the stack (in
// which case profiling will be enabled when the instance becomes inactive
// and gets called again).
if (!instance_->profilingEnabled()) {
if (!activation_->compartment()->wasm.profilingEnabled()) {
MOZ_ASSERT(done());
return;
}
// If pc isn't in the instance's code, we must have exited the code via an
// exit trampoline or signal handler.
if (!instance_->codeSegment().containsCodePC(state.pc)) {
initFromFP(activation);
code_ = activation_->compartment()->wasm.lookupCode(state.pc);
if (!code_) {
initFromFP();
return;
}
// Note: fp may be null while entering and leaving the activation.
uint8_t* fp = activation.fp();
const CodeRange* codeRange = instance_->lookupCodeRange(state.pc);
const CodeRange* codeRange = code_->lookupRange(state.pc);
switch (codeRange->kind()) {
case CodeRange::Function:
case CodeRange::CallThunk:
@ -591,8 +629,7 @@ ProfilingFrameIterator::ProfilingFrameIterator(const WasmActivation& activation,
// while pc is in the prologue/epilogue would skip the second-to-
// innermost call. To avoid this problem, we use the static structure of
// the code in the prologue and epilogue to do the Right Thing.
MOZ_ASSERT(instance_->codeSegment().containsCodePC(state.pc));
uint32_t offsetInModule = (uint8_t*)state.pc - instance_->codeSegment().code();
uint32_t offsetInModule = (uint8_t*)state.pc - code_->segment().base();
MOZ_ASSERT(offsetInModule >= codeRange->begin());
MOZ_ASSERT(offsetInModule < codeRange->end());
uint32_t offsetInCodeRange = offsetInModule - codeRange->begin();
@ -603,13 +640,13 @@ ProfilingFrameIterator::ProfilingFrameIterator(const WasmActivation& activation,
// still in lr and fp still holds the caller's fp.
callerPC_ = state.lr;
callerFP_ = fp;
AssertMatchesCallSite(*instance_, callerPC_, callerFP_, sp - 2);
AssertMatchesCallSite(*activation_, callerPC_, callerFP_, sp - 2);
} else if (offsetInModule == codeRange->profilingReturn() - PostStorePrePopFP) {
// Second-to-last instruction of the ARM/MIPS function; fp points to
// the caller's fp; have not yet popped AsmJSFrame.
callerPC_ = ReturnAddressFromFP(sp);
callerFP_ = CallerFPFromFP(sp);
AssertMatchesCallSite(*instance_, callerPC_, callerFP_, sp);
AssertMatchesCallSite(*activation_, callerPC_, callerFP_, sp);
} else
#endif
if (offsetInCodeRange < PushedFP || offsetInModule == codeRange->profilingReturn() ||
@ -619,19 +656,19 @@ ProfilingFrameIterator::ProfilingFrameIterator(const WasmActivation& activation,
// still points to the caller's fp.
callerPC_ = *sp;
callerFP_ = fp;
AssertMatchesCallSite(*instance_, callerPC_, callerFP_, sp - 1);
AssertMatchesCallSite(*activation_, callerPC_, callerFP_, sp - 1);
} else if (offsetInCodeRange < StoredFP) {
// The full AsmJSFrame has been pushed; fp still points to the
// caller's frame.
MOZ_ASSERT(fp == CallerFPFromFP(sp));
callerPC_ = ReturnAddressFromFP(sp);
callerFP_ = CallerFPFromFP(sp);
AssertMatchesCallSite(*instance_, callerPC_, callerFP_, sp);
AssertMatchesCallSite(*activation_, callerPC_, callerFP_, sp);
} else {
// Not in the prologue/epilogue.
callerPC_ = ReturnAddressFromFP(fp);
callerFP_ = CallerFPFromFP(fp);
AssertMatchesCallSite(*instance_, callerPC_, callerFP_, fp);
AssertMatchesCallSite(*activation_, callerPC_, callerFP_, fp);
}
break;
}
@ -658,7 +695,7 @@ ProfilingFrameIterator::ProfilingFrameIterator(const WasmActivation& activation,
// skipped frames. Thus, we use simply unwind based on fp.
callerPC_ = ReturnAddressFromFP(fp);
callerFP_ = CallerFPFromFP(fp);
AssertMatchesCallSite(*instance_, callerPC_, callerFP_, fp);
AssertMatchesCallSite(*activation_, callerPC_, callerFP_, fp);
break;
}
}
@ -685,11 +722,13 @@ ProfilingFrameIterator::operator++()
return;
}
const CodeRange* codeRange = instance_->lookupCodeRange(callerPC_);
MOZ_ASSERT(codeRange);
codeRange_ = codeRange;
code_ = activation_->compartment()->wasm.lookupCode(callerPC_);
MOZ_ASSERT(code_);
switch (codeRange->kind()) {
codeRange_ = code_->lookupRange(callerPC_);
MOZ_ASSERT(codeRange_);
switch (codeRange_->kind()) {
case CodeRange::Entry:
MOZ_ASSERT(callerFP_ == nullptr);
callerPC_ = nullptr;
@ -701,7 +740,7 @@ ProfilingFrameIterator::operator++()
case CodeRange::CallThunk:
stackAddress_ = callerFP_;
callerPC_ = ReturnAddressFromFP(callerFP_);
AssertMatchesCallSite(*instance_, callerPC_, CallerFPFromFP(callerFP_), callerFP_);
AssertMatchesCallSite(*activation_, callerPC_, CallerFPFromFP(callerFP_), callerFP_);
callerFP_ = CallerFPFromFP(callerFP_);
break;
}
@ -735,7 +774,7 @@ ProfilingFrameIterator::label() const
}
switch (codeRange_->kind()) {
case CodeRange::Function: return instance_->profilingLabel(codeRange_->funcIndex());
case CodeRange::Function: return code_->profilingLabel(codeRange_->funcIndex());
case CodeRange::Entry: return "entry trampoline (in asm.js)";
case CodeRange::ImportJitExit: return importJitDescription;
case CodeRange::ImportInterpExit: return importInterpDescription;
@ -750,12 +789,12 @@ ProfilingFrameIterator::label() const
// Runtime patching to enable/disable profiling
void
wasm::ToggleProfiling(const Instance& instance, const CallSite& callSite, bool enabled)
wasm::ToggleProfiling(const Code& code, const CallSite& callSite, bool enabled)
{
if (callSite.kind() != CallSite::Relative)
return;
uint8_t* callerRetAddr = instance.codeSegment().code() + callSite.returnAddressOffset();
uint8_t* callerRetAddr = code.segment().base() + callSite.returnAddressOffset();
#if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
void* callee = X86Encoding::GetRel32Target(callerRetAddr);
@ -782,12 +821,12 @@ wasm::ToggleProfiling(const Instance& instance, const CallSite& callSite, bool e
# error "Missing architecture"
#endif
const CodeRange* codeRange = instance.lookupCodeRange(callee);
const CodeRange* codeRange = code.lookupRange(callee);
if (!codeRange->isFunction())
return;
uint8_t* from = instance.codeSegment().code() + codeRange->funcNonProfilingEntry();
uint8_t* to = instance.codeSegment().code() + codeRange->funcProfilingEntry();
uint8_t* from = code.segment().base() + codeRange->funcNonProfilingEntry();
uint8_t* to = code.segment().base() + codeRange->funcProfilingEntry();
if (!enabled)
Swap(from, to);
@ -810,24 +849,24 @@ wasm::ToggleProfiling(const Instance& instance, const CallSite& callSite, bool e
}
void
wasm::ToggleProfiling(const Instance& instance, const CallThunk& callThunk, bool enabled)
wasm::ToggleProfiling(const Code& code, const CallThunk& callThunk, bool enabled)
{
const CodeRange& cr = instance.metadata().codeRanges[callThunk.u.codeRangeIndex];
const CodeRange& cr = code.metadata().codeRanges[callThunk.u.codeRangeIndex];
uint32_t calleeOffset = enabled ? cr.funcProfilingEntry() : cr.funcNonProfilingEntry();
MacroAssembler::repatchThunk(instance.codeSegment().code(), callThunk.offset, calleeOffset);
MacroAssembler::repatchThunk(code.segment().base(), callThunk.offset, calleeOffset);
}
void
wasm::ToggleProfiling(const Instance& instance, const CodeRange& codeRange, bool enabled)
wasm::ToggleProfiling(const Code& code, const CodeRange& codeRange, bool enabled)
{
if (!codeRange.isFunction())
return;
uint8_t* code = instance.codeSegment().code();
uint8_t* profilingEntry = code + codeRange.funcProfilingEntry();
uint8_t* tableProfilingJump = code + codeRange.funcTableProfilingJump();
uint8_t* profilingJump = code + codeRange.funcProfilingJump();
uint8_t* profilingEpilogue = code + codeRange.funcProfilingEpilogue();
uint8_t* codeBase = code.segment().base();
uint8_t* profilingEntry = codeBase + codeRange.funcProfilingEntry();
uint8_t* tableProfilingJump = codeBase + codeRange.funcTableProfilingJump();
uint8_t* profilingJump = codeBase + codeRange.funcProfilingJump();
uint8_t* profilingEpilogue = codeBase + codeRange.funcProfilingEpilogue();
if (enabled) {
MacroAssembler::patchNopToNearJump(tableProfilingJump, profilingEntry);

Просмотреть файл

@ -31,6 +31,7 @@ namespace jit { class MacroAssembler; class Label; }
namespace wasm {
class CallSite;
class Code;
class CodeRange;
class Instance;
class SigIdDesc;
@ -49,8 +50,8 @@ struct ProfilingOffsets;
// function stack frame.
class FrameIterator
{
JSContext* cx_;
const Instance* instance_;
const WasmActivation* activation_;
const Code* code_;
const CallSite* callsite_;
const CodeRange* codeRange_;
uint8_t* fp_;
@ -63,6 +64,9 @@ class FrameIterator
explicit FrameIterator(const WasmActivation& activation);
void operator++();
bool done() const;
const char* filename() const;
const char16_t* displayURL() const;
bool mutedErrors() const;
JSAtom* functionDisplayAtom() const;
unsigned lineOrBytecode() const;
};
@ -82,14 +86,15 @@ enum class ExitReason : uint32_t
// module is not in profiling mode, the activation is skipped.
class ProfilingFrameIterator
{
const Instance* instance_;
const WasmActivation* activation_;
const Code* code_;
const CodeRange* codeRange_;
uint8_t* callerFP_;
void* callerPC_;
void* stackAddress_;
ExitReason exitReason_;
void initFromFP(const WasmActivation& activation);
void initFromFP();
public:
ProfilingFrameIterator();
@ -120,13 +125,13 @@ GenerateFunctionEpilogue(jit::MacroAssembler& masm, unsigned framePushed, FuncOf
// Runtime patching to enable/disable profiling
void
ToggleProfiling(const Instance& instance, const CallSite& callSite, bool enabled);
ToggleProfiling(const Code& code, const CallSite& callSite, bool enabled);
void
ToggleProfiling(const Instance& instance, const CallThunk& callThunk, bool enabled);
ToggleProfiling(const Code& code, const CallThunk& callThunk, bool enabled);
void
ToggleProfiling(const Instance& instance, const CodeRange& codeRange, bool enabled);
ToggleProfiling(const Code& code, const CodeRange& codeRange, bool enabled);
} // namespace wasm
} // namespace js

Просмотреть файл

@ -76,17 +76,17 @@ ModuleGenerator::~ModuleGenerator()
if (outstanding_) {
AutoLockHelperThreadState lock;
while (true) {
IonCompileTaskPtrVector& worklist = HelperThreadState().wasmWorklist();
IonCompileTaskPtrVector& worklist = HelperThreadState().wasmWorklist(lock);
MOZ_ASSERT(outstanding_ >= worklist.length());
outstanding_ -= worklist.length();
worklist.clear();
IonCompileTaskPtrVector& finished = HelperThreadState().wasmFinishedList();
IonCompileTaskPtrVector& finished = HelperThreadState().wasmFinishedList(lock);
MOZ_ASSERT(outstanding_ >= finished.length());
outstanding_ -= finished.length();
finished.clear();
uint32_t numFailed = HelperThreadState().harvestFailedWasmJobs();
uint32_t numFailed = HelperThreadState().harvestFailedWasmJobs(lock);
MOZ_ASSERT(outstanding_ >= numFailed);
outstanding_ -= numFailed;
@ -199,12 +199,12 @@ ModuleGenerator::finishOutstandingTask()
while (true) {
MOZ_ASSERT(outstanding_ > 0);
if (HelperThreadState().wasmFailed())
if (HelperThreadState().wasmFailed(lock))
return false;
if (!HelperThreadState().wasmFinishedList().empty()) {
if (!HelperThreadState().wasmFinishedList(lock).empty()) {
outstanding_--;
task = HelperThreadState().wasmFinishedList().popCopy();
task = HelperThreadState().wasmFinishedList(lock).popCopy();
break;
}
@ -790,9 +790,9 @@ ModuleGenerator::startFuncDefs()
#ifdef DEBUG
{
AutoLockHelperThreadState lock;
MOZ_ASSERT(!HelperThreadState().wasmFailed());
MOZ_ASSERT(HelperThreadState().wasmWorklist().empty());
MOZ_ASSERT(HelperThreadState().wasmFinishedList().empty());
MOZ_ASSERT(!HelperThreadState().wasmFailed(lock));
MOZ_ASSERT(HelperThreadState().wasmWorklist(lock).empty());
MOZ_ASSERT(HelperThreadState().wasmFinishedList(lock).empty());
}
#endif
parallel_ = true;

Просмотреть файл

@ -18,18 +18,9 @@
#include "asmjs/WasmInstance.h"
#include "mozilla/BinarySearch.h"
#include "jsprf.h"
#include "asmjs/WasmBinaryToExperimentalText.h"
#include "asmjs/WasmJS.h"
#include "asmjs/WasmModule.h"
#include "builtin/SIMD.h"
#include "jit/BaselineJIT.h"
#include "jit/JitCommon.h"
#include "jit/JitCompartment.h"
#include "vm/StringBuffer.h"
#include "jsobjinlines.h"
@ -94,120 +85,50 @@ class SigIdSet
ExclusiveData<SigIdSet> sigIdSet;
JSContext**
Instance::addressOfContextPtr() const
{
return (JSContext**)(codeSegment().globalData() + ContextPtrGlobalDataOffset);
}
Instance**
Instance::addressOfInstancePtr() const
{
return (Instance**)(codeSegment().globalData() + InstancePtrGlobalDataOffset);
}
uint8_t**
Instance::addressOfMemoryBase() const
{
return (uint8_t**)(codeSegment_->globalData() + HeapGlobalDataOffset);
return (uint8_t**)(codeSegment().globalData() + HeapGlobalDataOffset);
}
void**
Instance::addressOfTableBase(size_t tableIndex) const
{
MOZ_ASSERT(metadata_->tables[tableIndex].globalDataOffset >= InitialGlobalDataBytes);
return (void**)(codeSegment_->globalData() + metadata_->tables[tableIndex].globalDataOffset);
MOZ_ASSERT(metadata().tables[tableIndex].globalDataOffset >= InitialGlobalDataBytes);
return (void**)(codeSegment().globalData() + metadata().tables[tableIndex].globalDataOffset);
}
const void**
Instance::addressOfSigId(const SigIdDesc& sigId) const
{
MOZ_ASSERT(sigId.globalDataOffset() >= InitialGlobalDataBytes);
return (const void**)(codeSegment_->globalData() + sigId.globalDataOffset());
return (const void**)(codeSegment().globalData() + sigId.globalDataOffset());
}
FuncImportExit&
Instance::funcImportToExit(const FuncImport& fi)
{
MOZ_ASSERT(fi.exitGlobalDataOffset() >= InitialGlobalDataBytes);
return *(FuncImportExit*)(codeSegment_->globalData() + fi.exitGlobalDataOffset());
}
WasmActivation*&
Instance::activation()
{
return *(WasmActivation**)(codeSegment_->globalData() + ActivationGlobalDataOffset);
}
bool
Instance::toggleProfiling(JSContext* cx)
{
profilingEnabled_ = !profilingEnabled_;
{
AutoWritableJitCode awjc(cx->runtime(), codeSegment_->code(), codeSegment_->codeLength());
AutoFlushICache afc("Instance::toggleProfiling");
AutoFlushICache::setRange(uintptr_t(codeSegment_->code()), codeSegment_->codeLength());
for (const CallSite& callSite : metadata_->callSites)
ToggleProfiling(*this, callSite, profilingEnabled_);
for (const CallThunk& callThunk : metadata_->callThunks)
ToggleProfiling(*this, callThunk, profilingEnabled_);
for (const CodeRange& codeRange : metadata_->codeRanges)
ToggleProfiling(*this, codeRange, profilingEnabled_);
}
// When enabled, generate profiling labels for every name in funcNames_
// that is the name of some Function CodeRange. This involves malloc() so
// do it now since, once we start sampling, we'll be in a signal-handing
// context where we cannot malloc.
if (profilingEnabled_) {
for (const CodeRange& codeRange : metadata_->codeRanges) {
if (!codeRange.isFunction())
continue;
TwoByteName name(cx);
if (!getFuncName(cx, codeRange.funcIndex(), &name))
return false;
if (!name.append('\0'))
return false;
UniqueChars label(JS_smprintf("%hs (%s:%u)",
name.begin(),
metadata_->filename.get(),
codeRange.funcLineOrBytecode()));
if (!label) {
ReportOutOfMemory(cx);
return false;
}
if (codeRange.funcIndex() >= funcLabels_.length()) {
if (!funcLabels_.resize(codeRange.funcIndex() + 1))
return false;
}
funcLabels_[codeRange.funcIndex()] = Move(label);
}
} else {
funcLabels_.clear();
}
// Typed-function tables' elements point directly to either the profiling or
// non-profiling prologue and must therefore be updated when the profiling
// mode is toggled.
for (const SharedTable& table : tables_) {
if (!table->isTypedFunction())
continue;
void** array = table->array();
uint32_t length = table->length();
for (size_t i = 0; i < length; i++) {
const CodeRange* codeRange = lookupCodeRange(array[i]);
void* from = codeSegment_->code() + codeRange->funcNonProfilingEntry();
void* to = codeSegment_->code() + codeRange->funcProfilingEntry();
if (!profilingEnabled_)
Swap(from, to);
MOZ_ASSERT(array[i] == from);
array[i] = to;
}
}
return true;
return *(FuncImportExit*)(codeSegment().globalData() + fi.exitGlobalDataOffset());
}
bool
Instance::callImport(JSContext* cx, uint32_t funcImportIndex, unsigned argc, const uint64_t* argv,
MutableHandleValue rval)
{
const FuncImport& fi = metadata_->funcImports[funcImportIndex];
const FuncImport& fi = metadata().funcImports[funcImportIndex];
InvokeArgs args(cx);
if (!args.init(argc))
@ -260,7 +181,7 @@ Instance::callImport(JSContext* cx, uint32_t funcImportIndex, unsigned argc, con
return true;
// The exit may already have become optimized.
void* jitExitCode = codeSegment_->code() + fi.jitExitCodeOffset();
void* jitExitCode = codeBase() + fi.jitExitCodeOffset();
if (exit.code == jitExitCode)
return true;
@ -324,84 +245,75 @@ Instance::callImport(JSContext* cx, uint32_t funcImportIndex, unsigned argc, con
}
/* static */ int32_t
Instance::callImport_void(int32_t funcImportIndex, int32_t argc, uint64_t* argv)
Instance::callImport_void(Instance* instance, int32_t funcImportIndex, int32_t argc, uint64_t* argv)
{
WasmActivation* activation = JSRuntime::innermostWasmActivation();
JSContext* cx = activation->cx();
JSContext* cx = instance->cx();
RootedValue rval(cx);
return activation->instance().callImport(cx, funcImportIndex, argc, argv, &rval);
return instance->callImport(cx, funcImportIndex, argc, argv, &rval);
}
/* static */ int32_t
Instance::callImport_i32(int32_t funcImportIndex, int32_t argc, uint64_t* argv)
Instance::callImport_i32(Instance* instance, int32_t funcImportIndex, int32_t argc, uint64_t* argv)
{
WasmActivation* activation = JSRuntime::innermostWasmActivation();
JSContext* cx = activation->cx();
JSContext* cx = instance->cx();
RootedValue rval(cx);
if (!activation->instance().callImport(cx, funcImportIndex, argc, argv, &rval))
if (!instance->callImport(cx, funcImportIndex, argc, argv, &rval))
return false;
return ToInt32(cx, rval, (int32_t*)argv);
}
/* static */ int32_t
Instance::callImport_i64(int32_t funcImportIndex, int32_t argc, uint64_t* argv)
Instance::callImport_i64(Instance* instance, int32_t funcImportIndex, int32_t argc, uint64_t* argv)
{
WasmActivation* activation = JSRuntime::innermostWasmActivation();
JSContext* cx = activation->cx();
JSContext* cx = instance->cx();
RootedValue rval(cx);
if (!activation->instance().callImport(cx, funcImportIndex, argc, argv, &rval))
if (!instance->callImport(cx, funcImportIndex, argc, argv, &rval))
return false;
return ReadI64Object(cx, rval, (int64_t*)argv);
}
/* static */ int32_t
Instance::callImport_f64(int32_t funcImportIndex, int32_t argc, uint64_t* argv)
Instance::callImport_f64(Instance* instance, int32_t funcImportIndex, int32_t argc, uint64_t* argv)
{
WasmActivation* activation = JSRuntime::innermostWasmActivation();
JSContext* cx = activation->cx();
JSContext* cx = instance->cx();
RootedValue rval(cx);
if (!activation->instance().callImport(cx, funcImportIndex, argc, argv, &rval))
if (!instance->callImport(cx, funcImportIndex, argc, argv, &rval))
return false;
return ToNumber(cx, rval, (double*)argv);
}
Instance::Instance(JSContext* cx,
UniqueCodeSegment codeSegment,
const Metadata& metadata,
const ShareableBytes* maybeBytecode,
UniqueCode code,
HandleWasmMemoryObject memory,
SharedTableVector&& tables,
Handle<FunctionVector> funcImports,
const ValVector& globalImports)
: codeSegment_(Move(codeSegment)),
metadata_(&metadata),
maybeBytecode_(maybeBytecode),
: compartment_(cx->compartment()),
code_(Move(code)),
memory_(memory),
tables_(Move(tables)),
profilingEnabled_(false)
tables_(Move(tables))
{
MOZ_ASSERT(funcImports.length() == metadata.funcImports.length());
MOZ_ASSERT(tables_.length() == metadata.tables.length());
MOZ_ASSERT(funcImports.length() == metadata().funcImports.length());
MOZ_ASSERT(tables_.length() == metadata().tables.length());
for (size_t i = 0; i < metadata.funcImports.length(); i++) {
const FuncImport& fi = metadata.funcImports[i];
*addressOfContextPtr() = cx;
*addressOfInstancePtr() = this;
for (size_t i = 0; i < metadata().funcImports.length(); i++) {
const FuncImport& fi = metadata().funcImports[i];
FuncImportExit& exit = funcImportToExit(fi);
exit.code = codeSegment_->code() + fi.interpExitCodeOffset();
exit.code = codeBase() + fi.interpExitCodeOffset();
exit.fun = funcImports[i];
exit.baselineScript = nullptr;
}
uint8_t* globalData = codeSegment_->globalData();
uint8_t* globalData = code_->segment().globalData();
for (size_t i = 0; i < metadata.globals.length(); i++) {
const GlobalDesc& global = metadata.globals[i];
for (size_t i = 0; i < metadata().globals.length(); i++) {
const GlobalDesc& global = metadata().globals[i];
if (global.isConstant())
continue;
@ -419,7 +331,7 @@ Instance::Instance(JSContext* cx,
break;
}
case InitExpr::Kind::GetGlobal: {
const GlobalDesc& imported = metadata.globals[init.globalIndex()];
const GlobalDesc& imported = metadata().globals[init.globalIndex()];
globalImports[imported.importIndex()].writePayload(globalAddr);
break;
}
@ -444,13 +356,13 @@ Instance::Instance(JSContext* cx,
bool
Instance::init(JSContext* cx)
{
if (!metadata_->sigIds.empty()) {
if (!metadata().sigIds.empty()) {
ExclusiveData<SigIdSet>::Guard lockedSigIdSet = sigIdSet.lock();
if (!lockedSigIdSet->ensureInitialized(cx))
return false;
for (const SigWithId& sig : metadata_->sigIds) {
for (const SigWithId& sig : metadata().sigIds) {
const void* sigId;
if (!lockedSigIdSet->allocateSigId(cx, sig, &sigId))
return false;
@ -464,16 +376,18 @@ Instance::init(JSContext* cx)
Instance::~Instance()
{
for (unsigned i = 0; i < metadata_->funcImports.length(); i++) {
FuncImportExit& exit = funcImportToExit(metadata_->funcImports[i]);
compartment_->wasm.unregisterInstance(*this);
for (unsigned i = 0; i < metadata().funcImports.length(); i++) {
FuncImportExit& exit = funcImportToExit(metadata().funcImports[i]);
if (exit.baselineScript)
exit.baselineScript->removeDependentWasmImport(*this, i);
}
if (!metadata_->sigIds.empty()) {
if (!metadata().sigIds.empty()) {
ExclusiveData<SigIdSet>::Guard lockedSigIdSet = sigIdSet.lock();
for (const SigWithId& sig : metadata_->sigIds) {
for (const SigWithId& sig : metadata().sigIds) {
if (const void* sigId = *addressOfSigId(sig.id))
lockedSigIdSet->deallocateSigId(sig, sigId);
}
@ -483,7 +397,7 @@ Instance::~Instance()
void
Instance::trace(JSTracer* trc)
{
for (const FuncImport& fi : metadata_->funcImports)
for (const FuncImport& fi : metadata().funcImports)
TraceNullableEdge(trc, &funcImportToExit(fi).fun, "wasm function import");
TraceNullableEdge(trc, &memory_, "wasm buffer");
}
@ -491,7 +405,7 @@ Instance::trace(JSTracer* trc)
SharedMem<uint8_t*>
Instance::memoryBase() const
{
MOZ_ASSERT(metadata_->usesMemory());
MOZ_ASSERT(metadata().usesMemory());
MOZ_ASSERT(*addressOfMemoryBase() == memory_->buffer().dataPointerEither());
return memory_->buffer().dataPointerEither();
}
@ -512,16 +426,10 @@ Instance::updateStackLimit(JSContext* cx)
bool
Instance::callExport(JSContext* cx, uint32_t funcIndex, CallArgs args)
{
const FuncExport& func = metadata_->lookupFuncExport(funcIndex);
if (!cx->compartment()->wasm.ensureProfilingState(cx))
return false;
// Enable/disable profiling in the Module to match the current global
// profiling state. Don't do this if the Module is already active on the
// stack since this would leave the Module in a state where profiling is
// enabled but the stack isn't unwindable.
if (profilingEnabled() != cx->runtime()->spsProfiler.enabled() && !activation()) {
if (!toggleProfiling(cx))
return false;
}
const FuncExport& func = metadata().lookupFuncExport(funcIndex);
// The calling convention for an external call into wasm is to pass an
// array of 16-byte values where each value contains either a coerced int32
@ -619,12 +527,12 @@ Instance::callExport(JSContext* cx, uint32_t funcIndex, CallArgs args)
// the optimized wasm-to-Ion FFI call path (which we want to be very
// fast) can avoid doing so. The JitActivation is marked as inactive so
// stack iteration will skip over it.
WasmActivation activation(cx, *this);
WasmActivation activation(cx);
JitActivation jitActivation(cx, /* active */ false);
// Call the per-exported-function trampoline created by GenerateEntry.
auto funcPtr = JS_DATA_TO_FUNC_PTR(ExportFuncPtr, codeSegment_->code() + func.entryOffset());
if (!CALL_GENERATED_3(funcPtr, exportArgs.begin(), codeSegment_->globalData(), tlsData()))
auto funcPtr = JS_DATA_TO_FUNC_PTR(ExportFuncPtr, codeBase() + func.entryOffset());
if (!CALL_GENERATED_3(funcPtr, exportArgs.begin(), codeSegment().globalData(), tlsData()))
return false;
}
@ -705,189 +613,53 @@ Instance::callExport(JSContext* cx, uint32_t funcIndex, CallArgs args)
return true;
}
const char experimentalWarning[] =
"Temporary\n"
".--. .--. ____ .-'''-. ,---. ,---.\n"
"| |_ | | .' __ `. / _ \\| \\ / |\n"
"| _( )_ | |/ ' \\ \\ (`' )/`--'| , \\/ , |\n"
"|(_ o _) | ||___| / |(_ o _). | |\\_ /| |\n"
"| (_,_) \\ | | _.-` | (_,_). '. | _( )_/ | |\n"
"| |/ \\| |.' _ |.---. \\ :| (_ o _) | |\n"
"| ' /\\ ` || _( )_ |\\ `-' || (_,_) | |\n"
"| / \\ |\\ (_ o _) / \\ / | | | |\n"
"`---' `---` '.(_,_).' `-...-' '--' '--'\n"
"text support (Work In Progress):\n\n";
const size_t experimentalWarningLinesCount = 12;
const char enabledMessage[] =
"Restart with developer tools open to view WebAssembly source";
JSString*
Instance::createText(JSContext* cx)
{
StringBuffer buffer(cx);
if (maybeBytecode_) {
const Bytes& bytes = maybeBytecode_->bytes;
if (!buffer.append(experimentalWarning))
return nullptr;
maybeSourceMap_.reset(cx->runtime()->new_<GeneratedSourceMap>(cx));
if (!maybeSourceMap_)
return nullptr;
if (!BinaryToExperimentalText(cx, bytes.begin(), bytes.length(), buffer,
ExperimentalTextFormatting(), maybeSourceMap_.get()))
return nullptr;
#if DEBUG
// Checking source map invariant: expression and function locations must be sorted
// by line number.
uint32_t lastLineno = 0;
for (size_t i = 0; i < maybeSourceMap_->exprlocs().length(); i++) {
MOZ_ASSERT(lastLineno <= maybeSourceMap_->exprlocs()[i].lineno);
lastLineno = maybeSourceMap_->exprlocs()[i].lineno;
}
lastLineno = 0;
for (size_t i = 0; i < maybeSourceMap_->functionlocs().length(); i++) {
MOZ_ASSERT(lastLineno <= maybeSourceMap_->functionlocs()[i].startLineno &&
maybeSourceMap_->functionlocs()[i].startLineno <=
maybeSourceMap_->functionlocs()[i].endLineno);
lastLineno = maybeSourceMap_->functionlocs()[i].endLineno + 1;
}
#endif
} else {
if (!buffer.append(enabledMessage))
return nullptr;
}
return buffer.finishString();
}
struct GeneratedSourceMapLinenoComparator
{
int operator()(const ExprLoc& loc) const {
return lineno == loc.lineno ? 0 : lineno < loc.lineno ? -1 : 1;
}
explicit GeneratedSourceMapLinenoComparator(uint32_t lineno_) : lineno(lineno_) {}
const uint32_t lineno;
};
bool
Instance::getLineOffsets(size_t lineno, Vector<uint32_t>& offsets)
{
// TODO Ensure text was generated?
if (!maybeSourceMap_)
return false;
if (lineno < experimentalWarningLinesCount)
return true;
lineno -= experimentalWarningLinesCount;
ExprLocVector& exprlocs = maybeSourceMap_->exprlocs();
// Binary search for the expression with the specified line number and
// rewind to the first expression, if more than one expression on the same line.
size_t match;
if (!BinarySearchIf(exprlocs, 0, exprlocs.length(),
GeneratedSourceMapLinenoComparator(lineno), &match))
return true;
while (match > 0 && exprlocs[match - 1].lineno == lineno)
match--;
// Returning all expression offsets that were printed on the specified line.
for (size_t i = match; i < exprlocs.length() && exprlocs[i].lineno == lineno; i++) {
if (!offsets.append(exprlocs[i].offset))
return false;
}
return true;
}
bool
Instance::getFuncName(JSContext* cx, uint32_t funcIndex, TwoByteName* name) const
{
const Bytes* maybeBytecode = maybeBytecode_ ? &maybeBytecode_.get()->bytes : nullptr;
return metadata_->getFuncName(cx, maybeBytecode, funcIndex, name);
}
JSAtom*
Instance::getFuncAtom(JSContext* cx, uint32_t funcIndex) const
{
TwoByteName name(cx);
if (!getFuncName(cx, funcIndex, &name))
return nullptr;
return AtomizeChars(cx, name.begin(), name.length());
}
void
Instance::deoptimizeImportExit(uint32_t funcImportIndex)
{
const FuncImport& fi = metadata_->funcImports[funcImportIndex];
const FuncImport& fi = metadata().funcImports[funcImportIndex];
FuncImportExit& exit = funcImportToExit(fi);
exit.code = codeSegment_->code() + fi.interpExitCodeOffset();
exit.code = codeBase() + fi.interpExitCodeOffset();
exit.baselineScript = nullptr;
}
struct CallSiteRetAddrOffset
bool
Instance::ensureProfilingState(JSContext* cx, bool newProfilingEnabled)
{
const CallSiteVector& callSites;
explicit CallSiteRetAddrOffset(const CallSiteVector& callSites) : callSites(callSites) {}
uint32_t operator[](size_t index) const {
return callSites[index].returnAddressOffset();
if (code_->profilingEnabled() == newProfilingEnabled)
return true;
if (!code_->ensureProfilingState(cx, newProfilingEnabled))
return false;
// Typed-function tables' elements point directly to either the profiling or
// non-profiling prologue and must therefore be updated when the profiling
// mode is toggled.
for (const SharedTable& table : tables_) {
if (!table->isTypedFunction() || !table->initialized())
continue;
// This logic will have to be somewhat generalized if wasm can create
// typed function tables since a single table can contain elements from
// multiple instances.
MOZ_ASSERT(metadata().kind == ModuleKind::AsmJS);
void** array = table->array();
uint32_t length = table->length();
for (size_t i = 0; i < length; i++) {
const CodeRange* codeRange = code_->lookupRange(array[i]);
void* from = codeBase() + codeRange->funcNonProfilingEntry();
void* to = codeBase() + codeRange->funcProfilingEntry();
if (!newProfilingEnabled)
Swap(from, to);
MOZ_ASSERT(array[i] == from);
array[i] = to;
}
}
};
const CallSite*
Instance::lookupCallSite(void* returnAddress) const
{
uint32_t target = ((uint8_t*)returnAddress) - codeSegment_->code();
size_t lowerBound = 0;
size_t upperBound = metadata_->callSites.length();
size_t match;
if (!BinarySearch(CallSiteRetAddrOffset(metadata_->callSites), lowerBound, upperBound, target, &match))
return nullptr;
return &metadata_->callSites[match];
return true;
}
const CodeRange*
Instance::lookupCodeRange(void* pc) const
{
CodeRange::PC target((uint8_t*)pc - codeSegment_->code());
size_t lowerBound = 0;
size_t upperBound = metadata_->codeRanges.length();
size_t match;
if (!BinarySearch(metadata_->codeRanges, lowerBound, upperBound, target, &match))
return nullptr;
return &metadata_->codeRanges[match];
}
#ifdef ASMJS_MAY_USE_SIGNAL_HANDLERS
struct MemoryAccessOffset
{
const MemoryAccessVector& accesses;
explicit MemoryAccessOffset(const MemoryAccessVector& accesses) : accesses(accesses) {}
uintptr_t operator[](size_t index) const {
return accesses[index].insnOffset();
}
};
const MemoryAccess*
Instance::lookupMemoryAccess(void* pc) const
{
MOZ_ASSERT(codeSegment_->containsFunctionPC(pc));
uint32_t target = ((uint8_t*)pc) - codeSegment_->code();
size_t lowerBound = 0;
size_t upperBound = metadata_->memoryAccesses.length();
size_t match;
if (!BinarySearch(MemoryAccessOffset(metadata_->memoryAccesses), lowerBound, upperBound, target, &match))
return nullptr;
return &metadata_->memoryAccesses[match];
}
#endif // ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_OOB
void
Instance::addSizeOfMisc(MallocSizeOf mallocSizeOf,
Metadata::SeenSet* seenMetadata,
@ -896,14 +668,10 @@ Instance::addSizeOfMisc(MallocSizeOf mallocSizeOf,
size_t* code,
size_t* data) const
{
*code += codeSegment_->codeLength();
*data += mallocSizeOf(this) +
codeSegment_->globalDataLength() +
metadata_->sizeOfIncludingThisIfNotSeen(mallocSizeOf, seenMetadata);
*data += mallocSizeOf(this);
code_->addSizeOfMisc(mallocSizeOf, seenMetadata, seenBytes, code, data);
for (const SharedTable& table : tables_)
*data += table->sizeOfIncludingThisIfNotSeen(mallocSizeOf, seenTables);
if (maybeBytecode_)
*data += maybeBytecode_->sizeOfIncludingThisIfNotSeen(mallocSizeOf, seenBytes);
}

Просмотреть файл

@ -30,8 +30,6 @@ class WasmInstanceObject;
namespace wasm {
class GeneratedSourceMap;
// Instance represents a wasm instance and provides all the support for runtime
// execution of code in the instance. Instances share various immutable data
// structures with the Module from which they were instantiated and other
@ -41,52 +39,40 @@ class GeneratedSourceMap;
class Instance
{
const UniqueCodeSegment codeSegment_;
const SharedMetadata metadata_;
const SharedBytes maybeBytecode_;
JSCompartment* const compartment_;
const UniqueCode code_;
GCPtrWasmMemoryObject memory_;
SharedTableVector tables_;
bool profilingEnabled_;
CacheableCharsVector funcLabels_;
UniquePtr<GeneratedSourceMap> maybeSourceMap_;
// Thread-local data for code running in this instance.
// When threading is supported, we need a TlsData object per thread per
// instance.
TlsData tlsData_;
// Internal helpers:
JSContext** addressOfContextPtr() const;
Instance** addressOfInstancePtr() const;
uint8_t** addressOfMemoryBase() const;
void** addressOfTableBase(size_t tableIndex) const;
const void** addressOfSigId(const SigIdDesc& sigId) const;
FuncImportExit& funcImportToExit(const FuncImport& fi);
MOZ_MUST_USE bool toggleProfiling(JSContext* cx);
// Get this instance's TLS data pointer for the current thread.
TlsData* tlsData() { return &tlsData_; }
// An instance keeps track of its innermost WasmActivation. A WasmActivation
// is pushed for the duration of each call of an export.
friend class js::WasmActivation;
WasmActivation*& activation();
// Import call slow paths which are called directly from wasm code.
friend void* AddressOf(SymbolicAddress, ExclusiveContext*);
static int32_t callImport_void(Instance*, int32_t, int32_t, uint64_t*);
static int32_t callImport_i32(Instance*, int32_t, int32_t, uint64_t*);
static int32_t callImport_i64(Instance*, int32_t, int32_t, uint64_t*);
static int32_t callImport_f64(Instance*, int32_t, int32_t, uint64_t*);
bool callImport(JSContext* cx, uint32_t funcImportIndex, unsigned argc, const uint64_t* argv,
MutableHandleValue rval);
static int32_t callImport_void(int32_t importIndex, int32_t argc, uint64_t* argv);
static int32_t callImport_i32(int32_t importIndex, int32_t argc, uint64_t* argv);
static int32_t callImport_i64(int32_t importIndex, int32_t argc, uint64_t* argv);
static int32_t callImport_f64(int32_t importIndex, int32_t argc, uint64_t* argv);
public:
Instance(JSContext* cx,
UniqueCodeSegment codeSegment,
const Metadata& metadata,
const ShareableBytes* maybeBytecode,
UniqueCode code,
HandleWasmMemoryObject memory,
SharedTableVector&& tables,
Handle<FunctionVector> funcImports,
@ -95,8 +81,13 @@ class Instance
bool init(JSContext* cx);
void trace(JSTracer* trc);
const CodeSegment& codeSegment() const { return *codeSegment_; }
const Metadata& metadata() const { return *metadata_; }
JSContext* cx() const { return *addressOfContextPtr(); }
JSCompartment* compartment() const { return compartment_; }
Code& code() { return *code_; }
const Code& code() const { return *code_; }
const CodeSegment& codeSegment() const { return code_->segment(); }
uint8_t* codeBase() const { return code_->segment().base(); }
const Metadata& metadata() const { return code_->metadata(); }
const SharedTableVector& tables() const { return tables_; }
SharedMem<uint8_t*> memoryBase() const;
size_t memoryLength() const;
@ -106,31 +97,6 @@ class Instance
MOZ_MUST_USE bool callExport(JSContext* cx, uint32_t funcIndex, CallArgs args);
// An instance has a profiling mode that is updated to match the runtime's
// profiling mode when calling an instance's exports when there are no other
// activations of the instance live on the stack. Once in profiling mode,
// ProfilingFrameIterator can be used to asynchronously walk the stack.
// Otherwise, the ProfilingFrameIterator will skip any activations of this
// instance.
bool profilingEnabled() const { return profilingEnabled_; }
const char* profilingLabel(uint32_t funcIndex) const { return funcLabels_[funcIndex].get(); }
// If the source binary was saved (by passing the bytecode to the
// constructor), this method will render the binary as text. Otherwise, a
// diagnostic string will be returned.
// Text format support functions:
JSString* createText(JSContext* cx);
bool getLineOffsets(size_t lineno, Vector<uint32_t>& offsets);
// Return the name associated with a given function index, or generate one
// if none was given by the module.
bool getFuncName(JSContext* cx, uint32_t funcIndex, TwoByteName* name) const;
JSAtom* getFuncAtom(JSContext* cx, uint32_t funcIndex) const;
// Initially, calls to imports in wasm code call out through the generic
// callImport method. If the imported callee gets JIT compiled and the types
// match up, callImport will patch the code to instead call through a thunk
@ -139,13 +105,9 @@ class Instance
void deoptimizeImportExit(uint32_t funcImportIndex);
// Stack frame iterator support:
// See Code::ensureProfilingState comment.
const CallSite* lookupCallSite(void* returnAddress) const;
const CodeRange* lookupCodeRange(void* pc) const;
#ifdef ASMJS_MAY_USE_SIGNAL_HANDLERS
const MemoryAccess* lookupMemoryAccess(void* pc) const;
#endif
MOZ_MUST_USE bool ensureProfilingState(JSContext* cx, bool enabled);
// Update the instance's copy of the stack limit.
void updateStackLimit(JSContext*);

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше