Merge m-c to b2g-inbound a=merge

This commit is contained in:
Wes Kocher 2014-12-30 16:05:28 -08:00
commit c6fa0d9891
150 changed files with 7277 additions and 2916 deletions

View File

@ -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;

View File

@ -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,

View File

@ -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,

View File

@ -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.

View 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):

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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;
}

View File

@ -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)
{

View File

@ -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,

View File

@ -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.
*/

View File

@ -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".

View File

@ -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.

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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;
};

View File

@ -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()));

View File

@ -102,6 +102,7 @@ EXPORTS += [
'MediaDecoderOwner.h',
'MediaDecoderReader.h',
'MediaDecoderStateMachine.h',
'MediaDecoderStateMachineScheduler.h',
'MediaInfo.h',
'MediaMetadataManager.h',
'MediaPromise.h',

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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);

View File

@ -523,7 +523,7 @@ nsNPAPIPluginInstance::Start()
return NS_ERROR_FAILURE;
}
return NS_OK;
return newResult;
}
nsresult nsNPAPIPluginInstance::SetWindow(NPWindow* window)

View File

@ -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,

View File

@ -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);

View File

@ -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)
{

View File

@ -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;

View File

@ -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) {

View File

@ -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();

View File

@ -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)
{

View File

@ -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;

View File

@ -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;

View File

@ -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; }

View File

@ -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;
}

View File

@ -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

View File

@ -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);

View File

@ -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,

View File

@ -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.
*

View 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

View 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

View 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

View File

@ -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

View File

@ -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)

View File

@ -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;
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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);
};

View File

@ -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);
}
}

View File

@ -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?!");

View File

@ -16,6 +16,7 @@
namespace mozilla {
namespace plugins {
class PluginAsyncSurrogate;
class PluginInstanceParent;
class PluginScriptableObjectParent;

View File

@ -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',

View File

@ -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");
}
}

View File

@ -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)

View File

@ -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)

View File

@ -154,3 +154,4 @@ skip-if = e10s
[test_spellcheck_pref.html]
skip-if = toolkit == 'android'
[test_bug1068979.html]
[test_bug1109465.html]

View 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>

View File

@ -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)
{

View File

@ -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

View File

@ -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) {

View File

@ -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.

View File

@ -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!");
}

View File

@ -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;

View File

@ -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.

View File

@ -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

View File

@ -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.

View 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));
}

View 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");
}

View File

@ -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());

View File

@ -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);

View File

@ -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()
{

View File

@ -254,6 +254,8 @@ class BaselineCompiler : public BaselineCompilerSpecific
bool emitArgumentTypeChecks();
bool emitDebugPrologue();
bool emitDebugTrap();
bool emitTraceLoggerEnter();
bool emitTraceLoggerExit();
bool emitSPSPush();
void emitSPSPop();

View File

@ -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)
{

View File

@ -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.

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -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_;
}

View File

@ -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();

View File

@ -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);

View File

@ -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

View File

@ -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());
}

View File

@ -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) \

View File

@ -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);

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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);
}

View File

@ -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)
{

View File

@ -30,7 +30,10 @@ BaselineCompilerShared::BaselineCompilerShared(JSContext *cx, TempAllocator &all
icLoadLabels_(),
pushedBeforeCall_(0),
inCall_(false),
spsPushToggleOffset_()
spsPushToggleOffset_(),
traceLoggerEnterToggleOffset_(),
traceLoggerExitToggleOffset_(),
traceLoggerScriptTextIdOffset_()
{ }
bool

View File

@ -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);

View File

@ -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

View File

@ -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;
}

View File

@ -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