зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central to autoland. r=merge a=merge CLOSED TREE
This commit is contained in:
Коммит
30e58c79b0
|
@ -7,10 +7,13 @@
|
|||
#include "Compatibility.h"
|
||||
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "mozilla/WindowsVersion.h"
|
||||
|
||||
#include "nsDataHashtable.h"
|
||||
#include "nsPrintfCString.h"
|
||||
#include "nsReadableUtils.h"
|
||||
#include "nsString.h"
|
||||
#include "nsTHashtable.h"
|
||||
#include "nsUnicharUtils.h"
|
||||
#include "nsWinUtils.h"
|
||||
|
||||
|
@ -31,32 +34,102 @@
|
|||
|
||||
#endif // defined(UIA_LOGGING)
|
||||
|
||||
static bool
|
||||
GetLocalObjectHandle(DWORD aSrcPid, HANDLE aSrcHandle, nsAutoHandle& aProcess,
|
||||
nsAutoHandle& aLocal)
|
||||
struct ByteArrayDeleter
|
||||
{
|
||||
aLocal.reset();
|
||||
|
||||
if (!aProcess) {
|
||||
HANDLE rawProcess = ::OpenProcess(PROCESS_DUP_HANDLE, FALSE, aSrcPid);
|
||||
if (!rawProcess) {
|
||||
LOG_ERROR(OpenProcess);
|
||||
return false;
|
||||
}
|
||||
|
||||
aProcess.own(rawProcess);
|
||||
void operator()(void* aBuf)
|
||||
{
|
||||
delete[] reinterpret_cast<char*>(aBuf);
|
||||
}
|
||||
};
|
||||
|
||||
HANDLE rawDuped;
|
||||
if (!::DuplicateHandle(aProcess.get(), aSrcHandle, ::GetCurrentProcess(),
|
||||
&rawDuped, GENERIC_READ, FALSE, 0)) {
|
||||
LOG_ERROR(DuplicateHandle);
|
||||
typedef UniquePtr<OBJECT_DIRECTORY_INFORMATION, ByteArrayDeleter> ObjDirInfoPtr;
|
||||
|
||||
// ComparatorFnT returns true to continue searching, or else false to indicate
|
||||
// search completion.
|
||||
template <typename ComparatorFnT>
|
||||
static bool
|
||||
FindNamedObject(ComparatorFnT aComparator)
|
||||
{
|
||||
// We want to enumerate every named kernel object in our session. We do this
|
||||
// by opening a directory object using a path constructed using the session
|
||||
// id under which our process resides.
|
||||
DWORD sessionId;
|
||||
if (!::ProcessIdToSessionId(::GetCurrentProcessId(), &sessionId)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
aLocal.own(rawDuped);
|
||||
nsAutoString path;
|
||||
path.AppendPrintf("\\Sessions\\%u\\BaseNamedObjects", sessionId);
|
||||
|
||||
return true;
|
||||
UNICODE_STRING baseNamedObjectsName;
|
||||
::RtlInitUnicodeString(&baseNamedObjectsName, path.get());
|
||||
|
||||
OBJECT_ATTRIBUTES attributes;
|
||||
InitializeObjectAttributes(&attributes, &baseNamedObjectsName, 0,
|
||||
nullptr, nullptr);
|
||||
|
||||
HANDLE rawBaseNamedObjects;
|
||||
NTSTATUS ntStatus = ::NtOpenDirectoryObject(&rawBaseNamedObjects,
|
||||
DIRECTORY_QUERY | DIRECTORY_TRAVERSE,
|
||||
&attributes);
|
||||
if (!NT_SUCCESS(ntStatus)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsAutoHandle baseNamedObjects(rawBaseNamedObjects);
|
||||
|
||||
ULONG context = 0, returnedLen;
|
||||
|
||||
ULONG objDirInfoBufLen = 1024 * sizeof(OBJECT_DIRECTORY_INFORMATION);
|
||||
ObjDirInfoPtr objDirInfo(
|
||||
reinterpret_cast<OBJECT_DIRECTORY_INFORMATION*>(new char[objDirInfoBufLen]));
|
||||
|
||||
// Now query that directory object for every named object that it contains.
|
||||
|
||||
BOOL firstCall = TRUE;
|
||||
|
||||
do {
|
||||
ntStatus = ::NtQueryDirectoryObject(baseNamedObjects, objDirInfo.get(),
|
||||
objDirInfoBufLen, FALSE, firstCall,
|
||||
&context, &returnedLen);
|
||||
#if defined(HAVE_64BIT_BUILD)
|
||||
if (!NT_SUCCESS(ntStatus)) {
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
if (ntStatus == STATUS_BUFFER_TOO_SMALL) {
|
||||
// This case only occurs on 32-bit builds running atop WOW64.
|
||||
// (See https://bugzilla.mozilla.org/show_bug.cgi?id=1423999#c3)
|
||||
objDirInfo.reset(reinterpret_cast<OBJECT_DIRECTORY_INFORMATION*>(new char[returnedLen]));
|
||||
objDirInfoBufLen = returnedLen;
|
||||
continue;
|
||||
} else if (!NT_SUCCESS(ntStatus)) {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
// NtQueryDirectoryObject gave us an array of OBJECT_DIRECTORY_INFORMATION
|
||||
// structures whose final entry is zeroed out.
|
||||
OBJECT_DIRECTORY_INFORMATION* curDir = objDirInfo.get();
|
||||
while (curDir->mName.Length && curDir->mTypeName.Length) {
|
||||
// We use nsDependentSubstring here because UNICODE_STRINGs are not
|
||||
// guaranteed to be null-terminated.
|
||||
nsDependentSubstring objName(curDir->mName.Buffer,
|
||||
curDir->mName.Length / sizeof(wchar_t));
|
||||
nsDependentSubstring typeName(curDir->mTypeName.Buffer,
|
||||
curDir->mTypeName.Length / sizeof(wchar_t));
|
||||
|
||||
if (!aComparator(objName, typeName)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
++curDir;
|
||||
}
|
||||
|
||||
firstCall = FALSE;
|
||||
} while (ntStatus == STATUS_MORE_ENTRIES);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
namespace mozilla {
|
||||
|
@ -74,15 +147,6 @@ Compatibility::OnUIAMessage(WPARAM aWParam, LPARAM aLParam)
|
|||
|
||||
Telemetry::AutoTimer<Telemetry::A11Y_UIA_DETECTION_TIMING_MS> timer;
|
||||
|
||||
static auto pNtQuerySystemInformation =
|
||||
reinterpret_cast<decltype(&::NtQuerySystemInformation)>(
|
||||
::GetProcAddress(::GetModuleHandleW(L"ntdll.dll"),
|
||||
"NtQuerySystemInformation"));
|
||||
|
||||
static auto pNtQueryObject =
|
||||
reinterpret_cast<decltype(&::NtQueryObject)>(
|
||||
::GetProcAddress(::GetModuleHandleW(L"ntdll.dll"), "NtQueryObject"));
|
||||
|
||||
// UIA creates a section containing the substring "HOOK_SHMEM_"
|
||||
NS_NAMED_LITERAL_STRING(kStrHookShmem, "HOOK_SHMEM_");
|
||||
|
||||
|
@ -90,7 +154,27 @@ Compatibility::OnUIAMessage(WPARAM aWParam, LPARAM aLParam)
|
|||
// current thread id and the UIA message's WPARAM and LPARAM.
|
||||
nsAutoString partialSectionSuffix;
|
||||
partialSectionSuffix.AppendPrintf("_%08x_%08x_%08x", ::GetCurrentThreadId(),
|
||||
aLParam, aWParam);
|
||||
static_cast<DWORD>(aLParam), aWParam);
|
||||
|
||||
// Find any named Section that matches the naming convention of the UIA shared
|
||||
// memory.
|
||||
nsAutoHandle section;
|
||||
auto comparator = [&](const nsDependentSubstring& aName,
|
||||
const nsDependentSubstring& aType) -> bool {
|
||||
if (aType.Equals(NS_LITERAL_STRING("Section")) &&
|
||||
FindInReadable(kStrHookShmem, aName) &&
|
||||
StringEndsWith(aName, partialSectionSuffix)) {
|
||||
section.own(::OpenFileMapping(GENERIC_READ, FALSE,
|
||||
PromiseFlatString(aName).get()));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
if (!FindNamedObject(comparator) || !section) {
|
||||
return Nothing();
|
||||
}
|
||||
|
||||
NTSTATUS ntStatus;
|
||||
|
||||
|
@ -105,7 +189,7 @@ Compatibility::OnUIAMessage(WPARAM aWParam, LPARAM aLParam)
|
|||
while (true) {
|
||||
handleInfoBuf = MakeUnique<char[]>(handleInfoBufLen);
|
||||
|
||||
ntStatus = pNtQuerySystemInformation(
|
||||
ntStatus = ::NtQuerySystemInformation(
|
||||
(SYSTEM_INFORMATION_CLASS) SystemExtendedHandleInformation,
|
||||
handleInfoBuf.get(), handleInfoBufLen, &handleInfoBufLen);
|
||||
if (ntStatus == STATUS_INFO_LENGTH_MISMATCH) {
|
||||
|
@ -119,161 +203,99 @@ Compatibility::OnUIAMessage(WPARAM aWParam, LPARAM aLParam)
|
|||
break;
|
||||
}
|
||||
|
||||
// Now we iterate through the system handle list, searching for a section
|
||||
// handle whose name matches the section name used by UIA.
|
||||
|
||||
static Maybe<USHORT> sSectionObjTypeIndex;
|
||||
|
||||
const DWORD ourPid = ::GetCurrentProcessId();
|
||||
|
||||
Maybe<PVOID> kernelObject;
|
||||
|
||||
ULONG lastPid = 0;
|
||||
nsAutoHandle process;
|
||||
static Maybe<USHORT> sectionObjTypeIndex;
|
||||
nsTHashtable<nsUint32HashKey> nonSectionObjTypes;
|
||||
nsDataHashtable<nsVoidPtrHashKey, DWORD> objMap;
|
||||
|
||||
auto handleInfo = reinterpret_cast<SYSTEM_HANDLE_INFORMATION_EX*>(handleInfoBuf.get());
|
||||
|
||||
for (ULONG index = 0; index < handleInfo->mHandleCount; ++index) {
|
||||
SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX& curHandle = handleInfo->mHandles[index];
|
||||
|
||||
if (lastPid && lastPid == curHandle.mPid && !process) {
|
||||
// During the previous iteration, we could not obtain a handle for this
|
||||
// pid. Skip any remaining handles belonging to that pid.
|
||||
HANDLE handle = reinterpret_cast<HANDLE>(curHandle.mHandle);
|
||||
|
||||
// The mapping of the curHandle.mObjectTypeIndex field depends on the
|
||||
// underlying OS kernel. As we scan through the handle list, we record the
|
||||
// type indices such that we may use those values to skip over handles that
|
||||
// refer to non-section objects.
|
||||
if (sectionObjTypeIndex) {
|
||||
// If we know the type index for Sections, that's the fastest check...
|
||||
if (sectionObjTypeIndex.value() != curHandle.mObjectTypeIndex) {
|
||||
// Not a section
|
||||
continue;
|
||||
}
|
||||
} else if (nonSectionObjTypes.Contains(static_cast<uint32_t>(
|
||||
curHandle.mObjectTypeIndex))) {
|
||||
// Otherwise we check whether or not the object type is definitely _not_
|
||||
// a Section...
|
||||
continue;
|
||||
}
|
||||
|
||||
// As a perf optimization, we reuse the same process handle as long as we're
|
||||
// still looking at the same pid. Once the pid changes, we need to reset
|
||||
// process so that we open a new handle to the newly-seen process.
|
||||
if (lastPid != curHandle.mPid) {
|
||||
process.reset();
|
||||
}
|
||||
|
||||
nsAutoHandle handle;
|
||||
|
||||
if (kernelObject.isSome() && kernelObject.value() == curHandle.mObject) {
|
||||
// If we know the value of the underlying kernel object, we can immediately
|
||||
// check for equality by comparing against curHandle.mObject
|
||||
remotePid = Some(static_cast<DWORD>(curHandle.mPid));
|
||||
break;
|
||||
} else if (sSectionObjTypeIndex.isSome()) {
|
||||
// Otherwise, if we know which object type value corresponds to a Section
|
||||
// object, we can use that to eliminate any handles that are not sections.
|
||||
if (curHandle.mObjectTypeIndex != sSectionObjTypeIndex.value()) {
|
||||
// Not a section handle
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
// Otherwise we need to query the handle to determine its type. Note that
|
||||
// each handle in the system list is relative to its owning process, so
|
||||
// we cannot do anything with it until we duplicate the handle into our
|
||||
// own process.
|
||||
|
||||
lastPid = curHandle.mPid;
|
||||
|
||||
if (!GetLocalObjectHandle((DWORD) curHandle.mPid,
|
||||
(HANDLE) curHandle.mHandle,
|
||||
process, handle)) {
|
||||
// We don't have access to do this, assume this handle isn't relevant
|
||||
continue;
|
||||
}
|
||||
|
||||
// Now we have our own handle to the object, lets find out what type of
|
||||
// object this handle represents. Any handle whose type is not "Section"
|
||||
// is of no interest to us.
|
||||
} else if (ourPid == curHandle.mPid) {
|
||||
// Otherwise we need to issue some system calls to find out the object
|
||||
// type corresponding to the current handle's type index.
|
||||
ULONG objTypeBufLen;
|
||||
ntStatus = pNtQueryObject(handle, ObjectTypeInformation, nullptr,
|
||||
0, &objTypeBufLen);
|
||||
ntStatus = ::NtQueryObject(handle, ObjectTypeInformation,
|
||||
nullptr, 0, &objTypeBufLen);
|
||||
if (ntStatus != STATUS_INFO_LENGTH_MISMATCH) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto objTypeBuf = MakeUnique<char[]>(objTypeBufLen);
|
||||
ntStatus = pNtQueryObject(handle, ObjectTypeInformation, objTypeBuf.get(),
|
||||
objTypeBufLen, &objTypeBufLen);
|
||||
ntStatus = ::NtQueryObject(handle, ObjectTypeInformation, objTypeBuf.get(),
|
||||
objTypeBufLen, &objTypeBufLen);
|
||||
if (!NT_SUCCESS(ntStatus)) {
|
||||
// We don't have access to do this, assume this handle isn't relevant
|
||||
continue;
|
||||
}
|
||||
|
||||
auto objType =
|
||||
reinterpret_cast<PUBLIC_OBJECT_TYPE_INFORMATION*>(objTypeBuf.get());
|
||||
|
||||
nsDependentString objTypeName(objType->TypeName.Buffer,
|
||||
objType->TypeName.Length / sizeof(wchar_t));
|
||||
// Now we check whether the object's type name matches "Section"
|
||||
nsDependentSubstring objTypeName(objType->TypeName.Buffer,
|
||||
objType->TypeName.Length / sizeof(wchar_t));
|
||||
if (!objTypeName.Equals(NS_LITERAL_STRING("Section"))) {
|
||||
// Not a section, so we don't care about this handle anymore.
|
||||
nonSectionObjTypes.PutEntry(static_cast<uint32_t>(curHandle.mObjectTypeIndex));
|
||||
continue;
|
||||
}
|
||||
|
||||
// We have a section, save this handle's type code so that we can go
|
||||
// faster in future iterations.
|
||||
sSectionObjTypeIndex = Some(curHandle.mObjectTypeIndex);
|
||||
sectionObjTypeIndex = Some(curHandle.mObjectTypeIndex);
|
||||
}
|
||||
|
||||
// If we reached this point without needing to query the handle, then we
|
||||
// need to open it here so that we can query its name.
|
||||
lastPid = curHandle.mPid;
|
||||
// At this point we know that curHandle references a Section object.
|
||||
// Now we can do some actual tests on it.
|
||||
|
||||
if ((!process || !handle) &&
|
||||
!GetLocalObjectHandle((DWORD) curHandle.mPid, (HANDLE) curHandle.mHandle,
|
||||
process, handle)) {
|
||||
// We don't have access to do this, assume this handle isn't relevant
|
||||
continue;
|
||||
}
|
||||
if (ourPid != curHandle.mPid) {
|
||||
if (kernelObject && kernelObject.value() == curHandle.mObject) {
|
||||
// The kernel objects match -- we have found the remote pid!
|
||||
remotePid = Some(curHandle.mPid);
|
||||
break;
|
||||
}
|
||||
|
||||
// At this point, |handle| is a valid section handle. Let's try to find
|
||||
// out the name of its underlying object.
|
||||
ULONG objNameBufLen;
|
||||
ntStatus = pNtQueryObject(handle,
|
||||
(OBJECT_INFORMATION_CLASS)ObjectNameInformation,
|
||||
nullptr, 0, &objNameBufLen);
|
||||
if (ntStatus != STATUS_INFO_LENGTH_MISMATCH) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto objNameBuf = MakeUnique<char[]>(objNameBufLen);
|
||||
ntStatus = pNtQueryObject(handle,
|
||||
(OBJECT_INFORMATION_CLASS)ObjectNameInformation,
|
||||
objNameBuf.get(), objNameBufLen, &objNameBufLen);
|
||||
if (!NT_SUCCESS(ntStatus)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto objNameInfo = reinterpret_cast<OBJECT_NAME_INFORMATION*>(objNameBuf.get());
|
||||
if (!objNameInfo->mName.Length) {
|
||||
// This section is unnamed. We don't care about those.
|
||||
continue;
|
||||
}
|
||||
|
||||
nsDependentString objName(objNameInfo->mName.Buffer,
|
||||
objNameInfo->mName.Length / sizeof(wchar_t));
|
||||
|
||||
// Check to see if the section's name matches our expected name.
|
||||
if (!FindInReadable(kStrHookShmem, objName) ||
|
||||
!StringEndsWith(objName, partialSectionSuffix)) {
|
||||
// The names don't match, continue searching.
|
||||
continue;
|
||||
}
|
||||
|
||||
// At this point we have a section handle whose name matches the one that
|
||||
// we're looking for.
|
||||
|
||||
if (curHandle.mPid == ourPid) {
|
||||
// Our own process also has a handle to the section of interest. While we
|
||||
// don't want our own pid, this *does* give us an opportunity to speed up
|
||||
// future iterations by examining each handle for its kernel object (which
|
||||
// is the same for all processes) instead of searching by name.
|
||||
// An object that is not ours. Since we do not yet know which kernel
|
||||
// object we're interested in, we'll save the current object for later.
|
||||
objMap.Put(curHandle.mObject, curHandle.mPid);
|
||||
} else if (handle == section.get()) {
|
||||
// This is the file mapping that we opened above. We save this mObject
|
||||
// in order to compare to Section objects opened by other processes.
|
||||
kernelObject = Some(curHandle.mObject);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Bingo! We want this pid!
|
||||
remotePid = Some(static_cast<DWORD>(curHandle.mPid));
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (!kernelObject) {
|
||||
return Nothing();
|
||||
}
|
||||
|
||||
if (!remotePid) {
|
||||
// We found kernelObject *after* we saw the remote process's copy. Now we
|
||||
// must look it up in objMap.
|
||||
DWORD pid;
|
||||
if (objMap.Get(kernelObject.value(), &pid)) {
|
||||
remotePid = Some(pid);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!remotePid) {
|
||||
return Nothing();
|
||||
}
|
||||
|
|
|
@ -9,10 +9,22 @@
|
|||
|
||||
#include <winternl.h>
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef STATUS_INFO_LENGTH_MISMATCH
|
||||
#define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L)
|
||||
#endif
|
||||
|
||||
#ifndef STATUS_BUFFER_TOO_SMALL
|
||||
#define STATUS_BUFFER_TOO_SMALL ((NTSTATUS)0xC0000023L)
|
||||
#endif
|
||||
|
||||
#ifndef STATUS_MORE_ENTRIES
|
||||
#define STATUS_MORE_ENTRIES ((NTSTATUS)0x00000105L)
|
||||
#endif
|
||||
|
||||
enum UndocSystemInformationClass
|
||||
{
|
||||
SystemExtendedHandleInformation = 64
|
||||
|
@ -47,4 +59,36 @@ struct OBJECT_NAME_INFORMATION
|
|||
UNICODE_STRING mName;
|
||||
};
|
||||
|
||||
// The following declarations are documented on MSDN but are not included in
|
||||
// public user-mode headers.
|
||||
|
||||
enum DirectoryObjectAccessFlags
|
||||
{
|
||||
DIRECTORY_QUERY = 0x0001,
|
||||
DIRECTORY_TRAVERSE = 0x0002,
|
||||
DIRECTORY_CREATE_OBJECT = 0x0004,
|
||||
DIRECTORY_CREATE_SUBDIRECTORY = 0x0008,
|
||||
DIRECTORY_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED | 0x000F
|
||||
};
|
||||
|
||||
NTSTATUS WINAPI
|
||||
NtOpenDirectoryObject(PHANDLE aDirectoryHandle, ACCESS_MASK aDesiredAccess,
|
||||
POBJECT_ATTRIBUTES aObjectAttributes);
|
||||
|
||||
struct OBJECT_DIRECTORY_INFORMATION
|
||||
{
|
||||
UNICODE_STRING mName;
|
||||
UNICODE_STRING mTypeName;
|
||||
};
|
||||
|
||||
NTSTATUS WINAPI
|
||||
NtQueryDirectoryObject(HANDLE aDirectoryHandle, PVOID aOutBuffer,
|
||||
ULONG aBufferLength, BOOLEAN aReturnSingleEntry,
|
||||
BOOLEAN aRestartScan, PULONG aContext,
|
||||
PULONG aOutReturnLength);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // mozilla_NtUndoc_h
|
||||
|
|
|
@ -46,6 +46,10 @@ SOURCES += [
|
|||
'ServiceProvider.cpp',
|
||||
]
|
||||
|
||||
OS_LIBS += [
|
||||
'ntdll',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_XUL']:
|
||||
UNIFIED_SOURCES += [
|
||||
'XULListboxAccessibleWrap.cpp',
|
||||
|
|
|
@ -819,7 +819,16 @@ WindowHelper.prototype = {
|
|||
});
|
||||
}
|
||||
Services.ww.registerNotification(windowObserver);
|
||||
Services.ww.openWindow(null,
|
||||
|
||||
let browserWin = null;
|
||||
if (Services.appinfo.OS !== "Darwin") {
|
||||
// Retrieve the browser window so we can specify it as the parent
|
||||
// of the dialog to simulate the way the user opens the dialog
|
||||
// on Windows and Linux.
|
||||
browserWin = Services.wm.getMostRecentWindow("navigator:browser");
|
||||
}
|
||||
|
||||
Services.ww.openWindow(browserWin,
|
||||
"chrome://browser/content/sanitize.xul",
|
||||
"SanitizeDialog",
|
||||
"chrome,titlebar,dialog,centerscreen,modal",
|
||||
|
|
|
@ -2834,10 +2834,14 @@ nsDocShell::MaybeCreateInitialClientSource(nsIPrincipal* aPrincipal)
|
|||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
MOZ_ALWAYS_SUCCEEDS(
|
||||
NS_NewURI(getter_AddRefs(uri), NS_LITERAL_CSTRING("about:blank")));
|
||||
|
||||
// We're done if there is no parent controller or if this docshell
|
||||
// is not permitted to control for some reason.
|
||||
Maybe<ServiceWorkerDescriptor> controller(parentInner->GetController());
|
||||
if (controller.isNothing() || !ServiceWorkerAllowedToControlWindow(nullptr)) {
|
||||
if (controller.isNothing() || !ServiceWorkerAllowedToControlWindow(principal, uri)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -11354,6 +11358,20 @@ nsDocShell::ScrollToAnchor(bool aCurHasRef, bool aNewHasRef,
|
|||
nsIPresShell::SCROLL_SMOOTH_AUTO);
|
||||
}
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
char* str = ToNewCString(aNewHash);
|
||||
if (!str) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
nsUnescape(str);
|
||||
NS_ConvertUTF8toUTF16 utf16Str(str);
|
||||
if (!utf16Str.IsEmpty()) {
|
||||
rv = shell->GoToAnchor(utf16Str, scroll,
|
||||
nsIPresShell::SCROLL_SMOOTH_AUTO);
|
||||
}
|
||||
free(str);
|
||||
}
|
||||
|
||||
// Above will fail if the anchor name is not UTF-8. Need to
|
||||
// convert from document charset to unicode.
|
||||
if (NS_FAILED(rv)) {
|
||||
|
@ -14098,51 +14116,26 @@ nsDocShell::CanSetOriginAttributes()
|
|||
}
|
||||
|
||||
bool
|
||||
nsDocShell::ServiceWorkerAllowedToControlWindow(nsIURI* aURI)
|
||||
nsDocShell::ServiceWorkerAllowedToControlWindow(nsIPrincipal* aPrincipal,
|
||||
nsIURI* aURI)
|
||||
{
|
||||
// NOTE: Ideally this method would call one of the
|
||||
// nsContentUtils::StorageAllowed*() methods to determine if the
|
||||
// interception is allowed. Unfortunately we cannot safely do this
|
||||
// before the first window loads in the child process because the
|
||||
// permission manager might not have all its data yet. Therefore,
|
||||
// we use this somewhat lame alternate implementation here. Once
|
||||
// interception is moved to the parent process we should switch
|
||||
// to calling nsContentUtils::StorageAllowed*(). See bug 1428130.
|
||||
MOZ_ASSERT(aPrincipal);
|
||||
MOZ_ASSERT(aURI);
|
||||
|
||||
if (UsePrivateBrowsing() || mSandboxFlags) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t cookieBehavior = nsContentUtils::CookiesBehavior();
|
||||
uint32_t lifetimePolicy = nsContentUtils::CookiesLifetimePolicy();
|
||||
if (cookieBehavior == nsICookieService::BEHAVIOR_REJECT ||
|
||||
lifetimePolicy == nsICookieService::ACCEPT_SESSION) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!aURI || cookieBehavior == nsICookieService::BEHAVIOR_ACCEPT) {
|
||||
return true;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDocShellTreeItem> parent;
|
||||
GetSameTypeParent(getter_AddRefs(parent));
|
||||
nsCOMPtr<nsPIDOMWindowOuter> parentWindow = parent ? parent->GetWindow()
|
||||
: nullptr;
|
||||
if (parentWindow) {
|
||||
nsresult rv = NS_OK;
|
||||
nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil =
|
||||
do_GetService(THIRDPARTYUTIL_CONTRACTID, &rv);
|
||||
if (thirdPartyUtil) {
|
||||
bool isThirdPartyURI = true;
|
||||
rv = thirdPartyUtil->IsThirdPartyWindow(parentWindow, aURI,
|
||||
&isThirdPartyURI);
|
||||
if (NS_SUCCEEDED(rv) && isThirdPartyURI) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
nsPIDOMWindowOuter* parentOuter = parent ? parent->GetWindow() : nullptr;
|
||||
nsPIDOMWindowInner* parentInner =
|
||||
parentOuter ? parentOuter->GetCurrentInnerWindow() : nullptr;
|
||||
|
||||
return true;
|
||||
nsContentUtils::StorageAccess storage =
|
||||
nsContentUtils::StorageAllowedForNewWindow(aPrincipal, aURI, parentInner);
|
||||
|
||||
return storage == nsContentUtils::StorageAccess::eAllow;
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -14369,9 +14362,12 @@ nsDocShell::ShouldPrepareForIntercept(nsIURI* aURI, bool aIsNonSubresourceReques
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPrincipal> principal =
|
||||
BasePrincipal::CreateCodebasePrincipal(aURI, mOriginAttributes);
|
||||
|
||||
// For navigations, first check to see if we are allowed to control a
|
||||
// window with the given URL.
|
||||
if (!ServiceWorkerAllowedToControlWindow(aURI)) {
|
||||
if (!ServiceWorkerAllowedToControlWindow(principal, aURI)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -14382,8 +14378,6 @@ nsDocShell::ShouldPrepareForIntercept(nsIURI* aURI, bool aIsNonSubresourceReques
|
|||
|
||||
// We're allowed to control a window, so check with the ServiceWorkerManager
|
||||
// for a matching service worker.
|
||||
nsCOMPtr<nsIPrincipal> principal =
|
||||
BasePrincipal::CreateCodebasePrincipal(aURI, mOriginAttributes);
|
||||
*aShouldIntercept = swm->IsAvailable(principal, aURI);
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -792,10 +792,8 @@ private: // member functions
|
|||
// controlled. The caller must still consult either the parent controller
|
||||
// or the ServiceWorkerManager to determine if a service worker should
|
||||
// actually control the window.
|
||||
//
|
||||
// A nullptr URL is considered to be an about:blank window and will not
|
||||
// trigger 3rd party iframe checks.
|
||||
bool ServiceWorkerAllowedToControlWindow(nsIURI* aURI);
|
||||
bool ServiceWorkerAllowedToControlWindow(nsIPrincipal* aPrincipal,
|
||||
nsIURI* aURI);
|
||||
|
||||
// Return the ClientInfo for the initial about:blank window, if it exists
|
||||
// or we have speculatively created a ClientSource in
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
#include "nsMimeTypeArray.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/dom/BodyExtractor.h"
|
||||
#include "mozilla/dom/DesktopNotification.h"
|
||||
#include "mozilla/dom/FetchBinding.h"
|
||||
#include "mozilla/dom/File.h"
|
||||
#include "nsGeolocation.h"
|
||||
|
@ -195,7 +194,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Navigator)
|
|||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPlugins)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPermissions)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGeolocation)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNotification)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBatteryManager)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBatteryPromise)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mConnection)
|
||||
|
@ -238,11 +236,6 @@ Navigator::Invalidate()
|
|||
mGeolocation = nullptr;
|
||||
}
|
||||
|
||||
if (mNotification) {
|
||||
mNotification->Shutdown();
|
||||
mNotification = nullptr;
|
||||
}
|
||||
|
||||
if (mBatteryManager) {
|
||||
mBatteryManager->Shutdown();
|
||||
mBatteryManager = nullptr;
|
||||
|
@ -1316,22 +1309,6 @@ Navigator::MozGetUserMediaDevices(const MediaStreamConstraints& aConstraints,
|
|||
aInnerWindowID, aCallID);
|
||||
}
|
||||
|
||||
DesktopNotificationCenter*
|
||||
Navigator::GetMozNotification(ErrorResult& aRv)
|
||||
{
|
||||
if (mNotification) {
|
||||
return mNotification;
|
||||
}
|
||||
|
||||
if (!mWindow || !mWindow->GetDocShell()) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
mNotification = new DesktopNotificationCenter(mWindow);
|
||||
return mNotification;
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
// Navigator::nsINavigatorBattery
|
||||
//*****************************************************************************
|
||||
|
|
|
@ -59,7 +59,6 @@ class BatteryManager;
|
|||
|
||||
class Promise;
|
||||
|
||||
class DesktopNotificationCenter;
|
||||
class MozIdleObserver;
|
||||
class Gamepad;
|
||||
class GamepadServiceTest;
|
||||
|
@ -178,7 +177,6 @@ public:
|
|||
void AddIdleObserver(MozIdleObserver& aObserver, ErrorResult& aRv);
|
||||
void RemoveIdleObserver(MozIdleObserver& aObserver, ErrorResult& aRv);
|
||||
|
||||
DesktopNotificationCenter* GetMozNotification(ErrorResult& aRv);
|
||||
already_AddRefed<LegacyMozTCPSocket> MozTCPSocket();
|
||||
network::Connection* GetConnection(ErrorResult& aRv);
|
||||
MediaDevices* GetMediaDevices(ErrorResult& aRv);
|
||||
|
@ -275,7 +273,6 @@ private:
|
|||
RefPtr<nsPluginArray> mPlugins;
|
||||
RefPtr<Permissions> mPermissions;
|
||||
RefPtr<Geolocation> mGeolocation;
|
||||
RefPtr<DesktopNotificationCenter> mNotification;
|
||||
RefPtr<battery::BatteryManager> mBatteryManager;
|
||||
RefPtr<Promise> mBatteryPromise;
|
||||
RefPtr<network::Connection> mConnection;
|
||||
|
|
|
@ -8896,7 +8896,7 @@ nsContentUtils::StorageAllowedForWindow(nsPIDOMWindowInner* aWindow)
|
|||
{
|
||||
if (nsIDocument* document = aWindow->GetExtantDoc()) {
|
||||
nsCOMPtr<nsIPrincipal> principal = document->NodePrincipal();
|
||||
return InternalStorageAllowedForPrincipal(principal, aWindow);
|
||||
return InternalStorageAllowedForPrincipal(principal, aWindow, nullptr);
|
||||
}
|
||||
|
||||
return StorageAccess::eDeny;
|
||||
|
@ -8910,17 +8910,30 @@ nsContentUtils::StorageAllowedForDocument(nsIDocument* aDoc)
|
|||
|
||||
if (nsPIDOMWindowInner* inner = aDoc->GetInnerWindow()) {
|
||||
nsCOMPtr<nsIPrincipal> principal = aDoc->NodePrincipal();
|
||||
return InternalStorageAllowedForPrincipal(principal, inner);
|
||||
return InternalStorageAllowedForPrincipal(principal, inner, nullptr);
|
||||
}
|
||||
|
||||
return StorageAccess::eDeny;
|
||||
}
|
||||
|
||||
// static, public
|
||||
nsContentUtils::StorageAccess
|
||||
nsContentUtils::StorageAllowedForNewWindow(nsIPrincipal* aPrincipal,
|
||||
nsIURI* aURI,
|
||||
nsPIDOMWindowInner* aParent)
|
||||
{
|
||||
MOZ_ASSERT(aPrincipal);
|
||||
MOZ_ASSERT(aURI);
|
||||
// parent may be nullptr
|
||||
|
||||
return InternalStorageAllowedForPrincipal(aPrincipal, aParent, aURI);
|
||||
}
|
||||
|
||||
// static, public
|
||||
nsContentUtils::StorageAccess
|
||||
nsContentUtils::StorageAllowedForPrincipal(nsIPrincipal* aPrincipal)
|
||||
{
|
||||
return InternalStorageAllowedForPrincipal(aPrincipal, nullptr);
|
||||
return InternalStorageAllowedForPrincipal(aPrincipal, nullptr, nullptr);
|
||||
}
|
||||
|
||||
// static, private
|
||||
|
@ -8979,7 +8992,8 @@ nsContentUtils::GetCookieBehaviorForPrincipal(nsIPrincipal* aPrincipal,
|
|||
// static, private
|
||||
nsContentUtils::StorageAccess
|
||||
nsContentUtils::InternalStorageAllowedForPrincipal(nsIPrincipal* aPrincipal,
|
||||
nsPIDOMWindowInner* aWindow)
|
||||
nsPIDOMWindowInner* aWindow,
|
||||
nsIURI* aURI)
|
||||
{
|
||||
MOZ_ASSERT(aPrincipal);
|
||||
|
||||
|
@ -9049,9 +9063,11 @@ nsContentUtils::InternalStorageAllowedForPrincipal(nsIPrincipal* aPrincipal,
|
|||
// affected, which is desireable due to the lack of automated testing for about:
|
||||
// URIs with these preferences set, and the importance of the correct functioning
|
||||
// of these URIs even with custom preferences.
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
nsresult rv = aPrincipal->GetURI(getter_AddRefs(uri));
|
||||
if (NS_SUCCEEDED(rv) && uri) {
|
||||
nsCOMPtr<nsIURI> uri = aURI;
|
||||
if (!uri) {
|
||||
Unused << aPrincipal->GetURI(getter_AddRefs(uri));
|
||||
}
|
||||
if (uri) {
|
||||
bool isAbout = false;
|
||||
MOZ_ALWAYS_SUCCEEDS(uri->SchemeIs("about", &isAbout));
|
||||
if (isAbout) {
|
||||
|
@ -9073,7 +9089,7 @@ nsContentUtils::InternalStorageAllowedForPrincipal(nsIPrincipal* aPrincipal,
|
|||
|
||||
bool thirdPartyWindow = false;
|
||||
if (NS_SUCCEEDED(thirdPartyUtil->IsThirdPartyWindow(
|
||||
aWindow->GetOuterWindow(), nullptr, &thirdPartyWindow)) && thirdPartyWindow) {
|
||||
aWindow->GetOuterWindow(), aURI, &thirdPartyWindow)) && thirdPartyWindow) {
|
||||
// XXX For non-cookie forms of storage, we handle BEHAVIOR_LIMIT_FOREIGN by
|
||||
// simply rejecting the request to use the storage. In the future, if we
|
||||
// change the meaning of BEHAVIOR_LIMIT_FOREIGN to be one which makes sense
|
||||
|
|
|
@ -2913,16 +2913,6 @@ public:
|
|||
|
||||
static bool IsNonSubresourceRequest(nsIChannel* aChannel);
|
||||
|
||||
static uint32_t CookiesBehavior()
|
||||
{
|
||||
return sCookiesBehavior;
|
||||
}
|
||||
|
||||
static uint32_t CookiesLifetimePolicy()
|
||||
{
|
||||
return sCookiesLifetimePolicy;
|
||||
}
|
||||
|
||||
// The order of these entries matters, as we use std::min for total ordering
|
||||
// of permissions. Private Browsing is considered to be more limiting
|
||||
// then session scoping
|
||||
|
@ -2961,6 +2951,14 @@ public:
|
|||
*/
|
||||
static StorageAccess StorageAllowedForDocument(nsIDocument* aDoc);
|
||||
|
||||
/*
|
||||
* Checks if storage should be allowed for a new window with the given
|
||||
* principal, load URI, and parent.
|
||||
*/
|
||||
static StorageAccess StorageAllowedForNewWindow(nsIPrincipal* aPrincipal,
|
||||
nsIURI* aURI,
|
||||
nsPIDOMWindowInner* aParent);
|
||||
|
||||
/*
|
||||
* Checks if storage for the given principal is permitted by the user's
|
||||
* preferences. The caller is assumed to not be a third-party iframe.
|
||||
|
@ -3338,13 +3336,15 @@ private:
|
|||
* Checks if storage for a given principal is permitted by the user's
|
||||
* preferences. If aWindow is non-null, its principal must be passed as
|
||||
* aPrincipal, and the third-party iframe and sandboxing status of the window
|
||||
* are also checked.
|
||||
* are also checked. If aURI is non-null, then it is used as the comparison
|
||||
* against aWindow to determine if this is a third-party load.
|
||||
*
|
||||
* Used in the implementation of StorageAllowedForWindow and
|
||||
* StorageAllowedForPrincipal.
|
||||
*/
|
||||
static StorageAccess InternalStorageAllowedForPrincipal(nsIPrincipal* aPrincipal,
|
||||
nsPIDOMWindowInner* aWindow);
|
||||
nsPIDOMWindowInner* aWindow,
|
||||
nsIURI* aURI);
|
||||
|
||||
static nsINode* GetCommonAncestorHelper(nsINode* aNode1, nsINode* aNode2);
|
||||
static nsIContent* GetCommonFlattenedTreeAncestorHelper(nsIContent* aContent1,
|
||||
|
|
|
@ -10035,10 +10035,7 @@ nsDocument::ScrollToRef()
|
|||
rv = NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// If UTF-8 URI failed then try to assume the string as a
|
||||
// document's charset.
|
||||
if (NS_FAILED(rv)) {
|
||||
auto encoding = GetDocumentCharacterSet();
|
||||
char* tmpstr = ToNewCString(mScrollToRef);
|
||||
if (!tmpstr) {
|
||||
return;
|
||||
|
@ -10048,10 +10045,19 @@ nsDocument::ScrollToRef()
|
|||
unescapedRef.Assign(tmpstr);
|
||||
free(tmpstr);
|
||||
|
||||
rv = encoding->DecodeWithoutBOMHandling(unescapedRef, ref);
|
||||
NS_ConvertUTF8toUTF16 utf16Str(unescapedRef);
|
||||
if (!utf16Str.IsEmpty()) {
|
||||
rv = shell->GoToAnchor(utf16Str, mChangeScrollPosWhenScrollingToRef);
|
||||
}
|
||||
|
||||
if (NS_SUCCEEDED(rv) && !ref.IsEmpty()) {
|
||||
rv = shell->GoToAnchor(ref, mChangeScrollPosWhenScrollingToRef);
|
||||
// If UTF-8 URI failed then try to assume the string as a
|
||||
// document's charset.
|
||||
if (NS_FAILED(rv)) {
|
||||
const Encoding* encoding = GetDocumentCharacterSet();
|
||||
rv = encoding->DecodeWithoutBOMHandling(unescapedRef, ref);
|
||||
if (NS_SUCCEEDED(rv) && !ref.IsEmpty()) {
|
||||
rv = shell->GoToAnchor(ref, mChangeScrollPosWhenScrollingToRef);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
#include "gfxPattern.h"
|
||||
#include "gfxPrefs.h"
|
||||
#include "gfxUtils.h"
|
||||
#include "gfx/gl/MozFramebuffer.h"
|
||||
#include "MozFramebuffer.h"
|
||||
#include "GLBlitHelper.h"
|
||||
#include "GLContext.h"
|
||||
#include "GLContextProvider.h"
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
#include "WebGLContext.h"
|
||||
|
||||
#include "GeckoProfiler.h"
|
||||
#include "gfx/gl/MozFramebuffer.h"
|
||||
#include "MozFramebuffer.h"
|
||||
#include "GLContext.h"
|
||||
#include "mozilla/CheckedInt.h"
|
||||
#include "mozilla/UniquePtrExtensions.h"
|
||||
|
|
|
@ -1,332 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include "mozilla/dom/DesktopNotification.h"
|
||||
#include "mozilla/dom/DesktopNotificationBinding.h"
|
||||
#include "mozilla/dom/AppNotificationServiceOptionsBinding.h"
|
||||
#include "mozilla/dom/ToJSValue.h"
|
||||
#include "mozilla/EventStateManager.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsContentPermissionHelper.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
#include "mozilla/dom/PBrowserChild.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "nsGlobalWindow.h"
|
||||
#include "nsIScriptSecurityManager.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "PermissionMessageUtils.h"
|
||||
#include "nsILoadContext.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
/*
|
||||
* Simple Request
|
||||
*/
|
||||
class DesktopNotificationRequest : public nsIContentPermissionRequest
|
||||
, public Runnable
|
||||
{
|
||||
virtual ~DesktopNotificationRequest()
|
||||
{
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIContentPermissionRequester> mRequester;
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSICONTENTPERMISSIONREQUEST
|
||||
|
||||
explicit DesktopNotificationRequest(DesktopNotification* aNotification)
|
||||
: Runnable("dom::DesktopNotificationRequest")
|
||||
, mDesktopNotification(aNotification)
|
||||
{
|
||||
mRequester = new nsContentPermissionRequester(mDesktopNotification->GetOwner());
|
||||
}
|
||||
|
||||
NS_IMETHOD Run() override
|
||||
{
|
||||
nsCOMPtr<nsPIDOMWindowInner> window = mDesktopNotification->GetOwner();
|
||||
nsContentPermissionUtils::AskPermission(this, window);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
RefPtr<DesktopNotification> mDesktopNotification;
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
/* AlertServiceObserver */
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
NS_IMPL_ISUPPORTS(AlertServiceObserver, nsIObserver)
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
/* DesktopNotification */
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
uint32_t DesktopNotification::sCount = 0;
|
||||
|
||||
nsresult
|
||||
DesktopNotification::PostDesktopNotification()
|
||||
{
|
||||
if (!mObserver) {
|
||||
mObserver = new AlertServiceObserver(this);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIAlertsService> alerts = do_GetService("@mozilla.org/alerts-service;1");
|
||||
if (!alerts) {
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
// Generate a unique name (which will also be used as a cookie) because
|
||||
// the nsIAlertsService will coalesce notifications with the same name.
|
||||
// In the case of IPC, the parent process will use the cookie to map
|
||||
// to nsIObservers, thus cookies must be unique to differentiate observers.
|
||||
nsString uniqueName = NS_LITERAL_STRING("desktop-notification:");
|
||||
uniqueName.AppendInt(sCount++);
|
||||
nsCOMPtr<nsPIDOMWindowInner> owner = GetOwner();
|
||||
if (!owner) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
nsCOMPtr<nsIDocument> doc = owner->GetDoc();
|
||||
nsIPrincipal* principal = doc->NodePrincipal();
|
||||
nsCOMPtr<nsILoadContext> loadContext = doc->GetLoadContext();
|
||||
bool inPrivateBrowsing = loadContext && loadContext->UsePrivateBrowsing();
|
||||
nsCOMPtr<nsIAlertNotification> alert =
|
||||
do_CreateInstance(ALERT_NOTIFICATION_CONTRACTID);
|
||||
NS_ENSURE_TRUE(alert, NS_ERROR_FAILURE);
|
||||
nsresult rv = alert->Init(uniqueName, mIconURL, mTitle,
|
||||
mDescription,
|
||||
true,
|
||||
uniqueName,
|
||||
NS_LITERAL_STRING("auto"),
|
||||
EmptyString(),
|
||||
EmptyString(),
|
||||
principal,
|
||||
inPrivateBrowsing,
|
||||
false /* requireInteraction */);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return alerts->ShowAlert(alert, mObserver);
|
||||
}
|
||||
|
||||
DesktopNotification::DesktopNotification(const nsAString & title,
|
||||
const nsAString & description,
|
||||
const nsAString & iconURL,
|
||||
nsPIDOMWindowInner* aWindow,
|
||||
bool aIsHandlingUserInput,
|
||||
nsIPrincipal* principal)
|
||||
: DOMEventTargetHelper(aWindow)
|
||||
, mTitle(title)
|
||||
, mDescription(description)
|
||||
, mIconURL(iconURL)
|
||||
, mPrincipal(principal)
|
||||
, mIsHandlingUserInput(aIsHandlingUserInput)
|
||||
, mAllow(false)
|
||||
, mShowHasBeenCalled(false)
|
||||
{
|
||||
if (Preferences::GetBool("notification.disabled", false)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If we are in testing mode (running mochitests, for example)
|
||||
// and we are suppose to allow requests, then just post an allow event.
|
||||
if (Preferences::GetBool("notification.prompt.testing", false) &&
|
||||
Preferences::GetBool("notification.prompt.testing.allow", true)) {
|
||||
mAllow = true;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DesktopNotification::Init()
|
||||
{
|
||||
RefPtr<DesktopNotificationRequest> request = new DesktopNotificationRequest(this);
|
||||
|
||||
NS_DispatchToMainThread(request);
|
||||
}
|
||||
|
||||
DesktopNotification::~DesktopNotification()
|
||||
{
|
||||
if (mObserver) {
|
||||
mObserver->Disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DesktopNotification::DispatchNotificationEvent(const nsString& aName)
|
||||
{
|
||||
if (NS_FAILED(CheckInnerWindowCorrectness())) {
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<Event> event = NS_NewDOMEvent(this, nullptr, nullptr);
|
||||
// it doesn't bubble, and it isn't cancelable
|
||||
event->InitEvent(aName, false, false);
|
||||
event->SetTrusted(true);
|
||||
bool dummy;
|
||||
DispatchEvent(event, &dummy);
|
||||
}
|
||||
|
||||
nsresult
|
||||
DesktopNotification::SetAllow(bool aAllow)
|
||||
{
|
||||
mAllow = aAllow;
|
||||
|
||||
// if we have called Show() already, lets go ahead and post a notification
|
||||
if (mShowHasBeenCalled && aAllow) {
|
||||
return PostDesktopNotification();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
DesktopNotification::HandleAlertServiceNotification(const char *aTopic)
|
||||
{
|
||||
if (NS_FAILED(CheckInnerWindowCorrectness())) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!strcmp("alertclickcallback", aTopic)) {
|
||||
DispatchNotificationEvent(NS_LITERAL_STRING("click"));
|
||||
} else if (!strcmp("alertfinished", aTopic)) {
|
||||
DispatchNotificationEvent(NS_LITERAL_STRING("close"));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DesktopNotification::Show(ErrorResult& aRv)
|
||||
{
|
||||
mShowHasBeenCalled = true;
|
||||
|
||||
if (!mAllow) {
|
||||
return;
|
||||
}
|
||||
|
||||
aRv = PostDesktopNotification();
|
||||
}
|
||||
|
||||
JSObject*
|
||||
DesktopNotification::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return DesktopNotificationBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
/* DesktopNotificationCenter */
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(DesktopNotificationCenter)
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(DesktopNotificationCenter)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(DesktopNotificationCenter)
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DesktopNotificationCenter)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
already_AddRefed<DesktopNotification>
|
||||
DesktopNotificationCenter::CreateNotification(const nsAString& aTitle,
|
||||
const nsAString& aDescription,
|
||||
const nsAString& aIconURL)
|
||||
{
|
||||
MOZ_ASSERT(mOwner);
|
||||
|
||||
RefPtr<DesktopNotification> notification =
|
||||
new DesktopNotification(aTitle,
|
||||
aDescription,
|
||||
aIconURL,
|
||||
mOwner,
|
||||
EventStateManager::IsHandlingUserInput(),
|
||||
mPrincipal);
|
||||
notification->Init();
|
||||
return notification.forget();
|
||||
}
|
||||
|
||||
JSObject*
|
||||
DesktopNotificationCenter::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return DesktopNotificationCenterBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
/* DesktopNotificationRequest */
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED(DesktopNotificationRequest, Runnable,
|
||||
nsIContentPermissionRequest)
|
||||
|
||||
NS_IMETHODIMP
|
||||
DesktopNotificationRequest::GetPrincipal(nsIPrincipal * *aRequestingPrincipal)
|
||||
{
|
||||
if (!mDesktopNotification) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
NS_IF_ADDREF(*aRequestingPrincipal = mDesktopNotification->mPrincipal);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DesktopNotificationRequest::GetWindow(mozIDOMWindow** aRequestingWindow)
|
||||
{
|
||||
if (!mDesktopNotification) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
NS_IF_ADDREF(*aRequestingWindow = mDesktopNotification->GetOwner());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DesktopNotificationRequest::GetElement(nsIDOMElement * *aElement)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aElement);
|
||||
*aElement = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DesktopNotificationRequest::GetIsHandlingUserInput(bool *aIsHandlingUserInput)
|
||||
{
|
||||
*aIsHandlingUserInput = mDesktopNotification->mIsHandlingUserInput;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DesktopNotificationRequest::Cancel()
|
||||
{
|
||||
nsresult rv = mDesktopNotification->SetAllow(false);
|
||||
mDesktopNotification = nullptr;
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DesktopNotificationRequest::Allow(JS::HandleValue aChoices)
|
||||
{
|
||||
MOZ_ASSERT(aChoices.isUndefined());
|
||||
nsresult rv = mDesktopNotification->SetAllow(true);
|
||||
mDesktopNotification = nullptr;
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DesktopNotificationRequest::GetRequester(nsIContentPermissionRequester** aRequester)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aRequester);
|
||||
|
||||
nsCOMPtr<nsIContentPermissionRequester> requester = mRequester;
|
||||
requester.forget(aRequester);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DesktopNotificationRequest::GetTypes(nsIArray** aTypes)
|
||||
{
|
||||
nsTArray<nsString> emptyOptions;
|
||||
return nsContentPermissionUtils::CreatePermissionArray(NS_LITERAL_CSTRING("desktop-notification"),
|
||||
NS_LITERAL_CSTRING("unused"),
|
||||
emptyOptions,
|
||||
aTypes);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
|
@ -1,178 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_DesktopNotification_h
|
||||
#define mozilla_dom_DesktopNotification_h
|
||||
|
||||
#include "nsIPrincipal.h"
|
||||
#include "nsIAlertsService.h"
|
||||
#include "nsIContentPermissionPrompt.h"
|
||||
|
||||
#include "nsIObserver.h"
|
||||
#include "nsString.h"
|
||||
#include "nsWeakPtr.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsIDOMWindow.h"
|
||||
#include "nsIScriptObjectPrincipal.h"
|
||||
|
||||
#include "nsIDOMEvent.h"
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/DOMEventTargetHelper.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "nsWrapperCache.h"
|
||||
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class AlertServiceObserver;
|
||||
class DesktopNotification;
|
||||
|
||||
/*
|
||||
* DesktopNotificationCenter
|
||||
* Object hangs off of the navigator object and hands out DesktopNotification objects
|
||||
*/
|
||||
class DesktopNotificationCenter final : public nsISupports,
|
||||
public nsWrapperCache
|
||||
{
|
||||
public:
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(DesktopNotificationCenter)
|
||||
|
||||
explicit DesktopNotificationCenter(nsPIDOMWindowInner* aWindow)
|
||||
{
|
||||
MOZ_ASSERT(aWindow);
|
||||
mOwner = aWindow;
|
||||
|
||||
nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(aWindow);
|
||||
MOZ_ASSERT(sop);
|
||||
|
||||
mPrincipal = sop->GetPrincipal();
|
||||
MOZ_ASSERT(mPrincipal);
|
||||
}
|
||||
|
||||
void Shutdown() {
|
||||
mOwner = nullptr;
|
||||
}
|
||||
|
||||
nsPIDOMWindowInner* GetParentObject() const
|
||||
{
|
||||
return mOwner;
|
||||
}
|
||||
|
||||
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
already_AddRefed<DesktopNotification>
|
||||
CreateNotification(const nsAString& title,
|
||||
const nsAString& description,
|
||||
const nsAString& iconURL);
|
||||
|
||||
private:
|
||||
virtual ~DesktopNotificationCenter()
|
||||
{
|
||||
}
|
||||
|
||||
nsCOMPtr<nsPIDOMWindowInner> mOwner;
|
||||
nsCOMPtr<nsIPrincipal> mPrincipal;
|
||||
};
|
||||
|
||||
class DesktopNotificationRequest;
|
||||
|
||||
class DesktopNotification final : public DOMEventTargetHelper
|
||||
{
|
||||
friend class DesktopNotificationRequest;
|
||||
|
||||
public:
|
||||
|
||||
DesktopNotification(const nsAString& aTitle,
|
||||
const nsAString& aDescription,
|
||||
const nsAString& aIconURL,
|
||||
nsPIDOMWindowInner* aWindow,
|
||||
bool aIsHandlingUserInput,
|
||||
nsIPrincipal* principal);
|
||||
|
||||
virtual ~DesktopNotification();
|
||||
|
||||
void Init();
|
||||
|
||||
/*
|
||||
* PostDesktopNotification
|
||||
* Uses alert service to display a notification
|
||||
*/
|
||||
nsresult PostDesktopNotification();
|
||||
|
||||
nsresult SetAllow(bool aAllow);
|
||||
|
||||
/*
|
||||
* Creates and dispatches a dom event of type aName
|
||||
*/
|
||||
void DispatchNotificationEvent(const nsString& aName);
|
||||
|
||||
void HandleAlertServiceNotification(const char *aTopic);
|
||||
|
||||
// WebIDL
|
||||
|
||||
nsPIDOMWindowInner* GetParentObject() const
|
||||
{
|
||||
return GetOwner();
|
||||
}
|
||||
|
||||
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
void Show(ErrorResult& aRv);
|
||||
|
||||
IMPL_EVENT_HANDLER(click)
|
||||
IMPL_EVENT_HANDLER(close)
|
||||
|
||||
protected:
|
||||
|
||||
nsString mTitle;
|
||||
nsString mDescription;
|
||||
nsString mIconURL;
|
||||
|
||||
RefPtr<AlertServiceObserver> mObserver;
|
||||
nsCOMPtr<nsIPrincipal> mPrincipal;
|
||||
bool mIsHandlingUserInput;
|
||||
bool mAllow;
|
||||
bool mShowHasBeenCalled;
|
||||
|
||||
static uint32_t sCount;
|
||||
};
|
||||
|
||||
class AlertServiceObserver: public nsIObserver
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
explicit AlertServiceObserver(DesktopNotification* notification)
|
||||
: mNotification(notification) {}
|
||||
|
||||
void Disconnect() { mNotification = nullptr; }
|
||||
|
||||
NS_IMETHOD
|
||||
Observe(nsISupports* aSubject,
|
||||
const char* aTopic,
|
||||
const char16_t* aData) override
|
||||
{
|
||||
|
||||
// forward to parent
|
||||
if (mNotification) {
|
||||
mNotification->HandleAlertServiceNotification(aTopic);
|
||||
}
|
||||
return NS_OK;
|
||||
};
|
||||
|
||||
private:
|
||||
virtual ~AlertServiceObserver() {}
|
||||
|
||||
DesktopNotification* mNotification;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* mozilla_dom_DesktopNotification_h */
|
|
@ -17,13 +17,11 @@ EXTRA_JS_MODULES += [
|
|||
]
|
||||
|
||||
EXPORTS.mozilla.dom += [
|
||||
'DesktopNotification.h',
|
||||
'Notification.h',
|
||||
'NotificationEvent.h',
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'DesktopNotification.cpp',
|
||||
'Notification.cpp',
|
||||
'NotificationEvent.cpp',
|
||||
]
|
||||
|
@ -40,6 +38,8 @@ LOCAL_INCLUDES += [
|
|||
BROWSER_CHROME_MANIFESTS += ['test/browser/browser.ini']
|
||||
XPCSHELL_TESTS_MANIFESTS += ['test/unit/xpcshell.ini']
|
||||
MOCHITEST_MANIFESTS += ['test/mochitest/mochitest.ini']
|
||||
MOCHITEST_CHROME_MANIFESTS += ['test/chrome/chrome.ini']
|
||||
|
||||
|
||||
if CONFIG['CC_TYPE'] in ('clang', 'gcc'):
|
||||
CXXFLAGS += ['-Wno-error=shadow']
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
[test_notification_system_principal.xul]
|
|
@ -1,6 +1,7 @@
|
|||
[DEFAULT]
|
||||
|
||||
support-files =
|
||||
create_notification.html
|
||||
MockServices.js
|
||||
NotificationTest.js
|
||||
|
||||
|
@ -8,3 +9,4 @@ support-files =
|
|||
[test_notification_storage.html]
|
||||
[test_bug931307.html]
|
||||
skip-if = (os == 'android') # Bug 1258975 on android.
|
||||
[test_notification_tag.html]
|
|
@ -91,12 +91,11 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=782211
|
|||
// Load two frames with the same origin that create notification with the same tag.
|
||||
// Both pages should generate notifications with the same name, and thus the second
|
||||
// notification should replace the first.
|
||||
frames["sameDomain"].location.href = "http://test1.example.org:80/tests/dom/tests/mochitest/notification/create_notification.html";
|
||||
frames["anotherSameDomain"].location.href = "http://test1.example.org:80/tests/dom/tests/mochitest/notification/create_notification.html";
|
||||
|
||||
frames["sameDomain"].location.href = "http://test1.example.org:80/tests/dom/notification/test/mochitest/create_notification.html";
|
||||
frames["anotherSameDomain"].location.href = "http://test1.example.org:80/tests/dom/notification/test/mochitest/create_notification.html";
|
||||
// Load a frame with a different origin that creates a notification with the same tag.
|
||||
// The notification name should be different and thus no notifications should be replaced.
|
||||
frames["crossDomain"].location.href = "http://test2.example.org:80/tests/dom/tests/mochitest/notification/create_notification.html";
|
||||
frames["crossDomain"].location.href = "http://test2.example.org:80/tests/dom/notification/test/mochitest/create_notification.html";
|
||||
}
|
||||
|
||||
SpecialPowers.pushPrefEnv({'set': [["notification.prompt.testing", true],
|
|
@ -2385,12 +2385,12 @@ nsSVGElement::DidAnimateTransformList(int32_t aModType)
|
|||
transformAttr,
|
||||
aModType);
|
||||
// When script changes the 'transform' attribute, Element::SetAttrAndNotify
|
||||
// will call nsNodeUtills::AttributeChanged, under which
|
||||
// will call nsNodeUtils::AttributeChanged, under which
|
||||
// SVGTransformableElement::GetAttributeChangeHint will be called and an
|
||||
// appropriate change event posted to update our frame's overflow rects.
|
||||
// The SetAttrAndNotify doesn't happen for transform changes caused by
|
||||
// 'animateTransform' though (and sending out the mutation events that
|
||||
// nsNodeUtills::AttributeChanged dispatches would be inappropriate
|
||||
// nsNodeUtils::AttributeChanged dispatches would be inappropriate
|
||||
// anyway), so we need to post the change event ourself.
|
||||
nsChangeHint changeHint = GetAttributeChangeHint(transformAttr, aModType);
|
||||
if (changeHint) {
|
||||
|
|
|
@ -270,10 +270,6 @@ var interfaceNamesInGlobalScope =
|
|||
"DataTransferItemList",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"DelayNode",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"DesktopNotification",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"DesktopNotificationCenter",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"DeviceLightEvent",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
|
@ -1,70 +0,0 @@
|
|||
const MOCK_ALERTS_CID = SpecialPowers.wrap(SpecialPowers.Components).ID("{48068bc2-40ab-4904-8afd-4cdfb3a385f3}");
|
||||
const ALERTS_SERVICE_CONTRACT_ID = "@mozilla.org/alerts-service;1";
|
||||
|
||||
const MOCK_SYSTEM_ALERTS_CID = SpecialPowers.wrap(SpecialPowers.Components).ID("{e86d888c-e41b-4b78-9104-2f2742a532de}");
|
||||
const SYSTEM_ALERTS_SERVICE_CONTRACT_ID = "@mozilla.org/system-alerts-service;1";
|
||||
|
||||
var registrar = SpecialPowers.wrap(SpecialPowers.Components).manager.
|
||||
QueryInterface(SpecialPowers.Ci.nsIComponentRegistrar);
|
||||
|
||||
var mockAlertsService = {
|
||||
showAlert: function(alert, alertListener) {
|
||||
// probably should do this async....
|
||||
SpecialPowers.wrap(alertListener).observe(null, "alertshow", alert.cookie);
|
||||
|
||||
if (SpecialPowers.getBoolPref("notification.prompt.testing.click_on_notification") == true) {
|
||||
SpecialPowers.wrap(alertListener).observe(null, "alertclickcallback", alert.cookie);
|
||||
}
|
||||
|
||||
SpecialPowers.wrap(alertListener).observe(null, "alertfinished", alert.cookie);
|
||||
},
|
||||
|
||||
showAlertNotification: function(imageUrl, title, text, textClickable,
|
||||
cookie, alertListener, name, bidi,
|
||||
lang, data) {
|
||||
return this.showAlert({
|
||||
cookie: cookie
|
||||
}, alertListener);
|
||||
},
|
||||
|
||||
QueryInterface: function(aIID) {
|
||||
if (SpecialPowers.wrap(aIID).equals(SpecialPowers.Ci.nsISupports) ||
|
||||
SpecialPowers.wrap(aIID).equals(SpecialPowers.Ci.nsIAlertsService)) {
|
||||
return this;
|
||||
}
|
||||
throw SpecialPowers.Components.results.NS_ERROR_NO_INTERFACE;
|
||||
},
|
||||
|
||||
createInstance: function(aOuter, aIID) {
|
||||
if (aOuter != null) {
|
||||
throw SpecialPowers.Components.results.NS_ERROR_NO_AGGREGATION;
|
||||
}
|
||||
return this.QueryInterface(aIID);
|
||||
}
|
||||
};
|
||||
mockAlertsService = SpecialPowers.wrapCallbackObject(mockAlertsService);
|
||||
|
||||
function setup_notifications(allowPrompt, forceClick, callback) {
|
||||
SpecialPowers.pushPrefEnv({'set': [["notification.prompt.testing", true],
|
||||
["notification.prompt.testing.allow", allowPrompt],
|
||||
["notification.prompt.testing.click_on_notification", forceClick]]},
|
||||
callback);
|
||||
|
||||
registrar.registerFactory(MOCK_SYSTEM_ALERTS_CID, "system alerts service",
|
||||
SYSTEM_ALERTS_SERVICE_CONTRACT_ID,
|
||||
mockAlertsService);
|
||||
|
||||
registrar.registerFactory(MOCK_ALERTS_CID, "alerts service",
|
||||
ALERTS_SERVICE_CONTRACT_ID,
|
||||
mockAlertsService);
|
||||
}
|
||||
|
||||
function reset_notifications() {
|
||||
registrar.unregisterFactory(MOCK_SYSTEM_ALERTS_CID, mockAlertsService);
|
||||
registrar.unregisterFactory(MOCK_ALERTS_CID, mockAlertsService);
|
||||
}
|
||||
|
||||
function is_feature_enabled() {
|
||||
return navigator.mozNotification && SpecialPowers.getBoolPref("notification.feature.enabled");
|
||||
}
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=573588
|
||||
-->
|
||||
<head>
|
||||
<title>Basic functional test</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="notification_common.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=573588">Basic property tests</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
</div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
<script type="text/javascript">
|
||||
if (is_feature_enabled()) {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
function showNotifications() {
|
||||
ok(navigator.mozNotification, "test for notification.");
|
||||
|
||||
var notification = navigator.mozNotification.createNotification("test", "test");
|
||||
ok(notification, "test to ensure we can create a notification");
|
||||
|
||||
notification.onclose = function() {
|
||||
ok(true, "notification was display and is now closing");
|
||||
reset_notifications();
|
||||
SimpleTest.finish();
|
||||
};
|
||||
|
||||
notification.onclick = function() {
|
||||
ok(false, "Click should not have been called.");
|
||||
reset_notifications();
|
||||
SimpleTest.finish();
|
||||
};
|
||||
|
||||
notification.show();
|
||||
}
|
||||
|
||||
setup_notifications(true, false, showNotifications);
|
||||
} else {
|
||||
ok(true, "Desktop notifications not enabled.");
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,53 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=573588
|
||||
-->
|
||||
<head>
|
||||
<title>Basic functional test</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="notification_common.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=573588">Basic property tests</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
</div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
<script type="text/javascript">
|
||||
if (is_feature_enabled()) {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
var click_was_called = false;
|
||||
|
||||
function showNotifications() {
|
||||
ok(navigator.mozNotification, "test for notification.");
|
||||
|
||||
var notification = navigator.mozNotification.createNotification("test", "test");
|
||||
ok(notification, "test to ensure we can create a notification");
|
||||
|
||||
notification.onclose = function() {
|
||||
ok(true, "notification was display and is now closing");
|
||||
ok(click_was_called, "was notification clicked?");
|
||||
|
||||
reset_notifications();
|
||||
SimpleTest.finish();
|
||||
};
|
||||
|
||||
notification.onclick = function() {
|
||||
ok(true, "Click was called. Good.");
|
||||
click_was_called = true;
|
||||
};
|
||||
|
||||
notification.show();
|
||||
}
|
||||
|
||||
setup_notifications(true, true, showNotifications);
|
||||
} else {
|
||||
ok(true, "Desktop notifications not enabled.");
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,34 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=605309
|
||||
-->
|
||||
<head>
|
||||
<title>Test for leak when window closes</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="notification_common.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
|
||||
<script>
|
||||
if (is_feature_enabled()) {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
function boom()
|
||||
{
|
||||
document.documentElement.focus();
|
||||
var x = navigator.mozNotification;
|
||||
document.documentElement.addEventListener('', function(){x});
|
||||
ok(true, "load callback called");
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
window.addEventListener("load", boom);
|
||||
} else {
|
||||
ok(true, "Desktop notifications not enabled.");
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<p> I like to write tests </p>
|
||||
</body>
|
||||
</html>
|
|
@ -96,7 +96,7 @@ AssembleClientData(const nsAString& aOrigin, const nsAString& aTyp,
|
|||
static void
|
||||
RegisteredKeysToScopedCredentialList(const nsAString& aAppId,
|
||||
const nsTArray<RegisteredKey>& aKeys,
|
||||
nsTArray<WebAuthnScopedCredentialDescriptor>& aList)
|
||||
nsTArray<WebAuthnScopedCredential>& aList)
|
||||
{
|
||||
for (const RegisteredKey& key : aKeys) {
|
||||
// Check for required attributes
|
||||
|
@ -116,7 +116,7 @@ RegisteredKeysToScopedCredentialList(const nsAString& aAppId,
|
|||
continue;
|
||||
}
|
||||
|
||||
WebAuthnScopedCredentialDescriptor c;
|
||||
WebAuthnScopedCredential c;
|
||||
c.id() = keyHandle;
|
||||
aList.AppendElement(c);
|
||||
}
|
||||
|
@ -392,7 +392,7 @@ U2F::Register(const nsAString& aAppId,
|
|||
}
|
||||
|
||||
// Build the exclusion list, if any
|
||||
nsTArray<WebAuthnScopedCredentialDescriptor> excludeList;
|
||||
nsTArray<WebAuthnScopedCredential> excludeList;
|
||||
RegisteredKeysToScopedCredentialList(adjustedAppId, aRegisteredKeys,
|
||||
excludeList);
|
||||
|
||||
|
@ -540,7 +540,7 @@ U2F::Sign(const nsAString& aAppId,
|
|||
}
|
||||
|
||||
// Build the key list, if any
|
||||
nsTArray<WebAuthnScopedCredentialDescriptor> permittedList;
|
||||
nsTArray<WebAuthnScopedCredential> permittedList;
|
||||
RegisteredKeysToScopedCredentialList(adjustedAppId, aRegisteredKeys,
|
||||
permittedList);
|
||||
|
||||
|
@ -573,6 +573,7 @@ U2F::Sign(const nsAString& aAppId,
|
|||
clientDataHash,
|
||||
adjustedTimeoutMillis,
|
||||
permittedList,
|
||||
false, /* requireUserVerification */
|
||||
extensions);
|
||||
|
||||
MOZ_ASSERT(mTransaction.isNothing());
|
||||
|
|
|
@ -20,13 +20,14 @@ namespace mozilla {
|
|||
namespace dom {
|
||||
|
||||
struct WebAuthnAuthenticatorSelection {
|
||||
bool requireResidentKey;
|
||||
bool requireUserVerification;
|
||||
bool requirePlatformAttachment;
|
||||
bool requireResidentKey;
|
||||
bool requireUserVerification;
|
||||
bool requirePlatformAttachment;
|
||||
};
|
||||
|
||||
struct WebAuthnScopedCredentialDescriptor {
|
||||
struct WebAuthnScopedCredential {
|
||||
uint8_t[] id;
|
||||
uint8_t transports;
|
||||
};
|
||||
|
||||
struct WebAuthnExtension {
|
||||
|
@ -37,7 +38,7 @@ struct WebAuthnMakeCredentialInfo {
|
|||
uint8_t[] RpIdHash;
|
||||
uint8_t[] ClientDataHash;
|
||||
uint32_t TimeoutMS;
|
||||
WebAuthnScopedCredentialDescriptor[] ExcludeList;
|
||||
WebAuthnScopedCredential[] ExcludeList;
|
||||
WebAuthnExtension[] Extensions;
|
||||
WebAuthnAuthenticatorSelection AuthenticatorSelection;
|
||||
};
|
||||
|
@ -46,7 +47,8 @@ struct WebAuthnGetAssertionInfo {
|
|||
uint8_t[] RpIdHash;
|
||||
uint8_t[] ClientDataHash;
|
||||
uint32_t TimeoutMS;
|
||||
WebAuthnScopedCredentialDescriptor[] AllowList;
|
||||
WebAuthnScopedCredential[] AllowList;
|
||||
bool RequireUserVerification;
|
||||
WebAuthnExtension[] Extensions;
|
||||
};
|
||||
|
||||
|
|
|
@ -100,7 +100,7 @@ U2FHIDTokenManager::~U2FHIDTokenManager()
|
|||
// * attestation signature
|
||||
//
|
||||
RefPtr<U2FRegisterPromise>
|
||||
U2FHIDTokenManager::Register(const nsTArray<WebAuthnScopedCredentialDescriptor>& aDescriptors,
|
||||
U2FHIDTokenManager::Register(const nsTArray<WebAuthnScopedCredential>& aCredentials,
|
||||
const WebAuthnAuthenticatorSelection &aAuthenticatorSelection,
|
||||
const nsTArray<uint8_t>& aApplication,
|
||||
const nsTArray<uint8_t>& aChallenge,
|
||||
|
@ -130,7 +130,7 @@ U2FHIDTokenManager::Register(const nsTArray<WebAuthnScopedCredentialDescriptor>&
|
|||
aChallenge.Length(),
|
||||
aApplication.Elements(),
|
||||
aApplication.Length(),
|
||||
U2FKeyHandles(aDescriptors).Get());
|
||||
U2FKeyHandles(aCredentials).Get());
|
||||
|
||||
if (mTransactionId == 0) {
|
||||
return U2FRegisterPromise::CreateAndReject(NS_ERROR_DOM_UNKNOWN_ERR, __func__);
|
||||
|
@ -156,22 +156,31 @@ U2FHIDTokenManager::Register(const nsTArray<WebAuthnScopedCredentialDescriptor>&
|
|||
// * Signature
|
||||
//
|
||||
RefPtr<U2FSignPromise>
|
||||
U2FHIDTokenManager::Sign(const nsTArray<WebAuthnScopedCredentialDescriptor>& aDescriptors,
|
||||
U2FHIDTokenManager::Sign(const nsTArray<WebAuthnScopedCredential>& aCredentials,
|
||||
const nsTArray<uint8_t>& aApplication,
|
||||
const nsTArray<uint8_t>& aChallenge,
|
||||
bool aRequireUserVerification,
|
||||
uint32_t aTimeoutMS)
|
||||
{
|
||||
MOZ_ASSERT(NS_GetCurrentThread() == gPBackgroundThread);
|
||||
|
||||
uint64_t signFlags = 0;
|
||||
|
||||
// Set flags for credential requests.
|
||||
if (aRequireUserVerification) {
|
||||
signFlags |= U2F_FLAG_REQUIRE_USER_VERIFICATION;
|
||||
}
|
||||
|
||||
ClearPromises();
|
||||
mTransactionId = rust_u2f_mgr_sign(mU2FManager,
|
||||
signFlags,
|
||||
(uint64_t)aTimeoutMS,
|
||||
u2f_sign_callback,
|
||||
aChallenge.Elements(),
|
||||
aChallenge.Length(),
|
||||
aApplication.Elements(),
|
||||
aApplication.Length(),
|
||||
U2FKeyHandles(aDescriptors).Get());
|
||||
U2FKeyHandles(aCredentials).Get());
|
||||
if (mTransactionId == 0) {
|
||||
return U2FSignPromise::CreateAndReject(NS_ERROR_DOM_UNKNOWN_ERR, __func__);
|
||||
}
|
||||
|
|
|
@ -20,12 +20,15 @@ namespace dom {
|
|||
|
||||
class U2FKeyHandles {
|
||||
public:
|
||||
explicit U2FKeyHandles(const nsTArray<WebAuthnScopedCredentialDescriptor>& aDescriptors)
|
||||
explicit U2FKeyHandles(const nsTArray<WebAuthnScopedCredential>& aCredentials)
|
||||
{
|
||||
mKeyHandles = rust_u2f_khs_new();
|
||||
|
||||
for (auto desc: aDescriptors) {
|
||||
rust_u2f_khs_add(mKeyHandles, desc.id().Elements(), desc.id().Length());
|
||||
for (auto cred: aCredentials) {
|
||||
rust_u2f_khs_add(mKeyHandles,
|
||||
cred.id().Elements(),
|
||||
cred.id().Length(),
|
||||
cred.transports());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -91,16 +94,17 @@ public:
|
|||
explicit U2FHIDTokenManager();
|
||||
|
||||
virtual RefPtr<U2FRegisterPromise>
|
||||
Register(const nsTArray<WebAuthnScopedCredentialDescriptor>& aDescriptors,
|
||||
Register(const nsTArray<WebAuthnScopedCredential>& aCredentials,
|
||||
const WebAuthnAuthenticatorSelection &aAuthenticatorSelection,
|
||||
const nsTArray<uint8_t>& aApplication,
|
||||
const nsTArray<uint8_t>& aChallenge,
|
||||
uint32_t aTimeoutMS) override;
|
||||
|
||||
virtual RefPtr<U2FSignPromise>
|
||||
Sign(const nsTArray<WebAuthnScopedCredentialDescriptor>& aDescriptors,
|
||||
Sign(const nsTArray<WebAuthnScopedCredential>& aCredentials,
|
||||
const nsTArray<uint8_t>& aApplication,
|
||||
const nsTArray<uint8_t>& aChallenge,
|
||||
bool aRequireUserVerification,
|
||||
uint32_t aTimeoutMS) override;
|
||||
|
||||
void Cancel() override;
|
||||
|
|
|
@ -625,7 +625,7 @@ U2FSoftTokenManager::IsRegistered(const nsTArray<uint8_t>& aKeyHandle,
|
|||
// * attestation signature
|
||||
//
|
||||
RefPtr<U2FRegisterPromise>
|
||||
U2FSoftTokenManager::Register(const nsTArray<WebAuthnScopedCredentialDescriptor>& aDescriptors,
|
||||
U2FSoftTokenManager::Register(const nsTArray<WebAuthnScopedCredential>& aCredentials,
|
||||
const WebAuthnAuthenticatorSelection &aAuthenticatorSelection,
|
||||
const nsTArray<uint8_t>& aApplication,
|
||||
const nsTArray<uint8_t>& aChallenge,
|
||||
|
@ -652,9 +652,9 @@ U2FSoftTokenManager::Register(const nsTArray<WebAuthnScopedCredentialDescriptor>
|
|||
}
|
||||
|
||||
// Optional exclusion list.
|
||||
for (auto desc: aDescriptors) {
|
||||
for (auto cred: aCredentials) {
|
||||
bool isRegistered = false;
|
||||
nsresult rv = IsRegistered(desc.id(), aApplication, isRegistered);
|
||||
nsresult rv = IsRegistered(cred.id(), aApplication, isRegistered);
|
||||
if (NS_FAILED(rv)) {
|
||||
return U2FRegisterPromise::CreateAndReject(rv, __func__);
|
||||
}
|
||||
|
@ -758,9 +758,10 @@ U2FSoftTokenManager::Register(const nsTArray<WebAuthnScopedCredentialDescriptor>
|
|||
// * Signature
|
||||
//
|
||||
RefPtr<U2FSignPromise>
|
||||
U2FSoftTokenManager::Sign(const nsTArray<WebAuthnScopedCredentialDescriptor>& aDescriptors,
|
||||
U2FSoftTokenManager::Sign(const nsTArray<WebAuthnScopedCredential>& aCredentials,
|
||||
const nsTArray<uint8_t>& aApplication,
|
||||
const nsTArray<uint8_t>& aChallenge,
|
||||
bool aRequireUserVerification,
|
||||
uint32_t aTimeoutMS)
|
||||
{
|
||||
nsNSSShutDownPreventionLock locker;
|
||||
|
@ -768,12 +769,17 @@ U2FSoftTokenManager::Sign(const nsTArray<WebAuthnScopedCredentialDescriptor>& aD
|
|||
return U2FSignPromise::CreateAndReject(NS_ERROR_NOT_AVAILABLE, __func__);
|
||||
}
|
||||
|
||||
// The U2F softtoken doesn't support user verification.
|
||||
if (aRequireUserVerification) {
|
||||
return U2FSignPromise::CreateAndReject(NS_ERROR_DOM_NOT_ALLOWED_ERR, __func__);
|
||||
}
|
||||
|
||||
nsTArray<uint8_t> keyHandle;
|
||||
for (auto desc: aDescriptors) {
|
||||
for (auto cred: aCredentials) {
|
||||
bool isRegistered = false;
|
||||
nsresult rv = IsRegistered(desc.id(), aApplication, isRegistered);
|
||||
nsresult rv = IsRegistered(cred.id(), aApplication, isRegistered);
|
||||
if (NS_SUCCEEDED(rv) && isRegistered) {
|
||||
keyHandle.Assign(desc.id());
|
||||
keyHandle.Assign(cred.id());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,16 +26,17 @@ public:
|
|||
explicit U2FSoftTokenManager(uint32_t aCounter);
|
||||
|
||||
virtual RefPtr<U2FRegisterPromise>
|
||||
Register(const nsTArray<WebAuthnScopedCredentialDescriptor>& aDescriptors,
|
||||
Register(const nsTArray<WebAuthnScopedCredential>& aCredentials,
|
||||
const WebAuthnAuthenticatorSelection &aAuthenticatorSelection,
|
||||
const nsTArray<uint8_t>& aApplication,
|
||||
const nsTArray<uint8_t>& aChallenge,
|
||||
uint32_t aTimeoutMS) override;
|
||||
|
||||
virtual RefPtr<U2FSignPromise>
|
||||
Sign(const nsTArray<WebAuthnScopedCredentialDescriptor>& aDescriptors,
|
||||
Sign(const nsTArray<WebAuthnScopedCredential>& aCredentials,
|
||||
const nsTArray<uint8_t>& aApplication,
|
||||
const nsTArray<uint8_t>& aChallenge,
|
||||
bool aRequireUserVerification,
|
||||
uint32_t aTimeoutMS) override;
|
||||
|
||||
virtual void Cancel() override;
|
||||
|
|
|
@ -322,6 +322,7 @@ U2FTokenManager::Sign(PWebAuthnTransactionParent* aTransactionParent,
|
|||
mTokenManagerImpl->Sign(aTransactionInfo.AllowList(),
|
||||
aTransactionInfo.RpIdHash(),
|
||||
aTransactionInfo.ClientDataHash(),
|
||||
aTransactionInfo.RequireUserVerification(),
|
||||
aTransactionInfo.TimeoutMS())
|
||||
->Then(GetCurrentThreadSerialEventTarget(), __func__,
|
||||
[tid, startTime](U2FSignResult&& aResult) {
|
||||
|
|
|
@ -63,16 +63,17 @@ public:
|
|||
U2FTokenTransport() {}
|
||||
|
||||
virtual RefPtr<U2FRegisterPromise>
|
||||
Register(const nsTArray<WebAuthnScopedCredentialDescriptor>& aDescriptors,
|
||||
Register(const nsTArray<WebAuthnScopedCredential>& aCredentials,
|
||||
const WebAuthnAuthenticatorSelection &aAuthenticatorSelection,
|
||||
const nsTArray<uint8_t>& aApplication,
|
||||
const nsTArray<uint8_t>& aChallenge,
|
||||
uint32_t aTimeoutMS) = 0;
|
||||
|
||||
virtual RefPtr<U2FSignPromise>
|
||||
Sign(const nsTArray<WebAuthnScopedCredentialDescriptor>& aDescriptors,
|
||||
Sign(const nsTArray<WebAuthnScopedCredential>& aCredentials,
|
||||
const nsTArray<uint8_t>& aApplication,
|
||||
const nsTArray<uint8_t>& aChallenge,
|
||||
bool aRequireUserVerification,
|
||||
uint32_t aTimeoutMS) = 0;
|
||||
|
||||
virtual void Cancel() = 0;
|
||||
|
|
|
@ -361,9 +361,9 @@ WebAuthnManager::MakeCredential(const MakePublicKeyCredentialOptions& aOptions,
|
|||
return promise.forget();
|
||||
}
|
||||
|
||||
nsTArray<WebAuthnScopedCredentialDescriptor> excludeList;
|
||||
nsTArray<WebAuthnScopedCredential> excludeList;
|
||||
for (const auto& s: aOptions.mExcludeCredentials) {
|
||||
WebAuthnScopedCredentialDescriptor c;
|
||||
WebAuthnScopedCredential c;
|
||||
CryptoBuffer cb;
|
||||
cb.Assign(s.mId);
|
||||
c.id() = cb;
|
||||
|
@ -533,13 +533,33 @@ WebAuthnManager::GetAssertion(const PublicKeyCredentialRequestOptions& aOptions,
|
|||
return promise.forget();
|
||||
}
|
||||
|
||||
nsTArray<WebAuthnScopedCredentialDescriptor> allowList;
|
||||
nsTArray<WebAuthnScopedCredential> allowList;
|
||||
for (const auto& s: aOptions.mAllowCredentials) {
|
||||
WebAuthnScopedCredentialDescriptor c;
|
||||
CryptoBuffer cb;
|
||||
cb.Assign(s.mId);
|
||||
c.id() = cb;
|
||||
allowList.AppendElement(c);
|
||||
if (s.mType == PublicKeyCredentialType::Public_key) {
|
||||
WebAuthnScopedCredential c;
|
||||
CryptoBuffer cb;
|
||||
cb.Assign(s.mId);
|
||||
c.id() = cb;
|
||||
|
||||
// Serialize transports.
|
||||
if (s.mTransports.WasPassed()) {
|
||||
uint8_t transports = 0;
|
||||
for (const auto& t: s.mTransports.Value()) {
|
||||
if (t == AuthenticatorTransport::Usb) {
|
||||
transports |= U2F_AUTHENTICATOR_TRANSPORT_USB;
|
||||
}
|
||||
if (t == AuthenticatorTransport::Nfc) {
|
||||
transports |= U2F_AUTHENTICATOR_TRANSPORT_NFC;
|
||||
}
|
||||
if (t == AuthenticatorTransport::Ble) {
|
||||
transports |= U2F_AUTHENTICATOR_TRANSPORT_BLE;
|
||||
}
|
||||
}
|
||||
c.transports() = transports;
|
||||
}
|
||||
|
||||
allowList.AppendElement(c);
|
||||
}
|
||||
}
|
||||
|
||||
if (!MaybeCreateBackgroundActor()) {
|
||||
|
@ -547,6 +567,10 @@ WebAuthnManager::GetAssertion(const PublicKeyCredentialRequestOptions& aOptions,
|
|||
return promise.forget();
|
||||
}
|
||||
|
||||
// Does the RP require user verification?
|
||||
bool requireUserVerification =
|
||||
aOptions.mUserVerification == UserVerificationRequirement::Required;
|
||||
|
||||
// TODO: Add extension list building
|
||||
// If extensions was specified, process any extensions supported by this
|
||||
// client platform, to produce the extension data that needs to be sent to the
|
||||
|
@ -559,6 +583,7 @@ WebAuthnManager::GetAssertion(const PublicKeyCredentialRequestOptions& aOptions,
|
|||
clientDataHash,
|
||||
adjustedTimeout,
|
||||
allowList,
|
||||
requireUserVerification,
|
||||
extensions);
|
||||
|
||||
ListenForVisibilityEvents();
|
||||
|
|
|
@ -8,6 +8,7 @@ scheme = https
|
|||
|
||||
[test_webauthn_abort_signal.html]
|
||||
[test_webauthn_authenticator_selection.html]
|
||||
[test_webauthn_authenticator_transports.html]
|
||||
[test_webauthn_loopback.html]
|
||||
[test_webauthn_no_token.html]
|
||||
[test_webauthn_make_credential.html]
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
<h1>W3C Web Authentication - Authenticator Selection Criteria</h1>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1406462">Mozilla Bug 1406462</a>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1406467">Mozilla Bug 1406467</a>
|
||||
|
||||
<script class="testbody" type="text/javascript">
|
||||
"use strict";
|
||||
|
@ -27,6 +28,10 @@
|
|||
ok(aResult.toString().startsWith("NotAllowedError"), "Expecting a NotAllowedError, got " + aResult);
|
||||
}
|
||||
|
||||
// We store the credential of the first successful make credential
|
||||
// operation so we can use it for get assertion tests later.
|
||||
let gCredential;
|
||||
|
||||
add_task(() => {
|
||||
// Enable the softtoken.
|
||||
return SpecialPowers.pushPrefEnv({"set": [
|
||||
|
@ -50,10 +55,34 @@
|
|||
return navigator.credentials.create({publicKey});
|
||||
}
|
||||
|
||||
// Test success cases.
|
||||
// Start a new GetAssertion() request.
|
||||
function requestGetAssertion(userVerification) {
|
||||
let newCredential = {
|
||||
type: "public-key",
|
||||
id: gCredential,
|
||||
transports: ["usb"],
|
||||
};
|
||||
|
||||
let publicKey = {
|
||||
challenge: crypto.getRandomValues(new Uint8Array(16)),
|
||||
timeout: 5000, // the minimum timeout is actually 15 seconds
|
||||
rpId: document.domain,
|
||||
allowCredentials: [newCredential]
|
||||
};
|
||||
|
||||
if (userVerification) {
|
||||
publicKey.userVerification = userVerification;
|
||||
}
|
||||
|
||||
return navigator.credentials.get({publicKey});
|
||||
}
|
||||
|
||||
// Test success cases for make credential.
|
||||
add_task(async () => {
|
||||
// No selection criteria.
|
||||
await requestMakeCredential({})
|
||||
// Save the credential so we can use it for sign success tests.
|
||||
.then(res => gCredential = res.rawId)
|
||||
.then(arrivingHereIsGood)
|
||||
.catch(arrivingHereIsBad);
|
||||
|
||||
|
@ -78,7 +107,25 @@
|
|||
.catch(arrivingHereIsBad);
|
||||
});
|
||||
|
||||
// Test the failure cases.
|
||||
// Test success cases for get assertion.
|
||||
add_task(async () => {
|
||||
// No selection criteria.
|
||||
await requestGetAssertion()
|
||||
.then(arrivingHereIsGood)
|
||||
.catch(arrivingHereIsBad);
|
||||
|
||||
// Prefer user verification.
|
||||
await requestGetAssertion("preferred")
|
||||
.then(arrivingHereIsGood)
|
||||
.catch(arrivingHereIsBad);
|
||||
|
||||
// Discourage user verification.
|
||||
await requestGetAssertion("discouraged")
|
||||
.then(arrivingHereIsGood)
|
||||
.catch(arrivingHereIsBad);
|
||||
});
|
||||
|
||||
// Test failure cases for make credential.
|
||||
add_task(async () => {
|
||||
// Request a platform authenticator.
|
||||
await requestMakeCredential({authenticatorAttachment: "platform"})
|
||||
|
@ -95,6 +142,14 @@
|
|||
.then(arrivingHereIsBad)
|
||||
.catch(expectNotAllowedError);
|
||||
});
|
||||
|
||||
// Test failure cases for get assertion.
|
||||
add_task(async () => {
|
||||
// Require user verification.
|
||||
await requestGetAssertion("required")
|
||||
.then(arrivingHereIsBad)
|
||||
.catch(expectNotAllowedError);
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
|
|
@ -0,0 +1,150 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset=utf-8>
|
||||
<head>
|
||||
<title>W3C Web Authentication - Authenticator Transports</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<script type="text/javascript" src="u2futil.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h1>W3C Web Authentication - Authenticator Transports</h1>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1406467">Mozilla Bug 1406467</a>
|
||||
|
||||
<script class="testbody" type="text/javascript">
|
||||
"use strict";
|
||||
|
||||
function arrivingHereIsGood(aResult) {
|
||||
ok(true, "Good result! Received a: " + aResult);
|
||||
}
|
||||
|
||||
function arrivingHereIsBad(aResult) {
|
||||
ok(false, "Bad result! Received a: " + aResult);
|
||||
}
|
||||
|
||||
function expectNotAllowedError(aResult) {
|
||||
ok(aResult.toString().startsWith("NotAllowedError"), "Expecting a NotAllowedError, got " + aResult);
|
||||
}
|
||||
|
||||
// Store the credential of the first successful make credential
|
||||
// operation so we can use it to get assertions later.
|
||||
let gCredential;
|
||||
|
||||
add_task(() => {
|
||||
// Enable the softtoken.
|
||||
return SpecialPowers.pushPrefEnv({"set": [
|
||||
["security.webauth.webauthn", true],
|
||||
["security.webauth.webauthn_enable_softtoken", true],
|
||||
["security.webauth.webauthn_enable_usbtoken", false],
|
||||
]});
|
||||
});
|
||||
|
||||
// Start a new MakeCredential() request.
|
||||
function requestMakeCredential(excludeCredentials) {
|
||||
let publicKey = {
|
||||
rp: {id: document.domain, name: "none", icon: "none"},
|
||||
user: {id: new Uint8Array(), name: "none", icon: "none", displayName: "none"},
|
||||
challenge: crypto.getRandomValues(new Uint8Array(16)),
|
||||
timeout: 5000, // the minimum timeout is actually 15 seconds
|
||||
pubKeyCredParams: [{type: "public-key", alg: cose_alg_ECDSA_w_SHA256}],
|
||||
excludeCredentials
|
||||
};
|
||||
|
||||
return navigator.credentials.create({publicKey});
|
||||
}
|
||||
|
||||
// Start a new GetAssertion() request.
|
||||
function requestGetAssertion(allowCredentials) {
|
||||
let publicKey = {
|
||||
challenge: crypto.getRandomValues(new Uint8Array(16)),
|
||||
timeout: 5000, // the minimum timeout is actually 15 seconds
|
||||
rpId: document.domain,
|
||||
allowCredentials
|
||||
};
|
||||
|
||||
return navigator.credentials.get({publicKey});
|
||||
}
|
||||
|
||||
// Test make credential behavior.
|
||||
add_task(async () => {
|
||||
// Make a credential.
|
||||
await requestMakeCredential([])
|
||||
// Save the credential for later.
|
||||
.then(res => gCredential = res.rawId)
|
||||
.then(arrivingHereIsGood)
|
||||
.catch(arrivingHereIsBad);
|
||||
|
||||
// Pass a random credential to exclude.
|
||||
await requestMakeCredential([{
|
||||
type: "public-key",
|
||||
id: crypto.getRandomValues(new Uint8Array(16)),
|
||||
transports: ["usb"],
|
||||
}]).then(arrivingHereIsGood)
|
||||
.catch(arrivingHereIsBad);
|
||||
|
||||
// Pass gCredential with transport=usb.
|
||||
await requestMakeCredential([{
|
||||
type: "public-key",
|
||||
id: gCredential,
|
||||
transports: ["usb"],
|
||||
}]).then(arrivingHereIsBad)
|
||||
.catch(expectNotAllowedError);
|
||||
|
||||
// Pass gCredential with transport=nfc.
|
||||
// The softoken pretends to support all transports.
|
||||
await requestMakeCredential([{
|
||||
type: "public-key",
|
||||
id: gCredential,
|
||||
transports: ["nfc"],
|
||||
}]).then(arrivingHereIsBad)
|
||||
.catch(expectNotAllowedError);
|
||||
|
||||
// Pass gCredential with an empty transports list.
|
||||
await requestMakeCredential([{
|
||||
type: "public-key",
|
||||
id: gCredential,
|
||||
transports: [],
|
||||
}]).then(arrivingHereIsBad)
|
||||
.catch(expectNotAllowedError);
|
||||
});
|
||||
|
||||
// Test get assertion behavior.
|
||||
add_task(async () => {
|
||||
// Request an assertion for gCredential.
|
||||
await requestGetAssertion([{
|
||||
type: "public-key",
|
||||
id: gCredential,
|
||||
transports: ["usb"],
|
||||
}]).then(arrivingHereIsGood)
|
||||
.catch(arrivingHereIsBad);
|
||||
|
||||
// Request an assertion for a random credential.
|
||||
await requestGetAssertion([{
|
||||
type: "public-key",
|
||||
id: crypto.getRandomValues(new Uint8Array(16)),
|
||||
transports: ["usb"],
|
||||
}]).then(arrivingHereIsBad)
|
||||
.catch(expectNotAllowedError);
|
||||
|
||||
// Request an assertion for gCredential with transport=nfc.
|
||||
// The softoken pretends to support all transports.
|
||||
await requestGetAssertion([{
|
||||
type: "public-key",
|
||||
id: gCredential,
|
||||
transports: ["nfc"],
|
||||
}]).then(arrivingHereIsGood)
|
||||
.catch(arrivingHereIsBad);
|
||||
|
||||
// Request an assertion for gCredential with an empty transports list.
|
||||
await requestGetAssertion([{
|
||||
type: "public-key",
|
||||
id: gCredential,
|
||||
transports: [],
|
||||
}]).then(arrivingHereIsGood)
|
||||
.catch(arrivingHereIsBad);
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -9,7 +9,7 @@ use crypto::digest::Digest;
|
|||
use crypto::sha2::Sha256;
|
||||
use std::io;
|
||||
use std::sync::mpsc::channel;
|
||||
use u2fhid::{RegisterFlags, U2FManager};
|
||||
use u2fhid::{AuthenticatorTransports, KeyHandle, RegisterFlags, SignFlags, U2FManager};
|
||||
|
||||
extern crate log;
|
||||
extern crate env_logger;
|
||||
|
@ -66,11 +66,17 @@ fn main() {
|
|||
let register_data = rx.recv().unwrap();
|
||||
println!("Register result: {}", base64::encode(®ister_data));
|
||||
println!("Asking a security key to sign now, with the data from the register...");
|
||||
let key_handle = u2f_get_key_handle_from_register_response(®ister_data).unwrap();
|
||||
let credential = u2f_get_key_handle_from_register_response(®ister_data).unwrap();
|
||||
let key_handle = KeyHandle {
|
||||
credential,
|
||||
transports: AuthenticatorTransports::empty(),
|
||||
};
|
||||
|
||||
let flags = SignFlags::empty();
|
||||
let (tx, rx) = channel();
|
||||
manager
|
||||
.sign(
|
||||
flags,
|
||||
15_000,
|
||||
chall_bytes,
|
||||
app_bytes,
|
||||
|
|
|
@ -9,7 +9,7 @@ use std::{ptr, slice};
|
|||
|
||||
use U2FManager;
|
||||
|
||||
type U2FKeyHandles = Vec<Vec<u8>>;
|
||||
type U2FKeyHandles = Vec<::KeyHandle>;
|
||||
type U2FResult = HashMap<u8, Vec<u8>>;
|
||||
type U2FCallback = extern "C" fn(u64, *mut U2FResult);
|
||||
|
||||
|
@ -52,8 +52,12 @@ pub unsafe extern "C" fn rust_u2f_khs_add(
|
|||
khs: *mut U2FKeyHandles,
|
||||
key_handle_ptr: *const u8,
|
||||
key_handle_len: usize,
|
||||
transports: u8,
|
||||
) {
|
||||
(*khs).push(from_raw(key_handle_ptr, key_handle_len));
|
||||
(*khs).push(::KeyHandle {
|
||||
credential: from_raw(key_handle_ptr, key_handle_len),
|
||||
transports: ::AuthenticatorTransports::from_bits_truncate(transports),
|
||||
});
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
|
@ -156,6 +160,7 @@ pub unsafe extern "C" fn rust_u2f_mgr_register(
|
|||
#[no_mangle]
|
||||
pub unsafe extern "C" fn rust_u2f_mgr_sign(
|
||||
mgr: *mut U2FManager,
|
||||
flags: u64,
|
||||
timeout: u64,
|
||||
callback: U2FCallback,
|
||||
challenge_ptr: *const u8,
|
||||
|
@ -178,21 +183,29 @@ pub unsafe extern "C" fn rust_u2f_mgr_sign(
|
|||
return 0;
|
||||
}
|
||||
|
||||
let flags = ::SignFlags::from_bits_truncate(flags);
|
||||
let challenge = from_raw(challenge_ptr, challenge_len);
|
||||
let application = from_raw(application_ptr, application_len);
|
||||
let key_handles = (*khs).clone();
|
||||
|
||||
let tid = new_tid();
|
||||
let res = (*mgr).sign(timeout, challenge, application, key_handles, move |rv| {
|
||||
if let Ok((key_handle, signature)) = rv {
|
||||
let mut result = U2FResult::new();
|
||||
result.insert(RESBUF_ID_KEYHANDLE, key_handle);
|
||||
result.insert(RESBUF_ID_SIGNATURE, signature);
|
||||
callback(tid, Box::into_raw(Box::new(result)));
|
||||
} else {
|
||||
callback(tid, ptr::null_mut());
|
||||
};
|
||||
});
|
||||
let res = (*mgr).sign(
|
||||
flags,
|
||||
timeout,
|
||||
challenge,
|
||||
application,
|
||||
key_handles,
|
||||
move |rv| {
|
||||
if let Ok((key_handle, signature)) = rv {
|
||||
let mut result = U2FResult::new();
|
||||
result.insert(RESBUF_ID_KEYHANDLE, key_handle);
|
||||
result.insert(RESBUF_ID_SIGNATURE, signature);
|
||||
callback(tid, Box::into_raw(Box::new(result)));
|
||||
} else {
|
||||
callback(tid, ptr::null_mut());
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
if res.is_ok() { tid } else { 0 }
|
||||
}
|
||||
|
|
|
@ -56,6 +56,24 @@ bitflags! {
|
|||
const REQUIRE_PLATFORM_ATTACHMENT = 4;
|
||||
}
|
||||
}
|
||||
bitflags! {
|
||||
pub struct SignFlags: u64 {
|
||||
const REQUIRE_USER_VERIFICATION = 1;
|
||||
}
|
||||
}
|
||||
bitflags! {
|
||||
pub struct AuthenticatorTransports: u8 {
|
||||
const USB = 1;
|
||||
const NFC = 2;
|
||||
const BLE = 4;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct KeyHandle {
|
||||
pub credential: Vec<u8>,
|
||||
pub transports: AuthenticatorTransports,
|
||||
}
|
||||
|
||||
#[cfg(fuzzing)]
|
||||
pub use u2fprotocol::*;
|
||||
|
|
|
@ -17,14 +17,15 @@ enum QueueAction {
|
|||
timeout: u64,
|
||||
challenge: Vec<u8>,
|
||||
application: Vec<u8>,
|
||||
key_handles: Vec<Vec<u8>>,
|
||||
key_handles: Vec<::KeyHandle>,
|
||||
callback: OnceCallback<Vec<u8>>,
|
||||
},
|
||||
Sign {
|
||||
flags: ::SignFlags,
|
||||
timeout: u64,
|
||||
challenge: Vec<u8>,
|
||||
application: Vec<u8>,
|
||||
key_handles: Vec<Vec<u8>>,
|
||||
key_handles: Vec<::KeyHandle>,
|
||||
callback: OnceCallback<(Vec<u8>, Vec<u8>)>,
|
||||
},
|
||||
Cancel,
|
||||
|
@ -64,6 +65,7 @@ impl U2FManager {
|
|||
);
|
||||
}
|
||||
Ok(QueueAction::Sign {
|
||||
flags,
|
||||
timeout,
|
||||
challenge,
|
||||
application,
|
||||
|
@ -71,7 +73,14 @@ impl U2FManager {
|
|||
callback,
|
||||
}) => {
|
||||
// This must not block, otherwise we can't cancel.
|
||||
sm.sign(timeout, challenge, application, key_handles, callback);
|
||||
sm.sign(
|
||||
flags,
|
||||
timeout,
|
||||
challenge,
|
||||
application,
|
||||
key_handles,
|
||||
callback,
|
||||
);
|
||||
}
|
||||
Ok(QueueAction::Cancel) => {
|
||||
// Cancelling must block so that we don't start a new
|
||||
|
@ -101,7 +110,7 @@ impl U2FManager {
|
|||
timeout: u64,
|
||||
challenge: Vec<u8>,
|
||||
application: Vec<u8>,
|
||||
key_handles: Vec<Vec<u8>>,
|
||||
key_handles: Vec<::KeyHandle>,
|
||||
callback: F,
|
||||
) -> io::Result<()>
|
||||
where
|
||||
|
@ -116,7 +125,7 @@ impl U2FManager {
|
|||
}
|
||||
|
||||
for key_handle in &key_handles {
|
||||
if key_handle.len() > 256 {
|
||||
if key_handle.credential.len() > 256 {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidInput,
|
||||
"Key handle too large",
|
||||
|
@ -138,10 +147,11 @@ impl U2FManager {
|
|||
|
||||
pub fn sign<F>(
|
||||
&self,
|
||||
flags: ::SignFlags,
|
||||
timeout: u64,
|
||||
challenge: Vec<u8>,
|
||||
application: Vec<u8>,
|
||||
key_handles: Vec<Vec<u8>>,
|
||||
key_handles: Vec<::KeyHandle>,
|
||||
callback: F,
|
||||
) -> io::Result<()>
|
||||
where
|
||||
|
@ -163,7 +173,7 @@ impl U2FManager {
|
|||
}
|
||||
|
||||
for key_handle in &key_handles {
|
||||
if key_handle.len() > 256 {
|
||||
if key_handle.credential.len() > 256 {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidInput,
|
||||
"Key handle too large",
|
||||
|
@ -173,6 +183,7 @@ impl U2FManager {
|
|||
|
||||
let callback = OnceCallback::new(callback);
|
||||
let action = QueueAction::Sign {
|
||||
flags,
|
||||
timeout,
|
||||
challenge,
|
||||
application,
|
||||
|
|
|
@ -10,6 +10,10 @@ use std::time::Duration;
|
|||
use util::{io_err, OnceCallback};
|
||||
use u2fprotocol::{u2f_init_device, u2f_is_keyhandle_valid, u2f_register, u2f_sign};
|
||||
|
||||
fn is_valid_transport(transports: ::AuthenticatorTransports) -> bool {
|
||||
transports.is_empty() || transports.contains(::AuthenticatorTransports::USB)
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct StateMachine {
|
||||
transaction: Option<Transaction>,
|
||||
|
@ -26,7 +30,7 @@ impl StateMachine {
|
|||
timeout: u64,
|
||||
challenge: Vec<u8>,
|
||||
application: Vec<u8>,
|
||||
key_handles: Vec<Vec<u8>>,
|
||||
key_handles: Vec<::KeyHandle>,
|
||||
callback: OnceCallback<Vec<u8>>,
|
||||
) {
|
||||
// Abort any prior register/sign calls.
|
||||
|
@ -60,8 +64,9 @@ impl StateMachine {
|
|||
// Iterate the exclude list and see if there are any matches.
|
||||
// Abort the state machine if we found a valid key handle.
|
||||
if key_handles.iter().any(|key_handle| {
|
||||
u2f_is_keyhandle_valid(dev, &challenge, &application, key_handle)
|
||||
.unwrap_or(false) /* no match on failure */
|
||||
is_valid_transport(key_handle.transports) &&
|
||||
u2f_is_keyhandle_valid(dev, &challenge, &application, &key_handle.credential)
|
||||
.unwrap_or(false) /* no match on failure */
|
||||
})
|
||||
{
|
||||
return;
|
||||
|
@ -85,10 +90,11 @@ impl StateMachine {
|
|||
|
||||
pub fn sign(
|
||||
&mut self,
|
||||
flags: ::SignFlags,
|
||||
timeout: u64,
|
||||
challenge: Vec<u8>,
|
||||
application: Vec<u8>,
|
||||
key_handles: Vec<Vec<u8>>,
|
||||
key_handles: Vec<::KeyHandle>,
|
||||
callback: OnceCallback<(Vec<u8>, Vec<u8>)>,
|
||||
) {
|
||||
// Abort any prior register/sign calls.
|
||||
|
@ -108,15 +114,38 @@ impl StateMachine {
|
|||
return;
|
||||
}
|
||||
|
||||
// We currently don't support user verification because we can't
|
||||
// ask tokens whether they do support that. If the flag is set,
|
||||
// ignore all tokens for now.
|
||||
//
|
||||
// Technically, this is a ConstraintError because we shouldn't talk
|
||||
// to this authenticator in the first place. But the result is the
|
||||
// same anyway.
|
||||
if !flags.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Find all matching key handles.
|
||||
let key_handles = key_handles
|
||||
.iter()
|
||||
.filter(|key_handle| {
|
||||
u2f_is_keyhandle_valid(dev, &challenge, &application, key_handle)
|
||||
u2f_is_keyhandle_valid(dev, &challenge, &application, &key_handle.credential)
|
||||
.unwrap_or(false) /* no match on failure */
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// Aggregate distinct transports from all given credentials.
|
||||
let transports = key_handles.iter().fold(
|
||||
::AuthenticatorTransports::empty(),
|
||||
|t, k| t | k.transports,
|
||||
);
|
||||
|
||||
// We currently only support USB. If the RP specifies transports
|
||||
// and doesn't include USB it's probably lying.
|
||||
if !is_valid_transport(transports) {
|
||||
return;
|
||||
}
|
||||
|
||||
while alive() {
|
||||
// If the device matches none of the given key handles
|
||||
// then just make it blink with bogus data.
|
||||
|
@ -129,8 +158,14 @@ impl StateMachine {
|
|||
} else {
|
||||
// Otherwise, try to sign.
|
||||
for key_handle in &key_handles {
|
||||
if let Ok(bytes) = u2f_sign(dev, &challenge, &application, key_handle) {
|
||||
callback.call(Ok((key_handle.to_vec(), bytes)));
|
||||
if let Ok(bytes) = u2f_sign(
|
||||
dev,
|
||||
&challenge,
|
||||
&application,
|
||||
&key_handle.credential,
|
||||
)
|
||||
{
|
||||
callback.call(Ok((key_handle.credential.clone(), bytes)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,10 @@ const uint64_t U2F_FLAG_REQUIRE_RESIDENT_KEY = 1;
|
|||
const uint64_t U2F_FLAG_REQUIRE_USER_VERIFICATION = 2;
|
||||
const uint64_t U2F_FLAG_REQUIRE_PLATFORM_ATTACHMENT = 4;
|
||||
|
||||
const uint8_t U2F_AUTHENTICATOR_TRANSPORT_USB = 1;
|
||||
const uint8_t U2F_AUTHENTICATOR_TRANSPORT_NFC = 2;
|
||||
const uint8_t U2F_AUTHENTICATOR_TRANSPORT_BLE = 4;
|
||||
|
||||
// NOTE: Preconditions
|
||||
// * All rust_u2f_mgr* pointers must refer to pointers which are returned
|
||||
// by rust_u2f_mgr_new, and must be freed with rust_u2f_mgr_free.
|
||||
|
@ -56,6 +60,7 @@ uint64_t rust_u2f_mgr_register(rust_u2f_manager* mgr,
|
|||
const rust_u2f_key_handles* khs);
|
||||
|
||||
uint64_t rust_u2f_mgr_sign(rust_u2f_manager* mgr,
|
||||
uint64_t flags,
|
||||
uint64_t timeout,
|
||||
rust_u2f_callback,
|
||||
const uint8_t* challenge_ptr,
|
||||
|
@ -72,7 +77,8 @@ uint64_t rust_u2f_mgr_cancel(rust_u2f_manager* mgr);
|
|||
rust_u2f_key_handles* rust_u2f_khs_new();
|
||||
void rust_u2f_khs_add(rust_u2f_key_handles* khs,
|
||||
const uint8_t* key_handle,
|
||||
size_t key_handle_len);
|
||||
size_t key_handle_len,
|
||||
uint8_t transports);
|
||||
/* unsafe */ void rust_u2f_khs_free(rust_u2f_key_handles* khs);
|
||||
|
||||
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
interface MozObserver;
|
||||
|
||||
[HeaderFile="mozilla/dom/DesktopNotification.h"]
|
||||
interface DesktopNotificationCenter
|
||||
{
|
||||
[NewObject]
|
||||
DesktopNotification createNotification(DOMString title,
|
||||
DOMString description,
|
||||
optional DOMString iconURL = "");
|
||||
};
|
||||
|
||||
interface DesktopNotification : EventTarget
|
||||
{
|
||||
[Throws]
|
||||
void show();
|
||||
|
||||
attribute EventHandler onclick;
|
||||
|
||||
attribute EventHandler onclose;
|
||||
};
|
|
@ -200,12 +200,6 @@ partial interface Navigator {
|
|||
void removeIdleObserver(MozIdleObserver aIdleObserver);
|
||||
};
|
||||
|
||||
// nsIDOMNavigatorDesktopNotification
|
||||
partial interface Navigator {
|
||||
[Throws, Pref="notification.feature.enabled", UnsafeInPrerendering]
|
||||
readonly attribute DesktopNotificationCenter mozNotification;
|
||||
};
|
||||
|
||||
// NetworkInformation
|
||||
partial interface Navigator {
|
||||
[Throws, Pref="dom.netinfo.enabled"]
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* The origin of this IDL file is
|
||||
* https://www.w3.org/TR/webauthn/
|
||||
* https://w3c.github.io/webauthn/
|
||||
*/
|
||||
|
||||
/***** Interfaces to Data *****/
|
||||
|
@ -94,6 +94,7 @@ dictionary PublicKeyCredentialRequestOptions {
|
|||
unsigned long timeout;
|
||||
USVString rpId;
|
||||
sequence<PublicKeyCredentialDescriptor> allowCredentials = [];
|
||||
UserVerificationRequirement userVerification = "preferred";
|
||||
// Extensions are not supported yet.
|
||||
// AuthenticationExtensions extensions; // Add in Bug 1406458
|
||||
};
|
||||
|
|
|
@ -97,9 +97,6 @@ with Files("DelayNode.webidl"):
|
|||
with Files("DynamicsCompressorNode.webidl"):
|
||||
BUG_COMPONENT = ("Core", "Web Audio")
|
||||
|
||||
with Files("DesktopNotification.webidl"):
|
||||
BUG_COMPONENT = ("Toolkit", "Notifications and Alerts")
|
||||
|
||||
with Files("FakePluginTagInit.webidl"):
|
||||
BUG_COMPONENT = ("Core", "Plug-ins")
|
||||
|
||||
|
@ -478,7 +475,6 @@ WEBIDL_FILES = [
|
|||
'DecoderDoctorNotification.webidl',
|
||||
'DedicatedWorkerGlobalScope.webidl',
|
||||
'DelayNode.webidl',
|
||||
'DesktopNotification.webidl',
|
||||
'DeviceMotionEvent.webidl',
|
||||
'Directory.webidl',
|
||||
'Document.webidl',
|
||||
|
|
|
@ -9,6 +9,7 @@ support-files =
|
|||
file_userContextId_openWindow.js
|
||||
force_refresh_browser_worker.js
|
||||
empty.html
|
||||
empty.js
|
||||
server_multie10s_update.sjs
|
||||
|
||||
[browser_devtools_serviceworker_interception.js]
|
||||
|
@ -16,5 +17,6 @@ support-files =
|
|||
[browser_download.js]
|
||||
[browser_multie10s_update.js]
|
||||
skip-if = !e10s || os != "win" # Bug 1404914
|
||||
[browser_storage_permission.js]
|
||||
[browser_userContextId_openWindow.js]
|
||||
skip-if = !e10s
|
||||
|
|
|
@ -0,0 +1,123 @@
|
|||
"use strict";
|
||||
|
||||
const { interfaces: Ci } = Components;
|
||||
|
||||
const BASE_URI = "http://mochi.test:8888/browser/dom/workers/test/serviceworkers/";
|
||||
const PAGE_URI = BASE_URI + "empty.html";
|
||||
const SCOPE = PAGE_URI + "?storage_permission";
|
||||
const SW_SCRIPT = BASE_URI + "empty.js";
|
||||
|
||||
|
||||
add_task(async function setup() {
|
||||
await SpecialPowers.pushPrefEnv({"set": [
|
||||
["dom.serviceWorkers.enabled", true],
|
||||
["dom.serviceWorkers.testing.enabled", true],
|
||||
]});
|
||||
|
||||
let tab = BrowserTestUtils.addTab(gBrowser, PAGE_URI);
|
||||
let browser = gBrowser.getBrowserForTab(tab);
|
||||
await BrowserTestUtils.browserLoaded(browser);
|
||||
|
||||
await ContentTask.spawn(browser, { script: SW_SCRIPT, scope: SCOPE },
|
||||
async function(opts) {
|
||||
let reg = await content.navigator.serviceWorker.register(opts.script,
|
||||
{ scope: opts.scope });
|
||||
let worker = reg.installing || reg.waiting || reg.active;
|
||||
await new Promise(resolve => {
|
||||
if (worker.state === "activated") {
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
worker.addEventListener("statechange", function onStateChange() {
|
||||
if (worker.state === "activated") {
|
||||
worker.removeEventListener("statechange", onStateChange);
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
await BrowserTestUtils.removeTab(tab);
|
||||
});
|
||||
|
||||
add_task(async function test_allow_permission() {
|
||||
Services.perms.add(Services.io.newURI(PAGE_URI), "cookie",
|
||||
Ci.nsICookiePermission.ACCESS_ALLOW);
|
||||
|
||||
let tab = BrowserTestUtils.addTab(gBrowser, SCOPE);
|
||||
let browser = gBrowser.getBrowserForTab(tab);
|
||||
await BrowserTestUtils.browserLoaded(browser);
|
||||
|
||||
let controller = await ContentTask.spawn(browser, null, async function() {
|
||||
return content.navigator.serviceWorker.controller;
|
||||
});
|
||||
|
||||
ok(!!controller, "page should be controlled with storage allowed");
|
||||
|
||||
await BrowserTestUtils.removeTab(tab);
|
||||
});
|
||||
|
||||
add_task(async function test_deny_permission() {
|
||||
Services.perms.add(Services.io.newURI(PAGE_URI), "cookie",
|
||||
Ci.nsICookiePermission.ACCESS_DENY);
|
||||
|
||||
let tab = BrowserTestUtils.addTab(gBrowser, SCOPE);
|
||||
let browser = gBrowser.getBrowserForTab(tab);
|
||||
await BrowserTestUtils.browserLoaded(browser);
|
||||
|
||||
let controller = await ContentTask.spawn(browser, null, async function() {
|
||||
return content.navigator.serviceWorker.controller;
|
||||
});
|
||||
|
||||
is(controller, null, "page should be not controlled with storage denied");
|
||||
|
||||
await BrowserTestUtils.removeTab(tab);
|
||||
Services.perms.remove(Services.io.newURI(PAGE_URI), "cookie");
|
||||
});
|
||||
|
||||
add_task(async function test_session_permission() {
|
||||
Services.perms.add(Services.io.newURI(PAGE_URI), "cookie",
|
||||
Ci.nsICookiePermission.ACCESS_SESSION);
|
||||
|
||||
let tab = BrowserTestUtils.addTab(gBrowser, SCOPE);
|
||||
let browser = gBrowser.getBrowserForTab(tab);
|
||||
await BrowserTestUtils.browserLoaded(browser);
|
||||
|
||||
let controller = await ContentTask.spawn(browser, null, async function() {
|
||||
return content.navigator.serviceWorker.controller;
|
||||
});
|
||||
|
||||
is(controller, null, "page should be not controlled with session storage");
|
||||
|
||||
await BrowserTestUtils.removeTab(tab);
|
||||
Services.perms.remove(Services.io.newURI(PAGE_URI), "cookie");
|
||||
});
|
||||
|
||||
add_task(async function cleanup() {
|
||||
Services.perms.remove(Services.io.newURI(PAGE_URI), "cookie");
|
||||
|
||||
let tab = BrowserTestUtils.addTab(gBrowser, PAGE_URI);
|
||||
let browser = gBrowser.getBrowserForTab(tab);
|
||||
await BrowserTestUtils.browserLoaded(browser);
|
||||
|
||||
await ContentTask.spawn(browser, SCOPE, async function(uri) {
|
||||
let reg = await content.navigator.serviceWorker.getRegistration(uri);
|
||||
let worker = reg.active;
|
||||
await reg.unregister();
|
||||
await new Promise(resolve => {
|
||||
if (worker.state === "redundant") {
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
worker.addEventListener("statechange", function onStateChange() {
|
||||
if (worker.state === "redundant") {
|
||||
worker.removeEventListener("statechange", onStateChange);
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
await BrowserTestUtils.removeTab(tab);
|
||||
});
|
|
@ -1,12 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
|
||||
|
||||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
xmlns:html="http://www.w3.org/1999/xhtml"
|
||||
title="Textbox tests">
|
||||
|
||||
<script type="text/javascript" src="platform.js"/>
|
||||
|
||||
<textbox type="timed"/>
|
||||
|
||||
</window>
|
|
@ -10,7 +10,6 @@ fails-if(Android) skip-if(winWidget) == emptytextbox-1.xul emptytextbox-ref.xul
|
|||
fails-if(Android) skip-if(winWidget) == emptytextbox-2.xul emptytextbox-ref.xul # Windows: bug 1239170
|
||||
!= emptytextbox-3.xul emptytextbox-ref.xul
|
||||
!= emptytextbox-4.xul emptytextbox-ref.xul
|
||||
fails-if(Android) skip-if(winWidget) == emptytextbox-5.xul emptytextbox-ref.xul # Windows: bug 1239170
|
||||
# There is no way to simulate a number textbox in windows XP/Vista/7 default theme using CSS.
|
||||
# Therefore, the equlity tests below should be marked as failing.
|
||||
!= number-1.xul number-ref.xul
|
||||
|
|
|
@ -126,7 +126,13 @@ static const char* kPreloadPermissions[] = {
|
|||
"beacon",
|
||||
"fetch",
|
||||
"image",
|
||||
"manifest"
|
||||
"manifest",
|
||||
|
||||
// This permission is preloaded to support properly blocking service worker
|
||||
// interception when a user has disabled storage for a specific site. Once
|
||||
// service worker interception moves to the parent process this should be
|
||||
// removed. See bug 1428130.
|
||||
"cookie"
|
||||
};
|
||||
|
||||
// A list of permissions that can have a fallback default permission
|
||||
|
|
|
@ -1656,28 +1656,31 @@ GLContext::InitExtensions()
|
|||
|
||||
std::vector<nsCString> driverExtensionList;
|
||||
|
||||
if (mSymbols.fGetStringi) {
|
||||
GLuint count = 0;
|
||||
GetUIntegerv(LOCAL_GL_NUM_EXTENSIONS, &count);
|
||||
for (GLuint i = 0; i < count; i++) {
|
||||
// This is UTF-8.
|
||||
const char* rawExt = (const char*)fGetStringi(LOCAL_GL_EXTENSIONS, i);
|
||||
[&]() {
|
||||
if (mSymbols.fGetStringi) {
|
||||
GLuint count = 0;
|
||||
if (GetPotentialInteger(LOCAL_GL_NUM_EXTENSIONS, (GLint*)&count)) {
|
||||
for (GLuint i = 0; i < count; i++) {
|
||||
// This is UTF-8.
|
||||
const char* rawExt = (const char*)fGetStringi(LOCAL_GL_EXTENSIONS, i);
|
||||
|
||||
// We CANNOT use nsDependentCString here, because the spec doesn't guarantee
|
||||
// that the pointers returned are different, only that their contents are.
|
||||
// On Flame, each of these index string queries returns the same address.
|
||||
driverExtensionList.push_back(nsCString(rawExt));
|
||||
// We CANNOT use nsDependentCString here, because the spec doesn't guarantee
|
||||
// that the pointers returned are different, only that their contents are.
|
||||
// On Flame, each of these index string queries returns the same address.
|
||||
driverExtensionList.push_back(nsCString(rawExt));
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
MOZ_ALWAYS_TRUE(!fGetError());
|
||||
const char* rawExts = (const char*)fGetString(LOCAL_GL_EXTENSIONS);
|
||||
MOZ_ALWAYS_TRUE(!fGetError());
|
||||
|
||||
const char* rawExts = (const char*)fGetString(LOCAL_GL_EXTENSIONS);
|
||||
if (rawExts) {
|
||||
nsDependentCString exts(rawExts);
|
||||
SplitByChar(exts, ' ', &driverExtensionList);
|
||||
}
|
||||
}
|
||||
}();
|
||||
const auto err = fGetError();
|
||||
MOZ_ALWAYS_TRUE(!err);
|
||||
|
||||
const bool shouldDumpExts = ShouldDumpExts();
|
||||
if (shouldDumpExts) {
|
||||
|
|
|
@ -161,12 +161,14 @@ MacIOSurfaceTextureHostOGL::PushResourceUpdates(wr::ResourceUpdateQueue& aResour
|
|||
|
||||
switch (GetFormat()) {
|
||||
case gfx::SurfaceFormat::R8G8B8X8:
|
||||
case gfx::SurfaceFormat::R8G8B8A8:
|
||||
case gfx::SurfaceFormat::B8G8R8A8:
|
||||
case gfx::SurfaceFormat::B8G8R8X8: {
|
||||
case gfx::SurfaceFormat::R8G8B8A8: {
|
||||
MOZ_ASSERT(aImageKeys.length() == 1);
|
||||
MOZ_ASSERT(mSurface->GetPlaneCount() == 0);
|
||||
wr::ImageDescriptor descriptor(GetSize(), GetFormat());
|
||||
// The internal pixel format of MacIOSurface is always BGRX or BGRA
|
||||
// format.
|
||||
auto format = GetFormat() == gfx::SurfaceFormat::R8G8B8A8 ? gfx::SurfaceFormat::B8G8R8A8
|
||||
: gfx::SurfaceFormat::B8G8R8X8;
|
||||
wr::ImageDescriptor descriptor(GetSize(), format);
|
||||
(aResources.*method)(aImageKeys[0], descriptor, aExtID, bufferType, 0);
|
||||
break;
|
||||
}
|
||||
|
@ -177,7 +179,7 @@ MacIOSurfaceTextureHostOGL::PushResourceUpdates(wr::ResourceUpdateQueue& aResour
|
|||
// and YCbCr at OpenGL 3.1)
|
||||
MOZ_ASSERT(aImageKeys.length() == 1);
|
||||
MOZ_ASSERT(mSurface->GetPlaneCount() == 0);
|
||||
wr::ImageDescriptor descriptor(GetSize(), gfx::SurfaceFormat::R8G8B8X8);
|
||||
wr::ImageDescriptor descriptor(GetSize(), gfx::SurfaceFormat::B8G8R8X8);
|
||||
(aResources.*method)(aImageKeys[0], descriptor, aExtID, bufferType, 0);
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -508,7 +508,8 @@ gfxMacFont::GetScaledFont(DrawTarget *aTarget)
|
|||
GetUnscaledFont(),
|
||||
GetAdjustedSize(),
|
||||
Color::FromABGR(mFontSmoothingBackgroundColor),
|
||||
!mStyle.useGrayscaleAntialiasing);
|
||||
!mStyle.useGrayscaleAntialiasing,
|
||||
IsSyntheticBold());
|
||||
if (!mAzureScaledFont) {
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
@ -66,9 +66,10 @@ inline Maybe<wr::ImageFormat>
|
|||
SurfaceFormatToImageFormat(gfx::SurfaceFormat aFormat) {
|
||||
switch (aFormat) {
|
||||
case gfx::SurfaceFormat::R8G8B8X8:
|
||||
// TODO: use RGBA + opaque flag
|
||||
case gfx::SurfaceFormat::R8G8B8A8:
|
||||
return Some(wr::ImageFormat::BGRA8);
|
||||
// WebRender not support RGBA8 and RGBX8. Assert here.
|
||||
MOZ_ASSERT(false);
|
||||
return Nothing();
|
||||
case gfx::SurfaceFormat::B8G8R8X8:
|
||||
// TODO: WebRender will have a BGRA + opaque flag for this but does not
|
||||
// have it yet (cf. issue #732).
|
||||
|
|
|
@ -9478,7 +9478,7 @@ CodeGenerator::generateWasm(wasm::SigIdDesc sigId, wasm::BytecodeOffset trapOffs
|
|||
// Since we just overflowed the stack, to be on the safe side, pop the
|
||||
// stack so that, when the trap exit stub executes, it is a safe
|
||||
// distance away from the end of the native stack.
|
||||
wasm::TrapDesc trap(trapOffset, wasm::Trap::StackOverflow, /* framePushed = */ 0);
|
||||
wasm::OldTrapDesc trap(trapOffset, wasm::Trap::StackOverflow, /* framePushed = */ 0);
|
||||
if (frameSize() > 0) {
|
||||
masm.bind(&onOverflow);
|
||||
masm.addToStackPtr(Imm32(frameSize()));
|
||||
|
@ -9496,7 +9496,7 @@ CodeGenerator::generateWasm(wasm::SigIdDesc sigId, wasm::BytecodeOffset trapOffs
|
|||
if (!generateOutOfLineCode())
|
||||
return false;
|
||||
|
||||
masm.wasmEmitTrapOutOfLineCode();
|
||||
masm.wasmEmitOldTrapOutOfLineCode();
|
||||
|
||||
masm.flush();
|
||||
if (masm.oom())
|
||||
|
@ -12350,7 +12350,7 @@ CodeGenerator::visitWasmTrap(LWasmTrap* lir)
|
|||
MOZ_ASSERT(gen->compilingWasm());
|
||||
const MWasmTrap* mir = lir->mir();
|
||||
|
||||
masm.jump(trap(mir, mir->trap()));
|
||||
masm.jump(oldTrap(mir, mir->trap()));
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -12363,7 +12363,7 @@ CodeGenerator::visitWasmBoundsCheck(LWasmBoundsCheck* ins)
|
|||
Register ptr = ToRegister(ins->ptr());
|
||||
Register boundsCheckLimit = ToRegister(ins->boundsCheckLimit());
|
||||
masm.wasmBoundsCheck(Assembler::AboveOrEqual, ptr, boundsCheckLimit,
|
||||
trap(mir, wasm::Trap::OutOfBounds));
|
||||
oldTrap(mir, wasm::Trap::OutOfBounds));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -12373,7 +12373,7 @@ CodeGenerator::visitWasmAlignmentCheck(LWasmAlignmentCheck* ins)
|
|||
const MWasmAlignmentCheck* mir = ins->mir();
|
||||
Register ptr = ToRegister(ins->ptr());
|
||||
masm.branchTest32(Assembler::NonZero, ptr, Imm32(mir->byteSize() - 1),
|
||||
trap(mir, wasm::Trap::UnalignedAccess));
|
||||
oldTrap(mir, wasm::Trap::UnalignedAccess));
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -2844,7 +2844,7 @@ MacroAssembler::callWithABINoProfiler(void* fun, MoveOp::Type result, CheckUnsaf
|
|||
}
|
||||
|
||||
void
|
||||
MacroAssembler::callWithABI(wasm::BytecodeOffset callOffset, wasm::SymbolicAddress imm,
|
||||
MacroAssembler::callWithABI(wasm::BytecodeOffset bytecode, wasm::SymbolicAddress imm,
|
||||
MoveOp::Type result)
|
||||
{
|
||||
MOZ_ASSERT(wasm::NeedsBuiltinThunk(imm));
|
||||
|
@ -2861,7 +2861,7 @@ MacroAssembler::callWithABI(wasm::BytecodeOffset callOffset, wasm::SymbolicAddre
|
|||
// points when placing arguments.
|
||||
loadWasmTlsRegFromFrame();
|
||||
|
||||
call(wasm::CallSiteDesc(callOffset.bytecodeOffset, wasm::CallSite::Symbolic), imm);
|
||||
call(wasm::CallSiteDesc(bytecode.offset, wasm::CallSite::Symbolic), imm);
|
||||
callWithABIPost(stackAdjust, result, /* callFromWasm = */ true);
|
||||
|
||||
Pop(WasmTlsReg);
|
||||
|
@ -3006,7 +3006,7 @@ MacroAssembler::wasmCallIndirect(const wasm::CallSiteDesc& desc, const wasm::Cal
|
|||
if (needsBoundsCheck) {
|
||||
loadWasmGlobalPtr(callee.tableLengthGlobalDataOffset(), scratch);
|
||||
|
||||
wasm::TrapDesc oobTrap(trapOffset, wasm::Trap::OutOfBounds, framePushed());
|
||||
wasm::OldTrapDesc oobTrap(trapOffset, wasm::Trap::OutOfBounds, framePushed());
|
||||
branch32(Assembler::Condition::AboveOrEqual, index, scratch, oobTrap);
|
||||
}
|
||||
|
||||
|
@ -3014,7 +3014,7 @@ MacroAssembler::wasmCallIndirect(const wasm::CallSiteDesc& desc, const wasm::Cal
|
|||
loadWasmGlobalPtr(callee.tableBaseGlobalDataOffset(), scratch);
|
||||
|
||||
// Load the callee from the table.
|
||||
wasm::TrapDesc nullTrap(trapOffset, wasm::Trap::IndirectCallToNull, framePushed());
|
||||
wasm::OldTrapDesc nullTrap(trapOffset, wasm::Trap::IndirectCallToNull, framePushed());
|
||||
if (callee.wasmTableIsExternal()) {
|
||||
static_assert(sizeof(wasm::ExternalTableElem) == 8 || sizeof(wasm::ExternalTableElem) == 16,
|
||||
"elements of external tables are two words");
|
||||
|
@ -3040,21 +3040,21 @@ MacroAssembler::wasmCallIndirect(const wasm::CallSiteDesc& desc, const wasm::Cal
|
|||
}
|
||||
|
||||
void
|
||||
MacroAssembler::wasmEmitTrapOutOfLineCode()
|
||||
MacroAssembler::wasmEmitOldTrapOutOfLineCode()
|
||||
{
|
||||
for (const wasm::TrapSite& site : trapSites()) {
|
||||
for (const wasm::OldTrapSite& site : oldTrapSites()) {
|
||||
// Trap out-of-line codes are created for two kinds of trap sites:
|
||||
// - jumps, which are bound directly to the trap out-of-line path
|
||||
// - memory accesses, which can fault and then have control transferred
|
||||
// to the out-of-line path directly via signal handler setting pc
|
||||
switch (site.kind) {
|
||||
case wasm::TrapSite::Jump: {
|
||||
case wasm::OldTrapSite::Jump: {
|
||||
RepatchLabel jump;
|
||||
jump.use(site.codeOffset);
|
||||
bind(&jump);
|
||||
break;
|
||||
}
|
||||
case wasm::TrapSite::MemoryAccess: {
|
||||
case wasm::OldTrapSite::MemoryAccess: {
|
||||
append(wasm::MemoryAccess(site.codeOffset, currentOffset()));
|
||||
break;
|
||||
}
|
||||
|
@ -3072,7 +3072,7 @@ MacroAssembler::wasmEmitTrapOutOfLineCode()
|
|||
// directly to the trap exit stub. This takes advantage of the fact
|
||||
// that there is already a CallSite for call_indirect and the
|
||||
// current pre-prologue stack/register state.
|
||||
append(wasm::TrapFarJump(site.trap, farJumpWithPatch()));
|
||||
append(wasm::OldTrapFarJump(site.trap, farJumpWithPatch()));
|
||||
} else {
|
||||
// Inherit the frame depth of the trap site. This value is captured
|
||||
// by the wasm::CallSite to allow unwinding this frame.
|
||||
|
@ -3098,7 +3098,7 @@ MacroAssembler::wasmEmitTrapOutOfLineCode()
|
|||
// trap-handling function. The frame iterator knows to skip the trap
|
||||
// exit's frame so that unwinding begins at the frame and offset of
|
||||
// the trapping instruction.
|
||||
wasm::CallSiteDesc desc(site.bytecodeOffset, wasm::CallSiteDesc::TrapExit);
|
||||
wasm::CallSiteDesc desc(site.offset, wasm::CallSiteDesc::OldTrapExit);
|
||||
call(desc, site.trap);
|
||||
}
|
||||
|
||||
|
@ -3113,7 +3113,7 @@ MacroAssembler::wasmEmitTrapOutOfLineCode()
|
|||
// iterator to find the right CodeRange while walking the stack.
|
||||
breakpoint();
|
||||
|
||||
trapSites().clear();
|
||||
oldTrapSites().clear();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -1506,7 +1506,7 @@ class MacroAssembler : public MacroAssemblerSpecific
|
|||
// Emit the out-of-line trap code to which trapping jumps/branches are
|
||||
// bound. This should be called once per function after all other codegen,
|
||||
// including "normal" OutOfLineCode.
|
||||
void wasmEmitTrapOutOfLineCode();
|
||||
void wasmEmitOldTrapOutOfLineCode();
|
||||
|
||||
// Perform a stack-overflow test, branching to the given Label on overflow.
|
||||
void wasmEmitStackCheck(Register sp, Register scratch, Label* onOverflow);
|
||||
|
|
|
@ -2453,7 +2453,7 @@ Assembler::as_b(Label* l, Condition c)
|
|||
}
|
||||
|
||||
BufferOffset
|
||||
Assembler::as_b(wasm::TrapDesc target, Condition c)
|
||||
Assembler::as_b(wasm::OldTrapDesc target, Condition c)
|
||||
{
|
||||
Label l;
|
||||
BufferOffset ret = as_b(&l, c);
|
||||
|
@ -2894,12 +2894,12 @@ Assembler::bind(Label* label, BufferOffset boff)
|
|||
}
|
||||
|
||||
void
|
||||
Assembler::bindLater(Label* label, wasm::TrapDesc target)
|
||||
Assembler::bindLater(Label* label, wasm::OldTrapDesc target)
|
||||
{
|
||||
if (label->used()) {
|
||||
BufferOffset b(label);
|
||||
do {
|
||||
append(wasm::TrapSite(target, b.getOffset()));
|
||||
append(wasm::OldTrapSite(target, b.getOffset()));
|
||||
} while (nextLink(b, &b));
|
||||
}
|
||||
label->reset();
|
||||
|
|
|
@ -1614,7 +1614,7 @@ class Assembler : public AssemblerShared
|
|||
BufferOffset as_b(BOffImm off, Condition c, Label* documentation = nullptr);
|
||||
|
||||
BufferOffset as_b(Label* l, Condition c = Always);
|
||||
BufferOffset as_b(wasm::TrapDesc target, Condition c = Always);
|
||||
BufferOffset as_b(wasm::OldTrapDesc target, Condition c = Always);
|
||||
BufferOffset as_b(BOffImm off, Condition c, BufferOffset inst);
|
||||
|
||||
// blx can go to either an immediate or a register. When blx'ing to a
|
||||
|
@ -1722,7 +1722,7 @@ class Assembler : public AssemblerShared
|
|||
bool nextLink(BufferOffset b, BufferOffset* next);
|
||||
void bind(Label* label, BufferOffset boff = BufferOffset());
|
||||
void bind(RepatchLabel* label);
|
||||
void bindLater(Label* label, wasm::TrapDesc target);
|
||||
void bindLater(Label* label, wasm::OldTrapDesc target);
|
||||
uint32_t currentOffset() {
|
||||
return nextOffset().getOffset();
|
||||
}
|
||||
|
|
|
@ -531,7 +531,7 @@ CodeGeneratorARM::divICommon(MDiv* mir, Register lhs, Register rhs, Register out
|
|||
masm.ma_cmp(rhs, Imm32(-1), scratch, Assembler::Equal);
|
||||
if (mir->canTruncateOverflow()) {
|
||||
if (mir->trapOnError()) {
|
||||
masm.ma_b(trap(mir, wasm::Trap::IntegerOverflow), Assembler::Equal);
|
||||
masm.ma_b(oldTrap(mir, wasm::Trap::IntegerOverflow), Assembler::Equal);
|
||||
} else {
|
||||
// (-INT32_MIN)|0 = INT32_MIN
|
||||
Label skip;
|
||||
|
@ -551,7 +551,7 @@ CodeGeneratorARM::divICommon(MDiv* mir, Register lhs, Register rhs, Register out
|
|||
masm.as_cmp(rhs, Imm8(0));
|
||||
if (mir->canTruncateInfinities()) {
|
||||
if (mir->trapOnError()) {
|
||||
masm.ma_b(trap(mir, wasm::Trap::IntegerDivideByZero), Assembler::Equal);
|
||||
masm.ma_b(oldTrap(mir, wasm::Trap::IntegerDivideByZero), Assembler::Equal);
|
||||
} else {
|
||||
// Infinity|0 == 0
|
||||
Label skip;
|
||||
|
@ -714,7 +714,7 @@ CodeGeneratorARM::modICommon(MMod* mir, Register lhs, Register rhs, Register out
|
|||
// wasm allows negative lhs and return 0 in this case.
|
||||
MOZ_ASSERT(mir->isTruncated());
|
||||
masm.as_cmp(rhs, Imm8(0));
|
||||
masm.ma_b(trap(mir, wasm::Trap::IntegerDivideByZero), Assembler::Equal);
|
||||
masm.ma_b(oldTrap(mir, wasm::Trap::IntegerDivideByZero), Assembler::Equal);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2120,7 +2120,7 @@ CodeGeneratorARM::visitWasmAddOffset(LWasmAddOffset* lir)
|
|||
ScratchRegisterScope scratch(masm);
|
||||
masm.ma_add(base, Imm32(mir->offset()), out, scratch, SetCC);
|
||||
|
||||
masm.ma_b(trap(mir, wasm::Trap::OutOfBounds), Assembler::CarrySet);
|
||||
masm.ma_b(oldTrap(mir, wasm::Trap::OutOfBounds), Assembler::CarrySet);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
|
@ -2417,7 +2417,7 @@ CodeGeneratorARM::generateUDivModZeroCheck(Register rhs, Register output, Label*
|
|||
masm.as_cmp(rhs, Imm8(0));
|
||||
if (mir->isTruncated()) {
|
||||
if (mir->trapOnError()) {
|
||||
masm.ma_b(trap(mir, wasm::Trap::IntegerDivideByZero), Assembler::Equal);
|
||||
masm.ma_b(oldTrap(mir, wasm::Trap::IntegerDivideByZero), Assembler::Equal);
|
||||
} else {
|
||||
Label skip;
|
||||
masm.ma_b(&skip, Assembler::NotEqual);
|
||||
|
@ -2768,7 +2768,7 @@ CodeGeneratorARM::visitDivOrModI64(LDivOrModI64* lir)
|
|||
if (lir->canBeDivideByZero()) {
|
||||
Register temp = WasmGetTemporaryForDivOrMod(lhs, rhs);
|
||||
masm.branchTest64(Assembler::Zero, rhs, rhs, temp,
|
||||
trap(lir, wasm::Trap::IntegerDivideByZero));
|
||||
oldTrap(lir, wasm::Trap::IntegerDivideByZero));
|
||||
}
|
||||
|
||||
auto* mir = lir->mir();
|
||||
|
@ -2781,7 +2781,7 @@ CodeGeneratorARM::visitDivOrModI64(LDivOrModI64* lir)
|
|||
if (mir->isMod())
|
||||
masm.xor64(output, output);
|
||||
else
|
||||
masm.jump(trap(lir, wasm::Trap::IntegerOverflow));
|
||||
masm.jump(oldTrap(lir, wasm::Trap::IntegerOverflow));
|
||||
masm.jump(&done);
|
||||
masm.bind(¬min);
|
||||
}
|
||||
|
@ -2814,7 +2814,7 @@ CodeGeneratorARM::visitUDivOrModI64(LUDivOrModI64* lir)
|
|||
if (lir->canBeDivideByZero()) {
|
||||
Register temp = WasmGetTemporaryForDivOrMod(lhs, rhs);
|
||||
masm.branchTest64(Assembler::Zero, rhs, rhs, temp,
|
||||
trap(lir, wasm::Trap::IntegerDivideByZero));
|
||||
oldTrap(lir, wasm::Trap::IntegerDivideByZero));
|
||||
}
|
||||
|
||||
masm.setupWasmABICall();
|
||||
|
|
|
@ -1390,7 +1390,7 @@ MacroAssemblerARM::ma_b(Label* dest, Assembler::Condition c)
|
|||
}
|
||||
|
||||
BufferOffset
|
||||
MacroAssemblerARM::ma_b(wasm::TrapDesc target, Assembler::Condition c)
|
||||
MacroAssemblerARM::ma_b(wasm::OldTrapDesc target, Assembler::Condition c)
|
||||
{
|
||||
return as_b(target, c);
|
||||
}
|
||||
|
@ -5751,12 +5751,12 @@ MacroAssemblerARM::outOfLineWasmTruncateToIntCheck(FloatRegister input, MIRType
|
|||
|
||||
// Handle errors.
|
||||
bind(&fail);
|
||||
asMasm().jump(wasm::TrapDesc(trapOffset, wasm::Trap::IntegerOverflow,
|
||||
asMasm().framePushed()));
|
||||
asMasm().jump(wasm::OldTrapDesc(trapOffset, wasm::Trap::IntegerOverflow,
|
||||
asMasm().framePushed()));
|
||||
|
||||
bind(&inputIsNaN);
|
||||
asMasm().jump(wasm::TrapDesc(trapOffset, wasm::Trap::InvalidConversionToInteger,
|
||||
asMasm().framePushed()));
|
||||
asMasm().jump(wasm::OldTrapDesc(trapOffset, wasm::Trap::InvalidConversionToInteger,
|
||||
asMasm().framePushed()));
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -346,7 +346,7 @@ class MacroAssemblerARM : public Assembler
|
|||
|
||||
// Branches when done from within arm-specific code.
|
||||
BufferOffset ma_b(Label* dest, Condition c = Always);
|
||||
BufferOffset ma_b(wasm::TrapDesc target, Condition c = Always);
|
||||
BufferOffset ma_b(wasm::OldTrapDesc target, Condition c = Always);
|
||||
void ma_b(void* target, Condition c = Always);
|
||||
void ma_bx(Register dest, Condition c = Always);
|
||||
|
||||
|
@ -677,7 +677,7 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM
|
|||
ma_ldr(addr, scratch, scratch2);
|
||||
ma_bx(scratch);
|
||||
}
|
||||
void jump(wasm::TrapDesc target) {
|
||||
void jump(wasm::OldTrapDesc target) {
|
||||
as_b(target);
|
||||
}
|
||||
|
||||
|
|
|
@ -215,7 +215,7 @@ class Assembler : public vixl::Assembler
|
|||
void bind(Label* label) { bind(label, nextOffset()); }
|
||||
void bind(Label* label, BufferOffset boff);
|
||||
void bind(RepatchLabel* label);
|
||||
void bindLater(Label* label, wasm::TrapDesc target) {
|
||||
void bindLater(Label* label, wasm::OldTrapDesc target) {
|
||||
MOZ_CRASH("NYI");
|
||||
}
|
||||
|
||||
|
|
|
@ -493,10 +493,10 @@ class MacroAssemblerCompat : public vixl::MacroAssembler
|
|||
}
|
||||
|
||||
using vixl::MacroAssembler::B;
|
||||
void B(wasm::TrapDesc) {
|
||||
void B(wasm::OldTrapDesc) {
|
||||
MOZ_CRASH("NYI");
|
||||
}
|
||||
void B(wasm::TrapDesc, Condition cond) {
|
||||
void B(wasm::OldTrapDesc, Condition cond) {
|
||||
MOZ_CRASH("NYI");
|
||||
}
|
||||
|
||||
|
@ -673,7 +673,7 @@ class MacroAssemblerCompat : public vixl::MacroAssembler
|
|||
loadPtr(addr, ip0);
|
||||
Br(vixl::ip0);
|
||||
}
|
||||
void jump(wasm::TrapDesc target) {
|
||||
void jump(wasm::OldTrapDesc target) {
|
||||
MOZ_CRASH("NYI");
|
||||
}
|
||||
|
||||
|
|
|
@ -1809,7 +1809,7 @@ AssemblerMIPSShared::bind(Label* label, BufferOffset boff)
|
|||
}
|
||||
|
||||
void
|
||||
AssemblerMIPSShared::bindLater(Label* label, wasm::TrapDesc target)
|
||||
AssemblerMIPSShared::bindLater(Label* label, wasm::OldTrapDesc target)
|
||||
{
|
||||
if (label->used()) {
|
||||
int32_t next;
|
||||
|
@ -1818,7 +1818,7 @@ AssemblerMIPSShared::bindLater(Label* label, wasm::TrapDesc target)
|
|||
do {
|
||||
Instruction* inst = editSrc(b);
|
||||
|
||||
append(wasm::TrapSite(target, b.getOffset()));
|
||||
append(wasm::OldTrapSite(target, b.getOffset()));
|
||||
next = inst[1].encode();
|
||||
inst[1].makeNop();
|
||||
|
||||
|
|
|
@ -1231,7 +1231,7 @@ class AssemblerMIPSShared : public AssemblerShared
|
|||
|
||||
// label operations
|
||||
void bind(Label* label, BufferOffset boff = BufferOffset());
|
||||
void bindLater(Label* label, wasm::TrapDesc target);
|
||||
void bindLater(Label* label, wasm::OldTrapDesc target);
|
||||
virtual void bind(InstImm* inst, uintptr_t branch, uintptr_t target) = 0;
|
||||
void bind(CodeOffset* label) {
|
||||
label->bind(currentOffset());
|
||||
|
|
|
@ -568,7 +568,7 @@ CodeGeneratorMIPSShared::visitDivI(LDivI* ins)
|
|||
// Handle divide by zero.
|
||||
if (mir->canBeDivideByZero()) {
|
||||
if (mir->trapOnError()) {
|
||||
masm.ma_b(rhs, rhs, trap(mir, wasm::Trap::IntegerDivideByZero), Assembler::Zero);
|
||||
masm.ma_b(rhs, rhs, oldTrap(mir, wasm::Trap::IntegerDivideByZero), Assembler::Zero);
|
||||
} else if (mir->canTruncateInfinities()) {
|
||||
// Truncated division by zero is zero (Infinity|0 == 0)
|
||||
Label notzero;
|
||||
|
@ -590,7 +590,7 @@ CodeGeneratorMIPSShared::visitDivI(LDivI* ins)
|
|||
|
||||
masm.move32(Imm32(-1), temp);
|
||||
if (mir->trapOnError()) {
|
||||
masm.ma_b(rhs, temp, trap(mir, wasm::Trap::IntegerOverflow), Assembler::Equal);
|
||||
masm.ma_b(rhs, temp, oldTrap(mir, wasm::Trap::IntegerOverflow), Assembler::Equal);
|
||||
} else if (mir->canTruncateOverflow()) {
|
||||
// (-INT32_MIN)|0 == INT32_MIN
|
||||
Label skip;
|
||||
|
@ -718,7 +718,7 @@ CodeGeneratorMIPSShared::visitModI(LModI* ins)
|
|||
if (mir->canBeDivideByZero()) {
|
||||
if (mir->isTruncated()) {
|
||||
if (mir->trapOnError()) {
|
||||
masm.ma_b(rhs, rhs, trap(mir, wasm::Trap::IntegerDivideByZero), Assembler::Zero);
|
||||
masm.ma_b(rhs, rhs, oldTrap(mir, wasm::Trap::IntegerDivideByZero), Assembler::Zero);
|
||||
} else {
|
||||
Label skip;
|
||||
masm.ma_b(rhs, Imm32(0), &skip, Assembler::NotEqual, ShortJump);
|
||||
|
@ -1559,10 +1559,10 @@ CodeGeneratorMIPSShared::visitOutOfLineWasmTruncateCheck(OutOfLineWasmTruncateCh
|
|||
|
||||
// Handle errors.
|
||||
masm.bind(&fail);
|
||||
masm.jump(trap(ool, wasm::Trap::IntegerOverflow));
|
||||
masm.jump(oldTrap(ool, wasm::Trap::IntegerOverflow));
|
||||
|
||||
masm.bind(&inputIsNaN);
|
||||
masm.jump(trap(ool, wasm::Trap::InvalidConversionToInteger));
|
||||
masm.jump(oldTrap(ool, wasm::Trap::InvalidConversionToInteger));
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -2415,7 +2415,7 @@ CodeGeneratorMIPSShared::visitUDivOrMod(LUDivOrMod* ins)
|
|||
if (ins->canBeDivideByZero()) {
|
||||
if (ins->mir()->isTruncated()) {
|
||||
if (ins->trapOnError()) {
|
||||
masm.ma_b(rhs, rhs, trap(ins, wasm::Trap::IntegerDivideByZero), Assembler::Zero);
|
||||
masm.ma_b(rhs, rhs, oldTrap(ins, wasm::Trap::IntegerDivideByZero), Assembler::Zero);
|
||||
} else {
|
||||
// Infinity|0 == 0
|
||||
Label notzero;
|
||||
|
@ -2767,7 +2767,7 @@ CodeGeneratorMIPSShared::visitWasmAddOffset(LWasmAddOffset* lir)
|
|||
Register base = ToRegister(lir->base());
|
||||
Register out = ToRegister(lir->output());
|
||||
|
||||
masm.ma_addTestCarry(out, base, Imm32(mir->offset()), trap(mir, wasm::Trap::OutOfBounds));
|
||||
masm.ma_addTestCarry(out, base, Imm32(mir->offset()), oldTrap(mir, wasm::Trap::OutOfBounds));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
|
|
|
@ -337,8 +337,8 @@ template void
|
|||
MacroAssemblerMIPSShared::ma_addTestCarry<Label*>(Register rd, Register rs,
|
||||
Register rt, Label* overflow);
|
||||
template void
|
||||
MacroAssemblerMIPSShared::ma_addTestCarry<wasm::TrapDesc>(Register rd, Register rs, Register rt,
|
||||
wasm::TrapDesc overflow);
|
||||
MacroAssemblerMIPSShared::ma_addTestCarry<wasm::OldTrapDesc>(Register rd, Register rs, Register rt,
|
||||
wasm::OldTrapDesc overflow);
|
||||
|
||||
template <typename L>
|
||||
void
|
||||
|
@ -352,8 +352,8 @@ template void
|
|||
MacroAssemblerMIPSShared::ma_addTestCarry<Label*>(Register rd, Register rs,
|
||||
Imm32 imm, Label* overflow);
|
||||
template void
|
||||
MacroAssemblerMIPSShared::ma_addTestCarry<wasm::TrapDesc>(Register rd, Register rs, Imm32 imm,
|
||||
wasm::TrapDesc overflow);
|
||||
MacroAssemblerMIPSShared::ma_addTestCarry<wasm::OldTrapDesc>(Register rd, Register rs, Imm32 imm,
|
||||
wasm::OldTrapDesc overflow);
|
||||
|
||||
// Subtract.
|
||||
void
|
||||
|
@ -796,7 +796,7 @@ MacroAssemblerMIPSShared::ma_b(Register lhs, ImmPtr imm, Label* l, Condition c,
|
|||
|
||||
template <typename T>
|
||||
void
|
||||
MacroAssemblerMIPSShared::ma_b(Register lhs, T rhs, wasm::TrapDesc target, Condition c,
|
||||
MacroAssemblerMIPSShared::ma_b(Register lhs, T rhs, wasm::OldTrapDesc target, Condition c,
|
||||
JumpKind jumpKind)
|
||||
{
|
||||
Label label;
|
||||
|
@ -805,13 +805,13 @@ MacroAssemblerMIPSShared::ma_b(Register lhs, T rhs, wasm::TrapDesc target, Condi
|
|||
}
|
||||
|
||||
template void MacroAssemblerMIPSShared::ma_b<Register>(Register lhs, Register rhs,
|
||||
wasm::TrapDesc target, Condition c,
|
||||
wasm::OldTrapDesc target, Condition c,
|
||||
JumpKind jumpKind);
|
||||
template void MacroAssemblerMIPSShared::ma_b<Imm32>(Register lhs, Imm32 rhs,
|
||||
wasm::TrapDesc target, Condition c,
|
||||
wasm::OldTrapDesc target, Condition c,
|
||||
JumpKind jumpKind);
|
||||
template void MacroAssemblerMIPSShared::ma_b<ImmTag>(Register lhs, ImmTag rhs,
|
||||
wasm::TrapDesc target, Condition c,
|
||||
wasm::OldTrapDesc target, Condition c,
|
||||
JumpKind jumpKind);
|
||||
|
||||
void
|
||||
|
@ -821,7 +821,7 @@ MacroAssemblerMIPSShared::ma_b(Label* label, JumpKind jumpKind)
|
|||
}
|
||||
|
||||
void
|
||||
MacroAssemblerMIPSShared::ma_b(wasm::TrapDesc target, JumpKind jumpKind)
|
||||
MacroAssemblerMIPSShared::ma_b(wasm::OldTrapDesc target, JumpKind jumpKind)
|
||||
{
|
||||
Label label;
|
||||
asMasm().branchWithCode(getBranchCode(BranchIsJump), &label, jumpKind);
|
||||
|
|
|
@ -164,11 +164,11 @@ class MacroAssemblerMIPSShared : public Assembler
|
|||
ma_b(lhs, ScratchRegister, l, c, jumpKind);
|
||||
}
|
||||
template <typename T>
|
||||
void ma_b(Register lhs, T rhs, wasm::TrapDesc target, Condition c,
|
||||
void ma_b(Register lhs, T rhs, wasm::OldTrapDesc target, Condition c,
|
||||
JumpKind jumpKind = LongJump);
|
||||
|
||||
void ma_b(Label* l, JumpKind jumpKind = LongJump);
|
||||
void ma_b(wasm::TrapDesc target, JumpKind jumpKind = LongJump);
|
||||
void ma_b(wasm::OldTrapDesc target, JumpKind jumpKind = LongJump);
|
||||
|
||||
// fp instructions
|
||||
void ma_lis(FloatRegister dest, float value);
|
||||
|
|
|
@ -380,7 +380,7 @@ CodeGeneratorMIPS::visitDivOrModI64(LDivOrModI64* lir)
|
|||
|
||||
// Handle divide by zero.
|
||||
if (lir->canBeDivideByZero())
|
||||
masm.branchTest64(Assembler::Zero, rhs, rhs, temp, trap(lir, wasm::Trap::IntegerDivideByZero));
|
||||
masm.branchTest64(Assembler::Zero, rhs, rhs, temp, oldTrap(lir, wasm::Trap::IntegerDivideByZero));
|
||||
|
||||
// Handle an integer overflow exception from INT64_MIN / -1.
|
||||
if (lir->canBeNegativeOverflow()) {
|
||||
|
@ -390,7 +390,7 @@ CodeGeneratorMIPS::visitDivOrModI64(LDivOrModI64* lir)
|
|||
if (lir->mir()->isMod()) {
|
||||
masm.xor64(output, output);
|
||||
} else {
|
||||
masm.jump(trap(lir, wasm::Trap::IntegerOverflow));
|
||||
masm.jump(oldTrap(lir, wasm::Trap::IntegerOverflow));
|
||||
}
|
||||
masm.jump(&done);
|
||||
masm.bind(¬min);
|
||||
|
@ -433,7 +433,7 @@ CodeGeneratorMIPS::visitUDivOrModI64(LUDivOrModI64* lir)
|
|||
|
||||
// Prevent divide by zero.
|
||||
if (lir->canBeDivideByZero())
|
||||
masm.branchTest64(Assembler::Zero, rhs, rhs, temp, trap(lir, wasm::Trap::IntegerDivideByZero));
|
||||
masm.branchTest64(Assembler::Zero, rhs, rhs, temp, oldTrap(lir, wasm::Trap::IntegerDivideByZero));
|
||||
|
||||
masm.setupWasmABICall();
|
||||
masm.passABIArg(lhs.high);
|
||||
|
|
|
@ -238,8 +238,8 @@ template void
|
|||
MacroAssemblerMIPS::ma_addTestOverflow<Label*>(Register rd, Register rs,
|
||||
Register rt, Label* overflow);
|
||||
template void
|
||||
MacroAssemblerMIPS::ma_addTestOverflow<wasm::TrapDesc>(Register rd, Register rs, Register rt,
|
||||
wasm::TrapDesc overflow);
|
||||
MacroAssemblerMIPS::ma_addTestOverflow<wasm::OldTrapDesc>(Register rd, Register rs, Register rt,
|
||||
wasm::OldTrapDesc overflow);
|
||||
|
||||
template <typename L>
|
||||
void
|
||||
|
@ -270,8 +270,8 @@ template void
|
|||
MacroAssemblerMIPS::ma_addTestOverflow<Label*>(Register rd, Register rs,
|
||||
Imm32 imm, Label* overflow);
|
||||
template void
|
||||
MacroAssemblerMIPS::ma_addTestOverflow<wasm::TrapDesc>(Register rd, Register rs, Imm32 imm,
|
||||
wasm::TrapDesc overflow);
|
||||
MacroAssemblerMIPS::ma_addTestOverflow<wasm::OldTrapDesc>(Register rd, Register rs, Imm32 imm,
|
||||
wasm::OldTrapDesc overflow);
|
||||
|
||||
// Subtract.
|
||||
void
|
||||
|
|
|
@ -306,7 +306,7 @@ class MacroAssemblerMIPSCompat : public MacroAssemblerMIPS
|
|||
branch(code);
|
||||
}
|
||||
|
||||
void jump(wasm::TrapDesc target) {
|
||||
void jump(wasm::OldTrapDesc target) {
|
||||
ma_b(target);
|
||||
}
|
||||
|
||||
|
|
|
@ -362,7 +362,7 @@ CodeGeneratorMIPS64::visitDivOrModI64(LDivOrModI64* lir)
|
|||
|
||||
// Handle divide by zero.
|
||||
if (lir->canBeDivideByZero())
|
||||
masm.ma_b(rhs, rhs, trap(lir, wasm::Trap::IntegerDivideByZero), Assembler::Zero);
|
||||
masm.ma_b(rhs, rhs, oldTrap(lir, wasm::Trap::IntegerDivideByZero), Assembler::Zero);
|
||||
|
||||
// Handle an integer overflow exception from INT64_MIN / -1.
|
||||
if (lir->canBeNegativeOverflow()) {
|
||||
|
@ -372,7 +372,7 @@ CodeGeneratorMIPS64::visitDivOrModI64(LDivOrModI64* lir)
|
|||
if (lir->mir()->isMod()) {
|
||||
masm.ma_xor(output, output);
|
||||
} else {
|
||||
masm.jump(trap(lir, wasm::Trap::IntegerOverflow));
|
||||
masm.jump(oldTrap(lir, wasm::Trap::IntegerOverflow));
|
||||
}
|
||||
masm.jump(&done);
|
||||
masm.bind(¬min);
|
||||
|
@ -399,7 +399,7 @@ CodeGeneratorMIPS64::visitUDivOrModI64(LUDivOrModI64* lir)
|
|||
|
||||
// Prevent divide by zero.
|
||||
if (lir->canBeDivideByZero())
|
||||
masm.ma_b(rhs, rhs, trap(lir, wasm::Trap::IntegerDivideByZero), Assembler::Zero);
|
||||
masm.ma_b(rhs, rhs, oldTrap(lir, wasm::Trap::IntegerDivideByZero), Assembler::Zero);
|
||||
|
||||
masm.as_ddivu(lhs, rhs);
|
||||
|
||||
|
|
|
@ -489,8 +489,8 @@ template void
|
|||
MacroAssemblerMIPS64::ma_addTestOverflow<Label*>(Register rd, Register rs,
|
||||
Register rt, Label* overflow);
|
||||
template void
|
||||
MacroAssemblerMIPS64::ma_addTestOverflow<wasm::TrapDesc>(Register rd, Register rs, Register rt,
|
||||
wasm::TrapDesc overflow);
|
||||
MacroAssemblerMIPS64::ma_addTestOverflow<wasm::OldTrapDesc>(Register rd, Register rs, Register rt,
|
||||
wasm::OldTrapDesc overflow);
|
||||
|
||||
template <typename L>
|
||||
void
|
||||
|
@ -511,8 +511,8 @@ template void
|
|||
MacroAssemblerMIPS64::ma_addTestOverflow<Label*>(Register rd, Register rs,
|
||||
Imm32 imm, Label* overflow);
|
||||
template void
|
||||
MacroAssemblerMIPS64::ma_addTestOverflow<wasm::TrapDesc>(Register rd, Register rs, Imm32 imm,
|
||||
wasm::TrapDesc overflow);
|
||||
MacroAssemblerMIPS64::ma_addTestOverflow<wasm::OldTrapDesc>(Register rd, Register rs, Imm32 imm,
|
||||
wasm::OldTrapDesc overflow);
|
||||
|
||||
// Subtract.
|
||||
void
|
||||
|
|
|
@ -335,7 +335,7 @@ class MacroAssemblerMIPS64Compat : public MacroAssemblerMIPS64
|
|||
branch(code);
|
||||
}
|
||||
|
||||
void jump(wasm::TrapDesc target) {
|
||||
void jump(wasm::OldTrapDesc target) {
|
||||
ma_b(target);
|
||||
}
|
||||
|
||||
|
|
|
@ -210,7 +210,7 @@ class MacroAssemblerNone : public Assembler
|
|||
void flushBuffer() { MOZ_CRASH(); }
|
||||
|
||||
template <typename T> void bind(T) { MOZ_CRASH(); }
|
||||
void bindLater(Label*, wasm::TrapDesc) { MOZ_CRASH(); }
|
||||
void bindLater(Label*, wasm::OldTrapDesc) { MOZ_CRASH(); }
|
||||
template <typename T> void j(Condition, T) { MOZ_CRASH(); }
|
||||
template <typename T> void jump(T) { MOZ_CRASH(); }
|
||||
void writeCodePointer(CodeOffset* label) { MOZ_CRASH(); }
|
||||
|
|
|
@ -811,47 +811,47 @@ struct CallFarJump
|
|||
|
||||
typedef Vector<CallFarJump, 0, SystemAllocPolicy> CallFarJumpVector;
|
||||
|
||||
// The TrapDesc struct describes a wasm trap that is about to be emitted. This
|
||||
// The OldTrapDesc struct describes a wasm trap that is about to be emitted. This
|
||||
// includes the logical wasm bytecode offset to report, the kind of instruction
|
||||
// causing the trap, and the stack depth right before control is transferred to
|
||||
// the trap out-of-line path.
|
||||
|
||||
struct TrapDesc : BytecodeOffset
|
||||
struct OldTrapDesc : BytecodeOffset
|
||||
{
|
||||
enum Kind { Jump, MemoryAccess };
|
||||
Kind kind;
|
||||
Trap trap;
|
||||
uint32_t framePushed;
|
||||
|
||||
TrapDesc(BytecodeOffset offset, Trap trap, uint32_t framePushed, Kind kind = Jump)
|
||||
OldTrapDesc(BytecodeOffset offset, Trap trap, uint32_t framePushed, Kind kind = Jump)
|
||||
: BytecodeOffset(offset), kind(kind), trap(trap), framePushed(framePushed)
|
||||
{}
|
||||
};
|
||||
|
||||
// A TrapSite captures all relevant information at the point of emitting the
|
||||
// An OldTrapSite captures all relevant information at the point of emitting the
|
||||
// in-line trapping instruction for the purpose of generating the out-of-line
|
||||
// trap code (at the end of the function).
|
||||
|
||||
struct TrapSite : TrapDesc
|
||||
struct OldTrapSite : OldTrapDesc
|
||||
{
|
||||
uint32_t codeOffset;
|
||||
|
||||
TrapSite(TrapDesc trap, uint32_t codeOffset)
|
||||
: TrapDesc(trap), codeOffset(codeOffset)
|
||||
OldTrapSite(OldTrapDesc trap, uint32_t codeOffset)
|
||||
: OldTrapDesc(trap), codeOffset(codeOffset)
|
||||
{}
|
||||
};
|
||||
|
||||
typedef Vector<TrapSite, 0, SystemAllocPolicy> TrapSiteVector;
|
||||
typedef Vector<OldTrapSite, 0, SystemAllocPolicy> OldTrapSiteVector;
|
||||
|
||||
// A TrapFarJump records the offset of a jump that needs to be patched to a trap
|
||||
// An OldTrapFarJump records the offset of a jump that needs to be patched to a trap
|
||||
// exit at the end of the module when trap exits are emitted.
|
||||
|
||||
struct TrapFarJump
|
||||
struct OldTrapFarJump
|
||||
{
|
||||
Trap trap;
|
||||
jit::CodeOffset jump;
|
||||
|
||||
TrapFarJump(Trap trap, jit::CodeOffset jump)
|
||||
OldTrapFarJump(Trap trap, jit::CodeOffset jump)
|
||||
: trap(trap), jump(jump)
|
||||
{}
|
||||
|
||||
|
@ -860,7 +860,7 @@ struct TrapFarJump
|
|||
}
|
||||
};
|
||||
|
||||
typedef Vector<TrapFarJump, 0, SystemAllocPolicy> TrapFarJumpVector;
|
||||
typedef Vector<OldTrapFarJump, 0, SystemAllocPolicy> OldTrapFarJumpVector;
|
||||
|
||||
} // namespace wasm
|
||||
|
||||
|
@ -871,8 +871,8 @@ class AssemblerShared
|
|||
{
|
||||
wasm::CallSiteVector callSites_;
|
||||
wasm::CallSiteTargetVector callSiteTargets_;
|
||||
wasm::TrapSiteVector trapSites_;
|
||||
wasm::TrapFarJumpVector trapFarJumps_;
|
||||
wasm::OldTrapSiteVector oldTrapSites_;
|
||||
wasm::OldTrapFarJumpVector oldTrapFarJumps_;
|
||||
wasm::CallFarJumpVector callFarJumps_;
|
||||
wasm::MemoryAccessVector memoryAccesses_;
|
||||
wasm::SymbolicAccessVector symbolicAccesses_;
|
||||
|
@ -930,11 +930,11 @@ class AssemblerShared
|
|||
enoughMemory_ &= callSites_.emplaceBack(desc, retAddr.offset());
|
||||
enoughMemory_ &= callSiteTargets_.emplaceBack(mozilla::Forward<Args>(args)...);
|
||||
}
|
||||
void append(wasm::TrapSite trapSite) {
|
||||
enoughMemory_ &= trapSites_.append(trapSite);
|
||||
void append(wasm::OldTrapSite trapSite) {
|
||||
enoughMemory_ &= oldTrapSites_.append(trapSite);
|
||||
}
|
||||
void append(wasm::TrapFarJump jmp) {
|
||||
enoughMemory_ &= trapFarJumps_.append(jmp);
|
||||
void append(wasm::OldTrapFarJump jmp) {
|
||||
enoughMemory_ &= oldTrapFarJumps_.append(jmp);
|
||||
}
|
||||
void append(wasm::CallFarJump jmp) {
|
||||
enoughMemory_ &= callFarJumps_.append(jmp);
|
||||
|
@ -945,11 +945,11 @@ class AssemblerShared
|
|||
void append(const wasm::MemoryAccessDesc& access, size_t codeOffset, size_t framePushed) {
|
||||
if (access.hasTrap()) {
|
||||
// If a memory access is trapping (wasm, SIMD.js, Atomics), create a
|
||||
// TrapSite now which will generate a trap out-of-line path at the end
|
||||
// OldTrapSite now which will generate a trap out-of-line path at the end
|
||||
// of the function which will *then* append a MemoryAccess.
|
||||
wasm::TrapDesc trap(access.trapOffset(), wasm::Trap::OutOfBounds, framePushed,
|
||||
wasm::TrapSite::MemoryAccess);
|
||||
append(wasm::TrapSite(trap, codeOffset));
|
||||
wasm::OldTrapDesc trap(access.trapOffset(), wasm::Trap::OutOfBounds, framePushed,
|
||||
wasm::OldTrapSite::MemoryAccess);
|
||||
append(wasm::OldTrapSite(trap, codeOffset));
|
||||
} else {
|
||||
// Otherwise, this is a plain asm.js access. On WASM_HUGE_MEMORY
|
||||
// platforms, asm.js uses signal handlers to remove bounds checks
|
||||
|
@ -966,8 +966,8 @@ class AssemblerShared
|
|||
|
||||
wasm::CallSiteVector& callSites() { return callSites_; }
|
||||
wasm::CallSiteTargetVector& callSiteTargets() { return callSiteTargets_; }
|
||||
wasm::TrapSiteVector& trapSites() { return trapSites_; }
|
||||
wasm::TrapFarJumpVector& trapFarJumps() { return trapFarJumps_; }
|
||||
wasm::OldTrapSiteVector& oldTrapSites() { return oldTrapSites_; }
|
||||
wasm::OldTrapFarJumpVector& oldTrapFarJumps() { return oldTrapFarJumps_; }
|
||||
wasm::CallFarJumpVector& callFarJumps() { return callFarJumps_; }
|
||||
wasm::MemoryAccessVector& memoryAccesses() { return memoryAccesses_; }
|
||||
wasm::SymbolicAccessVector& symbolicAccesses() { return symbolicAccesses_; }
|
||||
|
|
|
@ -503,8 +503,8 @@ class CodeGeneratorShared : public LElementVisitor
|
|||
#endif
|
||||
|
||||
template <class T>
|
||||
wasm::TrapDesc trap(T* mir, wasm::Trap trap) {
|
||||
return wasm::TrapDesc(mir->bytecodeOffset(), trap, masm.framePushed());
|
||||
wasm::OldTrapDesc oldTrap(T* mir, wasm::Trap trap) {
|
||||
return wasm::OldTrapDesc(mir->bytecodeOffset(), trap, masm.framePushed());
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
|
@ -285,7 +285,7 @@ CodeGeneratorX64::visitDivOrModI64(LDivOrModI64* lir)
|
|||
|
||||
// Handle divide by zero.
|
||||
if (lir->canBeDivideByZero()) {
|
||||
masm.branchTestPtr(Assembler::Zero, rhs, rhs, trap(lir, wasm::Trap::IntegerDivideByZero));
|
||||
masm.branchTestPtr(Assembler::Zero, rhs, rhs, oldTrap(lir, wasm::Trap::IntegerDivideByZero));
|
||||
}
|
||||
|
||||
// Handle an integer overflow exception from INT64_MIN / -1.
|
||||
|
@ -296,7 +296,7 @@ CodeGeneratorX64::visitDivOrModI64(LDivOrModI64* lir)
|
|||
if (lir->mir()->isMod())
|
||||
masm.xorl(output, output);
|
||||
else
|
||||
masm.jump(trap(lir, wasm::Trap::IntegerOverflow));
|
||||
masm.jump(oldTrap(lir, wasm::Trap::IntegerOverflow));
|
||||
masm.jump(&done);
|
||||
masm.bind(¬min);
|
||||
}
|
||||
|
@ -328,7 +328,7 @@ CodeGeneratorX64::visitUDivOrModI64(LUDivOrModI64* lir)
|
|||
|
||||
// Prevent divide by zero.
|
||||
if (lir->canBeDivideByZero())
|
||||
masm.branchTestPtr(Assembler::Zero, rhs, rhs, trap(lir, wasm::Trap::IntegerDivideByZero));
|
||||
masm.branchTestPtr(Assembler::Zero, rhs, rhs, oldTrap(lir, wasm::Trap::IntegerDivideByZero));
|
||||
|
||||
// Zero extend the lhs into rdx to make (rdx:rax).
|
||||
masm.xorl(rdx, rdx);
|
||||
|
|
|
@ -922,12 +922,12 @@ class AssemblerX86Shared : public AssemblerShared
|
|||
void j(Condition cond, RepatchLabel* label) { jSrc(cond, label); }
|
||||
void jmp(RepatchLabel* label) { jmpSrc(label); }
|
||||
|
||||
void j(Condition cond, wasm::TrapDesc target) {
|
||||
void j(Condition cond, wasm::OldTrapDesc target) {
|
||||
Label l;
|
||||
j(cond, &l);
|
||||
bindLater(&l, target);
|
||||
}
|
||||
void jmp(wasm::TrapDesc target) {
|
||||
void jmp(wasm::OldTrapDesc target) {
|
||||
Label l;
|
||||
jmp(&l);
|
||||
bindLater(&l, target);
|
||||
|
@ -963,11 +963,11 @@ class AssemblerX86Shared : public AssemblerShared
|
|||
}
|
||||
label->bind(dst.offset());
|
||||
}
|
||||
void bindLater(Label* label, wasm::TrapDesc target) {
|
||||
void bindLater(Label* label, wasm::OldTrapDesc target) {
|
||||
if (label->used()) {
|
||||
JmpSrc jmp(label->offset());
|
||||
do {
|
||||
append(wasm::TrapSite(target, jmp.offset()));
|
||||
append(wasm::OldTrapSite(target, jmp.offset()));
|
||||
} while (masm.nextJump(jmp, &jmp));
|
||||
}
|
||||
label->reset();
|
||||
|
|
|
@ -435,7 +435,7 @@ CodeGeneratorX86Shared::visitWasmAddOffset(LWasmAddOffset* lir)
|
|||
masm.move32(base, out);
|
||||
masm.add32(Imm32(mir->offset()), out);
|
||||
|
||||
masm.j(Assembler::CarrySet, trap(mir, wasm::Trap::OutOfBounds));
|
||||
masm.j(Assembler::CarrySet, oldTrap(mir, wasm::Trap::OutOfBounds));
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1026,7 +1026,7 @@ CodeGeneratorX86Shared::visitUDivOrMod(LUDivOrMod* ins)
|
|||
masm.test32(rhs, rhs);
|
||||
if (ins->mir()->isTruncated()) {
|
||||
if (ins->trapOnError()) {
|
||||
masm.j(Assembler::Zero, trap(ins, wasm::Trap::IntegerDivideByZero));
|
||||
masm.j(Assembler::Zero, oldTrap(ins, wasm::Trap::IntegerDivideByZero));
|
||||
} else {
|
||||
ool = new(alloc()) ReturnZero(output);
|
||||
masm.j(Assembler::Zero, ool->entry());
|
||||
|
@ -1074,7 +1074,7 @@ CodeGeneratorX86Shared::visitUDivOrModConstant(LUDivOrModConstant *ins) {
|
|||
if (d == 0) {
|
||||
if (ins->mir()->isTruncated()) {
|
||||
if (ins->trapOnError())
|
||||
masm.jump(trap(ins, wasm::Trap::IntegerDivideByZero));
|
||||
masm.jump(oldTrap(ins, wasm::Trap::IntegerDivideByZero));
|
||||
else
|
||||
masm.xorl(output, output);
|
||||
} else {
|
||||
|
@ -1213,7 +1213,7 @@ CodeGeneratorX86Shared::visitDivPowTwoI(LDivPowTwoI* ins)
|
|||
if (!mir->isTruncated())
|
||||
bailoutIf(Assembler::Overflow, ins->snapshot());
|
||||
else if (mir->trapOnError())
|
||||
masm.j(Assembler::Overflow, trap(mir, wasm::Trap::IntegerOverflow));
|
||||
masm.j(Assembler::Overflow, oldTrap(mir, wasm::Trap::IntegerOverflow));
|
||||
} else if (mir->isUnsigned() && !mir->isTruncated()) {
|
||||
// Unsigned division by 1 can overflow if output is not
|
||||
// truncated.
|
||||
|
@ -1332,7 +1332,7 @@ CodeGeneratorX86Shared::visitDivI(LDivI* ins)
|
|||
if (mir->canBeDivideByZero()) {
|
||||
masm.test32(rhs, rhs);
|
||||
if (mir->trapOnError()) {
|
||||
masm.j(Assembler::Zero, trap(mir, wasm::Trap::IntegerDivideByZero));
|
||||
masm.j(Assembler::Zero, oldTrap(mir, wasm::Trap::IntegerDivideByZero));
|
||||
} else if (mir->canTruncateInfinities()) {
|
||||
// Truncated division by zero is zero (Infinity|0 == 0)
|
||||
if (!ool)
|
||||
|
@ -1351,7 +1351,7 @@ CodeGeneratorX86Shared::visitDivI(LDivI* ins)
|
|||
masm.j(Assembler::NotEqual, ¬min);
|
||||
masm.cmp32(rhs, Imm32(-1));
|
||||
if (mir->trapOnError()) {
|
||||
masm.j(Assembler::Equal, trap(mir, wasm::Trap::IntegerOverflow));
|
||||
masm.j(Assembler::Equal, oldTrap(mir, wasm::Trap::IntegerOverflow));
|
||||
} else if (mir->canTruncateOverflow()) {
|
||||
// (-INT32_MIN)|0 == INT32_MIN and INT32_MIN is already in the
|
||||
// output register (lhs == eax).
|
||||
|
@ -1501,7 +1501,7 @@ CodeGeneratorX86Shared::visitModI(LModI* ins)
|
|||
masm.test32(rhs, rhs);
|
||||
if (mir->isTruncated()) {
|
||||
if (mir->trapOnError()) {
|
||||
masm.j(Assembler::Zero, trap(mir, wasm::Trap::IntegerDivideByZero));
|
||||
masm.j(Assembler::Zero, oldTrap(mir, wasm::Trap::IntegerDivideByZero));
|
||||
} else {
|
||||
if (!ool)
|
||||
ool = new(alloc()) ReturnZero(edx);
|
||||
|
@ -2523,7 +2523,7 @@ CodeGeneratorX86Shared::visitOutOfLineSimdFloatToIntCheck(OutOfLineSimdFloatToIn
|
|||
masm.jump(ool->rejoin());
|
||||
|
||||
if (gen->compilingWasm()) {
|
||||
masm.bindLater(&onConversionError, trap(ool, wasm::Trap::ImpreciseSimdConversion));
|
||||
masm.bindLater(&onConversionError, oldTrap(ool, wasm::Trap::ImpreciseSimdConversion));
|
||||
} else {
|
||||
masm.bind(&onConversionError);
|
||||
bailout(ool->ins()->snapshot());
|
||||
|
@ -2603,7 +2603,7 @@ CodeGeneratorX86Shared::visitFloat32x4ToUint32x4(LFloat32x4ToUint32x4* ins)
|
|||
masm.cmp32(temp, Imm32(0));
|
||||
|
||||
if (gen->compilingWasm())
|
||||
masm.j(Assembler::NotEqual, trap(mir, wasm::Trap::ImpreciseSimdConversion));
|
||||
masm.j(Assembler::NotEqual, oldTrap(mir, wasm::Trap::ImpreciseSimdConversion));
|
||||
else
|
||||
bailoutIf(Assembler::NotEqual, ins->snapshot());
|
||||
}
|
||||
|
|
|
@ -686,10 +686,10 @@ struct MOZ_RAII AutoHandleWasmTruncateToIntErrors
|
|||
~AutoHandleWasmTruncateToIntErrors() {
|
||||
// Handle errors.
|
||||
masm.bind(&fail);
|
||||
masm.jump(wasm::TrapDesc(off, wasm::Trap::IntegerOverflow, masm.framePushed()));
|
||||
masm.jump(wasm::OldTrapDesc(off, wasm::Trap::IntegerOverflow, masm.framePushed()));
|
||||
|
||||
masm.bind(&inputIsNaN);
|
||||
masm.jump(wasm::TrapDesc(off, wasm::Trap::InvalidConversionToInteger, masm.framePushed()));
|
||||
masm.jump(wasm::OldTrapDesc(off, wasm::Trap::InvalidConversionToInteger, masm.framePushed()));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -202,7 +202,7 @@ class MacroAssemblerX86Shared : public Assembler
|
|||
void jump(const Address& addr) {
|
||||
jmp(Operand(addr));
|
||||
}
|
||||
void jump(wasm::TrapDesc target) {
|
||||
void jump(wasm::OldTrapDesc target) {
|
||||
jmp(target);
|
||||
}
|
||||
|
||||
|
|
|
@ -1031,7 +1031,7 @@ CodeGeneratorX86::visitDivOrModI64(LDivOrModI64* lir)
|
|||
|
||||
// Handle divide by zero.
|
||||
if (lir->canBeDivideByZero())
|
||||
masm.branchTest64(Assembler::Zero, rhs, rhs, temp, trap(lir, wasm::Trap::IntegerDivideByZero));
|
||||
masm.branchTest64(Assembler::Zero, rhs, rhs, temp, oldTrap(lir, wasm::Trap::IntegerDivideByZero));
|
||||
|
||||
MDefinition* mir = lir->mir();
|
||||
|
||||
|
@ -1043,7 +1043,7 @@ CodeGeneratorX86::visitDivOrModI64(LDivOrModI64* lir)
|
|||
if (mir->isMod())
|
||||
masm.xor64(output, output);
|
||||
else
|
||||
masm.jump(trap(lir, wasm::Trap::IntegerOverflow));
|
||||
masm.jump(oldTrap(lir, wasm::Trap::IntegerOverflow));
|
||||
masm.jump(&done);
|
||||
masm.bind(¬min);
|
||||
}
|
||||
|
@ -1079,7 +1079,7 @@ CodeGeneratorX86::visitUDivOrModI64(LUDivOrModI64* lir)
|
|||
|
||||
// Prevent divide by zero.
|
||||
if (lir->canBeDivideByZero())
|
||||
masm.branchTest64(Assembler::Zero, rhs, rhs, temp, trap(lir, wasm::Trap::IntegerDivideByZero));
|
||||
masm.branchTest64(Assembler::Zero, rhs, rhs, temp, oldTrap(lir, wasm::Trap::IntegerDivideByZero));
|
||||
|
||||
masm.setupWasmABICall();
|
||||
masm.passABIArg(lhs.high);
|
||||
|
|
|
@ -20,6 +20,9 @@
|
|||
#include "vm/ErrorReporting.h"
|
||||
#include "vm/MallocProvider.h"
|
||||
#include "vm/Runtime.h"
|
||||
#ifdef XP_DARWIN
|
||||
# include "wasm/WasmSignalHandlers.h"
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
|
|
|
@ -22,9 +22,6 @@
|
|||
#include "jsatom.h"
|
||||
#include "jsscript.h"
|
||||
|
||||
#ifdef XP_DARWIN
|
||||
# include "wasm/WasmSignalHandlers.h"
|
||||
#endif
|
||||
#include "builtin/AtomicsObject.h"
|
||||
#include "builtin/Intl.h"
|
||||
#include "builtin/Promise.h"
|
||||
|
|
|
@ -1709,7 +1709,7 @@ jit::JitActivation::startWasmInterrupt(const JS::ProfilingFrameIterator::Registe
|
|||
|
||||
bool ignoredUnwound;
|
||||
wasm::UnwindState unwindState;
|
||||
MOZ_ALWAYS_TRUE(wasm::StartUnwinding(*this, state, &unwindState, &ignoredUnwound));
|
||||
MOZ_ALWAYS_TRUE(wasm::StartUnwinding(state, &unwindState, &ignoredUnwound));
|
||||
|
||||
void* pc = unwindState.pc;
|
||||
MOZ_ASSERT(wasm::LookupCode(pc)->lookupRange(pc)->isFunction());
|
||||
|
|
|
@ -3020,7 +3020,7 @@ class BaseCompiler final : public BaseCompilerInterface
|
|||
if (fr.initialSize() > debugFrameReserved)
|
||||
masm.addToStackPtr(Imm32(fr.initialSize() - debugFrameReserved));
|
||||
BytecodeOffset prologueTrapOffset(func_.lineOrBytecode);
|
||||
masm.jump(TrapDesc(prologueTrapOffset, Trap::StackOverflow, debugFrameReserved));
|
||||
masm.jump(OldTrapDesc(prologueTrapOffset, Trap::StackOverflow, debugFrameReserved));
|
||||
|
||||
masm.bind(&returnLabel_);
|
||||
|
||||
|
@ -3045,7 +3045,7 @@ class BaseCompiler final : public BaseCompilerInterface
|
|||
if (!generateOutOfLineCode())
|
||||
return false;
|
||||
|
||||
masm.wasmEmitTrapOutOfLineCode();
|
||||
masm.wasmEmitOldTrapOutOfLineCode();
|
||||
|
||||
offsets_.end = masm.currentOffset();
|
||||
|
||||
|
@ -3453,12 +3453,12 @@ class BaseCompiler final : public BaseCompilerInterface
|
|||
}
|
||||
|
||||
void checkDivideByZeroI32(RegI32 rhs, RegI32 srcDest, Label* done) {
|
||||
masm.branchTest32(Assembler::Zero, rhs, rhs, trap(Trap::IntegerDivideByZero));
|
||||
masm.branchTest32(Assembler::Zero, rhs, rhs, oldTrap(Trap::IntegerDivideByZero));
|
||||
}
|
||||
|
||||
void checkDivideByZeroI64(RegI64 r) {
|
||||
ScratchI32 scratch(*this);
|
||||
masm.branchTest64(Assembler::Zero, r, r, scratch, trap(Trap::IntegerDivideByZero));
|
||||
masm.branchTest64(Assembler::Zero, r, r, scratch, oldTrap(Trap::IntegerDivideByZero));
|
||||
}
|
||||
|
||||
void checkDivideSignedOverflowI32(RegI32 rhs, RegI32 srcDest, Label* done, bool zeroOnOverflow) {
|
||||
|
@ -3469,7 +3469,7 @@ class BaseCompiler final : public BaseCompilerInterface
|
|||
moveImm32(0, srcDest);
|
||||
masm.jump(done);
|
||||
} else {
|
||||
masm.branch32(Assembler::Equal, rhs, Imm32(-1), trap(Trap::IntegerOverflow));
|
||||
masm.branch32(Assembler::Equal, rhs, Imm32(-1), oldTrap(Trap::IntegerOverflow));
|
||||
}
|
||||
masm.bind(¬Min);
|
||||
}
|
||||
|
@ -3482,7 +3482,7 @@ class BaseCompiler final : public BaseCompilerInterface
|
|||
masm.xor64(srcDest, srcDest);
|
||||
masm.jump(done);
|
||||
} else {
|
||||
masm.jump(trap(Trap::IntegerOverflow));
|
||||
masm.jump(oldTrap(Trap::IntegerOverflow));
|
||||
}
|
||||
masm.bind(¬min);
|
||||
}
|
||||
|
@ -3809,7 +3809,7 @@ class BaseCompiler final : public BaseCompilerInterface
|
|||
|
||||
void unreachableTrap()
|
||||
{
|
||||
masm.jump(trap(Trap::Unreachable));
|
||||
masm.jump(oldTrap(Trap::Unreachable));
|
||||
#ifdef DEBUG
|
||||
masm.breakpoint();
|
||||
#endif
|
||||
|
@ -3940,7 +3940,7 @@ class BaseCompiler final : public BaseCompilerInterface
|
|||
(access->isAtomic() && !check->omitAlignmentCheck && !check->onlyPointerAlignment))
|
||||
{
|
||||
masm.branchAdd32(Assembler::CarrySet, Imm32(access->offset()), ptr,
|
||||
trap(Trap::OutOfBounds));
|
||||
oldTrap(Trap::OutOfBounds));
|
||||
access->clearOffset();
|
||||
check->onlyPointerAlignment = true;
|
||||
}
|
||||
|
@ -3951,7 +3951,7 @@ class BaseCompiler final : public BaseCompilerInterface
|
|||
MOZ_ASSERT(check->onlyPointerAlignment);
|
||||
// We only care about the low pointer bits here.
|
||||
masm.branchTest32(Assembler::NonZero, ptr, Imm32(access->byteSize() - 1),
|
||||
trap(Trap::UnalignedAccess));
|
||||
oldTrap(Trap::UnalignedAccess));
|
||||
}
|
||||
|
||||
// Ensure no tls if we don't need it.
|
||||
|
@ -3972,7 +3972,7 @@ class BaseCompiler final : public BaseCompilerInterface
|
|||
if (!check->omitBoundsCheck) {
|
||||
masm.wasmBoundsCheck(Assembler::AboveOrEqual, ptr,
|
||||
Address(tls, offsetof(TlsData, boundsCheckLimit)),
|
||||
trap(Trap::OutOfBounds));
|
||||
oldTrap(Trap::OutOfBounds));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -4905,11 +4905,11 @@ class BaseCompiler final : public BaseCompilerInterface
|
|||
return iter_.bytecodeOffset();
|
||||
}
|
||||
|
||||
TrapDesc trap(Trap t) const {
|
||||
OldTrapDesc oldTrap(Trap t) const {
|
||||
// Use masm.framePushed() because the value needed by the trap machinery
|
||||
// is the size of the frame overall, not the height of the stack area of
|
||||
// the frame.
|
||||
return TrapDesc(bytecodeOffset(), t, masm.framePushed());
|
||||
return OldTrapDesc(bytecodeOffset(), t, masm.framePushed());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
@ -8395,7 +8395,7 @@ BaseCompiler::emitWait(ValType type, uint32_t byteSize)
|
|||
default:
|
||||
MOZ_CRASH();
|
||||
}
|
||||
masm.branchTest32(Assembler::Signed, ReturnReg, ReturnReg, trap(Trap::ThrowReported));
|
||||
masm.branchTest32(Assembler::Signed, ReturnReg, ReturnReg, oldTrap(Trap::ThrowReported));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -8414,7 +8414,7 @@ BaseCompiler::emitWake()
|
|||
return true;
|
||||
|
||||
emitInstanceCall(lineOrBytecode, SigPII_, ExprType::I32, SymbolicAddress::Wake);
|
||||
masm.branchTest32(Assembler::Signed, ReturnReg, ReturnReg, trap(Trap::ThrowReported));
|
||||
masm.branchTest32(Assembler::Signed, ReturnReg, ReturnReg, oldTrap(Trap::ThrowReported));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -96,17 +96,24 @@ static bool
|
|||
WasmHandleDebugTrap()
|
||||
{
|
||||
JitActivation* activation = CallingActivation();
|
||||
MOZ_ASSERT(activation);
|
||||
JSContext* cx = activation->cx();
|
||||
Frame* fp = activation->wasmExitFP();
|
||||
Instance* instance = fp->tls->instance;
|
||||
const Code& code = instance->code();
|
||||
MOZ_ASSERT(code.metadata().debugEnabled);
|
||||
|
||||
WasmFrameIter frame(activation);
|
||||
MOZ_ASSERT(frame.debugEnabled());
|
||||
const CallSite* site = frame.debugTrapCallsite();
|
||||
// The debug trap stub is the innermost frame. It's return address is the
|
||||
// actual trap site.
|
||||
const CallSite* site = code.lookupCallSite(fp->returnAddress);
|
||||
MOZ_ASSERT(site);
|
||||
|
||||
// Advance to the actual trapping frame.
|
||||
fp = fp->callerFP;
|
||||
DebugFrame* debugFrame = DebugFrame::from(fp);
|
||||
|
||||
if (site->kind() == CallSite::EnterFrame) {
|
||||
if (!frame.instance()->enterFrameTrapsEnabled())
|
||||
if (!instance->enterFrameTrapsEnabled())
|
||||
return true;
|
||||
DebugFrame* debugFrame = frame.debugFrame();
|
||||
debugFrame->setIsDebuggee();
|
||||
debugFrame->observe(cx);
|
||||
// TODO call onEnterFrame
|
||||
|
@ -121,15 +128,13 @@ WasmHandleDebugTrap()
|
|||
return status == JSTRAP_CONTINUE;
|
||||
}
|
||||
if (site->kind() == CallSite::LeaveFrame) {
|
||||
DebugFrame* debugFrame = frame.debugFrame();
|
||||
debugFrame->updateReturnJSValue();
|
||||
bool ok = Debugger::onLeaveFrame(cx, debugFrame, nullptr, true);
|
||||
debugFrame->leave(cx);
|
||||
return ok;
|
||||
}
|
||||
|
||||
DebugFrame* debugFrame = frame.debugFrame();
|
||||
DebugState& debug = frame.instance()->debug();
|
||||
DebugState& debug = instance->debug();
|
||||
MOZ_ASSERT(debug.hasBreakpointTrapAtOffset(site->lineOrBytecode()));
|
||||
if (debug.stepModeEnabled(debugFrame->funcIndex())) {
|
||||
RootedValue result(cx, UndefinedValue());
|
||||
|
@ -234,7 +239,7 @@ WasmHandleThrow()
|
|||
}
|
||||
|
||||
static void
|
||||
WasmReportTrap(int32_t trapIndex)
|
||||
WasmOldReportTrap(int32_t trapIndex)
|
||||
{
|
||||
JSContext* cx = TlsContext.get();
|
||||
|
||||
|
@ -439,9 +444,9 @@ AddressOf(SymbolicAddress imm, ABIFunctionType* abiType)
|
|||
case SymbolicAddress::HandleThrow:
|
||||
*abiType = Args_General0;
|
||||
return FuncCast(WasmHandleThrow, *abiType);
|
||||
case SymbolicAddress::ReportTrap:
|
||||
case SymbolicAddress::OldReportTrap:
|
||||
*abiType = Args_General1;
|
||||
return FuncCast(WasmReportTrap, *abiType);
|
||||
return FuncCast(WasmOldReportTrap, *abiType);
|
||||
case SymbolicAddress::ReportOutOfBounds:
|
||||
*abiType = Args_General0;
|
||||
return FuncCast(WasmReportOutOfBounds, *abiType);
|
||||
|
@ -595,7 +600,7 @@ wasm::NeedsBuiltinThunk(SymbolicAddress sym)
|
|||
case SymbolicAddress::HandleExecutionInterrupt: // GenerateInterruptExit
|
||||
case SymbolicAddress::HandleDebugTrap: // GenerateDebugTrapStub
|
||||
case SymbolicAddress::HandleThrow: // GenerateThrowStub
|
||||
case SymbolicAddress::ReportTrap: // GenerateTrapExit
|
||||
case SymbolicAddress::OldReportTrap: // GenerateOldTrapExit
|
||||
case SymbolicAddress::ReportOutOfBounds: // GenerateOutOfBoundsExit
|
||||
case SymbolicAddress::ReportUnalignedAccess: // GeneratesUnalignedExit
|
||||
case SymbolicAddress::CallImport_Void: // GenerateImportInterpExit
|
||||
|
@ -891,8 +896,8 @@ wasm::EnsureBuiltinThunksInitialized()
|
|||
MOZ_ASSERT(masm.callSites().empty());
|
||||
MOZ_ASSERT(masm.callSiteTargets().empty());
|
||||
MOZ_ASSERT(masm.callFarJumps().empty());
|
||||
MOZ_ASSERT(masm.trapSites().empty());
|
||||
MOZ_ASSERT(masm.trapFarJumps().empty());
|
||||
MOZ_ASSERT(masm.oldTrapSites().empty());
|
||||
MOZ_ASSERT(masm.oldTrapFarJumps().empty());
|
||||
MOZ_ASSERT(masm.callFarJumps().empty());
|
||||
MOZ_ASSERT(masm.memoryAccesses().empty());
|
||||
MOZ_ASSERT(masm.symbolicAccesses().empty());
|
||||
|
|
|
@ -767,46 +767,6 @@ struct CallSiteRetAddrOffset
|
|||
}
|
||||
};
|
||||
|
||||
size_t
|
||||
Code::serializedSize() const
|
||||
{
|
||||
return metadata().serializedSize() +
|
||||
segment(Tier::Serialized).serializedSize();
|
||||
}
|
||||
|
||||
uint8_t*
|
||||
Code::serialize(uint8_t* cursor, const LinkData& linkData) const
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(!metadata().debugEnabled);
|
||||
|
||||
cursor = metadata().serialize(cursor);
|
||||
cursor = segment(Tier::Serialized).serialize(cursor, linkData.linkData(Tier::Serialized));
|
||||
return cursor;
|
||||
}
|
||||
|
||||
const uint8_t*
|
||||
Code::deserialize(const uint8_t* cursor, const SharedBytes& bytecode, const LinkData& linkData,
|
||||
Metadata& metadata)
|
||||
{
|
||||
cursor = metadata.deserialize(cursor);
|
||||
if (!cursor)
|
||||
return nullptr;
|
||||
|
||||
UniqueCodeSegment codeSegment = js::MakeUnique<CodeSegment>();
|
||||
if (!codeSegment)
|
||||
return nullptr;
|
||||
|
||||
cursor = codeSegment->deserialize(cursor, *bytecode, linkData.linkData(Tier::Serialized),
|
||||
metadata);
|
||||
if (!cursor)
|
||||
return nullptr;
|
||||
|
||||
segment1_ = takeOwnership(Move(codeSegment));
|
||||
metadata_ = &metadata;
|
||||
|
||||
return cursor;
|
||||
}
|
||||
|
||||
const CallSite*
|
||||
Code::lookupCallSite(void* returnAddress) const
|
||||
{
|
||||
|
@ -959,3 +919,43 @@ Code::addSizeOfMiscIfNotSeen(MallocSizeOf mallocSizeOf,
|
|||
for (auto t : tiers())
|
||||
segment(t).addSizeOfMisc(mallocSizeOf, code, data);
|
||||
}
|
||||
|
||||
size_t
|
||||
Code::serializedSize() const
|
||||
{
|
||||
return metadata().serializedSize() +
|
||||
segment(Tier::Serialized).serializedSize();
|
||||
}
|
||||
|
||||
uint8_t*
|
||||
Code::serialize(uint8_t* cursor, const LinkData& linkData) const
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(!metadata().debugEnabled);
|
||||
|
||||
cursor = metadata().serialize(cursor);
|
||||
cursor = segment(Tier::Serialized).serialize(cursor, linkData.linkData(Tier::Serialized));
|
||||
return cursor;
|
||||
}
|
||||
|
||||
const uint8_t*
|
||||
Code::deserialize(const uint8_t* cursor, const SharedBytes& bytecode, const LinkData& linkData,
|
||||
Metadata& metadata)
|
||||
{
|
||||
cursor = metadata.deserialize(cursor);
|
||||
if (!cursor)
|
||||
return nullptr;
|
||||
|
||||
UniqueCodeSegment codeSegment = js::MakeUnique<CodeSegment>();
|
||||
if (!codeSegment)
|
||||
return nullptr;
|
||||
|
||||
cursor = codeSegment->deserialize(cursor, *bytecode, linkData.linkData(Tier::Serialized),
|
||||
metadata);
|
||||
if (!cursor)
|
||||
return nullptr;
|
||||
|
||||
segment1_ = takeOwnership(Move(codeSegment));
|
||||
metadata_ = &metadata;
|
||||
|
||||
return cursor;
|
||||
}
|
||||
|
|
|
@ -130,7 +130,7 @@ class CodeSegment
|
|||
code_ = code;
|
||||
}
|
||||
|
||||
const Code* code() const { MOZ_ASSERT(code_); return code_; }
|
||||
const Code& code() const { MOZ_ASSERT(code_); return *code_; }
|
||||
Tier tier() const { return tier_; }
|
||||
|
||||
uint8_t* base() const { return bytes_.get(); }
|
||||
|
|
|
@ -35,24 +35,13 @@ using mozilla::Swap;
|
|||
WasmFrameIter::WasmFrameIter(JitActivation* activation, wasm::Frame* fp)
|
||||
: activation_(activation),
|
||||
code_(nullptr),
|
||||
callsite_(nullptr),
|
||||
codeRange_(nullptr),
|
||||
lineOrBytecode_(0),
|
||||
fp_(fp ? fp : activation->wasmExitFP()),
|
||||
unwind_(Unwind::False)
|
||||
{
|
||||
MOZ_ASSERT(fp_);
|
||||
|
||||
// Normally, execution exits wasm code via an exit stub which sets exitFP
|
||||
// to the exit stub's frame. Thus, in this case, we want to start iteration
|
||||
// at the caller of the exit frame, whose Code, CodeRange and CallSite are
|
||||
// indicated by the returnAddress of the exit stub's frame.
|
||||
|
||||
if (!activation->isWasmInterrupted()) {
|
||||
popFrame();
|
||||
MOZ_ASSERT(!done());
|
||||
return;
|
||||
}
|
||||
|
||||
// When asynchronously interrupted, exitFP is set to the interrupted frame
|
||||
// itself and so we do not want to skip it. Instead, we can recover the
|
||||
// Code and CodeRange from the JitActivation, which are set when control
|
||||
|
@ -61,12 +50,25 @@ WasmFrameIter::WasmFrameIter(JitActivation* activation, wasm::Frame* fp)
|
|||
// for which we can use the beginning of the function from the CodeRange
|
||||
// instead.
|
||||
|
||||
code_ = &fp_->tls->instance->code();
|
||||
MOZ_ASSERT(code_ == LookupCode(activation->wasmUnwindPC()));
|
||||
if (activation->isWasmInterrupted()) {
|
||||
code_ = &fp_->tls->instance->code();
|
||||
MOZ_ASSERT(code_ == LookupCode(activation->wasmUnwindPC()));
|
||||
|
||||
codeRange_ = code_->lookupRange(activation->wasmUnwindPC());
|
||||
MOZ_ASSERT(codeRange_->kind() == CodeRange::Function);
|
||||
codeRange_ = code_->lookupRange(activation->wasmUnwindPC());
|
||||
MOZ_ASSERT(codeRange_->kind() == CodeRange::Function);
|
||||
|
||||
lineOrBytecode_ = codeRange_->funcLineOrBytecode();
|
||||
|
||||
MOZ_ASSERT(!done());
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise, execution exits wasm code via an exit stub which sets exitFP
|
||||
// to the exit stub's frame. Thus, in this case, we want to start iteration
|
||||
// at the caller of the exit frame, whose Code, CodeRange and CallSite are
|
||||
// indicated by the returnAddress of the exit stub's frame.
|
||||
|
||||
popFrame();
|
||||
MOZ_ASSERT(!done());
|
||||
}
|
||||
|
||||
|
@ -112,7 +114,6 @@ WasmFrameIter::popFrame()
|
|||
if (!fp_) {
|
||||
code_ = nullptr;
|
||||
codeRange_ = nullptr;
|
||||
callsite_ = nullptr;
|
||||
|
||||
if (unwind_ == Unwind::True) {
|
||||
// TODO with bug 1319203, there may be other JIT frames above.
|
||||
|
@ -132,8 +133,10 @@ WasmFrameIter::popFrame()
|
|||
codeRange_ = code_->lookupRange(returnAddress);
|
||||
MOZ_ASSERT(codeRange_->kind() == CodeRange::Function);
|
||||
|
||||
callsite_ = code_->lookupCallSite(returnAddress);
|
||||
MOZ_ASSERT(callsite_);
|
||||
const CallSite* callsite = code_->lookupCallSite(returnAddress);
|
||||
MOZ_ASSERT(callsite);
|
||||
|
||||
lineOrBytecode_ = callsite->lineOrBytecode();
|
||||
|
||||
MOZ_ASSERT(!done());
|
||||
}
|
||||
|
@ -178,8 +181,7 @@ unsigned
|
|||
WasmFrameIter::lineOrBytecode() const
|
||||
{
|
||||
MOZ_ASSERT(!done());
|
||||
MOZ_ASSERT_IF(!callsite_, activation_->isWasmInterrupted());
|
||||
return callsite_ ? callsite_->lineOrBytecode() : codeRange_->funcLineOrBytecode();
|
||||
return lineOrBytecode_;
|
||||
}
|
||||
|
||||
Instance*
|
||||
|
@ -216,20 +218,7 @@ DebugFrame*
|
|||
WasmFrameIter::debugFrame() const
|
||||
{
|
||||
MOZ_ASSERT(!done());
|
||||
MOZ_ASSERT(debugEnabled());
|
||||
return reinterpret_cast<DebugFrame*>((uint8_t*)fp_ - DebugFrame::offsetOfFrame());
|
||||
}
|
||||
|
||||
const CallSite*
|
||||
WasmFrameIter::debugTrapCallsite() const
|
||||
{
|
||||
MOZ_ASSERT(!done());
|
||||
MOZ_ASSERT(callsite_);
|
||||
MOZ_ASSERT(debugEnabled());
|
||||
MOZ_ASSERT(callsite_->kind() == CallSite::EnterFrame ||
|
||||
callsite_->kind() == CallSite::LeaveFrame ||
|
||||
callsite_->kind() == CallSite::Breakpoint);
|
||||
return callsite_;
|
||||
return DebugFrame::from(fp_);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
@ -446,7 +435,7 @@ wasm::GenerateFunctionPrologue(MacroAssembler& masm, unsigned framePushed, const
|
|||
// Generate table entry:
|
||||
offsets->begin = masm.currentOffset();
|
||||
BytecodeOffset trapOffset(0); // ignored by masm.wasmEmitTrapOutOfLineCode
|
||||
TrapDesc trap(trapOffset, Trap::IndirectCallBadSig, masm.framePushed());
|
||||
OldTrapDesc trap(trapOffset, Trap::IndirectCallBadSig, masm.framePushed());
|
||||
switch (sigId.kind()) {
|
||||
case SigIdDesc::Kind::Global: {
|
||||
Register scratch = WasmTableCallScratchReg;
|
||||
|
@ -547,8 +536,7 @@ wasm::GenerateJitExitEpilogue(MacroAssembler& masm, unsigned framePushed, Callab
|
|||
// ProfilingFrameIterator
|
||||
|
||||
ProfilingFrameIterator::ProfilingFrameIterator()
|
||||
: activation_(nullptr),
|
||||
code_(nullptr),
|
||||
: code_(nullptr),
|
||||
codeRange_(nullptr),
|
||||
callerFP_(nullptr),
|
||||
callerPC_(nullptr),
|
||||
|
@ -559,8 +547,7 @@ ProfilingFrameIterator::ProfilingFrameIterator()
|
|||
}
|
||||
|
||||
ProfilingFrameIterator::ProfilingFrameIterator(const JitActivation& activation)
|
||||
: activation_(&activation),
|
||||
code_(nullptr),
|
||||
: code_(nullptr),
|
||||
codeRange_(nullptr),
|
||||
callerFP_(nullptr),
|
||||
callerPC_(nullptr),
|
||||
|
@ -571,8 +558,7 @@ ProfilingFrameIterator::ProfilingFrameIterator(const JitActivation& activation)
|
|||
}
|
||||
|
||||
ProfilingFrameIterator::ProfilingFrameIterator(const JitActivation& activation, const Frame* fp)
|
||||
: activation_(&activation),
|
||||
code_(nullptr),
|
||||
: code_(nullptr),
|
||||
codeRange_(nullptr),
|
||||
callerFP_(nullptr),
|
||||
callerPC_(nullptr),
|
||||
|
@ -584,7 +570,7 @@ ProfilingFrameIterator::ProfilingFrameIterator(const JitActivation& activation,
|
|||
}
|
||||
|
||||
static inline void
|
||||
AssertMatchesCallSite(const JitActivation& activation, void* callerPC, Frame* callerFP)
|
||||
AssertMatchesCallSite(void* callerPC, Frame* callerFP)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
const Code* code = LookupCode(callerPC);
|
||||
|
@ -633,12 +619,12 @@ ProfilingFrameIterator::initFromExitFP(const Frame* fp)
|
|||
fp = fp->callerFP;
|
||||
callerPC_ = fp->returnAddress;
|
||||
callerFP_ = fp->callerFP;
|
||||
AssertMatchesCallSite(*activation_, callerPC_, callerFP_);
|
||||
AssertMatchesCallSite(callerPC_, callerFP_);
|
||||
break;
|
||||
case CodeRange::ImportJitExit:
|
||||
case CodeRange::ImportInterpExit:
|
||||
case CodeRange::BuiltinThunk:
|
||||
case CodeRange::TrapExit:
|
||||
case CodeRange::OldTrapExit:
|
||||
case CodeRange::DebugTrap:
|
||||
case CodeRange::OutOfBoundsExit:
|
||||
case CodeRange::UnalignedExit:
|
||||
|
@ -652,8 +638,8 @@ ProfilingFrameIterator::initFromExitFP(const Frame* fp)
|
|||
}
|
||||
|
||||
bool
|
||||
js::wasm::StartUnwinding(const JitActivation& activation, const RegisterState& registers,
|
||||
UnwindState* unwindState, bool* unwoundCaller)
|
||||
js::wasm::StartUnwinding(const RegisterState& registers, UnwindState* unwindState,
|
||||
bool* unwoundCaller)
|
||||
{
|
||||
// Shorthands.
|
||||
uint8_t* const pc = (uint8_t*) registers.pc;
|
||||
|
@ -673,7 +659,7 @@ js::wasm::StartUnwinding(const JitActivation& activation, const RegisterState& r
|
|||
|
||||
const CodeSegment* codeSegment = LookupCodeSegment(pc);
|
||||
if (codeSegment) {
|
||||
code = codeSegment->code();
|
||||
code = &codeSegment->code();
|
||||
codeRange = code->lookupRange(pc);
|
||||
codeBase = codeSegment->base();
|
||||
} else if (!LookupBuiltinThunk(pc, &codeRange, &codeBase)) {
|
||||
|
@ -717,7 +703,7 @@ js::wasm::StartUnwinding(const JitActivation& activation, const RegisterState& r
|
|||
case CodeRange::ImportJitExit:
|
||||
case CodeRange::ImportInterpExit:
|
||||
case CodeRange::BuiltinThunk:
|
||||
case CodeRange::TrapExit:
|
||||
case CodeRange::OldTrapExit:
|
||||
case CodeRange::DebugTrap:
|
||||
#if defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
|
||||
if ((offsetFromEntry >= BeforePushRetAddr && offsetFromEntry < PushedFP) || codeRange->isThunk()) {
|
||||
|
@ -731,14 +717,14 @@ js::wasm::StartUnwinding(const JitActivation& activation, const RegisterState& r
|
|||
// fp holds the caller's fp.
|
||||
fixedPC = (uint8_t*) registers.lr;
|
||||
fixedFP = fp;
|
||||
AssertMatchesCallSite(activation, fixedPC, fixedFP);
|
||||
AssertMatchesCallSite(fixedPC, fixedFP);
|
||||
} else
|
||||
#elif defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64)
|
||||
if (offsetFromEntry == BeforePushRetAddr || codeRange->isThunk()) {
|
||||
// The return address is still in lr and fp holds the caller's fp.
|
||||
fixedPC = (uint8_t*) registers.lr;
|
||||
fixedFP = fp;
|
||||
AssertMatchesCallSite(activation, fixedPC, fixedFP);
|
||||
AssertMatchesCallSite(fixedPC, fixedFP);
|
||||
} else
|
||||
#endif
|
||||
if (offsetFromEntry == PushedRetAddr || codeRange->isThunk()) {
|
||||
|
@ -746,26 +732,26 @@ js::wasm::StartUnwinding(const JitActivation& activation, const RegisterState& r
|
|||
// points to the caller's fp.
|
||||
fixedPC = sp[0];
|
||||
fixedFP = fp;
|
||||
AssertMatchesCallSite(activation, fixedPC, fixedFP);
|
||||
AssertMatchesCallSite(fixedPC, fixedFP);
|
||||
} else if (offsetFromEntry >= PushedTLS && offsetFromEntry < PushedFP) {
|
||||
// The return address and caller's TLS have been pushed on the
|
||||
// stack; fp is still the caller's fp.
|
||||
fixedPC = sp[1];
|
||||
fixedFP = fp;
|
||||
AssertMatchesCallSite(activation, fixedPC, fixedFP);
|
||||
AssertMatchesCallSite(fixedPC, fixedFP);
|
||||
} else if (offsetFromEntry == PushedFP) {
|
||||
// The full Frame has been pushed; fp is still the caller's fp.
|
||||
MOZ_ASSERT(fp == reinterpret_cast<Frame*>(sp)->callerFP);
|
||||
fixedPC = reinterpret_cast<Frame*>(sp)->returnAddress;
|
||||
fixedFP = fp;
|
||||
AssertMatchesCallSite(activation, fixedPC, fixedFP);
|
||||
AssertMatchesCallSite(fixedPC, fixedFP);
|
||||
} else if (offsetInCode >= codeRange->ret() - PoppedFP &&
|
||||
offsetInCode < codeRange->ret() - PoppedTLSReg)
|
||||
{
|
||||
// The fixedFP field of the Frame has been popped into fp.
|
||||
fixedPC = sp[1];
|
||||
fixedFP = fp;
|
||||
AssertMatchesCallSite(activation, fixedPC, fixedFP);
|
||||
AssertMatchesCallSite(fixedPC, fixedFP);
|
||||
#if defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
|
||||
} else if (offsetInCode >= codeRange->ret() - PoppedTLSReg &&
|
||||
offsetInCode < codeRange->ret())
|
||||
|
@ -774,20 +760,20 @@ js::wasm::StartUnwinding(const JitActivation& activation, const RegisterState& r
|
|||
// exit reason hasn't been popped yet.
|
||||
fixedPC = sp[0];
|
||||
fixedFP = fp;
|
||||
AssertMatchesCallSite(activation, fixedPC, fixedFP);
|
||||
AssertMatchesCallSite(fixedPC, fixedFP);
|
||||
} else if (offsetInCode == codeRange->ret()) {
|
||||
// Both the TLS, fixedFP and ra have been popped and fp now
|
||||
// points to the caller's frame.
|
||||
fixedPC = (uint8_t*) registers.lr;
|
||||
fixedFP = fp;
|
||||
AssertMatchesCallSite(activation, fixedPC, fixedFP);
|
||||
AssertMatchesCallSite(fixedPC, fixedFP);
|
||||
#else
|
||||
} else if (offsetInCode == codeRange->ret()) {
|
||||
// Both the TLS and fixedFP fields have been popped and fp now
|
||||
// points to the caller's frame.
|
||||
fixedPC = sp[0];
|
||||
fixedFP = fp;
|
||||
AssertMatchesCallSite(activation, fixedPC, fixedFP);
|
||||
AssertMatchesCallSite(fixedPC, fixedFP);
|
||||
#endif
|
||||
} else {
|
||||
if (codeRange->kind() == CodeRange::ImportJitExit) {
|
||||
|
@ -804,7 +790,7 @@ js::wasm::StartUnwinding(const JitActivation& activation, const RegisterState& r
|
|||
fixedPC = pc;
|
||||
fixedFP = fp;
|
||||
*unwoundCaller = false;
|
||||
AssertMatchesCallSite(activation, fp->returnAddress, fp->callerFP);
|
||||
AssertMatchesCallSite(fp->returnAddress, fp->callerFP);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
@ -815,7 +801,7 @@ js::wasm::StartUnwinding(const JitActivation& activation, const RegisterState& r
|
|||
fixedPC = pc;
|
||||
fixedFP = fp;
|
||||
*unwoundCaller = false;
|
||||
AssertMatchesCallSite(activation, fp->returnAddress, fp->callerFP);
|
||||
AssertMatchesCallSite(fp->returnAddress, fp->callerFP);
|
||||
break;
|
||||
case CodeRange::InterpEntry:
|
||||
// The entry trampoline is the final frame in an wasm JitActivation. The
|
||||
|
@ -843,8 +829,7 @@ js::wasm::StartUnwinding(const JitActivation& activation, const RegisterState& r
|
|||
|
||||
ProfilingFrameIterator::ProfilingFrameIterator(const JitActivation& activation,
|
||||
const RegisterState& state)
|
||||
: activation_(&activation),
|
||||
code_(nullptr),
|
||||
: code_(nullptr),
|
||||
codeRange_(nullptr),
|
||||
callerFP_(nullptr),
|
||||
callerPC_(nullptr),
|
||||
|
@ -862,7 +847,7 @@ ProfilingFrameIterator::ProfilingFrameIterator(const JitActivation& activation,
|
|||
|
||||
bool unwoundCaller;
|
||||
UnwindState unwindState;
|
||||
if (!StartUnwinding(*activation_, state, &unwindState, &unwoundCaller)) {
|
||||
if (!StartUnwinding(state, &unwindState, &unwoundCaller)) {
|
||||
MOZ_ASSERT(done());
|
||||
return;
|
||||
}
|
||||
|
@ -917,14 +902,14 @@ ProfilingFrameIterator::operator++()
|
|||
case CodeRange::ImportJitExit:
|
||||
case CodeRange::ImportInterpExit:
|
||||
case CodeRange::BuiltinThunk:
|
||||
case CodeRange::TrapExit:
|
||||
case CodeRange::OldTrapExit:
|
||||
case CodeRange::DebugTrap:
|
||||
case CodeRange::OutOfBoundsExit:
|
||||
case CodeRange::UnalignedExit:
|
||||
case CodeRange::FarJumpIsland:
|
||||
stackAddress_ = callerFP_;
|
||||
callerPC_ = callerFP_->returnAddress;
|
||||
AssertMatchesCallSite(*activation_, callerPC_, callerFP_->callerFP);
|
||||
AssertMatchesCallSite(callerPC_, callerFP_->callerFP);
|
||||
callerFP_ = callerFP_->callerFP;
|
||||
break;
|
||||
case CodeRange::InterpEntry:
|
||||
|
@ -945,7 +930,7 @@ ThunkedNativeToDescription(SymbolicAddress func)
|
|||
case SymbolicAddress::HandleExecutionInterrupt:
|
||||
case SymbolicAddress::HandleDebugTrap:
|
||||
case SymbolicAddress::HandleThrow:
|
||||
case SymbolicAddress::ReportTrap:
|
||||
case SymbolicAddress::OldReportTrap:
|
||||
case SymbolicAddress::ReportOutOfBounds:
|
||||
case SymbolicAddress::ReportUnalignedAccess:
|
||||
case SymbolicAddress::CallImport_Void:
|
||||
|
@ -1075,7 +1060,7 @@ ProfilingFrameIterator::label() const
|
|||
case CodeRange::ImportJitExit: return importJitDescription;
|
||||
case CodeRange::BuiltinThunk: return builtinNativeDescription;
|
||||
case CodeRange::ImportInterpExit: return importInterpDescription;
|
||||
case CodeRange::TrapExit: return trapDescription;
|
||||
case CodeRange::OldTrapExit: return trapDescription;
|
||||
case CodeRange::DebugTrap: return debugTrapDescription;
|
||||
case CodeRange::OutOfBoundsExit: return "out-of-bounds stub (in wasm)";
|
||||
case CodeRange::UnalignedExit: return "unaligned trap stub (in wasm)";
|
||||
|
@ -1096,7 +1081,7 @@ wasm::LookupFaultingInstance(const CodeSegment& codeSegment, void* pc, void* fp)
|
|||
// simulators which call this function at every load/store before even
|
||||
// knowing whether there is a fault.
|
||||
|
||||
const CodeRange* codeRange = codeSegment.code()->lookupRange(pc);
|
||||
const CodeRange* codeRange = codeSegment.code().lookupRange(pc);
|
||||
if (!codeRange || !codeRange->isFunction())
|
||||
return nullptr;
|
||||
|
||||
|
@ -1107,7 +1092,7 @@ wasm::LookupFaultingInstance(const CodeSegment& codeSegment, void* pc, void* fp)
|
|||
return nullptr;
|
||||
|
||||
Instance* instance = reinterpret_cast<Frame*>(fp)->tls->instance;
|
||||
MOZ_RELEASE_ASSERT(&instance->code() == codeSegment.code());
|
||||
MOZ_RELEASE_ASSERT(&instance->code() == &codeSegment.code());
|
||||
return instance;
|
||||
}
|
||||
|
||||
|
|
|
@ -66,8 +66,8 @@ class WasmFrameIter
|
|||
private:
|
||||
jit::JitActivation* activation_;
|
||||
const Code* code_;
|
||||
const CallSite* callsite_;
|
||||
const CodeRange* codeRange_;
|
||||
unsigned lineOrBytecode_;
|
||||
Frame* fp_;
|
||||
Unwind unwind_;
|
||||
void** unwoundAddressOfReturnAddress_;
|
||||
|
@ -91,7 +91,6 @@ class WasmFrameIter
|
|||
void** unwoundAddressOfReturnAddress() const;
|
||||
bool debugEnabled() const;
|
||||
DebugFrame* debugFrame() const;
|
||||
const CallSite* debugTrapCallsite() const;
|
||||
};
|
||||
|
||||
enum class SymbolicAddress;
|
||||
|
@ -160,7 +159,6 @@ class ExitReason
|
|||
// asynchronously-interrupted thread's state.
|
||||
class ProfilingFrameIterator
|
||||
{
|
||||
const jit::JitActivation* activation_;
|
||||
const Code* code_;
|
||||
const CodeRange* codeRange_;
|
||||
Frame* callerFP_;
|
||||
|
@ -253,8 +251,8 @@ typedef JS::ProfilingFrameIterator::RegisterState RegisterState;
|
|||
// frame should be ignored.
|
||||
|
||||
bool
|
||||
StartUnwinding(const jit::JitActivation& activation, const RegisterState& registers,
|
||||
UnwindState* unwindState, bool* unwoundCaller);
|
||||
StartUnwinding(const RegisterState& registers, UnwindState* unwindState,
|
||||
bool* unwoundCaller);
|
||||
|
||||
} // namespace wasm
|
||||
} // namespace js
|
||||
|
|
|
@ -47,9 +47,9 @@ CompiledCode::swap(MacroAssembler& masm)
|
|||
|
||||
callSites.swap(masm.callSites());
|
||||
callSiteTargets.swap(masm.callSiteTargets());
|
||||
trapSites.swap(masm.trapSites());
|
||||
oldTrapSites.swap(masm.oldTrapSites());
|
||||
callFarJumps.swap(masm.callFarJumps());
|
||||
trapFarJumps.swap(masm.trapFarJumps());
|
||||
oldTrapFarJumps.swap(masm.oldTrapFarJumps());
|
||||
memoryAccesses.swap(masm.memoryAccesses());
|
||||
symbolicAccesses.swap(masm.symbolicAccesses());
|
||||
codeLabels.swap(masm.codeLabels());
|
||||
|
@ -75,7 +75,7 @@ ModuleGenerator::ModuleGenerator(const CompileArgs& args, ModuleEnvironment* env
|
|||
lifo_(GENERATOR_LIFO_DEFAULT_CHUNK_SIZE),
|
||||
masmAlloc_(&lifo_),
|
||||
masm_(MacroAssembler::WasmToken(), masmAlloc_),
|
||||
trapCodeOffsets_(),
|
||||
oldTrapCodeOffsets_(),
|
||||
debugTrapCodeOffset_(),
|
||||
lastPatchedCallSite_(0),
|
||||
startOfUnpatchedCallsites_(0),
|
||||
|
@ -86,7 +86,7 @@ ModuleGenerator::ModuleGenerator(const CompileArgs& args, ModuleEnvironment* env
|
|||
finishedFuncDefs_(false)
|
||||
{
|
||||
MOZ_ASSERT(IsCompilingWasm());
|
||||
std::fill(trapCodeOffsets_.begin(), trapCodeOffsets_.end(), 0);
|
||||
std::fill(oldTrapCodeOffsets_.begin(), oldTrapCodeOffsets_.end(), 0);
|
||||
}
|
||||
|
||||
ModuleGenerator::~ModuleGenerator()
|
||||
|
@ -206,8 +206,8 @@ ModuleGenerator::init(Metadata* maybeAsmJSMetadata)
|
|||
if (!metadataTier_->codeRanges.reserve(2 * env_->numFuncDefs()))
|
||||
return false;
|
||||
|
||||
const size_t CallSitesPerByteCode = 10;
|
||||
if (!metadataTier_->callSites.reserve(codeSectionSize / CallSitesPerByteCode))
|
||||
const size_t ByteCodesPerCallSite = 10;
|
||||
if (!metadataTier_->callSites.reserve(codeSectionSize / ByteCodesPerCallSite))
|
||||
return false;
|
||||
|
||||
const size_t MemoryAccessesPerByteCode = 10;
|
||||
|
@ -436,14 +436,14 @@ ModuleGenerator::linkCallSites()
|
|||
masm_.patchCall(callerOffset, p->value());
|
||||
break;
|
||||
}
|
||||
case CallSiteDesc::TrapExit: {
|
||||
case CallSiteDesc::OldTrapExit: {
|
||||
if (!existingTrapFarJumps[target.trap()]) {
|
||||
// See MacroAssembler::wasmEmitTrapOutOfLineCode for why we must
|
||||
// See MacroAssembler::wasmEmitOldTrapOutOfLineCode for why we must
|
||||
// reload the TLS register on this path.
|
||||
Offsets offsets;
|
||||
offsets.begin = masm_.currentOffset();
|
||||
masm_.loadPtr(Address(FramePointer, offsetof(Frame, tls)), WasmTlsReg);
|
||||
if (!trapFarJumps_.emplaceBack(target.trap(), masm_.farJumpWithPatch()))
|
||||
if (!oldTrapFarJumps_.emplaceBack(target.trap(), masm_.farJumpWithPatch()))
|
||||
return false;
|
||||
offsets.end = masm_.currentOffset();
|
||||
if (masm_.oom())
|
||||
|
@ -503,9 +503,9 @@ ModuleGenerator::noteCodeRange(uint32_t codeRangeIndex, const CodeRange& codeRan
|
|||
case CodeRange::ImportInterpExit:
|
||||
metadataTier_->funcImports[codeRange.funcIndex()].initInterpExitOffset(codeRange.begin());
|
||||
break;
|
||||
case CodeRange::TrapExit:
|
||||
MOZ_ASSERT(!trapCodeOffsets_[codeRange.trap()]);
|
||||
trapCodeOffsets_[codeRange.trap()] = codeRange.begin();
|
||||
case CodeRange::OldTrapExit:
|
||||
MOZ_ASSERT(!oldTrapCodeOffsets_[codeRange.trap()]);
|
||||
oldTrapCodeOffsets_[codeRange.trap()] = codeRange.begin();
|
||||
break;
|
||||
case CodeRange::DebugTrap:
|
||||
MOZ_ASSERT(!debugTrapCodeOffset_);
|
||||
|
@ -580,10 +580,10 @@ ModuleGenerator::linkCompiledCode(const CompiledCode& code)
|
|||
if (!callSiteTargets_.appendAll(code.callSiteTargets))
|
||||
return false;
|
||||
|
||||
MOZ_ASSERT(code.trapSites.empty());
|
||||
MOZ_ASSERT(code.oldTrapSites.empty());
|
||||
|
||||
auto trapFarJumpOp = [=](uint32_t, TrapFarJump* tfj) { tfj->offsetBy(offsetInModule); };
|
||||
if (!AppendForEach(&trapFarJumps_, code.trapFarJumps, trapFarJumpOp))
|
||||
auto trapFarJumpOp = [=](uint32_t, OldTrapFarJump* tfj) { tfj->offsetBy(offsetInModule); };
|
||||
if (!AppendForEach(&oldTrapFarJumps_, code.oldTrapFarJumps, trapFarJumpOp))
|
||||
return false;
|
||||
|
||||
auto callFarJumpOp = [=](uint32_t, CallFarJump* cfj) { cfj->offsetBy(offsetInModule); };
|
||||
|
@ -788,8 +788,8 @@ ModuleGenerator::finishCode()
|
|||
for (CallFarJump far : callFarJumps_)
|
||||
masm_.patchFarJump(far.jump, funcCodeRange(far.funcIndex).funcNormalEntry());
|
||||
|
||||
for (TrapFarJump far : trapFarJumps_)
|
||||
masm_.patchFarJump(far.jump, trapCodeOffsets_[far.trap]);
|
||||
for (OldTrapFarJump far : oldTrapFarJumps_)
|
||||
masm_.patchFarJump(far.jump, oldTrapCodeOffsets_[far.trap]);
|
||||
|
||||
for (CodeOffset farJump : debugTrapFarJumps_)
|
||||
masm_.patchFarJump(farJump, debugTrapCodeOffset_);
|
||||
|
@ -798,8 +798,8 @@ ModuleGenerator::finishCode()
|
|||
|
||||
MOZ_ASSERT(masm_.callSites().empty());
|
||||
MOZ_ASSERT(masm_.callSiteTargets().empty());
|
||||
MOZ_ASSERT(masm_.trapSites().empty());
|
||||
MOZ_ASSERT(masm_.trapFarJumps().empty());
|
||||
MOZ_ASSERT(masm_.oldTrapSites().empty());
|
||||
MOZ_ASSERT(masm_.oldTrapFarJumps().empty());
|
||||
MOZ_ASSERT(masm_.callFarJumps().empty());
|
||||
MOZ_ASSERT(masm_.memoryAccesses().empty());
|
||||
MOZ_ASSERT(masm_.symbolicAccesses().empty());
|
||||
|
|
|
@ -64,8 +64,8 @@ struct CompiledCode
|
|||
CodeRangeVector codeRanges;
|
||||
CallSiteVector callSites;
|
||||
CallSiteTargetVector callSiteTargets;
|
||||
TrapSiteVector trapSites;
|
||||
TrapFarJumpVector trapFarJumps;
|
||||
OldTrapSiteVector oldTrapSites;
|
||||
OldTrapFarJumpVector oldTrapFarJumps;
|
||||
CallFarJumpVector callFarJumps;
|
||||
MemoryAccessVector memoryAccesses;
|
||||
SymbolicAccessVector symbolicAccesses;
|
||||
|
@ -78,8 +78,8 @@ struct CompiledCode
|
|||
codeRanges.clear();
|
||||
callSites.clear();
|
||||
callSiteTargets.clear();
|
||||
trapSites.clear();
|
||||
trapFarJumps.clear();
|
||||
oldTrapSites.clear();
|
||||
oldTrapFarJumps.clear();
|
||||
callFarJumps.clear();
|
||||
memoryAccesses.clear();
|
||||
symbolicAccesses.clear();
|
||||
|
@ -92,8 +92,8 @@ struct CompiledCode
|
|||
codeRanges.empty() &&
|
||||
callSites.empty() &&
|
||||
callSiteTargets.empty() &&
|
||||
trapSites.empty() &&
|
||||
trapFarJumps.empty() &&
|
||||
oldTrapSites.empty() &&
|
||||
oldTrapFarJumps.empty() &&
|
||||
callFarJumps.empty() &&
|
||||
memoryAccesses.empty() &&
|
||||
symbolicAccesses.empty() &&
|
||||
|
@ -145,7 +145,7 @@ struct CompileTask
|
|||
class MOZ_STACK_CLASS ModuleGenerator
|
||||
{
|
||||
typedef Vector<CompileTask, 0, SystemAllocPolicy> CompileTaskVector;
|
||||
typedef EnumeratedArray<Trap, Trap::Limit, uint32_t> Uint32TrapArray;
|
||||
typedef EnumeratedArray<Trap, Trap::Limit, uint32_t> OldTrapOffsetArray;
|
||||
typedef Vector<jit::CodeOffset, 0, SystemAllocPolicy> CodeOffsetVector;
|
||||
|
||||
// Constant parameters
|
||||
|
@ -168,9 +168,9 @@ class MOZ_STACK_CLASS ModuleGenerator
|
|||
jit::TempAllocator masmAlloc_;
|
||||
jit::MacroAssembler masm_;
|
||||
Uint32Vector funcToCodeRange_;
|
||||
Uint32TrapArray trapCodeOffsets_;
|
||||
OldTrapOffsetArray oldTrapCodeOffsets_;
|
||||
uint32_t debugTrapCodeOffset_;
|
||||
TrapFarJumpVector trapFarJumps_;
|
||||
OldTrapFarJumpVector oldTrapFarJumps_;
|
||||
CallFarJumpVector callFarJumps_;
|
||||
CallSiteTargetVector callSiteTargets_;
|
||||
uint32_t lastPatchedCallSite_;
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче