mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-13 13:25:37 +00:00
Merge m-c to b2g-inbound a=merge
This commit is contained in:
commit
c6fa0d9891
@ -398,14 +398,14 @@ var shell = {
|
||||
}
|
||||
|
||||
let mediaKeys = {
|
||||
'MediaNextTrack': 'media-next-track-button',
|
||||
'MediaPreviousTrack': 'media-previous-track-button',
|
||||
'MediaTrackNext': 'media-next-track-button',
|
||||
'MediaTrackPrevious': 'media-previous-track-button',
|
||||
'MediaPause': 'media-pause-button',
|
||||
'MediaPlay': 'media-play-button',
|
||||
'MediaPlayPause': 'media-play-pause-button',
|
||||
'MediaStop': 'media-stop-button',
|
||||
'MediaRewind': 'media-rewind-button',
|
||||
'FastFwd': 'media-fast-forward-button'
|
||||
'MediaFastForward': 'media-fast-forward-button'
|
||||
};
|
||||
|
||||
let isMediaKey = false;
|
||||
|
@ -24,14 +24,14 @@ let test = asyncTest(function* () {
|
||||
messages: [
|
||||
{
|
||||
name: "Logged mixed active content",
|
||||
text: "Loading mixed (insecure) active content on a secure page \"http://example.com/\"",
|
||||
text: "Loading mixed (insecure) active content \"http://example.com/\" on a secure page",
|
||||
category: CATEGORY_SECURITY,
|
||||
severity: SEVERITY_WARNING,
|
||||
objects: true,
|
||||
},
|
||||
{
|
||||
name: "Logged mixed passive content - image",
|
||||
text: "Loading mixed (insecure) display content on a secure page \"http://example.com/tests/image/test/mochitest/blue.png\"",
|
||||
text: "Loading mixed (insecure) display content \"http://example.com/tests/image/test/mochitest/blue.png\" on a secure page",
|
||||
category: CATEGORY_SECURITY,
|
||||
severity: SEVERITY_WARNING,
|
||||
objects: true,
|
||||
|
@ -95,16 +95,17 @@ function afterNotificationShown(hud, notification, deferred)
|
||||
messages: [
|
||||
{
|
||||
name: "Logged blocking mixed active content",
|
||||
text: "Loading mixed (insecure) active content on a secure"+
|
||||
" page \"http://example.com/\"",
|
||||
text: "Loading mixed (insecure) active content \"http://example.com/\"" +
|
||||
" on a secure page",
|
||||
category: CATEGORY_SECURITY,
|
||||
severity: SEVERITY_WARNING,
|
||||
objects: true,
|
||||
},
|
||||
{
|
||||
name: "Logged blocking mixed passive content - image",
|
||||
text: "Loading mixed (insecure) display content on a secure page"+
|
||||
" \"http://example.com/tests/image/test/mochitest/blue.png\"",
|
||||
text: "Loading mixed (insecure) display content" +
|
||||
" \"http://example.com/tests/image/test/mochitest/blue.png\"" +
|
||||
" on a secure page",
|
||||
category: CATEGORY_SECURITY,
|
||||
severity: SEVERITY_WARNING,
|
||||
objects: true,
|
||||
|
@ -18,6 +18,7 @@ import sys
|
||||
import threading
|
||||
import tempfile
|
||||
import sqlite3
|
||||
import zipfile
|
||||
from datetime import datetime, timedelta
|
||||
from string import Template
|
||||
|
||||
@ -922,7 +923,7 @@ class Automation(object):
|
||||
os.makedirs(extensionsRootDir)
|
||||
|
||||
if os.path.isfile(extensionSource):
|
||||
reader = automationutils.ZipFileReader(extensionSource)
|
||||
reader = zipfile.ZipFile(extensionSource, "r")
|
||||
|
||||
for filename in reader.namelist():
|
||||
# Sanity check the zip file.
|
||||
|
@ -13,11 +13,9 @@ import signal
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
import zipfile
|
||||
import mozinfo
|
||||
|
||||
__all__ = [
|
||||
"ZipFileReader",
|
||||
"dumpLeakLog",
|
||||
"processLeakLog",
|
||||
'systemMemory',
|
||||
@ -40,68 +38,6 @@ def setAutomationLog(alt_logger):
|
||||
global log
|
||||
log = alt_logger
|
||||
|
||||
class ZipFileReader(object):
|
||||
"""
|
||||
Class to read zip files in Python 2.5 and later. Limited to only what we
|
||||
actually use.
|
||||
"""
|
||||
|
||||
def __init__(self, filename):
|
||||
self._zipfile = zipfile.ZipFile(filename, "r")
|
||||
|
||||
def __del__(self):
|
||||
self._zipfile.close()
|
||||
|
||||
def _getnormalizedpath(self, path):
|
||||
"""
|
||||
Gets a normalized path from 'path' (or the current working directory if
|
||||
'path' is None). Also asserts that the path exists.
|
||||
"""
|
||||
if path is None:
|
||||
path = os.curdir
|
||||
path = os.path.normpath(os.path.expanduser(path))
|
||||
assert os.path.isdir(path)
|
||||
return path
|
||||
|
||||
def _extractname(self, name, path):
|
||||
"""
|
||||
Extracts a file with the given name from the zip file to the given path.
|
||||
Also creates any directories needed along the way.
|
||||
"""
|
||||
filename = os.path.normpath(os.path.join(path, name))
|
||||
if name.endswith("/"):
|
||||
os.makedirs(filename)
|
||||
else:
|
||||
path = os.path.split(filename)[0]
|
||||
if not os.path.isdir(path):
|
||||
os.makedirs(path)
|
||||
with open(filename, "wb") as dest:
|
||||
dest.write(self._zipfile.read(name))
|
||||
|
||||
def namelist(self):
|
||||
return self._zipfile.namelist()
|
||||
|
||||
def read(self, name):
|
||||
return self._zipfile.read(name)
|
||||
|
||||
def extract(self, name, path = None):
|
||||
if hasattr(self._zipfile, "extract"):
|
||||
return self._zipfile.extract(name, path)
|
||||
|
||||
# This will throw if name is not part of the zip file.
|
||||
self._zipfile.getinfo(name)
|
||||
|
||||
self._extractname(name, self._getnormalizedpath(path))
|
||||
|
||||
def extractall(self, path = None):
|
||||
if hasattr(self._zipfile, "extractall"):
|
||||
return self._zipfile.extractall(path)
|
||||
|
||||
path = self._getnormalizedpath(path)
|
||||
|
||||
for name in self._zipfile.namelist():
|
||||
self._extractname(name, path)
|
||||
|
||||
# Python does not provide strsignal() even in the very latest 3.x.
|
||||
# This is a reasonable fake.
|
||||
def strsig(n):
|
||||
|
@ -7245,7 +7245,7 @@ dnl ========================================================
|
||||
if test -z "$MOZ_MEMORY"; then
|
||||
if test -n "$MOZ_JEMALLOC3" -a -z "$MOZ_REPLACE_MALLOC"; then
|
||||
MOZ_NATIVE_JEMALLOC=1
|
||||
AC_CHECK_FUNCS(mallctl nallocm,,
|
||||
AC_CHECK_FUNCS(mallctl nallocx,,
|
||||
[MOZ_NATIVE_JEMALLOC=
|
||||
break])
|
||||
if test -n "$MOZ_NATIVE_JEMALLOC"; then
|
||||
|
@ -40,29 +40,4 @@ DEPRECATED_OPERATION(SyncXMLHttpRequest)
|
||||
DEPRECATED_OPERATION(DataContainerEvent)
|
||||
DEPRECATED_OPERATION(SendAsBinary)
|
||||
DEPRECATED_OPERATION(Window_Controllers)
|
||||
DEPRECATED_OPERATION(KeyNameDown)
|
||||
DEPRECATED_OPERATION(KeyNameLeft)
|
||||
DEPRECATED_OPERATION(KeyNameRight)
|
||||
DEPRECATED_OPERATION(KeyNameUp)
|
||||
DEPRECATED_OPERATION(KeyNameCrsel)
|
||||
DEPRECATED_OPERATION(KeyNameDel)
|
||||
DEPRECATED_OPERATION(KeyNameExsel)
|
||||
DEPRECATED_OPERATION(KeyNameMenu)
|
||||
DEPRECATED_OPERATION(KeyNameEsc)
|
||||
DEPRECATED_OPERATION(KeyNameNonconvert)
|
||||
DEPRECATED_OPERATION(KeyNameHalfWidth)
|
||||
DEPRECATED_OPERATION(KeyNameRomanCharacters)
|
||||
DEPRECATED_OPERATION(KeyNameFullWidth)
|
||||
DEPRECATED_OPERATION(KeyNameSelectMedia)
|
||||
DEPRECATED_OPERATION(KeyNameMediaNextTrack)
|
||||
DEPRECATED_OPERATION(KeyNameMediaPreviousTrack)
|
||||
DEPRECATED_OPERATION(KeyNameRed)
|
||||
DEPRECATED_OPERATION(KeyNameGreen)
|
||||
DEPRECATED_OPERATION(KeyNameYellow)
|
||||
DEPRECATED_OPERATION(KeyNameBlue)
|
||||
DEPRECATED_OPERATION(KeyNameLive)
|
||||
DEPRECATED_OPERATION(KeyNameApps)
|
||||
DEPRECATED_OPERATION(KeyNameFastFwd)
|
||||
DEPRECATED_OPERATION(KeyNameZoom)
|
||||
DEPRECATED_OPERATION(KeyNameDeadKeys)
|
||||
DEPRECATED_OPERATION(ImportXULIntoContent)
|
||||
|
@ -46,7 +46,7 @@ DEFINE_KEYNAME_WITH_SAME_NAME(OS)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(ScrollLock)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Shift)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(Super)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(Symbol)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Symbol)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(SymbolLock)
|
||||
|
||||
/******************************************************************************
|
||||
@ -59,10 +59,10 @@ DEFINE_KEYNAME_WITH_SAME_NAME(Tab)
|
||||
/******************************************************************************
|
||||
* Navigation Keys
|
||||
*****************************************************************************/
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Down) // Rename to ArrowDown
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Left) // Rename to ArrowLeft
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Right) // Rename to ArrowRight
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Up) // Rename to ArrowUp
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(ArrowDown)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(ArrowLeft)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(ArrowRight)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(ArrowUp)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(End)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Home)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(PageDown)
|
||||
@ -74,14 +74,14 @@ DEFINE_KEYNAME_WITH_SAME_NAME(PageUp)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Backspace)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Clear)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Copy)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Crsel) // Rename to CrSel
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(CrSel)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Cut)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Del) // Rename to Delete
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Delete)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(EraseEof)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Exsel) // Rename to ExSel
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(ExSel)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Insert)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Paste)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(Redo)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Redo)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Undo)
|
||||
|
||||
/******************************************************************************
|
||||
@ -91,8 +91,8 @@ DEFINE_KEYNAME_WITH_SAME_NAME(Accept)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(Again)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Attn)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Cancel)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Menu) // Rename to ContextMenu
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Esc) // Rename to Escape
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(ContextMenu)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Escape)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Execute)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Find)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Help)
|
||||
@ -100,8 +100,8 @@ DEFINE_KEYNAME_WITH_SAME_NAME(Pause)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Play)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(Props)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Select)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(ZoomIn)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(ZoomOut)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(ZoomIn)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(ZoomOut)
|
||||
|
||||
/******************************************************************************
|
||||
* Device Keys
|
||||
@ -110,13 +110,13 @@ DEFINE_KEYNAME_WITH_SAME_NAME(BrightnessDown)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(BrightnessUp)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Camera)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Eject)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(LogOff)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(LogOff)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Power)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(PowerOff)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(PowerOff)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(PrintScreen)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(Hibernate)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(Standby)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(WakeUp)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Hibernate)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Standby)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(WakeUp)
|
||||
|
||||
/******************************************************************************
|
||||
* IME and Composition Keys
|
||||
@ -126,18 +126,18 @@ DEFINE_KEYNAME_WITH_SAME_NAME(Alphanumeric)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(CodeInput)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Compose)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Convert)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(Dead)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Dead)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(FinalMode)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(GroupFirst)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(GroupLast)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(GroupNext)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(GroupPrevious)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(GroupFirst)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(GroupLast)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(GroupNext)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(GroupPrevious)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(ModeChange)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(NextCandidate)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Nonconvert) // Rename to NonConvert
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(NonConvert)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(PreviousCandidate)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(Process)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(SingleCandidate)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(SingleCandidate)
|
||||
|
||||
/******************************************************************************
|
||||
* Keys specific to Korean keyboards
|
||||
@ -149,16 +149,16 @@ DEFINE_KEYNAME_WITH_SAME_NAME(JunjaMode)
|
||||
/******************************************************************************
|
||||
* Keys specific to Japanese keyboards
|
||||
*****************************************************************************/
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(Eisu)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(HalfWidth) // Rename to Hankaku
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Eisu)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Hankaku)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Hiragana)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(HiraganaKatakana)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(HiraganaKatakana)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(KanaMode)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(KanjiMode)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Katakana)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(RomanCharacters) // Rename to Romaji
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(FullWidth) // Rename to Zenkaku
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(ZenkakuHankaku)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Romaji)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Zenkaku)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(ZenkakuHankaku)
|
||||
|
||||
/******************************************************************************
|
||||
* General-Purpose Function Keys
|
||||
@ -206,20 +206,20 @@ DEFINE_KEYNAME_WITH_SAME_NAME(F35)
|
||||
/******************************************************************************
|
||||
* Multimedia Keys
|
||||
*****************************************************************************/
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(Close)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(MailForward)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(MailReply)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(MailSend)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Close)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(MailForward)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(MailReply)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(MailSend)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(MediaPlayPause)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(SelectMedia) // Rename to MediaSelect
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(MediaSelect)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(MediaStop)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(MediaNextTrack) // Rename to MediaTrackNext
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(MediaPreviousTrack) // Rename to MediaTrackPrevious
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(New)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(Open)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(Print)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(Save)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(SpellCheck)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(MediaTrackNext)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(MediaTrackPrevious)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(New)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Open)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Print)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Save)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(SpellCheck)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(VolumeDown)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(VolumeUp)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(VolumeMute)
|
||||
@ -227,17 +227,17 @@ DEFINE_KEYNAME_WITH_SAME_NAME(VolumeMute)
|
||||
/******************************************************************************
|
||||
* Application Keys
|
||||
*****************************************************************************/
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(LaunchCalculator)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(LaunchCalendar)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(LaunchCalculator)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(LaunchCalendar)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(LaunchMail)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(LaunchMediaPlayer)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(LaunchMusicPlayer)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(LaunchMyComputer)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(LaunchScreenSaver)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(LaunchSpreadsheet)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(LaunchWebBrowser)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(LaunchWebCam)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(LaunchWordProcessor)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(LaunchMediaPlayer)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(LaunchMusicPlayer)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(LaunchMyComputer)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(LaunchScreenSaver)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(LaunchSpreadsheet)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(LaunchWebBrowser)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(LaunchWebCam)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(LaunchWordProcessor)
|
||||
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(LaunchApplication1)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(LaunchApplication2)
|
||||
@ -279,43 +279,43 @@ DEFINE_KEYNAME_WITH_SAME_NAME(AudioBassBoostUp)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(AudioFaderFront)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(AudioFaderRear)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(AudioSurroundModeNext)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(AVRInput)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(AVRPower)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(AVRInput)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(AVRPower)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(ChannelDown)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(ChannelUp)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Red) // Rename to ColorF0Red
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Green) // Rename to ColorF1Green
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Yellow) // Rename to ColorF2Yellow
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Blue) // Rename to ColorF3Blue
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(Grey) // Rename to ColorF4Grey
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(Brown) // Rename to ColorF5Brown
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(ColorF0Red)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(ColorF1Green)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(ColorF2Yellow)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(ColorF3Blue)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(ColorF4Grey)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(ColorF5Brown)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(ClosedCaptionToggle)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Dimmer)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(DisplaySwap)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Exit)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(ClearFavorite0) // Rename to FavoriteClear0
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(ClearFavorite1) // Rename to FavoriteClear1
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(ClearFavorite2) // Rename to FavoriteClear2
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(ClearFavorite3) // Rename to FavoriteClear3
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(RecallFavorite0) // Rename to FavoriteRecall0
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(RecallFavorite1) // Rename to FavoriteRecall1
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(RecallFavorite2) // Rename to FavoriteRecall2
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(RecallFavorite3) // Rename to FavoriteRecall3
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(StoreFavorite0) // Rename to FavoriteStore0
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(StoreFavorite1) // Rename to FavoriteStore1
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(StoreFavorite2) // Rename to FavoriteStore2
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(StoreFavorite3) // Rename to FavoriteStore3
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(Exit)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(FavoriteClear0)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(FavoriteClear1)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(FavoriteClear2)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(FavoriteClear3)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(FavoriteRecall0)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(FavoriteRecall1)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(FavoriteRecall2)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(FavoriteRecall3)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(FavoriteStore0)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(FavoriteStore1)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(FavoriteStore2)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(FavoriteStore3)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Guide)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(NextDay) // Rename to GuideNextDay
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(PrevDay) // Rename to GuidePreviousDay
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(GuideNextDay)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(GuidePreviousDay)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Info)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(InstantReplay)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(Link)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(List) // Rename to ListProgram
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Live) // Rename to LiveContent
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(ListProgram)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(LiveContent)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(Lock)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Apps) // Rename to MediaApps
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(FastFwd) // Rename to MediaFastForward
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(MediaApps)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(MediaFastForward)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(MediaLast)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(MediaPause)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(MediaPlay)
|
||||
@ -340,36 +340,16 @@ DEFINE_KEYNAME_WITH_SAME_NAME(RandomToggle)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(ScreenModeNext)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Settings)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(SplitScreenToggle)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(STBInput)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(STBPower)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(STBInput)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(STBPower)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Subtitle)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(Teletext)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(TV)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(TVInput)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(TVPower)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(VideoModeNext)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(TV)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(TVInput)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(TVPower)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(VideoModeNext)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(Wink)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Zoom) // Rename to ZoomToggle
|
||||
|
||||
/******************************************************************************
|
||||
* Deprecated
|
||||
******************************************************************************/
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(DeadGrave)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(DeadAcute)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(DeadCircumflex)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(DeadTilde)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(DeadMacron)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(DeadBreve)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(DeadAboveDot)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(DeadUmlaut)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(DeadAboveRing)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(DeadDoubleacute)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(DeadCaron)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(DeadCedilla)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(DeadOgonek)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(DeadIota)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(DeadVoicedSound)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(DeadSemivoicedSound)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(ZoomToggle)
|
||||
|
||||
#undef DEFINE_KEYNAME_WITH_SAME_NAME
|
||||
#undef DEFINE_KEYNAME_INTERNAL
|
||||
|
@ -5,7 +5,6 @@
|
||||
|
||||
#include "mozilla/dom/KeyboardEvent.h"
|
||||
#include "mozilla/TextEvents.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "prtime.h"
|
||||
|
||||
namespace mozilla {
|
||||
@ -125,110 +124,7 @@ KeyboardEvent::GetModifierState(const nsAString& aKey,
|
||||
NS_IMETHODIMP
|
||||
KeyboardEvent::GetKey(nsAString& aKeyName)
|
||||
{
|
||||
WidgetKeyboardEvent* keyboardEvent = mEvent->AsKeyboardEvent();
|
||||
keyboardEvent->GetDOMKeyName(aKeyName);
|
||||
|
||||
nsIDocument::DeprecatedOperations deprecatedOperation;
|
||||
switch (keyboardEvent->mKeyNameIndex) {
|
||||
case KEY_NAME_INDEX_Down:
|
||||
deprecatedOperation = nsIDocument::eKeyNameDown;
|
||||
break;
|
||||
case KEY_NAME_INDEX_Left:
|
||||
deprecatedOperation = nsIDocument::eKeyNameLeft;
|
||||
break;
|
||||
case KEY_NAME_INDEX_Right:
|
||||
deprecatedOperation = nsIDocument::eKeyNameRight;
|
||||
break;
|
||||
case KEY_NAME_INDEX_Up:
|
||||
deprecatedOperation = nsIDocument::eKeyNameUp;
|
||||
break;
|
||||
case KEY_NAME_INDEX_Crsel:
|
||||
deprecatedOperation = nsIDocument::eKeyNameCrsel;
|
||||
break;
|
||||
case KEY_NAME_INDEX_Del:
|
||||
deprecatedOperation = nsIDocument::eKeyNameDel;
|
||||
break;
|
||||
case KEY_NAME_INDEX_Exsel:
|
||||
deprecatedOperation = nsIDocument::eKeyNameExsel;
|
||||
break;
|
||||
case KEY_NAME_INDEX_Menu:
|
||||
deprecatedOperation = nsIDocument::eKeyNameMenu;
|
||||
break;
|
||||
case KEY_NAME_INDEX_Esc:
|
||||
deprecatedOperation = nsIDocument::eKeyNameEsc;
|
||||
break;
|
||||
case KEY_NAME_INDEX_Nonconvert:
|
||||
deprecatedOperation = nsIDocument::eKeyNameNonconvert;
|
||||
break;
|
||||
case KEY_NAME_INDEX_HalfWidth:
|
||||
deprecatedOperation = nsIDocument::eKeyNameHalfWidth;
|
||||
break;
|
||||
case KEY_NAME_INDEX_RomanCharacters:
|
||||
deprecatedOperation = nsIDocument::eKeyNameRomanCharacters;
|
||||
break;
|
||||
case KEY_NAME_INDEX_FullWidth:
|
||||
deprecatedOperation = nsIDocument::eKeyNameFullWidth;
|
||||
break;
|
||||
case KEY_NAME_INDEX_SelectMedia:
|
||||
deprecatedOperation = nsIDocument::eKeyNameSelectMedia;
|
||||
break;
|
||||
case KEY_NAME_INDEX_MediaNextTrack:
|
||||
deprecatedOperation = nsIDocument::eKeyNameMediaNextTrack;
|
||||
break;
|
||||
case KEY_NAME_INDEX_MediaPreviousTrack:
|
||||
deprecatedOperation = nsIDocument::eKeyNameMediaPreviousTrack;
|
||||
break;
|
||||
case KEY_NAME_INDEX_Red:
|
||||
deprecatedOperation = nsIDocument::eKeyNameRed;
|
||||
break;
|
||||
case KEY_NAME_INDEX_Green:
|
||||
deprecatedOperation = nsIDocument::eKeyNameGreen;
|
||||
break;
|
||||
case KEY_NAME_INDEX_Yellow:
|
||||
deprecatedOperation = nsIDocument::eKeyNameYellow;
|
||||
break;
|
||||
case KEY_NAME_INDEX_Blue:
|
||||
deprecatedOperation = nsIDocument::eKeyNameBlue;
|
||||
break;
|
||||
case KEY_NAME_INDEX_Live:
|
||||
deprecatedOperation = nsIDocument::eKeyNameLive;
|
||||
break;
|
||||
case KEY_NAME_INDEX_Apps:
|
||||
deprecatedOperation = nsIDocument::eKeyNameApps;
|
||||
break;
|
||||
case KEY_NAME_INDEX_FastFwd:
|
||||
deprecatedOperation = nsIDocument::eKeyNameFastFwd;
|
||||
break;
|
||||
case KEY_NAME_INDEX_Zoom:
|
||||
deprecatedOperation = nsIDocument::eKeyNameZoom;
|
||||
break;
|
||||
case KEY_NAME_INDEX_DeadGrave:
|
||||
case KEY_NAME_INDEX_DeadAcute:
|
||||
case KEY_NAME_INDEX_DeadCircumflex:
|
||||
case KEY_NAME_INDEX_DeadTilde:
|
||||
case KEY_NAME_INDEX_DeadMacron:
|
||||
case KEY_NAME_INDEX_DeadBreve:
|
||||
case KEY_NAME_INDEX_DeadAboveDot:
|
||||
case KEY_NAME_INDEX_DeadUmlaut:
|
||||
case KEY_NAME_INDEX_DeadAboveRing:
|
||||
case KEY_NAME_INDEX_DeadDoubleacute:
|
||||
case KEY_NAME_INDEX_DeadCaron:
|
||||
case KEY_NAME_INDEX_DeadCedilla:
|
||||
case KEY_NAME_INDEX_DeadOgonek:
|
||||
case KEY_NAME_INDEX_DeadIota:
|
||||
case KEY_NAME_INDEX_DeadVoicedSound:
|
||||
case KEY_NAME_INDEX_DeadSemivoicedSound:
|
||||
deprecatedOperation = nsIDocument::eKeyNameDeadKeys;
|
||||
break;
|
||||
default:
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsIDocument* doc = mOwner ? mOwner->GetExtantDoc() : nullptr;
|
||||
if (NS_WARN_IF(!doc)) {
|
||||
return NS_OK;
|
||||
}
|
||||
doc->WarnOnceAbout(deprecatedOperation);
|
||||
mEvent->AsKeyboardEvent()->GetDOMKeyName(aKeyName);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -951,7 +951,7 @@ mozilla::plugins::PPluginModuleParent*
|
||||
ContentChild::AllocPPluginModuleParent(mozilla::ipc::Transport* aTransport,
|
||||
base::ProcessId aOtherProcess)
|
||||
{
|
||||
return plugins::PluginModuleContentParent::Create(aTransport, aOtherProcess);
|
||||
return plugins::PluginModuleContentParent::Initialize(aTransport, aOtherProcess);
|
||||
}
|
||||
|
||||
PContentBridgeChild*
|
||||
@ -2474,6 +2474,21 @@ ContentChild::RecvGetProfile(nsCString* aProfile)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ContentChild::RecvLoadPluginResult(const uint32_t& aPluginId, const bool& aResult)
|
||||
{
|
||||
plugins::PluginModuleContentParent::OnLoadPluginResult(aPluginId, aResult);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ContentChild::RecvAssociatePluginId(const uint32_t& aPluginId,
|
||||
const base::ProcessId& aProcessId)
|
||||
{
|
||||
plugins::PluginModuleContentParent::AssociatePluginId(aPluginId, aProcessId);
|
||||
return true;
|
||||
}
|
||||
|
||||
PBrowserOrId
|
||||
ContentChild::GetBrowserOrId(TabChild* aTabChild)
|
||||
{
|
||||
|
@ -362,6 +362,11 @@ public:
|
||||
|
||||
virtual bool RecvOnAppThemeChanged() MOZ_OVERRIDE;
|
||||
|
||||
virtual bool RecvAssociatePluginId(const uint32_t& aPluginId,
|
||||
const base::ProcessId& aProcessId) MOZ_OVERRIDE;
|
||||
virtual bool RecvLoadPluginResult(const uint32_t& aPluginId,
|
||||
const bool& aResult) MOZ_OVERRIDE;
|
||||
|
||||
virtual bool RecvStartProfiler(const uint32_t& aEntries,
|
||||
const double& aInterval,
|
||||
const nsTArray<nsCString>& aFeatures,
|
||||
|
@ -59,6 +59,7 @@ using struct ChromePackage from "mozilla/chrome/RegistryMessageUtils.h";
|
||||
using struct ResourceMapping from "mozilla/chrome/RegistryMessageUtils.h";
|
||||
using struct OverrideMapping from "mozilla/chrome/RegistryMessageUtils.h";
|
||||
using base::ChildPrivileges from "base/process_util.h";
|
||||
using base::ProcessId from "base/process.h";
|
||||
using struct IPC::Permission from "mozilla/net/NeckoMessageUtils.h";
|
||||
using class IPC::Principal from "mozilla/dom/PermissionMessageUtils.h";
|
||||
using struct mozilla::null_t from "ipc/IPCMessageUtils.h";
|
||||
@ -518,6 +519,19 @@ child:
|
||||
*/
|
||||
OnAppThemeChanged();
|
||||
|
||||
/**
|
||||
* Called during plugin initialization to map a plugin id to a child process
|
||||
* id.
|
||||
*/
|
||||
async AssociatePluginId(uint32_t aPluginId, ProcessId aProcessId);
|
||||
|
||||
/**
|
||||
* This call is used by async plugin initialization to notify the
|
||||
* PluginModuleContentParent that the PluginModuleChromeParent's async
|
||||
* init has completed.
|
||||
*/
|
||||
async LoadPluginResult(uint32_t aPluginId, bool aResult);
|
||||
|
||||
/**
|
||||
* Control the Gecko Profiler in the child process.
|
||||
*/
|
||||
|
@ -157,56 +157,6 @@ DataContainerEventWarning=Use of DataContainerEvent is deprecated. Use CustomEve
|
||||
SendAsBinaryWarning=The non-standard sendAsBinary method is deprecated and will soon be removed. Use the standard send(Blob data) method instead.
|
||||
# LOCALIZATION NOTE: Do not translate "window.controllers"
|
||||
Window_ControllersWarning=window.controllers is deprecated. Do not use it for UA detection.
|
||||
# LOCALIZATION NOTE: Do not translate "KeyboardEvent.key", "Down" and "ArrowDown".
|
||||
KeyNameDownWarning=KeyboardEvent.key value "Down" is obsolete and will be renamed to "ArrowDown". For more help https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent.key
|
||||
# LOCALIZATION NOTE: Do not translate "KeyboardEvent.key", "Left" and "ArrowLeft".
|
||||
KeyNameLeftWarning=KeyboardEvent.key value "Left" is obsolete and will be renamed to "ArrowLeft". For more help https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent.key
|
||||
# LOCALIZATION NOTE: Do not translate "KeyboardEvent.key", "Right" and "ArrowRight".
|
||||
KeyNameRightWarning=KeyboardEvent.key value "Right" is obsolete and will be renamed to "ArrowRight". For more help https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent.key
|
||||
# LOCALIZATION NOTE: Do not translate "KeyboardEvent.key", "Up" and "ArrowUp".
|
||||
KeyNameUpWarning=KeyboardEvent.key value "Up" is obsolete and will be renamed to "ArrowUp". For more help https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent.key
|
||||
# LOCALIZATION NOTE: Do not translate "KeyboardEvent.key", "Crsel" and "CrSel".
|
||||
KeyNameCrselWarning=KeyboardEvent.key value "Crsel" is obsolete and will be renamed to "CrSel". For more help https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent.key
|
||||
# LOCALIZATION NOTE: Do not translate "KeyboardEvent.key", "Del" and "Delete".
|
||||
KeyNameDelWarning=KeyboardEvent.key value "Del" is obsolete and will be renamed to "Delete". For more help https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent.key
|
||||
# LOCALIZATION NOTE: Do not translate "KeyboardEvent.key", "Exsel" and "ExSel".
|
||||
KeyNameExselWarning=KeyboardEvent.key value "Exsel" is obsolete and will be renamed to "ExSel". For more help https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent.key
|
||||
# LOCALIZATION NOTE: Do not translate "KeyboardEvent.key", "Menu" and "ContextMenu".
|
||||
KeyNameMenuWarning=KeyboardEvent.key value "Menu" is obsolete and will be renamed to "ContextMenu". For more help https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent.key
|
||||
# LOCALIZATION NOTE: Do not translate "KeyboardEvent.key", "Esc" and "Escape".
|
||||
KeyNameEscWarning=KeyboardEvent.key value "Esc" is obsolete and will be renamed to "Escape". For more help https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent.key
|
||||
# LOCALIZATION NOTE: Do not translate "KeyboardEvent.key", "Nonconvert" and "NonConvert".
|
||||
KeyNameNonconvertWarning=KeyboardEvent.key value "Nonconvert" is obsolete and will be renamed to "NonConvert". For more help https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent.key
|
||||
# LOCALIZATION NOTE: Do not translate "KeyboardEvent.key", "HalfWidth" and "Hankaku".
|
||||
KeyNameHalfWidthWarning=KeyboardEvent.key value "HalfWidth" is obsolete and will be renamed to "Hankaku". For more help https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent.key
|
||||
# LOCALIZATION NOTE: Do not translate "KeyboardEvent.key", "RomanCharacters", "Romaji" and "Eisu".
|
||||
KeyNameRomanCharactersWarning=KeyboardEvent.key value "RomanCharacters" is obsolete and will be renamed to "Romaji" or remapped to "Eisu". For more help https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent.key
|
||||
# LOCALIZATION NOTE: Do not translate "KeyboardEvent.key", "FullWith" and "Zenkaku".
|
||||
KeyNameFullWidthWarning=KeyboardEvent.key value "FullWidth" is obsolete and will be renamed to "Zenkaku". For more help https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent.key
|
||||
# LOCALIZATION NOTE: Do not translate "KeyboardEvent.key", "SelectMedia" and "MediaSelect".
|
||||
KeyNameSelectMediaWarning=KeyboardEvent.key value "SelectMedia" is obsolete and will be renamed to "MediaSelect". For more help https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent.key
|
||||
# LOCALIZATION NOTE: Do not translate "KeyboardEvent.key", "MediaNextTrack" and "MediaTrackNext".
|
||||
KeyNameMediaNextTrackWarning=KeyboardEvent.key value "MediaNextTrack" is obsolete and will be renamed to "MediaTrackNext". For more help https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent.key
|
||||
# LOCALIZATION NOTE: Do not translate "KeyboardEvent.key", "MediaPreviousTrack" and "MediaTrackPrevious".
|
||||
KeyNameMediaPreviousTrackWarning=KeyboardEvent.key value "MediaPreviousTrack" is obsolete and will be renamed to "MediaTrackPrevious". For more help https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent.key
|
||||
# LOCALIZATION NOTE: Do not translate "KeyboardEvent.key", "Red" and "ColorF0Red".
|
||||
KeyNameRedWarning=KeyboardEvent.key value "Red" is obsolete and will be renamed to "ColorF0Red". For more help https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent.key
|
||||
# LOCALIZATION NOTE: Do not translate "KeyboardEvent.key", "Green" and "ColorF1Green".
|
||||
KeyNameGreenWarning=KeyboardEvent.key value "Green" is obsolete and will be renamed to "ColorF1Green". For more help https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent.key
|
||||
# LOCALIZATION NOTE: Do not translate "KeyboardEvent.key", "Yellow" and "ColorF2Yellow".
|
||||
KeyNameYellowWarning=KeyboardEvent.key value "Yellow" is obsolete and will be renamed to "ColorF2Yellow". For more help https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent.key
|
||||
# LOCALIZATION NOTE: Do not translate "KeyboardEvent.key", "Blue" and "ColorF3Blue".
|
||||
KeyNameBlueWarning=KeyboardEvent.key value "Blue" is obsolete and will be renamed to "ColorF3Blue". For more help https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent.key
|
||||
# LOCALIZATION NOTE: Do not translate "KeyboardEvent.key", "Live".
|
||||
KeyNameLiveWarning=KeyboardEvent.key value "Live" is obsolete and will be removed. For more help https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent.key
|
||||
# LOCALIZATION NOTE: Do not translate "KeyboardEvent.key", "Apps".
|
||||
KeyNameAppsWarning=KeyboardEvent.key value "Apps" is obsolete and will be removed. For more help https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent.key
|
||||
# LOCALIZATION NOTE: Do not translate "KeyboardEvent.key", "FastFwd" and "MediaFastForward".
|
||||
KeyNameFastFwdWarning=KeyboardEvent.key value "FastFwd" is obsolete and will be renamed to "MediaFastForward". For more help https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent.key
|
||||
# LOCALIZATION NOTE: Do not translate "KeyboardEvent.key", "Zoom" and "ZoomToggle".
|
||||
KeyNameZoomWarning=KeyboardEvent.key value "Zoom" is obsolete and will be renamed to "ZoomToggle". For more help https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent.key
|
||||
# LOCALIZATION NOTE: Do not translate "KeyboardEvent.key" and "Dead".
|
||||
KeyNameDeadKeysWarning=KeyboardEvent.key values starting with "Dead" are obsolete and will be merged into just "Dead". For more help https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent.key
|
||||
ImportXULIntoContentWarning=Importing XUL nodes into a content document is deprecated. This functionality may be removed soon.
|
||||
XMLDocumentLoadPrincipalMismatch=Use of document.load forbidden on Documents that come from other Windows. Only the Window in which a Document was created is allowed to call .load on that Document. Preferably, use XMLHttpRequest instead.
|
||||
# LOCALIZATION NOTE: Do not translate "IndexedDB".
|
||||
|
@ -15,8 +15,9 @@ SHA1Sig=This site makes use of a SHA-1 Certificate; it's recommended you use cer
|
||||
InsecurePasswordsPresentOnPage=Password fields present on an insecure (http://) page. This is a security risk that allows user login credentials to be stolen.
|
||||
InsecureFormActionPasswordsPresent=Password fields present in a form with an insecure (http://) form action. This is a security risk that allows user login credentials to be stolen.
|
||||
InsecurePasswordsPresentOnIframe=Password fields present on an insecure (http://) iframe. This is a security risk that allows user login credentials to be stolen.
|
||||
LoadingMixedActiveContent=Loading mixed (insecure) active content on a secure page "%1$S"
|
||||
LoadingMixedDisplayContent=Loading mixed (insecure) display content on a secure page "%1$S"
|
||||
# LOCALIZATION NOTE: "%1$S" is the URI of the insecure mixed content resource
|
||||
LoadingMixedActiveContent2=Loading mixed (insecure) active content "%1$S" on a secure page
|
||||
LoadingMixedDisplayContent2=Loading mixed (insecure) display content "%1$S" on a secure page
|
||||
# LOCALIZATION NOTE: Do not translate "allow-scripts", "allow-same-origin", "sandbox" or "iframe"
|
||||
BothAllowScriptsAndSameOriginPresent=An iframe which has both allow-scripts and allow-same-origin for its sandbox attribute can remove its sandboxing.
|
||||
|
||||
|
@ -232,9 +232,6 @@ MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder,
|
||||
mBufferingWait = mScheduler->IsRealTime() ? 0 : 30;
|
||||
mLowDataThresholdUsecs = mScheduler->IsRealTime() ? 0 : LOW_DATA_THRESHOLD_USECS;
|
||||
|
||||
mVideoPrerollFrames = mScheduler->IsRealTime() ? 0 : mAmpleVideoFrames / 2;
|
||||
mAudioPrerollUsecs = mScheduler->IsRealTime() ? 0 : LOW_AUDIO_USECS * 2;
|
||||
|
||||
#ifdef XP_WIN
|
||||
// Ensure high precision timers are enabled on Windows, otherwise the state
|
||||
// machine thread isn't woken up at reliable intervals to set the next frame,
|
||||
@ -633,18 +630,7 @@ MediaDecoderStateMachine::DecodeVideo()
|
||||
return;
|
||||
}
|
||||
|
||||
// We don't want to consider skipping to the next keyframe if we've
|
||||
// only just started up the decode loop, so wait until we've decoded
|
||||
// some frames before enabling the keyframe skip logic on video.
|
||||
if (mIsVideoPrerolling &&
|
||||
(static_cast<uint32_t>(VideoQueue().GetSize())
|
||||
>= mVideoPrerollFrames * mPlaybackRate))
|
||||
{
|
||||
mIsVideoPrerolling = false;
|
||||
}
|
||||
|
||||
skipToNextKeyFrame = NeedToSkipToNextKeyframe();
|
||||
|
||||
currentTime = mState == DECODER_STATE_SEEKING ? 0 : GetMediaTime();
|
||||
|
||||
// Time the video decode, so that if it's slow, we can increase our low
|
||||
@ -693,14 +679,6 @@ MediaDecoderStateMachine::DecodeAudio()
|
||||
mon.NotifyAll();
|
||||
return;
|
||||
}
|
||||
|
||||
// We don't want to consider skipping to the next keyframe if we've
|
||||
// only just started up the decode loop, so wait until we've decoded
|
||||
// some audio data before enabling the keyframe skip logic on audio.
|
||||
if (mIsAudioPrerolling &&
|
||||
GetDecodedAudioDuration() >= mAudioPrerollUsecs * mPlaybackRate) {
|
||||
mIsAudioPrerolling = false;
|
||||
}
|
||||
}
|
||||
|
||||
SAMPLE_LOG("DecodeAudio() queued=%i, decoder-queued=%o",
|
||||
@ -758,12 +736,19 @@ MediaDecoderStateMachine::OnAudioDecoded(AudioData* aAudioSample)
|
||||
return;
|
||||
}
|
||||
|
||||
case DECODER_STATE_BUFFERING:
|
||||
case DECODER_STATE_BUFFERING: {
|
||||
// If we're buffering, this may be the sample we need to stop buffering.
|
||||
// Schedule the state machine and then fall through.
|
||||
// Save it and schedule the state machine.
|
||||
Push(audio);
|
||||
ScheduleStateMachine();
|
||||
return;
|
||||
}
|
||||
|
||||
case DECODER_STATE_DECODING: {
|
||||
Push(audio);
|
||||
if (mIsAudioPrerolling && DonePrerollingAudio()) {
|
||||
StopPrerollingAudio();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@ -894,7 +879,13 @@ MediaDecoderStateMachine::OnNotDecoded(MediaData::Type aType,
|
||||
VideoQueue().Push(mFirstVideoFrameAfterSeek);
|
||||
mFirstVideoFrameAfterSeek = nullptr;
|
||||
}
|
||||
isAudio ? AudioQueue().Finish() : VideoQueue().Finish();
|
||||
if (isAudio) {
|
||||
AudioQueue().Finish();
|
||||
StopPrerollingAudio();
|
||||
} else {
|
||||
VideoQueue().Finish();
|
||||
StopPrerollingVideo();
|
||||
}
|
||||
switch (mState) {
|
||||
case DECODER_STATE_DECODING_FIRSTFRAME: {
|
||||
MaybeFinishDecodeFirstFrame();
|
||||
@ -973,12 +964,20 @@ MediaDecoderStateMachine::OnVideoDecoded(VideoData* aVideoSample)
|
||||
return;
|
||||
}
|
||||
|
||||
case DECODER_STATE_BUFFERING:
|
||||
case DECODER_STATE_BUFFERING: {
|
||||
// If we're buffering, this may be the sample we need to stop buffering.
|
||||
// Schedule the state machine and then fall through.
|
||||
// Save it and schedule the state machine.
|
||||
Push(video);
|
||||
ScheduleStateMachine();
|
||||
return;
|
||||
}
|
||||
|
||||
case DECODER_STATE_DECODING: {
|
||||
Push(video);
|
||||
if (mIsVideoPrerolling && DonePrerollingVideo()) {
|
||||
StopPrerollingVideo();
|
||||
}
|
||||
|
||||
// If the requested video sample was slow to arrive, increase the
|
||||
// amount of audio we buffer to ensure that we don't run out of audio.
|
||||
// TODO: Detect when we're truly async, and don't do this if so, as
|
||||
@ -1197,22 +1196,34 @@ int64_t MediaDecoderStateMachine::GetCurrentTimeViaMediaStreamSync() const
|
||||
return mSyncPointInDecodedStream + streamDelta;
|
||||
}
|
||||
|
||||
void MediaDecoderStateMachine::StartPlayback()
|
||||
void MediaDecoderStateMachine::MaybeStartPlayback()
|
||||
{
|
||||
DECODER_LOG("StartPlayback()");
|
||||
|
||||
NS_ASSERTION(!IsPlaying(), "Shouldn't be playing when StartPlayback() is called");
|
||||
AssertCurrentThreadInMonitor();
|
||||
if (IsPlaying()) {
|
||||
// Logging this case is really spammy - don't do it.
|
||||
return;
|
||||
}
|
||||
|
||||
bool playStatePermits = mDecoder->GetState() == MediaDecoder::PLAY_STATE_PLAYING;
|
||||
bool decodeStatePermits = mState == DECODER_STATE_DECODING || mState == DECODER_STATE_COMPLETED;
|
||||
if (!playStatePermits || !decodeStatePermits || mIsAudioPrerolling || mIsVideoPrerolling) {
|
||||
DECODER_LOG("Not starting playback [playStatePermits: %d, decodeStatePermits: %d, "
|
||||
"mIsAudioPrerolling: %d, mIsVideoPrerolling: %d]", (int) playStatePermits,
|
||||
(int) decodeStatePermits, (int) mIsAudioPrerolling, (int) mIsVideoPrerolling);
|
||||
return;
|
||||
}
|
||||
|
||||
if (mDecoder->CheckDecoderCanOffloadAudio()) {
|
||||
DECODER_LOG("Offloading playback");
|
||||
return;
|
||||
}
|
||||
|
||||
DECODER_LOG("MaybeStartPlayback() starting playback");
|
||||
|
||||
mDecoder->NotifyPlaybackStarted();
|
||||
SetPlayStartTime(TimeStamp::Now());
|
||||
MOZ_ASSERT(IsPlaying());
|
||||
|
||||
NS_ASSERTION(IsPlaying(), "Should report playing by end of StartPlayback()");
|
||||
nsresult rv = StartAudioThread();
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
|
||||
@ -1460,8 +1471,8 @@ void MediaDecoderStateMachine::StartDecoding()
|
||||
}
|
||||
|
||||
// Reset other state to pristine values before starting decode.
|
||||
mIsAudioPrerolling = true;
|
||||
mIsVideoPrerolling = true;
|
||||
mIsAudioPrerolling = !DonePrerollingAudio();
|
||||
mIsVideoPrerolling = !DonePrerollingVideo();
|
||||
|
||||
// Ensure that we've got tasks enqueued to decode data if we need to.
|
||||
DispatchDecodeTasksIfNeeded();
|
||||
@ -1502,25 +1513,45 @@ void MediaDecoderStateMachine::DoNotifyWaitingForResourcesStatusChanged()
|
||||
ScheduleStateMachine();
|
||||
}
|
||||
|
||||
void MediaDecoderStateMachine::Play()
|
||||
void MediaDecoderStateMachine::PlayInternal()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
|
||||
NS_ASSERTION(OnStateMachineThread(), "Should be on state machine thread.");
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
|
||||
// Once we start playing, we don't want to minimize our prerolling, as we
|
||||
// assume the user is likely to want to keep playing in future. This needs to
|
||||
// happen before we invoke StartDecoding().
|
||||
if (mMinimizePreroll) {
|
||||
mMinimizePreroll = false;
|
||||
DispatchDecodeTasksIfNeeded();
|
||||
}
|
||||
|
||||
// Some state transitions still happen synchronously on the main thread. So
|
||||
// if the main thread invokes Play() and then Seek(), the seek will initiate
|
||||
// synchronously on the main thread, and the asynchronous PlayInternal task
|
||||
// will arrive when it's no longer valid. The proper thing to do is to move
|
||||
// all state transitions to the state machine thread, but for now we just
|
||||
// make sure that none of the possible main-thread state transitions (Seek(),
|
||||
// SetDormant(), and Shutdown()) have not occurred.
|
||||
if (mState != DECODER_STATE_DECODING && mState != DECODER_STATE_BUFFERING &&
|
||||
mState != DECODER_STATE_COMPLETED)
|
||||
{
|
||||
DECODER_LOG("Unexpected state - Bailing out of PlayInternal()");
|
||||
return;
|
||||
}
|
||||
|
||||
// When asked to play, switch to decoding state only if
|
||||
// we are currently buffering. In other cases, we'll start playing anyway
|
||||
// when the state machine notices the decoder's state change to PLAYING.
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
if (mState == DECODER_STATE_BUFFERING) {
|
||||
DECODER_LOG("Changed state from BUFFERING to DECODING");
|
||||
SetState(DECODER_STATE_DECODING);
|
||||
mDecodeStartTime = TimeStamp::Now();
|
||||
StartDecoding();
|
||||
}
|
||||
|
||||
if (mDecodingFrozenAtStateDecoding) {
|
||||
mDecodingFrozenAtStateDecoding = false;
|
||||
DispatchDecodeTasksIfNeeded();
|
||||
}
|
||||
// Once we start playing, we don't want to minimize our prerolling, as we
|
||||
// assume the user is likely to want to keep playing in future.
|
||||
mMinimizePreroll = false;
|
||||
|
||||
ScheduleStateMachine();
|
||||
}
|
||||
|
||||
@ -2259,13 +2290,7 @@ MediaDecoderStateMachine::FinishDecodeFirstFrame()
|
||||
// So we need to check if this has occurred, else our decode pipeline won't
|
||||
// run (since it doesn't need to) and we won't detect end of stream.
|
||||
CheckIfDecodeComplete();
|
||||
|
||||
if ((mState == DECODER_STATE_DECODING || mState == DECODER_STATE_COMPLETED) &&
|
||||
mDecoder->GetState() == MediaDecoder::PLAY_STATE_PLAYING &&
|
||||
!IsPlaying())
|
||||
{
|
||||
StartPlayback();
|
||||
}
|
||||
MaybeStartPlayback();
|
||||
|
||||
if (mQueuedSeekTarget.IsValid()) {
|
||||
EnqueueStartQueuedSeekTask();
|
||||
@ -2642,12 +2667,8 @@ nsresult MediaDecoderStateMachine::RunStateMachine()
|
||||
StopPlayback();
|
||||
}
|
||||
|
||||
if (mDecoder->GetState() == MediaDecoder::PLAY_STATE_PLAYING &&
|
||||
!IsPlaying()) {
|
||||
// We are playing, but the state machine does not know it yet. Tell it
|
||||
// that it is, so that the clock can be properly queried.
|
||||
StartPlayback();
|
||||
}
|
||||
// Start playback if necessary so that the clock can be properly queried.
|
||||
MaybeStartPlayback();
|
||||
|
||||
AdvanceFrame();
|
||||
NS_ASSERTION(mDecoder->GetState() != MediaDecoder::PLAY_STATE_PLAYING ||
|
||||
@ -2682,8 +2703,8 @@ nsresult MediaDecoderStateMachine::RunStateMachine()
|
||||
MOZ_ASSERT(mReader->IsWaitForDataSupported(),
|
||||
"Don't yet have a strategy for non-heuristic + non-WaitForData");
|
||||
DispatchDecodeTasksIfNeeded();
|
||||
MOZ_ASSERT_IF(OutOfDecodedAudio(), mAudioRequestStatus != RequestStatus::Idle);
|
||||
MOZ_ASSERT_IF(OutOfDecodedVideo(), mVideoRequestStatus != RequestStatus::Idle);
|
||||
MOZ_ASSERT_IF(!mMinimizePreroll && OutOfDecodedAudio(), mAudioRequestStatus != RequestStatus::Idle);
|
||||
MOZ_ASSERT_IF(!mMinimizePreroll && OutOfDecodedVideo(), mVideoRequestStatus != RequestStatus::Idle);
|
||||
DECODER_LOG("In buffering mode, waiting to be notified: outOfAudio: %d, "
|
||||
"mAudioStatus: %d, outOfVideo: %d, mVideoStatus: %d",
|
||||
OutOfDecodedAudio(), mAudioRequestStatus,
|
||||
@ -2698,11 +2719,7 @@ nsresult MediaDecoderStateMachine::RunStateMachine()
|
||||
// Notify to allow blocked decoder thread to continue
|
||||
mDecoder->GetReentrantMonitor().NotifyAll();
|
||||
UpdateReadyState();
|
||||
if (mDecoder->GetState() == MediaDecoder::PLAY_STATE_PLAYING &&
|
||||
!IsPlaying())
|
||||
{
|
||||
StartPlayback();
|
||||
}
|
||||
MaybeStartPlayback();
|
||||
NS_ASSERTION(IsStateMachineScheduled(), "Must have timer scheduled");
|
||||
return NS_OK;
|
||||
}
|
||||
@ -2976,8 +2993,8 @@ void MediaDecoderStateMachine::AdvanceFrame()
|
||||
|
||||
// We've got enough data to keep playing until at least the next frame.
|
||||
// Start playing now if need be.
|
||||
if (!IsPlaying() && ((mFragmentEndTime >= 0 && clock_time < mFragmentEndTime) || mFragmentEndTime < 0)) {
|
||||
StartPlayback();
|
||||
if ((mFragmentEndTime >= 0 && clock_time < mFragmentEndTime) || mFragmentEndTime < 0) {
|
||||
MaybeStartPlayback();
|
||||
}
|
||||
|
||||
if (currentFrame) {
|
||||
@ -3363,6 +3380,7 @@ void
|
||||
MediaDecoderStateMachine::SetMinimizePrerollUntilPlaybackStarts()
|
||||
{
|
||||
AssertCurrentThreadInMonitor();
|
||||
DECODER_LOG("SetMinimizePrerollUntilPlaybackStarts()");
|
||||
mMinimizePreroll = true;
|
||||
}
|
||||
|
||||
|
@ -89,6 +89,7 @@ hardware (via AudioStream).
|
||||
#include "MediaDecoderReader.h"
|
||||
#include "MediaDecoderOwner.h"
|
||||
#include "MediaMetadataManager.h"
|
||||
#include "MediaDecoderStateMachineScheduler.h"
|
||||
|
||||
class nsITimer;
|
||||
|
||||
@ -197,7 +198,18 @@ public:
|
||||
// Cause state transitions. These methods obtain the decoder monitor
|
||||
// to synchronise the change of state, and to notify other threads
|
||||
// that the state has changed.
|
||||
void Play();
|
||||
void Play()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
nsRefPtr<nsRunnable> r = NS_NewRunnableMethod(this, &MediaDecoderStateMachine::PlayInternal);
|
||||
GetStateMachineThread()->Dispatch(r, NS_DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
private:
|
||||
// The actual work for the above, which happens asynchronously on the state
|
||||
// machine thread.
|
||||
void PlayInternal();
|
||||
public:
|
||||
|
||||
// Seeks to the decoder to aTarget asynchronously.
|
||||
// Must be called from the main thread.
|
||||
@ -580,9 +592,10 @@ protected:
|
||||
// The decoder monitor must be held.
|
||||
void StopPlayback();
|
||||
|
||||
// Sets internal state which causes playback of media to begin or resume.
|
||||
// If the conditions are right, sets internal state which causes playback
|
||||
// of media to begin or resume.
|
||||
// Must be called with the decode monitor held.
|
||||
void StartPlayback();
|
||||
void MaybeStartPlayback();
|
||||
|
||||
// Moves the decoder into decoding state. Called on the state machine
|
||||
// thread. The decoder monitor must be held.
|
||||
@ -931,8 +944,48 @@ protected:
|
||||
// unneccessarily if we start playing as soon as the first sample is
|
||||
// decoded. These two fields store how many video frames and audio
|
||||
// samples we must consume before are considered to be finished prerolling.
|
||||
uint32_t mAudioPrerollUsecs;
|
||||
uint32_t mVideoPrerollFrames;
|
||||
uint32_t AudioPrerollUsecs() const
|
||||
{
|
||||
if (mScheduler->IsRealTime()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t result = mLowAudioThresholdUsecs * 2;
|
||||
MOZ_ASSERT(result <= mAmpleAudioThresholdUsecs, "Prerolling will never finish");
|
||||
return result;
|
||||
}
|
||||
uint32_t VideoPrerollFrames() const { return mScheduler->IsRealTime() ? 0 : mAmpleVideoFrames / 2; }
|
||||
|
||||
bool DonePrerollingAudio()
|
||||
{
|
||||
AssertCurrentThreadInMonitor();
|
||||
return !IsAudioDecoding() || GetDecodedAudioDuration() >= AudioPrerollUsecs() * mPlaybackRate;
|
||||
}
|
||||
|
||||
bool DonePrerollingVideo()
|
||||
{
|
||||
AssertCurrentThreadInMonitor();
|
||||
return !IsVideoDecoding() ||
|
||||
static_cast<uint32_t>(VideoQueue().GetSize()) >= VideoPrerollFrames() * mPlaybackRate;
|
||||
}
|
||||
|
||||
void StopPrerollingAudio()
|
||||
{
|
||||
AssertCurrentThreadInMonitor();
|
||||
if (mIsAudioPrerolling) {
|
||||
mIsAudioPrerolling = false;
|
||||
ScheduleStateMachine();
|
||||
}
|
||||
}
|
||||
|
||||
void StopPrerollingVideo()
|
||||
{
|
||||
AssertCurrentThreadInMonitor();
|
||||
if (mIsVideoPrerolling) {
|
||||
mIsVideoPrerolling = false;
|
||||
ScheduleStateMachine();
|
||||
}
|
||||
}
|
||||
|
||||
// This temporarily stores the first frame we decode after we seek.
|
||||
// This is so that if we hit end of stream while we're decoding to reach
|
||||
|
@ -72,7 +72,7 @@ MP4Reader::MP4Reader(AbstractMediaDecoder* aDecoder)
|
||||
, mDemuxerInitialized(false)
|
||||
, mIsEncrypted(false)
|
||||
, mIndexReady(false)
|
||||
, mIndexMonitor("MP4 index")
|
||||
, mDemuxerMonitor("MP4 Demuxer")
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread.");
|
||||
MOZ_COUNT_CTOR(MP4Reader);
|
||||
@ -157,7 +157,7 @@ MP4Reader::Init(MediaDecoderReader* aCloneDonor)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread.");
|
||||
PlatformDecoderModule::Init();
|
||||
mDemuxer = new MP4Demuxer(new MP4Stream(mDecoder->GetResource(), &mIndexMonitor), &mIndexMonitor);
|
||||
mDemuxer = new MP4Demuxer(new MP4Stream(mDecoder->GetResource(), &mDemuxerMonitor), &mDemuxerMonitor);
|
||||
|
||||
InitLayersBackendType();
|
||||
|
||||
@ -294,12 +294,10 @@ MP4Reader::ReadMetadata(MediaInfo* aInfo,
|
||||
MetadataTags** aTags)
|
||||
{
|
||||
if (!mDemuxerInitialized) {
|
||||
{
|
||||
MonitorAutoLock mon(mIndexMonitor);
|
||||
bool ok = mDemuxer->Init();
|
||||
NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE);
|
||||
mIndexReady = true;
|
||||
}
|
||||
MonitorAutoLock mon(mDemuxerMonitor);
|
||||
bool ok = mDemuxer->Init();
|
||||
NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE);
|
||||
mIndexReady = true;
|
||||
|
||||
// To decode, we need valid video and a place to put it.
|
||||
mInfo.mVideo.mHasVideo = mVideo.mActive = mDemuxer->HasValidVideo() &&
|
||||
@ -308,6 +306,7 @@ MP4Reader::ReadMetadata(MediaInfo* aInfo,
|
||||
mInfo.mAudio.mHasAudio = mAudio.mActive = mDemuxer->HasValidAudio();
|
||||
|
||||
{
|
||||
MonitorAutoUnlock unlock(mDemuxerMonitor);
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
mIsEncrypted = mDemuxer->Crypto().valid;
|
||||
}
|
||||
@ -411,7 +410,11 @@ MP4Reader::ReadMetadata(MediaInfo* aInfo,
|
||||
}
|
||||
|
||||
// Get the duration, and report it to the decoder if we have it.
|
||||
Microseconds duration = mDemuxer->Duration();
|
||||
Microseconds duration;
|
||||
{
|
||||
MonitorAutoLock lock(mDemuxerMonitor);
|
||||
duration = mDemuxer->Duration();
|
||||
}
|
||||
if (duration != -1) {
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
mDecoder->SetMediaDuration(duration);
|
||||
@ -420,7 +423,7 @@ MP4Reader::ReadMetadata(MediaInfo* aInfo,
|
||||
*aInfo = mInfo;
|
||||
*aTags = nullptr;
|
||||
|
||||
MonitorAutoLock mon(mIndexMonitor);
|
||||
MonitorAutoLock mon(mDemuxerMonitor);
|
||||
UpdateIndex();
|
||||
|
||||
return NS_OK;
|
||||
@ -437,6 +440,7 @@ MP4Reader::IsMediaSeekable()
|
||||
{
|
||||
// We can seek if we get a duration *and* the reader reports that it's
|
||||
// seekable.
|
||||
MonitorAutoLock mon(mDemuxerMonitor);
|
||||
return mDecoder->GetResource()->IsTransportSeekable() && mDemuxer->CanSeek();
|
||||
}
|
||||
|
||||
@ -631,7 +635,14 @@ MP4Reader::ReturnOutput(MediaData* aData, TrackType aTrack)
|
||||
MP4Sample*
|
||||
MP4Reader::PopSample(TrackType aTrack)
|
||||
{
|
||||
MonitorAutoLock mon(mIndexMonitor);
|
||||
MonitorAutoLock mon(mDemuxerMonitor);
|
||||
return PopSampleLocked(aTrack);
|
||||
}
|
||||
|
||||
MP4Sample*
|
||||
MP4Reader::PopSampleLocked(TrackType aTrack)
|
||||
{
|
||||
mDemuxerMonitor.AssertCurrentThreadOwns();
|
||||
switch (aTrack) {
|
||||
case kAudio:
|
||||
return mDemuxer->DemuxAudioSample();
|
||||
@ -673,12 +684,12 @@ MP4Reader::ResetDecode()
|
||||
MOZ_ASSERT(GetTaskQueue()->IsCurrentThreadIn());
|
||||
Flush(kVideo);
|
||||
{
|
||||
MonitorAutoLock mon(mIndexMonitor);
|
||||
MonitorAutoLock mon(mDemuxerMonitor);
|
||||
mDemuxer->SeekVideo(0);
|
||||
}
|
||||
Flush(kAudio);
|
||||
{
|
||||
MonitorAutoLock mon(mIndexMonitor);
|
||||
MonitorAutoLock mon(mDemuxerMonitor);
|
||||
mDemuxer->SeekAudio(0);
|
||||
}
|
||||
return MediaDecoderReader::ResetDecode();
|
||||
@ -821,6 +832,7 @@ MP4Reader::Seek(int64_t aTime,
|
||||
{
|
||||
LOG("MP4Reader::Seek(%lld)", aTime);
|
||||
MOZ_ASSERT(GetTaskQueue()->IsCurrentThreadIn());
|
||||
MonitorAutoLock mon(mDemuxerMonitor);
|
||||
if (!mDecoder->GetResource()->IsTransportSeekable() || !mDemuxer->CanSeek()) {
|
||||
VLOG("Seek() END (Unseekable)");
|
||||
return SeekPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
|
||||
@ -829,7 +841,7 @@ MP4Reader::Seek(int64_t aTime,
|
||||
mQueuedVideoSample = nullptr;
|
||||
if (mDemuxer->HasValidVideo()) {
|
||||
mDemuxer->SeekVideo(aTime);
|
||||
mQueuedVideoSample = PopSample(kVideo);
|
||||
mQueuedVideoSample = PopSampleLocked(kVideo);
|
||||
}
|
||||
if (mDemuxer->HasValidAudio()) {
|
||||
mDemuxer->SeekAudio(
|
||||
@ -856,7 +868,7 @@ MP4Reader::UpdateIndex()
|
||||
int64_t
|
||||
MP4Reader::GetEvictionOffset(double aTime)
|
||||
{
|
||||
MonitorAutoLock mon(mIndexMonitor);
|
||||
MonitorAutoLock mon(mDemuxerMonitor);
|
||||
if (!mIndexReady) {
|
||||
return 0;
|
||||
}
|
||||
@ -867,7 +879,7 @@ MP4Reader::GetEvictionOffset(double aTime)
|
||||
nsresult
|
||||
MP4Reader::GetBuffered(dom::TimeRanges* aBuffered)
|
||||
{
|
||||
MonitorAutoLock mon(mIndexMonitor);
|
||||
MonitorAutoLock mon(mDemuxerMonitor);
|
||||
if (!mIndexReady) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -102,6 +102,7 @@ private:
|
||||
// Blocks until the demuxer produces an sample of specified type.
|
||||
// Returns nullptr on error on EOS. Caller must delete sample.
|
||||
mp4_demuxer::MP4Sample* PopSample(mp4_demuxer::TrackType aTrack);
|
||||
mp4_demuxer::MP4Sample* PopSampleLocked(mp4_demuxer::TrackType aTrack);
|
||||
|
||||
bool SkipVideoDemuxToNextKeyFrame(int64_t aTimeThreshold, uint32_t& parsed);
|
||||
|
||||
@ -259,7 +260,7 @@ private:
|
||||
bool mIsEncrypted;
|
||||
|
||||
bool mIndexReady;
|
||||
Monitor mIndexMonitor;
|
||||
Monitor mDemuxerMonitor;
|
||||
nsRefPtr<SharedDecoderManager> mSharedDecoderManager;
|
||||
};
|
||||
|
||||
|
@ -289,10 +289,8 @@ AppleVDADecoder::OutputFrame(CVPixelBufferRef aImage,
|
||||
// Frames come out in DTS order but we need to output them
|
||||
// in composition order.
|
||||
mReorderQueue.Push(data);
|
||||
// Assume a frame with a PTS <= current DTS is ready.
|
||||
while (mReorderQueue.Length() > mMaxRefFrames) {
|
||||
nsRefPtr<VideoData> readyData = mReorderQueue.Pop();
|
||||
mCallback->Output(readyData);
|
||||
mCallback->Output(mReorderQueue.Pop());
|
||||
}
|
||||
LOG("%llu decoded frames queued",
|
||||
static_cast<unsigned long long>(mReorderQueue.Length()));
|
||||
|
@ -102,6 +102,7 @@ EXPORTS += [
|
||||
'MediaDecoderOwner.h',
|
||||
'MediaDecoderReader.h',
|
||||
'MediaDecoderStateMachine.h',
|
||||
'MediaDecoderStateMachineScheduler.h',
|
||||
'MediaInfo.h',
|
||||
'MediaMetadataManager.h',
|
||||
'MediaPromise.h',
|
||||
|
@ -37,6 +37,7 @@
|
||||
#include "ImageContainer.h"
|
||||
#include "SharedThreadPool.h"
|
||||
#include "VideoFrameContainer.h"
|
||||
#include "VideoUtils.h"
|
||||
|
||||
using namespace android;
|
||||
|
||||
@ -1275,14 +1276,12 @@ MediaCodecReader::CreateTaskQueues()
|
||||
{
|
||||
if (mAudioTrack.mSource != nullptr && mAudioTrack.mCodec != nullptr &&
|
||||
!mAudioTrack.mTaskQueue) {
|
||||
mAudioTrack.mTaskQueue = new MediaTaskQueue(
|
||||
SharedThreadPool::Get(NS_LITERAL_CSTRING("MediaCodecReader Audio"), 1));
|
||||
mAudioTrack.mTaskQueue = CreateMediaDecodeTaskQueue();
|
||||
NS_ENSURE_TRUE(mAudioTrack.mTaskQueue, false);
|
||||
}
|
||||
if (mVideoTrack.mSource != nullptr && mVideoTrack.mCodec != nullptr &&
|
||||
!mVideoTrack.mTaskQueue) {
|
||||
mVideoTrack.mTaskQueue = new MediaTaskQueue(
|
||||
SharedThreadPool::Get(NS_LITERAL_CSTRING("MediaCodecReader Video"), 1));
|
||||
if (mVideoTrack.mSource != nullptr && mVideoTrack.mCodec != nullptr &&
|
||||
!mVideoTrack.mTaskQueue) {
|
||||
mVideoTrack.mTaskQueue = CreateMediaDecodeTaskQueue();
|
||||
NS_ENSURE_TRUE(mVideoTrack.mTaskQueue, false);
|
||||
}
|
||||
|
||||
|
@ -19,6 +19,7 @@ var manager = new MediaTestManager;
|
||||
|
||||
function loaded(event) {
|
||||
var v = event.target;
|
||||
info(v.token + ": event=" + event.type);
|
||||
if (v._finished)
|
||||
return;
|
||||
v.play();
|
||||
@ -26,19 +27,21 @@ function loaded(event) {
|
||||
|
||||
function started(event) {
|
||||
var v = event.target;
|
||||
info(v.token + ": event=" + event.type);
|
||||
if (v._finished)
|
||||
return;
|
||||
ok(!v.paused, "Video should not be paused while playing");
|
||||
ok(!v.paused, v.token + ": Video should not be paused while playing");
|
||||
v.parentNode.removeChild(v);
|
||||
v._played = true;
|
||||
}
|
||||
|
||||
function stopped(event) {
|
||||
var v = event.target;
|
||||
info(v.token + ": event=" + event.type);
|
||||
if (v._finished)
|
||||
return;
|
||||
v._finished = true;
|
||||
ok(v.paused, "Video should be paused after removing from the Document");
|
||||
ok(v.paused, v.token + ": Video should be paused after removing from the Document");
|
||||
removeNodeAndSource(v);
|
||||
manager.finished(v.token);
|
||||
}
|
||||
|
@ -28,7 +28,10 @@
|
||||
#include "js/HashTable.h"
|
||||
#include "mozilla/HashFunctions.h"
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
#include "mozilla/plugins/PluginAsyncSurrogate.h"
|
||||
|
||||
using mozilla::plugins::AsyncNPObject;
|
||||
using mozilla::plugins::PluginAsyncSurrogate;
|
||||
|
||||
#define NPRUNTIME_JSCLASS_NAME "NPObject JS wrapper class"
|
||||
|
||||
@ -94,10 +97,24 @@ static nsTArray<NPObject*>* sDelayedReleases;
|
||||
|
||||
namespace {
|
||||
|
||||
inline void
|
||||
CastNPObject(NPObject *aObj, PluginScriptableObjectParent*& aActor,
|
||||
PluginAsyncSurrogate*& aSurrogate)
|
||||
{
|
||||
aActor = nullptr;
|
||||
aSurrogate = nullptr;
|
||||
if (aObj->_class == PluginScriptableObjectParent::GetClass()) {
|
||||
aActor = static_cast<ParentNPObject*>(aObj)->parent;
|
||||
} else if (aObj->_class == PluginAsyncSurrogate::GetClass()) {
|
||||
aSurrogate = static_cast<AsyncNPObject*>(aObj)->mSurrogate;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool
|
||||
NPObjectIsOutOfProcessProxy(NPObject *obj)
|
||||
{
|
||||
return obj->_class == PluginScriptableObjectParent::GetClass();
|
||||
return obj->_class == PluginScriptableObjectParent::GetClass() ||
|
||||
obj->_class == PluginAsyncSurrogate::GetClass();
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
@ -1389,15 +1406,23 @@ NPObjWrapper_GetProperty(JSContext *cx, JS::Handle<JSObject*> obj, JS::Handle<js
|
||||
NPIdentifier identifier = JSIdToNPIdentifier(id);
|
||||
|
||||
if (NPObjectIsOutOfProcessProxy(npobj)) {
|
||||
PluginScriptableObjectParent* actor =
|
||||
static_cast<ParentNPObject*>(npobj)->parent;
|
||||
PluginScriptableObjectParent* actor = nullptr;
|
||||
PluginAsyncSurrogate* surrogate = nullptr;
|
||||
CastNPObject(npobj, actor, surrogate);
|
||||
|
||||
// actor may be null if the plugin crashed.
|
||||
if (!actor)
|
||||
// actor and surrogate may be null if the plugin crashed.
|
||||
if (!actor && !surrogate)
|
||||
return false;
|
||||
|
||||
bool success = actor->GetPropertyHelper(identifier, &hasProperty,
|
||||
&hasMethod, &npv);
|
||||
bool success = false;
|
||||
if (surrogate) {
|
||||
success = surrogate->GetPropertyHelper(npobj, identifier, &hasProperty,
|
||||
&hasMethod, &npv);
|
||||
} else if (actor) {
|
||||
success = actor->GetPropertyHelper(identifier, &hasProperty, &hasMethod,
|
||||
&npv);
|
||||
}
|
||||
|
||||
if (!ReportExceptionIfPending(cx)) {
|
||||
if (success)
|
||||
_releasevariantvalue(&npv);
|
||||
@ -2253,3 +2278,35 @@ NPObjectMember_Trace(JSTracer *trc, JSObject *obj)
|
||||
"NPObject Member => npobjWrapper");
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
bool
|
||||
nsJSObjWrapper::HasOwnProperty(NPObject *npobj, NPIdentifier npid)
|
||||
{
|
||||
NPP npp = NPPStack::Peek();
|
||||
dom::AutoJSAPI jsapi;
|
||||
if (NS_WARN_IF(!jsapi.InitWithLegacyErrorReporting(GetGlobalObject(npp)))) {
|
||||
return false;
|
||||
}
|
||||
JSContext *cx = jsapi.cx();
|
||||
|
||||
if (!npobj) {
|
||||
ThrowJSException(cx,
|
||||
"Null npobj in nsJSObjWrapper::NP_HasOwnProperty!");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
nsJSObjWrapper *npjsobj = (nsJSObjWrapper *)npobj;
|
||||
bool found, ok = false;
|
||||
|
||||
AutoJSExceptionReporter reporter(cx);
|
||||
JS::Rooted<JSObject*> jsobj(cx, npjsobj->mJSObj);
|
||||
JSAutoCompartment ac(cx, jsobj);
|
||||
|
||||
NS_ASSERTION(NPIdentifierIsInt(npid) || NPIdentifierIsString(npid),
|
||||
"id must be either string or int!\n");
|
||||
JS::Rooted<jsid> id(cx, NPIdentifierToJSId(npid));
|
||||
ok = ::JS_AlreadyHasOwnPropertyById(cx, jsobj, id, &found);
|
||||
return ok && found;
|
||||
}
|
||||
|
@ -44,6 +44,7 @@ public:
|
||||
|
||||
static NPObject *GetNewOrUsed(NPP npp, JSContext *cx,
|
||||
JS::Handle<JSObject*> obj);
|
||||
static bool HasOwnProperty(NPObject* npobj, NPIdentifier npid);
|
||||
|
||||
protected:
|
||||
explicit nsJSObjWrapper(NPP npp);
|
||||
|
@ -523,7 +523,7 @@ nsNPAPIPluginInstance::Start()
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
return newResult;
|
||||
}
|
||||
|
||||
nsresult nsNPAPIPluginInstance::SetWindow(NPWindow* window)
|
||||
|
@ -331,20 +331,32 @@ nsNPAPIPluginStreamListener::OnStartBinding(nsPluginStreamListenerPeer* streamPe
|
||||
|
||||
if (error != NPERR_NO_ERROR)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
switch(streamType)
|
||||
|
||||
if (streamType == nsPluginStreamListenerPeer::STREAM_TYPE_UNKNOWN) {
|
||||
SuspendRequest();
|
||||
} else if (!SetStreamType(streamType, false)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
nsNPAPIPluginStreamListener::SetStreamType(uint16_t aType, bool aNeedsResume)
|
||||
{
|
||||
switch(aType)
|
||||
{
|
||||
case NP_NORMAL:
|
||||
mStreamType = NP_NORMAL;
|
||||
mStreamType = NP_NORMAL;
|
||||
break;
|
||||
case NP_ASFILEONLY:
|
||||
mStreamType = NP_ASFILEONLY;
|
||||
mStreamType = NP_ASFILEONLY;
|
||||
break;
|
||||
case NP_ASFILE:
|
||||
mStreamType = NP_ASFILE;
|
||||
mStreamType = NP_ASFILE;
|
||||
break;
|
||||
case NP_SEEK:
|
||||
mStreamType = NP_SEEK;
|
||||
mStreamType = NP_SEEK;
|
||||
// Seekable streams should continue to exist even after OnStopRequest
|
||||
// is fired, so we AddRef ourself an extra time and Release when the
|
||||
// plugin calls NPN_DestroyStream (CleanUpStream). If the plugin never
|
||||
@ -353,11 +365,16 @@ nsNPAPIPluginStreamListener::OnStartBinding(nsPluginStreamListenerPeer* streamPe
|
||||
NS_ADDREF_THIS();
|
||||
break;
|
||||
default:
|
||||
return NS_ERROR_FAILURE;
|
||||
return false;
|
||||
}
|
||||
|
||||
mStreamStarted = true;
|
||||
return NS_OK;
|
||||
if (aNeedsResume) {
|
||||
if (mStreamListenerPeer) {
|
||||
mStreamListenerPeer->OnStreamTypeSet(mStreamType);
|
||||
}
|
||||
ResumeRequest();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
@ -369,18 +386,20 @@ nsNPAPIPluginStreamListener::SuspendRequest()
|
||||
nsresult rv = StartDataPump();
|
||||
if (NS_FAILED(rv))
|
||||
return;
|
||||
|
||||
|
||||
mIsSuspended = true;
|
||||
|
||||
if (mStreamListenerPeer) {
|
||||
mStreamListenerPeer->SuspendRequests();
|
||||
mStreamListenerPeer->SuspendRequests();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsNPAPIPluginStreamListener::ResumeRequest()
|
||||
{
|
||||
mStreamListenerPeer->ResumeRequests();
|
||||
if (mStreamListenerPeer) {
|
||||
mStreamListenerPeer->ResumeRequests();
|
||||
}
|
||||
mIsSuspended = false;
|
||||
}
|
||||
|
||||
@ -390,7 +409,7 @@ nsNPAPIPluginStreamListener::StartDataPump()
|
||||
nsresult rv;
|
||||
mDataPumpTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
|
||||
// Start pumping data to the plugin every 100ms until it obeys and
|
||||
// eats the data.
|
||||
return mDataPumpTimer->InitWithCallback(this, 100,
|
||||
|
@ -83,6 +83,7 @@ public:
|
||||
nsresult OnStopBinding(nsPluginStreamListenerPeer* streamPeer,
|
||||
nsresult status);
|
||||
nsresult GetStreamType(int32_t *result);
|
||||
bool SetStreamType(uint16_t aType, bool aNeedsResume = true);
|
||||
|
||||
bool IsStarted();
|
||||
nsresult CleanUpStream(NPReason reason);
|
||||
|
@ -50,6 +50,7 @@
|
||||
#include "nsPluginStreamListenerPeer.h"
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
#include "mozilla/LoadInfo.h"
|
||||
#include "mozilla/plugins/PluginAsyncSurrogate.h"
|
||||
#include "mozilla/plugins/PluginBridge.h"
|
||||
#include "mozilla/plugins/PluginTypes.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
@ -110,6 +111,7 @@
|
||||
using namespace mozilla;
|
||||
using mozilla::TimeStamp;
|
||||
using mozilla::plugins::PluginTag;
|
||||
using mozilla::plugins::PluginAsyncSurrogate;
|
||||
|
||||
// Null out a strong ref to a linked list iteratively to avoid
|
||||
// exhausting the stack (bug 486349).
|
||||
@ -830,6 +832,7 @@ nsPluginHost::InstantiatePluginInstance(const char *aMimeType, nsIURI* aURL,
|
||||
if (NS_FAILED(rv)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
const bool isAsyncInit = (rv == NS_PLUGIN_INIT_PENDING);
|
||||
|
||||
nsRefPtr<nsNPAPIPluginInstance> instance;
|
||||
rv = instanceOwner->GetInstance(getter_AddRefs(instance));
|
||||
@ -837,11 +840,9 @@ nsPluginHost::InstantiatePluginInstance(const char *aMimeType, nsIURI* aURL,
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (instance) {
|
||||
instanceOwner->CreateWidget();
|
||||
|
||||
// If we've got a native window, the let the plugin know about it.
|
||||
instanceOwner->CallSetWindow();
|
||||
// Async init plugins will initiate their own widget creation.
|
||||
if (!isAsyncInit && instance) {
|
||||
CreateWidget(instanceOwner);
|
||||
}
|
||||
|
||||
// At this point we consider instantiation to be successful. Do not return an error.
|
||||
@ -3327,6 +3328,14 @@ nsresult nsPluginHost::NewPluginStreamListener(nsIURI* aURI,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void nsPluginHost::CreateWidget(nsPluginInstanceOwner* aOwner)
|
||||
{
|
||||
aOwner->CreateWidget();
|
||||
|
||||
// If we've got a native window, the let the plugin know about it.
|
||||
aOwner->CallSetWindow();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsPluginHost::Observe(nsISupports *aSubject,
|
||||
const char *aTopic,
|
||||
const char16_t *someData)
|
||||
@ -3954,6 +3963,12 @@ PluginDestructionGuard::PluginDestructionGuard(nsNPAPIPluginInstance *aInstance)
|
||||
Init();
|
||||
}
|
||||
|
||||
PluginDestructionGuard::PluginDestructionGuard(PluginAsyncSurrogate *aSurrogate)
|
||||
: mInstance(static_cast<nsNPAPIPluginInstance*>(aSurrogate->GetNPP()->ndata))
|
||||
{
|
||||
InitAsync();
|
||||
}
|
||||
|
||||
PluginDestructionGuard::PluginDestructionGuard(NPP npp)
|
||||
: mInstance(npp ? static_cast<nsNPAPIPluginInstance*>(npp->ndata) : nullptr)
|
||||
{
|
||||
|
@ -30,6 +30,12 @@
|
||||
#include "nsCRT.h"
|
||||
#include "mozilla/plugins/PluginTypes.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace plugins {
|
||||
class PluginAsyncSurrogate;
|
||||
} // namespace mozilla
|
||||
} // namespace plugins
|
||||
|
||||
class nsNPAPIPlugin;
|
||||
class nsIComponentManager;
|
||||
class nsIFile;
|
||||
@ -203,6 +209,8 @@ public:
|
||||
nsNPAPIPluginInstance* aInstance,
|
||||
nsIStreamListener **aStreamListener);
|
||||
|
||||
void CreateWidget(nsPluginInstanceOwner* aOwner);
|
||||
|
||||
private:
|
||||
friend class nsPluginUnloadRunnable;
|
||||
|
||||
@ -333,11 +341,11 @@ private:
|
||||
static nsPluginHost* sInst;
|
||||
};
|
||||
|
||||
class MOZ_STACK_CLASS PluginDestructionGuard : protected PRCList
|
||||
class PluginDestructionGuard : protected PRCList
|
||||
{
|
||||
public:
|
||||
explicit PluginDestructionGuard(nsNPAPIPluginInstance *aInstance);
|
||||
|
||||
explicit PluginDestructionGuard(mozilla::plugins::PluginAsyncSurrogate *aSurrogate);
|
||||
explicit PluginDestructionGuard(NPP npp);
|
||||
|
||||
~PluginDestructionGuard();
|
||||
@ -355,6 +363,18 @@ protected:
|
||||
PR_INSERT_BEFORE(this, &sListHead);
|
||||
}
|
||||
|
||||
void InitAsync()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Should be on the main thread");
|
||||
|
||||
mDelayedDestroy = false;
|
||||
|
||||
PR_INIT_CLIST(this);
|
||||
// Instances with active surrogates must be inserted *after* sListHead so
|
||||
// that they appear to be at the bottom of the stack
|
||||
PR_INSERT_AFTER(this, &sListHead);
|
||||
}
|
||||
|
||||
nsRefPtr<nsNPAPIPluginInstance> mInstance;
|
||||
bool mDelayedDestroy;
|
||||
|
||||
|
@ -1452,6 +1452,28 @@ void nsPluginInstanceOwner::ExitFullScreen(jobject view) {
|
||||
|
||||
#endif
|
||||
|
||||
void
|
||||
nsPluginInstanceOwner::NotifyHostAsyncInitFailed()
|
||||
{
|
||||
nsCOMPtr<nsIObjectLoadingContent> content = do_QueryInterface(mContent);
|
||||
content->StopPluginInstance();
|
||||
}
|
||||
|
||||
void
|
||||
nsPluginInstanceOwner::NotifyHostCreateWidget()
|
||||
{
|
||||
mPluginHost->CreateWidget(this);
|
||||
#ifdef XP_MACOSX
|
||||
FixUpPluginWindow(ePluginPaintEnable);
|
||||
#else
|
||||
if (mPluginFrame) {
|
||||
mPluginFrame->InvalidateFrame();
|
||||
} else {
|
||||
CallSetWindow();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
nsresult nsPluginInstanceOwner::DispatchFocusToPlugin(nsIDOMEvent* aFocusEvent)
|
||||
{
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
@ -3169,6 +3191,10 @@ nsPluginInstanceOwner::UpdateDocumentActiveState(bool aIsActive)
|
||||
NS_IMETHODIMP
|
||||
nsPluginInstanceOwner::CallSetWindow()
|
||||
{
|
||||
if (!mWidgetCreationComplete) {
|
||||
// No widget yet, we can't run this code
|
||||
return NS_OK;
|
||||
}
|
||||
if (mPluginFrame) {
|
||||
mPluginFrame->CallSetWindow(false);
|
||||
} else if (mInstance) {
|
||||
|
@ -255,7 +255,10 @@ public:
|
||||
// Called from AndroidJNI when we removed the fullscreen view.
|
||||
static void ExitFullScreen(jobject view);
|
||||
#endif
|
||||
|
||||
|
||||
void NotifyHostAsyncInitFailed();
|
||||
void NotifyHostCreateWidget();
|
||||
|
||||
private:
|
||||
virtual ~nsPluginInstanceOwner();
|
||||
|
||||
|
@ -266,6 +266,7 @@ nsPluginStreamListenerPeer::nsPluginStreamListenerPeer()
|
||||
mHaveFiredOnStartRequest = false;
|
||||
mDataForwardToRequest = nullptr;
|
||||
|
||||
mUseLocalCache = false;
|
||||
mSeekable = false;
|
||||
mModified = 0;
|
||||
mStreamOffset = 0;
|
||||
@ -533,7 +534,9 @@ nsPluginStreamListenerPeer::OnStartRequest(nsIRequest *request,
|
||||
|
||||
// Set up the stream listener...
|
||||
rv = SetUpStreamListener(request, aURL);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
@ -1046,8 +1049,6 @@ nsresult nsPluginStreamListenerPeer::SetUpStreamListener(nsIRequest *request,
|
||||
|
||||
mPStreamListener->SetStreamListenerPeer(this);
|
||||
|
||||
bool useLocalCache = false;
|
||||
|
||||
// get httpChannel to retrieve some info we need for nsIPluginStreamInfo setup
|
||||
nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
|
||||
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(channel);
|
||||
@ -1103,7 +1104,7 @@ nsresult nsPluginStreamListenerPeer::SetUpStreamListener(nsIRequest *request,
|
||||
nsAutoCString contentEncoding;
|
||||
if (NS_SUCCEEDED(httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("Content-Encoding"),
|
||||
contentEncoding))) {
|
||||
useLocalCache = true;
|
||||
mUseLocalCache = true;
|
||||
} else {
|
||||
// set seekability (seekable if the stream has a known length and if the
|
||||
// http server accepts byte ranges).
|
||||
@ -1132,6 +1133,9 @@ nsresult nsPluginStreamListenerPeer::SetUpStreamListener(nsIRequest *request,
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!mRequest);
|
||||
mRequest = request;
|
||||
|
||||
rv = mPStreamListener->OnStartBinding(this);
|
||||
|
||||
mStartBinding = true;
|
||||
@ -1139,23 +1143,37 @@ nsresult nsPluginStreamListenerPeer::SetUpStreamListener(nsIRequest *request,
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
mPStreamListener->GetStreamType(&mStreamType);
|
||||
int32_t streamType = NP_NORMAL;
|
||||
mPStreamListener->GetStreamType(&streamType);
|
||||
|
||||
if (!useLocalCache && mStreamType >= NP_ASFILE) {
|
||||
// check it out if this is not a file channel.
|
||||
nsCOMPtr<nsIFileChannel> fileChannel = do_QueryInterface(request);
|
||||
if (!fileChannel) {
|
||||
useLocalCache = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (useLocalCache) {
|
||||
SetupPluginCacheFile(channel);
|
||||
if (streamType != STREAM_TYPE_UNKNOWN) {
|
||||
OnStreamTypeSet(streamType);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsPluginStreamListenerPeer::OnStreamTypeSet(const int32_t aStreamType)
|
||||
{
|
||||
MOZ_ASSERT(mRequest);
|
||||
mStreamType = aStreamType;
|
||||
if (!mUseLocalCache && mStreamType >= NP_ASFILE) {
|
||||
// check it out if this is not a file channel.
|
||||
nsCOMPtr<nsIFileChannel> fileChannel = do_QueryInterface(mRequest);
|
||||
if (!fileChannel) {
|
||||
mUseLocalCache = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (mUseLocalCache) {
|
||||
nsCOMPtr<nsIChannel> channel = do_QueryInterface(mRequest);
|
||||
SetupPluginCacheFile(channel);
|
||||
}
|
||||
}
|
||||
|
||||
const int32_t nsPluginStreamListenerPeer::STREAM_TYPE_UNKNOWN = UINT16_MAX;
|
||||
|
||||
nsresult
|
||||
nsPluginStreamListenerPeer::OnFileAvailable(nsIFile* aFile)
|
||||
{
|
||||
|
@ -128,6 +128,11 @@ public:
|
||||
requestsCopy[i]->Resume();
|
||||
}
|
||||
|
||||
// Called by nsNPAPIPluginStreamListener
|
||||
void OnStreamTypeSet(const int32_t aStreamType);
|
||||
|
||||
static const int32_t STREAM_TYPE_UNKNOWN;
|
||||
|
||||
private:
|
||||
nsresult SetUpStreamListener(nsIRequest* request, nsIURI* aURL);
|
||||
nsresult SetupPluginCacheFile(nsIChannel* channel);
|
||||
@ -159,6 +164,8 @@ private:
|
||||
nsDataHashtable<nsUint32HashKey, uint32_t>* mDataForwardToRequest;
|
||||
|
||||
nsCString mContentType;
|
||||
bool mUseLocalCache;
|
||||
nsCOMPtr<nsIRequest> mRequest;
|
||||
bool mSeekable;
|
||||
uint32_t mModified;
|
||||
nsRefPtr<nsNPAPIPluginInstance> mPluginInstance;
|
||||
|
@ -17,11 +17,7 @@ BrowserStreamChild::BrowserStreamChild(PluginInstanceChild* instance,
|
||||
const uint32_t& length,
|
||||
const uint32_t& lastmodified,
|
||||
StreamNotifyChild* notifyData,
|
||||
const nsCString& headers,
|
||||
const nsCString& mimeType,
|
||||
const bool& seekable,
|
||||
NPError* rv,
|
||||
uint16_t* stype)
|
||||
const nsCString& headers)
|
||||
: mInstance(instance)
|
||||
, mStreamStatus(kStreamOpen)
|
||||
, mDestroyPending(NOT_DESTROYED)
|
||||
@ -34,9 +30,9 @@ BrowserStreamChild::BrowserStreamChild(PluginInstanceChild* instance,
|
||||
, mStreamNotify(notifyData)
|
||||
, mDeliveryTracker(MOZ_THIS_IN_INITIALIZER_LIST())
|
||||
{
|
||||
PLUGIN_LOG_DEBUG(("%s (%s, %i, %i, %p, %s, %s)", FULLFUNCTION,
|
||||
PLUGIN_LOG_DEBUG(("%s (%s, %i, %i, %p, %s)", FULLFUNCTION,
|
||||
url.get(), length, lastmodified, (void*) notifyData,
|
||||
headers.get(), mimeType.get()));
|
||||
headers.get()));
|
||||
|
||||
AssertPluginThread();
|
||||
|
||||
@ -46,8 +42,10 @@ BrowserStreamChild::BrowserStreamChild(PluginInstanceChild* instance,
|
||||
mStream.end = length;
|
||||
mStream.lastmodified = lastmodified;
|
||||
mStream.headers = NullableStringGet(mHeaders);
|
||||
if (notifyData)
|
||||
if (notifyData) {
|
||||
mStream.notifyData = notifyData->mClosure;
|
||||
notifyData->SetAssociatedStream(this);
|
||||
}
|
||||
}
|
||||
|
||||
NPError
|
||||
@ -68,9 +66,6 @@ BrowserStreamChild::StreamConstructed(
|
||||
}
|
||||
else {
|
||||
mState = ALIVE;
|
||||
|
||||
if (mStreamNotify)
|
||||
mStreamNotify->SetAssociatedStream(this);
|
||||
}
|
||||
|
||||
return rv;
|
||||
|
@ -23,11 +23,7 @@ public:
|
||||
const uint32_t& length,
|
||||
const uint32_t& lastmodified,
|
||||
StreamNotifyChild* notifyData,
|
||||
const nsCString& headers,
|
||||
const nsCString& mimeType,
|
||||
const bool& seekable,
|
||||
NPError* rv,
|
||||
uint16_t* stype);
|
||||
const nsCString& headers);
|
||||
virtual ~BrowserStreamChild();
|
||||
|
||||
virtual bool IsBrowserStream() MOZ_OVERRIDE { return true; }
|
||||
|
@ -5,6 +5,7 @@
|
||||
|
||||
|
||||
#include "BrowserStreamParent.h"
|
||||
#include "PluginAsyncSurrogate.h"
|
||||
#include "PluginInstanceParent.h"
|
||||
#include "nsNPAPIPlugin.h"
|
||||
|
||||
@ -21,9 +22,15 @@ BrowserStreamParent::BrowserStreamParent(PluginInstanceParent* npp,
|
||||
NPStream* stream)
|
||||
: mNPP(npp)
|
||||
, mStream(stream)
|
||||
, mState(ALIVE)
|
||||
, mDeferredDestroyReason(NPRES_DONE)
|
||||
, mState(INITIALIZING)
|
||||
{
|
||||
mStream->pdata = static_cast<AStream*>(this);
|
||||
nsNPAPIStreamWrapper* wrapper =
|
||||
reinterpret_cast<nsNPAPIStreamWrapper*>(mStream->ndata);
|
||||
if (wrapper) {
|
||||
mStreamListener = wrapper->GetStreamListener();
|
||||
}
|
||||
}
|
||||
|
||||
BrowserStreamParent::~BrowserStreamParent()
|
||||
@ -36,6 +43,43 @@ BrowserStreamParent::ActorDestroy(ActorDestroyReason aWhy)
|
||||
// Implement me! Bug 1005159
|
||||
}
|
||||
|
||||
bool
|
||||
BrowserStreamParent::RecvAsyncNPP_NewStreamResult(const NPError& rv,
|
||||
const uint16_t& stype)
|
||||
{
|
||||
PLUGIN_LOG_DEBUG_FUNCTION;
|
||||
PluginAsyncSurrogate* surrogate = mNPP->GetAsyncSurrogate();
|
||||
MOZ_ASSERT(surrogate);
|
||||
surrogate->AsyncCallArriving();
|
||||
nsRefPtr<nsNPAPIPluginStreamListener> streamListener = mStreamListener.forget();
|
||||
if (mState == DEFERRING_DESTROY) {
|
||||
// We've been asked to destroy ourselves before init was complete.
|
||||
mState = DYING;
|
||||
unused << SendNPP_DestroyStream(mDeferredDestroyReason);
|
||||
return true;
|
||||
}
|
||||
|
||||
NPError error = rv;
|
||||
if (error == NPERR_NO_ERROR) {
|
||||
if (!streamListener) {
|
||||
return false;
|
||||
}
|
||||
if (streamListener->SetStreamType(stype)) {
|
||||
mState = ALIVE;
|
||||
} else {
|
||||
error = NPERR_GENERIC_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if (error != NPERR_NO_ERROR) {
|
||||
// We need to clean up the stream
|
||||
parent::_destroystream(mNPP->GetNPP(), mStream, NPRES_DONE);
|
||||
unused << PBrowserStreamParent::Send__delete__(this);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BrowserStreamParent::AnswerNPN_RequestRead(const IPCByteRanges& ranges,
|
||||
NPError* result)
|
||||
@ -43,6 +87,11 @@ BrowserStreamParent::AnswerNPN_RequestRead(const IPCByteRanges& ranges,
|
||||
PLUGIN_LOG_DEBUG_FUNCTION;
|
||||
|
||||
switch (mState) {
|
||||
case INITIALIZING:
|
||||
NS_ERROR("Requesting a read before initialization has completed");
|
||||
*result = NPERR_GENERIC_ERROR;
|
||||
return false;
|
||||
|
||||
case ALIVE:
|
||||
break;
|
||||
|
||||
@ -95,9 +144,16 @@ BrowserStreamParent::RecvNPN_DestroyStream(const NPReason& reason)
|
||||
void
|
||||
BrowserStreamParent::NPP_DestroyStream(NPReason reason)
|
||||
{
|
||||
NS_ASSERTION(ALIVE == mState, "NPP_DestroyStream called twice?");
|
||||
mState = DYING;
|
||||
unused << SendNPP_DestroyStream(reason);
|
||||
NS_ASSERTION(ALIVE == mState || INITIALIZING == mState,
|
||||
"NPP_DestroyStream called twice?");
|
||||
bool stillInitializing = INITIALIZING == mState;
|
||||
if (stillInitializing) {
|
||||
mState = DEFERRING_DESTROY;
|
||||
mDeferredDestroyReason = reason;
|
||||
} else {
|
||||
mState = DYING;
|
||||
unused << SendNPP_DestroyStream(reason);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
@ -117,6 +173,9 @@ BrowserStreamParent::RecvStreamDestroyed()
|
||||
int32_t
|
||||
BrowserStreamParent::WriteReady()
|
||||
{
|
||||
if (mState == INITIALIZING) {
|
||||
return 0;
|
||||
}
|
||||
return kSendDataChunk;
|
||||
}
|
||||
|
||||
|
@ -8,6 +8,8 @@
|
||||
|
||||
#include "mozilla/plugins/PBrowserStreamParent.h"
|
||||
#include "mozilla/plugins/AStream.h"
|
||||
#include "nsNPAPIPluginStreamListener.h"
|
||||
#include "nsPluginStreamListenerPeer.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace plugins {
|
||||
@ -28,6 +30,10 @@ public:
|
||||
|
||||
virtual void ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
|
||||
|
||||
virtual bool RecvAsyncNPP_NewStreamResult(
|
||||
const NPError& rv,
|
||||
const uint16_t& stype) MOZ_OVERRIDE;
|
||||
|
||||
virtual bool AnswerNPN_RequestRead(const IPCByteRanges& ranges,
|
||||
NPError* result) MOZ_OVERRIDE;
|
||||
|
||||
@ -41,14 +47,25 @@ public:
|
||||
|
||||
void NPP_DestroyStream(NPReason reason);
|
||||
|
||||
void SetAlive()
|
||||
{
|
||||
if (mState == INITIALIZING) {
|
||||
mState = ALIVE;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
using PBrowserStreamParent::SendNPP_DestroyStream;
|
||||
|
||||
PluginInstanceParent* mNPP;
|
||||
NPStream* mStream;
|
||||
nsCOMPtr<nsISupports> mStreamPeer;
|
||||
nsRefPtr<nsNPAPIPluginStreamListener> mStreamListener;
|
||||
NPReason mDeferredDestroyReason;
|
||||
|
||||
enum {
|
||||
INITIALIZING,
|
||||
DEFERRING_DESTROY,
|
||||
ALIVE,
|
||||
DYING,
|
||||
DELETING
|
||||
|
@ -36,6 +36,7 @@ child:
|
||||
async __delete__();
|
||||
|
||||
parent:
|
||||
async AsyncNPP_NewStreamResult(NPError rv, uint16_t stype);
|
||||
intr NPN_RequestRead(IPCByteRanges ranges)
|
||||
returns (NPError result);
|
||||
async NPN_DestroyStream(NPReason reason);
|
||||
|
@ -207,21 +207,29 @@ parent:
|
||||
// them to use the plugin.
|
||||
sync NegotiatedCarbon();
|
||||
|
||||
// Notifies the parent of its NPP_New result code.
|
||||
async AsyncNPP_NewResult(NPError aResult);
|
||||
|
||||
both:
|
||||
async PPluginScriptableObject();
|
||||
|
||||
child:
|
||||
/* NPP_NewStream */
|
||||
intr PBrowserStream(nsCString url,
|
||||
uint32_t length,
|
||||
uint32_t lastmodified,
|
||||
nullable PStreamNotify notifyData,
|
||||
nsCString headers,
|
||||
nsCString mimeType,
|
||||
bool seekable)
|
||||
async PBrowserStream(nsCString url,
|
||||
uint32_t length,
|
||||
uint32_t lastmodified,
|
||||
nullable PStreamNotify notifyData,
|
||||
nsCString headers);
|
||||
|
||||
// Implements the legacy (synchronous) version of NPP_NewStream for when
|
||||
// async plugin init is preffed off.
|
||||
intr NPP_NewStream(PBrowserStream actor, nsCString mimeType, bool seekable)
|
||||
returns (NPError rv,
|
||||
uint16_t stype);
|
||||
|
||||
// Implements the async plugin init version of NPP_NewStream.
|
||||
async AsyncNPP_NewStream(PBrowserStream actor, nsCString mimeType, bool seekable);
|
||||
|
||||
parent:
|
||||
/* NPN_NewStream */
|
||||
intr PPluginStream(nsCString mimeType,
|
||||
|
@ -54,12 +54,21 @@ child:
|
||||
intr NP_Initialize(PluginSettings settings)
|
||||
returns (NPError rv);
|
||||
|
||||
intr PPluginInstance(nsCString aMimeType,
|
||||
uint16_t aMode,
|
||||
nsCString[] aNames,
|
||||
nsCString[] aValues)
|
||||
async AsyncNP_Initialize(PluginSettings settings);
|
||||
|
||||
async PPluginInstance(nsCString aMimeType,
|
||||
uint16_t aMode,
|
||||
nsCString[] aNames,
|
||||
nsCString[] aValues);
|
||||
|
||||
// Implements the synchronous version of NPP_New for when async plugin init
|
||||
// is preffed off.
|
||||
intr SyncNPP_New(PPluginInstance aActor)
|
||||
returns (NPError rv);
|
||||
|
||||
// Implements the async plugin init version of NPP_New.
|
||||
async AsyncNPP_New(PPluginInstance aActor);
|
||||
|
||||
intr NP_Shutdown()
|
||||
returns (NPError rv);
|
||||
|
||||
@ -89,12 +98,15 @@ child:
|
||||
async StartProfiler(uint32_t aEntries, double aInterval, nsCString[] aFeatures,
|
||||
nsCString[] aThreadNameFilters);
|
||||
async StopProfiler();
|
||||
|
||||
intr GetProfile()
|
||||
returns (nsCString aProfile);
|
||||
|
||||
async SettingChanged(PluginSettings settings);
|
||||
|
||||
parent:
|
||||
async NP_InitializeResult(NPError aError);
|
||||
|
||||
/**
|
||||
* This message is only used on X11 platforms.
|
||||
*
|
||||
|
882
dom/plugins/ipc/PluginAsyncSurrogate.cpp
Normal file
882
dom/plugins/ipc/PluginAsyncSurrogate.cpp
Normal file
@ -0,0 +1,882 @@
|
||||
/* -*- 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 "PluginAsyncSurrogate.h"
|
||||
|
||||
#include "base/message_loop.h"
|
||||
#include "base/message_pump_default.h"
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
#include "mozilla/plugins/PluginInstanceParent.h"
|
||||
#include "mozilla/plugins/PluginModuleParent.h"
|
||||
#include "mozilla/plugins/PluginScriptableObjectParent.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "nsJSNPRuntime.h"
|
||||
#include "nsNPAPIPlugin.h"
|
||||
#include "nsNPAPIPluginInstance.h"
|
||||
#include "nsNPAPIPluginStreamListener.h"
|
||||
#include "nsPluginInstanceOwner.h"
|
||||
#include "nsPluginStreamListenerPeer.h"
|
||||
#include "npruntime.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "PluginMessageUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace plugins {
|
||||
|
||||
AsyncNPObject::AsyncNPObject(PluginAsyncSurrogate* aSurrogate)
|
||||
: NPObject()
|
||||
, mSurrogate(aSurrogate)
|
||||
, mRealObject(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
AsyncNPObject::~AsyncNPObject()
|
||||
{
|
||||
if (mRealObject) {
|
||||
parent::_releaseobject(mRealObject);
|
||||
mRealObject = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
NPObject*
|
||||
AsyncNPObject::GetRealObject()
|
||||
{
|
||||
if (mRealObject) {
|
||||
return mRealObject;
|
||||
}
|
||||
PluginInstanceParent* instance = PluginInstanceParent::Cast(mSurrogate->GetNPP());
|
||||
if (!instance) {
|
||||
return nullptr;
|
||||
}
|
||||
NPError err = instance->NPP_GetValue(NPPVpluginScriptableNPObject,
|
||||
&mRealObject);
|
||||
if (err != NPERR_NO_ERROR) {
|
||||
return nullptr;
|
||||
}
|
||||
return mRealObject;
|
||||
}
|
||||
|
||||
class MOZ_STACK_CLASS RecursionGuard
|
||||
{
|
||||
public:
|
||||
RecursionGuard()
|
||||
: mIsRecursive(sHasEntered)
|
||||
{
|
||||
if (!mIsRecursive) {
|
||||
sHasEntered = true;
|
||||
}
|
||||
}
|
||||
|
||||
~RecursionGuard()
|
||||
{
|
||||
if (!mIsRecursive) {
|
||||
sHasEntered = false;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool
|
||||
IsRecursive()
|
||||
{
|
||||
return mIsRecursive;
|
||||
}
|
||||
|
||||
private:
|
||||
bool mIsRecursive;
|
||||
static bool sHasEntered;
|
||||
};
|
||||
|
||||
bool RecursionGuard::sHasEntered = false;
|
||||
|
||||
PluginAsyncSurrogate::PluginAsyncSurrogate(PluginModuleParent* aParent)
|
||||
: mParent(aParent)
|
||||
, mInstance(nullptr)
|
||||
, mMode(0)
|
||||
, mWindow(nullptr)
|
||||
, mAcceptCalls(false)
|
||||
, mInstantiated(false)
|
||||
, mAsyncSetWindow(false)
|
||||
, mInitCancelled(false)
|
||||
, mAsyncCallsInFlight(0)
|
||||
{
|
||||
MOZ_ASSERT(aParent);
|
||||
}
|
||||
|
||||
PluginAsyncSurrogate::~PluginAsyncSurrogate()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
PluginAsyncSurrogate::Init(NPMIMEType aPluginType, NPP aInstance, uint16_t aMode,
|
||||
int16_t aArgc, char* aArgn[], char* aArgv[])
|
||||
{
|
||||
mMimeType = aPluginType;
|
||||
mInstance = aInstance;
|
||||
mMode = aMode;
|
||||
for (int i = 0; i < aArgc; ++i) {
|
||||
mNames.AppendElement(NullableString(aArgn[i]));
|
||||
mValues.AppendElement(NullableString(aArgv[i]));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
PluginAsyncSurrogate::Create(PluginModuleParent* aParent, NPMIMEType aPluginType,
|
||||
NPP aInstance, uint16_t aMode, int16_t aArgc,
|
||||
char* aArgn[], char* aArgv[])
|
||||
{
|
||||
nsRefPtr<PluginAsyncSurrogate> surrogate(new PluginAsyncSurrogate(aParent));
|
||||
if (!surrogate->Init(aPluginType, aInstance, aMode, aArgc, aArgn, aArgv)) {
|
||||
return false;
|
||||
}
|
||||
PluginAsyncSurrogate* rawSurrogate = nullptr;
|
||||
surrogate.forget(&rawSurrogate);
|
||||
aInstance->pdata = static_cast<PluginDataResolver*>(rawSurrogate);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* static */ PluginAsyncSurrogate*
|
||||
PluginAsyncSurrogate::Cast(NPP aInstance)
|
||||
{
|
||||
MOZ_ASSERT(aInstance);
|
||||
PluginDataResolver* resolver =
|
||||
reinterpret_cast<PluginDataResolver*>(aInstance->pdata);
|
||||
if (!resolver) {
|
||||
return nullptr;
|
||||
}
|
||||
return resolver->GetAsyncSurrogate();
|
||||
}
|
||||
|
||||
nsresult
|
||||
PluginAsyncSurrogate::NPP_New(NPError* aError)
|
||||
{
|
||||
nsresult rv = mParent->NPP_NewInternal(mMimeType.BeginWriting(), mInstance,
|
||||
mMode, mNames, mValues, nullptr,
|
||||
aError);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
PluginAsyncSurrogate::NP_GetEntryPoints(NPPluginFuncs* aFuncs)
|
||||
{
|
||||
aFuncs->version = (NP_VERSION_MAJOR << 8) | NP_VERSION_MINOR;
|
||||
aFuncs->destroy = &NPP_Destroy;
|
||||
aFuncs->getvalue = &NPP_GetValue;
|
||||
aFuncs->setvalue = &NPP_SetValue;
|
||||
aFuncs->newstream = &NPP_NewStream;
|
||||
aFuncs->setwindow = &NPP_SetWindow;
|
||||
aFuncs->writeready = &NPP_WriteReady;
|
||||
aFuncs->event = &NPP_HandleEvent;
|
||||
// We need to set these so that content code doesn't make assumptions
|
||||
// about these operations not being supported
|
||||
aFuncs->write = &PluginModuleParent::NPP_Write;
|
||||
aFuncs->asfile = &PluginModuleParent::NPP_StreamAsFile;
|
||||
aFuncs->destroystream = &PluginModuleParent::NPP_DestroyStream;
|
||||
}
|
||||
|
||||
NPError
|
||||
PluginAsyncSurrogate::NPP_Destroy(NPSavedData** aSave)
|
||||
{
|
||||
if (!WaitForInit()) {
|
||||
return NPERR_GENERIC_ERROR;
|
||||
}
|
||||
return PluginModuleParent::NPP_Destroy(mInstance, aSave);
|
||||
}
|
||||
|
||||
NPError
|
||||
PluginAsyncSurrogate::NPP_GetValue(NPPVariable aVariable, void* aRetval)
|
||||
{
|
||||
if (aVariable != NPPVpluginScriptableNPObject) {
|
||||
if (!WaitForInit()) {
|
||||
return NPERR_GENERIC_ERROR;
|
||||
}
|
||||
PluginInstanceParent* instance = PluginInstanceParent::Cast(mInstance);
|
||||
MOZ_ASSERT(instance);
|
||||
return instance->NPP_GetValue(aVariable, aRetval);
|
||||
}
|
||||
|
||||
NPObject* npobject = parent::_createobject(mInstance,
|
||||
const_cast<NPClass*>(GetClass()));
|
||||
MOZ_ASSERT(npobject);
|
||||
MOZ_ASSERT(npobject->_class == GetClass());
|
||||
MOZ_ASSERT(npobject->referenceCount == 1);
|
||||
*(NPObject**)aRetval = npobject;
|
||||
return npobject ? NPERR_NO_ERROR : NPERR_GENERIC_ERROR;
|
||||
}
|
||||
|
||||
NPError
|
||||
PluginAsyncSurrogate::NPP_SetValue(NPNVariable aVariable, void* aValue)
|
||||
{
|
||||
if (!WaitForInit()) {
|
||||
return NPERR_GENERIC_ERROR;
|
||||
}
|
||||
return PluginModuleParent::NPP_SetValue(mInstance, aVariable, aValue);
|
||||
}
|
||||
|
||||
NPError
|
||||
PluginAsyncSurrogate::NPP_NewStream(NPMIMEType aType, NPStream* aStream,
|
||||
NPBool aSeekable, uint16_t* aStype)
|
||||
{
|
||||
mPendingNewStreamCalls.AppendElement(PendingNewStreamCall(aType, aStream,
|
||||
aSeekable));
|
||||
if (aStype) {
|
||||
*aStype = nsPluginStreamListenerPeer::STREAM_TYPE_UNKNOWN;
|
||||
}
|
||||
return NPERR_NO_ERROR;
|
||||
}
|
||||
|
||||
NPError
|
||||
PluginAsyncSurrogate::NPP_SetWindow(NPWindow* aWindow)
|
||||
{
|
||||
mWindow = aWindow;
|
||||
mAsyncSetWindow = false;
|
||||
return NPERR_NO_ERROR;
|
||||
}
|
||||
|
||||
nsresult
|
||||
PluginAsyncSurrogate::AsyncSetWindow(NPWindow* aWindow)
|
||||
{
|
||||
mWindow = aWindow;
|
||||
mAsyncSetWindow = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
PluginAsyncSurrogate::NPP_Print(NPPrint* aPrintInfo)
|
||||
{
|
||||
// Do nothing, we've got nothing to print right now
|
||||
}
|
||||
|
||||
int16_t
|
||||
PluginAsyncSurrogate::NPP_HandleEvent(void* event)
|
||||
{
|
||||
// Drop the event -- the plugin isn't around to handle it
|
||||
return false;
|
||||
}
|
||||
|
||||
int32_t
|
||||
PluginAsyncSurrogate::NPP_WriteReady(NPStream* aStream)
|
||||
{
|
||||
// We'll tell the browser to retry in a bit. Eventually NPP_WriteReady
|
||||
// will resolve to the plugin's NPP_WriteReady and this should all just work.
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* static */ NPError
|
||||
PluginAsyncSurrogate::NPP_Destroy(NPP aInstance, NPSavedData** aSave)
|
||||
{
|
||||
PluginAsyncSurrogate* rawSurrogate = Cast(aInstance);
|
||||
MOZ_ASSERT(rawSurrogate);
|
||||
PluginModuleParent* module = rawSurrogate->GetParent();
|
||||
if (module && !module->IsInitialized()) {
|
||||
// Take ownership of pdata's surrogate since we're going to release it
|
||||
nsRefPtr<PluginAsyncSurrogate> surrogate(dont_AddRef(rawSurrogate));
|
||||
aInstance->pdata = nullptr;
|
||||
// We haven't actually called NPP_New yet, so we should remove the
|
||||
// surrogate for this instance.
|
||||
bool removeOk = module->RemovePendingSurrogate(surrogate);
|
||||
MOZ_ASSERT(removeOk);
|
||||
if (!removeOk) {
|
||||
return NPERR_GENERIC_ERROR;
|
||||
}
|
||||
surrogate->mInitCancelled = true;
|
||||
return NPERR_NO_ERROR;
|
||||
}
|
||||
return rawSurrogate->NPP_Destroy(aSave);
|
||||
}
|
||||
|
||||
/* static */ NPError
|
||||
PluginAsyncSurrogate::NPP_GetValue(NPP aInstance, NPPVariable aVariable,
|
||||
void* aRetval)
|
||||
{
|
||||
PluginAsyncSurrogate* surrogate = Cast(aInstance);
|
||||
MOZ_ASSERT(surrogate);
|
||||
return surrogate->NPP_GetValue(aVariable, aRetval);
|
||||
}
|
||||
|
||||
/* static */ NPError
|
||||
PluginAsyncSurrogate::NPP_SetValue(NPP aInstance, NPNVariable aVariable,
|
||||
void* aValue)
|
||||
{
|
||||
PluginAsyncSurrogate* surrogate = Cast(aInstance);
|
||||
MOZ_ASSERT(surrogate);
|
||||
return surrogate->NPP_SetValue(aVariable, aValue);
|
||||
}
|
||||
|
||||
/* static */ NPError
|
||||
PluginAsyncSurrogate::NPP_NewStream(NPP aInstance, NPMIMEType aType,
|
||||
NPStream* aStream, NPBool aSeekable,
|
||||
uint16_t* aStype)
|
||||
{
|
||||
PluginAsyncSurrogate* surrogate = Cast(aInstance);
|
||||
MOZ_ASSERT(surrogate);
|
||||
return surrogate->NPP_NewStream(aType, aStream, aSeekable, aStype);
|
||||
}
|
||||
|
||||
/* static */ NPError
|
||||
PluginAsyncSurrogate::NPP_SetWindow(NPP aInstance, NPWindow* aWindow)
|
||||
{
|
||||
PluginAsyncSurrogate* surrogate = Cast(aInstance);
|
||||
MOZ_ASSERT(surrogate);
|
||||
return surrogate->NPP_SetWindow(aWindow);
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
PluginAsyncSurrogate::NPP_Print(NPP aInstance, NPPrint* aPrintInfo)
|
||||
{
|
||||
PluginAsyncSurrogate* surrogate = Cast(aInstance);
|
||||
MOZ_ASSERT(surrogate);
|
||||
surrogate->NPP_Print(aPrintInfo);
|
||||
}
|
||||
|
||||
/* static */ int16_t
|
||||
PluginAsyncSurrogate::NPP_HandleEvent(NPP aInstance, void* aEvent)
|
||||
{
|
||||
PluginAsyncSurrogate* surrogate = Cast(aInstance);
|
||||
MOZ_ASSERT(surrogate);
|
||||
return surrogate->NPP_HandleEvent(aEvent);
|
||||
}
|
||||
|
||||
/* static */ int32_t
|
||||
PluginAsyncSurrogate::NPP_WriteReady(NPP aInstance, NPStream* aStream)
|
||||
{
|
||||
PluginAsyncSurrogate* surrogate = Cast(aInstance);
|
||||
MOZ_ASSERT(surrogate);
|
||||
return surrogate->NPP_WriteReady(aStream);
|
||||
}
|
||||
|
||||
PluginAsyncSurrogate::PendingNewStreamCall::PendingNewStreamCall(
|
||||
NPMIMEType aType, NPStream* aStream, NPBool aSeekable)
|
||||
: mType(NullableString(aType))
|
||||
, mStream(aStream)
|
||||
, mSeekable(aSeekable)
|
||||
{
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
PluginAsyncSurrogate::SetStreamType(NPStream* aStream, uint16_t aStreamType)
|
||||
{
|
||||
nsNPAPIStreamWrapper* wrapper =
|
||||
reinterpret_cast<nsNPAPIStreamWrapper*>(aStream->ndata);
|
||||
if (!wrapper) {
|
||||
return false;
|
||||
}
|
||||
nsNPAPIPluginStreamListener* streamListener = wrapper->GetStreamListener();
|
||||
if (!streamListener) {
|
||||
return false;
|
||||
}
|
||||
return streamListener->SetStreamType(aStreamType);
|
||||
}
|
||||
|
||||
void
|
||||
PluginAsyncSurrogate::OnInstanceCreated(PluginInstanceParent* aInstance)
|
||||
{
|
||||
for (PRUint32 i = 0, len = mPendingNewStreamCalls.Length(); i < len; ++i) {
|
||||
PendingNewStreamCall& curPendingCall = mPendingNewStreamCalls[i];
|
||||
uint16_t streamType = NP_NORMAL;
|
||||
NPError curError = aInstance->NPP_NewStream(
|
||||
const_cast<char*>(NullableStringGet(curPendingCall.mType)),
|
||||
curPendingCall.mStream, curPendingCall.mSeekable,
|
||||
&streamType);
|
||||
if (curError != NPERR_NO_ERROR) {
|
||||
// If we failed here then the send failed and we need to clean up
|
||||
parent::_destroystream(mInstance, curPendingCall.mStream, NPRES_DONE);
|
||||
}
|
||||
}
|
||||
mPendingNewStreamCalls.Clear();
|
||||
mInstantiated = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* During asynchronous initialization it might be necessary to wait for the
|
||||
* plugin to complete its initialization. This typically occurs when the result
|
||||
* of a plugin call depends on the plugin being fully instantiated. For example,
|
||||
* if some JS calls into the plugin, the call must be executed synchronously to
|
||||
* preserve correctness.
|
||||
*
|
||||
* This function works by pumping the plugin's IPC channel for events until
|
||||
* initialization has completed.
|
||||
*/
|
||||
bool
|
||||
PluginAsyncSurrogate::WaitForInit()
|
||||
{
|
||||
if (mInitCancelled) {
|
||||
return false;
|
||||
}
|
||||
if (mAcceptCalls) {
|
||||
return true;
|
||||
}
|
||||
Telemetry::AutoTimer<Telemetry::BLOCKED_ON_PLUGINASYNCSURROGATE_WAITFORINIT_MS>
|
||||
timer(mParent->GetHistogramKey());
|
||||
bool result = false;
|
||||
MOZ_ASSERT(mParent);
|
||||
if (mParent->IsChrome()) {
|
||||
PluginProcessParent* process = static_cast<PluginModuleChromeParent*>(mParent)->Process();
|
||||
MOZ_ASSERT(process);
|
||||
process->SetCallRunnableImmediately(true);
|
||||
if (!process->WaitUntilConnected()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!mParent->WaitForIPCConnection()) {
|
||||
return false;
|
||||
}
|
||||
if (!mParent->IsChrome()) {
|
||||
// For e10s content processes, we need to spin the content channel until the
|
||||
// protocol bridging has occurred.
|
||||
dom::ContentChild* cp = dom::ContentChild::GetSingleton();
|
||||
mozilla::ipc::MessageChannel* contentChannel = cp->GetIPCChannel();
|
||||
MOZ_ASSERT(contentChannel);
|
||||
while (!mParent->mNPInitialized) {
|
||||
result = contentChannel->WaitForIncomingMessage();
|
||||
if (!result) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
mozilla::ipc::MessageChannel* channel = mParent->GetIPCChannel();
|
||||
MOZ_ASSERT(channel);
|
||||
while (!mAcceptCalls) {
|
||||
result = channel->WaitForIncomingMessage();
|
||||
if (!result) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
PluginAsyncSurrogate::AsyncCallDeparting()
|
||||
{
|
||||
++mAsyncCallsInFlight;
|
||||
if (!mPluginDestructionGuard) {
|
||||
mPluginDestructionGuard = MakeUnique<PluginDestructionGuard>(this);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PluginAsyncSurrogate::AsyncCallArriving()
|
||||
{
|
||||
MOZ_ASSERT(mAsyncCallsInFlight > 0);
|
||||
if (--mAsyncCallsInFlight == 0) {
|
||||
mPluginDestructionGuard.reset(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PluginAsyncSurrogate::NotifyAsyncInitFailed()
|
||||
{
|
||||
// Clean up any pending NewStream requests
|
||||
for (uint32_t i = 0, len = mPendingNewStreamCalls.Length(); i < len; ++i) {
|
||||
PendingNewStreamCall& curPendingCall = mPendingNewStreamCalls[i];
|
||||
parent::_destroystream(mInstance, curPendingCall.mStream, NPRES_DONE);
|
||||
}
|
||||
mPendingNewStreamCalls.Clear();
|
||||
|
||||
nsNPAPIPluginInstance* inst =
|
||||
static_cast<nsNPAPIPluginInstance*>(mInstance->ndata);
|
||||
if (!inst) {
|
||||
return;
|
||||
}
|
||||
nsPluginInstanceOwner* owner = inst->GetOwner();
|
||||
if (!owner) {
|
||||
return;
|
||||
}
|
||||
owner->NotifyHostAsyncInitFailed();
|
||||
}
|
||||
|
||||
// static
|
||||
NPObject*
|
||||
PluginAsyncSurrogate::ScriptableAllocate(NPP aInstance, NPClass* aClass)
|
||||
{
|
||||
PLUGIN_LOG_DEBUG_FUNCTION;
|
||||
if (aClass != GetClass()) {
|
||||
NS_ERROR("Huh?! Wrong class!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return new AsyncNPObject(Cast(aInstance));
|
||||
}
|
||||
|
||||
// static
|
||||
void
|
||||
PluginAsyncSurrogate::ScriptableInvalidate(NPObject* aObject)
|
||||
{
|
||||
PLUGIN_LOG_DEBUG_FUNCTION;
|
||||
if (aObject->_class != GetClass()) {
|
||||
NS_ERROR("Don't know what kind of object this is!");
|
||||
return;
|
||||
}
|
||||
|
||||
AsyncNPObject* object = static_cast<AsyncNPObject*>(aObject);
|
||||
if (!object->mSurrogate->WaitForInit()) {
|
||||
return;
|
||||
}
|
||||
NPObject* realObject = object->GetRealObject();
|
||||
if (!realObject) {
|
||||
return;
|
||||
}
|
||||
realObject->_class->invalidate(realObject);
|
||||
}
|
||||
|
||||
// static
|
||||
void
|
||||
PluginAsyncSurrogate::ScriptableDeallocate(NPObject* aObject)
|
||||
{
|
||||
PLUGIN_LOG_DEBUG_FUNCTION;
|
||||
if (aObject->_class != GetClass()) {
|
||||
NS_ERROR("Don't know what kind of object this is!");
|
||||
return;
|
||||
}
|
||||
|
||||
AsyncNPObject* object = static_cast<AsyncNPObject*>(aObject);
|
||||
delete object;
|
||||
}
|
||||
|
||||
// static
|
||||
bool
|
||||
PluginAsyncSurrogate::ScriptableHasMethod(NPObject* aObject,
|
||||
NPIdentifier aName)
|
||||
{
|
||||
PLUGIN_LOG_DEBUG_FUNCTION;
|
||||
if (aObject->_class != GetClass()) {
|
||||
NS_ERROR("Don't know what kind of object this is!");
|
||||
return false;
|
||||
}
|
||||
|
||||
RecursionGuard guard;
|
||||
if (guard.IsRecursive()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
AsyncNPObject* object = static_cast<AsyncNPObject*>(aObject);
|
||||
MOZ_ASSERT(object);
|
||||
bool checkPluginObject = !object->mSurrogate->mInstantiated &&
|
||||
!object->mSurrogate->mAcceptCalls;
|
||||
|
||||
if (!object->mSurrogate->WaitForInit()) {
|
||||
return false;
|
||||
}
|
||||
NPObject* realObject = object->GetRealObject();
|
||||
if (!realObject) {
|
||||
return false;
|
||||
}
|
||||
bool result = realObject->_class->hasMethod(realObject, aName);
|
||||
if (!result && checkPluginObject) {
|
||||
// We may be calling into this object because properties in the WebIDL
|
||||
// object hadn't been set yet. Now that we're further along in
|
||||
// initialization, we should try again.
|
||||
const NPNetscapeFuncs* npn = object->mSurrogate->mParent->GetNetscapeFuncs();
|
||||
NPObject* pluginObject = nullptr;
|
||||
NPError nperror = npn->getvalue(object->mSurrogate->mInstance,
|
||||
NPNVPluginElementNPObject,
|
||||
(void*)&pluginObject);
|
||||
if (nperror == NPERR_NO_ERROR) {
|
||||
NPPAutoPusher nppPusher(object->mSurrogate->mInstance);
|
||||
result = pluginObject->_class->hasMethod(pluginObject, aName);
|
||||
npn->releaseobject(pluginObject);
|
||||
NPUTF8* idstr = npn->utf8fromidentifier(aName);
|
||||
npn->memfree(idstr);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool
|
||||
PluginAsyncSurrogate::GetPropertyHelper(NPObject* aObject, NPIdentifier aName,
|
||||
bool* aHasProperty, bool* aHasMethod,
|
||||
NPVariant* aResult)
|
||||
{
|
||||
PLUGIN_LOG_DEBUG_FUNCTION;
|
||||
|
||||
if (!aObject) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RecursionGuard guard;
|
||||
if (guard.IsRecursive()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
WaitForInit();
|
||||
|
||||
AsyncNPObject* object = static_cast<AsyncNPObject*>(aObject);
|
||||
NPObject* realObject = object->GetRealObject();
|
||||
if (realObject->_class != PluginScriptableObjectParent::GetClass()) {
|
||||
NS_ERROR("Don't know what kind of object this is!");
|
||||
return false;
|
||||
}
|
||||
|
||||
PluginScriptableObjectParent* actor =
|
||||
static_cast<ParentNPObject*>(realObject)->parent;
|
||||
bool success = actor->GetPropertyHelper(aName, aHasProperty, aHasMethod, aResult);
|
||||
if (!success) {
|
||||
const NPNetscapeFuncs* npn = mParent->GetNetscapeFuncs();
|
||||
NPObject* pluginObject = nullptr;
|
||||
NPError nperror = npn->getvalue(mInstance, NPNVPluginElementNPObject,
|
||||
(void*)&pluginObject);
|
||||
if (nperror == NPERR_NO_ERROR) {
|
||||
NPPAutoPusher nppPusher(mInstance);
|
||||
bool hasProperty = nsJSObjWrapper::HasOwnProperty(pluginObject, aName);
|
||||
NPUTF8* idstr = npn->utf8fromidentifier(aName);
|
||||
npn->memfree(idstr);
|
||||
bool hasMethod = false;
|
||||
if (hasProperty) {
|
||||
hasMethod = pluginObject->_class->hasMethod(pluginObject, aName);
|
||||
success = pluginObject->_class->getProperty(pluginObject, aName, aResult);
|
||||
idstr = npn->utf8fromidentifier(aName);
|
||||
npn->memfree(idstr);
|
||||
}
|
||||
*aHasProperty = hasProperty;
|
||||
*aHasMethod = hasMethod;
|
||||
npn->releaseobject(pluginObject);
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
// static
|
||||
bool
|
||||
PluginAsyncSurrogate::ScriptableInvoke(NPObject* aObject,
|
||||
NPIdentifier aName,
|
||||
const NPVariant* aArgs,
|
||||
uint32_t aArgCount,
|
||||
NPVariant* aResult)
|
||||
{
|
||||
PLUGIN_LOG_DEBUG_FUNCTION;
|
||||
if (aObject->_class != GetClass()) {
|
||||
NS_ERROR("Don't know what kind of object this is!");
|
||||
return false;
|
||||
}
|
||||
|
||||
AsyncNPObject* object = static_cast<AsyncNPObject*>(aObject);
|
||||
if (!object->mSurrogate->WaitForInit()) {
|
||||
return false;
|
||||
}
|
||||
NPObject* realObject = object->GetRealObject();
|
||||
if (!realObject) {
|
||||
return false;
|
||||
}
|
||||
return realObject->_class->invoke(realObject, aName, aArgs, aArgCount, aResult);
|
||||
}
|
||||
|
||||
// static
|
||||
bool
|
||||
PluginAsyncSurrogate::ScriptableInvokeDefault(NPObject* aObject,
|
||||
const NPVariant* aArgs,
|
||||
uint32_t aArgCount,
|
||||
NPVariant* aResult)
|
||||
{
|
||||
PLUGIN_LOG_DEBUG_FUNCTION;
|
||||
if (aObject->_class != GetClass()) {
|
||||
NS_ERROR("Don't know what kind of object this is!");
|
||||
return false;
|
||||
}
|
||||
|
||||
AsyncNPObject* object = static_cast<AsyncNPObject*>(aObject);
|
||||
if (!object->mSurrogate->WaitForInit()) {
|
||||
return false;
|
||||
}
|
||||
NPObject* realObject = object->GetRealObject();
|
||||
if (!realObject) {
|
||||
return false;
|
||||
}
|
||||
return realObject->_class->invokeDefault(realObject, aArgs, aArgCount, aResult);
|
||||
}
|
||||
|
||||
// static
|
||||
bool
|
||||
PluginAsyncSurrogate::ScriptableHasProperty(NPObject* aObject,
|
||||
NPIdentifier aName)
|
||||
{
|
||||
PLUGIN_LOG_DEBUG_FUNCTION;
|
||||
if (aObject->_class != GetClass()) {
|
||||
NS_ERROR("Don't know what kind of object this is!");
|
||||
return false;
|
||||
}
|
||||
|
||||
RecursionGuard guard;
|
||||
if (guard.IsRecursive()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
AsyncNPObject* object = static_cast<AsyncNPObject*>(aObject);
|
||||
MOZ_ASSERT(object);
|
||||
bool checkPluginObject = !object->mSurrogate->mInstantiated &&
|
||||
!object->mSurrogate->mAcceptCalls;
|
||||
|
||||
if (!object->mSurrogate->WaitForInit()) {
|
||||
return false;
|
||||
}
|
||||
NPObject* realObject = object->GetRealObject();
|
||||
if (!realObject) {
|
||||
return false;
|
||||
}
|
||||
bool result = realObject->_class->hasProperty(realObject, aName);
|
||||
const NPNetscapeFuncs* npn = object->mSurrogate->mParent->GetNetscapeFuncs();
|
||||
NPUTF8* idstr = npn->utf8fromidentifier(aName);
|
||||
npn->memfree(idstr);
|
||||
if (!result && checkPluginObject) {
|
||||
// We may be calling into this object because properties in the WebIDL
|
||||
// object hadn't been set yet. Now that we're further along in
|
||||
// initialization, we should try again.
|
||||
NPObject* pluginObject = nullptr;
|
||||
NPError nperror = npn->getvalue(object->mSurrogate->mInstance,
|
||||
NPNVPluginElementNPObject,
|
||||
(void*)&pluginObject);
|
||||
if (nperror == NPERR_NO_ERROR) {
|
||||
NPPAutoPusher nppPusher(object->mSurrogate->mInstance);
|
||||
result = nsJSObjWrapper::HasOwnProperty(pluginObject, aName);
|
||||
npn->releaseobject(pluginObject);
|
||||
idstr = npn->utf8fromidentifier(aName);
|
||||
npn->memfree(idstr);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// static
|
||||
bool
|
||||
PluginAsyncSurrogate::ScriptableGetProperty(NPObject* aObject,
|
||||
NPIdentifier aName,
|
||||
NPVariant* aResult)
|
||||
{
|
||||
PLUGIN_LOG_DEBUG_FUNCTION;
|
||||
// See GetPropertyHelper below.
|
||||
NS_NOTREACHED("Shouldn't ever call this directly!");
|
||||
return false;
|
||||
}
|
||||
|
||||
// static
|
||||
bool
|
||||
PluginAsyncSurrogate::ScriptableSetProperty(NPObject* aObject,
|
||||
NPIdentifier aName,
|
||||
const NPVariant* aValue)
|
||||
{
|
||||
PLUGIN_LOG_DEBUG_FUNCTION;
|
||||
if (aObject->_class != GetClass()) {
|
||||
NS_ERROR("Don't know what kind of object this is!");
|
||||
return false;
|
||||
}
|
||||
|
||||
AsyncNPObject* object = static_cast<AsyncNPObject*>(aObject);
|
||||
if (!object->mSurrogate->WaitForInit()) {
|
||||
return false;
|
||||
}
|
||||
NPObject* realObject = object->GetRealObject();
|
||||
if (!realObject) {
|
||||
return false;
|
||||
}
|
||||
return realObject->_class->setProperty(realObject, aName, aValue);
|
||||
}
|
||||
|
||||
// static
|
||||
bool
|
||||
PluginAsyncSurrogate::ScriptableRemoveProperty(NPObject* aObject,
|
||||
NPIdentifier aName)
|
||||
{
|
||||
PLUGIN_LOG_DEBUG_FUNCTION;
|
||||
if (aObject->_class != GetClass()) {
|
||||
NS_ERROR("Don't know what kind of object this is!");
|
||||
return false;
|
||||
}
|
||||
|
||||
AsyncNPObject* object = static_cast<AsyncNPObject*>(aObject);
|
||||
if (!object->mSurrogate->WaitForInit()) {
|
||||
return false;
|
||||
}
|
||||
NPObject* realObject = object->GetRealObject();
|
||||
if (!realObject) {
|
||||
return false;
|
||||
}
|
||||
return realObject->_class->removeProperty(realObject, aName);
|
||||
}
|
||||
|
||||
// static
|
||||
bool
|
||||
PluginAsyncSurrogate::ScriptableEnumerate(NPObject* aObject,
|
||||
NPIdentifier** aIdentifiers,
|
||||
uint32_t* aCount)
|
||||
{
|
||||
PLUGIN_LOG_DEBUG_FUNCTION;
|
||||
if (aObject->_class != GetClass()) {
|
||||
NS_ERROR("Don't know what kind of object this is!");
|
||||
return false;
|
||||
}
|
||||
|
||||
AsyncNPObject* object = static_cast<AsyncNPObject*>(aObject);
|
||||
if (!object->mSurrogate->WaitForInit()) {
|
||||
return false;
|
||||
}
|
||||
NPObject* realObject = object->GetRealObject();
|
||||
if (!realObject) {
|
||||
return false;
|
||||
}
|
||||
return realObject->_class->enumerate(realObject, aIdentifiers, aCount);
|
||||
}
|
||||
|
||||
// static
|
||||
bool
|
||||
PluginAsyncSurrogate::ScriptableConstruct(NPObject* aObject,
|
||||
const NPVariant* aArgs,
|
||||
uint32_t aArgCount,
|
||||
NPVariant* aResult)
|
||||
{
|
||||
PLUGIN_LOG_DEBUG_FUNCTION;
|
||||
if (aObject->_class != GetClass()) {
|
||||
NS_ERROR("Don't know what kind of object this is!");
|
||||
return false;
|
||||
}
|
||||
|
||||
AsyncNPObject* object = static_cast<AsyncNPObject*>(aObject);
|
||||
if (!object->mSurrogate->WaitForInit()) {
|
||||
return false;
|
||||
}
|
||||
NPObject* realObject = object->GetRealObject();
|
||||
if (!realObject) {
|
||||
return false;
|
||||
}
|
||||
return realObject->_class->construct(realObject, aArgs, aArgCount, aResult);
|
||||
}
|
||||
|
||||
const NPClass PluginAsyncSurrogate::sNPClass = {
|
||||
NP_CLASS_STRUCT_VERSION,
|
||||
PluginAsyncSurrogate::ScriptableAllocate,
|
||||
PluginAsyncSurrogate::ScriptableDeallocate,
|
||||
PluginAsyncSurrogate::ScriptableInvalidate,
|
||||
PluginAsyncSurrogate::ScriptableHasMethod,
|
||||
PluginAsyncSurrogate::ScriptableInvoke,
|
||||
PluginAsyncSurrogate::ScriptableInvokeDefault,
|
||||
PluginAsyncSurrogate::ScriptableHasProperty,
|
||||
PluginAsyncSurrogate::ScriptableGetProperty,
|
||||
PluginAsyncSurrogate::ScriptableSetProperty,
|
||||
PluginAsyncSurrogate::ScriptableRemoveProperty,
|
||||
PluginAsyncSurrogate::ScriptableEnumerate,
|
||||
PluginAsyncSurrogate::ScriptableConstruct
|
||||
};
|
||||
|
||||
PushSurrogateAcceptCalls::PushSurrogateAcceptCalls(PluginInstanceParent* aInstance)
|
||||
: mSurrogate(nullptr)
|
||||
, mPrevAcceptCallsState(false)
|
||||
{
|
||||
MOZ_ASSERT(aInstance);
|
||||
mSurrogate = aInstance->GetAsyncSurrogate();
|
||||
if (mSurrogate) {
|
||||
mPrevAcceptCallsState = mSurrogate->SetAcceptingCalls(true);
|
||||
}
|
||||
}
|
||||
|
||||
PushSurrogateAcceptCalls::~PushSurrogateAcceptCalls()
|
||||
{
|
||||
if (mSurrogate) {
|
||||
mSurrogate->SetAcceptingCalls(mPrevAcceptCallsState);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace plugins
|
||||
} // namespace mozilla
|
179
dom/plugins/ipc/PluginAsyncSurrogate.h
Normal file
179
dom/plugins/ipc/PluginAsyncSurrogate.h
Normal file
@ -0,0 +1,179 @@
|
||||
/* -*- 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 dom_plugins_ipc_PluginAsyncSurrogate_h
|
||||
#define dom_plugins_ipc_PluginAsyncSurrogate_h
|
||||
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "npapi.h"
|
||||
#include "npfunctions.h"
|
||||
#include "npruntime.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
#include "nsPluginHost.h"
|
||||
#include "nsString.h"
|
||||
#include "nsTArray.h"
|
||||
#include "PluginDataResolver.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace plugins {
|
||||
|
||||
class PluginInstanceParent;
|
||||
class PluginModuleParent;
|
||||
|
||||
class PluginAsyncSurrogate : public PluginDataResolver
|
||||
{
|
||||
public:
|
||||
NS_INLINE_DECL_REFCOUNTING(PluginAsyncSurrogate)
|
||||
|
||||
bool Init(NPMIMEType aPluginType, NPP aInstance, uint16_t aMode,
|
||||
int16_t aArgc, char* aArgn[], char* aArgv[]);
|
||||
nsresult NPP_New(NPError* aError);
|
||||
NPError NPP_Destroy(NPSavedData** aSave);
|
||||
NPError NPP_GetValue(NPPVariable aVariable, void* aRetval);
|
||||
NPError NPP_SetValue(NPNVariable aVariable, void* aValue);
|
||||
NPError NPP_NewStream(NPMIMEType aType, NPStream* aStream, NPBool aSeekable,
|
||||
uint16_t* aStype);
|
||||
NPError NPP_SetWindow(NPWindow* aWindow);
|
||||
nsresult AsyncSetWindow(NPWindow* aWindow);
|
||||
void NPP_Print(NPPrint* aPrintInfo);
|
||||
int16_t NPP_HandleEvent(void* aEvent);
|
||||
int32_t NPP_WriteReady(NPStream* aStream);
|
||||
void OnInstanceCreated(PluginInstanceParent* aInstance);
|
||||
static bool Create(PluginModuleParent* aParent, NPMIMEType aPluginType,
|
||||
NPP aInstance, uint16_t aMode, int16_t aArgc,
|
||||
char* aArgn[], char* aArgv[]);
|
||||
static const NPClass* GetClass() { return &sNPClass; }
|
||||
static void NP_GetEntryPoints(NPPluginFuncs* aFuncs);
|
||||
static PluginAsyncSurrogate* Cast(NPP aInstance);
|
||||
|
||||
virtual PluginAsyncSurrogate*
|
||||
GetAsyncSurrogate() { return this; }
|
||||
|
||||
virtual PluginInstanceParent*
|
||||
GetInstance() { return nullptr; }
|
||||
|
||||
NPP GetNPP() { return mInstance; }
|
||||
|
||||
bool GetPropertyHelper(NPObject* aObject, NPIdentifier aName,
|
||||
bool* aHasProperty, bool* aHasMethod,
|
||||
NPVariant* aResult);
|
||||
|
||||
PluginModuleParent*
|
||||
GetParent() { return mParent; }
|
||||
|
||||
bool SetAcceptingCalls(bool aAccept)
|
||||
{
|
||||
bool prevState = mAcceptCalls;
|
||||
if (mInstantiated) {
|
||||
aAccept = true;
|
||||
}
|
||||
mAcceptCalls = aAccept;
|
||||
return prevState;
|
||||
}
|
||||
|
||||
void AsyncCallDeparting();
|
||||
void AsyncCallArriving();
|
||||
|
||||
void NotifyAsyncInitFailed();
|
||||
|
||||
private:
|
||||
explicit PluginAsyncSurrogate(PluginModuleParent* aParent);
|
||||
virtual ~PluginAsyncSurrogate();
|
||||
|
||||
bool WaitForInit();
|
||||
|
||||
static bool SetStreamType(NPStream* aStream, uint16_t aStreamType);
|
||||
|
||||
static NPError NPP_Destroy(NPP aInstance, NPSavedData** aSave);
|
||||
static NPError NPP_GetValue(NPP aInstance, NPPVariable aVariable, void* aRetval);
|
||||
static NPError NPP_SetValue(NPP aInstance, NPNVariable aVariable, void* aValue);
|
||||
static NPError NPP_NewStream(NPP aInstance, NPMIMEType aType, NPStream* aStream,
|
||||
NPBool aSeekable, uint16_t* aStype);
|
||||
static NPError NPP_SetWindow(NPP aInstance, NPWindow* aWindow);
|
||||
static void NPP_Print(NPP aInstance, NPPrint* aPrintInfo);
|
||||
static int16_t NPP_HandleEvent(NPP aInstance, void* aEvent);
|
||||
static int32_t NPP_WriteReady(NPP aInstance, NPStream* aStream);
|
||||
|
||||
static NPObject* ScriptableAllocate(NPP aInstance, NPClass* aClass);
|
||||
static void ScriptableInvalidate(NPObject* aObject);
|
||||
static void ScriptableDeallocate(NPObject* aObject);
|
||||
static bool ScriptableHasMethod(NPObject* aObject, NPIdentifier aName);
|
||||
static bool ScriptableInvoke(NPObject* aObject, NPIdentifier aName,
|
||||
const NPVariant* aArgs, uint32_t aArgCount,
|
||||
NPVariant* aResult);
|
||||
static bool ScriptableInvokeDefault(NPObject* aObject, const NPVariant* aArgs,
|
||||
uint32_t aArgCount, NPVariant* aResult);
|
||||
static bool ScriptableHasProperty(NPObject* aObject, NPIdentifier aName);
|
||||
static bool ScriptableGetProperty(NPObject* aObject, NPIdentifier aName,
|
||||
NPVariant* aResult);
|
||||
static bool ScriptableSetProperty(NPObject* aObject, NPIdentifier aName,
|
||||
const NPVariant* aValue);
|
||||
static bool ScriptableRemoveProperty(NPObject* aObject, NPIdentifier aName);
|
||||
static bool ScriptableEnumerate(NPObject* aObject, NPIdentifier** aIdentifiers,
|
||||
uint32_t* aCount);
|
||||
static bool ScriptableConstruct(NPObject* aObject, const NPVariant* aArgs,
|
||||
uint32_t aArgCount, NPVariant* aResult);
|
||||
|
||||
private:
|
||||
struct PendingNewStreamCall
|
||||
{
|
||||
PendingNewStreamCall(NPMIMEType aType, NPStream* aStream, NPBool aSeekable);
|
||||
~PendingNewStreamCall() {}
|
||||
nsCString mType;
|
||||
NPStream* mStream;
|
||||
NPBool mSeekable;
|
||||
};
|
||||
|
||||
private:
|
||||
PluginModuleParent* mParent;
|
||||
// These values are used to construct the plugin instance
|
||||
nsCString mMimeType;
|
||||
NPP mInstance;
|
||||
uint16_t mMode;
|
||||
InfallibleTArray<nsCString> mNames;
|
||||
InfallibleTArray<nsCString> mValues;
|
||||
// This is safe to store as a pointer because the spec says it will remain
|
||||
// valid until destruction or a subsequent NPP_SetWindow call.
|
||||
NPWindow* mWindow;
|
||||
nsTArray<PendingNewStreamCall> mPendingNewStreamCalls;
|
||||
UniquePtr<PluginDestructionGuard> mPluginDestructionGuard;
|
||||
|
||||
bool mAcceptCalls;
|
||||
bool mInstantiated;
|
||||
bool mAsyncSetWindow;
|
||||
bool mInitCancelled;
|
||||
int32_t mAsyncCallsInFlight;
|
||||
|
||||
static const NPClass sNPClass;
|
||||
};
|
||||
|
||||
struct AsyncNPObject : NPObject
|
||||
{
|
||||
explicit AsyncNPObject(PluginAsyncSurrogate* aSurrogate);
|
||||
~AsyncNPObject();
|
||||
|
||||
NPObject* GetRealObject();
|
||||
|
||||
nsRefPtr<PluginAsyncSurrogate> mSurrogate;
|
||||
NPObject* mRealObject;
|
||||
};
|
||||
|
||||
class MOZ_STACK_CLASS PushSurrogateAcceptCalls
|
||||
{
|
||||
public:
|
||||
explicit PushSurrogateAcceptCalls(PluginInstanceParent* aInstance);
|
||||
~PushSurrogateAcceptCalls();
|
||||
|
||||
private:
|
||||
PluginAsyncSurrogate* mSurrogate;
|
||||
bool mPrevAcceptCallsState;
|
||||
};
|
||||
|
||||
} // namespace plugins
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // dom_plugins_ipc_PluginAsyncSurrogate_h
|
26
dom/plugins/ipc/PluginDataResolver.h
Normal file
26
dom/plugins/ipc/PluginDataResolver.h
Normal file
@ -0,0 +1,26 @@
|
||||
/* -*- 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 dom_plugins_ipc_PluginDataResolver_h
|
||||
#define dom_plugins_ipc_PluginDataResolver_h
|
||||
|
||||
namespace mozilla {
|
||||
namespace plugins {
|
||||
|
||||
class PluginAsyncSurrogate;
|
||||
class PluginInstanceParent;
|
||||
|
||||
class PluginDataResolver
|
||||
{
|
||||
public:
|
||||
virtual PluginAsyncSurrogate* GetAsyncSurrogate() = 0;
|
||||
virtual PluginInstanceParent* GetInstance() = 0;
|
||||
};
|
||||
|
||||
} // namespace plugins
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // dom_plugins_ipc_PluginDataResolver_h
|
@ -119,8 +119,16 @@ CreateDrawTargetForSurface(gfxASurface *aSurface)
|
||||
return drawTarget;
|
||||
}
|
||||
|
||||
PluginInstanceChild::PluginInstanceChild(const NPPluginFuncs* aPluginIface)
|
||||
PluginInstanceChild::PluginInstanceChild(const NPPluginFuncs* aPluginIface,
|
||||
const nsCString& aMimeType,
|
||||
const uint16_t& aMode,
|
||||
const InfallibleTArray<nsCString>& aNames,
|
||||
const InfallibleTArray<nsCString>& aValues)
|
||||
: mPluginIface(aPluginIface)
|
||||
, mMimeType(aMimeType)
|
||||
, mMode(aMode)
|
||||
, mNames(aNames)
|
||||
, mValues(aValues)
|
||||
#if defined(XP_MACOSX)
|
||||
, mContentsScaleFactor(1.0)
|
||||
#endif
|
||||
@ -210,6 +218,54 @@ PluginInstanceChild::~PluginInstanceChild()
|
||||
#endif
|
||||
}
|
||||
|
||||
NPError
|
||||
PluginInstanceChild::DoNPP_New()
|
||||
{
|
||||
// unpack the arguments into a C format
|
||||
int argc = mNames.Length();
|
||||
NS_ASSERTION(argc == (int) mValues.Length(),
|
||||
"argn.length != argv.length");
|
||||
|
||||
nsAutoArrayPtr<char*> argn(new char*[1 + argc]);
|
||||
nsAutoArrayPtr<char*> argv(new char*[1 + argc]);
|
||||
argn[argc] = 0;
|
||||
argv[argc] = 0;
|
||||
|
||||
for (int i = 0; i < argc; ++i) {
|
||||
argn[i] = const_cast<char*>(NullableStringGet(mNames[i]));
|
||||
argv[i] = const_cast<char*>(NullableStringGet(mValues[i]));
|
||||
}
|
||||
|
||||
NPP npp = GetNPP();
|
||||
|
||||
NPError rv = mPluginIface->newp((char*)NullableStringGet(mMimeType), npp,
|
||||
mMode, argc, argn, argv, 0);
|
||||
if (NPERR_NO_ERROR != rv) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
Initialize();
|
||||
|
||||
#if defined(XP_MACOSX) && defined(__i386__)
|
||||
// If an i386 Mac OS X plugin has selected the Carbon event model then
|
||||
// we have to fail. We do not support putting Carbon event model plugins
|
||||
// out of process. Note that Carbon is the default model so out of process
|
||||
// plugins need to actively negotiate something else in order to work
|
||||
// out of process.
|
||||
if (EventModel() == NPEventModelCarbon) {
|
||||
// Send notification that a plugin tried to negotiate Carbon NPAPI so that
|
||||
// users can be notified that restarting the browser in i386 mode may allow
|
||||
// them to use the plugin.
|
||||
SendNegotiatedCarbon();
|
||||
|
||||
// Fail to instantiate.
|
||||
rv = NPERR_MODULE_LOAD_FAILED_ERROR;
|
||||
}
|
||||
#endif
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
int
|
||||
PluginInstanceChild::GetQuirks()
|
||||
{
|
||||
@ -2234,21 +2290,86 @@ PluginInstanceChild::RecvPPluginScriptableObjectConstructor(
|
||||
}
|
||||
|
||||
bool
|
||||
PluginInstanceChild::AnswerPBrowserStreamConstructor(
|
||||
PluginInstanceChild::RecvPBrowserStreamConstructor(
|
||||
PBrowserStreamChild* aActor,
|
||||
const nsCString& url,
|
||||
const uint32_t& length,
|
||||
const uint32_t& lastmodified,
|
||||
PStreamNotifyChild* notifyData,
|
||||
const nsCString& headers,
|
||||
const nsCString& mimeType,
|
||||
const bool& seekable,
|
||||
NPError* rv,
|
||||
uint16_t* stype)
|
||||
const nsCString& headers)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
NPError
|
||||
PluginInstanceChild::DoNPP_NewStream(BrowserStreamChild* actor,
|
||||
const nsCString& mimeType,
|
||||
const bool& seekable,
|
||||
uint16_t* stype)
|
||||
{
|
||||
AssertPluginThread();
|
||||
*rv = static_cast<BrowserStreamChild*>(aActor)
|
||||
->StreamConstructed(mimeType, seekable, stype);
|
||||
NPError rv = actor->StreamConstructed(mimeType, seekable, stype);
|
||||
return rv;
|
||||
}
|
||||
|
||||
bool
|
||||
PluginInstanceChild::AnswerNPP_NewStream(PBrowserStreamChild* actor,
|
||||
const nsCString& mimeType,
|
||||
const bool& seekable,
|
||||
NPError* rv,
|
||||
uint16_t* stype)
|
||||
{
|
||||
*rv = DoNPP_NewStream(static_cast<BrowserStreamChild*>(actor), mimeType,
|
||||
seekable, stype);
|
||||
return true;
|
||||
}
|
||||
|
||||
class NewStreamAsyncCall : public ChildAsyncCall
|
||||
{
|
||||
public:
|
||||
NewStreamAsyncCall(PluginInstanceChild* aInstance,
|
||||
BrowserStreamChild* aBrowserStreamChild,
|
||||
const nsCString& aMimeType,
|
||||
const bool aSeekable)
|
||||
: ChildAsyncCall(aInstance, nullptr, nullptr)
|
||||
, mBrowserStreamChild(aBrowserStreamChild)
|
||||
, mMimeType(aMimeType)
|
||||
, mSeekable(aSeekable)
|
||||
{
|
||||
}
|
||||
|
||||
void Run() MOZ_OVERRIDE
|
||||
{
|
||||
RemoveFromAsyncList();
|
||||
|
||||
uint16_t stype = NP_NORMAL;
|
||||
NPError rv = mInstance->DoNPP_NewStream(mBrowserStreamChild, mMimeType,
|
||||
mSeekable, &stype);
|
||||
DebugOnly<bool> sendOk =
|
||||
mBrowserStreamChild->SendAsyncNPP_NewStreamResult(rv, stype);
|
||||
MOZ_ASSERT(sendOk);
|
||||
}
|
||||
|
||||
private:
|
||||
BrowserStreamChild* mBrowserStreamChild;
|
||||
const nsCString mMimeType;
|
||||
const bool mSeekable;
|
||||
};
|
||||
|
||||
bool
|
||||
PluginInstanceChild::RecvAsyncNPP_NewStream(PBrowserStreamChild* actor,
|
||||
const nsCString& mimeType,
|
||||
const bool& seekable)
|
||||
{
|
||||
// Reusing ChildAsyncCall so that the task is cancelled properly on Destroy
|
||||
BrowserStreamChild* child = static_cast<BrowserStreamChild*>(actor);
|
||||
NewStreamAsyncCall* task = new NewStreamAsyncCall(this, child, mimeType,
|
||||
seekable);
|
||||
{
|
||||
MutexAutoLock lock(mAsyncCallMutex);
|
||||
mPendingAsyncCalls.AppendElement(task);
|
||||
}
|
||||
MessageLoop::current()->PostTask(FROM_HERE, task);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -2257,16 +2378,12 @@ PluginInstanceChild::AllocPBrowserStreamChild(const nsCString& url,
|
||||
const uint32_t& length,
|
||||
const uint32_t& lastmodified,
|
||||
PStreamNotifyChild* notifyData,
|
||||
const nsCString& headers,
|
||||
const nsCString& mimeType,
|
||||
const bool& seekable,
|
||||
NPError* rv,
|
||||
uint16_t *stype)
|
||||
const nsCString& headers)
|
||||
{
|
||||
AssertPluginThread();
|
||||
return new BrowserStreamChild(this, url, length, lastmodified,
|
||||
static_cast<StreamNotifyChild*>(notifyData),
|
||||
headers, mimeType, seekable, rv, stype);
|
||||
headers);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -143,29 +143,31 @@ protected:
|
||||
virtual bool
|
||||
RecvPPluginScriptableObjectConstructor(PPluginScriptableObjectChild* aActor) MOZ_OVERRIDE;
|
||||
|
||||
virtual bool
|
||||
RecvPBrowserStreamConstructor(PBrowserStreamChild* aActor, const nsCString& url,
|
||||
const uint32_t& length, const uint32_t& lastmodified,
|
||||
PStreamNotifyChild* notifyData, const nsCString& headers);
|
||||
|
||||
virtual bool
|
||||
AnswerNPP_NewStream(
|
||||
PBrowserStreamChild* actor,
|
||||
const nsCString& mimeType,
|
||||
const bool& seekable,
|
||||
NPError* rv,
|
||||
uint16_t* stype) MOZ_OVERRIDE;
|
||||
|
||||
virtual bool
|
||||
RecvAsyncNPP_NewStream(
|
||||
PBrowserStreamChild* actor,
|
||||
const nsCString& mimeType,
|
||||
const bool& seekable) MOZ_OVERRIDE;
|
||||
|
||||
virtual PBrowserStreamChild*
|
||||
AllocPBrowserStreamChild(const nsCString& url,
|
||||
const uint32_t& length,
|
||||
const uint32_t& lastmodified,
|
||||
PStreamNotifyChild* notifyData,
|
||||
const nsCString& headers,
|
||||
const nsCString& mimeType,
|
||||
const bool& seekable,
|
||||
NPError* rv,
|
||||
uint16_t *stype) MOZ_OVERRIDE;
|
||||
|
||||
virtual bool
|
||||
AnswerPBrowserStreamConstructor(
|
||||
PBrowserStreamChild* aActor,
|
||||
const nsCString& url,
|
||||
const uint32_t& length,
|
||||
const uint32_t& lastmodified,
|
||||
PStreamNotifyChild* notifyData,
|
||||
const nsCString& headers,
|
||||
const nsCString& mimeType,
|
||||
const bool& seekable,
|
||||
NPError* rv,
|
||||
uint16_t* stype) MOZ_OVERRIDE;
|
||||
const nsCString& headers) MOZ_OVERRIDE;
|
||||
|
||||
virtual bool
|
||||
DeallocPBrowserStreamChild(PBrowserStreamChild* stream) MOZ_OVERRIDE;
|
||||
@ -202,10 +204,22 @@ protected:
|
||||
#endif
|
||||
|
||||
public:
|
||||
explicit PluginInstanceChild(const NPPluginFuncs* aPluginIface);
|
||||
PluginInstanceChild(const NPPluginFuncs* aPluginIface,
|
||||
const nsCString& aMimeType,
|
||||
const uint16_t& aMode,
|
||||
const InfallibleTArray<nsCString>& aNames,
|
||||
const InfallibleTArray<nsCString>& aValues);
|
||||
|
||||
virtual ~PluginInstanceChild();
|
||||
|
||||
NPError DoNPP_New();
|
||||
|
||||
// Common sync+async implementation of NPP_NewStream
|
||||
NPError DoNPP_NewStream(BrowserStreamChild* actor,
|
||||
const nsCString& mimeType,
|
||||
const bool& seekable,
|
||||
uint16_t* stype);
|
||||
|
||||
bool Initialize();
|
||||
|
||||
NPP GetNPP()
|
||||
@ -352,6 +366,10 @@ private:
|
||||
|
||||
#endif
|
||||
const NPPluginFuncs* mPluginIface;
|
||||
nsCString mMimeType;
|
||||
uint16_t mMode;
|
||||
InfallibleTArray<nsCString> mNames;
|
||||
InfallibleTArray<nsCString> mValues;
|
||||
NPP_t mData;
|
||||
NPWindow mWindow;
|
||||
#if defined(XP_MACOSX)
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "PluginInstanceParent.h"
|
||||
#include "BrowserStreamParent.h"
|
||||
#include "PluginAsyncSurrogate.h"
|
||||
#include "PluginBackgroundDestroyer.h"
|
||||
#include "PluginModuleParent.h"
|
||||
#include "PluginStreamParent.h"
|
||||
@ -21,6 +22,7 @@
|
||||
#include "gfxPlatform.h"
|
||||
#include "gfxSharedImageSurface.h"
|
||||
#include "nsNPAPIPluginInstance.h"
|
||||
#include "nsPluginInstanceOwner.h"
|
||||
#ifdef MOZ_X11
|
||||
#include "gfxXlibSurface.h"
|
||||
#endif
|
||||
@ -75,7 +77,9 @@ PluginInstanceParent::PluginInstanceParent(PluginModuleParent* parent,
|
||||
NPP npp,
|
||||
const nsCString& aMimeType,
|
||||
const NPNetscapeFuncs* npniface)
|
||||
: mParent(parent)
|
||||
: mParent(parent)
|
||||
, mSurrogate(PluginAsyncSurrogate::Cast(npp))
|
||||
, mUseSurrogate(true)
|
||||
, mNPP(npp)
|
||||
, mNPNIface(npniface)
|
||||
, mWindowType(NPWindowTypeWindow)
|
||||
@ -167,11 +171,7 @@ PluginInstanceParent::AllocPBrowserStreamParent(const nsCString& url,
|
||||
const uint32_t& length,
|
||||
const uint32_t& lastmodified,
|
||||
PStreamNotifyParent* notifyData,
|
||||
const nsCString& headers,
|
||||
const nsCString& mimeType,
|
||||
const bool& seekable,
|
||||
NPError* rv,
|
||||
uint16_t *stype)
|
||||
const nsCString& headers)
|
||||
{
|
||||
NS_RUNTIMEABORT("Not reachable");
|
||||
return nullptr;
|
||||
@ -783,6 +783,12 @@ PluginInstanceParent::EndUpdateBackground(gfxContext* aCtx,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PluginAsyncSurrogate*
|
||||
PluginInstanceParent::GetAsyncSurrogate()
|
||||
{
|
||||
return mSurrogate;
|
||||
}
|
||||
|
||||
bool
|
||||
PluginInstanceParent::CreateBackground(const nsIntSize& aSize)
|
||||
{
|
||||
@ -1309,24 +1315,36 @@ PluginInstanceParent::NPP_NewStream(NPMIMEType type, NPStream* stream,
|
||||
|
||||
BrowserStreamParent* bs = new BrowserStreamParent(this, stream);
|
||||
|
||||
NPError err;
|
||||
{ // Scope for timer
|
||||
Telemetry::AutoTimer<Telemetry::BLOCKED_ON_PLUGIN_STREAM_INIT_MS>
|
||||
timer(Module()->GetHistogramKey());
|
||||
if (!CallPBrowserStreamConstructor(bs,
|
||||
NullableString(stream->url),
|
||||
stream->end,
|
||||
stream->lastmodified,
|
||||
static_cast<PStreamNotifyParent*>(stream->notifyData),
|
||||
NullableString(stream->headers),
|
||||
NullableString(type), seekable,
|
||||
&err, stype)) {
|
||||
return NPERR_GENERIC_ERROR;
|
||||
}
|
||||
if (!SendPBrowserStreamConstructor(bs,
|
||||
NullableString(stream->url),
|
||||
stream->end,
|
||||
stream->lastmodified,
|
||||
static_cast<PStreamNotifyParent*>(stream->notifyData),
|
||||
NullableString(stream->headers))) {
|
||||
return NPERR_GENERIC_ERROR;
|
||||
}
|
||||
|
||||
if (NPERR_NO_ERROR != err)
|
||||
unused << PBrowserStreamParent::Send__delete__(bs);
|
||||
Telemetry::AutoTimer<Telemetry::BLOCKED_ON_PLUGIN_STREAM_INIT_MS>
|
||||
timer(Module()->GetHistogramKey());
|
||||
|
||||
NPError err = NPERR_NO_ERROR;
|
||||
if (mParent->IsStartingAsync()) {
|
||||
MOZ_ASSERT(mSurrogate);
|
||||
mSurrogate->AsyncCallDeparting();
|
||||
if (SendAsyncNPP_NewStream(bs, NullableString(type), seekable)) {
|
||||
*stype = UINT16_MAX;
|
||||
} else {
|
||||
err = NPERR_GENERIC_ERROR;
|
||||
}
|
||||
} else {
|
||||
bs->SetAlive();
|
||||
if (!CallNPP_NewStream(bs, NullableString(type), seekable, &err, stype)) {
|
||||
err = NPERR_GENERIC_ERROR;
|
||||
}
|
||||
if (NPERR_NO_ERROR != err) {
|
||||
unused << PBrowserStreamParent::Send__delete__(bs);
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
@ -1636,6 +1654,49 @@ PluginInstanceParent::RecvNegotiatedCarbon()
|
||||
return true;
|
||||
}
|
||||
|
||||
nsPluginInstanceOwner*
|
||||
PluginInstanceParent::GetOwner()
|
||||
{
|
||||
nsNPAPIPluginInstance* inst = static_cast<nsNPAPIPluginInstance*>(mNPP->ndata);
|
||||
if (!inst) {
|
||||
return nullptr;
|
||||
}
|
||||
return inst->GetOwner();
|
||||
}
|
||||
|
||||
bool
|
||||
PluginInstanceParent::RecvAsyncNPP_NewResult(const NPError& aResult)
|
||||
{
|
||||
// NB: mUseSurrogate must be cleared before doing anything else, especially
|
||||
// calling NPP_SetWindow!
|
||||
mUseSurrogate = false;
|
||||
|
||||
mSurrogate->AsyncCallArriving();
|
||||
if (aResult == NPERR_NO_ERROR) {
|
||||
mSurrogate->SetAcceptingCalls(true);
|
||||
}
|
||||
|
||||
nsPluginInstanceOwner* owner = GetOwner();
|
||||
if (!owner) {
|
||||
// This is possible in async plugin land; the instance may outlive
|
||||
// the owner
|
||||
return true;
|
||||
}
|
||||
|
||||
if (aResult != NPERR_NO_ERROR) {
|
||||
owner->NotifyHostAsyncInitFailed();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Now we need to do a bunch of exciting post-NPP_New housekeeping.
|
||||
owner->NotifyHostCreateWidget();
|
||||
|
||||
MOZ_ASSERT(mSurrogate);
|
||||
mSurrogate->OnInstanceCreated(this);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#if defined(OS_WIN)
|
||||
|
||||
/*
|
||||
@ -1875,3 +1936,29 @@ PluginInstanceParent::AnswerPluginFocusChange(const bool& gotFocus)
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
PluginInstanceParent*
|
||||
PluginInstanceParent::Cast(NPP aInstance, PluginAsyncSurrogate** aSurrogate)
|
||||
{
|
||||
PluginDataResolver* resolver =
|
||||
static_cast<PluginDataResolver*>(aInstance->pdata);
|
||||
|
||||
// If the plugin crashed and the PluginInstanceParent was deleted,
|
||||
// aInstance->pdata will be nullptr.
|
||||
if (!resolver) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PluginInstanceParent* instancePtr = resolver->GetInstance();
|
||||
|
||||
if (instancePtr && aInstance != instancePtr->mNPP) {
|
||||
NS_RUNTIMEABORT("Corrupted plugin data.");
|
||||
}
|
||||
|
||||
if (aSurrogate) {
|
||||
*aSurrogate = resolver->GetAsyncSurrogate();
|
||||
}
|
||||
|
||||
return instancePtr;
|
||||
}
|
||||
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "nsDataHashtable.h"
|
||||
#include "nsHashKeys.h"
|
||||
#include "nsRect.h"
|
||||
#include "PluginDataResolver.h"
|
||||
|
||||
#ifdef MOZ_X11
|
||||
class gfxXlibSurface;
|
||||
@ -30,6 +31,7 @@ class gfxXlibSurface;
|
||||
|
||||
class gfxASurface;
|
||||
class gfxContext;
|
||||
class nsPluginInstanceOwner;
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
@ -42,6 +44,7 @@ class PBrowserStreamParent;
|
||||
class PluginModuleParent;
|
||||
|
||||
class PluginInstanceParent : public PPluginInstanceParent
|
||||
, public PluginDataResolver
|
||||
{
|
||||
friend class PluginModuleParent;
|
||||
friend class BrowserStreamParent;
|
||||
@ -74,11 +77,7 @@ public:
|
||||
const uint32_t& length,
|
||||
const uint32_t& lastmodified,
|
||||
PStreamNotifyParent* notifyData,
|
||||
const nsCString& headers,
|
||||
const nsCString& mimeType,
|
||||
const bool& seekable,
|
||||
NPError* rv,
|
||||
uint16_t *stype) MOZ_OVERRIDE;
|
||||
const nsCString& headers) MOZ_OVERRIDE;
|
||||
virtual bool
|
||||
DeallocPBrowserStreamParent(PBrowserStreamParent* stream) MOZ_OVERRIDE;
|
||||
|
||||
@ -210,6 +209,9 @@ public:
|
||||
virtual bool
|
||||
RecvNegotiatedCarbon() MOZ_OVERRIDE;
|
||||
|
||||
virtual bool
|
||||
RecvAsyncNPP_NewResult(const NPError& aResult) MOZ_OVERRIDE;
|
||||
|
||||
NPError NPP_SetWindow(const NPWindow* aWindow);
|
||||
|
||||
NPError NPP_GetValue(NPPVariable variable, void* retval);
|
||||
@ -254,6 +256,12 @@ public:
|
||||
return mNPP;
|
||||
}
|
||||
|
||||
bool
|
||||
UseSurrogate() const
|
||||
{
|
||||
return mUseSurrogate;
|
||||
}
|
||||
|
||||
virtual bool
|
||||
AnswerPluginFocusChange(const bool& gotFocus) MOZ_OVERRIDE;
|
||||
|
||||
@ -271,6 +279,13 @@ public:
|
||||
const nsIntRect& aRect);
|
||||
void DidComposite() { unused << SendNPP_DidComposite(); }
|
||||
|
||||
virtual PluginAsyncSurrogate* GetAsyncSurrogate();
|
||||
|
||||
virtual PluginInstanceParent* GetInstance() { return this; }
|
||||
|
||||
static PluginInstanceParent* Cast(NPP instance,
|
||||
PluginAsyncSurrogate** aSurrogate = nullptr);
|
||||
|
||||
private:
|
||||
// Create an appropriate platform surface for a background of size
|
||||
// |aSize|. Return true if successful.
|
||||
@ -291,8 +306,12 @@ private:
|
||||
PPluginScriptableObjectParent** aValue,
|
||||
NPError* aResult);
|
||||
|
||||
nsPluginInstanceOwner* GetOwner();
|
||||
|
||||
private:
|
||||
PluginModuleParent* mParent;
|
||||
nsRefPtr<PluginAsyncSurrogate> mSurrogate;
|
||||
bool mUseSurrogate;
|
||||
NPP mNPP;
|
||||
const NPNetscapeFuncs* mNPNIface;
|
||||
NPWindowType mWindowType;
|
||||
|
@ -95,6 +95,13 @@ static GetWindowInfoPtr sGetWindowInfoPtrStub = nullptr;
|
||||
static HWND sBrowserHwnd = nullptr;
|
||||
#endif
|
||||
|
||||
template<>
|
||||
struct RunnableMethodTraits<PluginModuleChild>
|
||||
{
|
||||
static void RetainCallee(PluginModuleChild* obj) { }
|
||||
static void ReleaseCallee(PluginModuleChild* obj) { }
|
||||
};
|
||||
|
||||
/* static */
|
||||
PluginModuleChild*
|
||||
PluginModuleChild::CreateForContentProcess(mozilla::ipc::Transport* aTransport,
|
||||
@ -1881,7 +1888,21 @@ PluginModuleChild::AnswerNP_GetEntryPoints(NPError* _retval)
|
||||
}
|
||||
|
||||
bool
|
||||
PluginModuleChild::AnswerNP_Initialize(const PluginSettings& aSettings, NPError* _retval)
|
||||
PluginModuleChild::AnswerNP_Initialize(const PluginSettings& aSettings, NPError* rv)
|
||||
{
|
||||
*rv = DoNP_Initialize(aSettings);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
PluginModuleChild::RecvAsyncNP_Initialize(const PluginSettings& aSettings)
|
||||
{
|
||||
NPError error = DoNP_Initialize(aSettings);
|
||||
return SendNP_InitializeResult(error);
|
||||
}
|
||||
|
||||
NPError
|
||||
PluginModuleChild::DoNP_Initialize(const PluginSettings& aSettings)
|
||||
{
|
||||
PLUGIN_LOG_DEBUG_METHOD;
|
||||
AssertPluginThread();
|
||||
@ -1900,12 +1921,11 @@ PluginModuleChild::AnswerNP_Initialize(const PluginSettings& aSettings, NPError*
|
||||
SendBackUpXResources(FileDescriptor(xSocketFd));
|
||||
#endif
|
||||
|
||||
NPError result;
|
||||
#if defined(OS_LINUX) || defined(OS_BSD)
|
||||
*_retval = mInitializeFunc(&sBrowserFuncs, &mFunctions);
|
||||
return true;
|
||||
result = mInitializeFunc(&sBrowserFuncs, &mFunctions);
|
||||
#elif defined(OS_WIN) || defined(OS_MACOSX)
|
||||
*_retval = mInitializeFunc(&sBrowserFuncs);
|
||||
return true;
|
||||
result = mInitializeFunc(&sBrowserFuncs);
|
||||
#else
|
||||
# error Please implement me for your platform
|
||||
#endif
|
||||
@ -1913,6 +1933,8 @@ PluginModuleChild::AnswerNP_Initialize(const PluginSettings& aSettings, NPError*
|
||||
#ifdef XP_WIN
|
||||
CleanupProtectedModeHook();
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#if defined(XP_WIN)
|
||||
@ -2035,8 +2057,7 @@ PPluginInstanceChild*
|
||||
PluginModuleChild::AllocPPluginInstanceChild(const nsCString& aMimeType,
|
||||
const uint16_t& aMode,
|
||||
const InfallibleTArray<nsCString>& aNames,
|
||||
const InfallibleTArray<nsCString>& aValues,
|
||||
NPError* rv)
|
||||
const InfallibleTArray<nsCString>& aValues)
|
||||
{
|
||||
PLUGIN_LOG_DEBUG_METHOD;
|
||||
AssertPluginThread();
|
||||
@ -2052,7 +2073,8 @@ PluginModuleChild::AllocPPluginInstanceChild(const nsCString& aMimeType,
|
||||
}
|
||||
#endif
|
||||
|
||||
return new PluginInstanceChild(&mFunctions);
|
||||
return new PluginInstanceChild(&mFunctions, aMimeType, aMode, aNames,
|
||||
aValues);
|
||||
}
|
||||
|
||||
void
|
||||
@ -2105,68 +2127,39 @@ PluginModuleChild::InitQuirksModes(const nsCString& aMimeType)
|
||||
}
|
||||
|
||||
bool
|
||||
PluginModuleChild::AnswerPPluginInstanceConstructor(PPluginInstanceChild* aActor,
|
||||
const nsCString& aMimeType,
|
||||
const uint16_t& aMode,
|
||||
const InfallibleTArray<nsCString>& aNames,
|
||||
const InfallibleTArray<nsCString>& aValues,
|
||||
NPError* rv)
|
||||
PluginModuleChild::RecvPPluginInstanceConstructor(PPluginInstanceChild* aActor,
|
||||
const nsCString& aMimeType,
|
||||
const uint16_t& aMode,
|
||||
const InfallibleTArray<nsCString>& aNames,
|
||||
const InfallibleTArray<nsCString>& aValues)
|
||||
{
|
||||
PLUGIN_LOG_DEBUG_METHOD;
|
||||
AssertPluginThread();
|
||||
|
||||
NS_ASSERTION(aActor, "Null actor!");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
PluginModuleChild::AnswerSyncNPP_New(PPluginInstanceChild* aActor, NPError* rv)
|
||||
{
|
||||
PLUGIN_LOG_DEBUG_METHOD;
|
||||
PluginInstanceChild* childInstance =
|
||||
reinterpret_cast<PluginInstanceChild*>(aActor);
|
||||
NS_ASSERTION(childInstance, "Null actor!");
|
||||
|
||||
// unpack the arguments into a C format
|
||||
int argc = aNames.Length();
|
||||
NS_ASSERTION(argc == (int) aValues.Length(),
|
||||
"argn.length != argv.length");
|
||||
|
||||
nsAutoArrayPtr<char*> argn(new char*[1 + argc]);
|
||||
nsAutoArrayPtr<char*> argv(new char*[1 + argc]);
|
||||
argn[argc] = 0;
|
||||
argv[argc] = 0;
|
||||
|
||||
for (int i = 0; i < argc; ++i) {
|
||||
argn[i] = const_cast<char*>(NullableStringGet(aNames[i]));
|
||||
argv[i] = const_cast<char*>(NullableStringGet(aValues[i]));
|
||||
}
|
||||
|
||||
NPP npp = childInstance->GetNPP();
|
||||
|
||||
// FIXME/cjones: use SAFE_CALL stuff
|
||||
*rv = mFunctions.newp((char*)NullableStringGet(aMimeType),
|
||||
npp,
|
||||
aMode,
|
||||
argc,
|
||||
argn,
|
||||
argv,
|
||||
0);
|
||||
if (NPERR_NO_ERROR != *rv) {
|
||||
return true;
|
||||
}
|
||||
|
||||
childInstance->Initialize();
|
||||
|
||||
#if defined(XP_MACOSX) && defined(__i386__)
|
||||
// If an i386 Mac OS X plugin has selected the Carbon event model then
|
||||
// we have to fail. We do not support putting Carbon event model plugins
|
||||
// out of process. Note that Carbon is the default model so out of process
|
||||
// plugins need to actively negotiate something else in order to work
|
||||
// out of process.
|
||||
if (childInstance->EventModel() == NPEventModelCarbon) {
|
||||
// Send notification that a plugin tried to negotiate Carbon NPAPI so that
|
||||
// users can be notified that restarting the browser in i386 mode may allow
|
||||
// them to use the plugin.
|
||||
childInstance->SendNegotiatedCarbon();
|
||||
|
||||
// Fail to instantiate.
|
||||
*rv = NPERR_MODULE_LOAD_FAILED_ERROR;
|
||||
}
|
||||
#endif
|
||||
AssertPluginThread();
|
||||
*rv = childInstance->DoNPP_New();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
PluginModuleChild::RecvAsyncNPP_New(PPluginInstanceChild* aActor)
|
||||
{
|
||||
PLUGIN_LOG_DEBUG_METHOD;
|
||||
PluginInstanceChild* childInstance =
|
||||
reinterpret_cast<PluginInstanceChild*>(aActor);
|
||||
AssertPluginThread();
|
||||
NPError rv = childInstance->DoNPP_New();
|
||||
childInstance->SendAsyncNPP_NewResult(rv);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -78,6 +78,10 @@ protected:
|
||||
virtual bool RecvDisableFlashProtectedMode() MOZ_OVERRIDE;
|
||||
virtual bool AnswerNP_GetEntryPoints(NPError* rv) MOZ_OVERRIDE;
|
||||
virtual bool AnswerNP_Initialize(const PluginSettings& aSettings, NPError* rv) MOZ_OVERRIDE;
|
||||
virtual bool RecvAsyncNP_Initialize(const PluginSettings& aSettings) MOZ_OVERRIDE;
|
||||
virtual bool AnswerSyncNPP_New(PPluginInstanceChild* aActor, NPError* rv)
|
||||
MOZ_OVERRIDE;
|
||||
virtual bool RecvAsyncNPP_New(PPluginInstanceChild* aActor) MOZ_OVERRIDE;
|
||||
|
||||
virtual PPluginModuleChild*
|
||||
AllocPPluginModuleChild(mozilla::ipc::Transport* aTransport,
|
||||
@ -87,19 +91,19 @@ protected:
|
||||
AllocPPluginInstanceChild(const nsCString& aMimeType,
|
||||
const uint16_t& aMode,
|
||||
const InfallibleTArray<nsCString>& aNames,
|
||||
const InfallibleTArray<nsCString>& aValues,
|
||||
NPError* rv) MOZ_OVERRIDE;
|
||||
const InfallibleTArray<nsCString>& aValues)
|
||||
MOZ_OVERRIDE;
|
||||
|
||||
virtual bool
|
||||
DeallocPPluginInstanceChild(PPluginInstanceChild* aActor) MOZ_OVERRIDE;
|
||||
|
||||
virtual bool
|
||||
AnswerPPluginInstanceConstructor(PPluginInstanceChild* aActor,
|
||||
const nsCString& aMimeType,
|
||||
const uint16_t& aMode,
|
||||
const InfallibleTArray<nsCString>& aNames,
|
||||
const InfallibleTArray<nsCString>& aValues,
|
||||
NPError* rv) MOZ_OVERRIDE;
|
||||
RecvPPluginInstanceConstructor(PPluginInstanceChild* aActor,
|
||||
const nsCString& aMimeType,
|
||||
const uint16_t& aMode,
|
||||
const InfallibleTArray<nsCString>& aNames,
|
||||
const InfallibleTArray<nsCString>& aValues)
|
||||
MOZ_OVERRIDE;
|
||||
virtual bool
|
||||
AnswerNP_Shutdown(NPError *rv) MOZ_OVERRIDE;
|
||||
|
||||
@ -286,6 +290,7 @@ public:
|
||||
const PluginSettings& Settings() const { return mCachedSettings; }
|
||||
|
||||
private:
|
||||
NPError DoNP_Initialize(const PluginSettings& aSettings);
|
||||
void AddQuirk(PluginQuirks quirk) {
|
||||
if (mQuirks == QUIRKS_NOT_INITIALIZED)
|
||||
mQuirks = 0;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -40,6 +40,7 @@ namespace plugins {
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class BrowserStreamParent;
|
||||
class PluginAsyncSurrogate;
|
||||
class PluginInstanceParent;
|
||||
|
||||
#ifdef XP_WIN
|
||||
@ -79,8 +80,8 @@ protected:
|
||||
AllocPPluginInstanceParent(const nsCString& aMimeType,
|
||||
const uint16_t& aMode,
|
||||
const InfallibleTArray<nsCString>& aNames,
|
||||
const InfallibleTArray<nsCString>& aValues,
|
||||
NPError* rv) MOZ_OVERRIDE;
|
||||
const InfallibleTArray<nsCString>& aValues)
|
||||
MOZ_OVERRIDE;
|
||||
|
||||
virtual bool
|
||||
DeallocPPluginInstanceParent(PPluginInstanceParent* aActor) MOZ_OVERRIDE;
|
||||
@ -89,6 +90,13 @@ public:
|
||||
explicit PluginModuleParent(bool aIsChrome);
|
||||
virtual ~PluginModuleParent();
|
||||
|
||||
bool RemovePendingSurrogate(const nsRefPtr<PluginAsyncSurrogate>& aSurrogate);
|
||||
|
||||
/** @return the state of the pref that controls async plugin init */
|
||||
bool IsStartingAsync() const { return mIsStartingAsync; }
|
||||
/** @return whether this modules NP_Initialize has successfully completed
|
||||
executing */
|
||||
bool IsInitialized() const { return mNPInitialized; }
|
||||
bool IsChrome() const { return mIsChrome; }
|
||||
|
||||
virtual void SetPlugin(nsNPAPIPlugin* plugin) MOZ_OVERRIDE
|
||||
@ -108,6 +116,8 @@ public:
|
||||
|
||||
void ProcessRemoteNativeEventsInInterruptCall();
|
||||
|
||||
virtual bool WaitForIPCConnection() { return true; }
|
||||
|
||||
nsCString GetHistogramKey() const {
|
||||
return mPluginName + mPluginVersion;
|
||||
}
|
||||
@ -159,8 +169,11 @@ protected:
|
||||
virtual bool
|
||||
RecvNPN_ReloadPlugins(const bool& aReloadPages) MOZ_OVERRIDE;
|
||||
|
||||
static PluginInstanceParent* InstCast(NPP instance);
|
||||
static BrowserStreamParent* StreamCast(NPP instance, NPStream* s);
|
||||
virtual bool
|
||||
RecvNP_InitializeResult(const NPError& aError) MOZ_OVERRIDE;
|
||||
|
||||
static BrowserStreamParent* StreamCast(NPP instance, NPStream* s,
|
||||
PluginAsyncSurrogate** aSurrogate = nullptr);
|
||||
|
||||
protected:
|
||||
virtual void UpdatePluginTimeout() {}
|
||||
@ -169,6 +182,11 @@ protected:
|
||||
|
||||
void SetPluginFuncs(NPPluginFuncs* aFuncs);
|
||||
|
||||
nsresult NPP_NewInternal(NPMIMEType pluginType, NPP instance, uint16_t mode,
|
||||
InfallibleTArray<nsCString>& names,
|
||||
InfallibleTArray<nsCString>& values,
|
||||
NPSavedData* saved, NPError* error);
|
||||
|
||||
// NPP-like API that Gecko calls are trampolined into. These
|
||||
// messages then get forwarded along to the plugin instance,
|
||||
// and then eventually the child process.
|
||||
@ -235,8 +253,11 @@ protected:
|
||||
virtual nsresult ContentsScaleFactorChanged(NPP instance, double aContentsScaleFactor);
|
||||
#endif
|
||||
|
||||
void InitAsyncSurrogates();
|
||||
|
||||
protected:
|
||||
void NotifyPluginCrashed();
|
||||
void OnInitFailure();
|
||||
|
||||
bool GetSetting(NPNVariable aVariable);
|
||||
void GetSettings(PluginSettings* aSettings);
|
||||
@ -245,7 +266,7 @@ protected:
|
||||
bool mShutdown;
|
||||
bool mClearSiteDataSupported;
|
||||
bool mGetSitesWithDataSupported;
|
||||
const NPNetscapeFuncs* mNPNIface;
|
||||
NPNetscapeFuncs* mNPNIface;
|
||||
nsNPAPIPlugin* mPlugin;
|
||||
ScopedMethodFactory<PluginModuleParent> mTaskFactory;
|
||||
nsString mPluginDumpID;
|
||||
@ -266,18 +287,29 @@ protected:
|
||||
GetPluginDetails(nsACString& aPluginName, nsACString& aPluginVersion);
|
||||
|
||||
friend class mozilla::dom::CrashReporterParent;
|
||||
friend class mozilla::plugins::PluginAsyncSurrogate;
|
||||
|
||||
bool mIsStartingAsync;
|
||||
bool mNPInitialized;
|
||||
nsTArray<nsRefPtr<PluginAsyncSurrogate>> mSurrogateInstances;
|
||||
nsresult mAsyncNewRv;
|
||||
NPPluginFuncs* mAsyncInitPluginFuncs;
|
||||
};
|
||||
|
||||
class PluginModuleContentParent : public PluginModuleParent
|
||||
{
|
||||
public:
|
||||
explicit PluginModuleContentParent();
|
||||
|
||||
static PluginLibrary* LoadModule(uint32_t aPluginId);
|
||||
|
||||
static PluginModuleContentParent* Create(mozilla::ipc::Transport* aTransport,
|
||||
base::ProcessId aOtherProcess);
|
||||
static PluginModuleContentParent* Initialize(mozilla::ipc::Transport* aTransport,
|
||||
base::ProcessId aOtherProcess);
|
||||
|
||||
static void OnLoadPluginResult(const uint32_t& aPluginId, const bool& aResult);
|
||||
static void AssociatePluginId(uint32_t aPluginId, base::ProcessId aProcessId);
|
||||
|
||||
private:
|
||||
explicit PluginModuleContentParent();
|
||||
|
||||
#ifdef MOZ_CRASHREPORTER_INJECTOR
|
||||
void OnCrash(DWORD processID) MOZ_OVERRIDE {}
|
||||
@ -313,6 +345,17 @@ class PluginModuleChromeParent
|
||||
OnHangUIContinue();
|
||||
#endif // XP_WIN
|
||||
|
||||
virtual bool WaitForIPCConnection() MOZ_OVERRIDE;
|
||||
|
||||
virtual bool
|
||||
RecvNP_InitializeResult(const NPError& aError) MOZ_OVERRIDE;
|
||||
|
||||
void
|
||||
SetContentParent(dom::ContentParent* aContentParent);
|
||||
|
||||
bool
|
||||
SendAssociatePluginId();
|
||||
|
||||
void CachedSettingChanged();
|
||||
|
||||
private:
|
||||
@ -341,8 +384,14 @@ private:
|
||||
PluginProcessParent* Process() const { return mSubprocess; }
|
||||
base::ProcessHandle ChildProcessHandle() { return mSubprocess->GetChildProcessHandle(); }
|
||||
|
||||
#if !defined(XP_UNIX) || defined(XP_MACOSX) || defined(MOZ_WIDGET_GONK)
|
||||
virtual nsresult NP_Initialize(NPNetscapeFuncs* bFuncs, NPError* error);
|
||||
#if defined(XP_UNIX) && !defined(XP_MACOSX) && !defined(MOZ_WIDGET_GONK)
|
||||
virtual nsresult NP_Initialize(NPNetscapeFuncs* bFuncs, NPPluginFuncs* pFuncs, NPError* error) MOZ_OVERRIDE;
|
||||
#else
|
||||
virtual nsresult NP_Initialize(NPNetscapeFuncs* bFuncs, NPError* error) MOZ_OVERRIDE;
|
||||
#endif
|
||||
|
||||
#if defined(XP_WIN) || defined(XP_MACOSX)
|
||||
virtual nsresult NP_GetEntryPoints(NPPluginFuncs* pFuncs, NPError* error) MOZ_OVERRIDE;
|
||||
#endif
|
||||
|
||||
virtual void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE;
|
||||
@ -421,17 +470,45 @@ private:
|
||||
#endif
|
||||
|
||||
friend class mozilla::dom::CrashReporterParent;
|
||||
friend class mozilla::plugins::PluginAsyncSurrogate;
|
||||
|
||||
#ifdef MOZ_CRASHREPORTER_INJECTOR
|
||||
void InitializeInjector();
|
||||
|
||||
|
||||
void OnCrash(DWORD processID) MOZ_OVERRIDE;
|
||||
|
||||
DWORD mFlashProcess1;
|
||||
DWORD mFlashProcess2;
|
||||
#endif
|
||||
|
||||
void OnProcessLaunched(const bool aSucceeded);
|
||||
|
||||
class LaunchedTask : public LaunchCompleteTask
|
||||
{
|
||||
public:
|
||||
explicit LaunchedTask(PluginModuleChromeParent* aModule)
|
||||
: mModule(aModule)
|
||||
{
|
||||
MOZ_ASSERT(aModule);
|
||||
}
|
||||
|
||||
void Run() MOZ_OVERRIDE
|
||||
{
|
||||
mModule->OnProcessLaunched(mLaunchSucceeded);
|
||||
}
|
||||
|
||||
private:
|
||||
PluginModuleChromeParent* mModule;
|
||||
};
|
||||
|
||||
friend class LaunchedTask;
|
||||
|
||||
bool mInitOnAsyncConnect;
|
||||
nsresult mAsyncInitRv;
|
||||
NPError mAsyncInitError;
|
||||
dom::ContentParent* mContentParent;
|
||||
nsCOMPtr<nsIObserver> mOfflineObserver;
|
||||
bool mIsFlashPlugin;
|
||||
};
|
||||
|
||||
} // namespace plugins
|
||||
|
@ -12,12 +12,14 @@
|
||||
#include "mozilla/ipc/BrowserProcessSubThread.h"
|
||||
#include "mozilla/plugins/PluginMessageUtils.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
using std::vector;
|
||||
using std::string;
|
||||
|
||||
using mozilla::ipc::BrowserProcessSubThread;
|
||||
using mozilla::ipc::GeckoChildProcessHost;
|
||||
using mozilla::plugins::LaunchCompleteTask;
|
||||
using mozilla::plugins::PluginProcessParent;
|
||||
using base::ProcessArchitecture;
|
||||
|
||||
@ -30,7 +32,9 @@ struct RunnableMethodTraits<PluginProcessParent>
|
||||
|
||||
PluginProcessParent::PluginProcessParent(const std::string& aPluginFilePath) :
|
||||
GeckoChildProcessHost(GeckoProcessType_Plugin),
|
||||
mPluginFilePath(aPluginFilePath)
|
||||
mPluginFilePath(aPluginFilePath),
|
||||
mMainMsgLoop(MessageLoop::current()),
|
||||
mRunCompleteTaskImmediately(false)
|
||||
{
|
||||
}
|
||||
|
||||
@ -39,7 +43,7 @@ PluginProcessParent::~PluginProcessParent()
|
||||
}
|
||||
|
||||
bool
|
||||
PluginProcessParent::Launch(int32_t timeoutMs)
|
||||
PluginProcessParent::Launch(mozilla::UniquePtr<LaunchCompleteTask> aLaunchCompleteTask)
|
||||
{
|
||||
ProcessArchitecture currentArchitecture = base::GetCurrentProcessArchitecture();
|
||||
uint32_t containerArchitectures = GetSupportedArchitecturesForProcessType(GeckoProcessType_Plugin);
|
||||
@ -74,10 +78,16 @@ PluginProcessParent::Launch(int32_t timeoutMs)
|
||||
}
|
||||
}
|
||||
|
||||
mLaunchCompleteTask = mozilla::Move(aLaunchCompleteTask);
|
||||
|
||||
vector<string> args;
|
||||
args.push_back(MungePluginDsoPath(mPluginFilePath));
|
||||
Telemetry::AutoTimer<Telemetry::PLUGIN_STARTUP_MS> timer;
|
||||
return SyncLaunch(args, timeoutMs, selectedArchitecture);
|
||||
|
||||
bool result = AsyncLaunch(args, selectedArchitecture);
|
||||
if (!result) {
|
||||
mLaunchCompleteTask = nullptr;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
@ -94,3 +104,50 @@ PluginProcessParent::Delete()
|
||||
ioLoop->PostTask(FROM_HERE,
|
||||
NewRunnableMethod(this, &PluginProcessParent::Delete));
|
||||
}
|
||||
|
||||
void
|
||||
PluginProcessParent::SetCallRunnableImmediately(bool aCallImmediately)
|
||||
{
|
||||
mRunCompleteTaskImmediately = aCallImmediately;
|
||||
}
|
||||
|
||||
bool
|
||||
PluginProcessParent::WaitUntilConnected(int32_t aTimeoutMs)
|
||||
{
|
||||
bool result = GeckoChildProcessHost::WaitUntilConnected(aTimeoutMs);
|
||||
if (mRunCompleteTaskImmediately && mLaunchCompleteTask) {
|
||||
if (result) {
|
||||
mLaunchCompleteTask->SetLaunchSucceeded();
|
||||
}
|
||||
mLaunchCompleteTask->Run();
|
||||
mLaunchCompleteTask = nullptr;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
PluginProcessParent::OnChannelConnected(int32_t peer_pid)
|
||||
{
|
||||
GeckoChildProcessHost::OnChannelConnected(peer_pid);
|
||||
if (mLaunchCompleteTask && !mRunCompleteTaskImmediately) {
|
||||
mLaunchCompleteTask->SetLaunchSucceeded();
|
||||
mMainMsgLoop->PostTask(FROM_HERE, mLaunchCompleteTask.release());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PluginProcessParent::OnChannelError()
|
||||
{
|
||||
GeckoChildProcessHost::OnChannelError();
|
||||
if (mLaunchCompleteTask && !mRunCompleteTaskImmediately) {
|
||||
mMainMsgLoop->PostTask(FROM_HERE, mLaunchCompleteTask.release());
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
PluginProcessParent::IsConnected()
|
||||
{
|
||||
mozilla::MonitorAutoLock lock(mMonitor);
|
||||
return mProcessState == PROCESS_CONNECTED;
|
||||
}
|
||||
|
||||
|
@ -11,15 +11,32 @@
|
||||
#include "base/basictypes.h"
|
||||
|
||||
#include "base/file_path.h"
|
||||
#include "base/task.h"
|
||||
#include "base/thread.h"
|
||||
#include "base/waitable_event.h"
|
||||
#include "chrome/common/child_process_host.h"
|
||||
|
||||
#include "mozilla/ipc/GeckoChildProcessHost.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIRunnable.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace plugins {
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class LaunchCompleteTask : public Task
|
||||
{
|
||||
public:
|
||||
LaunchCompleteTask()
|
||||
: mLaunchSucceeded(false)
|
||||
{
|
||||
}
|
||||
|
||||
void SetLaunchSucceeded() { mLaunchSucceeded = true; }
|
||||
|
||||
protected:
|
||||
bool mLaunchSucceeded;
|
||||
};
|
||||
|
||||
class PluginProcessParent : public mozilla::ipc::GeckoChildProcessHost
|
||||
{
|
||||
@ -28,10 +45,13 @@ public:
|
||||
~PluginProcessParent();
|
||||
|
||||
/**
|
||||
* Synchronously launch the plugin process. If the process fails to launch
|
||||
* after timeoutMs, this method will return false.
|
||||
* Launch the plugin process. If the process fails to launch,
|
||||
* this method will return false.
|
||||
*
|
||||
* @param aLaunchCompleteTask Task that is executed on the main
|
||||
* thread once the asynchonous launch has completed.
|
||||
*/
|
||||
bool Launch(int32_t timeoutMs);
|
||||
bool Launch(UniquePtr<LaunchCompleteTask> aLaunchCompleteTask = UniquePtr<LaunchCompleteTask>());
|
||||
|
||||
void Delete();
|
||||
|
||||
@ -45,8 +65,19 @@ public:
|
||||
using mozilla::ipc::GeckoChildProcessHost::GetShutDownEvent;
|
||||
using mozilla::ipc::GeckoChildProcessHost::GetChannel;
|
||||
|
||||
void SetCallRunnableImmediately(bool aCallImmediately);
|
||||
virtual bool WaitUntilConnected(int32_t aTimeoutMs = 0) MOZ_OVERRIDE;
|
||||
|
||||
virtual void OnChannelConnected(int32_t peer_pid) MOZ_OVERRIDE;
|
||||
virtual void OnChannelError() MOZ_OVERRIDE;
|
||||
|
||||
bool IsConnected();
|
||||
|
||||
private:
|
||||
std::string mPluginFilePath;
|
||||
UniquePtr<LaunchCompleteTask> mLaunchCompleteTask;
|
||||
MessageLoop* mMainMsgLoop;
|
||||
bool mRunCompleteTaskImmediately;
|
||||
|
||||
DISALLOW_EVIL_CONSTRUCTORS(PluginProcessParent);
|
||||
};
|
||||
|
@ -1281,5 +1281,7 @@ PluginScriptableObjectChild::CollectForInstance(NPObjectData* d, void* userArg)
|
||||
PluginScriptableObjectChild::NotifyOfInstanceShutdown(PluginInstanceChild* aInstance)
|
||||
{
|
||||
AssertPluginThread();
|
||||
sObjectMap->EnumerateEntries(CollectForInstance, aInstance);
|
||||
if (sObjectMap) {
|
||||
sObjectMap->EnumerateEntries(CollectForInstance, aInstance);
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "mozilla/plugins/PluginTypes.h"
|
||||
#include "mozilla/unused.h"
|
||||
#include "nsNPAPIPlugin.h"
|
||||
#include "PluginAsyncSurrogate.h"
|
||||
#include "PluginScriptableObjectUtils.h"
|
||||
|
||||
using namespace mozilla;
|
||||
@ -110,6 +111,7 @@ inline void
|
||||
ReleaseVariant(NPVariant& aVariant,
|
||||
PluginInstanceParent* aInstance)
|
||||
{
|
||||
PushSurrogateAcceptCalls acceptCalls(aInstance);
|
||||
const NPNetscapeFuncs* npn = GetNetscapeFuncs(aInstance);
|
||||
if (npn) {
|
||||
npn->releasevariantvalue(&aVariant);
|
||||
@ -643,6 +645,7 @@ PluginScriptableObjectParent::CreateProxyObject()
|
||||
NS_ASSERTION(mInstance, "Must have an instance!");
|
||||
NS_ASSERTION(mType == Proxy, "Shouldn't call this for non-proxy object!");
|
||||
|
||||
PushSurrogateAcceptCalls acceptCalls(mInstance);
|
||||
const NPNetscapeFuncs* npn = GetNetscapeFuncs(mInstance);
|
||||
|
||||
NPObject* npobject = npn->createobject(mInstance->GetNPP(),
|
||||
@ -761,6 +764,7 @@ PluginScriptableObjectParent::AnswerHasMethod(const PluginIdentifier& aId,
|
||||
return true;
|
||||
}
|
||||
|
||||
PushSurrogateAcceptCalls acceptCalls(instance);
|
||||
const NPNetscapeFuncs* npn = GetNetscapeFuncs(instance);
|
||||
if (!npn) {
|
||||
NS_ERROR("No netscape funcs?!");
|
||||
@ -801,6 +805,7 @@ PluginScriptableObjectParent::AnswerInvoke(const PluginIdentifier& aId,
|
||||
return true;
|
||||
}
|
||||
|
||||
PushSurrogateAcceptCalls acceptCalls(instance);
|
||||
const NPNetscapeFuncs* npn = GetNetscapeFuncs(instance);
|
||||
if (!npn) {
|
||||
NS_ERROR("No netscape funcs?!");
|
||||
@ -890,6 +895,7 @@ PluginScriptableObjectParent::AnswerInvokeDefault(const InfallibleTArray<Variant
|
||||
return true;
|
||||
}
|
||||
|
||||
PushSurrogateAcceptCalls acceptCalls(instance);
|
||||
const NPNetscapeFuncs* npn = GetNetscapeFuncs(instance);
|
||||
if (!npn) {
|
||||
NS_ERROR("No netscape funcs?!");
|
||||
@ -970,6 +976,7 @@ PluginScriptableObjectParent::AnswerHasProperty(const PluginIdentifier& aId,
|
||||
return true;
|
||||
}
|
||||
|
||||
PushSurrogateAcceptCalls acceptCalls(instance);
|
||||
const NPNetscapeFuncs* npn = GetNetscapeFuncs(instance);
|
||||
if (!npn) {
|
||||
NS_ERROR("No netscape funcs?!");
|
||||
@ -1012,6 +1019,7 @@ PluginScriptableObjectParent::AnswerGetParentProperty(
|
||||
return true;
|
||||
}
|
||||
|
||||
PushSurrogateAcceptCalls acceptCalls(instance);
|
||||
const NPNetscapeFuncs* npn = GetNetscapeFuncs(instance);
|
||||
if (!npn) {
|
||||
NS_ERROR("No netscape funcs?!");
|
||||
@ -1068,6 +1076,7 @@ PluginScriptableObjectParent::AnswerSetProperty(const PluginIdentifier& aId,
|
||||
return true;
|
||||
}
|
||||
|
||||
PushSurrogateAcceptCalls acceptCalls(instance);
|
||||
const NPNetscapeFuncs* npn = GetNetscapeFuncs(instance);
|
||||
if (!npn) {
|
||||
NS_ERROR("No netscape funcs?!");
|
||||
@ -1114,6 +1123,7 @@ PluginScriptableObjectParent::AnswerRemoveProperty(const PluginIdentifier& aId,
|
||||
return true;
|
||||
}
|
||||
|
||||
PushSurrogateAcceptCalls acceptCalls(instance);
|
||||
const NPNetscapeFuncs* npn = GetNetscapeFuncs(instance);
|
||||
if (!npn) {
|
||||
NS_ERROR("No netscape funcs?!");
|
||||
@ -1152,6 +1162,7 @@ PluginScriptableObjectParent::AnswerEnumerate(InfallibleTArray<PluginIdentifier>
|
||||
return true;
|
||||
}
|
||||
|
||||
PushSurrogateAcceptCalls acceptCalls(instance);
|
||||
const NPNetscapeFuncs* npn = GetNetscapeFuncs(instance);
|
||||
if (!npn) {
|
||||
NS_WARNING("No netscape funcs?!");
|
||||
@ -1204,6 +1215,7 @@ PluginScriptableObjectParent::AnswerConstruct(const InfallibleTArray<Variant>& a
|
||||
return true;
|
||||
}
|
||||
|
||||
PushSurrogateAcceptCalls acceptCalls(instance);
|
||||
const NPNetscapeFuncs* npn = GetNetscapeFuncs(instance);
|
||||
if (!npn) {
|
||||
NS_ERROR("No netscape funcs?!");
|
||||
@ -1296,6 +1308,7 @@ PluginScriptableObjectParent::AnswerNPN_Evaluate(const nsCString& aScript,
|
||||
return true;
|
||||
}
|
||||
|
||||
PushSurrogateAcceptCalls acceptCalls(instance);
|
||||
const NPNetscapeFuncs* npn = GetNetscapeFuncs(instance);
|
||||
if (!npn) {
|
||||
NS_ERROR("No netscape funcs?!");
|
||||
|
@ -16,6 +16,7 @@
|
||||
namespace mozilla {
|
||||
namespace plugins {
|
||||
|
||||
class PluginAsyncSurrogate;
|
||||
class PluginInstanceParent;
|
||||
class PluginScriptableObjectParent;
|
||||
|
||||
|
@ -21,7 +21,9 @@ EXPORTS.mozilla.plugins += [
|
||||
'NPEventOSX.h',
|
||||
'NPEventUnix.h',
|
||||
'NPEventWindows.h',
|
||||
'PluginAsyncSurrogate.h',
|
||||
'PluginBridge.h',
|
||||
'PluginDataResolver.h',
|
||||
'PluginInstanceChild.h',
|
||||
'PluginInstanceParent.h',
|
||||
'PluginMessageUtils.h',
|
||||
@ -80,6 +82,7 @@ UNIFIED_SOURCES += [
|
||||
'BrowserStreamParent.cpp',
|
||||
'ChildAsyncCall.cpp',
|
||||
'ChildTimer.cpp',
|
||||
'PluginAsyncSurrogate.cpp',
|
||||
'PluginBackgroundDestroyer.cpp',
|
||||
'PluginInstanceParent.cpp',
|
||||
'PluginMessageUtils.cpp',
|
||||
|
@ -178,9 +178,9 @@ LogMixedContentMessage(MixedContentTypes aClassification,
|
||||
severityFlag = nsIScriptError::warningFlag;
|
||||
messageCategory.AssignLiteral("Mixed Content Message");
|
||||
if (aClassification == eMixedDisplay) {
|
||||
messageLookupKey.AssignLiteral("LoadingMixedDisplayContent");
|
||||
messageLookupKey.AssignLiteral("LoadingMixedDisplayContent2");
|
||||
} else {
|
||||
messageLookupKey.AssignLiteral("LoadingMixedActiveContent");
|
||||
messageLookupKey.AssignLiteral("LoadingMixedActiveContent2");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -42,7 +42,9 @@ NS_IMPL_CYCLE_COLLECTION_INHERITED(IMETextTxn, EditTxn,
|
||||
// mRangeList can't lead to cycles
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IMETextTxn)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsITransaction, IMETextTxn)
|
||||
if (aIID.Equals(NS_GET_IID(IMETextTxn))) {
|
||||
foundInterface = static_cast<nsITransaction*>(this);
|
||||
} else
|
||||
NS_INTERFACE_MAP_END_INHERITING(EditTxn)
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(IMETextTxn, EditTxn)
|
||||
|
@ -38,7 +38,9 @@ NS_IMPL_CYCLE_COLLECTION_INHERITED(InsertTextTxn, EditTxn,
|
||||
NS_IMPL_ADDREF_INHERITED(InsertTextTxn, EditTxn)
|
||||
NS_IMPL_RELEASE_INHERITED(InsertTextTxn, EditTxn)
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(InsertTextTxn)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsITransaction, InsertTextTxn)
|
||||
if (aIID.Equals(NS_GET_IID(InsertTextTxn))) {
|
||||
foundInterface = static_cast<nsITransaction*>(this);
|
||||
} else
|
||||
NS_INTERFACE_MAP_END_INHERITING(EditTxn)
|
||||
|
||||
|
||||
|
@ -154,3 +154,4 @@ skip-if = e10s
|
||||
[test_spellcheck_pref.html]
|
||||
skip-if = toolkit == 'android'
|
||||
[test_bug1068979.html]
|
||||
[test_bug1109465.html]
|
||||
|
69
editor/libeditor/tests/test_bug1109465.html
Normal file
69
editor/libeditor/tests/test_bug1109465.html
Normal file
@ -0,0 +1,69 @@
|
||||
<!DOCTYPE>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1109465
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 1109465</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="display">
|
||||
<textarea></textarea>
|
||||
</div>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
|
||||
<script class="testbody" type="application/javascript">
|
||||
|
||||
/** Test for Bug 1109465 **/
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SimpleTest.waitForFocus(function() {
|
||||
var t = document.querySelector("textarea");
|
||||
t.focus();
|
||||
|
||||
// Type foo\nbar and place the caret at the end of the last line
|
||||
synthesizeKey("f", {});
|
||||
synthesizeKey("o", {});
|
||||
synthesizeKey("o", {});
|
||||
synthesizeKey("VK_RETURN", {});
|
||||
synthesizeKey("b", {});
|
||||
synthesizeKey("a", {});
|
||||
synthesizeKey("r", {});
|
||||
synthesizeKey("VK_UP", {});
|
||||
is(t.selectionStart, 3, "Correct start of selection");
|
||||
is(t.selectionEnd, 3, "Correct end of selection");
|
||||
|
||||
// Compose an IME string
|
||||
synthesizeComposition({ type: "compositionstart" });
|
||||
var composingString = "\u306B";
|
||||
synthesizeCompositionChange(
|
||||
{ "composition":
|
||||
{ "string": composingString,
|
||||
"clauses":
|
||||
[
|
||||
{ "length": 1, "attr": COMPOSITION_ATTR_RAWINPUT }
|
||||
]
|
||||
},
|
||||
"caret": { "start": 1, "length": 0 }
|
||||
});
|
||||
synthesizeComposition({ type: "compositioncommitasis" });
|
||||
is(t.value, "foo\u306B\nbar", "Correct value after composition");
|
||||
|
||||
// Now undo to test that the transaction merger has correctly detected the
|
||||
// IMETextTxn.
|
||||
synthesizeKey("Z", {accelKey: true});
|
||||
is(t.value, "foo\nbar", "Correct value after undo");
|
||||
|
||||
SimpleTest.finish();
|
||||
});
|
||||
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
@ -315,8 +315,6 @@ GeckoChildProcessHost::SyncLaunch(std::vector<std::string> aExtraOpts, int aTime
|
||||
{
|
||||
PrepareLaunch();
|
||||
|
||||
PRIntervalTime timeoutTicks = (aTimeoutMs > 0) ?
|
||||
PR_MillisecondsToInterval(aTimeoutMs) : PR_INTERVAL_NO_TIMEOUT;
|
||||
MessageLoop* ioLoop = XRE_GetIOMessageLoop();
|
||||
NS_ASSERTION(MessageLoop::current() != ioLoop, "sync launch from the IO thread NYI");
|
||||
|
||||
@ -324,8 +322,40 @@ GeckoChildProcessHost::SyncLaunch(std::vector<std::string> aExtraOpts, int aTime
|
||||
NewRunnableMethod(this,
|
||||
&GeckoChildProcessHost::RunPerformAsyncLaunch,
|
||||
aExtraOpts, arch));
|
||||
|
||||
return WaitUntilConnected(aTimeoutMs);
|
||||
}
|
||||
|
||||
bool
|
||||
GeckoChildProcessHost::AsyncLaunch(std::vector<std::string> aExtraOpts,
|
||||
base::ProcessArchitecture arch)
|
||||
{
|
||||
PrepareLaunch();
|
||||
|
||||
MessageLoop* ioLoop = XRE_GetIOMessageLoop();
|
||||
ioLoop->PostTask(FROM_HERE,
|
||||
NewRunnableMethod(this,
|
||||
&GeckoChildProcessHost::RunPerformAsyncLaunch,
|
||||
aExtraOpts, arch));
|
||||
|
||||
// This may look like the sync launch wait, but we only delay as
|
||||
// long as it takes to create the channel.
|
||||
MonitorAutoLock lock(mMonitor);
|
||||
while (mProcessState < CHANNEL_INITIALIZED) {
|
||||
lock.Wait();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
GeckoChildProcessHost::WaitUntilConnected(int32_t aTimeoutMs)
|
||||
{
|
||||
// NB: this uses a different mechanism than the chromium parent
|
||||
// class.
|
||||
PRIntervalTime timeoutTicks = (aTimeoutMs > 0) ?
|
||||
PR_MillisecondsToInterval(aTimeoutMs) : PR_INTERVAL_NO_TIMEOUT;
|
||||
|
||||
MonitorAutoLock lock(mMonitor);
|
||||
PRIntervalTime waitStart = PR_IntervalNow();
|
||||
PRIntervalTime current;
|
||||
@ -354,27 +384,6 @@ GeckoChildProcessHost::SyncLaunch(std::vector<std::string> aExtraOpts, int aTime
|
||||
return mProcessState == PROCESS_CONNECTED;
|
||||
}
|
||||
|
||||
bool
|
||||
GeckoChildProcessHost::AsyncLaunch(std::vector<std::string> aExtraOpts)
|
||||
{
|
||||
PrepareLaunch();
|
||||
|
||||
MessageLoop* ioLoop = XRE_GetIOMessageLoop();
|
||||
ioLoop->PostTask(FROM_HERE,
|
||||
NewRunnableMethod(this,
|
||||
&GeckoChildProcessHost::RunPerformAsyncLaunch,
|
||||
aExtraOpts, base::GetCurrentProcessArchitecture()));
|
||||
|
||||
// This may look like the sync launch wait, but we only delay as
|
||||
// long as it takes to create the channel.
|
||||
MonitorAutoLock lock(mMonitor);
|
||||
while (mProcessState < CHANNEL_INITIALIZED) {
|
||||
lock.Wait();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
GeckoChildProcessHost::LaunchAndWaitForProcessHandle(StringVector aExtraOpts)
|
||||
{
|
||||
|
@ -52,7 +52,10 @@ public:
|
||||
// Block until the IPC channel for our subprocess is initialized,
|
||||
// but no longer. The child process may or may not have been
|
||||
// created when this method returns.
|
||||
bool AsyncLaunch(StringVector aExtraOpts=StringVector());
|
||||
bool AsyncLaunch(StringVector aExtraOpts=StringVector(),
|
||||
base::ProcessArchitecture arch=base::GetCurrentProcessArchitecture());
|
||||
|
||||
virtual bool WaitUntilConnected(int32_t aTimeoutMs = 0);
|
||||
|
||||
// Block until the IPC channel for our subprocess is initialized and
|
||||
// the OS process is created. The subprocess may or may not have
|
||||
|
@ -298,6 +298,7 @@ MessageChannel::MessageChannel(MessageListener *aListener)
|
||||
mRecvdErrors(0),
|
||||
mRemoteStackDepthGuess(false),
|
||||
mSawInterruptOutMsg(false),
|
||||
mIsWaitingForIncoming(false),
|
||||
mAbortOnError(false),
|
||||
mBlockScripts(false),
|
||||
mFlags(REQUIRE_DEFAULT),
|
||||
@ -664,7 +665,8 @@ MessageChannel::OnMessageReceivedFromLink(const Message& aMsg)
|
||||
}
|
||||
|
||||
bool shouldWakeUp = AwaitingInterruptReply() ||
|
||||
(AwaitingSyncReply() && !ShouldDeferMessage(aMsg));
|
||||
(AwaitingSyncReply() && !ShouldDeferMessage(aMsg)) ||
|
||||
AwaitingIncomingMessage();
|
||||
|
||||
// There are three cases we're concerned about, relating to the state of the
|
||||
// main thread:
|
||||
@ -987,6 +989,35 @@ MessageChannel::Call(Message* aMsg, Message* aReply)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
MessageChannel::WaitForIncomingMessage()
|
||||
{
|
||||
#ifdef OS_WIN
|
||||
SyncStackFrame frame(this, true);
|
||||
#endif
|
||||
|
||||
{ // Scope for lock
|
||||
MonitorAutoLock lock(*mMonitor);
|
||||
AutoEnterWaitForIncoming waitingForIncoming(*this);
|
||||
if (mChannelState != ChannelConnected) {
|
||||
return false;
|
||||
}
|
||||
if (!HasPendingEvents()) {
|
||||
return WaitForInterruptNotify();
|
||||
}
|
||||
}
|
||||
|
||||
return OnMaybeDequeueOne();
|
||||
}
|
||||
|
||||
bool
|
||||
MessageChannel::HasPendingEvents()
|
||||
{
|
||||
AssertWorkerThread();
|
||||
mMonitor->AssertCurrentThreadOwns();
|
||||
return Connected() && !mPending.empty();
|
||||
}
|
||||
|
||||
bool
|
||||
MessageChannel::InterruptEventOccurred()
|
||||
{
|
||||
@ -1546,7 +1577,7 @@ MessageChannel::OnChannelErrorFromLink()
|
||||
if (InterruptStackDepth() > 0)
|
||||
NotifyWorkerThread();
|
||||
|
||||
if (AwaitingSyncReply())
|
||||
if (AwaitingSyncReply() || AwaitingIncomingMessage())
|
||||
NotifyWorkerThread();
|
||||
|
||||
if (ChannelClosing != mChannelState) {
|
||||
|
@ -124,6 +124,9 @@ class MessageChannel : HasResultCodes
|
||||
// Make an Interrupt call to the other side of the channel
|
||||
bool Call(Message* aMsg, Message* aReply);
|
||||
|
||||
// Wait until a message is received
|
||||
bool WaitForIncomingMessage();
|
||||
|
||||
bool CanSend() const;
|
||||
|
||||
void SetReplyTimeoutMs(int32_t aTimeoutMs);
|
||||
@ -214,6 +217,7 @@ class MessageChannel : HasResultCodes
|
||||
void DispatchOnChannelConnected();
|
||||
|
||||
bool InterruptEventOccurred();
|
||||
bool HasPendingEvents();
|
||||
|
||||
bool ProcessPendingRequest(const Message &aUrgent);
|
||||
|
||||
@ -319,6 +323,30 @@ class MessageChannel : HasResultCodes
|
||||
mMonitor->AssertCurrentThreadOwns();
|
||||
return !mInterruptStack.empty();
|
||||
}
|
||||
bool AwaitingIncomingMessage() const {
|
||||
mMonitor->AssertCurrentThreadOwns();
|
||||
return mIsWaitingForIncoming;
|
||||
}
|
||||
|
||||
class MOZ_STACK_CLASS AutoEnterWaitForIncoming
|
||||
{
|
||||
public:
|
||||
explicit AutoEnterWaitForIncoming(MessageChannel& aChannel)
|
||||
: mChannel(aChannel)
|
||||
{
|
||||
aChannel.mMonitor->AssertCurrentThreadOwns();
|
||||
aChannel.mIsWaitingForIncoming = true;
|
||||
}
|
||||
|
||||
~AutoEnterWaitForIncoming()
|
||||
{
|
||||
mChannel.mIsWaitingForIncoming = false;
|
||||
}
|
||||
|
||||
private:
|
||||
MessageChannel& mChannel;
|
||||
};
|
||||
friend class AutoEnterWaitForIncoming;
|
||||
|
||||
// Returns true if we're dispatching a sync message's callback.
|
||||
bool DispatchingSyncMessage() const {
|
||||
@ -639,6 +667,11 @@ class MessageChannel : HasResultCodes
|
||||
// ExitedCxxStack(), from which this variable is reset.
|
||||
bool mSawInterruptOutMsg;
|
||||
|
||||
// Are we waiting on this channel for an incoming message? This is used
|
||||
// to implement WaitForIncomingMessage(). Must only be accessed while owning
|
||||
// mMonitor.
|
||||
bool mIsWaitingForIncoming;
|
||||
|
||||
// Map of replies received "out of turn", because of Interrupt
|
||||
// in-calls racing with replies to outstanding in-calls. See
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=521929.
|
||||
|
@ -966,7 +966,7 @@ MessageChannel::WaitForInterruptNotify()
|
||||
return WaitForSyncNotify();
|
||||
}
|
||||
|
||||
if (!InterruptStackDepth()) {
|
||||
if (!InterruptStackDepth() && !AwaitingIncomingMessage()) {
|
||||
// There is currently no way to recover from this condition.
|
||||
NS_RUNTIMEABORT("StackDepth() is 0 in call to MessageChannel::WaitForNotify!");
|
||||
}
|
||||
|
@ -1673,7 +1673,7 @@ static bool
|
||||
EnableTraceLogger(JSContext *cx, unsigned argc, jsval *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
|
||||
TraceLoggerThread *logger = TraceLoggerForMainThread(cx->runtime());
|
||||
args.rval().setBoolean(TraceLoggerEnable(logger, cx));
|
||||
|
||||
return true;
|
||||
@ -1683,7 +1683,7 @@ static bool
|
||||
DisableTraceLogger(JSContext *cx, unsigned argc, jsval *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
|
||||
TraceLoggerThread *logger = TraceLoggerForMainThread(cx->runtime());
|
||||
args.rval().setBoolean(TraceLoggerDisable(logger));
|
||||
|
||||
return true;
|
||||
|
@ -163,6 +163,53 @@ function TypedArrayIndexOf(searchElement, fromIndex = 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// ES6 draft rev30 (2014/12/24) 22.2.3.14 %TypedArray%.prototype.join(separator).
|
||||
function TypedArrayJoin(separator) {
|
||||
// This function is not generic.
|
||||
if (!IsObject(this) || !IsTypedArray(this)) {
|
||||
return callFunction(CallTypedArrayMethodIfWrapped, this, separator, "TypedArrayJoin");
|
||||
}
|
||||
|
||||
// Steps 1-2.
|
||||
var O = this;
|
||||
|
||||
// Steps 3-5.
|
||||
var len = TypedArrayLength(O);
|
||||
|
||||
// Steps 6-7.
|
||||
var sep = separator === undefined ? "," : ToString(separator);
|
||||
|
||||
// Step 8.
|
||||
if (len === 0)
|
||||
return "";
|
||||
|
||||
// Step 9.
|
||||
var element0 = O[0];
|
||||
|
||||
// Steps 10-11.
|
||||
// Omit the 'if' clause in step 10, since typed arrays can not have undefined or null elements.
|
||||
var R = ToString(element0);
|
||||
|
||||
// Steps 12-13.
|
||||
for (var k = 1; k < len; k++) {
|
||||
// Step 13.a.
|
||||
var S = R + sep;
|
||||
|
||||
// Step 13.b.
|
||||
var element = O[k];
|
||||
|
||||
// Steps 13.c-13.d.
|
||||
// Omit the 'if' clause in step 13.c, since typed arrays can not have undefined or null elements.
|
||||
var next = ToString(element);
|
||||
|
||||
// Step 13.e.
|
||||
R = S + next;
|
||||
}
|
||||
|
||||
// Step 14.
|
||||
return R;
|
||||
}
|
||||
|
||||
// ES6 draft rev29 (2014/12/06) 22.2.3.16 %TypedArray%.prototype.lastIndexOf(searchElement [,fromIndex]).
|
||||
function TypedArrayLastIndexOf(searchElement, fromIndex = undefined) {
|
||||
// This function is not generic.
|
||||
|
@ -2985,16 +2985,16 @@ AC_SUBST(MOZ_OPTIMIZE_SIZE_TWEAK)
|
||||
AC_SUBST(MOZ_PGO_OPTIMIZE_FLAGS)
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Enable trace logging
|
||||
dnl = Disable trace logging
|
||||
dnl ========================================================
|
||||
MOZ_ARG_ENABLE_BOOL(trace-logging,
|
||||
[ --enable-trace-logging Enable trace logging],
|
||||
ENABLE_TRACE_LOGGING=1,
|
||||
ENABLE_TRACE_LOGGING=1
|
||||
MOZ_ARG_DISABLE_BOOL(trace-logging,
|
||||
[ --disable-trace-logging Disable trace logging],
|
||||
ENABLE_TRACE_LOGGING= )
|
||||
|
||||
AC_SUBST(ENABLE_TRACE_LOGGING)
|
||||
|
||||
if test "$ENABLE_TRACE_LOGGING"; then
|
||||
if test -n "$ENABLE_TRACE_LOGGING"; then
|
||||
AC_DEFINE(JS_TRACE_LOGGING)
|
||||
fi
|
||||
|
||||
|
@ -220,14 +220,14 @@ frontend::CompileScript(ExclusiveContext *cx, LifoAlloc *alloc, HandleObject sco
|
||||
|
||||
RootedString source(cx, source_);
|
||||
|
||||
js::TraceLogger *logger = nullptr;
|
||||
js::TraceLoggerThread *logger = nullptr;
|
||||
if (cx->isJSContext())
|
||||
logger = TraceLoggerForMainThread(cx->asJSContext()->runtime());
|
||||
else
|
||||
logger = TraceLoggerForCurrentThread();
|
||||
uint32_t logId = js::TraceLogCreateTextId(logger, options);
|
||||
js::AutoTraceLog scriptLogger(logger, logId);
|
||||
js::AutoTraceLog typeLogger(logger, TraceLogger::ParserCompileScript);
|
||||
js::TraceLoggerEvent event(logger, TraceLogger_AnnotateScripts, options);
|
||||
js::AutoTraceLog scriptLogger(logger, event);
|
||||
js::AutoTraceLog typeLogger(logger, TraceLogger_ParserCompileScript);
|
||||
|
||||
/*
|
||||
* The scripted callerFrame can only be given for compile-and-go scripts
|
||||
@ -473,10 +473,10 @@ frontend::CompileLazyFunction(JSContext *cx, Handle<LazyScript*> lazy, const cha
|
||||
.setNoScriptRval(false)
|
||||
.setSelfHostingMode(false);
|
||||
|
||||
js::TraceLogger *logger = js::TraceLoggerForMainThread(cx->runtime());
|
||||
uint32_t logId = js::TraceLogCreateTextId(logger, options);
|
||||
js::AutoTraceLog scriptLogger(logger, logId);
|
||||
js::AutoTraceLog typeLogger(logger, TraceLogger::ParserCompileLazy);
|
||||
js::TraceLoggerThread *logger = js::TraceLoggerForMainThread(cx->runtime());
|
||||
js::TraceLoggerEvent event(logger, TraceLogger_AnnotateScripts, options);
|
||||
js::AutoTraceLog scriptLogger(logger, event);
|
||||
js::AutoTraceLog typeLogger(logger, TraceLogger_ParserCompileLazy);
|
||||
|
||||
Parser<FullParseHandler> parser(cx, &cx->tempLifoAlloc(), options, chars, length,
|
||||
/* foldConstants = */ true, nullptr, lazy);
|
||||
@ -531,10 +531,10 @@ CompileFunctionBody(JSContext *cx, MutableHandleFunction fun, const ReadOnlyComp
|
||||
const AutoNameVector &formals, SourceBufferHolder &srcBuf,
|
||||
HandleObject enclosingScope, GeneratorKind generatorKind)
|
||||
{
|
||||
js::TraceLogger *logger = js::TraceLoggerForMainThread(cx->runtime());
|
||||
uint32_t logId = js::TraceLogCreateTextId(logger, options);
|
||||
js::AutoTraceLog scriptLogger(logger, logId);
|
||||
js::AutoTraceLog typeLogger(logger, TraceLogger::ParserCompileFunction);
|
||||
js::TraceLoggerThread *logger = js::TraceLoggerForMainThread(cx->runtime());
|
||||
js::TraceLoggerEvent event(logger, TraceLogger_AnnotateScripts, options);
|
||||
js::AutoTraceLog scriptLogger(logger, event);
|
||||
js::AutoTraceLog typeLogger(logger, TraceLogger_ParserCompileFunction);
|
||||
|
||||
// FIXME: make Function pass in two strings and parse them as arguments and
|
||||
// ProgramElements respectively.
|
||||
|
88
js/src/jit-test/tests/tracelogger/drainTraceLogger.js
Normal file
88
js/src/jit-test/tests/tracelogger/drainTraceLogger.js
Normal file
@ -0,0 +1,88 @@
|
||||
function TestDrainTraceLoggerInvariants(obj) {
|
||||
var scripts = 0;
|
||||
var stops = 0;
|
||||
for (var i = 0; i < objs.length; i++) {
|
||||
if (objs[i].logType == "Scripts") {
|
||||
scripts++;
|
||||
assertEq("fileName" in objs[i], true);
|
||||
assertEq("lineNumber" in objs[i], true);
|
||||
assertEq("columnNumber" in objs[i], true);
|
||||
} else if (objs[i].logType == "Stop") {
|
||||
stops++;
|
||||
} else {
|
||||
assertEq(true, false);
|
||||
}
|
||||
}
|
||||
assertEq(scripts, stops);
|
||||
}
|
||||
|
||||
function GetMaxScriptDepth(obj) {
|
||||
var max_depth = 0;
|
||||
for (var i = 0; i < objs.length; i++) {
|
||||
if (objs[i].logType == "Stop")
|
||||
depth--;
|
||||
else {
|
||||
depth++;
|
||||
if (depth > max_depth)
|
||||
max_depth = depth;
|
||||
}
|
||||
}
|
||||
return max_depth;
|
||||
}
|
||||
|
||||
function foo1() {
|
||||
foo2();
|
||||
}
|
||||
function foo2() {
|
||||
|
||||
}
|
||||
|
||||
var du = new Debugger();
|
||||
if (typeof du.drainTraceLoggerTraces == "function") {
|
||||
print(1);
|
||||
// Test normal setup.
|
||||
du = new Debugger();
|
||||
du.setupTraceLoggerForTraces();
|
||||
|
||||
du.startTraceLogger();
|
||||
du.endTraceLogger();
|
||||
|
||||
var objs = du.drainTraceLoggerTraces();
|
||||
TestDrainTraceLoggerInvariants(objs);
|
||||
var empty_depth = GetMaxScriptDepth(objs);
|
||||
var empty_length = objs.length;
|
||||
|
||||
// Test basic script.
|
||||
for (var i=0; i<20; i++)
|
||||
foo1();
|
||||
|
||||
du = new Debugger();
|
||||
du.setupTraceLoggerTraces();
|
||||
|
||||
du.startTraceLogger();
|
||||
foo1();
|
||||
du.endTraceLogger();
|
||||
|
||||
var objs = du.drainTraceLoggerTraces();
|
||||
TestDrainTraceLoggerInvariants(objs);
|
||||
assertEq(empty_depth + 2 == GetMaxScriptDepth(objs));
|
||||
assertEq(empty_length + 4 == GetMaxScriptDepth(objs));
|
||||
|
||||
// Test basic script.
|
||||
for (var i=0; i<20; i++)
|
||||
foo1();
|
||||
|
||||
du = new Debugger();
|
||||
du.setupTraceLoggerForTraces();
|
||||
|
||||
du.startTraceLogger();
|
||||
for (var i=0; i<100; i++) {
|
||||
foo1();
|
||||
}
|
||||
du.endTraceLogger();
|
||||
|
||||
var objs = du.drainTraceLoggerTraces();
|
||||
TestDrainTraceLoggerInvariants(objs);
|
||||
assertEq(empty_depth + 2 == GetMaxScriptDepth(objs));
|
||||
assertEq(empty_length + 4*100 == GetMaxScriptDepth(objs));
|
||||
}
|
70
js/src/jit-test/tests/tracelogger/setupTraceLogger.js
Normal file
70
js/src/jit-test/tests/tracelogger/setupTraceLogger.js
Normal file
@ -0,0 +1,70 @@
|
||||
|
||||
var du = new Debugger();
|
||||
if (typeof du.setupTraceLogger == "function") {
|
||||
|
||||
// Try enabling.
|
||||
assertEq(du.setupTraceLogger({
|
||||
Scripts: true
|
||||
}), true);
|
||||
|
||||
// No fail on re-enabling.
|
||||
assertEq(du.setupTraceLogger({
|
||||
Scripts: true
|
||||
}), true);
|
||||
|
||||
// Try disabling.
|
||||
assertEq(du.setupTraceLogger({
|
||||
Scripts: false
|
||||
}), true);
|
||||
|
||||
// No fail on re-disabling.
|
||||
assertEq(du.setupTraceLogger({
|
||||
Scripts: false
|
||||
}), true);
|
||||
|
||||
// Throw exception if TraceLog item to report isn't found.
|
||||
var success = du.setupTraceLogger({
|
||||
Scripts: false,
|
||||
Test: true
|
||||
});
|
||||
assertEq(success, false);
|
||||
|
||||
// SetupTraceLogger only enables individual items,
|
||||
// when all items can be toggled.
|
||||
du.startTraceLogger();
|
||||
var obj = du.drainTraceLogger();
|
||||
du.setupTraceLogger({
|
||||
Scripts: true,
|
||||
Test: true,
|
||||
});
|
||||
assertEq(du.drainTraceLogger().length, 0);
|
||||
du.endTraceLogger();
|
||||
|
||||
// Expects an object as first argument.
|
||||
succes = du.setupTraceLogger("blaat");
|
||||
assertEq(succes, false);
|
||||
|
||||
// Expects an object as first argument.
|
||||
succes = du.setupTraceLogger("blaat");
|
||||
assertEq(succes, false);
|
||||
|
||||
// Expects an object as first argument.
|
||||
failed = false;
|
||||
try {
|
||||
du.setupTraceLogger();
|
||||
} catch (e) {
|
||||
failed = true;
|
||||
}
|
||||
assertEq(failed, true);
|
||||
|
||||
// No problem with added to many arguments.
|
||||
succes = du.setupTraceLogger({}, "test");
|
||||
assertEq(succes, true);
|
||||
}
|
||||
|
||||
var du2 = new Debugger();
|
||||
if (typeof du2.setupTraceLoggerForTraces == "function") {
|
||||
du2.setupTraceLoggerForTraces({});
|
||||
du2.setupTraceLoggerForTraces("test");
|
||||
du2.setupTraceLoggerForTraces({}, "test");
|
||||
}
|
@ -41,8 +41,8 @@ jit::Bailout(BailoutStack *sp, BaselineBailoutInfo **bailoutInfo)
|
||||
JitFrameIterator iter(jitActivations);
|
||||
MOZ_ASSERT(!iter.ionScript()->invalidated());
|
||||
|
||||
TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
|
||||
TraceLogTimestamp(logger, TraceLogger::Bailout);
|
||||
TraceLoggerThread *logger = TraceLoggerForMainThread(cx->runtime());
|
||||
TraceLogTimestamp(logger, TraceLogger_Bailout);
|
||||
|
||||
JitSpew(JitSpew_IonBailouts, "Took bailout! Snapshot offset: %d", iter.snapshotOffset());
|
||||
|
||||
@ -107,8 +107,8 @@ jit::InvalidationBailout(InvalidationBailoutStack *sp, size_t *frameSizeOut,
|
||||
BailoutFrameInfo bailoutData(jitActivations, sp);
|
||||
JitFrameIterator iter(jitActivations);
|
||||
|
||||
TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
|
||||
TraceLogTimestamp(logger, TraceLogger::Invalidation);
|
||||
TraceLoggerThread *logger = TraceLoggerForMainThread(cx->runtime());
|
||||
TraceLogTimestamp(logger, TraceLogger_Invalidation);
|
||||
|
||||
JitSpew(JitSpew_IonBailouts, "Took invalidation bailout! Snapshot offset: %d", iter.snapshotOffset());
|
||||
|
||||
|
@ -1381,9 +1381,9 @@ jit::BailoutIonToBaseline(JSContext *cx, JitActivation *activation, JitFrameIter
|
||||
MOZ_ASSERT(poppedLastSPSFrameOut);
|
||||
MOZ_ASSERT(!*poppedLastSPSFrameOut);
|
||||
|
||||
TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
|
||||
TraceLogStopEvent(logger, TraceLogger::IonMonkey);
|
||||
TraceLogStartEvent(logger, TraceLogger::Baseline);
|
||||
TraceLoggerThread *logger = TraceLoggerForMainThread(cx->runtime());
|
||||
TraceLogStopEvent(logger, TraceLogger_IonMonkey);
|
||||
TraceLogStartEvent(logger, TraceLogger_Baseline);
|
||||
|
||||
// The caller of the top frame must be one of the following:
|
||||
// IonJS - Ion calling into Ion.
|
||||
@ -1494,8 +1494,12 @@ jit::BailoutIonToBaseline(JSContext *cx, JitActivation *activation, JitFrameIter
|
||||
snapIter.settleOnFrame();
|
||||
|
||||
if (frameNo > 0) {
|
||||
TraceLogStartEvent(logger, TraceLogCreateTextId(logger, scr));
|
||||
TraceLogStartEvent(logger, TraceLogger::Baseline);
|
||||
// TraceLogger doesn't create entries for inlined frames. But we
|
||||
// see them in Baseline. Here we create the start events of those
|
||||
// entries. So they correspond to what we will see in Baseline.
|
||||
TraceLoggerEvent scriptEvent(logger, TraceLogger_Scripts, scr);
|
||||
TraceLogStartEvent(logger, scriptEvent);
|
||||
TraceLogStartEvent(logger, TraceLogger_Baseline);
|
||||
}
|
||||
|
||||
JitSpew(JitSpew_BaselineBailouts, " FrameNo %d", frameNo);
|
||||
|
@ -81,9 +81,10 @@ BaselineCompiler::compile()
|
||||
JitSpew(JitSpew_Codegen, "# Emitting baseline code for script %s:%d",
|
||||
script->filename(), script->lineno());
|
||||
|
||||
TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
|
||||
AutoTraceLog logScript(logger, TraceLogCreateTextId(logger, script));
|
||||
AutoTraceLog logCompile(logger, TraceLogger::BaselineCompilation);
|
||||
TraceLoggerThread *logger = TraceLoggerForMainThread(cx->runtime());
|
||||
TraceLoggerEvent scriptEvent(logger, TraceLogger_AnnotateScripts, script);
|
||||
AutoTraceLog logScript(logger, scriptEvent);
|
||||
AutoTraceLog logCompile(logger, TraceLogger_BaselineCompilation);
|
||||
|
||||
if (!script->ensureHasTypes(cx) || !script->ensureHasAnalyzedArgsUsage(cx))
|
||||
return Method_Error;
|
||||
@ -175,6 +176,10 @@ BaselineCompiler::compile()
|
||||
prologueOffset_.fixup(&masm);
|
||||
epilogueOffset_.fixup(&masm);
|
||||
spsPushToggleOffset_.fixup(&masm);
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
traceLoggerEnterToggleOffset_.fixup(&masm);
|
||||
traceLoggerExitToggleOffset_.fixup(&masm);
|
||||
#endif
|
||||
postDebugPrologueOffset_.fixup(&masm);
|
||||
|
||||
// Note: There is an extra entry in the bytecode type map for the search hint, see below.
|
||||
@ -184,6 +189,8 @@ BaselineCompiler::compile()
|
||||
BaselineScript::New(script, prologueOffset_.offset(),
|
||||
epilogueOffset_.offset(),
|
||||
spsPushToggleOffset_.offset(),
|
||||
traceLoggerEnterToggleOffset_.offset(),
|
||||
traceLoggerExitToggleOffset_.offset(),
|
||||
postDebugPrologueOffset_.offset(),
|
||||
icEntries_.length(),
|
||||
pcMappingIndexEntries.length(),
|
||||
@ -239,6 +246,11 @@ BaselineCompiler::compile()
|
||||
if (cx->runtime()->spsProfiler.enabled())
|
||||
baselineScript->toggleSPS(true);
|
||||
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
// Initialize the tracelogger instrumentation.
|
||||
baselineScript->initTraceLogger(cx->runtime(), script);
|
||||
#endif
|
||||
|
||||
uint32_t *bytecodeMap = baselineScript->bytecodeTypeMap();
|
||||
types::FillBytecodeTypeMap(script, bytecodeMap);
|
||||
|
||||
@ -375,13 +387,8 @@ BaselineCompiler::emitPrologue()
|
||||
masm.bind(&earlyStackCheckFailed);
|
||||
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
|
||||
Register loggerReg = RegisterSet::Volatile().takeGeneral();
|
||||
masm.Push(loggerReg);
|
||||
masm.movePtr(ImmPtr(logger), loggerReg);
|
||||
masm.tracelogStart(loggerReg, TraceLogCreateTextId(logger, script));
|
||||
masm.tracelogStart(loggerReg, TraceLogger::Baseline);
|
||||
masm.Pop(loggerReg);
|
||||
if (!emitTraceLoggerEnter())
|
||||
return false;
|
||||
#endif
|
||||
|
||||
// Record the offset of the prologue, because Ion can bailout before
|
||||
@ -425,15 +432,8 @@ BaselineCompiler::emitEpilogue()
|
||||
masm.bind(&return_);
|
||||
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
|
||||
Register loggerReg = RegisterSet::Volatile().takeGeneral();
|
||||
masm.Push(loggerReg);
|
||||
masm.movePtr(ImmPtr(logger), loggerReg);
|
||||
masm.tracelogStop(loggerReg, TraceLogger::Baseline);
|
||||
// Stop the script. Using a stop without checking the textId, since we
|
||||
// we didn't save the textId for the script.
|
||||
masm.tracelogStop(loggerReg);
|
||||
masm.Pop(loggerReg);
|
||||
if (!emitTraceLoggerExit())
|
||||
return false;
|
||||
#endif
|
||||
|
||||
// Pop SPS frame if necessary
|
||||
@ -773,6 +773,64 @@ BaselineCompiler::emitDebugTrap()
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
bool
|
||||
BaselineCompiler::emitTraceLoggerEnter()
|
||||
{
|
||||
TraceLoggerThread *logger = TraceLoggerForMainThread(cx->runtime());
|
||||
RegisterSet regs = RegisterSet::Volatile();
|
||||
Register loggerReg = regs.takeGeneral();
|
||||
Register scriptReg = regs.takeGeneral();
|
||||
|
||||
Label noTraceLogger;
|
||||
traceLoggerEnterToggleOffset_ = masm.toggledJump(&noTraceLogger);
|
||||
|
||||
masm.Push(loggerReg);
|
||||
masm.Push(scriptReg);
|
||||
|
||||
masm.movePtr(ImmPtr(logger), loggerReg);
|
||||
|
||||
// Script start.
|
||||
masm.movePtr(ImmGCPtr(script), scriptReg);
|
||||
masm.loadPtr(Address(scriptReg, JSScript::offsetOfBaselineScript()), scriptReg);
|
||||
Address scriptEvent(scriptReg, BaselineScript::offsetOfTraceLoggerScriptEvent());
|
||||
masm.computeEffectiveAddress(scriptEvent, scriptReg);
|
||||
masm.tracelogStartEvent(loggerReg, scriptReg);
|
||||
|
||||
// Engine start.
|
||||
masm.tracelogStartId(loggerReg, TraceLogger_Baseline, /* force = */ true);
|
||||
|
||||
masm.Pop(scriptReg);
|
||||
masm.Pop(loggerReg);
|
||||
|
||||
masm.bind(&noTraceLogger);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BaselineCompiler::emitTraceLoggerExit()
|
||||
{
|
||||
TraceLoggerThread *logger = TraceLoggerForMainThread(cx->runtime());
|
||||
Register loggerReg = RegisterSet::Volatile().takeGeneral();
|
||||
|
||||
Label noTraceLogger;
|
||||
traceLoggerExitToggleOffset_ = masm.toggledJump(&noTraceLogger);
|
||||
|
||||
masm.Push(loggerReg);
|
||||
masm.movePtr(ImmPtr(logger), loggerReg);
|
||||
|
||||
masm.tracelogStopId(loggerReg, TraceLogger_Baseline, /* force = */ true);
|
||||
masm.tracelogStopId(loggerReg, TraceLogger_Scripts, /* force = */ true);
|
||||
|
||||
masm.Pop(loggerReg);
|
||||
|
||||
masm.bind(&noTraceLogger);
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool
|
||||
BaselineCompiler::emitSPSPush()
|
||||
{
|
||||
|
@ -254,6 +254,8 @@ class BaselineCompiler : public BaselineCompilerSpecific
|
||||
bool emitArgumentTypeChecks();
|
||||
bool emitDebugPrologue();
|
||||
bool emitDebugTrap();
|
||||
bool emitTraceLoggerEnter();
|
||||
bool emitTraceLoggerExit();
|
||||
bool emitSPSPush();
|
||||
void emitSPSPop();
|
||||
|
||||
|
@ -42,7 +42,9 @@ PCMappingSlotInfo::ToSlotLocation(const StackValue *stackVal)
|
||||
}
|
||||
|
||||
BaselineScript::BaselineScript(uint32_t prologueOffset, uint32_t epilogueOffset,
|
||||
uint32_t spsPushToggleOffset, uint32_t postDebugPrologueOffset)
|
||||
uint32_t spsPushToggleOffset, uint32_t traceLoggerEnterToggleOffset,
|
||||
uint32_t traceLoggerExitToggleOffset,
|
||||
uint32_t postDebugPrologueOffset)
|
||||
: method_(nullptr),
|
||||
templateScope_(nullptr),
|
||||
fallbackStubSpace_(),
|
||||
@ -53,6 +55,15 @@ BaselineScript::BaselineScript(uint32_t prologueOffset, uint32_t epilogueOffset,
|
||||
spsOn_(false),
|
||||
#endif
|
||||
spsPushToggleOffset_(spsPushToggleOffset),
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
# ifdef DEBUG
|
||||
traceLoggerScriptsEnabled_(false),
|
||||
traceLoggerEngineEnabled_(false),
|
||||
# endif
|
||||
traceLoggerEnterToggleOffset_(traceLoggerEnterToggleOffset),
|
||||
traceLoggerExitToggleOffset_(traceLoggerExitToggleOffset),
|
||||
traceLoggerScriptEvent_(),
|
||||
#endif
|
||||
postDebugPrologueOffset_(postDebugPrologueOffset),
|
||||
flags_(0)
|
||||
{ }
|
||||
@ -192,9 +203,9 @@ jit::EnterBaselineAtBranch(JSContext *cx, InterpreterFrame *fp, jsbytecode *pc)
|
||||
data.calleeToken = CalleeToToken(fp->script());
|
||||
}
|
||||
|
||||
TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
|
||||
TraceLogStopEvent(logger, TraceLogger::Interpreter);
|
||||
TraceLogStartEvent(logger, TraceLogger::Baseline);
|
||||
TraceLoggerThread *logger = TraceLoggerForMainThread(cx->runtime());
|
||||
TraceLogStopEvent(logger, TraceLogger_Interpreter);
|
||||
TraceLogStartEvent(logger, TraceLogger_Baseline);
|
||||
|
||||
JitExecStatus status = EnterBaseline(cx, data);
|
||||
if (status != JitExec_Ok)
|
||||
@ -341,7 +352,8 @@ jit::CanEnterBaselineMethod(JSContext *cx, RunState &state)
|
||||
|
||||
BaselineScript *
|
||||
BaselineScript::New(JSScript *jsscript, uint32_t prologueOffset, uint32_t epilogueOffset,
|
||||
uint32_t spsPushToggleOffset, uint32_t postDebugPrologueOffset,
|
||||
uint32_t spsPushToggleOffset, uint32_t traceLoggerEnterToggleOffset,
|
||||
uint32_t traceLoggerExitToggleOffset, uint32_t postDebugPrologueOffset,
|
||||
size_t icEntries, size_t pcMappingIndexEntries, size_t pcMappingSize,
|
||||
size_t bytecodeTypeMapEntries, size_t yieldEntries)
|
||||
{
|
||||
@ -368,7 +380,8 @@ BaselineScript::New(JSScript *jsscript, uint32_t prologueOffset, uint32_t epilog
|
||||
if (!script)
|
||||
return nullptr;
|
||||
new (script) BaselineScript(prologueOffset, epilogueOffset,
|
||||
spsPushToggleOffset, postDebugPrologueOffset);
|
||||
spsPushToggleOffset, traceLoggerEnterToggleOffset,
|
||||
traceLoggerExitToggleOffset, postDebugPrologueOffset);
|
||||
|
||||
size_t offsetCursor = sizeof(BaselineScript);
|
||||
MOZ_ASSERT(offsetCursor == AlignBytes(sizeof(BaselineScript), DataAlignment));
|
||||
@ -895,6 +908,90 @@ BaselineScript::toggleSPS(bool enable)
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
void
|
||||
BaselineScript::initTraceLogger(JSRuntime *runtime, JSScript *script)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
traceLoggerScriptsEnabled_ = TraceLogTextIdEnabled(TraceLogger_Scripts);
|
||||
traceLoggerEngineEnabled_ = TraceLogTextIdEnabled(TraceLogger_Engine);
|
||||
#endif
|
||||
|
||||
TraceLoggerThread *logger = TraceLoggerForMainThread(runtime);
|
||||
if (TraceLogTextIdEnabled(TraceLogger_Scripts))
|
||||
traceLoggerScriptEvent_ = TraceLoggerEvent(logger, TraceLogger_Scripts, script);
|
||||
else
|
||||
traceLoggerScriptEvent_ = TraceLoggerEvent(logger, TraceLogger_Scripts);
|
||||
|
||||
if (TraceLogTextIdEnabled(TraceLogger_Engine) || TraceLogTextIdEnabled(TraceLogger_Scripts)) {
|
||||
CodeLocationLabel enter(method_, CodeOffsetLabel(traceLoggerEnterToggleOffset_));
|
||||
CodeLocationLabel exit(method_, CodeOffsetLabel(traceLoggerExitToggleOffset_));
|
||||
Assembler::ToggleToCmp(enter);
|
||||
Assembler::ToggleToCmp(exit);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
BaselineScript::toggleTraceLoggerScripts(JSRuntime *runtime, JSScript *script, bool enable)
|
||||
{
|
||||
bool engineEnabled = TraceLogTextIdEnabled(TraceLogger_Engine);
|
||||
|
||||
MOZ_ASSERT(enable == !traceLoggerScriptsEnabled_);
|
||||
MOZ_ASSERT(engineEnabled == traceLoggerEngineEnabled_);
|
||||
|
||||
// Patch the logging script textId to be correct.
|
||||
// When logging log the specific textId else the global Scripts textId.
|
||||
TraceLoggerThread *logger = TraceLoggerForMainThread(runtime);
|
||||
if (enable)
|
||||
traceLoggerScriptEvent_ = TraceLoggerEvent(logger, TraceLogger_Scripts, script);
|
||||
else
|
||||
traceLoggerScriptEvent_ = TraceLoggerEvent(logger, TraceLogger_Scripts);
|
||||
|
||||
// Enable/Disable the traceLogger prologue and epilogue.
|
||||
CodeLocationLabel enter(method_, CodeOffsetLabel(traceLoggerEnterToggleOffset_));
|
||||
CodeLocationLabel exit(method_, CodeOffsetLabel(traceLoggerExitToggleOffset_));
|
||||
if (!engineEnabled) {
|
||||
if (enable) {
|
||||
Assembler::ToggleToCmp(enter);
|
||||
Assembler::ToggleToCmp(exit);
|
||||
} else {
|
||||
Assembler::ToggleToJmp(enter);
|
||||
Assembler::ToggleToJmp(exit);
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
traceLoggerScriptsEnabled_ = enable;
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
BaselineScript::toggleTraceLoggerEngine(bool enable)
|
||||
{
|
||||
bool scriptsEnabled = TraceLogTextIdEnabled(TraceLogger_Scripts);
|
||||
|
||||
MOZ_ASSERT(enable == !traceLoggerEngineEnabled_);
|
||||
MOZ_ASSERT(scriptsEnabled == traceLoggerScriptsEnabled_);
|
||||
|
||||
// Enable/Disable the traceLogger prologue and epilogue.
|
||||
CodeLocationLabel enter(method_, CodeOffsetLabel(traceLoggerEnterToggleOffset_));
|
||||
CodeLocationLabel exit(method_, CodeOffsetLabel(traceLoggerExitToggleOffset_));
|
||||
if (!scriptsEnabled) {
|
||||
if (enable) {
|
||||
Assembler::ToggleToCmp(enter);
|
||||
Assembler::ToggleToCmp(exit);
|
||||
} else {
|
||||
Assembler::ToggleToJmp(enter);
|
||||
Assembler::ToggleToJmp(exit);
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
traceLoggerEngineEnabled_ = enable;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
BaselineScript::purgeOptimizedStubs(Zone *zone)
|
||||
{
|
||||
@ -1002,6 +1099,34 @@ jit::ToggleBaselineSPS(JSRuntime *runtime, bool enable)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
void
|
||||
jit::ToggleBaselineTraceLoggerScripts(JSRuntime *runtime, bool enable)
|
||||
{
|
||||
for (ZonesIter zone(runtime, SkipAtoms); !zone.done(); zone.next()) {
|
||||
for (gc::ZoneCellIter i(zone, gc::FINALIZE_SCRIPT); !i.done(); i.next()) {
|
||||
JSScript *script = i.get<JSScript>();
|
||||
if (!script->hasBaselineScript())
|
||||
continue;
|
||||
script->baselineScript()->toggleTraceLoggerScripts(runtime, script, enable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
jit::ToggleBaselineTraceLoggerEngine(JSRuntime *runtime, bool enable)
|
||||
{
|
||||
for (ZonesIter zone(runtime, SkipAtoms); !zone.done(); zone.next()) {
|
||||
for (gc::ZoneCellIter i(zone, gc::FINALIZE_SCRIPT); !i.done(); i.next()) {
|
||||
JSScript *script = i.get<JSScript>();
|
||||
if (!script->hasBaselineScript())
|
||||
continue;
|
||||
script->baselineScript()->toggleTraceLoggerEngine(enable);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
MarkActiveBaselineScripts(JSRuntime *rt, const JitActivationIterator &activation)
|
||||
{
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "jit/Bailouts.h"
|
||||
#include "jit/IonCode.h"
|
||||
#include "jit/MacroAssembler.h"
|
||||
#include "vm/TraceLogging.h"
|
||||
|
||||
namespace js {
|
||||
namespace jit {
|
||||
@ -144,6 +145,17 @@ struct BaselineScript
|
||||
#endif
|
||||
uint32_t spsPushToggleOffset_;
|
||||
|
||||
// The offsets and event used for Tracelogger toggling.
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
# ifdef DEBUG
|
||||
bool traceLoggerScriptsEnabled_;
|
||||
bool traceLoggerEngineEnabled_;
|
||||
# endif
|
||||
uint32_t traceLoggerEnterToggleOffset_;
|
||||
uint32_t traceLoggerExitToggleOffset_;
|
||||
TraceLoggerEvent traceLoggerScriptEvent_;
|
||||
#endif
|
||||
|
||||
// Native code offsets right after the debug prologue VM call returns, or
|
||||
// would have returned. This offset is recorded even when debug mode is
|
||||
// off to aid on-stack debug mode recompilation.
|
||||
@ -202,11 +214,13 @@ struct BaselineScript
|
||||
public:
|
||||
// Do not call directly, use BaselineScript::New. This is public for cx->new_.
|
||||
BaselineScript(uint32_t prologueOffset, uint32_t epilogueOffset,
|
||||
uint32_t spsPushToggleOffset, uint32_t postDebugPrologueOffset);
|
||||
uint32_t spsPushToggleOffset, uint32_t traceLoggerEnterToggleOffset,
|
||||
uint32_t traceLoggerExitToggleOffset, uint32_t postDebugPrologueOffset);
|
||||
|
||||
static BaselineScript *New(JSScript *jsscript, uint32_t prologueOffset,
|
||||
uint32_t epilogueOffset, uint32_t postDebugPrologueOffset,
|
||||
uint32_t spsPushToggleOffset, size_t icEntries,
|
||||
uint32_t spsPushToggleOffset, uint32_t traceLoggerEnterToggleOffset,
|
||||
uint32_t traceLoggerExitToggleOffset, size_t icEntries,
|
||||
size_t pcMappingIndexEntries, size_t pcMappingSize,
|
||||
size_t bytecodeTypeMapEntries, size_t yieldEntries);
|
||||
|
||||
@ -386,6 +400,16 @@ struct BaselineScript
|
||||
|
||||
void toggleSPS(bool enable);
|
||||
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
void initTraceLogger(JSRuntime *runtime, JSScript *script);
|
||||
void toggleTraceLoggerScripts(JSRuntime *runtime, JSScript *script, bool enable);
|
||||
void toggleTraceLoggerEngine(bool enable);
|
||||
|
||||
static size_t offsetOfTraceLoggerScriptEvent() {
|
||||
return offsetof(BaselineScript, traceLoggerScriptEvent_);
|
||||
}
|
||||
#endif
|
||||
|
||||
void noteAccessedGetter(uint32_t pcOffset);
|
||||
void noteArrayWriteHole(uint32_t pcOffset);
|
||||
|
||||
@ -438,6 +462,11 @@ AddSizeOfBaselineData(JSScript *script, mozilla::MallocSizeOf mallocSizeOf, size
|
||||
void
|
||||
ToggleBaselineSPS(JSRuntime *runtime, bool enable);
|
||||
|
||||
void
|
||||
ToggleBaselineTraceLoggerScripts(JSRuntime *runtime, bool enable);
|
||||
void
|
||||
ToggleBaselineTraceLoggerEngine(JSRuntime *runtime, bool enable);
|
||||
|
||||
struct BaselineBailoutInfo
|
||||
{
|
||||
// Pointer into the current C stack, where overwriting will start.
|
||||
|
@ -2022,8 +2022,8 @@ CodeGenerator::visitOsrEntry(LOsrEntry *lir)
|
||||
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
if (gen->info().executionMode() == SequentialExecution) {
|
||||
emitTracelogStopEvent(TraceLogger::Baseline);
|
||||
emitTracelogStartEvent(TraceLogger::IonMonkey);
|
||||
emitTracelogStopEvent(TraceLogger_Baseline);
|
||||
emitTracelogStartEvent(TraceLogger_IonMonkey);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -7349,10 +7349,8 @@ CodeGenerator::generate()
|
||||
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
if (!gen->compilingAsmJS() && gen->info().executionMode() == SequentialExecution) {
|
||||
if (!emitTracelogScriptStart())
|
||||
return false;
|
||||
if (!emitTracelogStartEvent(TraceLogger::IonMonkey))
|
||||
return false;
|
||||
emitTracelogScriptStart();
|
||||
emitTracelogStartEvent(TraceLogger_IonMonkey);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -7625,19 +7623,25 @@ CodeGenerator::link(JSContext *cx, types::CompilerConstraintList *constraints)
|
||||
ionScript->copyPatchableBackedges(cx, code, patchableBackedges_.begin(), masm);
|
||||
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
|
||||
TraceLoggerThread *logger = TraceLoggerForMainThread(cx->runtime());
|
||||
for (uint32_t i = 0; i < patchableTraceLoggers_.length(); i++) {
|
||||
patchableTraceLoggers_[i].fixup(&masm);
|
||||
Assembler::PatchDataWithValueCheck(CodeLocationLabel(code, patchableTraceLoggers_[i]),
|
||||
ImmPtr(logger),
|
||||
ImmPtr(nullptr));
|
||||
}
|
||||
uint32_t scriptId = TraceLogCreateTextId(logger, script);
|
||||
for (uint32_t i = 0; i < patchableTLScripts_.length(); i++) {
|
||||
patchableTLScripts_[i].fixup(&masm);
|
||||
Assembler::PatchDataWithValueCheck(CodeLocationLabel(code, patchableTLScripts_[i]),
|
||||
ImmPtr((void *) uintptr_t(scriptId)),
|
||||
ImmPtr((void *)0));
|
||||
|
||||
if (patchableTLScripts_.length() > 0) {
|
||||
MOZ_ASSERT(TraceLogTextIdEnabled(TraceLogger_Scripts));
|
||||
TraceLoggerEvent event(logger, TraceLogger_Scripts, script);
|
||||
ionScript->setTraceLoggerEvent(event);
|
||||
uint32_t textId = event.payload()->textId();
|
||||
for (uint32_t i = 0; i < patchableTLScripts_.length(); i++) {
|
||||
patchableTLScripts_[i].fixup(&masm);
|
||||
Assembler::PatchDataWithValueCheck(CodeLocationLabel(code, patchableTLScripts_[i]),
|
||||
ImmPtr((void *) uintptr_t(textId)),
|
||||
ImmPtr((void *)0));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -548,9 +548,10 @@ jit::LazyLinkTopActivation(JSContext *cx)
|
||||
builder->remove();
|
||||
|
||||
if (CodeGenerator *codegen = builder->backgroundCodegen()) {
|
||||
js::TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
|
||||
AutoTraceLog logScript(logger, TraceLogCreateTextId(logger, script));
|
||||
AutoTraceLog logLink(logger, TraceLogger::IonLinking);
|
||||
js::TraceLoggerThread *logger = TraceLoggerForMainThread(cx->runtime());
|
||||
TraceLoggerEvent event(logger, TraceLogger_AnnotateScripts, script);
|
||||
AutoTraceLog logScript(logger, event);
|
||||
AutoTraceLog logLink(logger, TraceLogger_IonLinking);
|
||||
|
||||
JitContext jctx(cx, &builder->alloc());
|
||||
|
||||
@ -1272,7 +1273,7 @@ bool
|
||||
OptimizeMIR(MIRGenerator *mir)
|
||||
{
|
||||
MIRGraph &graph = mir->graph();
|
||||
TraceLogger *logger;
|
||||
TraceLoggerThread *logger;
|
||||
if (GetJitContext()->runtime->onMainThread())
|
||||
logger = TraceLoggerForMainThread(GetJitContext()->runtime);
|
||||
else
|
||||
@ -1290,7 +1291,7 @@ OptimizeMIR(MIRGenerator *mir)
|
||||
return false;
|
||||
|
||||
if (!mir->compilingAsmJS()) {
|
||||
AutoTraceLog log(logger, TraceLogger::FoldTests);
|
||||
AutoTraceLog log(logger, TraceLogger_FoldTests);
|
||||
FoldTests(graph);
|
||||
IonSpewPass("Fold Tests");
|
||||
AssertBasicGraphCoherency(graph);
|
||||
@ -1300,7 +1301,7 @@ OptimizeMIR(MIRGenerator *mir)
|
||||
}
|
||||
|
||||
{
|
||||
AutoTraceLog log(logger, TraceLogger::SplitCriticalEdges);
|
||||
AutoTraceLog log(logger, TraceLogger_SplitCriticalEdges);
|
||||
if (!SplitCriticalEdges(graph))
|
||||
return false;
|
||||
IonSpewPass("Split Critical Edges");
|
||||
@ -1311,7 +1312,7 @@ OptimizeMIR(MIRGenerator *mir)
|
||||
}
|
||||
|
||||
{
|
||||
AutoTraceLog log(logger, TraceLogger::RenumberBlocks);
|
||||
AutoTraceLog log(logger, TraceLogger_RenumberBlocks);
|
||||
if (!RenumberBlocks(graph))
|
||||
return false;
|
||||
IonSpewPass("Renumber Blocks");
|
||||
@ -1322,7 +1323,7 @@ OptimizeMIR(MIRGenerator *mir)
|
||||
}
|
||||
|
||||
{
|
||||
AutoTraceLog log(logger, TraceLogger::DominatorTree);
|
||||
AutoTraceLog log(logger, TraceLogger_DominatorTree);
|
||||
if (!BuildDominatorTree(graph))
|
||||
return false;
|
||||
// No spew: graph not changed.
|
||||
@ -1332,7 +1333,7 @@ OptimizeMIR(MIRGenerator *mir)
|
||||
}
|
||||
|
||||
{
|
||||
AutoTraceLog log(logger, TraceLogger::PhiAnalysis);
|
||||
AutoTraceLog log(logger, TraceLogger_PhiAnalysis);
|
||||
// Aggressive phi elimination must occur before any code elimination. If the
|
||||
// script contains a try-statement, we only compiled the try block and not
|
||||
// the catch or finally blocks, so in this case it's also invalid to use
|
||||
@ -1358,7 +1359,7 @@ OptimizeMIR(MIRGenerator *mir)
|
||||
}
|
||||
|
||||
if (mir->optimizationInfo().scalarReplacementEnabled()) {
|
||||
AutoTraceLog log(logger, TraceLogger::ScalarReplacement);
|
||||
AutoTraceLog log(logger, TraceLogger_ScalarReplacement);
|
||||
if (!ScalarReplacement(mir, graph))
|
||||
return false;
|
||||
IonSpewPass("Scalar Replacement");
|
||||
@ -1369,7 +1370,7 @@ OptimizeMIR(MIRGenerator *mir)
|
||||
}
|
||||
|
||||
if (!mir->compilingAsmJS()) {
|
||||
AutoTraceLog log(logger, TraceLogger::ApplyTypes);
|
||||
AutoTraceLog log(logger, TraceLogger_ApplyTypes);
|
||||
if (!ApplyTypeInformation(mir, graph))
|
||||
return false;
|
||||
IonSpewPass("Apply types");
|
||||
@ -1384,7 +1385,7 @@ OptimizeMIR(MIRGenerator *mir)
|
||||
// are not deleted, leaving them dangling. This is ok, since we'll rerun
|
||||
// AliasAnalysis, which recomputes them, before they're needed.
|
||||
if (graph.entryBlock()->info().executionMode() == ParallelExecution) {
|
||||
AutoTraceLog log(logger, TraceLogger::ParallelSafetyAnalysis);
|
||||
AutoTraceLog log(logger, TraceLogger_ParallelSafetyAnalysis);
|
||||
ParallelSafetyAnalysis analysis(mir, graph);
|
||||
if (!analysis.analyze())
|
||||
return false;
|
||||
@ -1403,7 +1404,7 @@ OptimizeMIR(MIRGenerator *mir)
|
||||
if (mir->optimizationInfo().licmEnabled() ||
|
||||
mir->optimizationInfo().gvnEnabled())
|
||||
{
|
||||
AutoTraceLog log(logger, TraceLogger::AliasAnalysis);
|
||||
AutoTraceLog log(logger, TraceLogger_AliasAnalysis);
|
||||
AliasAnalysis analysis(mir, graph);
|
||||
if (!analysis.analyze())
|
||||
return false;
|
||||
@ -1426,7 +1427,7 @@ OptimizeMIR(MIRGenerator *mir)
|
||||
}
|
||||
|
||||
if (mir->optimizationInfo().gvnEnabled()) {
|
||||
AutoTraceLog log(logger, TraceLogger::GVN);
|
||||
AutoTraceLog log(logger, TraceLogger_GVN);
|
||||
if (!gvn.run(ValueNumberer::UpdateAliasAnalysis))
|
||||
return false;
|
||||
IonSpewPass("GVN");
|
||||
@ -1437,7 +1438,7 @@ OptimizeMIR(MIRGenerator *mir)
|
||||
}
|
||||
|
||||
if (mir->optimizationInfo().licmEnabled()) {
|
||||
AutoTraceLog log(logger, TraceLogger::LICM);
|
||||
AutoTraceLog log(logger, TraceLogger_LICM);
|
||||
// LICM can hoist instructions from conditional branches and trigger
|
||||
// repeated bailouts. Disable it if this script is known to bailout
|
||||
// frequently.
|
||||
@ -1454,7 +1455,7 @@ OptimizeMIR(MIRGenerator *mir)
|
||||
}
|
||||
|
||||
if (mir->optimizationInfo().rangeAnalysisEnabled()) {
|
||||
AutoTraceLog log(logger, TraceLogger::RangeAnalysis);
|
||||
AutoTraceLog log(logger, TraceLogger_RangeAnalysis);
|
||||
RangeAnalysis r(mir, graph);
|
||||
if (!r.addBetaNodes())
|
||||
return false;
|
||||
@ -1512,7 +1513,7 @@ OptimizeMIR(MIRGenerator *mir)
|
||||
}
|
||||
|
||||
if (mir->optimizationInfo().loopUnrollingEnabled()) {
|
||||
AutoTraceLog log(logger, TraceLogger::LoopUnrolling);
|
||||
AutoTraceLog log(logger, TraceLogger_LoopUnrolling);
|
||||
|
||||
if (!UnrollLoops(graph, r.loopIterationBounds))
|
||||
return false;
|
||||
@ -1523,7 +1524,7 @@ OptimizeMIR(MIRGenerator *mir)
|
||||
}
|
||||
|
||||
if (mir->optimizationInfo().eaaEnabled()) {
|
||||
AutoTraceLog log(logger, TraceLogger::EffectiveAddressAnalysis);
|
||||
AutoTraceLog log(logger, TraceLogger_EffectiveAddressAnalysis);
|
||||
EffectiveAddressAnalysis eaa(graph);
|
||||
if (!eaa.analyze())
|
||||
return false;
|
||||
@ -1535,7 +1536,7 @@ OptimizeMIR(MIRGenerator *mir)
|
||||
}
|
||||
|
||||
{
|
||||
AutoTraceLog log(logger, TraceLogger::EliminateDeadCode);
|
||||
AutoTraceLog log(logger, TraceLogger_EliminateDeadCode);
|
||||
if (!EliminateDeadCode(mir, graph))
|
||||
return false;
|
||||
IonSpewPass("DCE");
|
||||
@ -1546,7 +1547,7 @@ OptimizeMIR(MIRGenerator *mir)
|
||||
}
|
||||
|
||||
{
|
||||
AutoTraceLog log(logger, TraceLogger::EliminateDeadCode);
|
||||
AutoTraceLog log(logger, TraceLogger_EliminateDeadCode);
|
||||
if (!Sink(mir, graph))
|
||||
return false;
|
||||
IonSpewPass("Sink");
|
||||
@ -1559,7 +1560,7 @@ OptimizeMIR(MIRGenerator *mir)
|
||||
// Make loops contiguous. We do this after GVN/UCE and range analysis,
|
||||
// which can remove CFG edges, exposing more blocks that can be moved.
|
||||
{
|
||||
AutoTraceLog log(logger, TraceLogger::MakeLoopsContiguous);
|
||||
AutoTraceLog log(logger, TraceLogger_MakeLoopsContiguous);
|
||||
if (!MakeLoopsContiguous(graph))
|
||||
return false;
|
||||
IonSpewPass("Make loops contiguous");
|
||||
@ -1573,7 +1574,7 @@ OptimizeMIR(MIRGenerator *mir)
|
||||
// depend on knowing the final order in which instructions will execute.
|
||||
|
||||
if (mir->optimizationInfo().edgeCaseAnalysisEnabled()) {
|
||||
AutoTraceLog log(logger, TraceLogger::EdgeCaseAnalysis);
|
||||
AutoTraceLog log(logger, TraceLogger_EdgeCaseAnalysis);
|
||||
EdgeCaseAnalysis edgeCaseAnalysis(mir, graph);
|
||||
if (!edgeCaseAnalysis.analyzeLate())
|
||||
return false;
|
||||
@ -1585,7 +1586,7 @@ OptimizeMIR(MIRGenerator *mir)
|
||||
}
|
||||
|
||||
if (mir->optimizationInfo().eliminateRedundantChecksEnabled()) {
|
||||
AutoTraceLog log(logger, TraceLogger::EliminateRedundantChecks);
|
||||
AutoTraceLog log(logger, TraceLogger_EliminateRedundantChecks);
|
||||
// Note: check elimination has to run after all other passes that move
|
||||
// instructions. Since check uses are replaced with the actual index,
|
||||
// code motion after this pass could incorrectly move a load or store
|
||||
@ -1604,7 +1605,7 @@ GenerateLIR(MIRGenerator *mir)
|
||||
{
|
||||
MIRGraph &graph = mir->graph();
|
||||
|
||||
TraceLogger *logger;
|
||||
TraceLoggerThread *logger;
|
||||
if (GetJitContext()->runtime->onMainThread())
|
||||
logger = TraceLoggerForMainThread(GetJitContext()->runtime);
|
||||
else
|
||||
@ -1616,7 +1617,7 @@ GenerateLIR(MIRGenerator *mir)
|
||||
|
||||
LIRGenerator lirgen(mir, graph, *lir);
|
||||
{
|
||||
AutoTraceLog log(logger, TraceLogger::GenerateLIR);
|
||||
AutoTraceLog log(logger, TraceLogger_GenerateLIR);
|
||||
if (!lirgen.generate())
|
||||
return nullptr;
|
||||
IonSpewPass("Generate LIR");
|
||||
@ -1628,7 +1629,7 @@ GenerateLIR(MIRGenerator *mir)
|
||||
AllocationIntegrityState integrity(*lir);
|
||||
|
||||
{
|
||||
AutoTraceLog log(logger, TraceLogger::RegisterAllocation);
|
||||
AutoTraceLog log(logger, TraceLogger_RegisterAllocation);
|
||||
|
||||
switch (mir->optimizationInfo().registerAllocator()) {
|
||||
case RegisterAllocator_LSRA: {
|
||||
@ -1698,12 +1699,12 @@ GenerateLIR(MIRGenerator *mir)
|
||||
CodeGenerator *
|
||||
GenerateCode(MIRGenerator *mir, LIRGraph *lir)
|
||||
{
|
||||
TraceLogger *logger;
|
||||
TraceLoggerThread *logger;
|
||||
if (GetJitContext()->runtime->onMainThread())
|
||||
logger = TraceLoggerForMainThread(GetJitContext()->runtime);
|
||||
else
|
||||
logger = TraceLoggerForCurrentThread();
|
||||
AutoTraceLog log(logger, TraceLogger::GenerateCode);
|
||||
AutoTraceLog log(logger, TraceLogger_GenerateCode);
|
||||
|
||||
CodeGenerator *codegen = js_new<CodeGenerator>(mir, lir);
|
||||
if (!codegen)
|
||||
@ -1745,7 +1746,7 @@ AttachFinishedCompilations(JSContext *cx)
|
||||
|
||||
GlobalHelperThreadState::IonBuilderVector &finished = HelperThreadState().ionFinishedList();
|
||||
|
||||
TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
|
||||
TraceLoggerThread *logger = TraceLoggerForMainThread(cx->runtime());
|
||||
|
||||
// Incorporate any off thread compilations for the compartment which have
|
||||
// finished, failed or have been cancelled.
|
||||
@ -1797,8 +1798,9 @@ AttachFinishedCompilations(JSContext *cx)
|
||||
if (CodeGenerator *codegen = builder->backgroundCodegen()) {
|
||||
RootedScript script(cx, builder->script());
|
||||
JitContext jctx(cx, &builder->alloc());
|
||||
AutoTraceLog logScript(logger, TraceLogCreateTextId(logger, script));
|
||||
AutoTraceLog logLink(logger, TraceLogger::IonLinking);
|
||||
TraceLoggerEvent event(logger, TraceLogger_AnnotateScripts, script);
|
||||
AutoTraceLog logScript(logger, event);
|
||||
AutoTraceLog logLink(logger, TraceLogger_IonLinking);
|
||||
|
||||
// Root the assembler until the builder is finished below. As it
|
||||
// was constructed off thread, the assembler has not been rooted
|
||||
@ -1876,9 +1878,10 @@ IonCompile(JSContext *cx, JSScript *script,
|
||||
ExecutionMode executionMode, bool recompile,
|
||||
OptimizationLevel optimizationLevel)
|
||||
{
|
||||
TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
|
||||
AutoTraceLog logScript(logger, TraceLogCreateTextId(logger, script));
|
||||
AutoTraceLog logCompile(logger, TraceLogger::IonCompilation);
|
||||
TraceLoggerThread *logger = TraceLoggerForMainThread(cx->runtime());
|
||||
TraceLoggerEvent event(logger, TraceLogger_AnnotateScripts, script);
|
||||
AutoTraceLog logScript(logger, event);
|
||||
AutoTraceLog logCompile(logger, TraceLogger_IonCompilation);
|
||||
|
||||
MOZ_ASSERT(optimizationLevel > Optimization_DontCompile);
|
||||
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "vm/ArgumentsObject.h"
|
||||
#include "vm/Opcodes.h"
|
||||
#include "vm/RegExpStatics.h"
|
||||
#include "vm/TraceLogging.h"
|
||||
|
||||
#include "jsinferinlines.h"
|
||||
#include "jsobjinlines.h"
|
||||
@ -342,6 +343,11 @@ IonBuilder::canInlineTarget(JSFunction *target, CallInfo &callInfo)
|
||||
if (!optimizationInfo().inlineInterpreted())
|
||||
return InliningDecision_DontInline;
|
||||
|
||||
if (TraceLogTextIdEnabled(TraceLogger_InlinedScripts)) {
|
||||
return DontInline(nullptr, "Tracelogging of inlined scripts is enabled"
|
||||
"but Tracelogger cannot do that yet.");
|
||||
}
|
||||
|
||||
if (!target->isInterpreted())
|
||||
return DontInline(nullptr, "Non-interpreted target");
|
||||
|
||||
@ -4472,6 +4478,9 @@ IonBuilder::patchInlinedReturn(CallInfo &callInfo, MBasicBlock *exit, MBasicBloc
|
||||
rdef = callInfo.getArg(0);
|
||||
}
|
||||
|
||||
if (!callInfo.isSetter())
|
||||
rdef = specializeInlinedReturn(rdef, exit);
|
||||
|
||||
MGoto *replacement = MGoto::New(alloc(), bottom);
|
||||
exit->end(replacement);
|
||||
if (!bottom->addPredecessorWithoutPhis(exit))
|
||||
@ -4480,6 +4489,47 @@ IonBuilder::patchInlinedReturn(CallInfo &callInfo, MBasicBlock *exit, MBasicBloc
|
||||
return rdef;
|
||||
}
|
||||
|
||||
MDefinition *
|
||||
IonBuilder::specializeInlinedReturn(MDefinition *rdef, MBasicBlock *exit)
|
||||
{
|
||||
// Remove types from the return definition that weren't observed.
|
||||
types::TemporaryTypeSet *types = bytecodeTypes(pc);
|
||||
|
||||
// The observed typeset doesn't contain extra information.
|
||||
if (types->empty() || types->unknown())
|
||||
return rdef;
|
||||
|
||||
// Decide if specializing is needed using the result typeset if available,
|
||||
// else use the result type.
|
||||
|
||||
if (rdef->resultTypeSet()) {
|
||||
// Don't specialize if return typeset is a subset of the
|
||||
// observed typeset. The return typeset is already more specific.
|
||||
if (rdef->resultTypeSet()->isSubset(types))
|
||||
return rdef;
|
||||
} else {
|
||||
// Don't specialize if types are inaccordance, except for MIRType_Value
|
||||
// and MIRType_Object (when not unknown object), since the typeset
|
||||
// contains more specific information.
|
||||
MIRType observedType = types->getKnownMIRType();
|
||||
if (observedType == rdef->type() &&
|
||||
observedType != MIRType_Value &&
|
||||
(observedType != MIRType_Object || types->unknownObject()))
|
||||
{
|
||||
return rdef;
|
||||
}
|
||||
}
|
||||
|
||||
setCurrent(exit);
|
||||
|
||||
MTypeBarrier *barrier = nullptr;
|
||||
rdef = addTypeBarrier(rdef, types, BarrierKind::TypeSet, &barrier);
|
||||
if (barrier)
|
||||
barrier->setNotMovable();
|
||||
|
||||
return rdef;
|
||||
}
|
||||
|
||||
MDefinition *
|
||||
IonBuilder::patchInlinedReturns(CallInfo &callInfo, MIRGraphReturns &returns, MBasicBlock *bottom)
|
||||
{
|
||||
@ -6818,55 +6868,60 @@ IonBuilder::testSingletonPropertyTypes(MDefinition *obj, JSObject *singleton, Pr
|
||||
return false;
|
||||
}
|
||||
|
||||
// Given an observed type set, annotates the IR as much as possible:
|
||||
// (1) If no type information is provided, the value on the top of the stack is
|
||||
// left in place.
|
||||
// (2) If a single type definitely exists, and no type barrier is needed,
|
||||
// then an infallible unbox instruction replaces the value on the top of
|
||||
// the stack.
|
||||
// (3) If a type barrier is needed, but has an unknown type set, leave the
|
||||
// value at the top of the stack.
|
||||
// (4) If a type barrier is needed, and has a single type, an unbox
|
||||
// instruction replaces the top of the stack.
|
||||
// (5) Lastly, a type barrier instruction replaces the top of the stack.
|
||||
bool
|
||||
IonBuilder::pushTypeBarrier(MDefinition *def, types::TemporaryTypeSet *observed, BarrierKind kind)
|
||||
{
|
||||
MOZ_ASSERT(def == current->peek(-1));
|
||||
|
||||
MDefinition *replace = addTypeBarrier(current->pop(), observed, kind);
|
||||
if (!replace)
|
||||
return false;
|
||||
|
||||
current->push(replace);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Given an observed type set, annotates the IR as much as possible:
|
||||
// (1) If no type information is provided, the given value is returned.
|
||||
// (2) If a single type definitely exists, and no type barrier is needed,
|
||||
// then an infallible unbox instruction is returned.
|
||||
// (3) If a type barrier is needed, but has an unknown type set, the given
|
||||
// value is returned.
|
||||
// (4) Lastly, a type barrier instruction is added and returned.
|
||||
MDefinition *
|
||||
IonBuilder::addTypeBarrier(MDefinition *def, types::TemporaryTypeSet *observed, BarrierKind kind,
|
||||
MTypeBarrier **pbarrier)
|
||||
{
|
||||
// Barriers are never needed for instructions whose result will not be used.
|
||||
if (BytecodeIsPopped(pc))
|
||||
return true;
|
||||
return def;
|
||||
|
||||
// If the instruction has no side effects, we'll resume the entire operation.
|
||||
// The actual type barrier will occur in the interpreter. If the
|
||||
// instruction is effectful, even if it has a singleton type, there
|
||||
// must be a resume point capturing the original def, and resuming
|
||||
// to that point will explicitly monitor the new type.
|
||||
|
||||
if (kind == BarrierKind::NoBarrier) {
|
||||
MDefinition *replace = ensureDefiniteType(def, observed->getKnownMIRType());
|
||||
if (replace != def) {
|
||||
current->pop();
|
||||
current->push(replace);
|
||||
}
|
||||
replace->setResultTypeSet(observed);
|
||||
return true;
|
||||
return replace;
|
||||
}
|
||||
|
||||
if (observed->unknown())
|
||||
return true;
|
||||
return def;
|
||||
|
||||
current->pop();
|
||||
|
||||
MInstruction *barrier = MTypeBarrier::New(alloc(), def, observed, kind);
|
||||
MTypeBarrier *barrier = MTypeBarrier::New(alloc(), def, observed, kind);
|
||||
current->add(barrier);
|
||||
|
||||
if (barrier->type() == MIRType_Undefined)
|
||||
return pushConstant(UndefinedValue());
|
||||
if (barrier->type() == MIRType_Null)
|
||||
return pushConstant(NullValue());
|
||||
if (pbarrier)
|
||||
*pbarrier = barrier;
|
||||
|
||||
current->push(barrier);
|
||||
return true;
|
||||
if (barrier->type() == MIRType_Undefined)
|
||||
return constant(UndefinedValue());
|
||||
if (barrier->type() == MIRType_Null)
|
||||
return constant(NullValue());
|
||||
|
||||
return barrier;
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -358,6 +358,8 @@ class IonBuilder
|
||||
|
||||
// Add a guard which ensure that the set of type which goes through this
|
||||
// generated code correspond to the observed types for the bytecode.
|
||||
MDefinition *addTypeBarrier(MDefinition *def, types::TemporaryTypeSet *observed,
|
||||
BarrierKind kind, MTypeBarrier **pbarrier = nullptr);
|
||||
bool pushTypeBarrier(MDefinition *def, types::TemporaryTypeSet *observed, BarrierKind kind);
|
||||
|
||||
// As pushTypeBarrier, but will compute the needBarrier boolean itself based
|
||||
@ -841,6 +843,7 @@ class IonBuilder
|
||||
MDefinition *patchInlinedReturn(CallInfo &callInfo, MBasicBlock *exit, MBasicBlock *bottom);
|
||||
MDefinition *patchInlinedReturns(CallInfo &callInfo, MIRGraphReturns &returns,
|
||||
MBasicBlock *bottom);
|
||||
MDefinition *specializeInlinedReturn(MDefinition *rdef, MBasicBlock *exit);
|
||||
|
||||
bool objectsHaveCommonPrototype(types::TemporaryTypeSet *types, PropertyName *name,
|
||||
bool isGetter, JSObject *foundProto, bool *guardGlobal);
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "jit/IonOptimizationLevels.h"
|
||||
#include "jit/IonTypes.h"
|
||||
#include "js/UbiNode.h"
|
||||
#include "vm/TraceLogging.h"
|
||||
|
||||
namespace js {
|
||||
|
||||
@ -285,6 +286,9 @@ struct IonScript
|
||||
// a LOOPENTRY pc other than osrPc_.
|
||||
uint32_t osrPcMismatchCounter_;
|
||||
|
||||
// The tracelogger event used to log the start/stop of this IonScript.
|
||||
TraceLoggerEvent traceLoggerScriptEvent_;
|
||||
|
||||
IonBuilder *pendingBuilder_;
|
||||
|
||||
private:
|
||||
@ -462,6 +466,9 @@ struct IonScript
|
||||
bool hasSPSInstrumentation() const {
|
||||
return hasSPSInstrumentation_;
|
||||
}
|
||||
void setTraceLoggerEvent(TraceLoggerEvent &event) {
|
||||
traceLoggerScriptEvent_ = event;
|
||||
}
|
||||
const uint8_t *snapshots() const {
|
||||
return reinterpret_cast<const uint8_t *>(this) + snapshots_;
|
||||
}
|
||||
|
@ -714,7 +714,7 @@ void
|
||||
HandleException(ResumeFromException *rfe)
|
||||
{
|
||||
JSContext *cx = GetJSContextFromJitCode();
|
||||
TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
|
||||
TraceLoggerThread *logger = TraceLoggerForMainThread(cx->runtime());
|
||||
|
||||
rfe->kind = ResumeFromException::RESUME_ENTRY_FRAME;
|
||||
|
||||
@ -781,8 +781,8 @@ HandleException(ResumeFromException *rfe)
|
||||
JSScript *script = frames.script();
|
||||
probes::ExitScript(cx, script, script->functionNonDelazifying(), popSPSFrame);
|
||||
if (!frames.more()) {
|
||||
TraceLogStopEvent(logger, TraceLogger::IonMonkey);
|
||||
TraceLogStopEvent(logger);
|
||||
TraceLogStopEvent(logger, TraceLogger_IonMonkey);
|
||||
TraceLogStopEvent(logger, TraceLogger_Scripts);
|
||||
break;
|
||||
}
|
||||
++frames;
|
||||
@ -812,8 +812,8 @@ HandleException(ResumeFromException *rfe)
|
||||
if (rfe->kind != ResumeFromException::RESUME_ENTRY_FRAME)
|
||||
return;
|
||||
|
||||
TraceLogStopEvent(logger, TraceLogger::Baseline);
|
||||
TraceLogStopEvent(logger);
|
||||
TraceLogStopEvent(logger, TraceLogger_Baseline);
|
||||
TraceLogStopEvent(logger, TraceLogger_Scripts);
|
||||
|
||||
// Unwind profiler pseudo-stack
|
||||
JSScript *script = iter.script();
|
||||
|
@ -299,12 +299,8 @@ class LSimdShuffle : public LInstructionHelper<1, 2, 1>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(SimdShuffle);
|
||||
LSimdShuffle(const LAllocation &lhs, const LAllocation &rhs, const LDefinition &temp)
|
||||
{
|
||||
setOperand(0, lhs);
|
||||
setOperand(1, rhs);
|
||||
setTemp(0, temp);
|
||||
}
|
||||
LSimdShuffle()
|
||||
{}
|
||||
|
||||
const LAllocation *lhs() {
|
||||
return getOperand(0);
|
||||
|
@ -3966,14 +3966,12 @@ LIRGenerator::visitSimdShuffle(MSimdShuffle *ins)
|
||||
bool wFromLHS = ins->laneW() < 4;
|
||||
uint32_t lanesFromLHS = (ins->laneX() < 4) + (ins->laneY() < 4) + zFromLHS + wFromLHS;
|
||||
|
||||
LUse lhs = useRegisterAtStart(ins->lhs());
|
||||
LUse rhs = useRegister(ins->rhs());
|
||||
LSimdShuffle *lir = new (alloc()) LSimdShuffle();
|
||||
lowerForFPU(lir, ins, ins->lhs(), ins->rhs());
|
||||
|
||||
// See codegen for requirements details.
|
||||
LDefinition temp = (lanesFromLHS == 3) ? tempCopy(ins->rhs(), 1) : LDefinition::BogusTemp();
|
||||
|
||||
LSimdShuffle *lir = new (alloc()) LSimdShuffle(lhs, rhs, temp);
|
||||
defineReuseInput(lir, ins, 0);
|
||||
lir->setTemp(0, temp);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1669,9 +1669,10 @@ MacroAssembler::printf(const char *output, Register value)
|
||||
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
void
|
||||
MacroAssembler::tracelogStart(Register logger, uint32_t textId)
|
||||
MacroAssembler::tracelogStartId(Register logger, uint32_t textId, bool force)
|
||||
{
|
||||
void (&TraceLogFunc)(TraceLogger*, uint32_t) = TraceLogStartEvent;
|
||||
if (!force && !TraceLogTextIdEnabled(textId))
|
||||
return;
|
||||
|
||||
PushRegsInMask(RegisterSet::Volatile());
|
||||
|
||||
@ -1684,16 +1685,14 @@ MacroAssembler::tracelogStart(Register logger, uint32_t textId)
|
||||
passABIArg(logger);
|
||||
move32(Imm32(textId), temp);
|
||||
passABIArg(temp);
|
||||
callWithABINoProfiling(JS_FUNC_TO_DATA_PTR(void *, TraceLogFunc));
|
||||
callWithABINoProfiling(JS_FUNC_TO_DATA_PTR(void *, TraceLogStartEventPrivate));
|
||||
|
||||
PopRegsInMask(RegisterSet::Volatile());
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::tracelogStart(Register logger, Register textId)
|
||||
MacroAssembler::tracelogStartId(Register logger, Register textId)
|
||||
{
|
||||
void (&TraceLogFunc)(TraceLogger*, uint32_t) = TraceLogStartEvent;
|
||||
|
||||
PushRegsInMask(RegisterSet::Volatile());
|
||||
|
||||
RegisterSet regs = RegisterSet::Volatile();
|
||||
@ -1705,17 +1704,37 @@ MacroAssembler::tracelogStart(Register logger, Register textId)
|
||||
setupUnalignedABICall(2, temp);
|
||||
passABIArg(logger);
|
||||
passABIArg(textId);
|
||||
callWithABINoProfiling(JS_FUNC_TO_DATA_PTR(void *, TraceLogFunc));
|
||||
|
||||
regs.add(temp);
|
||||
callWithABINoProfiling(JS_FUNC_TO_DATA_PTR(void *, TraceLogStartEventPrivate));
|
||||
|
||||
PopRegsInMask(RegisterSet::Volatile());
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::tracelogStop(Register logger, uint32_t textId)
|
||||
MacroAssembler::tracelogStartEvent(Register logger, Register event)
|
||||
{
|
||||
void (&TraceLogFunc)(TraceLogger*, uint32_t) = TraceLogStopEvent;
|
||||
void (&TraceLogFunc)(TraceLoggerThread *, const TraceLoggerEvent &) = TraceLogStartEvent;
|
||||
|
||||
PushRegsInMask(RegisterSet::Volatile());
|
||||
|
||||
RegisterSet regs = RegisterSet::Volatile();
|
||||
regs.takeUnchecked(logger);
|
||||
regs.takeUnchecked(event);
|
||||
|
||||
Register temp = regs.takeGeneral();
|
||||
|
||||
setupUnalignedABICall(2, temp);
|
||||
passABIArg(logger);
|
||||
passABIArg(event);
|
||||
callWithABINoProfiling(JS_FUNC_TO_DATA_PTR(void *, TraceLogFunc));
|
||||
|
||||
PopRegsInMask(RegisterSet::Volatile());
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::tracelogStopId(Register logger, uint32_t textId, bool force)
|
||||
{
|
||||
if (!force && !TraceLogTextIdEnabled(textId))
|
||||
return;
|
||||
|
||||
PushRegsInMask(RegisterSet::Volatile());
|
||||
|
||||
@ -1728,23 +1747,19 @@ MacroAssembler::tracelogStop(Register logger, uint32_t textId)
|
||||
passABIArg(logger);
|
||||
move32(Imm32(textId), temp);
|
||||
passABIArg(temp);
|
||||
callWithABINoProfiling(JS_FUNC_TO_DATA_PTR(void *, TraceLogFunc));
|
||||
|
||||
regs.add(temp);
|
||||
callWithABINoProfiling(JS_FUNC_TO_DATA_PTR(void *, TraceLogStopEventPrivate));
|
||||
|
||||
PopRegsInMask(RegisterSet::Volatile());
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::tracelogStop(Register logger, Register textId)
|
||||
MacroAssembler::tracelogStopId(Register logger, Register textId)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
void (&TraceLogFunc)(TraceLogger*, uint32_t) = TraceLogStopEvent;
|
||||
|
||||
PushRegsInMask(RegisterSet::Volatile());
|
||||
|
||||
RegisterSet regs = RegisterSet::Volatile();
|
||||
regs.takeUnchecked(logger);
|
||||
|
||||
regs.takeUnchecked(textId);
|
||||
|
||||
Register temp = regs.takeGeneral();
|
||||
@ -1752,33 +1767,7 @@ MacroAssembler::tracelogStop(Register logger, Register textId)
|
||||
setupUnalignedABICall(2, temp);
|
||||
passABIArg(logger);
|
||||
passABIArg(textId);
|
||||
callWithABINoProfiling(JS_FUNC_TO_DATA_PTR(void *, TraceLogFunc));
|
||||
|
||||
regs.add(temp);
|
||||
|
||||
PopRegsInMask(RegisterSet::Volatile());
|
||||
#else
|
||||
tracelogStop(logger);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::tracelogStop(Register logger)
|
||||
{
|
||||
void (&TraceLogFunc)(TraceLogger*) = TraceLogStopEvent;
|
||||
|
||||
PushRegsInMask(RegisterSet::Volatile());
|
||||
|
||||
RegisterSet regs = RegisterSet::Volatile();
|
||||
regs.takeUnchecked(logger);
|
||||
|
||||
Register temp = regs.takeGeneral();
|
||||
|
||||
setupUnalignedABICall(1, temp);
|
||||
passABIArg(logger);
|
||||
callWithABINoProfiling(JS_FUNC_TO_DATA_PTR(void *, TraceLogFunc));
|
||||
|
||||
regs.add(temp);
|
||||
callWithABINoProfiling(JS_FUNC_TO_DATA_PTR(void *, TraceLogStopEventPrivate));
|
||||
|
||||
PopRegsInMask(RegisterSet::Volatile());
|
||||
}
|
||||
|
@ -1207,11 +1207,11 @@ class MacroAssembler : public MacroAssemblerSpecific
|
||||
void printf(const char *output, Register value);
|
||||
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
void tracelogStart(Register logger, uint32_t textId);
|
||||
void tracelogStart(Register logger, Register textId);
|
||||
void tracelogStop(Register logger, uint32_t textId);
|
||||
void tracelogStop(Register logger, Register textId);
|
||||
void tracelogStop(Register logger);
|
||||
void tracelogStartId(Register logger, uint32_t textId, bool force = false);
|
||||
void tracelogStartId(Register logger, Register textId);
|
||||
void tracelogStartEvent(Register logger, Register event);
|
||||
void tracelogStopId(Register logger, uint32_t textId, bool force = false);
|
||||
void tracelogStopId(Register logger, Register textId);
|
||||
#endif
|
||||
|
||||
#define DISPATCH_FLOATING_POINT_OP(method, type, arg1d, arg1f, arg2) \
|
||||
|
@ -278,6 +278,8 @@ TypeBarrierPolicy::adjustInputs(TempAllocator &alloc, MInstruction *def)
|
||||
// Unbox / propagate the right type.
|
||||
MUnbox::Mode mode = MUnbox::TypeBarrier;
|
||||
MInstruction *replace = MUnbox::New(alloc, ins->getOperand(0), ins->type(), mode);
|
||||
if (!ins->isMovable())
|
||||
replace->setNotMovable();
|
||||
|
||||
ins->block()->insertBefore(ins, replace);
|
||||
ins->replaceOperand(0, replace);
|
||||
|
@ -771,9 +771,9 @@ DebugEpilogueOnBaselineReturn(JSContext *cx, BaselineFrame *frame, jsbytecode *p
|
||||
if (!DebugEpilogue(cx, frame, pc, true)) {
|
||||
// DebugEpilogue popped the frame by updating jitTop, so run the stop event
|
||||
// here before we enter the exception handler.
|
||||
TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
|
||||
TraceLogStopEvent(logger, TraceLogger::Baseline);
|
||||
TraceLogStopEvent(logger); // Leave script.
|
||||
TraceLoggerThread *logger = TraceLoggerForMainThread(cx->runtime());
|
||||
TraceLogStopEvent(logger, TraceLogger_Baseline);
|
||||
TraceLogStopEvent(logger, TraceLogger_Scripts);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -59,10 +59,8 @@ CodeGeneratorARM::generateEpilogue()
|
||||
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
if (gen->info().executionMode() == SequentialExecution) {
|
||||
if (!emitTracelogStopEvent(TraceLogger::IonMonkey))
|
||||
return false;
|
||||
if (!emitTracelogScriptStop())
|
||||
return false;
|
||||
emitTracelogStopEvent(TraceLogger_IonMonkey);
|
||||
emitTracelogScriptStop();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -57,10 +57,8 @@ CodeGeneratorMIPS::generateEpilogue()
|
||||
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
if (gen->info().executionMode() == SequentialExecution) {
|
||||
if (!emitTracelogStopEvent(TraceLogger::IonMonkey))
|
||||
return false;
|
||||
if (!emitTracelogScriptStop())
|
||||
return false;
|
||||
emitTracelogStopEvent(TraceLogger::IonMonkey);
|
||||
emitTracelogScriptStop();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -2103,10 +2103,42 @@ class AssemblerX86Shared : public AssemblerShared
|
||||
MOZ_ASSERT(HasSSE2());
|
||||
masm.vunpcklps_rr(src1.code(), src0.code(), dest.code());
|
||||
}
|
||||
void vunpcklps(const Operand &src1, FloatRegister src0, FloatRegister dest) {
|
||||
MOZ_ASSERT(HasSSE2());
|
||||
switch (src1.kind()) {
|
||||
case Operand::FPREG:
|
||||
masm.vunpcklps_rr(src1.fpu(), src0.code(), dest.code());
|
||||
break;
|
||||
case Operand::MEM_REG_DISP:
|
||||
masm.vunpcklps_mr(src1.disp(), src1.base(), src0.code(), dest.code());
|
||||
break;
|
||||
case Operand::MEM_ADDRESS32:
|
||||
masm.vunpcklps_mr(src1.address(), src0.code(), dest.code());
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("unexpected operand kind");
|
||||
}
|
||||
}
|
||||
void vunpckhps(FloatRegister src1, FloatRegister src0, FloatRegister dest) {
|
||||
MOZ_ASSERT(HasSSE2());
|
||||
masm.vunpckhps_rr(src1.code(), src0.code(), dest.code());
|
||||
}
|
||||
void vunpckhps(const Operand &src1, FloatRegister src0, FloatRegister dest) {
|
||||
MOZ_ASSERT(HasSSE2());
|
||||
switch (src1.kind()) {
|
||||
case Operand::FPREG:
|
||||
masm.vunpckhps_rr(src1.fpu(), src0.code(), dest.code());
|
||||
break;
|
||||
case Operand::MEM_REG_DISP:
|
||||
masm.vunpckhps_mr(src1.disp(), src1.base(), src0.code(), dest.code());
|
||||
break;
|
||||
case Operand::MEM_ADDRESS32:
|
||||
masm.vunpckhps_mr(src1.address(), src0.code(), dest.code());
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("unexpected operand kind");
|
||||
}
|
||||
}
|
||||
void vshufps(uint32_t mask, FloatRegister src1, FloatRegister src0, FloatRegister dest) {
|
||||
MOZ_ASSERT(HasSSE2());
|
||||
masm.vshufps_irr(mask, src1.code(), src0.code(), dest.code());
|
||||
@ -2324,6 +2356,19 @@ class AssemblerX86Shared : public AssemblerShared
|
||||
MOZ_ASSERT(HasSSE41());
|
||||
masm.vinsertps_irr(mask, src1.code(), src0.code(), dest.code());
|
||||
}
|
||||
void vinsertps(uint32_t mask, const Operand &src1, FloatRegister src0, FloatRegister dest) {
|
||||
MOZ_ASSERT(HasSSE41());
|
||||
switch (src1.kind()) {
|
||||
case Operand::FPREG:
|
||||
masm.vinsertps_irr(mask, src1.fpu(), src0.code(), dest.code());
|
||||
break;
|
||||
case Operand::MEM_REG_DISP:
|
||||
masm.vinsertps_imr(mask, src1.disp(), src1.base(), src0.code(), dest.code());
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("unexpected operand kind");
|
||||
}
|
||||
}
|
||||
unsigned blendpsMask(bool x, bool y, bool z, bool w) {
|
||||
return x | (y << 1) | (z << 2) | (w << 3);
|
||||
}
|
||||
|
@ -30,7 +30,8 @@
|
||||
#ifndef jit_shared_BaseAssembler_x86_shared_h
|
||||
#define jit_shared_BaseAssembler_x86_shared_h
|
||||
|
||||
#include <inttypes.h>
|
||||
#include "mozilla/IntegerPrintfMacros.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "jit/shared/AssemblerBuffer-x86-shared.h"
|
||||
@ -2938,11 +2939,27 @@ public:
|
||||
{
|
||||
twoByteOpSimd("vunpcklps", VEX_PS, OP2_UNPCKLPS_VsdWsd, src1, src0, dst);
|
||||
}
|
||||
void vunpcklps_mr(int32_t offset, RegisterID base, XMMRegisterID src0, XMMRegisterID dst)
|
||||
{
|
||||
twoByteOpSimd("vunpcklps", VEX_PS, OP2_UNPCKLPS_VsdWsd, offset, base, src0, dst);
|
||||
}
|
||||
void vunpcklps_mr(const void *addr, XMMRegisterID src0, XMMRegisterID dst)
|
||||
{
|
||||
twoByteOpSimd("vunpcklps", VEX_PS, OP2_UNPCKLPS_VsdWsd, addr, src0, dst);
|
||||
}
|
||||
|
||||
void vunpckhps_rr(XMMRegisterID src1, XMMRegisterID src0, XMMRegisterID dst)
|
||||
{
|
||||
twoByteOpSimd("vunpckhps", VEX_PS, OP2_UNPCKHPS_VsdWsd, src1, src0, dst);
|
||||
}
|
||||
void vunpckhps_mr(int32_t offset, RegisterID base, XMMRegisterID src0, XMMRegisterID dst)
|
||||
{
|
||||
twoByteOpSimd("vunpckhps", VEX_PS, OP2_UNPCKHPS_VsdWsd, offset, base, src0, dst);
|
||||
}
|
||||
void vunpckhps_mr(const void *addr, XMMRegisterID src0, XMMRegisterID dst)
|
||||
{
|
||||
twoByteOpSimd("vunpckhps", VEX_PS, OP2_UNPCKHPS_VsdWsd, addr, src0, dst);
|
||||
}
|
||||
|
||||
void vpand_rr(XMMRegisterID src1, XMMRegisterID src0, XMMRegisterID dst)
|
||||
{
|
||||
@ -3606,6 +3623,10 @@ public:
|
||||
{
|
||||
threeByteOpImmSimd("vinsertps", VEX_PD, OP3_INSERTPS_VpsUps, ESCAPE_INSERTPS, mask, src1, src0, dst);
|
||||
}
|
||||
void vinsertps_imr(uint32_t mask, int32_t offset, RegisterID base, XMMRegisterID src0, XMMRegisterID dst)
|
||||
{
|
||||
threeByteOpImmSimd("vinsertps", VEX_PD, OP3_INSERTPS_VpsUps, ESCAPE_INSERTPS, mask, offset, base, src0, dst);
|
||||
}
|
||||
|
||||
void vpinsrd_irr(unsigned lane, RegisterID src1, XMMRegisterID src0, XMMRegisterID dst)
|
||||
{
|
||||
|
@ -30,7 +30,10 @@ BaselineCompilerShared::BaselineCompilerShared(JSContext *cx, TempAllocator &all
|
||||
icLoadLabels_(),
|
||||
pushedBeforeCall_(0),
|
||||
inCall_(false),
|
||||
spsPushToggleOffset_()
|
||||
spsPushToggleOffset_(),
|
||||
traceLoggerEnterToggleOffset_(),
|
||||
traceLoggerExitToggleOffset_(),
|
||||
traceLoggerScriptTextIdOffset_()
|
||||
{ }
|
||||
|
||||
bool
|
||||
|
@ -68,6 +68,9 @@ class BaselineCompilerShared
|
||||
mozilla::DebugOnly<bool> inCall_;
|
||||
|
||||
CodeOffsetLabel spsPushToggleOffset_;
|
||||
CodeOffsetLabel traceLoggerEnterToggleOffset_;
|
||||
CodeOffsetLabel traceLoggerExitToggleOffset_;
|
||||
CodeOffsetLabel traceLoggerScriptTextIdOffset_;
|
||||
|
||||
BaselineCompilerShared(JSContext *cx, TempAllocator &alloc, JSScript *script);
|
||||
|
||||
|
@ -1020,7 +1020,7 @@ CodeGeneratorShared::callVM(const VMFunction &fun, LInstruction *ins, const Regi
|
||||
#endif
|
||||
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
emitTracelogStartEvent(TraceLogger::VM);
|
||||
emitTracelogStartEvent(TraceLogger_VM);
|
||||
#endif
|
||||
|
||||
// Stack is:
|
||||
@ -1065,7 +1065,7 @@ CodeGeneratorShared::callVM(const VMFunction &fun, LInstruction *ins, const Regi
|
||||
// ... frame ...
|
||||
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
emitTracelogStopEvent(TraceLogger::VM);
|
||||
emitTracelogStopEvent(TraceLogger_VM);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -1398,9 +1398,12 @@ CodeGeneratorShared::computeDivisionConstants(int d) {
|
||||
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
|
||||
bool
|
||||
void
|
||||
CodeGeneratorShared::emitTracelogScript(bool isStart)
|
||||
{
|
||||
if (!TraceLogTextIdEnabled(TraceLogger_Scripts))
|
||||
return;
|
||||
|
||||
Label done;
|
||||
|
||||
RegisterSet regs = RegisterSet::Volatile();
|
||||
@ -1410,36 +1413,33 @@ CodeGeneratorShared::emitTracelogScript(bool isStart)
|
||||
masm.Push(logger);
|
||||
|
||||
CodeOffsetLabel patchLogger = masm.movWithPatch(ImmPtr(nullptr), logger);
|
||||
if (!patchableTraceLoggers_.append(patchLogger))
|
||||
return false;
|
||||
masm.propagateOOM(patchableTraceLoggers_.append(patchLogger));
|
||||
|
||||
Address enabledAddress(logger, TraceLogger::offsetOfEnabled());
|
||||
Address enabledAddress(logger, TraceLoggerThread::offsetOfEnabled());
|
||||
masm.branch32(Assembler::Equal, enabledAddress, Imm32(0), &done);
|
||||
|
||||
masm.Push(script);
|
||||
|
||||
CodeOffsetLabel patchScript = masm.movWithPatch(ImmWord(0), script);
|
||||
if (!patchableTLScripts_.append(patchScript))
|
||||
return false;
|
||||
masm.propagateOOM(patchableTLScripts_.append(patchScript));
|
||||
|
||||
if (isStart)
|
||||
masm.tracelogStart(logger, script);
|
||||
masm.tracelogStartId(logger, script);
|
||||
else
|
||||
masm.tracelogStop(logger, script);
|
||||
masm.tracelogStopId(logger, script);
|
||||
|
||||
masm.Pop(script);
|
||||
|
||||
masm.bind(&done);
|
||||
|
||||
masm.Pop(logger);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
void
|
||||
CodeGeneratorShared::emitTracelogTree(bool isStart, uint32_t textId)
|
||||
{
|
||||
if (!TraceLogTextIdEnabled(textId))
|
||||
return true;
|
||||
return;
|
||||
|
||||
Label done;
|
||||
RegisterSet regs = RegisterSet::Volatile();
|
||||
@ -1448,26 +1448,19 @@ CodeGeneratorShared::emitTracelogTree(bool isStart, uint32_t textId)
|
||||
masm.Push(logger);
|
||||
|
||||
CodeOffsetLabel patchLocation = masm.movWithPatch(ImmPtr(nullptr), logger);
|
||||
if (!patchableTraceLoggers_.append(patchLocation))
|
||||
return false;
|
||||
masm.propagateOOM(patchableTraceLoggers_.append(patchLocation));
|
||||
|
||||
Address enabledAddress(logger, TraceLogger::offsetOfEnabled());
|
||||
Address enabledAddress(logger, TraceLoggerThread::offsetOfEnabled());
|
||||
masm.branch32(Assembler::Equal, enabledAddress, Imm32(0), &done);
|
||||
|
||||
if (isStart) {
|
||||
masm.tracelogStart(logger, textId);
|
||||
} else {
|
||||
#ifdef DEBUG
|
||||
masm.tracelogStop(logger, textId);
|
||||
#else
|
||||
masm.tracelogStop(logger);
|
||||
#endif
|
||||
}
|
||||
if (isStart)
|
||||
masm.tracelogStartId(logger, textId);
|
||||
else
|
||||
masm.tracelogStopId(logger, textId);
|
||||
|
||||
masm.bind(&done);
|
||||
|
||||
masm.Pop(logger);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -58,10 +58,8 @@ CodeGeneratorX86Shared::generateEpilogue()
|
||||
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
if (gen->info().executionMode() == SequentialExecution) {
|
||||
if (!emitTracelogStopEvent(TraceLogger::IonMonkey))
|
||||
return false;
|
||||
if (!emitTracelogScriptStop())
|
||||
return false;
|
||||
emitTracelogStopEvent(TraceLogger_IonMonkey);
|
||||
emitTracelogScriptStop();
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -2145,9 +2143,8 @@ CodeGeneratorX86Shared::visitSimdSplatX4(LSimdSplatX4 *ins)
|
||||
}
|
||||
case MIRType_Float32x4: {
|
||||
FloatRegister r = ToFloatRegister(ins->getOperand(0));
|
||||
if (r != output)
|
||||
masm.moveFloat32x4(r, output);
|
||||
masm.vshufps(0, output, output, output);
|
||||
FloatRegister rCopy = masm.reusedInputFloat32x4(r, output);
|
||||
masm.vshufps(0, rCopy, rCopy, output);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@ -2191,7 +2188,12 @@ CodeGeneratorX86Shared::visitSimdExtractElementF(LSimdExtractElementF *ins)
|
||||
uint32_t mask = MacroAssembler::ComputeShuffleMask(lane);
|
||||
masm.shuffleFloat32(mask, input, output);
|
||||
}
|
||||
masm.canonicalizeFloat(output);
|
||||
// NaNs contained within SIMD values are not enforced to be canonical, so
|
||||
// when we extract an element into a "regular" scalar JS value, we have to
|
||||
// canonicalize. In asm.js code, we can skip this, as asm.js only has to
|
||||
// canonicalize NaNs at FFI boundaries.
|
||||
if (!gen->compilingAsmJS())
|
||||
masm.canonicalizeFloat(output);
|
||||
}
|
||||
|
||||
void
|
||||
@ -2331,9 +2333,8 @@ void
|
||||
CodeGeneratorX86Shared::visitSimdShuffle(LSimdShuffle *ins)
|
||||
{
|
||||
FloatRegister lhs = ToFloatRegister(ins->lhs());
|
||||
FloatRegister rhs = ToFloatRegister(ins->rhs());
|
||||
Operand rhs = ToOperand(ins->rhs());
|
||||
FloatRegister out = ToFloatRegister(ins->output());
|
||||
MOZ_ASSERT(out == lhs); // define reuse input
|
||||
|
||||
uint32_t x = ins->laneX();
|
||||
uint32_t y = ins->laneY();
|
||||
@ -2372,8 +2373,8 @@ CodeGeneratorX86Shared::visitSimdShuffle(LSimdShuffle *ins)
|
||||
unsigned firstMask = -1, secondMask = -1;
|
||||
|
||||
// register-register vmovss preserves the high lanes.
|
||||
if (ins->lanesMatch(4, 1, 2, 3)) {
|
||||
masm.vmovss(rhs, lhs, out);
|
||||
if (ins->lanesMatch(4, 1, 2, 3) && rhs.kind() == Operand::FPREG) {
|
||||
masm.vmovss(FloatRegister::FromCode(rhs.fpu()), lhs, out);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -2396,7 +2397,7 @@ CodeGeneratorX86Shared::visitSimdShuffle(LSimdShuffle *ins)
|
||||
srcLane = SimdLane(w - 4);
|
||||
dstLane = LaneW;
|
||||
}
|
||||
masm.vinsertps(masm.vinsertpsMask(srcLane, dstLane), rhs, out, out);
|
||||
masm.vinsertps(masm.vinsertpsMask(srcLane, dstLane), rhs, lhs, out);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -2405,21 +2406,21 @@ CodeGeneratorX86Shared::visitSimdShuffle(LSimdShuffle *ins)
|
||||
if (x < 4 && y < 4) {
|
||||
if (w >= 4) {
|
||||
w %= 4;
|
||||
// T = (Rw Rw Lz Lz) = vshufps(firstMask, lhs, rhs, rhs)
|
||||
// T = (Rw Rw Lz Lz) = vshufps(firstMask, lhs, rhs, rhsCopy)
|
||||
firstMask = MacroAssembler::ComputeShuffleMask(w, w, z, z);
|
||||
// (Lx Ly Lz Rw) = (Lx Ly Tz Tx) = vshufps(secondMask, T, lhs, lhs)
|
||||
// (Lx Ly Lz Rw) = (Lx Ly Tz Tx) = vshufps(secondMask, T, lhs, out)
|
||||
secondMask = MacroAssembler::ComputeShuffleMask(x, y, LaneZ, LaneX);
|
||||
} else {
|
||||
MOZ_ASSERT(z >= 4);
|
||||
z %= 4;
|
||||
// T = (Rz Rz Lw Lw) = vshufps(firstMask, lhs, rhs, rhs)
|
||||
// T = (Rz Rz Lw Lw) = vshufps(firstMask, lhs, rhs, rhsCopy)
|
||||
firstMask = MacroAssembler::ComputeShuffleMask(z, z, w, w);
|
||||
// (Lx Ly Rz Lw) = (Lx Ly Tx Tz) = vshufps(secondMask, T, lhs, lhs)
|
||||
// (Lx Ly Rz Lw) = (Lx Ly Tx Tz) = vshufps(secondMask, T, lhs, out)
|
||||
secondMask = MacroAssembler::ComputeShuffleMask(x, y, LaneX, LaneZ);
|
||||
}
|
||||
|
||||
masm.vshufps(firstMask, lhs, rhsCopy, rhsCopy);
|
||||
masm.vshufps(secondMask, rhsCopy, lhs, lhs);
|
||||
masm.vshufps(secondMask, rhsCopy, lhs, out);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -2427,22 +2428,26 @@ CodeGeneratorX86Shared::visitSimdShuffle(LSimdShuffle *ins)
|
||||
|
||||
if (y >= 4) {
|
||||
y %= 4;
|
||||
// T = (Ry Ry Lx Lx) = vshufps(firstMask, lhs, rhs, rhs)
|
||||
// T = (Ry Ry Lx Lx) = vshufps(firstMask, lhs, rhs, rhsCopy)
|
||||
firstMask = MacroAssembler::ComputeShuffleMask(y, y, x, x);
|
||||
// (Lx Ry Lz Lw) = (Tz Tx Lz Lw) = vshufps(secondMask, lhs, T, T)
|
||||
// (Lx Ry Lz Lw) = (Tz Tx Lz Lw) = vshufps(secondMask, lhs, T, out)
|
||||
secondMask = MacroAssembler::ComputeShuffleMask(LaneZ, LaneX, z, w);
|
||||
} else {
|
||||
MOZ_ASSERT(x >= 4);
|
||||
x %= 4;
|
||||
// T = (Rx Rx Ly Ly) = vshufps(firstMask, lhs, rhs, rhs)
|
||||
// T = (Rx Rx Ly Ly) = vshufps(firstMask, lhs, rhs, rhsCopy)
|
||||
firstMask = MacroAssembler::ComputeShuffleMask(x, x, y, y);
|
||||
// (Rx Ly Lz Lw) = (Tx Tz Lz Lw) = vshufps(secondMask, lhs, T, T)
|
||||
// (Rx Ly Lz Lw) = (Tx Tz Lz Lw) = vshufps(secondMask, lhs, T, out)
|
||||
secondMask = MacroAssembler::ComputeShuffleMask(LaneX, LaneZ, z, w);
|
||||
}
|
||||
|
||||
masm.vshufps(firstMask, lhs, rhsCopy, rhsCopy);
|
||||
masm.vshufps(secondMask, lhs, rhsCopy, rhsCopy);
|
||||
masm.moveFloat32x4(rhsCopy, out);
|
||||
if (AssemblerX86Shared::HasAVX()) {
|
||||
masm.vshufps(secondMask, lhs, rhsCopy, out);
|
||||
} else {
|
||||
masm.vshufps(secondMask, lhs, rhsCopy, rhsCopy);
|
||||
masm.moveFloat32x4(rhsCopy, out);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@ -2453,9 +2458,10 @@ CodeGeneratorX86Shared::visitSimdShuffle(LSimdShuffle *ins)
|
||||
// but can't be reached because operands would get swapped (bug 1084404).
|
||||
if (ins->lanesMatch(2, 3, 6, 7)) {
|
||||
if (AssemblerX86Shared::HasAVX()) {
|
||||
masm.vmovhlps(lhs, rhs, out);
|
||||
FloatRegister rhsCopy = masm.reusedInputAlignedFloat32x4(rhs, ScratchSimdReg);
|
||||
masm.vmovhlps(lhs, rhsCopy, out);
|
||||
} else {
|
||||
masm.moveFloat32x4(rhs, ScratchSimdReg);
|
||||
masm.loadAlignedFloat32x4(rhs, ScratchSimdReg);
|
||||
masm.vmovhlps(lhs, ScratchSimdReg, ScratchSimdReg);
|
||||
masm.moveFloat32x4(ScratchSimdReg, out);
|
||||
}
|
||||
@ -2463,7 +2469,16 @@ CodeGeneratorX86Shared::visitSimdShuffle(LSimdShuffle *ins)
|
||||
}
|
||||
|
||||
if (ins->lanesMatch(0, 1, 4, 5)) {
|
||||
masm.vmovlhps(rhs, lhs, out);
|
||||
FloatRegister rhsCopy;
|
||||
if (rhs.kind() == Operand::FPREG) {
|
||||
// No need to make an actual copy, since the operand is already
|
||||
// in a register, and it won't be clobbered by the vmovlhps.
|
||||
rhsCopy = FloatRegister::FromCode(rhs.fpu());
|
||||
} else {
|
||||
masm.loadAlignedFloat32x4(rhs, ScratchSimdReg);
|
||||
rhsCopy = ScratchSimdReg;
|
||||
}
|
||||
masm.vmovlhps(rhsCopy, lhs, out);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -2475,9 +2490,10 @@ CodeGeneratorX86Shared::visitSimdShuffle(LSimdShuffle *ins)
|
||||
// TODO swapped case would be better (bug 1084404)
|
||||
if (ins->lanesMatch(4, 0, 5, 1)) {
|
||||
if (AssemblerX86Shared::HasAVX()) {
|
||||
masm.vunpcklps(lhs, rhs, out);
|
||||
FloatRegister rhsCopy = masm.reusedInputAlignedFloat32x4(rhs, ScratchSimdReg);
|
||||
masm.vunpcklps(lhs, rhsCopy, out);
|
||||
} else {
|
||||
masm.moveFloat32x4(rhs, ScratchSimdReg);
|
||||
masm.loadAlignedFloat32x4(rhs, ScratchSimdReg);
|
||||
masm.vunpcklps(lhs, ScratchSimdReg, ScratchSimdReg);
|
||||
masm.moveFloat32x4(ScratchSimdReg, out);
|
||||
}
|
||||
@ -2485,16 +2501,17 @@ CodeGeneratorX86Shared::visitSimdShuffle(LSimdShuffle *ins)
|
||||
}
|
||||
|
||||
if (ins->lanesMatch(2, 6, 3, 7)) {
|
||||
masm.vunpckhps(rhs, lhs, lhs);
|
||||
masm.vunpckhps(rhs, lhs, out);
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO swapped case would be better (bug 1084404)
|
||||
if (ins->lanesMatch(6, 2, 7, 3)) {
|
||||
if (AssemblerX86Shared::HasAVX()) {
|
||||
masm.vunpckhps(lhs, rhs, out);
|
||||
FloatRegister rhsCopy = masm.reusedInputAlignedFloat32x4(rhs, ScratchSimdReg);
|
||||
masm.vunpckhps(lhs, rhsCopy, out);
|
||||
} else {
|
||||
masm.moveFloat32x4(rhs, ScratchSimdReg);
|
||||
masm.loadAlignedFloat32x4(rhs, ScratchSimdReg);
|
||||
masm.vunpckhps(lhs, ScratchSimdReg, ScratchSimdReg);
|
||||
masm.moveFloat32x4(ScratchSimdReg, out);
|
||||
}
|
||||
@ -2504,7 +2521,7 @@ CodeGeneratorX86Shared::visitSimdShuffle(LSimdShuffle *ins)
|
||||
// In one vshufps
|
||||
if (x < 4 && y < 4) {
|
||||
mask = MacroAssembler::ComputeShuffleMask(x, y, z % 4, w % 4);
|
||||
masm.vshufps(mask, rhs, out, out);
|
||||
masm.vshufps(mask, rhs, lhs, out);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -155,9 +155,9 @@ LIRGeneratorX86Shared::lowerForBitAndAndBranch(LBitAndAndBranch *baab, MInstruct
|
||||
void
|
||||
LIRGeneratorX86Shared::lowerMulI(MMul *mul, MDefinition *lhs, MDefinition *rhs)
|
||||
{
|
||||
// Note: lhs is used twice, so that we can restore the original value for the
|
||||
// negative zero check.
|
||||
LMulI *lir = new(alloc()) LMulI(useRegisterAtStart(lhs), useOrConstant(rhs), use(lhs));
|
||||
// Note: If we need a negative zero check, lhs is used twice.
|
||||
LAllocation lhsCopy = mul->canBeNegativeZero() ? use(lhs) : LAllocation();
|
||||
LMulI *lir = new(alloc()) LMulI(useRegisterAtStart(lhs), useOrConstant(rhs), lhsCopy);
|
||||
if (mul->fallible())
|
||||
assignSnapshot(lir, Bailout_DoubleOutput);
|
||||
defineReuseInput(lir, mul, 0);
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user