Merge mozilla-central to b2g-inbound

This commit is contained in:
Carsten "Tomcat" Book 2015-01-29 16:24:07 +01:00
Родитель 2dd63b97e6 395905d963
Коммит 649363b3d7
131 изменённых файлов: 4408 добавлений и 1032 удалений

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

@ -1188,6 +1188,10 @@ pref("security.sandbox.windows.log", false);
pref("dom.ipc.plugins.sandbox.default", false);
pref("dom.ipc.plugins.sandbox.flash", true);
// This controls whether the Windows NPAPI process sandbox is using a more
// strict sandboxing policy. This will require a restart.
pref("dom.ipc.plugins.moreStrictSandbox", false);
#if defined(MOZ_CONTENT_SANDBOX)
// This controls whether the Windows content process sandbox is using a more
// strict sandboxing policy. This will require a restart.

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

@ -16,7 +16,7 @@ Cu.import("resource://gre/modules/FxAccountsCommon.js", fxAccountsCommon);
Cu.import("resource://services-sync/util.js");
const PREF_LAST_FXA_USER = "identity.fxaccounts.lastSignedInUserHash";
const PREF_SYNC_SHOW_CUSTOMIZATION = "services.sync.ui.showCustomizationDialog";
const PREF_SYNC_SHOW_CUSTOMIZATION = "services.sync-setup.ui.showCustomizationDialog";
const ACTION_URL_PARAM = "action";

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

@ -4,8 +4,6 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#endif
Cu.import("resource://gre/modules/NewTabUtils.jsm");
/**
* Keeps thumbnails of open web pages up-to-date.
*/

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

@ -3872,7 +3872,10 @@ function OpenBrowserWindow(options)
}
if (options && options.remote) {
let omtcEnabled = gPrefService.getBoolPref("layers.offmainthreadcomposition.enabled");
// If we're using remote tabs by default, then OMTC will be force-enabled,
// despite the preference returning as false.
let omtcEnabled = gPrefService.getBoolPref("layers.offmainthreadcomposition.enabled")
|| Services.appinfo.browserTabsRemoteAutostart;
if (!omtcEnabled) {
alert("To use out-of-process tabs, you must set the layers.offmainthreadcomposition.enabled preference and restart. Opening a normal window instead.");
} else {

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

@ -33,8 +33,12 @@ const PREF_LOG_LEVEL = "browser.uitour.loglevel";
const PREF_SEENPAGEIDS = "browser.uitour.seenPageIDs";
const BACKGROUND_PAGE_ACTIONS_ALLOWED = new Set([
"endUrlbarCapture",
"getConfiguration",
"getTreatmentTag",
"hideHighlight",
"hideInfo",
"hideMenu",
"ping",
"registerPageID",
"setConfiguration",

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

@ -505,7 +505,7 @@ IsFeatureInBlacklist(const nsCOMPtr<nsIGfxInfo>& gfxInfo, int32_t feature)
static already_AddRefed<GLContext>
CreateHeadlessNativeGL(bool forceEnabled, const nsCOMPtr<nsIGfxInfo>& gfxInfo,
WebGLContext* webgl)
bool requireCompatProfile, WebGLContext* webgl)
{
if (!forceEnabled &&
IsFeatureInBlacklist(gfxInfo, nsIGfxInfo::FEATURE_WEBGL_OPENGL))
@ -515,7 +515,7 @@ CreateHeadlessNativeGL(bool forceEnabled, const nsCOMPtr<nsIGfxInfo>& gfxInfo,
return nullptr;
}
nsRefPtr<GLContext> gl = gl::GLContextProvider::CreateHeadless();
nsRefPtr<GLContext> gl = gl::GLContextProvider::CreateHeadless(requireCompatProfile);
if (!gl) {
webgl->GenerateWarning("Error during native OpenGL init.");
return nullptr;
@ -530,7 +530,7 @@ CreateHeadlessNativeGL(bool forceEnabled, const nsCOMPtr<nsIGfxInfo>& gfxInfo,
// Eventually, we want to be able to pick ANGLE-EGL or native EGL.
static already_AddRefed<GLContext>
CreateHeadlessANGLE(bool forceEnabled, const nsCOMPtr<nsIGfxInfo>& gfxInfo,
WebGLContext* webgl)
bool requireCompatProfile, WebGLContext* webgl)
{
nsRefPtr<GLContext> gl;
@ -543,7 +543,7 @@ CreateHeadlessANGLE(bool forceEnabled, const nsCOMPtr<nsIGfxInfo>& gfxInfo,
return nullptr;
}
gl = gl::GLContextProviderEGL::CreateHeadless();
gl = gl::GLContextProviderEGL::CreateHeadless(requireCompatProfile);
if (!gl) {
webgl->GenerateWarning("Error during ANGLE OpenGL init.");
return nullptr;
@ -555,13 +555,13 @@ CreateHeadlessANGLE(bool forceEnabled, const nsCOMPtr<nsIGfxInfo>& gfxInfo,
}
static already_AddRefed<GLContext>
CreateHeadlessEGL(bool forceEnabled, const nsCOMPtr<nsIGfxInfo>& gfxInfo,
CreateHeadlessEGL(bool forceEnabled, bool requireCompatProfile,
WebGLContext* webgl)
{
nsRefPtr<GLContext> gl;
#ifdef ANDROID
gl = gl::GLContextProviderEGL::CreateHeadless();
gl = gl::GLContextProviderEGL::CreateHeadless(requireCompatProfile);
if (!gl) {
webgl->GenerateWarning("Error during EGL OpenGL init.");
return nullptr;
@ -583,16 +583,22 @@ CreateHeadlessGL(bool forceEnabled, const nsCOMPtr<nsIGfxInfo>& gfxInfo,
if (PR_GetEnv("MOZ_WEBGL_FORCE_OPENGL"))
disableANGLE = true;
bool requireCompatProfile = webgl->IsWebGL2() ? false : true;
nsRefPtr<GLContext> gl;
if (preferEGL)
gl = CreateHeadlessEGL(forceEnabled, gfxInfo, webgl);
gl = CreateHeadlessEGL(forceEnabled, requireCompatProfile, webgl);
if (!gl && !disableANGLE)
gl = CreateHeadlessANGLE(forceEnabled, gfxInfo, webgl);
if (!gl && !disableANGLE) {
gl = CreateHeadlessANGLE(forceEnabled, gfxInfo, requireCompatProfile,
webgl);
}
if (!gl)
gl = CreateHeadlessNativeGL(forceEnabled, gfxInfo, webgl);
if (!gl) {
gl = CreateHeadlessNativeGL(forceEnabled, gfxInfo,
requireCompatProfile, webgl);
}
return gl.forget();
}

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

@ -1209,9 +1209,10 @@ protected:
// -------------------------------------------------------------------------
// WebGL 2 specifics (implemented in WebGL2Context.cpp)
public:
virtual bool IsWebGL2() const = 0;
protected:
bool InitWebGL2();
// -------------------------------------------------------------------------

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

@ -2107,7 +2107,6 @@ WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width,
// if we're reading alpha, we may need to do fixup. Note that we don't allow
// GL_ALPHA to readpixels currently, but we had the code written for it already.
const bool formatHasAlpha = format == LOCAL_GL_ALPHA ||
format == LOCAL_GL_RGBA;
if (!formatHasAlpha)

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

@ -1117,11 +1117,12 @@ WebGLContext::AssertCachedState()
AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_CLEAR_VALUE, mStencilClearValue);
GLint stencilBits = 0;
gl->fGetIntegerv(LOCAL_GL_STENCIL_BITS, &stencilBits);
const GLuint stencilRefMask = (1 << stencilBits) - 1;
if (GetStencilBits(&stencilBits)) {
const GLuint stencilRefMask = (1 << stencilBits) - 1;
AssertMaskedUintParamCorrect(gl, LOCAL_GL_STENCIL_REF, stencilRefMask, mStencilRefFront);
AssertMaskedUintParamCorrect(gl, LOCAL_GL_STENCIL_BACK_REF, stencilRefMask, mStencilRefBack);
AssertMaskedUintParamCorrect(gl, LOCAL_GL_STENCIL_REF, stencilRefMask, mStencilRefFront);
AssertMaskedUintParamCorrect(gl, LOCAL_GL_STENCIL_BACK_REF, stencilRefMask, mStencilRefBack);
}
AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_VALUE_MASK, mStencilValueMaskFront);
AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_BACK_VALUE_MASK, mStencilValueMaskBack);

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

@ -1779,8 +1779,8 @@ WebGLContext::InitAndValidateGL()
MakeContextCurrent();
// on desktop OpenGL, we always keep vertex attrib 0 array enabled
if (!gl->IsGLES())
// For OpenGL compat. profiles, we always keep vertex attrib 0 array enabled.
if (gl->IsCompatibilityProfile())
gl->fEnableVertexAttribArray(0);
if (MinCapabilityMode())
@ -1889,7 +1889,7 @@ WebGLContext::InitAndValidateGL()
// Always 1 for GLES2
mMaxFramebufferColorAttachments = 1;
if (!gl->IsGLES()) {
if (gl->IsCompatibilityProfile()) {
// gl_PointSize is always available in ES2 GLSL, but has to be
// specifically enabled on desktop GLSL.
gl->fEnable(LOCAL_GL_VERTEX_PROGRAM_POINT_SIZE);

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

@ -3303,6 +3303,15 @@ bool HTMLMediaElement::ShouldCheckAllowOrigin()
return mCORSMode != CORS_NONE;
}
bool HTMLMediaElement::IsCORSSameOrigin()
{
bool subsumes;
nsRefPtr<nsIPrincipal> principal = GetCurrentPrincipal();
return
(NS_SUCCEEDED(NodePrincipal()->Subsumes(principal, &subsumes)) && subsumes) ||
ShouldCheckAllowOrigin();
}
void HTMLMediaElement::UpdateReadyStateForData(MediaDecoderOwner::NextFrameStatus aNextFrame)
{
mLastNextFrameStatus = aNextFrame;
@ -3648,22 +3657,13 @@ void HTMLMediaElement::NotifyDecoderPrincipalChanged()
{
nsRefPtr<nsIPrincipal> principal = GetCurrentPrincipal();
bool subsumes;
mDecoder->UpdateSameOriginStatus(
!principal ||
(NS_SUCCEEDED(NodePrincipal()->Subsumes(principal, &subsumes)) && subsumes) ||
mCORSMode != CORS_NONE);
mDecoder->UpdateSameOriginStatus(!principal || IsCORSSameOrigin());
for (uint32_t i = 0; i < mOutputStreams.Length(); ++i) {
OutputMediaStream* ms = &mOutputStreams[i];
ms->mStream->SetCORSMode(mCORSMode);
ms->mStream->CombineWithPrincipal(principal);
}
#ifdef MOZ_EME
if (mMediaKeys && NS_FAILED(mMediaKeys->CheckPrincipals())) {
mMediaKeys->Shutdown();
}
#endif
}
void HTMLMediaElement::UpdateMediaSize(nsIntSize size)
@ -4307,8 +4307,6 @@ HTMLMediaElement::SetMediaKeys(mozilla::dom::MediaKeys* aMediaKeys,
if (mDecoder) {
mDecoder->SetCDMProxy(mMediaKeys->GetCDMProxy());
}
// Update the same-origin status.
NotifyDecoderPrincipalChanged();
}
promise->MaybeResolve(JS::UndefinedHandleValue);
return promise.forget();
@ -4341,8 +4339,13 @@ void
HTMLMediaElement::DispatchEncrypted(const nsTArray<uint8_t>& aInitData,
const nsAString& aInitDataType)
{
nsRefPtr<MediaEncryptedEvent> event(
MediaEncryptedEvent::Constructor(this, aInitDataType, aInitData));
nsRefPtr<MediaEncryptedEvent> event;
if (IsCORSSameOrigin()) {
event = MediaEncryptedEvent::Constructor(this, aInitDataType, aInitData);
} else {
event = MediaEncryptedEvent::Constructor(this);
}
nsRefPtr<AsyncEventDispatcher> asyncDispatcher =
new AsyncEventDispatcher(this, event);
asyncDispatcher->PostDOMEvent();

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

@ -245,6 +245,10 @@ public:
// Check if the media element had crossorigin set when loading started
bool ShouldCheckAllowOrigin();
// Returns true if the currently loaded resource is CORS same-origin with
// respect to the document.
bool IsCORSSameOrigin();
// Is the media element potentially playing as defined by the HTML 5 specification.
// http://www.whatwg.org/specs/web-apps/current-work/#potentially-playing
bool IsPotentiallyPlaying() const;

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

@ -4,7 +4,18 @@ BlockMixedDisplayContent = Blocked loading mixed display content "%1$S"
BlockMixedActiveContent = Blocked loading mixed active content "%1$S"
# CORS
CrossSiteRequestBlocked=Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at %1$S. This can be fixed by moving the resource to the same domain or enabling CORS.
# LOCALIZATION NOTE: Do not translate "Access-Control-Allow-Origin", Access-Control-Allow-Credentials, Access-Control-Allow-Methods, Access-Control-Allow-Headers
CORSDisabled=Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at %1$S. (Reason: CORS disabled).
CORSRequestFailed=Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at %1$S. (Reason: CORS request failed).
CORSRequestNotHttp=Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at %1$S. (Reason: CORS request not http).
CORSMissingAllowOrigin=Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at %1$S. (Reason: CORS header 'Access-Control-Allow-Origin' missing).
CORSAllowOriginNotMatchingOrigin=Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at %1$S. (Reason: CORS header 'Access-Control-Allow-Origin' does not match '%2$S').
CORSMethodNotFound=Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at %1$S. (Reason: Did not find method in CORS header 'Access-Control-Allow-Methods').
CORSMissingAllowCredentials=Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at %1$S. (Reason: expected 'true' in CORS header 'Access-Control-Allow-Credentials').
CORSPreflightDidNotSucceed=Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at %1$S. (Reason: CORS preflight channel did not succeed).
CORSInvalidAllowMethod=Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at %1$S. (Reason: invalid token '%2$S' in CORS header 'Access-Control-Allow-Methods').
CORSInvalidAllowHeader=Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at %1$S. (Reason: invalid token '%2$S' in CORS header 'Access-Control-Allow-Headers').
CORSMissingAllowHeaderFromPreflight=Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at %1$S. (Reason: missing token '%2$S' in CORS header 'Access-Control-Allow-Headers' from CORS preflight channel"));
# LOCALIZATION NOTE: Do not translate "Strict-Transport-Security" or "HSTS"
InvalidSTSHeaders=The site specified an invalid Strict-Transport-Security header.

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

@ -1578,9 +1578,9 @@ void MediaDecoderStateMachine::StartDecoding()
void MediaDecoderStateMachine::StartWaitForResources()
{
NS_ASSERTION(OnStateMachineThread() || OnDecodeThread(),
"Should be on state machine or decode thread.");
AssertCurrentThreadInMonitor();
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
NS_ASSERTION(OnDecodeThread(),
"Should be on decode thread.");
SetState(DECODER_STATE_WAIT_FOR_RESOURCES);
DECODER_LOG("StartWaitForResources");
}
@ -1967,7 +1967,7 @@ MediaDecoderStateMachine::EnsureAudioDecodeTaskQueued()
SAMPLE_LOG("EnsureAudioDecodeTaskQueued isDecoding=%d status=%d",
IsAudioDecoding(), mAudioRequestStatus);
if (mState >= DECODER_STATE_COMPLETED) {
if (mState >= DECODER_STATE_COMPLETED || mState == DECODER_STATE_DORMANT) {
return NS_OK;
}
@ -2012,7 +2012,7 @@ MediaDecoderStateMachine::EnsureVideoDecodeTaskQueued()
NS_ASSERTION(OnStateMachineThread() || OnDecodeThread(),
"Should be on state machine or decode thread.");
if (mState >= DECODER_STATE_COMPLETED) {
if (mState >= DECODER_STATE_COMPLETED || mState == DECODER_STATE_DORMANT) {
return NS_OK;
}
@ -2179,28 +2179,28 @@ nsresult MediaDecoderStateMachine::DecodeMetadata()
MOZ_ASSERT(mState == DECODER_STATE_DECODING_METADATA);
DECODER_LOG("Decoding Media Headers");
mReader->PreReadMetadata();
if (mReader->IsWaitingMediaResources()) {
StartWaitForResources();
return NS_OK;
}
nsresult res;
MediaInfo info;
bool isAwaitingResources = false;
{
ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor());
res = mReader->ReadMetadata(&info, getter_Transfers(mMetadataTags));
}
mReader->PreReadMetadata();
if (NS_SUCCEEDED(res)) {
if (mState == DECODER_STATE_DECODING_METADATA &&
mReader->IsWaitingMediaResources()) {
// change state to DECODER_STATE_WAIT_FOR_RESOURCES
if (mReader->IsWaitingMediaResources()) {
StartWaitForResources();
// affect values only if ReadMetadata succeeds
return NS_OK;
}
res = mReader->ReadMetadata(&info, getter_Transfers(mMetadataTags));
isAwaitingResources = mReader->IsWaitingMediaResources();
}
if (NS_SUCCEEDED(res) &&
mState == DECODER_STATE_DECODING_METADATA &&
isAwaitingResources) {
// change state to DECODER_STATE_WAIT_FOR_RESOURCES
StartWaitForResources();
// affect values only if ReadMetadata succeeds
return NS_OK;
}
if (NS_SUCCEEDED(res)) {
@ -2766,12 +2766,11 @@ nsresult MediaDecoderStateMachine::RunStateMachine()
// Now that those threads are stopped, there's no possibility of
// mPendingWakeDecoder being needed again. Revoke it.
mPendingWakeDecoder = nullptr;
{
ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor());
// Wait for the thread decoding, if any, to exit.
DecodeTaskQueue()->AwaitIdle();
mReader->ReleaseMediaResources();
}
DebugOnly<nsresult> rv = DecodeTaskQueue()->Dispatch(
NS_NewRunnableMethod(mReader, &MediaDecoderReader::ReleaseMediaResources));
MOZ_ASSERT(NS_SUCCEEDED(rv));
mAudioRequestStatus = RequestStatus::Idle;
mVideoRequestStatus = RequestStatus::Idle;
return NS_OK;
}

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

@ -51,6 +51,15 @@ MediaEncryptedEvent::WrapObjectInternal(JSContext* aCx)
return MediaEncryptedEventBinding::Wrap(aCx, this);
}
already_AddRefed<MediaEncryptedEvent>
MediaEncryptedEvent::Constructor(EventTarget* aOwner)
{
nsRefPtr<MediaEncryptedEvent> e = new MediaEncryptedEvent(aOwner);
e->InitEvent(NS_LITERAL_STRING("encrypted"), false, false);
e->SetTrusted(true);
return e.forget();
}
already_AddRefed<MediaEncryptedEvent>
MediaEncryptedEvent::Constructor(EventTarget* aOwner,
const nsAString& aInitDataType,

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

@ -38,6 +38,9 @@ public:
virtual JSObject* WrapObjectInternal(JSContext* aCx) MOZ_OVERRIDE;
static already_AddRefed<MediaEncryptedEvent>
Constructor(EventTarget* aOwner);
static already_AddRefed<MediaEncryptedEvent>
Constructor(EventTarget* aOwner,
const nsAString& aInitDataType,

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

@ -433,33 +433,6 @@ MediaKeys::Bind(HTMLMediaElement* aElement)
}
mElement = aElement;
nsresult rv = CheckPrincipals();
if (NS_FAILED(rv)) {
mElement = nullptr;
return rv;
}
return NS_OK;
}
nsresult
MediaKeys::CheckPrincipals()
{
MOZ_ASSERT(NS_IsMainThread());
if (!IsBoundToMediaElement()) {
return NS_ERROR_FAILURE;
}
nsRefPtr<nsIPrincipal> elementPrincipal(mElement->GetCurrentPrincipal());
nsRefPtr<nsIPrincipal> elementTopLevelPrincipal(mElement->GetTopLevelPrincipal());
if (!elementPrincipal ||
!mPrincipal ||
!elementPrincipal->Equals(mPrincipal) ||
!elementTopLevelPrincipal ||
!mTopLevelPrincipal ||
!elementTopLevelPrincipal->Equals(mTopLevelPrincipal)) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}

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

@ -117,10 +117,6 @@ public:
// Returns true if this MediaKeys has been bound to a media element.
bool IsBoundToMediaElement() const;
// Return NS_OK if the principals are the same as when the MediaKeys
// was created, failure otherwise.
nsresult CheckPrincipals();
private:
bool IsInPrivateBrowsing();

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

@ -117,6 +117,9 @@ MP4Reader::MP4Reader(AbstractMediaDecoder* aDecoder)
, mIsEncrypted(false)
, mIndexReady(false)
, mDemuxerMonitor("MP4 Demuxer")
#if defined(XP_WIN)
, mDormantEnabled(Preferences::GetBool("media.decoder.heuristic.dormant.enabled", false))
#endif
{
MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread.");
MOZ_COUNT_CTOR(MP4Reader);
@ -252,15 +255,15 @@ private:
#endif
void MP4Reader::RequestCodecResource() {
#ifdef MOZ_GONK_MEDIACODEC
if(mVideo.mDecoder) {
#if defined(MOZ_GONK_MEDIACODEC) || defined(XP_WIN)
if (mVideo.mDecoder) {
mVideo.mDecoder->AllocateMediaResources();
}
#endif
}
bool MP4Reader::IsWaitingOnCodecResource() {
#ifdef MOZ_GONK_MEDIACODEC
#if defined(MOZ_GONK_MEDIACODEC) || defined(XP_WIN)
return mVideo.mDecoder && mVideo.mDecoder->IsWaitingMediaResources();
#endif
return false;
@ -446,7 +449,8 @@ MP4Reader::ReadMetadata(MediaInfo* aInfo,
mVideo.mCallback = new DecoderCallback(this, kVideo);
if (mSharedDecoderManager) {
mVideo.mDecoder =
mSharedDecoderManager->CreateVideoDecoder(video,
mSharedDecoderManager->CreateVideoDecoder(mPlatform,
video,
mLayersBackendType,
mDecoder->GetImageContainer(),
mVideo.mTaskQueue,
@ -1001,15 +1005,20 @@ MP4Reader::GetBuffered(dom::TimeRanges* aBuffered)
bool MP4Reader::IsDormantNeeded()
{
#ifdef MOZ_GONK_MEDIACODEC
return mVideo.mDecoder && mVideo.mDecoder->IsDormantNeeded();
#if defined(MOZ_GONK_MEDIACODEC) || defined(XP_WIN)
return
#if defined(XP_WIN)
mDormantEnabled &&
#endif
mVideo.mDecoder &&
mVideo.mDecoder->IsDormantNeeded();
#endif
return false;
}
void MP4Reader::ReleaseMediaResources()
{
#ifdef MOZ_GONK_MEDIACODEC
#if defined(MOZ_GONK_MEDIACODEC) || defined(XP_WIN)
// Before freeing a video codec, all video buffers needed to be released
// even from graphics pipeline.
VideoFrameContainer* container = mDecoder->GetVideoFrameContainer();
@ -1024,7 +1033,7 @@ void MP4Reader::ReleaseMediaResources()
void MP4Reader::NotifyResourcesStatusChanged()
{
#ifdef MOZ_GONK_MEDIACODEC
#if defined(MOZ_GONK_MEDIACODEC) || defined(XP_WIN)
if (mDecoder) {
mDecoder->NotifyWaitingForResourcesStatusChanged();
}
@ -1043,7 +1052,7 @@ MP4Reader::SetIdle()
void
MP4Reader::SetSharedDecoderManager(SharedDecoderManager* aManager)
{
#ifdef MOZ_GONK_MEDIACODEC
#if defined(MOZ_GONK_MEDIACODEC) || defined(XP_WIN)
mSharedDecoderManager = aManager;
#endif
}

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

@ -267,6 +267,10 @@ private:
bool mIndexReady;
Monitor mDemuxerMonitor;
nsRefPtr<SharedDecoderManager> mSharedDecoderManager;
#if defined(XP_WIN)
const bool mDormantEnabled;
#endif
};
} // namespace mozilla

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

@ -55,11 +55,14 @@ public:
};
SharedDecoderManager::SharedDecoderManager()
: mActiveProxy(nullptr)
: mTaskQueue(new MediaTaskQueue(GetMediaDecodeThreadPool()))
, mActiveProxy(nullptr)
, mActiveCallback(nullptr)
, mWaitForInternalDrain(false)
, mMonitor("SharedDecoderProxy")
, mDecoderReleasedResources(false)
{
MOZ_ASSERT(NS_IsMainThread()); // taskqueue must be created on main thread.
mCallback = new SharedDecoderCallback(this);
}
@ -67,14 +70,18 @@ SharedDecoderManager::~SharedDecoderManager() {}
already_AddRefed<MediaDataDecoder>
SharedDecoderManager::CreateVideoDecoder(
PlatformDecoderModule* aPDM,
const mp4_demuxer::VideoDecoderConfig& aConfig,
layers::LayersBackend aLayersBackend, layers::ImageContainer* aImageContainer,
MediaTaskQueue* aVideoTaskQueue, MediaDataDecoderCallback* aCallback)
{
if (!mDecoder) {
nsRefPtr<PlatformDecoderModule> platform(PlatformDecoderModule::Create());
mDecoder = platform->CreateVideoDecoder(
aConfig, aLayersBackend, aImageContainer, aVideoTaskQueue, mCallback);
// We use the manager's task queue for the decoder, rather than the one
// passed in, so that none of the objects sharing the decoder can shutdown
// the task queue while we're potentially still using it for a *different*
// object also sharing the decoder.
mDecoder = aPDM->CreateVideoDecoder(
aConfig, aLayersBackend, aImageContainer, mTaskQueue, mCallback);
if (!mDecoder) {
return nullptr;
}
@ -96,6 +103,11 @@ SharedDecoderManager::Select(SharedDecoderProxy* aProxy)
mActiveProxy = aProxy;
mActiveCallback = aProxy->mCallback;
if (mDecoderReleasedResources) {
mDecoder->AllocateMediaResources();
mDecoderReleasedResources = false;
}
}
void
@ -125,6 +137,28 @@ SharedDecoderManager::DrainComplete()
}
}
void
SharedDecoderManager::ReleaseMediaResources()
{
mDecoderReleasedResources = true;
mDecoder->ReleaseMediaResources();
mActiveProxy = nullptr;
}
void
SharedDecoderManager::Shutdown()
{
if (mDecoder) {
mDecoder->Shutdown();
mDecoder = nullptr;
}
if (mTaskQueue) {
mTaskQueue->BeginShutdown();
mTaskQueue->AwaitShutdownAndIdle();
mTaskQueue = nullptr;
}
}
SharedDecoderProxy::SharedDecoderProxy(
SharedDecoderManager* aManager, MediaDataDecoderCallback* aCallback)
: mManager(aManager), mCallback(aCallback)
@ -146,7 +180,6 @@ SharedDecoderProxy::Input(mp4_demuxer::MP4Sample* aSample)
mManager->Select(this);
}
return mManager->mDecoder->Input(aSample);
return NS_OK;
}
nsresult
@ -193,7 +226,7 @@ void
SharedDecoderProxy::ReleaseMediaResources()
{
if (mManager->mActiveProxy == this) {
mManager->mDecoder->ReleaseMediaResources();
mManager->ReleaseMediaResources();
}
}

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

@ -25,6 +25,7 @@ public:
SharedDecoderManager();
already_AddRefed<MediaDataDecoder> CreateVideoDecoder(
PlatformDecoderModule* aPDM,
const mp4_demuxer::VideoDecoderConfig& aConfig,
layers::LayersBackend aLayersBackend,
layers::ImageContainer* aImageContainer, MediaTaskQueue* aVideoTaskQueue,
@ -33,6 +34,8 @@ public:
void SetReader(MediaDecoderReader* aReader);
void Select(SharedDecoderProxy* aProxy);
void SetIdle(MediaDataDecoder* aProxy);
void ReleaseMediaResources();
void Shutdown();
friend class SharedDecoderProxy;
friend class SharedDecoderCallback;
@ -42,11 +45,13 @@ private:
void DrainComplete();
nsRefPtr<MediaDataDecoder> mDecoder;
nsRefPtr<MediaTaskQueue> mTaskQueue;
SharedDecoderProxy* mActiveProxy;
MediaDataDecoderCallback* mActiveCallback;
nsAutoPtr<MediaDataDecoderCallback> mCallback;
bool mWaitForInternalDrain;
Monitor mMonitor;
bool mDecoderReleasedResources;
};
class SharedDecoderProxy : public MediaDataDecoder

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

@ -173,7 +173,7 @@ protected:
return true;
}
mGLContext = GLContextProvider::CreateHeadless();
mGLContext = GLContextProvider::CreateHeadless(false);
return mGLContext;
}

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

@ -48,7 +48,13 @@ WMFMediaDataDecoder::Init()
nsresult
WMFMediaDataDecoder::Shutdown()
{
mTaskQueue->FlushAndDispatch(NS_NewRunnableMethod(this, &WMFMediaDataDecoder::ProcessShutdown));
DebugOnly<nsresult> rv = mTaskQueue->FlushAndDispatch(
NS_NewRunnableMethod(this, &WMFMediaDataDecoder::ProcessShutdown));
#ifdef DEBUG
if (NS_FAILED(rv)) {
NS_WARNING("WMFMediaDataDecoder::Shutdown() dispatch of task failed!");
}
#endif
return NS_OK;
}
@ -60,6 +66,13 @@ WMFMediaDataDecoder::ProcessShutdown()
mDecoder = nullptr;
}
void
WMFMediaDataDecoder::ProcessReleaseDecoder()
{
mMFTManager->Shutdown();
mDecoder = nullptr;
}
// Inserts data into the decoder's pipeline.
nsresult
WMFMediaDataDecoder::Input(mp4_demuxer::MP4Sample* aSample)
@ -142,4 +155,28 @@ WMFMediaDataDecoder::Drain()
return NS_OK;
}
void
WMFMediaDataDecoder::AllocateMediaResources()
{
mDecoder = mMFTManager->Init();
}
void
WMFMediaDataDecoder::ReleaseMediaResources()
{
DebugOnly<nsresult> rv = mTaskQueue->FlushAndDispatch(
NS_NewRunnableMethod(this, &WMFMediaDataDecoder::ProcessReleaseDecoder));
#ifdef DEBUG
if (NS_FAILED(rv)) {
NS_WARNING("WMFMediaDataDecoder::ReleaseMediaResources() dispatch of task failed!");
}
#endif
}
void
WMFMediaDataDecoder::ReleaseDecoder()
{
ReleaseMediaResources();
}
} // namespace mozilla

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

@ -70,6 +70,12 @@ public:
virtual nsresult Shutdown() MOZ_OVERRIDE;
virtual bool IsWaitingMediaResources() { return false; };
virtual bool IsDormantNeeded() { return true; };
virtual void AllocateMediaResources() MOZ_OVERRIDE;
virtual void ReleaseMediaResources() MOZ_OVERRIDE;
virtual void ReleaseDecoder() MOZ_OVERRIDE;
private:
// Called on the task queue. Inserts the sample into the decoder, and
@ -85,6 +91,7 @@ private:
void ProcessDrain();
void ProcessShutdown();
void ProcessReleaseDecoder();
RefPtr<MediaTaskQueue> mTaskQueue;
MediaDataDecoderCallback* mCallback;

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

@ -100,7 +100,9 @@ WMFVideoMFTManager::~WMFVideoMFTManager()
{
MOZ_COUNT_DTOR(WMFVideoMFTManager);
// Ensure DXVA/D3D9 related objects are released on the main thread.
DeleteOnMainThread(mDXVA2Manager);
if (mDXVA2Manager) {
DeleteOnMainThread(mDXVA2Manager);
}
}
const GUID&
@ -140,6 +142,8 @@ public:
bool
WMFVideoMFTManager::InitializeDXVA()
{
MOZ_ASSERT(!mDXVA2Manager);
// If we use DXVA but aren't running with a D3D layer manager then the
// readback of decoded video frames from GPU to CPU memory grinds painting
// to a halt, and makes playback performance *worse*.
@ -150,7 +154,8 @@ WMFVideoMFTManager::InitializeDXVA()
return false;
}
if (gfxWindowsPlatform::GetPlatform()->IsWARP()) {
if (gfxWindowsPlatform::GetPlatform()->IsWARP() ||
!gfxPlatform::CanUseDXVA()) {
return false;
}
@ -487,6 +492,7 @@ void
WMFVideoMFTManager::Shutdown()
{
mDecoder = nullptr;
DeleteOnMainThread(mDXVA2Manager);
}
} // namespace mozilla

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

@ -411,6 +411,11 @@ MediaSourceReader::ContinueShutdown()
mVideoTrack = nullptr;
mVideoReader = nullptr;
if (mSharedDecoderManager) {
mSharedDecoderManager->Shutdown();
mSharedDecoderManager = nullptr;
}
MOZ_ASSERT(mAudioPromise.IsEmpty());
MOZ_ASSERT(mVideoPromise.IsEmpty());

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

@ -41,6 +41,7 @@
#include "VideoUtils.h"
using namespace android;
using namespace mozilla::layers;
namespace mozilla {
@ -806,11 +807,49 @@ MediaCodecReader::TextureClientRecycleCallback(TextureClient* aClient)
if (!mTextureClientIndexes.Get(aClient, &index)) {
return;
}
#if MOZ_WIDGET_GONK && ANDROID_VERSION >= 17
sp<Fence> fence = aClient->GetReleaseFenceHandle().mFence;
if (fence.get() && fence->isValid()) {
mPendingReleaseItems.AppendElement(ReleaseItem(index, fence));
} else {
mPendingReleaseItems.AppendElement(ReleaseItem(index, nullptr));
}
#else
mPendingReleaseItems.AppendElement(ReleaseItem(index));
#endif
mTextureClientIndexes.Remove(aClient);
}
if (mVideoTrack.mCodec != nullptr) {
mVideoTrack.mCodec->releaseOutputBuffer(index);
if (mVideoTrack.mReleaseBufferTaskQueue->IsEmpty()) {
RefPtr<nsIRunnable> task =
NS_NewRunnableMethod(this,
&MediaCodecReader::WaitFenceAndReleaseOutputBuffer);
mVideoTrack.mReleaseBufferTaskQueue->Dispatch(task);
}
}
void
MediaCodecReader::WaitFenceAndReleaseOutputBuffer()
{
nsTArray<ReleaseItem> releasingItems;
{
MutexAutoLock autoLock(mTextureClientIndexesLock);
releasingItems.AppendElements(mPendingReleaseItems);
mPendingReleaseItems.Clear();
}
for (size_t i = 0; i < releasingItems.Length(); i++) {
#if MOZ_WIDGET_GONK && ANDROID_VERSION >= 17
sp<Fence> fence;
fence = releasingItems[i].mReleaseFence;
if (fence.get() && fence->isValid()) {
fence->waitForever("MediaCodecReader");
}
#endif
if (mVideoTrack.mCodec != nullptr) {
mVideoTrack.mCodec->releaseOutputBuffer(releasingItems[i].mReleaseIndex);
}
}
}
@ -1250,16 +1289,21 @@ MediaCodecReader::DestroyMediaSources()
void
MediaCodecReader::ShutdownTaskQueues()
{
if(mAudioTrack.mTaskQueue) {
if (mAudioTrack.mTaskQueue) {
mAudioTrack.mTaskQueue->BeginShutdown();
mAudioTrack.mTaskQueue->AwaitShutdownAndIdle();
mAudioTrack.mTaskQueue = nullptr;
}
if(mVideoTrack.mTaskQueue) {
if (mVideoTrack.mTaskQueue) {
mVideoTrack.mTaskQueue->BeginShutdown();
mVideoTrack.mTaskQueue->AwaitShutdownAndIdle();
mVideoTrack.mTaskQueue = nullptr;
}
if (mVideoTrack.mReleaseBufferTaskQueue) {
mVideoTrack.mReleaseBufferTaskQueue->BeginShutdown();
mVideoTrack.mReleaseBufferTaskQueue->AwaitShutdownAndIdle();
mVideoTrack.mReleaseBufferTaskQueue = nullptr;
}
}
bool
@ -1274,6 +1318,8 @@ MediaCodecReader::CreateTaskQueues()
!mVideoTrack.mTaskQueue) {
mVideoTrack.mTaskQueue = CreateMediaDecodeTaskQueue();
NS_ENSURE_TRUE(mVideoTrack.mTaskQueue, false);
mVideoTrack.mReleaseBufferTaskQueue = CreateMediaDecodeTaskQueue();
NS_ENSURE_TRUE(mVideoTrack.mReleaseBufferTaskQueue, false);
}
return true;

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

@ -22,6 +22,10 @@
#include "I420ColorConverterHelper.h"
#include "MediaCodecProxy.h"
#include "MediaOmxCommonReader.h"
#include "mozilla/layers/FenceUtils.h"
#if MOZ_WIDGET_GONK && ANDROID_VERSION >= 17
#include <ui/Fence.h>
#endif
namespace android {
struct ALooper;
@ -47,6 +51,7 @@ class TextureClient;
class MediaCodecReader : public MediaOmxCommonReader
{
typedef mozilla::layers::TextureClient TextureClient;
typedef mozilla::layers::FenceHandle FenceHandle;
public:
MediaCodecReader(AbstractMediaDecoder* aDecoder);
@ -264,6 +269,7 @@ private:
// Protected by mTrackMonitor.
MediaPromiseHolder<VideoDataPromise> mVideoPromise;
nsRefPtr<MediaTaskQueue> mReleaseBufferTaskQueue;
private:
// Forbidden
VideoTrack(const VideoTrack &rhs) = delete;
@ -415,6 +421,7 @@ private:
static void TextureClientRecycleCallback(TextureClient* aClient,
void* aClosure);
void TextureClientRecycleCallback(TextureClient* aClient);
void WaitFenceAndReleaseOutputBuffer();
void ReleaseRecycledTextureClients();
static PLDHashOperator ReleaseTextureClient(TextureClient* aClient,
@ -450,6 +457,26 @@ private:
int64_t mNextParserPosition;
int64_t mParsedDataLength;
nsAutoPtr<MP3FrameParser> mMP3FrameParser;
#if MOZ_WIDGET_GONK && ANDROID_VERSION >= 17
// mReleaseIndex corresponding to a graphic buffer, and the mReleaseFence is
// the graohic buffer's fence. We must wait for the fence signaled by
// compositor, otherwise we will see the flicker because the HW decoder and
// compositor use the buffer concurrently.
struct ReleaseItem {
ReleaseItem(size_t aIndex, const android::sp<android::Fence>& aFence)
: mReleaseIndex(aIndex)
, mReleaseFence(aFence) {}
size_t mReleaseIndex;
android::sp<android::Fence> mReleaseFence;
};
#else
struct ReleaseItem {
ReleaseItem(size_t aIndex)
: mReleaseIndex(aIndex) {}
size_t mReleaseIndex;
};
#endif
nsTArray<ReleaseItem> mPendingReleaseItems;
};
} // namespace mozilla

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

@ -13,6 +13,9 @@ function parseQuery(request, key) {
}
var types = {
js: "text/javascript",
m4s: "video/mp4",
mp4: "video/mp4",
ogg: "video/ogg",
ogv: "video/ogg",
oga: "audio/ogg",

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

@ -114,6 +114,15 @@ function UpdateSessionFunc(test, token, sessionType) {
}
}
function MaybeCrossOriginURI(test, uri)
{
if (test.crossOrigin) {
return "http://test2.mochi.test:8888/tests/dom/media/test/allowed.sjs?" + uri;
} else {
return uri;
}
}
function PlayFragmented(test, elem, token)
{
return new Promise(function(resolve, reject) {
@ -140,7 +149,7 @@ function PlayFragmented(test, elem, token)
return;
}
var fragmentFile = test.fragments[curFragment++];
var fragmentFile = MaybeCrossOriginURI(test, test.fragments[curFragment++]);
var req = new XMLHttpRequest();
req.open("GET", fragmentFile);
@ -179,7 +188,7 @@ function LoadTest(test, elem, token)
// This file isn't fragmented; set the media source normally.
return new Promise(function(resolve, reject) {
elem.src = test.name;
elem.src = MaybeCrossOriginURI(test, test.name);
resolve();
});
}
@ -187,6 +196,7 @@ function LoadTest(test, elem, token)
function SetupEME(test, token, params)
{
var v = document.createElement("video");
v.crossOrigin = test.crossOrigin || false;
// Log events dispatched to make debugging easier...
[ "canplay", "canplaythrough", "ended", "error", "loadeddata",

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

@ -652,6 +652,18 @@ var gEMETests = [
sessionType:"temporary",
duration:0.47
},
{
name:"short-cenc.mp4",
type:"video/mp4; codecs=\"avc1.64000d,mp4a.40.2\"",
keys: {
// "keyid" : "key"
"7e571d017e571d017e571d017e571d01" : "7e5711117e5711117e5711117e571111",
"7e571d027e571d027e571d027e571d02" : "7e5722227e5722227e5722227e572222",
},
sessionType:"temporary",
duration:0.47,
crossOrigin:true,
},
{
name:"gizmo-frag-cencinit.mp4",
fragments: [ "gizmo-frag-cencinit.mp4", "gizmo-frag-cenc1.m4s", "gizmo-frag-cenc2.m4s" ],
@ -664,6 +676,19 @@ var gEMETests = [
sessionType:"temporary",
duration:2.00,
},
{
name:"gizmo-frag-cencinit.mp4",
fragments: [ "gizmo-frag-cencinit.mp4", "gizmo-frag-cenc1.m4s", "gizmo-frag-cenc2.m4s" ],
type:"video/mp4; codecs=\"avc1.64000d,mp4a.40.2\"",
keys: {
// "keyid" : "key"
"7e571d037e571d037e571d037e571d03" : "7e5733337e5733337e5733337e573333",
"7e571d047e571d047e571d047e571d04" : "7e5744447e5744447e5744447e574444",
},
sessionType:"temporary",
duration:2.00,
crossOrigin:true,
},
];
function checkMetadata(msg, e, test) {

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

@ -364,6 +364,8 @@ skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439
[test_defaultMuted.html]
[test_delay_load.html]
skip-if = buildapp == 'b2g' && toolkit != 'gonk' # bug 1082984
[test_eme_access_control.html]
skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s # bug 1043403, bug 1057908
[test_eme_canvas_blocked.html]
skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s # bug 1043403, bug 1057908
[test_eme_persistent_sessions.html]

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

@ -0,0 +1,112 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test EME blocked cross-origin</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<script type="text/javascript" src="manifest.js"></script>
<script type="text/javascript" src="eme.js"></script>
</head>
<body>
<pre id="test">
<script class="testbody" type="text/javascript">
var manager = new MediaTestManager;
function TestNoCORS(test, token)
{
var token = token + "_nocors";
manager.started(token);
var v = document.createElement("video");
v.addEventListener("encrypted", function(ev) {
is(ev.initDataType, "", "initDataType should be empty for CORS cross-origin media");
is(ev.initData, null, "initData should be null for CORS cross-origin media");
manager.finished(token);
});
v.addEventListener("error", function() {
ok(false, "Should not receive error loading cross-origin media without crossorigin attribute");
});
v.src = test.uri;
}
function TestCORSFailure(test, token)
{
var token = token + "_corsfail";
manager.started(token);
var v = document.createElement("video");
v.crossOrigin = true;
v.addEventListener("error", function(ev) {
ok(true, "Should get error loading cross-origin media");
manager.finished(token);
});
v.addEventListener("encrypted", function() {
ok(false, "Should not receive encrypted event loading cross-origin media");
});
v.src = test.uri;
}
function TestCORSSuccess(test, token)
{
var token = token + "_corsok";
manager.started(token);
var v = document.createElement("video");
v.crossOrigin = true;
v.addEventListener("error", function(ev) {
ok(false, "Should not get error loading cross-origin media");
});
v.addEventListener("encrypted", function(ev) {
ok(ev.initData.byteLength > 0, "Should get encryption initData loading cross-origin media");
is(ev.initDataType, "cenc", "Should get correct encryption initDataType loading cross-origin media");
manager.finished(token);
});
v.src = test.uri;
}
function startTest(test, token)
{
test.uri = "http://test1.mochi.test:8888/tests/dom/media/test/" + test.name;
TestNoCORS(test, token);
TestCORSFailure(test, token);
test.uri = "http://test1.mochi.test:8888/tests/dom/media/test/allowed.sjs?" + test.name;
TestCORSSuccess(test, token);
}
function beginTest() {
manager.runTests(gEMETests.filter(t => t.crossOrigin), startTest);
}
var prefs = [
[ "media.mediasource.enabled", true ],
[ "media.mediasource.youtubeonly", false ],
[ "media.mediasource.mp4.enabled", true ],
];
if (/Linux/.test(navigator.userAgent) ||
!document.createElement('video').canPlayType("video/mp4")) {
// XXX remove once we have mp4 PlatformDecoderModules on all platforms.
prefs.push([ "media.fragmented-mp4.exposed", true ]);
prefs.push([ "media.fragmented-mp4.use-blank-decoder", true ]);
}
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPrefEnv({ "set" : prefs }, beginTest);
</script>
</pre>
</body>
</html>

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

@ -5,7 +5,7 @@
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<script type="text/javascript" src="manifest.js"></script>
<script type="text/javascript" src="eme.js"></script>
<script type="text/javascript" src="http://test1.mochi.test:8888/tests/dom/media/test/eme.js"></script>
</head>
<body>
<pre id="test">

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

@ -9,8 +9,6 @@
<body>
<pre id="test">
<script class="testbody" type="text/javascript">
SimpleTest.waitForExplicitFinish();
var manager = new MediaTestManager;
function checkDrawImage(vout) {
@ -27,6 +25,8 @@ function startTest(test, token) {
var v = document.createElement('video');
var vout = document.createElement('video');
vout.token = token;
v.name = token + "(v)";
vout.name = token + "(vout)";
v.src = test.name;
var stream = v.mozCaptureStreamUntilEnded();
@ -53,6 +53,19 @@ function startTest(test, token) {
document.body.appendChild(vout);
v.play();
vout.play();
// Log events for debugging.
var events = ["suspend", "play", "canplay", "canplaythrough", "loadstart", "loadedmetadata",
"loadeddata", "playing", "ended", "error", "stalled", "emptied", "abort",
"waiting", "pause"];
function logEvent(e) {
info(e.target.name + ": got " + e.type);
}
events.forEach(function(e) {
v.addEventListener(e, logEvent, false);
vout.addEventListener(e, logEvent, false);
});
}
manager.runTests(gSmallTests, startTest);

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

@ -111,7 +111,8 @@ WMFReader::InitializeDXVA()
return false;
}
if (gfxWindowsPlatform::GetPlatform()->IsWARP()) {
if (gfxWindowsPlatform::GetPlatform()->IsWARP() ||
!gfxPlatform::CanUseDXVA()) {
return false;
}

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

@ -91,9 +91,8 @@ static nsRefPtr<GLContext> sPluginContext = nullptr;
static bool EnsureGLContext()
{
if (!sPluginContext) {
gfxIntSize dummySize(16, 16);
sPluginContext = GLContextProvider::CreateOffscreen(dummySize,
SurfaceCaps::Any());
bool requireCompatProfile = true;
sPluginContext = GLContextProvider::CreateHeadless(requireCompatProfile);
}
return sPluginContext != nullptr;

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

@ -72,6 +72,9 @@ BrowserStreamParent::RecvAsyncNPP_NewStreamResult(const NPError& rv,
}
if (error != NPERR_NO_ERROR) {
// streamListener was suspended during async init. We must resume the stream
// request prior to calling _destroystream for cleanup to work correctly.
streamListener->ResumeRequest();
// We need to clean up the stream
parent::_destroystream(mNPP->GetNPP(), mStream, NPRES_DONE);
unused << PBrowserStreamParent::Send__delete__(this);

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

@ -14,6 +14,10 @@
#include "mozilla/Telemetry.h"
#include "nsThreadUtils.h"
#if defined(XP_WIN) && defined(MOZ_SANDBOX)
#include "mozilla/Preferences.h"
#endif
using std::vector;
using std::string;
@ -48,6 +52,8 @@ PluginProcessParent::Launch(mozilla::UniquePtr<LaunchCompleteTask> aLaunchComple
{
#if defined(XP_WIN) && defined(MOZ_SANDBOX)
mEnableNPAPISandbox = aEnableSandbox;
mMoreStrictSandbox =
Preferences::GetBool("dom.ipc.plugins.moreStrictSandbox");
#else
if (aEnableSandbox) {
MOZ_ASSERT(false,

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

@ -42,16 +42,25 @@ using namespace mozilla;
static bool gDisableCORS = false;
static bool gDisableCORSPrivateData = false;
static nsresult
LogBlockedRequest(nsIRequest* aRequest)
static void
LogBlockedRequest(nsIRequest* aRequest,
const char* aProperty,
const char16_t* aParam)
{
nsresult rv = NS_OK;
// Get the innerWindowID associated with the XMLHTTPRequest
uint64_t innerWindowID = nsContentUtils::GetInnerWindowID(aRequest);
// Build the error object and log it to the console
nsCOMPtr<nsIConsoleService> console(do_GetService(NS_CONSOLESERVICE_CONTRACTID, &rv));
if (NS_FAILED(rv)) {
NS_WARNING("Failed to log blocked cross-site request (no console)");
return;
}
if (!innerWindowID) {
return NS_ERROR_FAILURE;
nsCOMPtr<nsIScriptError> scriptError =
do_CreateInstance(NS_SCRIPTERROR_CONTRACTID, &rv);
if (NS_FAILED(rv)) {
NS_WARNING("Failed to log blocked cross-site request (no scriptError)");
return;
}
nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
@ -65,32 +74,47 @@ LogBlockedRequest(nsIRequest* aRequest)
// Generate the error message
nsXPIDLString blockedMessage;
NS_ConvertUTF8toUTF16 specUTF16(spec);
const char16_t* params[] = { specUTF16.get() };
const char16_t* params[] = { specUTF16.get(), aParam };
rv = nsContentUtils::FormatLocalizedString(nsContentUtils::eSECURITY_PROPERTIES,
"CrossSiteRequestBlocked",
aProperty,
params,
blockedMessage);
// Build the error object and log it to the console
nsCOMPtr<nsIConsoleService> console(do_GetService(NS_CONSOLESERVICE_CONTRACTID, &rv));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIScriptError> scriptError = do_CreateInstance(NS_SCRIPTERROR_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
if (NS_FAILED(rv)) {
NS_WARNING("Failed to log blocked cross-site request (no formalizedStr");
return;
}
nsAutoString msg(blockedMessage.get());
rv = scriptError->InitWithWindowID(msg,
NS_ConvertUTF8toUTF16(spec),
EmptyString(),
0,
0,
nsIScriptError::warningFlag,
"CORS",
innerWindowID);
NS_ENSURE_SUCCESS(rv, rv);
rv = console->LogMessage(scriptError);
return rv;
// query innerWindowID and log to web console, otherwise log to
// the error to the browser console.
uint64_t innerWindowID = nsContentUtils::GetInnerWindowID(aRequest);
if (innerWindowID > 0) {
rv = scriptError->InitWithWindowID(msg,
EmptyString(), // sourceName
EmptyString(), // sourceLine
0, // lineNumber
0, // columnNumber
nsIScriptError::warningFlag,
"CORS",
innerWindowID);
}
else {
rv = scriptError->Init(msg,
EmptyString(), // sourceName
EmptyString(), // sourceLine
0, // lineNumber
0, // columnNumber
nsIScriptError::warningFlag,
"CORS");
}
if (NS_FAILED(rv)) {
NS_WARNING("Failed to log blocked cross-site request (scriptError init failed)");
return;
}
console->LogMessage(scriptError);
}
//////////////////////////////////////////////////////////////////////////
@ -470,8 +494,6 @@ nsCORSListenerProxy::OnStartRequest(nsIRequest* aRequest,
nsresult rv = CheckRequestApproved(aRequest);
mRequestApproved = NS_SUCCEEDED(rv);
if (!mRequestApproved) {
rv = LogBlockedRequest(aRequest);
NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Failed to log blocked cross-site request");
if (sPreflightCache) {
nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
if (channel) {
@ -503,31 +525,45 @@ nsCORSListenerProxy::CheckRequestApproved(nsIRequest* aRequest)
}
if (gDisableCORS) {
LogBlockedRequest(aRequest, "CORSDisabled", nullptr);
return NS_ERROR_DOM_BAD_URI;
}
// Check if the request failed
nsresult status;
nsresult rv = aRequest->GetStatus(&status);
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_SUCCESS(status, status);
if (NS_FAILED(rv)) {
LogBlockedRequest(aRequest, "CORSRequestFailed", nullptr);
return rv;
}
if (NS_FAILED(status)) {
LogBlockedRequest(aRequest, "CORSRequestFailed", nullptr);
return status;
}
// Test that things worked on a HTTP level
nsCOMPtr<nsIHttpChannel> http = do_QueryInterface(aRequest);
NS_ENSURE_TRUE(http, NS_ERROR_DOM_BAD_URI);
if (!http) {
LogBlockedRequest(aRequest, "CORSRequestNotHttp", nullptr);
return NS_ERROR_DOM_BAD_URI;
}
// Check the Access-Control-Allow-Origin header
nsAutoCString allowedOriginHeader;
rv = http->GetResponseHeader(
NS_LITERAL_CSTRING("Access-Control-Allow-Origin"), allowedOriginHeader);
NS_ENSURE_SUCCESS(rv, rv);
if (NS_FAILED(rv)) {
LogBlockedRequest(aRequest, "CORSMissingAllowOrigin", nullptr);
return rv;
}
if (mWithCredentials || !allowedOriginHeader.EqualsLiteral("*")) {
nsAutoCString origin;
rv = nsContentUtils::GetASCIIOrigin(mOriginHeaderPrincipal, origin);
NS_ENSURE_SUCCESS(rv, rv);
nsContentUtils::GetASCIIOrigin(mOriginHeaderPrincipal, origin);
if (!allowedOriginHeader.Equals(origin)) {
LogBlockedRequest(aRequest, "CORSAllowOriginNotMatchingOrigin",
NS_ConvertUTF8toUTF16(allowedOriginHeader).get());
return NS_ERROR_DOM_BAD_URI;
}
}
@ -537,9 +573,9 @@ nsCORSListenerProxy::CheckRequestApproved(nsIRequest* aRequest)
nsAutoCString allowCredentialsHeader;
rv = http->GetResponseHeader(
NS_LITERAL_CSTRING("Access-Control-Allow-Credentials"), allowCredentialsHeader);
NS_ENSURE_SUCCESS(rv, rv);
if (!allowCredentialsHeader.EqualsLiteral("true")) {
LogBlockedRequest(aRequest, "CORSMissingAllowCredentials", nullptr);
return NS_ERROR_DOM_BAD_URI;
}
}
@ -547,8 +583,8 @@ nsCORSListenerProxy::CheckRequestApproved(nsIRequest* aRequest)
if (mIsPreflight) {
bool succeedded;
rv = http->GetRequestSucceeded(&succeedded);
NS_ENSURE_SUCCESS(rv, rv);
if (!succeedded) {
if (NS_FAILED(rv) || !succeedded) {
LogBlockedRequest(aRequest, "CORSPreflightDidNotSucceed", nullptr);
return NS_ERROR_DOM_BAD_URI;
}
@ -567,11 +603,16 @@ nsCORSListenerProxy::CheckRequestApproved(nsIRequest* aRequest)
continue;
}
if (!NS_IsValidHTTPToken(method)) {
LogBlockedRequest(aRequest, "CORSInvalidAllowMethod",
NS_ConvertUTF8toUTF16(method).get());
return NS_ERROR_DOM_BAD_URI;
}
foundMethod |= mPreflightMethod.Equals(method);
}
NS_ENSURE_TRUE(foundMethod, NS_ERROR_DOM_BAD_URI);
if (!foundMethod) {
LogBlockedRequest(aRequest, "CORSMethodNotFound", nullptr);
return NS_ERROR_DOM_BAD_URI;
}
// The "Access-Control-Allow-Headers" header contains a comma separated
// list of header names.
@ -586,6 +627,8 @@ nsCORSListenerProxy::CheckRequestApproved(nsIRequest* aRequest)
continue;
}
if (!NS_IsValidHTTPToken(header)) {
LogBlockedRequest(aRequest, "CORSInvalidAllowHeader",
NS_ConvertUTF8toUTF16(header).get());
return NS_ERROR_DOM_BAD_URI;
}
headers.AppendElement(header);
@ -593,6 +636,8 @@ nsCORSListenerProxy::CheckRequestApproved(nsIRequest* aRequest)
for (uint32_t i = 0; i < mPreflightHeaders.Length(); ++i) {
if (!headers.Contains(mPreflightHeaders[i],
nsCaseInsensitiveCStringArrayComparator())) {
LogBlockedRequest(aRequest, "CORSMissingAllowHeaderFromPreflight",
NS_ConvertUTF8toUTF16(mPreflightHeaders[i]).get());
return NS_ERROR_DOM_BAD_URI;
}
}
@ -656,9 +701,6 @@ nsCORSListenerProxy::AsyncOnChannelRedirect(nsIChannel *aOldChannel,
if (!NS_IsInternalSameURIRedirect(aOldChannel, aNewChannel, aFlags)) {
rv = CheckRequestApproved(aOldChannel);
if (NS_FAILED(rv)) {
rv = LogBlockedRequest(aOldChannel);
NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Failed to log blocked cross-site request");
if (sPreflightCache) {
nsCOMPtr<nsIURI> oldURI;
NS_GetFinalChannelURI(aOldChannel, getter_AddRefs(oldURI));

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

@ -8,6 +8,7 @@
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <vector>
#include "GLContext.h"
#include "GLBlitHelper.h"
@ -156,8 +157,7 @@ static const char *sExtensionNames[] = {
"GL_OES_texture_half_float",
"GL_OES_texture_half_float_linear",
"GL_OES_texture_npot",
"GL_OES_vertex_array_object",
nullptr
"GL_OES_vertex_array_object"
};
static bool
@ -317,6 +317,8 @@ GLContext::~GLContext() {
ReportOutstandingNames();
}
#endif
DeleteAndClearIterable(mDriverExtensionList);
}
/*static*/ void
@ -501,6 +503,8 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl)
mInitialized = LoadSymbols(&symbols[0], trygl, prefix);
MakeCurrent();
if (mInitialized) {
MOZ_ASSERT(mProfile != ContextProfile::Unknown);
uint32_t version = 0;
ParseGLVersion(this, &version);
@ -656,6 +660,15 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl)
}
}
if (IsFeatureProvidedByCoreSymbols(GLFeature::get_string_indexed)) {
SymLoadStruct moreSymbols[] = {
{ (PRFuncPtr*) &mSymbols.fGetStringi, { "GetStringi", nullptr } },
END_SYMBOLS
};
MOZ_ALWAYS_TRUE(LoadSymbols(moreSymbols, trygl, prefix));
}
InitExtensions();
InitFeatures();
@ -670,12 +683,6 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl)
MarkUnsupported(GLFeature::standard_derivatives);
}
if (Vendor() == GLVendor::Imagination &&
Renderer() == GLRenderer::SGX540) {
// Bug 980048
MarkExtensionUnsupported(OES_EGL_sync);
}
if (Renderer() == GLRenderer::MicrosoftBasicRenderDriver) {
// Bug 978966: on Microsoft's "Basic Render Driver" (software renderer)
// multisampling hardcodes blending with the default blendfunc, which breaks WebGL.
@ -1468,10 +1475,13 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl)
// We're ready for final setup.
fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
if (mCaps.any)
DetermineCaps();
// TODO: Remove SurfaceCaps::any.
if (mCaps.any) {
mCaps.any = false;
mCaps.color = true;
mCaps.alpha = false;
}
UpdatePixelFormat();
UpdateGLFormats(mCaps);
mTexGarbageBin = new TextureGarbageBin(this);
@ -1593,61 +1603,101 @@ GLContext::DebugCallback(GLenum source,
void
GLContext::InitExtensions()
{
MakeCurrent();
const char* extensions = (const char*)fGetString(LOCAL_GL_EXTENSIONS);
if (!extensions)
return;
MOZ_ASSERT(IsCurrent());
InitializeExtensionsBitSet(mAvailableExtensions, extensions,
sExtensionNames);
if (IsFeatureProvidedByCoreSymbols(GLFeature::get_string_indexed)) {
GLuint count = 0;
GetUIntegerv(LOCAL_GL_NUM_EXTENSIONS, &count);
for (GLuint i = 0; i < count; i++) {
// This is UTF-8.
const char* rawExt = (const char*)fGetStringi(LOCAL_GL_EXTENSIONS,
i);
nsACString* ext = new nsDependentCString(rawExt);
mDriverExtensionList.push_back(ext);
}
} else {
MOZ_ALWAYS_TRUE(!fGetError());
const char* rawExts = (const char*)fGetString(LOCAL_GL_EXTENSIONS);
MOZ_ALWAYS_TRUE(!fGetError());
if (WorkAroundDriverBugs() &&
Vendor() == GLVendor::Qualcomm) {
// Some Adreno drivers do not report GL_OES_EGL_sync, but they really do support it.
MarkExtensionSupported(OES_EGL_sync);
if (rawExts) {
nsDependentCString exts(rawExts);
SplitByChar(exts, ' ', &mDriverExtensionList);
}
}
if (WorkAroundDriverBugs() &&
Renderer() == GLRenderer::AndroidEmulator) {
// the Android emulator, which we use to run B2G reftests on,
// doesn't expose the OES_rgb8_rgba8 extension, but it seems to
// support it (tautologically, as it only runs on desktop GL).
MarkExtensionSupported(OES_rgb8_rgba8);
const bool shouldDumpExts = ShouldDumpExts();
if (shouldDumpExts) {
printf_stderr("%i GL driver extensions:\n",
(uint32_t)mDriverExtensionList.size());
}
if (WorkAroundDriverBugs() &&
Vendor() == GLVendor::VMware &&
Renderer() == GLRenderer::GalliumLlvmpipe)
{
// The llvmpipe driver that is used on linux try servers appears to have
// buggy support for s3tc/dxt1 compressed textures.
// See Bug 975824.
MarkExtensionUnsupported(EXT_texture_compression_s3tc);
MarkExtensionUnsupported(EXT_texture_compression_dxt1);
MarkExtensionUnsupported(ANGLE_texture_compression_dxt3);
MarkExtensionUnsupported(ANGLE_texture_compression_dxt5);
}
MarkBitfieldByStrings(mDriverExtensionList, shouldDumpExts, sExtensionNames,
mAvailableExtensions);
if (WorkAroundDriverBugs()) {
if (Vendor() == GLVendor::Qualcomm) {
// Some Adreno drivers do not report GL_OES_EGL_sync, but they really do support it.
MarkExtensionSupported(OES_EGL_sync);
}
if (Vendor() == GLVendor::Imagination &&
Renderer() == GLRenderer::SGX540)
{
// Bug 980048
MarkExtensionUnsupported(OES_EGL_sync);
}
if (Renderer() == GLRenderer::AndroidEmulator) {
// the Android emulator, which we use to run B2G reftests on,
// doesn't expose the OES_rgb8_rgba8 extension, but it seems to
// support it (tautologically, as it only runs on desktop GL).
MarkExtensionSupported(OES_rgb8_rgba8);
}
if (Vendor() == GLVendor::VMware &&
Renderer() == GLRenderer::GalliumLlvmpipe)
{
// The llvmpipe driver that is used on linux try servers appears to have
// buggy support for s3tc/dxt1 compressed textures.
// See Bug 975824.
MarkExtensionUnsupported(EXT_texture_compression_s3tc);
MarkExtensionUnsupported(EXT_texture_compression_dxt1);
MarkExtensionUnsupported(ANGLE_texture_compression_dxt3);
MarkExtensionUnsupported(ANGLE_texture_compression_dxt5);
}
#ifdef XP_MACOSX
// Bug 1009642: On OSX Mavericks (10.9), the driver for Intel HD
// 3000 appears to be buggy WRT updating sub-images of S3TC
// textures with glCompressedTexSubImage2D. Works on Intel HD 4000
// and Intel HD 5000/Iris that I tested.
if (WorkAroundDriverBugs() &&
nsCocoaFeatures::OSXVersionMajor() == 10 &&
nsCocoaFeatures::OSXVersionMinor() == 9 &&
Renderer() == GLRenderer::IntelHD3000)
{
MarkExtensionUnsupported(EXT_texture_compression_s3tc);
}
// Bug 1009642: On OSX Mavericks (10.9), the driver for Intel HD
// 3000 appears to be buggy WRT updating sub-images of S3TC
// textures with glCompressedTexSubImage2D. Works on Intel HD 4000
// and Intel HD 5000/Iris that I tested.
if (nsCocoaFeatures::OSXVersionMajor() == 10 &&
nsCocoaFeatures::OSXVersionMinor() == 9 &&
Renderer() == GLRenderer::IntelHD3000)
{
MarkExtensionUnsupported(EXT_texture_compression_s3tc);
}
#endif
}
if (shouldDumpExts) {
printf_stderr("\nActivated extensions:\n");
for (size_t i = 0; i < mAvailableExtensions.size(); i++) {
if (!mAvailableExtensions[i])
continue;
const char* ext = sExtensionNames[i];
printf_stderr("[%i] %s\n", (uint32_t)i, ext);
}
}
}
void
GLContext::PlatformStartup()
{
RegisterStrongMemoryReporter(new GfxTexturesReporter());
RegisterStrongMemoryReporter(new GfxTexturesReporter());
}
// Common code for checking for both GL extensions and GLX extensions.
@ -1688,66 +1738,6 @@ GLContext::ListHasExtension(const GLubyte *extensions, const char *extension)
return false;
}
void
GLContext::DetermineCaps()
{
PixelBufferFormat format = QueryPixelFormat();
SurfaceCaps caps;
caps.color = !!format.red && !!format.green && !!format.blue;
caps.bpp16 = caps.color && format.ColorBits() == 16;
caps.alpha = !!format.alpha;
caps.depth = !!format.depth;
caps.stencil = !!format.stencil;
caps.antialias = format.samples > 1;
caps.preserve = true;
mCaps = caps;
}
PixelBufferFormat
GLContext::QueryPixelFormat()
{
PixelBufferFormat format;
ScopedBindFramebuffer autoFB(this, 0);
fGetIntegerv(LOCAL_GL_RED_BITS , &format.red );
fGetIntegerv(LOCAL_GL_GREEN_BITS, &format.green);
fGetIntegerv(LOCAL_GL_BLUE_BITS , &format.blue );
fGetIntegerv(LOCAL_GL_ALPHA_BITS, &format.alpha);
fGetIntegerv(LOCAL_GL_DEPTH_BITS, &format.depth);
fGetIntegerv(LOCAL_GL_STENCIL_BITS, &format.stencil);
fGetIntegerv(LOCAL_GL_SAMPLES, &format.samples);
return format;
}
void
GLContext::UpdatePixelFormat()
{
PixelBufferFormat format = QueryPixelFormat();
#ifdef MOZ_GL_DEBUG
const SurfaceCaps& caps = Caps();
MOZ_ASSERT(!caps.any, "Did you forget to DetermineCaps()?");
MOZ_ASSERT(caps.color == !!format.red);
MOZ_ASSERT(caps.color == !!format.green);
MOZ_ASSERT(caps.color == !!format.blue);
// These we either must have if they're requested, or
// we can have if they're not.
MOZ_ASSERT(caps.alpha == !!format.alpha || !caps.alpha);
MOZ_ASSERT(caps.depth == !!format.depth || !caps.depth);
MOZ_ASSERT(caps.stencil == !!format.stencil || !caps.stencil);
MOZ_ASSERT(caps.antialias == (format.samples > 1));
#endif
mPixelFormat = new PixelBufferFormat(format);
}
GLFormats
GLContext::ChooseGLFormats(const SurfaceCaps& caps) const
{
@ -2417,6 +2407,12 @@ GLContext::FlushIfHeavyGLCallsSinceLastFlush()
fFlush();
}
/*static*/ bool
GLContext::ShouldDumpExts()
{
return PR_GetEnv("MOZ_GL_DUMP_EXTS");
}
bool
DoesStringMatch(const char* aString, const char *aWantedString)
{
@ -2448,5 +2444,27 @@ GLContext::ShouldSpew()
return spew;
}
void
SplitByChar(const nsACString& str, const char delim,
std::vector<nsACString*>* out)
{
uint32_t start = 0;
while (true) {
int32_t end = str.FindChar(' ', start);
if (end == -1)
break;
uint32_t len = (uint32_t)end - start;
nsACString* substr = new nsDependentCSubstring(str, start, len);
out->push_back(substr);
start = end + 1;
continue;
}
nsACString* substr = new nsDependentCSubstring(str, start);
out->push_back(substr);
}
} /* namespace gl */
} /* namespace mozilla */

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

@ -104,6 +104,7 @@ enum class GLFeature {
get_integer_indexed,
get_integer64_indexed,
get_query_object_iv,
get_string_indexed,
gpu_shader4,
instanced_arrays,
instanced_non_arrays,
@ -308,7 +309,6 @@ public:
virtual bool IsCurrent() = 0;
protected:
bool mInitialized;
bool mIsOffscreen;
bool mIsGlobalSharedContext;
@ -325,9 +325,12 @@ protected:
GLVendor mVendor;
GLRenderer mRenderer;
inline void SetProfileVersion(ContextProfile profile, unsigned int version) {
MOZ_ASSERT(!mInitialized, "SetProfileVersion can only be called before initialization!");
MOZ_ASSERT(profile != ContextProfile::Unknown && profile != ContextProfile::OpenGL, "Invalid `profile` for SetProfileVersion");
void SetProfileVersion(ContextProfile profile, uint32_t version) {
MOZ_ASSERT(!mInitialized, "SetProfileVersion can only be called before"
" initialization!");
MOZ_ASSERT(profile != ContextProfile::Unknown &&
profile != ContextProfile::OpenGL,
"Invalid `profile` for SetProfileVersion");
MOZ_ASSERT(version >= 100, "Invalid `version` for SetProfileVersion");
mVersion = version;
@ -457,6 +460,7 @@ public:
return mAvailableExtensions[aKnownExtension];
}
protected:
void MarkExtensionUnsupported(GLExtensions aKnownExtension) {
mAvailableExtensions[aKnownExtension] = 0;
}
@ -465,42 +469,6 @@ public:
mAvailableExtensions[aKnownExtension] = 1;
}
public:
template<size_t N>
static void InitializeExtensionsBitSet(std::bitset<N>& extensionsBitset,
const char* extStr,
const char** extList)
{
char* exts = ::strdup(extStr);
if (ShouldSpew())
printf_stderr("Extensions: %s\n", exts);
char* cur = exts;
bool done = false;
while (!done) {
char* space = strchr(cur, ' ');
if (space) {
*space = '\0';
} else {
done = true;
}
for (int i = 0; extList[i]; ++i) {
if (PL_strcasecmp(cur, extList[i]) == 0) {
if (ShouldSpew())
printf_stderr("Found extension %s\n", cur);
extensionsBitset[i] = true;
}
}
cur = space + 1;
}
free(exts);
}
protected:
std::bitset<Extensions_Max> mAvailableExtensions;
// -----------------------------------------------------------------------------
@ -3180,6 +3148,17 @@ public:
AFTER_GL_CALL;
}
// -----------------------------------------------------------------------------
// get_string_indexed
const GLubyte* fGetStringi(GLenum name, GLuint index) {
BEFORE_GL_CALL;
ASSERT_SYMBOL_PRESENT(fGetStringi);
const GLubyte* ret = mSymbols.fGetStringi(name, index);
AFTER_GL_CALL;
return ret;
}
// -----------------------------------------------------------------------------
// Constructor
protected:
@ -3448,11 +3427,9 @@ public:
fViewport(0, 0, size.width, size.height);
mCaps = mScreen->mCaps;
if (mCaps.any)
DetermineCaps();
MOZ_ASSERT(!mCaps.any);
UpdateGLFormats(mCaps);
UpdatePixelFormat();
return true;
}
@ -3475,10 +3452,8 @@ public:
protected:
SurfaceCaps mCaps;
nsAutoPtr<GLFormats> mGLFormats;
nsAutoPtr<PixelBufferFormat> mPixelFormat;
public:
void DetermineCaps();
const SurfaceCaps& Caps() const {
return mCaps;
}
@ -3494,14 +3469,6 @@ public:
return *mGLFormats;
}
PixelBufferFormat QueryPixelFormat();
void UpdatePixelFormat();
const PixelBufferFormat& GetPixelFormat() const {
MOZ_ASSERT(mPixelFormat);
return *mPixelFormat;
}
bool IsFramebufferComplete(GLuint fb, GLenum* status = nullptr);
// Does not check completeness.
@ -3541,7 +3508,7 @@ public:
}
bool IsOffscreen() const {
return mScreen;
return mIsOffscreen;
}
GLScreenBuffer* Screen() const {
@ -3578,6 +3545,8 @@ protected:
void InitExtensions();
std::vector<nsACString*> mDriverExtensionList;
GLint mViewportRect[4];
GLint mScissorRect[4];
@ -3696,10 +3665,55 @@ protected:
public:
void FlushIfHeavyGLCallsSinceLastFlush();
static bool ShouldSpew();
static bool ShouldDumpExts();
};
bool DoesStringMatch(const char* aString, const char *aWantedString);
void SplitByChar(const nsACString& str, const char delim,
std::vector<nsACString*>* out);
template<size_t N>
bool
MarkBitfieldByString(const nsACString& str, const char* (&markStrList)[N],
std::bitset<N>& markList)
{
for (size_t i = 0; i < N; i++) {
if (str.Equals(markStrList[i])) {
markList[i] = 1;
return true;
}
}
return false;
}
template<size_t N>
void
MarkBitfieldByStrings(const std::vector<nsACString*> strList,
bool dumpStrings, const char* (&markStrList)[N],
std::bitset<N>& markList)
{
for (auto itr = strList.begin(); itr != strList.end(); ++itr) {
const nsACString& str = **itr;
const bool wasMarked = MarkBitfieldByString(str, markStrList,
markList);
if (dumpStrings) {
nsCString nullTermed(str);
printf_stderr(" %s%s\n", nullTermed.BeginReading(),
wasMarked ? "(*)" : "");
}
}
}
template<typename C>
void
DeleteAndClearIterable(C& cont)
{
for(auto itr = cont.begin(); itr != cont.end(); ++itr) {
delete *itr;
}
cont.clear();
}
} /* namespace gl */
} /* namespace mozilla */

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

@ -28,10 +28,8 @@ class GLContextCGL : public GLContext
public:
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GLContextCGL, MOZ_OVERRIDE)
GLContextCGL(const SurfaceCaps& caps,
GLContext *shareContext,
NSOpenGLContext *context,
bool isOffscreen = false);
GLContextCGL(const SurfaceCaps& caps, NSOpenGLContext* context,
bool isOffscreen, ContextProfile profile);
~GLContextCGL();

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

@ -274,6 +274,16 @@ static const FeatureInfo sFeatureInfoArr[] = {
* ARB_occlusion_query (added by OpenGL 2.0).
*/
},
{
"get_string_indexed",
GLVersion::GL3,
GLESVersion::ES3,
GLContext::Extension_None,
{
GLContext::Extensions_End
}
// glGetStringi
},
{
"gpu_shader4",
GLVersion::GL3,

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

@ -21,16 +21,14 @@ namespace gl {
using namespace mozilla::gfx;
static bool gUseDoubleBufferedWindows = true;
class CGLLibrary
{
public:
CGLLibrary()
: mInitialized(false),
mOGLLibrary(nullptr),
mPixelFormat(nullptr)
{ }
: mInitialized(false)
, mUseDoubleBufferedWindows(true)
, mOGLLibrary(nullptr)
{}
bool EnsureInitialized()
{
@ -46,48 +44,33 @@ public:
}
const char* db = PR_GetEnv("MOZ_CGL_DB");
gUseDoubleBufferedWindows = (!db || *db != '0');
if (db) {
mUseDoubleBufferedWindows = *db != '0';
}
mInitialized = true;
return true;
}
NSOpenGLPixelFormat *PixelFormat()
{
if (mPixelFormat == nullptr) {
NSOpenGLPixelFormatAttribute attribs[] = {
NSOpenGLPFAAccelerated,
NSOpenGLPFAAllowOfflineRenderers,
NSOpenGLPFADoubleBuffer,
0
};
if (!gUseDoubleBufferedWindows) {
attribs[2] = 0;
}
mPixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs];
}
return mPixelFormat;
bool UseDoubleBufferedWindows() const {
MOZ_ASSERT(mInitialized);
return mUseDoubleBufferedWindows;
}
private:
bool mInitialized;
bool mUseDoubleBufferedWindows;
PRLibrary *mOGLLibrary;
NSOpenGLPixelFormat *mPixelFormat;
};
CGLLibrary sCGLLibrary;
GLContextCGL::GLContextCGL(
const SurfaceCaps& caps,
GLContext *shareContext,
NSOpenGLContext *context,
bool isOffscreen)
: GLContext(caps, shareContext, isOffscreen),
mContext(context)
GLContextCGL::GLContextCGL(const SurfaceCaps& caps, NSOpenGLContext* context,
bool isOffscreen, ContextProfile profile)
: GLContext(caps, nullptr, isOffscreen)
, mContext(context)
{
SetProfileVersion(ContextProfile::OpenGLCompatibility, 210);
SetProfileVersion(profile, 210);
}
GLContextCGL::~GLContextCGL()
@ -162,7 +145,7 @@ GLContextCGL::SetupLookupFunction()
bool
GLContextCGL::IsDoubleBuffered() const
{
return gUseDoubleBufferedWindows;
return sCGLLibrary.UseDoubleBufferedWindows();
}
bool
@ -182,26 +165,66 @@ GLContextCGL::SwapBuffers()
}
static GLContextCGL *
GetGlobalContextCGL()
{
return static_cast<GLContextCGL*>(GLContextProviderCGL::GetGlobalContext());
}
already_AddRefed<GLContext>
GLContextProviderCGL::CreateWrappingExisting(void*, void*)
{
return nullptr;
}
static const NSOpenGLPixelFormatAttribute kAttribs_singleBuffered[] = {
NSOpenGLPFAAccelerated,
NSOpenGLPFAAllowOfflineRenderers,
0
};
static const NSOpenGLPixelFormatAttribute kAttribs_doubleBuffered[] = {
NSOpenGLPFAAccelerated,
NSOpenGLPFAAllowOfflineRenderers,
NSOpenGLPFADoubleBuffer,
0
};
static const NSOpenGLPixelFormatAttribute kAttribs_offscreen[] = {
NSOpenGLPFAPixelBuffer,
0
};
static const NSOpenGLPixelFormatAttribute kAttribs_offscreen_coreProfile[] = {
NSOpenGLPFAAccelerated,
NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core,
0
};
static NSOpenGLContext*
CreateWithFormat(const NSOpenGLPixelFormatAttribute* attribs)
{
NSOpenGLPixelFormat* format = [[NSOpenGLPixelFormat alloc]
initWithAttributes:attribs];
if (!format)
return nullptr;
NSOpenGLContext* context = [[NSOpenGLContext alloc] initWithFormat:format
shareContext:nullptr];
[format release];
return context;
}
already_AddRefed<GLContext>
GLContextProviderCGL::CreateForWindow(nsIWidget *aWidget)
{
GLContextCGL *shareContext = GetGlobalContextCGL();
if (!sCGLLibrary.EnsureInitialized()) {
return nullptr;
}
NSOpenGLContext *context = [[NSOpenGLContext alloc]
initWithFormat:sCGLLibrary.PixelFormat()
shareContext:(shareContext ? shareContext->mContext : NULL)];
const NSOpenGLPixelFormatAttribute* attribs;
if (sCGLLibrary.UseDoubleBufferedWindows()) {
attribs = kAttribs_doubleBuffered;
} else {
attribs = kAttribs_singleBuffered;
}
NSOpenGLContext* context = CreateWithFormat(attribs);
if (!context) {
return nullptr;
}
@ -211,10 +234,13 @@ GLContextProviderCGL::CreateForWindow(nsIWidget *aWidget)
[context setValues:&opaque forParameter:NSOpenGLCPSurfaceOpacity];
SurfaceCaps caps = SurfaceCaps::ForRGBA();
nsRefPtr<GLContextCGL> glContext = new GLContextCGL(caps,
shareContext,
context);
ContextProfile profile = ContextProfile::OpenGLCompatibility;
nsRefPtr<GLContextCGL> glContext = new GLContextCGL(caps, context, false,
profile);
if (!glContext->Init()) {
glContext = nullptr;
[context release];
return nullptr;
}
@ -222,49 +248,54 @@ GLContextProviderCGL::CreateForWindow(nsIWidget *aWidget)
}
static already_AddRefed<GLContextCGL>
CreateOffscreenFBOContext(bool aShare = true)
CreateOffscreenFBOContext(bool requireCompatProfile)
{
if (!sCGLLibrary.EnsureInitialized()) {
return nullptr;
}
GLContextCGL *shareContext = aShare ? GetGlobalContextCGL() : nullptr;
if (aShare && !shareContext) {
// if there is no share context, then we can't use FBOs.
return nullptr;
}
ContextProfile profile;
NSOpenGLContext* context = nullptr;
NSOpenGLContext *context = [[NSOpenGLContext alloc]
initWithFormat:sCGLLibrary.PixelFormat()
shareContext:shareContext ? shareContext->GetNSOpenGLContext() : NULL];
if (!requireCompatProfile) {
profile = ContextProfile::OpenGLCore;
context = CreateWithFormat(kAttribs_offscreen_coreProfile);
}
if (!context) {
profile = ContextProfile::OpenGLCompatibility;
context = CreateWithFormat(kAttribs_offscreen);
}
if (!context) {
return nullptr;
}
SurfaceCaps dummyCaps = SurfaceCaps::Any();
nsRefPtr<GLContextCGL> glContext = new GLContextCGL(dummyCaps, shareContext, context, true);
nsRefPtr<GLContextCGL> glContext = new GLContextCGL(dummyCaps, context,
true, profile);
return glContext.forget();
}
already_AddRefed<GLContext>
GLContextProviderCGL::CreateHeadless()
GLContextProviderCGL::CreateHeadless(bool requireCompatProfile)
{
nsRefPtr<GLContextCGL> glContext = CreateOffscreenFBOContext();
if (!glContext)
nsRefPtr<GLContextCGL> gl;
gl = CreateOffscreenFBOContext(requireCompatProfile);
if (!gl)
return nullptr;
if (!glContext->Init())
if (!gl->Init())
return nullptr;
return glContext.forget();
return gl.forget();
}
already_AddRefed<GLContext>
GLContextProviderCGL::CreateOffscreen(const gfxIntSize& size,
const SurfaceCaps& caps)
const SurfaceCaps& caps,
bool requireCompatProfile)
{
nsRefPtr<GLContext> glContext = CreateHeadless();
nsRefPtr<GLContext> glContext = CreateHeadless(requireCompatProfile);
if (!glContext->InitOffscreen(ToIntSize(size), caps))
return nullptr;
@ -299,7 +330,7 @@ GLContextProviderCGL::GetGlobalContext()
void
GLContextProviderCGL::Shutdown()
{
gGlobalContext = nullptr;
gGlobalContext = nullptr;
}
} /* namespace gl */

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

@ -878,7 +878,7 @@ GLContextEGL::CreateEGLPixmapOffscreenContext(const gfxIntSize& size)
}
already_AddRefed<GLContext>
GLContextProviderEGL::CreateHeadless()
GLContextProviderEGL::CreateHeadless(bool)
{
if (!sEGLLibrary.EnsureInitialized()) {
return nullptr;
@ -897,9 +897,10 @@ GLContextProviderEGL::CreateHeadless()
// often without the ability to texture from them directly.
already_AddRefed<GLContext>
GLContextProviderEGL::CreateOffscreen(const gfxIntSize& size,
const SurfaceCaps& caps)
const SurfaceCaps& caps,
bool requireCompatProfile)
{
nsRefPtr<GLContext> glContext = CreateHeadless();
nsRefPtr<GLContext> glContext = CreateHeadless(requireCompatProfile);
if (!glContext)
return nullptr;

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

@ -1213,7 +1213,7 @@ DONE_CREATING_PIXMAP:
}
already_AddRefed<GLContext>
GLContextProviderGLX::CreateHeadless()
GLContextProviderGLX::CreateHeadless(bool)
{
gfxIntSize dummySize = gfxIntSize(16, 16);
nsRefPtr<GLContext> glContext = CreateOffscreenPixmapContext(dummySize);
@ -1225,9 +1225,10 @@ GLContextProviderGLX::CreateHeadless()
already_AddRefed<GLContext>
GLContextProviderGLX::CreateOffscreen(const gfxIntSize& size,
const SurfaceCaps& caps)
const SurfaceCaps& caps,
bool requireCompatProfile)
{
nsRefPtr<GLContext> glContext = CreateHeadless();
nsRefPtr<GLContext> glContext = CreateHeadless(requireCompatProfile);
if (!glContext)
return nullptr;

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

@ -58,11 +58,12 @@ public:
*/
static already_AddRefed<GLContext>
CreateOffscreen(const gfxIntSize& size,
const SurfaceCaps& caps);
const SurfaceCaps& caps,
bool requireCompatProfile);
// Just create a context. We'll add offscreen stuff ourselves.
static already_AddRefed<GLContext>
CreateHeadless();
CreateHeadless(bool requireCompatProfile);
/**
* Create wrapping Gecko GLContext for external gl context.

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

@ -22,13 +22,14 @@ GLContextProviderNull::CreateWrappingExisting(void*, void*)
already_AddRefed<GLContext>
GLContextProviderNull::CreateOffscreen(const gfxIntSize&,
const SurfaceCaps&)
const SurfaceCaps&,
bool)
{
return nullptr;
}
already_AddRefed<GLContext>
GLContextProviderNull::CreateHeadless()
GLContextProviderNull::CreateHeadless(bool)
{
return nullptr;
}

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

@ -607,7 +607,7 @@ CreateWindowOffscreenContext()
}
already_AddRefed<GLContext>
GLContextProviderWGL::CreateHeadless()
GLContextProviderWGL::CreateHeadless(bool)
{
if (!sWGLLib.EnsureInitialized()) {
return nullptr;
@ -641,9 +641,10 @@ GLContextProviderWGL::CreateHeadless()
already_AddRefed<GLContext>
GLContextProviderWGL::CreateOffscreen(const gfxIntSize& size,
const SurfaceCaps& caps)
const SurfaceCaps& caps,
bool requireCompatProfile)
{
nsRefPtr<GLContext> glContext = CreateHeadless();
nsRefPtr<GLContext> glContext = CreateHeadless(requireCompatProfile);
if (!glContext)
return nullptr;

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

@ -666,6 +666,10 @@ struct GLContextSymbols
GLsizei width, GLsizei height, GLsizei depth,
GLenum format, GLsizei imageSize, const GLvoid* data);
PFNGLCOMPRESSEDTEXSUBIMAGE3D fCompressedTexSubImage3D;
// get_string_indexed
typedef const GLubyte* (GLAPIENTRY * pfnGLGetStringiT)(GLenum name, GLuint index);
pfnGLGetStringiT fGetStringi;
};
}

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

@ -12,8 +12,3 @@ GLFormats::GLFormats()
{
std::memset(this, 0, sizeof(GLFormats));
}
PixelBufferFormat::PixelBufferFormat()
{
std::memset(this, 0, sizeof(PixelBufferFormat));
}

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

@ -43,19 +43,6 @@ struct GLFormats
GLsizei samples;
};
struct PixelBufferFormat
{
// Constructs a zeroed object:
PixelBufferFormat();
int red, green, blue;
int alpha;
int depth, stencil;
int samples;
int ColorBits() const { return red + green + blue; }
};
} /* namespace gl */
} /* namespace mozilla */

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

@ -35,8 +35,7 @@ static const char *sEGLExtensionNames[] = {
"EGL_EXT_create_context_robustness",
"EGL_KHR_image",
"EGL_KHR_fence_sync",
"EGL_ANDROID_native_fence_sync",
nullptr
"EGL_ANDROID_native_fence_sync"
};
#if defined(ANDROID)
@ -421,15 +420,23 @@ GLLibraryEGL::EnsureInitialized()
void
GLLibraryEGL::InitExtensions()
{
const char *extensions = (const char*)fQueryString(mEGLDisplay, LOCAL_EGL_EXTENSIONS);
if (!extensions) {
const char* rawExts = (const char*)fQueryString(mEGLDisplay,
LOCAL_EGL_EXTENSIONS);
if (rawExts) {
nsDependentCString exts(rawExts);
SplitByChar(exts, ' ', &mDriverExtensionList);
} else {
NS_WARNING("Failed to load EGL extension list!");
return;
}
GLContext::InitializeExtensionsBitSet(mAvailableExtensions, extensions,
sEGLExtensionNames);
const bool shouldDumpExts = GLContext::ShouldDumpExts();
if (shouldDumpExts) {
printf_stderr("%i EGL driver extensions:\n",
(uint32_t)mDriverExtensionList.size());
}
MarkBitfieldByStrings(mDriverExtensionList, shouldDumpExts,
sEGLExtensionNames, mAvailableExtensions);
}
void

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

@ -15,6 +15,7 @@
#include "GeckoProfiler.h"
#include <bitset>
#include <vector>
#if defined(XP_WIN)
@ -142,6 +143,7 @@ public:
}
protected:
std::vector<nsACString*> mDriverExtensionList;
std::bitset<Extensions_Max> mAvailableExtensions;
public:

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

@ -39,7 +39,7 @@ GLImage::GetAsSourceSurface()
MOZ_ASSERT(NS_IsMainThread(), "Should be on the main thread");
if (!sSnapshotContext) {
sSnapshotContext = GLContextProvider::CreateHeadless();
sSnapshotContext = GLContextProvider::CreateHeadless(false);
if (!sSnapshotContext) {
NS_WARNING("Failed to create snapshot GLContext");
return nullptr;

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

@ -364,6 +364,54 @@ TextureClientD3D11::BorrowDrawTarget()
return mDrawTarget;
}
static const GUID sD3D11TextureUsage =
{ 0xd89275b0, 0x6c7d, 0x4038, { 0xb5, 0xfa, 0x4d, 0x87, 0x16, 0xd5, 0xcc, 0x4e } };
/* This class get's it's lifetime tied to a D3D texture
* and increments memory usage on construction and decrements
* on destruction */
class TextureMemoryMeasurer : public IUnknown
{
public:
TextureMemoryMeasurer(size_t aMemoryUsed)
{
mMemoryUsed = aMemoryUsed;
gfxWindowsPlatform::sD3D11MemoryUsed += mMemoryUsed;
mRefCnt = 0;
}
STDMETHODIMP_(ULONG) AddRef() {
mRefCnt++;
return mRefCnt;
}
STDMETHODIMP QueryInterface(REFIID riid,
void **ppvObject)
{
IUnknown *punk = nullptr;
if (riid == IID_IUnknown) {
punk = this;
}
*ppvObject = punk;
if (punk) {
punk->AddRef();
return S_OK;
} else {
return E_NOINTERFACE;
}
}
STDMETHODIMP_(ULONG) Release() {
int refCnt = --mRefCnt;
if (refCnt == 0) {
gfxWindowsPlatform::sD3D11MemoryUsed -= mMemoryUsed;
delete this;
}
return refCnt;
}
private:
int mRefCnt;
int mMemoryUsed;
};
bool
TextureClientD3D11::AllocateForSurface(gfx::IntSize aSize, TextureAllocationFlags aFlags)
{
@ -386,6 +434,14 @@ TextureClientD3D11::AllocateForSurface(gfx::IntSize aSize, TextureAllocationFlag
newDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED;
hr = d3d11device->CreateTexture2D(&newDesc, nullptr, byRef(mTexture));
if (FAILED(hr)) {
gfxCriticalError(CriticalLog::DefaultOptions(Factory::ReasonableSurfaceSize(aSize))) << "[D3D11] 2 CreateTexture2D failure " << aSize << " Code: " << gfx::hexa(hr);
return false;
}
mTexture->SetPrivateDataInterface(sD3D11TextureUsage,
new TextureMemoryMeasurer(newDesc.Width * newDesc.Height *
(mFormat == SurfaceFormat::A8 ?
1 : 4)));
} else
{
ID3D10Device* device = gfxWindowsPlatform::GetPlatform()->GetD3D10Device();
@ -397,11 +453,15 @@ TextureClientD3D11::AllocateForSurface(gfx::IntSize aSize, TextureAllocationFlag
newDesc.MiscFlags = D3D10_RESOURCE_MISC_SHARED;
hr = device->CreateTexture2D(&newDesc, nullptr, byRef(mTexture10));
}
if (FAILED(hr)) {
gfxCriticalError(CriticalLog::DefaultOptions(Factory::ReasonableSurfaceSize(aSize))) << "[D3D10] 2 CreateTexture2D failure " << aSize << " Code: " << gfx::hexa(hr);
return false;
}
mTexture10->SetPrivateDataInterface(sD3D11TextureUsage,
new TextureMemoryMeasurer(newDesc.Width * newDesc.Height *
(mFormat == SurfaceFormat::A8 ?
1 : 4)));
if (FAILED(hr)) {
gfxCriticalError(CriticalLog::DefaultOptions(Factory::ReasonableSurfaceSize(aSize))) << "[D3D11] 2 CreateTexture2D failure " << aSize << " Code: " << gfx::hexa(hr);
return false;
}
// Defer clearing to the next time we lock to avoid an extra (expensive) lock.

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

@ -124,8 +124,11 @@ CompositorOGL::CreateContext()
SurfaceCaps caps = SurfaceCaps::ForRGB();
caps.preserve = false;
caps.bpp16 = gfxPlatform::GetPlatform()->GetOffscreenFormat() == gfxImageFormat::RGB16_565;
bool requireCompatProfile = true;
context = GLContextProvider::CreateOffscreen(gfxIntSize(mSurfaceSize.width,
mSurfaceSize.height), caps);
mSurfaceSize.height),
caps, requireCompatProfile);
}
if (!context)

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

@ -45,7 +45,7 @@ public:
caps.preserve = false;
caps.bpp16 = false;
nsRefPtr<GLContext> context = GLContextProvider::CreateOffscreen(
gfxIntSize(gCompWidth, gCompHeight), caps);
gfxIntSize(gCompWidth, gCompHeight), caps, true);
return context.forget().take();
}
return nullptr;

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

@ -1099,8 +1099,9 @@ gfxPlatform::GetSkiaGLGlue()
* FIXME: This should be stored in TLS or something, since there needs to be one for each thread using it. As it
* stands, this only works on the main thread.
*/
mozilla::gl::SurfaceCaps caps = mozilla::gl::SurfaceCaps::ForRGBA();
nsRefPtr<mozilla::gl::GLContext> glContext = mozilla::gl::GLContextProvider::CreateOffscreen(gfxIntSize(16, 16), caps);
bool requireCompatProfile = true;
nsRefPtr<mozilla::gl::GLContext> glContext;
glContext = mozilla::gl::GLContextProvider::CreateHeadless(requireCompatProfile);
if (!glContext) {
printf_stderr("Failed to create GLContext for SkiaGL!\n");
return nullptr;
@ -2164,6 +2165,7 @@ gfxPlatform::OptimalFormatForContent(gfxContentType aContent)
*/
static bool sLayersSupportsD3D9 = false;
static bool sLayersSupportsD3D11 = false;
static bool sLayersSupportsDXVA = false;
static bool sBufferRotationCheckPref = true;
static bool sPrefBrowserTabsRemoteAutostart = false;
@ -2205,6 +2207,11 @@ InitLayersAccelerationPrefs()
// Always support D3D11 when WARP is allowed.
sLayersSupportsD3D11 = true;
}
if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DXVA, &status))) {
if (status == nsIGfxInfo::FEATURE_STATUS_OK) {
sLayersSupportsDXVA = true;
}
}
}
}
#endif
@ -2231,6 +2238,15 @@ gfxPlatform::CanUseDirect3D11()
return sLayersSupportsD3D11;
}
bool
gfxPlatform::CanUseDXVA()
{
// this function is called from the compositor thread, so it is not
// safe to init the prefs etc. from here.
MOZ_ASSERT(sLayersAccelerationPrefsInitialized);
return sLayersSupportsDXVA;
}
bool
gfxPlatform::BufferRotationEnabled()
{

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

@ -481,6 +481,7 @@ public:
static bool CanUseDirect3D9();
static bool CanUseDirect3D11();
static bool CanUseDXVA();
/**
* Is it possible to use buffer rotation. Note that these

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

@ -650,9 +650,10 @@ gfxUserFontEntry::LoadPlatformFont(const uint8_t* aFontData, uint32_t& aLength)
if (LOG_ENABLED()) {
nsAutoCString fontURI;
mSrcList[mSrcIndex].mURI->GetSpec(fontURI);
LOG(("userfonts (%p) [src %d] loaded uri: (%s) for (%s) gen: %8.8x\n",
LOG(("userfonts (%p) [src %d] loaded uri: (%s) for (%s) (%p) gen: %8.8x\n",
mFontSet, mSrcIndex, fontURI.get(),
NS_ConvertUTF16toUTF8(mFamilyName).get(),
this,
uint32_t(mFontSet->mGeneration)));
}
#endif
@ -786,17 +787,6 @@ gfxUserFontSet::FindOrCreateUserFontEntry(
aItalicStyle, aFeatureSettings,
aLanguageOverride, aUnicodeRanges);
entry->mFamilyName = aFamilyName;
#ifdef PR_LOGGING
if (LOG_ENABLED()) {
LOG(("userfonts (%p) created \"%s\" (%p) with style: %s weight: %d "
"stretch: %d",
this, NS_ConvertUTF16toUTF8(aFamilyName).get(), entry.get(),
(aItalicStyle & NS_FONT_STYLE_ITALIC ? "italic" :
(aItalicStyle & NS_FONT_STYLE_OBLIQUE ? "oblique" : "normal")),
aWeight, aStretch));
}
#endif
}
return entry.forget();
@ -865,8 +855,11 @@ gfxUserFontSet::AddUserFontEntry(const nsAString& aFamilyName,
#ifdef PR_LOGGING
if (LOG_ENABLED()) {
LOG(("userfonts (%p) added \"%s\" (%p)",
this, NS_ConvertUTF16toUTF8(aFamilyName).get(), aUserFontEntry));
LOG(("userfonts (%p) added to \"%s\" (%p) style: %s weight: %d "
"stretch: %d",
this, NS_ConvertUTF16toUTF8(aFamilyName).get(), aUserFontEntry,
(aUserFontEntry->IsItalic() ? "italic" : "normal"),
aUserFontEntry->Weight(), aUserFontEntry->Stretch()));
}
#endif
}

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

@ -325,6 +325,25 @@ public:
NS_IMPL_ISUPPORTS(GPUAdapterReporter, nsIMemoryReporter)
Atomic<size_t> gfxWindowsPlatform::sD3D11MemoryUsed;
class D3D11TextureReporter MOZ_FINAL : public nsIMemoryReporter
{
public:
NS_DECL_ISUPPORTS
NS_IMETHOD CollectReports(nsIHandleReportCallback *aHandleReport,
nsISupports* aData, bool aAnonymize) MOZ_OVERRIDE
{
return MOZ_COLLECT_REPORT("d3d11-shared-textures", KIND_OTHER, UNITS_BYTES,
gfxWindowsPlatform::sD3D11MemoryUsed,
"Memory used for D3D11 shared textures");
}
};
NS_IMPL_ISUPPORTS(D3D11TextureReporter, nsIMemoryReporter)
gfxWindowsPlatform::gfxWindowsPlatform()
: mD3D11DeviceInitialized(false)
, mIsWARP(false)
@ -352,6 +371,7 @@ gfxWindowsPlatform::gfxWindowsPlatform()
UpdateRenderMode();
RegisterStrongMemoryReporter(new GPUAdapterReporter());
RegisterStrongMemoryReporter(new D3D11TextureReporter());
}
gfxWindowsPlatform::~gfxWindowsPlatform()

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

@ -22,6 +22,7 @@
#include "gfxPlatform.h"
#include "gfxTypes.h"
#include "mozilla/Attributes.h"
#include "mozilla/Atomics.h"
#include "nsTArray.h"
#include "nsDataHashtable.h"
@ -252,6 +253,8 @@ public:
bool IsWARP() { return mIsWARP; }
static mozilla::Atomic<size_t> sD3D11MemoryUsed;
protected:
RenderMode mRenderMode;

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

@ -98,9 +98,7 @@ GeckoChildProcessHost::GeckoChildProcessHost(GeckoProcessType aProcessType,
#if defined(MOZ_SANDBOX) && defined(XP_WIN)
mEnableSandboxLogging(false),
mEnableNPAPISandbox(false),
#if defined(MOZ_CONTENT_SANDBOX)
mMoreStrictContentSandbox(false),
#endif
mMoreStrictSandbox(false),
#endif
mChildProcessHandle(0)
#if defined(MOZ_WIDGET_COCOA)
@ -273,7 +271,7 @@ GeckoChildProcessHost::PrepareLaunch()
#if defined(MOZ_CONTENT_SANDBOX)
// We need to get the pref here as the process is launched off main thread.
if (mProcessType == GeckoProcessType_Content) {
mMoreStrictContentSandbox =
mMoreStrictSandbox =
Preferences::GetBool("security.sandbox.windows.content.moreStrict");
mEnableSandboxLogging =
Preferences::GetBool("security.sandbox.windows.log");
@ -807,7 +805,7 @@ GeckoChildProcessHost::PerformAsyncLaunchInternal(std::vector<std::string>& aExt
case GeckoProcessType_Content:
#if defined(MOZ_CONTENT_SANDBOX)
if (!PR_GetEnv("MOZ_DISABLE_CONTENT_SANDBOX")) {
mSandboxBroker.SetSecurityLevelForContentProcess(mMoreStrictContentSandbox);
mSandboxBroker.SetSecurityLevelForContentProcess(mMoreStrictSandbox);
cmdLine.AppendLooseValue(UTF8ToWide("-sandbox"));
shouldSandboxCurrentProcess = true;
}
@ -816,7 +814,7 @@ GeckoChildProcessHost::PerformAsyncLaunchInternal(std::vector<std::string>& aExt
case GeckoProcessType_Plugin:
if (mEnableNPAPISandbox &&
!PR_GetEnv("MOZ_DISABLE_NPAPI_SANDBOX")) {
mSandboxBroker.SetSecurityLevelForPluginProcess();
mSandboxBroker.SetSecurityLevelForPluginProcess(mMoreStrictSandbox);
cmdLine.AppendLooseValue(UTF8ToWide("-sandbox"));
shouldSandboxCurrentProcess = true;
}

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

@ -177,9 +177,7 @@ protected:
// sandboxing in this class at some point. Unfortunately it will take a bit
// of reorganizing so I don't think this patch is the right time.
bool mEnableNPAPISandbox;
#if defined(MOZ_CONTENT_SANDBOX)
bool mMoreStrictContentSandbox;
#endif
bool mMoreStrictSandbox;
#endif
#endif // XP_WIN

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

@ -0,0 +1,30 @@
function toint32() {
// The test case to trigger MToInt32 operation.
var ToInteger = getSelfHostedValue("ToInteger");
// Case1: The input operand is constant int32.
var result = ToInteger(1);
assertEq(result, 1);
// Case2: The input operand is constant double.
result = ToInteger(0.12);
assertEq(result, 0);
// Case3: The input operand is constant float.
result = ToInteger(Math.fround(0.13));
assertEq(result, 0);
// Case4: The input operand is constant boolean.
result = ToInteger(true);
assertEq(result, 1);
// Case5: The input operand is null.
result = ToInteger(null);
assertEq(result, 0);
}
toint32();
toint32();

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

@ -3806,10 +3806,20 @@ CodeGenerator::generateBody()
if (!addNativeToBytecodeEntry(iter->mirRaw()->trackedSite()))
return false;
}
// Track the start native offset of optimizations.
if (iter->mirRaw()->trackedOptimizations()) {
if (!addTrackedOptimizationsEntry(iter->mirRaw()->trackedOptimizations()))
return false;
}
}
iter->accept(this);
// Track the end native offset of optimizations.
if (iter->mirRaw() && iter->mirRaw()->trackedOptimizations())
extendTrackedOptimizationsEntry(iter->mirRaw()->trackedOptimizations());
#ifdef DEBUG
if (!counts)
emitDebugResultChecks(*iter);
@ -7235,6 +7245,28 @@ CodeGenerator::link(JSContext *cx, types::CompilerConstraintList *constraints)
// nativeToBytecodeScriptList_ is no longer needed.
js_free(nativeToBytecodeScriptList_);
// Generate the tracked optimizations map.
if (isOptimizationTrackingEnabled()) {
// Treat OOMs and failures as if optimization tracking were turned off.
types::TypeSet::TypeList *allTypes = cx->new_<types::TypeSet::TypeList>();
if (allTypes && generateCompactTrackedOptimizationsMap(cx, code, allTypes)) {
const uint8_t *optsRegionTableAddr = trackedOptimizationsMap_ +
trackedOptimizationsRegionTableOffset_;
const IonTrackedOptimizationsRegionTable *optsRegionTable =
(const IonTrackedOptimizationsRegionTable *) optsRegionTableAddr;
const uint8_t *optsTypesTableAddr = trackedOptimizationsMap_ +
trackedOptimizationsTypesTableOffset_;
const IonTrackedOptimizationsTypesTable *optsTypesTable =
(const IonTrackedOptimizationsTypesTable *) optsTypesTableAddr;
const uint8_t *optsAttemptsTableAddr = trackedOptimizationsMap_ +
trackedOptimizationsAttemptsTableOffset_;
const IonTrackedOptimizationsAttemptsTable *optsAttemptsTable =
(const IonTrackedOptimizationsAttemptsTable *) optsAttemptsTableAddr;
entry.initTrackedOptimizations(optsRegionTable, optsTypesTable, optsAttemptsTable,
allTypes);
}
}
// Add entry to the global table.
JitcodeGlobalTable *globalTable = cx->runtime()->jitRuntime()->getJitcodeGlobalTable();
if (!globalTable->addEntry(entry, cx->runtime())) {

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

@ -16,6 +16,8 @@
namespace js {
namespace jit {
class TrackedOptimizations;
inline unsigned
StartArgSlot(JSScript *script)
{
@ -130,13 +132,16 @@ class BytecodeSite : public TempObject
// Bytecode address within innermost active function.
jsbytecode *pc_;
// Optimization information at the pc.
TrackedOptimizations *optimizations_;
public:
BytecodeSite()
: tree_(nullptr), pc_(nullptr)
: tree_(nullptr), pc_(nullptr), optimizations_(nullptr)
{}
BytecodeSite(InlineScriptTree *tree, jsbytecode *pc)
: tree_(tree), pc_(pc)
: tree_(tree), pc_(pc), optimizations_(nullptr)
{
MOZ_ASSERT(tree_ != nullptr);
MOZ_ASSERT(pc_ != nullptr);
@ -153,6 +158,19 @@ class BytecodeSite : public TempObject
JSScript *script() const {
return tree_ ? tree_->script() : nullptr;
}
bool hasOptimizations() const {
return !!optimizations_;
}
TrackedOptimizations *optimizations() const {
MOZ_ASSERT(hasOptimizations());
return optimizations_;
}
void setOptimizations(TrackedOptimizations *optimizations) {
optimizations_ = optimizations;
}
};
enum AnalysisMode {

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

@ -1717,6 +1717,30 @@ TrackPropertiesForSingletonScopes(JSContext *cx, JSScript *script, BaselineFrame
}
}
static void
TrackIonAbort(JSContext *cx, JSScript *script, jsbytecode *pc, const char *message)
{
if (!cx->runtime()->jitRuntime()->isOptimizationTrackingEnabled(cx->runtime()))
return;
// Only bother tracking aborts of functions we're attempting to
// Ion-compile after successfully running in Baseline.
if (!script->hasBaselineScript())
return;
JitcodeGlobalTable *table = cx->runtime()->jitRuntime()->getJitcodeGlobalTable();
JitcodeGlobalEntry entry;
table->lookupInfallible(script->baselineScript()->method()->raw(), &entry, cx->runtime());
entry.baselineEntry().trackIonAbort(pc, message);
}
static void
TrackAndSpewIonAbort(JSContext *cx, JSScript *script, const char *message)
{
JitSpew(JitSpew_IonAbort, message);
TrackIonAbort(cx, script, script->code(), message);
}
static AbortReason
IonCompile(JSContext *cx, JSScript *script,
BaselineFrame *baselineFrame, jsbytecode *osrPc, bool constructing,
@ -1822,6 +1846,15 @@ IonCompile(JSContext *cx, JSScript *script,
return AbortReason_Alloc;
}
}
if (builder->hadActionableAbort()) {
JSScript *abortScript;
jsbytecode *abortPc;
const char *abortMessage;
builder->actionableAbortLocationAndMessage(&abortScript, &abortPc, &abortMessage);
TrackIonAbort(cx, abortScript, abortPc, abortMessage);
}
return reason;
}
@ -1861,7 +1894,7 @@ IonCompile(JSContext *cx, JSScript *script,
}
static bool
CheckFrame(BaselineFrame *frame)
CheckFrame(JSContext *cx, BaselineFrame *frame)
{
MOZ_ASSERT(!frame->script()->isGenerator());
MOZ_ASSERT(!frame->isDebuggerEvalFrame());
@ -1869,12 +1902,12 @@ CheckFrame(BaselineFrame *frame)
// This check is to not overrun the stack.
if (frame->isFunctionFrame()) {
if (TooManyActualArguments(frame->numActualArgs())) {
JitSpew(JitSpew_IonAbort, "too many actual args");
TrackAndSpewIonAbort(cx, frame->script(), "too many actual arguments");
return false;
}
if (TooManyFormalArguments(frame->numFormalArgs())) {
JitSpew(JitSpew_IonAbort, "too many args");
TrackAndSpewIonAbort(cx, frame->script(), "too many arguments");
return false;
}
}
@ -1889,12 +1922,12 @@ CheckScript(JSContext *cx, JSScript *script, bool osr)
// Eval frames are not yet supported. Supporting this will require new
// logic in pushBailoutFrame to deal with linking prev.
// Additionally, JSOP_DEFVAR support will require baking in isEvalFrame().
JitSpew(JitSpew_IonAbort, "eval script");
TrackAndSpewIonAbort(cx, script, "eval script");
return false;
}
if (script->isGenerator()) {
JitSpew(JitSpew_IonAbort, "generator script");
TrackAndSpewIonAbort(cx, script, "generator script");
return false;
}
@ -1902,7 +1935,7 @@ CheckScript(JSContext *cx, JSScript *script, bool osr)
// Support non-CNG functions but not other scripts. For global scripts,
// IonBuilder currently uses the global object as scope chain, this is
// not valid for non-CNG code.
JitSpew(JitSpew_IonAbort, "not compile-and-go");
TrackAndSpewIonAbort(cx, script, "not compile-and-go");
return false;
}
@ -1923,6 +1956,7 @@ CheckScriptSize(JSContext *cx, JSScript* script)
if (!OffThreadCompilationAvailable(cx)) {
JitSpew(JitSpew_IonAbort, "Script too large (%u bytes) (%u locals/args)",
script->length(), numLocalsAndArgs);
TrackIonAbort(cx, script, script->code(), "too large");
return Method_CantCompile;
}
}
@ -1957,7 +1991,7 @@ Compile(JSContext *cx, HandleScript script, BaselineFrame *osrFrame, jsbytecode
return Method_Skipped;
if (script->isDebuggee() || (osrFrame && osrFrame->isDebuggee())) {
JitSpew(JitSpew_IonAbort, "debugging");
TrackAndSpewIonAbort(cx, script, "debugging");
return Method_Skipped;
}
@ -2045,7 +2079,7 @@ jit::CanEnterAtBranch(JSContext *cx, JSScript *script, BaselineFrame *osrFrame,
return Method_Skipped;
// Mark as forbidden if frame can't be handled.
if (!CheckFrame(osrFrame)) {
if (!CheckFrame(cx, osrFrame)) {
ForbidCompilation(cx, script);
return Method_CantCompile;
}
@ -2112,13 +2146,13 @@ jit::CanEnter(JSContext *cx, RunState &state)
InvokeState &invoke = *state.asInvoke();
if (TooManyActualArguments(invoke.args().length())) {
JitSpew(JitSpew_IonAbort, "too many actual args");
TrackAndSpewIonAbort(cx, script, "too many actual args");
ForbidCompilation(cx, script);
return Method_CantCompile;
}
if (TooManyFormalArguments(invoke.args().callee().as<JSFunction>().nargs())) {
JitSpew(JitSpew_IonAbort, "too many args");
TrackAndSpewIonAbort(cx, script, "too many args");
ForbidCompilation(cx, script);
return Method_CantCompile;
}
@ -2157,7 +2191,7 @@ jit::CompileFunctionForBaseline(JSContext *cx, HandleScript script, BaselineFram
MOZ_ASSERT(frame->isFunctionFrame());
// Mark as forbidden if frame can't be handled.
if (!CheckFrame(frame)) {
if (!CheckFrame(cx, frame)) {
ForbidCompilation(cx, script);
return Method_CantCompile;
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

@ -18,6 +18,7 @@
#include "jit/MIR.h"
#include "jit/MIRGenerator.h"
#include "jit/MIRGraph.h"
#include "jit/OptimizationTracking.h"
namespace js {
namespace jit {
@ -234,6 +235,7 @@ class IonBuilder
uint32_t readIndex(jsbytecode *pc);
JSAtom *readAtom(jsbytecode *pc);
bool abort(const char *message, ...);
void trackActionableAbort(const char *message);
void spew(const char *message);
JSFunction *getSingleCallTarget(types::TemporaryTypeSet *calleeTypes);
@ -448,10 +450,10 @@ class IonBuilder
bool isDOM);
bool setPropTryDefiniteSlot(bool *emitted, MDefinition *obj,
PropertyName *name, MDefinition *value,
types::TemporaryTypeSet *objTypes);
bool barrier, types::TemporaryTypeSet *objTypes);
bool setPropTryInlineAccess(bool *emitted, MDefinition *obj,
PropertyName *name, MDefinition *value,
types::TemporaryTypeSet *objTypes);
bool barrier, types::TemporaryTypeSet *objTypes);
bool setPropTryTypedObject(bool *emitted, MDefinition *obj,
PropertyName *name, MDefinition *value);
bool setPropTryReferencePropOfTypedObject(bool *emitted,
@ -518,6 +520,7 @@ class IonBuilder
ReferenceTypeDescr::Type type,
PropertyName *name);
MDefinition *neuterCheck(MDefinition *obj);
JSObject *getStaticTypedArrayObject(MDefinition *obj, MDefinition *index);
// jsop_setelem() helpers.
bool setElemTryTypedArray(bool *emitted, MDefinition *object,
@ -904,6 +907,14 @@ class IonBuilder
// performed by FinishOffThreadBuilder().
CodeGenerator *backgroundCodegen_;
// Some aborts are actionable (e.g., using an unsupported bytecode). When
// optimization tracking is enabled, the location and message of the abort
// are recorded here so they may be propagated to the script's
// corresponding JitcodeGlobalEntry::BaselineEntry.
JSScript *actionableAbortScript_;
jsbytecode *actionableAbortPc_;
const char *actionableAbortMessage_;
public:
void clearForBackEnd();
@ -922,6 +933,21 @@ class IonBuilder
const JSAtomState &names() { return compartment->runtime()->names(); }
bool hadActionableAbort() const {
MOZ_ASSERT(!actionableAbortScript_ ||
(actionableAbortPc_ && actionableAbortMessage_));
return actionableAbortScript_ != nullptr;
}
void actionableAbortLocationAndMessage(JSScript **abortScript, jsbytecode **abortPc,
const char **abortMessage)
{
MOZ_ASSERT(hadActionableAbort());
*abortScript = actionableAbortScript_;
*abortPc = actionableAbortPc_;
*abortMessage = actionableAbortMessage_;
}
private:
bool init();
@ -948,11 +974,20 @@ class IonBuilder
MBasicBlock *current;
uint32_t loopDepth_;
Vector<BytecodeSite *, 0, JitAllocPolicy> trackedOptimizationSites_;
BytecodeSite *bytecodeSite(jsbytecode *pc) {
MOZ_ASSERT(info().inlineScriptTree()->script()->containsPC(pc));
// See comment in maybeTrackedOptimizationSite.
if (isOptimizationTrackingEnabled()) {
if (BytecodeSite *site = maybeTrackedOptimizationSite(pc))
return site;
}
return new(alloc()) BytecodeSite(info().inlineScriptTree(), pc);
}
BytecodeSite *maybeTrackedOptimizationSite(jsbytecode *pc);
MDefinition *lexicalCheck_;
void setLexicalCheck(MDefinition *lexical) {
@ -1051,6 +1086,59 @@ class IonBuilder
}
MGetPropertyCache *maybeFallbackFunctionGetter_;
// Used in tracking outcomes of optimization strategies for devtools.
void startTrackingOptimizations();
// The track* methods below are called often. Do not combine them with the
// unchecked variants, despite the unchecked variants having no other
// callers.
void trackTypeInfo(TrackedTypeSite site, MIRType mirType,
types::TemporaryTypeSet *typeSet)
{
if (MOZ_UNLIKELY(current->trackedSite()->hasOptimizations()))
trackTypeInfoUnchecked(site, mirType, typeSet);
}
void trackTypeInfo(TrackedTypeSite site, JSObject *obj) {
if (MOZ_UNLIKELY(current->trackedSite()->hasOptimizations()))
trackTypeInfoUnchecked(site, obj);
}
void trackTypeInfo(CallInfo &callInfo) {
if (MOZ_UNLIKELY(current->trackedSite()->hasOptimizations()))
trackTypeInfoUnchecked(callInfo);
}
void trackOptimizationAttempt(TrackedStrategy strategy) {
if (MOZ_UNLIKELY(current->trackedSite()->hasOptimizations()))
trackOptimizationAttemptUnchecked(strategy);
}
void amendOptimizationAttempt(uint32_t index) {
if (MOZ_UNLIKELY(current->trackedSite()->hasOptimizations()))
amendOptimizationAttemptUnchecked(index);
}
void trackOptimizationOutcome(TrackedOutcome outcome) {
if (MOZ_UNLIKELY(current->trackedSite()->hasOptimizations()))
trackOptimizationOutcomeUnchecked(outcome);
}
void trackOptimizationSuccess() {
if (MOZ_UNLIKELY(current->trackedSite()->hasOptimizations()))
trackOptimizationSuccessUnchecked();
}
void trackInlineSuccess(InliningStatus status = InliningStatus_Inlined) {
if (MOZ_UNLIKELY(current->trackedSite()->hasOptimizations()))
trackInlineSuccessUnchecked(status);
}
// Out-of-line variants that don't check if optimization tracking is
// enabled.
void trackTypeInfoUnchecked(TrackedTypeSite site, MIRType mirType,
types::TemporaryTypeSet *typeSet);
void trackTypeInfoUnchecked(TrackedTypeSite site, JSObject *obj);
void trackTypeInfoUnchecked(CallInfo &callInfo);
void trackOptimizationAttemptUnchecked(TrackedStrategy strategy);
void amendOptimizationAttemptUnchecked(uint32_t index);
void trackOptimizationOutcomeUnchecked(TrackedOutcome outcome);
void trackOptimizationSuccessUnchecked();
void trackInlineSuccessUnchecked(InliningStatus status);
};
class CallInfo

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

@ -402,6 +402,10 @@ class JitRuntime
bool isProfilerInstrumentationEnabled(JSRuntime *rt) {
return rt->spsProfiler.enabled();
}
bool isOptimizationTrackingEnabled(JSRuntime *rt) {
return isProfilerInstrumentationEnabled(rt);
}
};
class JitZone

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

@ -255,6 +255,7 @@ jit::CheckLogging()
" unroll Loop unrolling\n"
" logs C1 and JSON visualization logging\n"
" profiling Profiling-related information\n"
" trackopts Optimization tracking information\n"
" all Everything\n"
"\n"
" bl-aborts Baseline compiler abort messages\n"
@ -315,6 +316,8 @@ jit::CheckLogging()
EnableIonDebugLogging();
if (ContainsFlag(env, "profiling"))
EnableChannel(JitSpew_Profiling);
if (ContainsFlag(env, "trackopts"))
EnableChannel(JitSpew_OptimizationTracking);
if (ContainsFlag(env, "all"))
LoggingBits = uint32_t(-1);

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

@ -46,6 +46,8 @@ namespace jit {
_(Pools) \
/* Profiling-related information */ \
_(Profiling) \
/* Information of tracked opt strats */ \
_(OptimizationTracking) \
/* Debug info about the I$ */ \
_(CacheFlush) \
\

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

@ -109,6 +109,19 @@ JitcodeGlobalEntry::IonEntry::destroy()
// Free the script list
js_free(scriptList_);
scriptList_ = nullptr;
// The optimizations region and attempts table is in the same block of
// memory, the beginning of which is pointed to by
// optimizationsRegionTable_->payloadStart().
if (optsRegionTable_) {
MOZ_ASSERT(optsAttemptsTable_);
js_free((void *) optsRegionTable_->payloadStart());
}
optsRegionTable_ = nullptr;
optsTypesTable_ = nullptr;
optsAttemptsTable_ = nullptr;
js_delete(optsAllTypes_);
optsAllTypes_ = nullptr;
}
bool

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

@ -10,6 +10,7 @@
#include "ds/SplayTree.h"
#include "jit/CompactBuffer.h"
#include "jit/CompileInfo.h"
#include "jit/OptimizationTracking.h"
#include "jit/shared/CodeGenerator-shared.h"
namespace js {
@ -106,6 +107,23 @@ class JitcodeGlobalEntry
// of the memory space.
JitcodeIonTable *regionTable_;
// optsRegionTable_ points to the table within the compact
// optimizations map indexing all regions that have tracked
// optimization attempts. optsTypesTable_ is the tracked typed info
// associated with the attempts vectors; it is the same length as the
// attempts table. optsAttemptsTable_ is the table indexing those
// attempts vectors.
//
// All pointers point into the same block of memory; the beginning of
// the block is optimizationRegionTable_->payloadStart().
const IonTrackedOptimizationsRegionTable *optsRegionTable_;
const IonTrackedOptimizationsTypesTable *optsTypesTable_;
const IonTrackedOptimizationsAttemptsTable *optsAttemptsTable_;
// The types table above records type sets, which have been gathered
// into one vector here.
types::TypeSet::TypeList *optsAllTypes_;
struct ScriptNamePair {
JSScript *script;
char *str;
@ -136,6 +154,21 @@ class JitcodeGlobalEntry
BaseEntry::init(Ion, nativeStartAddr, nativeEndAddr);
regionTable_ = regionTable;
scriptList_ = scriptList;
optsRegionTable_ = nullptr;
optsTypesTable_ = nullptr;
optsAllTypes_ = nullptr;
optsAttemptsTable_ = nullptr;
}
void initTrackedOptimizations(const IonTrackedOptimizationsRegionTable *regionTable,
const IonTrackedOptimizationsTypesTable *typesTable,
const IonTrackedOptimizationsAttemptsTable *attemptsTable,
types::TypeSet::TypeList *allTypes)
{
optsRegionTable_ = regionTable;
optsTypesTable_ = typesTable;
optsAttemptsTable_ = attemptsTable;
optsAllTypes_ = allTypes;
}
SizedScriptList *sizedScriptList() const {
@ -176,6 +209,12 @@ class JitcodeGlobalEntry
uint32_t callStackAtAddr(JSRuntime *rt, void *ptr, const char **results,
uint32_t maxResults) const;
bool hasTrackedOptimizations() const {
return !!optsRegionTable_;
}
bool optimizationAttemptsAtAddr(void *ptr, mozilla::Maybe<AttemptsVector> &attempts);
};
struct BaselineEntry : public BaseEntry
@ -183,6 +222,12 @@ class JitcodeGlobalEntry
JSScript *script_;
const char *str_;
// Last location that caused Ion to abort compilation and the reason
// therein, if any. Only actionable aborts are tracked. Internal
// errors like OOMs are not.
jsbytecode *ionAbortPc_;
const char *ionAbortMessage_;
void init(void *nativeStartAddr, void *nativeEndAddr, JSScript *script, const char *str)
{
MOZ_ASSERT(script != nullptr);
@ -199,6 +244,18 @@ class JitcodeGlobalEntry
return str_;
}
void trackIonAbort(jsbytecode *pc, const char *message) {
MOZ_ASSERT(script_->containsPC(pc));
MOZ_ASSERT(message);
ionAbortPc_ = pc;
ionAbortMessage_ = message;
}
bool hadIonAbort() const {
MOZ_ASSERT(!ionAbortPc_ || ionAbortMessage_);
return ionAbortPc_ != nullptr;
}
void destroy();
bool callStackAtAddr(JSRuntime *rt, void *ptr, BytecodeLocationVector &results,

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

@ -33,8 +33,13 @@ IonBuilder::inlineNativeCall(CallInfo &callInfo, JSFunction *target)
MOZ_ASSERT(target->isNative());
JSNative native = target->native();
if (!optimizationInfo().inlineNative())
if (!optimizationInfo().inlineNative()) {
trackOptimizationOutcome(TrackedOutcome::CantInlineDisabledIon);
return InliningStatus_NotInlined;
}
// Default failure reason is observing an unsupported type.
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadType);
// Atomic natives.
if (native == atomics_compareExchange)
@ -355,8 +360,10 @@ IonBuilder::inlineArray(CallInfo &callInfo)
AllocatingBehaviour allocating = NewArray_Unallocating;
JSObject *templateObject = inspector->getTemplateObjectForNative(pc, js_Array);
if (!templateObject)
if (!templateObject) {
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeNoTemplateObj);
return InliningStatus_NotInlined;
}
ArrayObject *templateArray = &templateObject->as<ArrayObject>();
// Multiple arguments imply array initialization, not just construction.
@ -402,6 +409,9 @@ IonBuilder::inlineArray(CallInfo &callInfo)
return InliningStatus_Inlined;
}
// The next several checks all may fail due to range conditions.
trackOptimizationOutcome(TrackedOutcome::ArrayRange);
// Negative lengths generate a RangeError, unhandled by the inline path.
initLength = arg->constantValue().toInt32();
if (initLength >= NativeObject::NELEMENTS_LIMIT)
@ -476,8 +486,10 @@ IonBuilder::inlineArray(CallInfo &callInfo)
IonBuilder::InliningStatus
IonBuilder::inlineArrayPopShift(CallInfo &callInfo, MArrayPopShift::Mode mode)
{
if (callInfo.constructing())
if (callInfo.constructing()) {
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
return InliningStatus_NotInlined;
}
MIRType returnType = getInlineReturnType();
if (returnType == MIRType_Undefined || returnType == MIRType_Null)
@ -497,11 +509,15 @@ IonBuilder::inlineArrayPopShift(CallInfo &callInfo, MArrayPopShift::Mode mode)
types::TemporaryTypeSet *thisTypes = obj->resultTypeSet();
if (!thisTypes || thisTypes->getKnownClass(constraints()) != &ArrayObject::class_)
return InliningStatus_NotInlined;
if (thisTypes->hasObjectFlags(constraints(), unhandledFlags))
if (thisTypes->hasObjectFlags(constraints(), unhandledFlags)) {
trackOptimizationOutcome(TrackedOutcome::ArrayBadFlags);
return InliningStatus_NotInlined;
}
if (types::ArrayPrototypeHasIndexedProperty(constraints(), script()))
if (types::ArrayPrototypeHasIndexedProperty(constraints(), script())) {
trackOptimizationOutcome(TrackedOutcome::ProtoIndexedProps);
return InliningStatus_NotInlined;
}
callInfo.setImplicitlyUsedUnchecked();
@ -533,8 +549,10 @@ IonBuilder::inlineArrayPopShift(CallInfo &callInfo, MArrayPopShift::Mode mode)
IonBuilder::InliningStatus
IonBuilder::inlineArraySplice(CallInfo &callInfo)
{
if (callInfo.argc() != 2 || callInfo.constructing())
if (callInfo.argc() != 2 || callInfo.constructing()) {
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
return InliningStatus_NotInlined;
}
// Ensure |this|, argument and result are objects.
if (getInlineReturnType() != MIRType_Object)
@ -550,8 +568,10 @@ IonBuilder::inlineArraySplice(CallInfo &callInfo)
// Specialize arr.splice(start, deleteCount) with unused return value and
// avoid creating the result array in this case.
if (!BytecodeIsPopped(pc))
if (!BytecodeIsPopped(pc)) {
trackOptimizationOutcome(TrackedOutcome::CantInlineGeneric);
return InliningStatus_NotInlined;
}
MArraySplice *ins = MArraySplice::New(alloc(),
callInfo.thisArg(),
@ -569,8 +589,10 @@ IonBuilder::inlineArraySplice(CallInfo &callInfo)
IonBuilder::InliningStatus
IonBuilder::inlineArrayJoin(CallInfo &callInfo)
{
if (callInfo.argc() != 1 || callInfo.constructing())
if (callInfo.argc() != 1 || callInfo.constructing()) {
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
return InliningStatus_NotInlined;
}
if (getInlineReturnType() != MIRType_String)
return InliningStatus_NotInlined;
@ -592,14 +614,17 @@ IonBuilder::inlineArrayJoin(CallInfo &callInfo)
IonBuilder::InliningStatus
IonBuilder::inlineArrayPush(CallInfo &callInfo)
{
if (callInfo.argc() != 1 || callInfo.constructing())
if (callInfo.argc() != 1 || callInfo.constructing()) {
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
return InliningStatus_NotInlined;
}
MDefinition *obj = callInfo.thisArg();
MDefinition *value = callInfo.getArg(0);
if (PropertyWriteNeedsTypeBarrier(alloc(), constraints(), current,
&obj, nullptr, &value, /* canModify = */ false))
{
trackOptimizationOutcome(TrackedOutcome::NeedsTypeBarrier);
return InliningStatus_NotInlined;
}
MOZ_ASSERT(obj == callInfo.thisArg() && value == callInfo.getArg(0));
@ -615,16 +640,21 @@ IonBuilder::inlineArrayPush(CallInfo &callInfo)
if (thisTypes->hasObjectFlags(constraints(), types::OBJECT_FLAG_SPARSE_INDEXES |
types::OBJECT_FLAG_LENGTH_OVERFLOW))
{
trackOptimizationOutcome(TrackedOutcome::ArrayBadFlags);
return InliningStatus_NotInlined;
}
if (types::ArrayPrototypeHasIndexedProperty(constraints(), script()))
if (types::ArrayPrototypeHasIndexedProperty(constraints(), script())) {
trackOptimizationOutcome(TrackedOutcome::ProtoIndexedProps);
return InliningStatus_NotInlined;
}
types::TemporaryTypeSet::DoubleConversion conversion =
thisTypes->convertDoubleElements(constraints());
if (conversion == types::TemporaryTypeSet::AmbiguousDoubleConversion)
if (conversion == types::TemporaryTypeSet::AmbiguousDoubleConversion) {
trackOptimizationOutcome(TrackedOutcome::ArrayDoubleConversion);
return InliningStatus_NotInlined;
}
callInfo.setImplicitlyUsedUnchecked();
value = callInfo.getArg(0);
@ -654,8 +684,10 @@ IonBuilder::inlineArrayPush(CallInfo &callInfo)
IonBuilder::InliningStatus
IonBuilder::inlineArrayConcat(CallInfo &callInfo)
{
if (callInfo.argc() != 1 || callInfo.constructing())
if (callInfo.argc() != 1 || callInfo.constructing()) {
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
return InliningStatus_NotInlined;
}
// Ensure |this|, argument and result are objects.
if (getInlineReturnType() != MIRType_Object)
@ -676,6 +708,7 @@ IonBuilder::inlineArrayConcat(CallInfo &callInfo)
if (thisTypes->hasObjectFlags(constraints(), types::OBJECT_FLAG_SPARSE_INDEXES |
types::OBJECT_FLAG_LENGTH_OVERFLOW))
{
trackOptimizationOutcome(TrackedOutcome::ArrayBadFlags);
return InliningStatus_NotInlined;
}
@ -684,12 +717,15 @@ IonBuilder::inlineArrayConcat(CallInfo &callInfo)
if (argTypes->hasObjectFlags(constraints(), types::OBJECT_FLAG_SPARSE_INDEXES |
types::OBJECT_FLAG_LENGTH_OVERFLOW))
{
trackOptimizationOutcome(TrackedOutcome::ArrayBadFlags);
return InliningStatus_NotInlined;
}
// Watch out for indexed properties on the prototype.
if (types::ArrayPrototypeHasIndexedProperty(constraints(), script()))
if (types::ArrayPrototypeHasIndexedProperty(constraints(), script())) {
trackOptimizationOutcome(TrackedOutcome::ProtoIndexedProps);
return InliningStatus_NotInlined;
}
// Require the 'this' types to have a specific type matching the current
// global, so we can create the result object inline.
@ -708,6 +744,7 @@ IonBuilder::inlineArrayConcat(CallInfo &callInfo)
if (!thisTypes->hasObjectFlags(constraints(), types::OBJECT_FLAG_NON_PACKED) &&
argTypes->hasObjectFlags(constraints(), types::OBJECT_FLAG_NON_PACKED))
{
trackOptimizationOutcome(TrackedOutcome::ArrayBadFlags);
return InliningStatus_NotInlined;
}
@ -755,11 +792,10 @@ IonBuilder::inlineArrayConcat(CallInfo &callInfo)
IonBuilder::InliningStatus
IonBuilder::inlineMathAbs(CallInfo &callInfo)
{
if (callInfo.constructing())
return InliningStatus_NotInlined;
if (callInfo.argc() != 1)
if (callInfo.argc() != 1 || callInfo.constructing()) {
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
return InliningStatus_NotInlined;
}
MIRType returnType = getInlineReturnType();
MIRType argType = callInfo.getArg(0)->type();
@ -790,11 +826,10 @@ IonBuilder::inlineMathAbs(CallInfo &callInfo)
IonBuilder::InliningStatus
IonBuilder::inlineMathFloor(CallInfo &callInfo)
{
if (callInfo.constructing())
return InliningStatus_NotInlined;
if (callInfo.argc() != 1)
if (callInfo.argc() != 1 || callInfo.constructing()) {
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
return InliningStatus_NotInlined;
}
MIRType argType = callInfo.getArg(0)->type();
MIRType returnType = getInlineReturnType();
@ -835,11 +870,10 @@ IonBuilder::inlineMathFloor(CallInfo &callInfo)
IonBuilder::InliningStatus
IonBuilder::inlineMathCeil(CallInfo &callInfo)
{
if (callInfo.constructing())
return InliningStatus_NotInlined;
if (callInfo.argc() != 1)
if (callInfo.argc() != 1 || callInfo.constructing()) {
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
return InliningStatus_NotInlined;
}
MIRType argType = callInfo.getArg(0)->type();
MIRType returnType = getInlineReturnType();
@ -880,11 +914,10 @@ IonBuilder::inlineMathCeil(CallInfo &callInfo)
IonBuilder::InliningStatus
IonBuilder::inlineMathClz32(CallInfo &callInfo)
{
if (callInfo.constructing())
return InliningStatus_NotInlined;
if (callInfo.argc() != 1)
if (callInfo.argc() != 1 || callInfo.constructing()) {
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
return InliningStatus_NotInlined;
}
MIRType returnType = getInlineReturnType();
if (returnType != MIRType_Int32)
@ -905,11 +938,10 @@ IonBuilder::inlineMathClz32(CallInfo &callInfo)
IonBuilder::InliningStatus
IonBuilder::inlineMathRound(CallInfo &callInfo)
{
if (callInfo.constructing())
return InliningStatus_NotInlined;
if (callInfo.argc() != 1)
if (callInfo.argc() != 1 || callInfo.constructing()) {
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
return InliningStatus_NotInlined;
}
MIRType returnType = getInlineReturnType();
MIRType argType = callInfo.getArg(0)->type();
@ -950,11 +982,10 @@ IonBuilder::inlineMathRound(CallInfo &callInfo)
IonBuilder::InliningStatus
IonBuilder::inlineMathSqrt(CallInfo &callInfo)
{
if (callInfo.constructing())
return InliningStatus_NotInlined;
if (callInfo.argc() != 1)
if (callInfo.argc() != 1 || callInfo.constructing()) {
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
return InliningStatus_NotInlined;
}
MIRType argType = callInfo.getArg(0)->type();
if (getInlineReturnType() != MIRType_Double)
@ -973,11 +1004,10 @@ IonBuilder::inlineMathSqrt(CallInfo &callInfo)
IonBuilder::InliningStatus
IonBuilder::inlineMathAtan2(CallInfo &callInfo)
{
if (callInfo.constructing())
return InliningStatus_NotInlined;
if (callInfo.argc() != 2)
if (callInfo.argc() != 2 || callInfo.constructing()) {
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
return InliningStatus_NotInlined;
}
if (getInlineReturnType() != MIRType_Double)
return InliningStatus_NotInlined;
@ -999,12 +1029,16 @@ IonBuilder::inlineMathAtan2(CallInfo &callInfo)
IonBuilder::InliningStatus
IonBuilder::inlineMathHypot(CallInfo &callInfo)
{
if (callInfo.constructing())
if (callInfo.constructing()) {
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
return InliningStatus_NotInlined;
}
uint32_t argc = callInfo.argc();
if (argc < 2 || argc > 4)
if (argc < 2 || argc > 4) {
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
return InliningStatus_NotInlined;
}
if (getInlineReturnType() != MIRType_Double)
return InliningStatus_NotInlined;
@ -1034,11 +1068,10 @@ IonBuilder::inlineMathHypot(CallInfo &callInfo)
IonBuilder::InliningStatus
IonBuilder::inlineMathPow(CallInfo &callInfo)
{
if (callInfo.constructing())
return InliningStatus_NotInlined;
if (callInfo.argc() != 2)
if (callInfo.argc() != 2 || callInfo.constructing()) {
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
return InliningStatus_NotInlined;
}
// Typechecking.
MIRType baseType = callInfo.getArg(0)->type();
@ -1140,8 +1173,10 @@ IonBuilder::inlineMathPow(CallInfo &callInfo)
IonBuilder::InliningStatus
IonBuilder::inlineMathRandom(CallInfo &callInfo)
{
if (callInfo.constructing())
if (callInfo.constructing()) {
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
return InliningStatus_NotInlined;
}
if (getInlineReturnType() != MIRType_Double)
return InliningStatus_NotInlined;
@ -1157,8 +1192,10 @@ IonBuilder::inlineMathRandom(CallInfo &callInfo)
IonBuilder::InliningStatus
IonBuilder::inlineMathImul(CallInfo &callInfo)
{
if (callInfo.argc() != 2 || callInfo.constructing())
if (callInfo.argc() != 2 || callInfo.constructing()) {
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
return InliningStatus_NotInlined;
}
MIRType returnType = getInlineReturnType();
if (returnType != MIRType_Int32)
@ -1186,8 +1223,10 @@ IonBuilder::inlineMathImul(CallInfo &callInfo)
IonBuilder::InliningStatus
IonBuilder::inlineMathFRound(CallInfo &callInfo)
{
if (callInfo.argc() != 1 || callInfo.constructing())
if (callInfo.argc() != 1 || callInfo.constructing()) {
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
return InliningStatus_NotInlined;
}
// MIRType can't be Float32, as this point, as getInlineReturnType uses JSVal types
// to infer the returned MIR type.
@ -1217,8 +1256,10 @@ IonBuilder::inlineMathFRound(CallInfo &callInfo)
IonBuilder::InliningStatus
IonBuilder::inlineMathMinMax(CallInfo &callInfo, bool max)
{
if (callInfo.argc() < 1 || callInfo.constructing())
if (callInfo.argc() < 1 || callInfo.constructing()) {
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
return InliningStatus_NotInlined;
}
MIRType returnType = getInlineReturnType();
if (!IsNumberType(returnType))
@ -1286,8 +1327,10 @@ IonBuilder::inlineMathMinMax(CallInfo &callInfo, bool max)
IonBuilder::InliningStatus
IonBuilder::inlineStringObject(CallInfo &callInfo)
{
if (callInfo.argc() != 1 || !callInfo.constructing())
if (callInfo.argc() != 1 || !callInfo.constructing()) {
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
return InliningStatus_NotInlined;
}
// ConvertToString doesn't support objects.
if (callInfo.getArg(0)->mightBeType(MIRType_Object))
@ -1313,8 +1356,11 @@ IonBuilder::inlineStringObject(CallInfo &callInfo)
IonBuilder::InliningStatus
IonBuilder::inlineStringSplit(CallInfo &callInfo)
{
if (callInfo.argc() != 1 || callInfo.constructing())
if (callInfo.argc() != 1 || callInfo.constructing()) {
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
return InliningStatus_NotInlined;
}
if (callInfo.thisArg()->type() != MIRType_String)
return InliningStatus_NotInlined;
if (callInfo.getArg(0)->type() != MIRType_String)
@ -1353,8 +1399,10 @@ IonBuilder::inlineStringSplit(CallInfo &callInfo)
IonBuilder::InliningStatus
IonBuilder::inlineStrCharCodeAt(CallInfo &callInfo)
{
if (callInfo.argc() != 1 || callInfo.constructing())
if (callInfo.argc() != 1 || callInfo.constructing()) {
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
return InliningStatus_NotInlined;
}
if (getInlineReturnType() != MIRType_Int32)
return InliningStatus_NotInlined;
@ -1389,11 +1437,10 @@ IonBuilder::inlineStrCharCodeAt(CallInfo &callInfo)
IonBuilder::InliningStatus
IonBuilder::inlineConstantCharCodeAt(CallInfo &callInfo)
{
if (!callInfo.thisArg()->isConstantValue())
return InliningStatus_NotInlined;
if (!callInfo.getArg(0)->isConstantValue())
if (!callInfo.thisArg()->isConstantValue() || !callInfo.getArg(0)->isConstantValue()) {
trackOptimizationOutcome(TrackedOutcome::CantInlineGeneric);
return InliningStatus_NotInlined;
}
const js::Value *strval = callInfo.thisArg()->constantVp();
const js::Value *idxval = callInfo.getArg(0)->constantVp();
@ -1402,12 +1449,16 @@ IonBuilder::inlineConstantCharCodeAt(CallInfo &callInfo)
return InliningStatus_NotInlined;
JSString *str = strval->toString();
if (!str->isLinear())
if (!str->isLinear()) {
trackOptimizationOutcome(TrackedOutcome::CantInlineGeneric);
return InliningStatus_NotInlined;
}
int32_t idx = idxval->toInt32();
if (idx < 0 || (uint32_t(idx) >= str->length()))
if (idx < 0 || (uint32_t(idx) >= str->length())) {
trackOptimizationOutcome(TrackedOutcome::OutOfBounds);
return InliningStatus_NotInlined;
}
callInfo.setImplicitlyUsedUnchecked();
@ -1422,8 +1473,10 @@ IonBuilder::inlineConstantCharCodeAt(CallInfo &callInfo)
IonBuilder::InliningStatus
IonBuilder::inlineStrFromCharCode(CallInfo &callInfo)
{
if (callInfo.argc() != 1 || callInfo.constructing())
if (callInfo.argc() != 1 || callInfo.constructing()) {
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
return InliningStatus_NotInlined;
}
if (getInlineReturnType() != MIRType_String)
return InliningStatus_NotInlined;
@ -1444,8 +1497,10 @@ IonBuilder::inlineStrFromCharCode(CallInfo &callInfo)
IonBuilder::InliningStatus
IonBuilder::inlineStrCharAt(CallInfo &callInfo)
{
if (callInfo.argc() != 1 || callInfo.constructing())
if (callInfo.argc() != 1 || callInfo.constructing()) {
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
return InliningStatus_NotInlined;
}
if (getInlineReturnType() != MIRType_String)
return InliningStatus_NotInlined;
@ -1478,8 +1533,10 @@ IonBuilder::inlineStrCharAt(CallInfo &callInfo)
IonBuilder::InliningStatus
IonBuilder::inlineRegExpExec(CallInfo &callInfo)
{
if (callInfo.argc() != 1 || callInfo.constructing())
if (callInfo.argc() != 1 || callInfo.constructing()) {
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
return InliningStatus_NotInlined;
}
if (callInfo.thisArg()->type() != MIRType_Object)
return InliningStatus_NotInlined;
@ -1514,8 +1571,10 @@ IonBuilder::inlineRegExpExec(CallInfo &callInfo)
IonBuilder::InliningStatus
IonBuilder::inlineRegExpTest(CallInfo &callInfo)
{
if (callInfo.argc() != 1 || callInfo.constructing())
if (callInfo.argc() != 1 || callInfo.constructing()) {
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
return InliningStatus_NotInlined;
}
// TI can infer a nullptr return type of regexp_test with eager compilation.
if (CallResultEscapes(pc) && getInlineReturnType() != MIRType_Boolean)
@ -1548,8 +1607,10 @@ IonBuilder::inlineRegExpTest(CallInfo &callInfo)
IonBuilder::InliningStatus
IonBuilder::inlineStrReplace(CallInfo &callInfo)
{
if (callInfo.argc() != 2 || callInfo.constructing())
if (callInfo.argc() != 2 || callInfo.constructing()) {
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
return InliningStatus_NotInlined;
}
// Return: String.
if (getInlineReturnType() != MIRType_String)
@ -1666,8 +1727,10 @@ IonBuilder::InliningStatus
IonBuilder::inlineUnsafePutElements(CallInfo &callInfo)
{
uint32_t argc = callInfo.argc();
if (argc < 3 || (argc % 3) != 0 || callInfo.constructing())
if (argc < 3 || (argc % 3) != 0 || callInfo.constructing()) {
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
return InliningStatus_NotInlined;
}
/* Important:
*
@ -1834,8 +1897,10 @@ IonBuilder::inlineHasClass(CallInfo &callInfo,
const Class *clasp1, const Class *clasp2,
const Class *clasp3, const Class *clasp4)
{
if (callInfo.constructing() || callInfo.argc() != 1)
if (callInfo.constructing() || callInfo.argc() != 1) {
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
return InliningStatus_NotInlined;
}
if (callInfo.getArg(0)->type() != MIRType_Object)
return InliningStatus_NotInlined;
@ -1942,8 +2007,10 @@ IonBuilder::inlineTypedArrayLength(CallInfo &callInfo)
IonBuilder::InliningStatus
IonBuilder::inlineObjectIsTypeDescr(CallInfo &callInfo)
{
if (callInfo.constructing() || callInfo.argc() != 1)
if (callInfo.constructing() || callInfo.argc() != 1) {
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
return InliningStatus_NotInlined;
}
if (callInfo.getArg(0)->type() != MIRType_Object)
return InliningStatus_NotInlined;
@ -1979,8 +2046,10 @@ IonBuilder::inlineObjectIsTypeDescr(CallInfo &callInfo)
IonBuilder::InliningStatus
IonBuilder::inlineSetTypedObjectOffset(CallInfo &callInfo)
{
if (callInfo.argc() != 2 || callInfo.constructing())
if (callInfo.argc() != 2 || callInfo.constructing()) {
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
return InliningStatus_NotInlined;
}
MDefinition *typedObj = callInfo.getArg(0);
MDefinition *offset = callInfo.getArg(1);
@ -2021,8 +2090,10 @@ IonBuilder::inlineSetTypedObjectOffset(CallInfo &callInfo)
IonBuilder::InliningStatus
IonBuilder::inlineUnsafeSetReservedSlot(CallInfo &callInfo)
{
if (callInfo.argc() != 3 || callInfo.constructing())
if (callInfo.argc() != 3 || callInfo.constructing()) {
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
return InliningStatus_NotInlined;
}
if (getInlineReturnType() != MIRType_Undefined)
return InliningStatus_NotInlined;
if (callInfo.getArg(0)->type() != MIRType_Object)
@ -2051,8 +2122,10 @@ IonBuilder::inlineUnsafeSetReservedSlot(CallInfo &callInfo)
IonBuilder::InliningStatus
IonBuilder::inlineUnsafeGetReservedSlot(CallInfo &callInfo, MIRType knownValueType)
{
if (callInfo.argc() != 2 || callInfo.constructing())
if (callInfo.argc() != 2 || callInfo.constructing()) {
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
return InliningStatus_NotInlined;
}
if (callInfo.getArg(0)->type() != MIRType_Object)
return InliningStatus_NotInlined;
if (callInfo.getArg(1)->type() != MIRType_Int32)
@ -2091,8 +2164,10 @@ IonBuilder::inlineUnsafeGetReservedSlot(CallInfo &callInfo, MIRType knownValueTy
IonBuilder::InliningStatus
IonBuilder::inlineIsCallable(CallInfo &callInfo)
{
if (callInfo.argc() != 1 || callInfo.constructing())
if (callInfo.argc() != 1 || callInfo.constructing()) {
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
return InliningStatus_NotInlined;
}
if (getInlineReturnType() != MIRType_Boolean)
return InliningStatus_NotInlined;
@ -2134,8 +2209,10 @@ IonBuilder::inlineIsCallable(CallInfo &callInfo)
IonBuilder::InliningStatus
IonBuilder::inlineIsObject(CallInfo &callInfo)
{
if (callInfo.argc() != 1 || callInfo.constructing())
if (callInfo.argc() != 1 || callInfo.constructing()) {
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
return InliningStatus_NotInlined;
}
if (getInlineReturnType() != MIRType_Boolean)
return InliningStatus_NotInlined;
@ -2153,8 +2230,10 @@ IonBuilder::inlineIsObject(CallInfo &callInfo)
IonBuilder::InliningStatus
IonBuilder::inlineToObject(CallInfo &callInfo)
{
if (callInfo.argc() != 1 || callInfo.constructing())
if (callInfo.argc() != 1 || callInfo.constructing()) {
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
return InliningStatus_NotInlined;
}
// If we know the input type is an object, nop ToObject.
if (getInlineReturnType() != MIRType_Object)
@ -2172,8 +2251,10 @@ IonBuilder::inlineToObject(CallInfo &callInfo)
IonBuilder::InliningStatus
IonBuilder::inlineToInteger(CallInfo &callInfo)
{
if (callInfo.argc() != 1 || callInfo.constructing())
if (callInfo.argc() != 1 || callInfo.constructing()) {
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
return InliningStatus_NotInlined;
}
MDefinition *input = callInfo.getArg(0);
@ -2253,8 +2334,10 @@ IonBuilder::inlineAssertFloat32(CallInfo &callInfo)
IonBuilder::InliningStatus
IonBuilder::inlineBoundFunction(CallInfo &nativeCallInfo, JSFunction *target)
{
if (!target->getBoundFunctionTarget()->is<JSFunction>())
return InliningStatus_NotInlined;
trackOptimizationOutcome(TrackedOutcome::CantInlineBound);
if (!target->getBoundFunctionTarget()->is<JSFunction>())
return InliningStatus_NotInlined;
JSFunction *scriptedTarget = &(target->getBoundFunctionTarget()->as<JSFunction>());
@ -2307,8 +2390,10 @@ IonBuilder::inlineBoundFunction(CallInfo &nativeCallInfo, JSFunction *target)
IonBuilder::InliningStatus
IonBuilder::inlineAtomicsCompareExchange(CallInfo &callInfo)
{
if (callInfo.argc() != 4 || callInfo.constructing())
if (callInfo.argc() != 4 || callInfo.constructing()) {
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
return InliningStatus_NotInlined;
}
Scalar::Type arrayType;
if (!atomicsMeetsPreconditions(callInfo, &arrayType))
@ -2353,8 +2438,10 @@ IonBuilder::inlineAtomicsCompareExchange(CallInfo &callInfo)
IonBuilder::InliningStatus
IonBuilder::inlineAtomicsLoad(CallInfo &callInfo)
{
if (callInfo.argc() != 2 || callInfo.constructing())
if (callInfo.argc() != 2 || callInfo.constructing()) {
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
return InliningStatus_NotInlined;
}
Scalar::Type arrayType;
if (!atomicsMeetsPreconditions(callInfo, &arrayType))
@ -2379,8 +2466,10 @@ IonBuilder::inlineAtomicsLoad(CallInfo &callInfo)
IonBuilder::InliningStatus
IonBuilder::inlineAtomicsStore(CallInfo &callInfo)
{
if (callInfo.argc() != 3 || callInfo.constructing())
if (callInfo.argc() != 3 || callInfo.constructing()) {
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
return InliningStatus_NotInlined;
}
Scalar::Type arrayType;
if (!atomicsMeetsPreconditions(callInfo, &arrayType))
@ -2413,8 +2502,10 @@ IonBuilder::inlineAtomicsStore(CallInfo &callInfo)
IonBuilder::InliningStatus
IonBuilder::inlineAtomicsFence(CallInfo &callInfo)
{
if (callInfo.argc() != 0 || callInfo.constructing())
if (callInfo.argc() != 0 || callInfo.constructing()) {
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
return InliningStatus_NotInlined;
}
callInfo.setImplicitlyUsedUnchecked();
@ -2428,8 +2519,10 @@ IonBuilder::inlineAtomicsFence(CallInfo &callInfo)
IonBuilder::InliningStatus
IonBuilder::inlineAtomicsBinop(CallInfo &callInfo, JSFunction *target)
{
if (callInfo.argc() != 3 || callInfo.constructing())
if (callInfo.argc() != 3 || callInfo.constructing()) {
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
return InliningStatus_NotInlined;
}
Scalar::Type arrayType;
if (!atomicsMeetsPreconditions(callInfo, &arrayType))
@ -2552,8 +2645,10 @@ IonBuilder::InliningStatus
IonBuilder::inlineConstructTypedObject(CallInfo &callInfo, TypeDescr *descr)
{
// Only inline default constructors for now.
if (callInfo.argc() != 0)
if (callInfo.argc() != 0) {
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
return InliningStatus_NotInlined;
}
if (size_t(descr->size()) > InlineTypedObject::MaximumSize)
return InliningStatus_NotInlined;

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

@ -2058,18 +2058,17 @@ MMinMax::foldsTo(TempAllocator &alloc)
// The folded MConstant should maintain the same MIRType with
// the original MMinMax.
MConstant *constant;
if (type() == MIRType_Int32) {
int32_t cast = static_cast<int32_t>(result);
MOZ_ASSERT(cast == result);
constant = MConstant::New(alloc, Int32Value(cast));
int32_t cast;
if (mozilla::NumberEqualsInt32(result, &cast))
return MConstant::New(alloc, Int32Value(cast));
} else {
MOZ_ASSERT(IsFloatingPointType(type()));
constant = MConstant::New(alloc, DoubleValue(result));
MConstant *constant = MConstant::New(alloc, DoubleValue(result));
if (type() == MIRType_Float32)
constant->setResultType(MIRType_Float32);
return constant;
}
return constant;
}
MDefinition *operand = lhs()->isConstantValue() ? rhs() : lhs();
@ -3045,6 +3044,32 @@ MDefinition *
MToInt32::foldsTo(TempAllocator &alloc)
{
MDefinition *input = getOperand(0);
// Fold this operation if the input operand is constant.
if (input->isConstant()) {
Value val = input->toConstant()->value();
DebugOnly<MacroAssembler::IntConversionInputKind> convert = conversion();
switch (input->type()) {
case MIRType_Null:
MOZ_ASSERT(convert == MacroAssembler::IntConversion_Any);
return MConstant::New(alloc, Int32Value(0));
case MIRType_Boolean:
MOZ_ASSERT(convert == MacroAssembler::IntConversion_Any ||
convert == MacroAssembler::IntConversion_NumbersOrBoolsOnly);
return MConstant::New(alloc, Int32Value(val.toBoolean()));
case MIRType_Int32:
return MConstant::New(alloc, Int32Value(val.toInt32()));
case MIRType_Float32:
case MIRType_Double:
int32_t ival;
// Only the value within the range of Int32 can be substitued as constant.
if (mozilla::NumberEqualsInt32(val.toNumber(), &ival))
return MConstant::New(alloc, Int32Value(ival));
default:
break;
}
}
if (input->type() == MIRType_Int32)
return input;
return this;

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

@ -456,6 +456,11 @@ class MDefinition : public MNode
InlineScriptTree *trackedTree() const {
return trackedSite_ ? trackedSite_->tree() : nullptr;
}
TrackedOptimizations *trackedOptimizations() const {
return trackedSite_ && trackedSite_->hasOptimizations()
? trackedSite_->optimizations()
: nullptr;
}
JSScript *profilerLeaveScript() const {
return trackedTree()->outermostCaller()->script();

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

@ -87,6 +87,10 @@ class MIRGenerator
return !compilingAsmJS() && instrumentedProfiling();
}
bool isOptimizationTrackingEnabled() {
return isProfilerInstrumentationEnabled() && !info().isAnalysis();
}
// Whether the main thread is trying to cancel this build.
bool shouldCancel(const char *why) {
maybePause();

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

@ -204,7 +204,7 @@ MIRGraph::unmarkBlocks()
MBasicBlock *
MBasicBlock::New(MIRGraph &graph, BytecodeAnalysis *analysis, CompileInfo &info,
MBasicBlock *pred, const BytecodeSite *site, Kind kind)
MBasicBlock *pred, BytecodeSite *site, Kind kind)
{
MOZ_ASSERT(site->pc() != nullptr);
@ -220,7 +220,7 @@ MBasicBlock::New(MIRGraph &graph, BytecodeAnalysis *analysis, CompileInfo &info,
MBasicBlock *
MBasicBlock::NewPopN(MIRGraph &graph, CompileInfo &info,
MBasicBlock *pred, const BytecodeSite *site, Kind kind, uint32_t popped)
MBasicBlock *pred, BytecodeSite *site, Kind kind, uint32_t popped)
{
MBasicBlock *block = new(graph.alloc()) MBasicBlock(graph, info, site, kind);
if (!block->init())
@ -234,7 +234,7 @@ MBasicBlock::NewPopN(MIRGraph &graph, CompileInfo &info,
MBasicBlock *
MBasicBlock::NewWithResumePoint(MIRGraph &graph, CompileInfo &info,
MBasicBlock *pred, const BytecodeSite *site,
MBasicBlock *pred, BytecodeSite *site,
MResumePoint *resumePoint)
{
MBasicBlock *block = new(graph.alloc()) MBasicBlock(graph, info, site, NORMAL);
@ -256,7 +256,7 @@ MBasicBlock::NewWithResumePoint(MIRGraph &graph, CompileInfo &info,
MBasicBlock *
MBasicBlock::NewPendingLoopHeader(MIRGraph &graph, CompileInfo &info,
MBasicBlock *pred, const BytecodeSite *site,
MBasicBlock *pred, BytecodeSite *site,
unsigned stackPhiCount)
{
MOZ_ASSERT(site->pc() != nullptr);
@ -324,7 +324,7 @@ MBasicBlock::NewAsmJS(MIRGraph &graph, CompileInfo &info, MBasicBlock *pred, Kin
return block;
}
MBasicBlock::MBasicBlock(MIRGraph &graph, CompileInfo &info, const BytecodeSite *site, Kind kind)
MBasicBlock::MBasicBlock(MIRGraph &graph, CompileInfo &info, BytecodeSite *site, Kind kind)
: unreachable_(false),
graph_(graph),
info_(info),

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

@ -46,7 +46,7 @@ class MBasicBlock : public TempObject, public InlineListNode<MBasicBlock>
};
private:
MBasicBlock(MIRGraph &graph, CompileInfo &info, const BytecodeSite *site, Kind kind);
MBasicBlock(MIRGraph &graph, CompileInfo &info, BytecodeSite *site, Kind kind);
bool init();
void copySlots(MBasicBlock *from);
bool inherit(TempAllocator &alloc, BytecodeAnalysis *analysis, MBasicBlock *pred,
@ -107,14 +107,14 @@ class MBasicBlock : public TempObject, public InlineListNode<MBasicBlock>
// Creates a new basic block for a MIR generator. If |pred| is not nullptr,
// its slots and stack depth are initialized from |pred|.
static MBasicBlock *New(MIRGraph &graph, BytecodeAnalysis *analysis, CompileInfo &info,
MBasicBlock *pred, const BytecodeSite *site, Kind kind);
MBasicBlock *pred, BytecodeSite *site, Kind kind);
static MBasicBlock *NewPopN(MIRGraph &graph, CompileInfo &info,
MBasicBlock *pred, const BytecodeSite *site, Kind kind, uint32_t popn);
MBasicBlock *pred, BytecodeSite *site, Kind kind, uint32_t popn);
static MBasicBlock *NewWithResumePoint(MIRGraph &graph, CompileInfo &info,
MBasicBlock *pred, const BytecodeSite *site,
MBasicBlock *pred, BytecodeSite *site,
MResumePoint *resumePoint);
static MBasicBlock *NewPendingLoopHeader(MIRGraph &graph, CompileInfo &info,
MBasicBlock *pred, const BytecodeSite *site,
MBasicBlock *pred, BytecodeSite *site,
unsigned loopStateSlots);
static MBasicBlock *NewSplitEdge(MIRGraph &graph, CompileInfo &info, MBasicBlock *pred);
static MBasicBlock *NewAsmJS(MIRGraph &graph, CompileInfo &info,
@ -602,13 +602,14 @@ class MBasicBlock : public TempObject, public InlineListNode<MBasicBlock>
void dump(FILE *fp);
void dump();
// Track bailouts by storing the current pc in MIR instruction added at this
// cycle. This is also used for tracking calls when profiling.
void updateTrackedSite(const BytecodeSite *site) {
// Track bailouts by storing the current pc in MIR instruction added at
// this cycle. This is also used for tracking calls and optimizations when
// profiling.
void updateTrackedSite(BytecodeSite *site) {
MOZ_ASSERT(site->tree() == trackedSite_->tree());
trackedSite_ = site;
}
const BytecodeSite *trackedSite() const {
BytecodeSite *trackedSite() const {
return trackedSite_;
}
jsbytecode *trackedPc() const {
@ -657,7 +658,7 @@ class MBasicBlock : public TempObject, public InlineListNode<MBasicBlock>
Vector<MBasicBlock *, 1, JitAllocPolicy> immediatelyDominated_;
MBasicBlock *immediateDominator_;
const BytecodeSite *trackedSite_;
BytecodeSite *trackedSite_;
#if defined(JS_ION_PERF) || defined(DEBUG)
unsigned lineno_;

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

@ -0,0 +1,764 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* 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 jit_OptimizationTracking_h
#define jit_OptimizationTracking_h
#include "mozilla/Maybe.h"
#include "jsinfer.h"
#include "jit/CompactBuffer.h"
#include "jit/CompileInfo.h"
#include "jit/JitAllocPolicy.h"
#include "jit/shared/CodeGenerator-shared.h"
namespace js {
namespace jit {
#define TRACKED_STRATEGY_LIST(_) \
_(GetProp_ArgumentsLength, \
"getprop arguments.length") \
_(GetProp_ArgumentsCallee, \
"getprop arguments.callee") \
_(GetProp_InferredConstant, \
"getprop inferred constant") \
_(GetProp_Constant, \
"getprop constant") \
_(GetProp_TypedObject, \
"getprop TypedObject") \
_(GetProp_DefiniteSlot, \
"getprop definite slot") \
_(GetProp_CommonGetter, \
"getprop common getter") \
_(GetProp_InlineAccess, \
"getprop inline access") \
_(GetProp_Innerize, \
"getprop innerize (access on global window)") \
_(GetProp_InlineCache, \
"getprop IC") \
\
_(SetProp_CommonSetter, \
"setprop common setter") \
_(SetProp_TypedObject, \
"setprop TypedObject") \
_(SetProp_DefiniteSlot, \
"setprop definite slot") \
_(SetProp_InlineAccess, \
"setprop inline access") \
\
_(GetElem_TypedObject, \
"getprop TypedObject") \
_(GetElem_Dense, \
"getelem dense") \
_(GetElem_TypedStatic, \
"getelem TypedArray static") \
_(GetElem_TypedArray, \
"getelem TypedArray") \
_(GetElem_String, \
"getelem string") \
_(GetElem_Arguments, \
"getelem arguments") \
_(GetElem_ArgumentsInlined, \
"getelem arguments inlined") \
_(GetElem_InlineCache, \
"getelem IC") \
\
_(SetElem_TypedObject, \
"setelem TypedObject") \
_(SetElem_TypedStatic, \
"setelem TypedArray static") \
_(SetElem_TypedArray, \
"setelem TypedArray") \
_(SetElem_Dense, \
"setelem dense") \
_(SetElem_Arguments, \
"setelem arguments") \
_(SetElem_InlineCache, \
"setelem IC") \
\
_(Call_Inline, \
"call inline")
// Ordering is important below. All outcomes before GenericSuccess will be
// considered failures, and all outcomes after GenericSuccess will be
// considered successes.
#define TRACKED_OUTCOME_LIST(_) \
_(GenericFailure, \
"failure") \
_(Disabled, \
"disabled") \
_(NoTypeInfo, \
"no type info") \
_(NoAnalysisInfo, \
"no newscript analysis") \
_(NoShapeInfo, \
"cannot determine shape") \
_(UnknownObject, \
"unknown object") \
_(UnknownProperties, \
"unknown properties") \
_(Singleton, \
"is singleton") \
_(NotSingleton, \
"is not singleton") \
_(NotFixedSlot, \
"property not in fixed slot") \
_(NotObject, \
"not definitely an object") \
_(NotStruct, \
"not definitely a TypedObject struct") \
_(StructNoField, \
"struct doesn't definitely have field") \
_(NeedsTypeBarrier, \
"needs type barrier") \
_(InDictionaryMode, \
"object in dictionary mode") \
_(NoProtoFound, \
"no proto found") \
_(MultiProtoPaths, \
"not all paths to property go through same proto") \
_(NonWritableProperty, \
"non-writable property") \
_(ProtoIndexedProps, \
"prototype has indexed properties") \
_(ArrayBadFlags, \
"array observed to be sparse, overflowed .length, or has been iterated") \
_(ArrayDoubleConversion, \
"array has ambiguous double conversion") \
_(ArrayRange, \
"array range issue (.length problems)") \
_(ArraySeenNegativeIndex, \
"has seen array access with negative index") \
_(TypedObjectNeutered, \
"TypedObject might have been neutered") \
_(TypedObjectArrayRange, \
"TypedObject array of unknown length") \
_(AccessNotDense, \
"access not on dense native (check receiver, index, and result types)") \
_(AccessNotTypedObject, \
"access not on typed array (check receiver and index types)") \
_(AccessNotTypedArray, \
"access not on typed array (check receiver, index, and result types)") \
_(AccessNotString, \
"getelem not on string (check receiver and index types)") \
_(StaticTypedArrayUint32, \
"static uint32 arrays currently cannot be optimized") \
_(StaticTypedArrayCantComputeMask, \
"can't compute mask for static typed array access (index isn't constant or not int32)") \
_(OutOfBounds, \
"observed out of bounds access") \
_(GetElemStringNotCached, \
"getelem on strings is not inline cached") \
_(NonNativeReceiver, \
"observed non-native receiver") \
_(IndexType, \
"index type must be int32, string, or symbol") \
_(SetElemNonDenseNonTANotCached, \
"setelem on non-dense non-TAs are not inline cached") \
\
_(CantInlineGeneric, \
"can't inline") \
_(CantInlineNoTarget, \
"can't inline: no target") \
_(CantInlineNotInterpreted, \
"can't inline: not interpreted") \
_(CantInlineNoBaseline, \
"can't inline: no baseline code") \
_(CantInlineLazy, \
"can't inline: lazy script") \
_(CantInlineNotConstructor, \
"can't inline: calling non-constructor with 'new'") \
_(CantInlineDisabledIon, \
"can't inline: ion disabled for callee") \
_(CantInlineTooManyArgs, \
"can't inline: too many arguments") \
_(CantInlineRecursive, \
"can't inline: recursive") \
_(CantInlineHeavyweight, \
"can't inline: heavyweight") \
_(CantInlineNeedsArgsObj, \
"can't inline: needs arguments object") \
_(CantInlineDebuggee, \
"can't inline: debuggee") \
_(CantInlineUnknownProps, \
"can't inline: type has unknown properties") \
_(CantInlineExceededDepth, \
"can't inline: exceeded inlining depth") \
_(CantInlineBigLoop, \
"can't inline: big function with a loop") \
_(CantInlineBigCaller, \
"can't inline: big caller") \
_(CantInlineBigCallee, \
"can't inline: big callee") \
_(CantInlineNotHot, \
"can't inline: not hot enough") \
_(CantInlineNotInDispatch, \
"can't inline: not in dispatch table") \
_(CantInlineNativeBadForm, \
"can't inline native: bad form (arity mismatch/constructing)") \
_(CantInlineNativeBadType, \
"can't inline native: bad argument or return type observed") \
_(CantInlineNativeNoTemplateObj, \
"can't inline native: no template object") \
_(CantInlineBound, \
"can't inline bound function invocation") \
\
_(GenericSuccess, \
"success") \
_(Inlined, \
"inlined") \
_(DOM, \
"DOM") \
_(Monomorphic, \
"monomorphic") \
_(Polymorphic, \
"polymorphic")
#define TRACKED_TYPESITE_LIST(_) \
_(Receiver, \
"receiver object") \
_(Index, \
"index") \
_(Value, \
"value") \
_(Call_Target, \
"call target") \
_(Call_This, \
"call 'this'") \
_(Call_Arg, \
"call argument") \
_(Call_Return, \
"call return")
enum class TrackedStrategy : uint32_t {
#define STRATEGY_OP(name, msg) name,
TRACKED_STRATEGY_LIST(STRATEGY_OP)
#undef STRATEGY_OPT
Count
};
enum class TrackedOutcome : uint32_t {
#define OUTCOME_OP(name, msg) name,
TRACKED_OUTCOME_LIST(OUTCOME_OP)
#undef OUTCOME_OP
Count
};
enum class TrackedTypeSite : uint32_t {
#define TYPESITE_OP(name, msg) name,
TRACKED_TYPESITE_LIST(TYPESITE_OP)
#undef TYPESITE_OP
Count
};
class OptimizationAttempt
{
TrackedStrategy strategy_;
TrackedOutcome outcome_;
public:
OptimizationAttempt(TrackedStrategy strategy, TrackedOutcome outcome)
: strategy_(strategy),
outcome_(outcome)
{ }
void setOutcome(TrackedOutcome outcome) { outcome_ = outcome; }
bool succeeded() const { return outcome_ >= TrackedOutcome::GenericSuccess; }
bool failed() const { return outcome_ < TrackedOutcome::GenericSuccess; }
TrackedStrategy strategy() const { return strategy_; }
TrackedOutcome outcome() const { return outcome_; }
bool operator ==(const OptimizationAttempt &other) const {
return strategy_ == other.strategy_ && outcome_ == other.outcome_;
}
bool operator !=(const OptimizationAttempt &other) const {
return strategy_ != other.strategy_ || outcome_ != other.outcome_;
}
HashNumber hash() const {
return (HashNumber(strategy_) << 8) + HashNumber(outcome_);
}
explicit OptimizationAttempt(CompactBufferReader &reader);
void writeCompact(CompactBufferWriter &writer) const;
};
typedef Vector<OptimizationAttempt, 4, JitAllocPolicy> TempAttemptsVector;
typedef Vector<OptimizationAttempt, 4, SystemAllocPolicy> AttemptsVector;
class UniqueTrackedTypes;
class TrackedTypeInfo
{
TrackedTypeSite site_;
MIRType mirType_;
types::TypeSet::TypeList types_;
public:
TrackedTypeInfo(TrackedTypeInfo &&other)
: site_(other.site_),
mirType_(other.mirType_),
types_(mozilla::Move(other.types_))
{ }
TrackedTypeInfo(TrackedTypeSite site, MIRType mirType)
: site_(site),
mirType_(mirType)
{ }
bool trackTypeSet(types::TemporaryTypeSet *typeSet);
bool trackType(types::Type type);
TrackedTypeSite site() const { return site_; }
MIRType mirType() const { return mirType_; }
const types::TypeSet::TypeList &types() const { return types_; }
bool operator ==(const TrackedTypeInfo &other) const;
bool operator !=(const TrackedTypeInfo &other) const;
HashNumber hash() const;
// This constructor is designed to be used in conjunction with readTypes
// below it. The same reader must be passed to readTypes after
// instantiating the TrackedTypeInfo.
explicit TrackedTypeInfo(CompactBufferReader &reader);
bool readTypes(CompactBufferReader &reader, const types::TypeSet::TypeList *allTypes);
bool writeCompact(CompactBufferWriter &writer, UniqueTrackedTypes &uniqueTypes) const;
};
typedef Vector<TrackedTypeInfo, 1, JitAllocPolicy> TempTrackedTypeInfoVector;
typedef Vector<TrackedTypeInfo, 1, SystemAllocPolicy> TrackedTypeInfoVector;
// Tracks the optimization attempts made at a bytecode location.
class TrackedOptimizations : public TempObject
{
friend class UniqueTrackedOptimizations;
TempTrackedTypeInfoVector types_;
TempAttemptsVector attempts_;
uint32_t currentAttempt_;
public:
explicit TrackedOptimizations(TempAllocator &alloc)
: types_(alloc),
attempts_(alloc),
currentAttempt_(UINT32_MAX)
{ }
bool trackTypeInfo(TrackedTypeInfo &&ty);
bool trackAttempt(TrackedStrategy strategy);
void amendAttempt(uint32_t index);
void trackOutcome(TrackedOutcome outcome);
void trackSuccess();
bool matchTypes(const TempTrackedTypeInfoVector &other) const;
bool matchAttempts(const TempAttemptsVector &other) const;
void spew() const;
};
// Assigns each unique sequence of optimization attempts an index; outputs a
// compact table.
class UniqueTrackedOptimizations
{
public:
struct SortEntry
{
const TempTrackedTypeInfoVector *types;
const TempAttemptsVector *attempts;
uint32_t frequency;
};
typedef Vector<SortEntry, 4> SortedVector;
private:
struct Key
{
const TempTrackedTypeInfoVector *types;
const TempAttemptsVector *attempts;
typedef Key Lookup;
static HashNumber hash(const Lookup &lookup);
static bool match(const Key &key, const Lookup &lookup);
static void rekey(Key &key, const Key &newKey) {
key = newKey;
}
};
struct Entry
{
uint8_t index;
uint32_t frequency;
};
// Map of unique (TempTrackedTypeInfoVector, TempAttemptsVector) pairs to
// indices.
typedef HashMap<Key, Entry, Key> AttemptsMap;
AttemptsMap map_;
// TempAttemptsVectors sorted by frequency.
SortedVector sorted_;
public:
explicit UniqueTrackedOptimizations(JSContext *cx)
: map_(cx),
sorted_(cx)
{ }
bool init() { return map_.init(); }
bool add(const TrackedOptimizations *optimizations);
bool sortByFrequency(JSContext *cx);
bool sorted() const { return !sorted_.empty(); }
uint32_t count() const { MOZ_ASSERT(sorted()); return sorted_.length(); }
const SortedVector &sortedVector() const { MOZ_ASSERT(sorted()); return sorted_; }
uint8_t indexOf(const TrackedOptimizations *optimizations) const;
};
// A compact table of tracked optimization information. Pictorially,
//
// +------------------------------------------------+
// | Region 1 | |
// |------------------------------------------------| |
// | Region 2 | |
// |------------------------------------------------| |-- PayloadR of list-of-list of
// | ... | | range triples (see below)
// |------------------------------------------------| |
// | Region M | |
// +================================================+ <- IonTrackedOptimizationsRegionTable
// | uint32_t numRegions_ = M | |
// +------------------------------------------------+ |
// | Region 1 | |
// | uint32_t regionOffset = size(PayloadR) | |
// +------------------------------------------------+ |-- Table
// | ... | |
// +------------------------------------------------+ |
// | Region M | |
// | uint32_t regionOffset | |
// +================================================+
// | Optimization type info 1 | |
// |------------------------------------------------| |
// | Optimization type info 2 | |-- PayloadT of list of
// |------------------------------------------------| | IonTrackedOptimizationTypeInfo in
// | ... | | order of decreasing frequency
// |------------------------------------------------| |
// | Optimization type info N | |
// +================================================+ <- IonTrackedOptimizationsTypesTable
// | uint32_t numEntries_ = N | |
// +------------------------------------------------+ |
// | Optimization type info 1 | |
// | uint32_t entryOffset = size(PayloadT) | |
// +------------------------------------------------+ |-- Table
// | ... | |
// +------------------------------------------------+ |
// | Optimization type info N | |
// | uint32_t entryOffset | |
// +================================================+
// | Optimization attempts 1 | |
// |------------------------------------------------| |
// | Optimization attempts 2 | |-- PayloadA of list of
// |------------------------------------------------| | IonTrackedOptimizationAttempts in
// | ... | | order of decreasing frequency
// |------------------------------------------------| |
// | Optimization attempts N | |
// +================================================+ <- IonTrackedOptimizationsAttemptsTable
// | uint32_t numEntries_ = N | |
// +------------------------------------------------+ |
// | Optimization attempts 1 | |
// | uint32_t entryOffset = size(PayloadA) | |
// +------------------------------------------------+ |-- Table
// | ... | |
// +------------------------------------------------+ |
// | Optimization attempts N | |
// | uint32_t entryOffset | |
// +------------------------------------------------+
//
// Abstractly, each region in the PayloadR section is a list of triples of the
// following, in order of ascending startOffset:
//
// (startOffset, endOffset, optimization attempts index)
//
// The range of [startOffset, endOffset) is the native machine code offsets
// for which the optimization attempts referred to by the index applies.
//
// Concretely, each region starts with a header of:
//
// { startOffset : 32, endOffset : 32 }
//
// followed by an (endOffset, index) pair, then by delta-encoded variants
// triples described below.
//
// Each list of type infos in the PayloadT section is a list of triples:
//
// (kind, MIR type, type set)
//
// The type set is separately in another vector, and what is encoded instead
// is the (offset, length) pair needed to index into that vector.
//
// Each list of optimization attempts in the PayloadA section is a list of
// pairs:
//
// (strategy, outcome)
//
// Both tail tables for PayloadR and PayloadA use reverse offsets from the
// table pointers.
class IonTrackedOptimizationsRegion
{
const uint8_t *start_;
const uint8_t *end_;
// Unpacked state.
uint32_t startOffset_;
uint32_t endOffset_;
const uint8_t *rangesStart_;
void unpackHeader();
public:
IonTrackedOptimizationsRegion(const uint8_t *start, const uint8_t *end)
: start_(start), end_(end),
startOffset_(0), endOffset_(0), rangesStart_(nullptr)
{
MOZ_ASSERT(start < end);
unpackHeader();
}
// Offsets for the entire range that this region covers.
//
// This, as well as the offsets for the deltas, is open at the ending
// address: [startOffset, endOffset).
uint32_t startOffset() const { return startOffset_; }
uint32_t endOffset() const { return endOffset_; }
class RangeIterator {
const uint8_t *cur_;
const uint8_t *start_;
const uint8_t *end_;
uint32_t firstStartOffset_;
uint32_t prevEndOffset_;
public:
RangeIterator(const uint8_t *start, const uint8_t *end, uint32_t startOffset)
: cur_(start), start_(start), end_(end),
firstStartOffset_(startOffset), prevEndOffset_(0)
{ }
bool more() const { return cur_ < end_; }
void readNext(uint32_t *startOffset, uint32_t *endOffset, uint8_t *index);
};
RangeIterator ranges() const { return RangeIterator(rangesStart_, end_, startOffset_); }
mozilla::Maybe<uint8_t> findAttemptsIndex(uint32_t offset) const;
// For the variants below, S stands for startDelta, L for length, and I
// for index. These were automatically generated from training on the
// Octane benchmark.
//
// byte 1 byte 0
// SSSS-SSSL LLLL-LII0
// startDelta max 127, length max 63, index max 3
static const uint32_t ENC1_MASK = 0x1;
static const uint32_t ENC1_MASK_VAL = 0x0;
static const uint32_t ENC1_START_DELTA_MAX = 0x7f;
static const uint32_t ENC1_START_DELTA_SHIFT = 9;
static const uint32_t ENC1_LENGTH_MAX = 0x3f;
static const uint32_t ENC1_LENGTH_SHIFT = 3;
static const uint32_t ENC1_INDEX_MAX = 0x3;
static const uint32_t ENC1_INDEX_SHIFT = 1;
// byte 2 byte 1 byte 0
// SSSS-SSSS SSSS-LLLL LLII-II01
// startDelta max 4095, length max 63, index max 15
static const uint32_t ENC2_MASK = 0x3;
static const uint32_t ENC2_MASK_VAL = 0x1;
static const uint32_t ENC2_START_DELTA_MAX = 0xfff;
static const uint32_t ENC2_START_DELTA_SHIFT = 12;
static const uint32_t ENC2_LENGTH_MAX = 0x3f;
static const uint32_t ENC2_LENGTH_SHIFT = 6;
static const uint32_t ENC2_INDEX_MAX = 0xf;
static const uint32_t ENC2_INDEX_SHIFT = 2;
// byte 3 byte 2 byte 1 byte 0
// SSSS-SSSS SSSL-LLLL LLLL-LIII IIII-I011
// startDelta max 2047, length max 1023, index max 255
static const uint32_t ENC3_MASK = 0x7;
static const uint32_t ENC3_MASK_VAL = 0x3;
static const uint32_t ENC3_START_DELTA_MAX = 0x7ff;
static const uint32_t ENC3_START_DELTA_SHIFT = 21;
static const uint32_t ENC3_LENGTH_MAX = 0x3ff;
static const uint32_t ENC3_LENGTH_SHIFT = 11;
static const uint32_t ENC3_INDEX_MAX = 0xff;
static const uint32_t ENC3_INDEX_SHIFT = 3;
// byte 4 byte 3 byte 2 byte 1 byte 0
// SSSS-SSSS SSSS-SSSL LLLL-LLLL LLLL-LIII IIII-I111
// startDelta max 32767, length max 16383, index max 255
static const uint32_t ENC4_MASK = 0x7;
static const uint32_t ENC4_MASK_VAL = 0x7;
static const uint32_t ENC4_START_DELTA_MAX = 0x7fff;
static const uint32_t ENC4_START_DELTA_SHIFT = 25;
static const uint32_t ENC4_LENGTH_MAX = 0x3fff;
static const uint32_t ENC4_LENGTH_SHIFT = 11;
static const uint32_t ENC4_INDEX_MAX = 0xff;
static const uint32_t ENC4_INDEX_SHIFT = 3;
static bool IsDeltaEncodeable(uint32_t startDelta, uint32_t length) {
MOZ_ASSERT(length != 0);
return startDelta <= ENC4_START_DELTA_MAX && length <= ENC4_LENGTH_MAX;
}
static const uint32_t MAX_RUN_LENGTH = 100;
typedef CodeGeneratorShared::NativeToTrackedOptimizations NativeToTrackedOptimizations;
static uint32_t ExpectedRunLength(const NativeToTrackedOptimizations *start,
const NativeToTrackedOptimizations *end);
static void ReadDelta(CompactBufferReader &reader, uint32_t *startDelta, uint32_t *length,
uint8_t *index);
static void WriteDelta(CompactBufferWriter &writer, uint32_t startDelta, uint32_t length,
uint8_t index);
static bool WriteRun(CompactBufferWriter &writer,
const NativeToTrackedOptimizations *start,
const NativeToTrackedOptimizations *end,
const UniqueTrackedOptimizations &unique);
};
class IonTrackedOptimizationsAttempts
{
const uint8_t *start_;
const uint8_t *end_;
public:
IonTrackedOptimizationsAttempts(const uint8_t *start, const uint8_t *end)
: start_(start), end_(end)
{
// Cannot be empty.
MOZ_ASSERT(start < end);
}
template <class T>
bool readVector(T *attempts) {
CompactBufferReader reader(start_, end_);
const uint8_t *cur = start_;
while (cur != end_) {
if (!attempts->append(OptimizationAttempt(reader)))
return false;
cur = reader.currentPosition();
MOZ_ASSERT(cur <= end_);
}
return true;
}
};
class IonTrackedOptimizationsTypeInfo
{
const uint8_t *start_;
const uint8_t *end_;
public:
IonTrackedOptimizationsTypeInfo(const uint8_t *start, const uint8_t *end)
: start_(start), end_(end)
{
// Can be empty; i.e., no type info was tracked.
}
bool empty() const { return start_ == end_; }
template <class T>
bool readVector(T *types, const types::TypeSet::TypeList *allTypes) {
CompactBufferReader reader(start_, end_);
const uint8_t *cur = start_;
while (cur != end_) {
TrackedTypeInfo ty(reader);
if (!ty.readTypes(reader, allTypes))
return false;
if (!types->append(mozilla::Move(ty)))
return false;
cur = reader.currentPosition();
MOZ_ASSERT(cur <= end_);
}
return true;
}
};
template <class Entry>
class IonTrackedOptimizationsOffsetsTable
{
uint32_t padding_;
uint32_t numEntries_;
uint32_t entryOffsets_[1];
protected:
const uint8_t *payloadEnd() const {
return (uint8_t *)(this) - padding_;
}
public:
uint32_t numEntries() const { return numEntries_; }
uint32_t entryOffset(uint32_t index) const {
MOZ_ASSERT(index < numEntries());
return entryOffsets_[index];
}
Entry entry(uint32_t index) const {
const uint8_t *start = payloadEnd() - entryOffset(index);
const uint8_t *end = payloadEnd();
if (index < numEntries() - 1)
end -= entryOffset(index + 1);
return Entry(start, end);
}
};
class IonTrackedOptimizationsRegionTable
: public IonTrackedOptimizationsOffsetsTable<IonTrackedOptimizationsRegion>
{
public:
mozilla::Maybe<IonTrackedOptimizationsRegion> findRegion(uint32_t offset) const;
const uint8_t *payloadStart() const { return payloadEnd() - entryOffset(0); }
};
typedef IonTrackedOptimizationsOffsetsTable<IonTrackedOptimizationsAttempts>
IonTrackedOptimizationsAttemptsTable;
typedef IonTrackedOptimizationsOffsetsTable<IonTrackedOptimizationsTypeInfo>
IonTrackedOptimizationsTypesTable;
bool
WriteIonTrackedOptimizationsTable(JSContext *cx, CompactBufferWriter &writer,
const CodeGeneratorShared::NativeToTrackedOptimizations *start,
const CodeGeneratorShared::NativeToTrackedOptimizations *end,
const UniqueTrackedOptimizations &unique,
uint32_t *numRegions, uint32_t *regionTableOffsetp,
uint32_t *typesTableOffsetp, uint32_t *attemptsTableOffsetp,
types::TypeSet::TypeList *allTypes);
} // namespace jit
} // namespace js
#endif // jit_OptimizationTracking_h

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

@ -15,6 +15,7 @@
#include "jit/MacroAssembler.h"
#include "jit/MIR.h"
#include "jit/MIRGenerator.h"
#include "jit/OptimizationTracking.h"
#include "js/Conversions.h"
#include "vm/TraceLogging.h"
@ -59,6 +60,11 @@ CodeGeneratorShared::CodeGeneratorShared(MIRGenerator *gen, LIRGraph *graph, Mac
nativeToBytecodeNumRegions_(0),
nativeToBytecodeScriptList_(nullptr),
nativeToBytecodeScriptListLength_(0),
trackedOptimizationsMap_(nullptr),
trackedOptimizationsMapSize_(0),
trackedOptimizationsRegionTableOffset_(0),
trackedOptimizationsTypesTableOffset_(0),
trackedOptimizationsAttemptsTableOffset_(0),
osrEntryOffset_(0),
skipArgCheckEntryOffset_(0),
#ifdef CHECK_OSIPOINT_REGISTERS
@ -261,6 +267,53 @@ CodeGeneratorShared::dumpNativeToBytecodeEntry(uint32_t idx)
#endif
}
bool
CodeGeneratorShared::addTrackedOptimizationsEntry(const TrackedOptimizations *optimizations)
{
if (!isOptimizationTrackingEnabled())
return true;
MOZ_ASSERT(optimizations);
uint32_t nativeOffset = masm.currentOffset();
if (!trackedOptimizations_.empty()) {
NativeToTrackedOptimizations &lastEntry = trackedOptimizations_.back();
MOZ_ASSERT(nativeOffset >= lastEntry.endOffset.offset());
// If we're still generating code for the same set of optimizations,
// we are done.
if (lastEntry.optimizations == optimizations)
return true;
}
// If we're generating code for a new set of optimizations, add a new
// entry.
NativeToTrackedOptimizations entry;
entry.startOffset = CodeOffsetLabel(nativeOffset);
entry.endOffset = CodeOffsetLabel(nativeOffset);
entry.optimizations = optimizations;
return trackedOptimizations_.append(entry);
}
void
CodeGeneratorShared::extendTrackedOptimizationsEntry(const TrackedOptimizations *optimizations)
{
if (!isOptimizationTrackingEnabled())
return;
uint32_t nativeOffset = masm.currentOffset();
NativeToTrackedOptimizations &entry = trackedOptimizations_.back();
MOZ_ASSERT(entry.optimizations == optimizations);
MOZ_ASSERT(nativeOffset >= entry.endOffset.offset());
entry.endOffset = CodeOffsetLabel(nativeOffset);
// If we generated no code, remove the last entry.
if (nativeOffset == entry.startOffset.offset())
trackedOptimizations_.popBack();
}
// see OffsetOfFrameSlot
static inline int32_t
ToStackIndex(LAllocation *a)
@ -722,6 +775,159 @@ CodeGeneratorShared::verifyCompactNativeToBytecodeMap(JitCode *code)
#endif // DEBUG
}
bool
CodeGeneratorShared::generateCompactTrackedOptimizationsMap(JSContext *cx, JitCode *code,
types::TypeSet::TypeList *allTypes)
{
MOZ_ASSERT(trackedOptimizationsMap_ == nullptr);
MOZ_ASSERT(trackedOptimizationsMapSize_ == 0);
MOZ_ASSERT(trackedOptimizationsRegionTableOffset_ == 0);
MOZ_ASSERT(trackedOptimizationsTypesTableOffset_ == 0);
MOZ_ASSERT(trackedOptimizationsAttemptsTableOffset_ == 0);
if (trackedOptimizations_.empty())
return true;
UniqueTrackedOptimizations unique(cx);
if (!unique.init())
return false;
// Iterate through all entries, fix up their masm offsets and deduplicate
// their optimization attempts.
for (size_t i = 0; i < trackedOptimizations_.length(); i++) {
NativeToTrackedOptimizations &entry = trackedOptimizations_[i];
entry.startOffset = CodeOffsetLabel(masm.actualOffset(entry.startOffset.offset()));
entry.endOffset = CodeOffsetLabel(masm.actualOffset(entry.endOffset.offset()));
if (!unique.add(entry.optimizations))
return false;
}
// Sort the unique optimization attempts by frequency to stabilize the
// attempts' indices in the compact table we will write later.
if (!unique.sortByFrequency(cx))
return false;
// Write out the ranges and the table.
CompactBufferWriter writer;
uint32_t numRegions;
uint32_t regionTableOffset;
uint32_t typesTableOffset;
uint32_t attemptsTableOffset;
if (!WriteIonTrackedOptimizationsTable(cx, writer,
trackedOptimizations_.begin(),
trackedOptimizations_.end(),
unique, &numRegions,
&regionTableOffset, &typesTableOffset,
&attemptsTableOffset, allTypes))
{
return false;
}
MOZ_ASSERT(regionTableOffset > 0);
MOZ_ASSERT(typesTableOffset > 0);
MOZ_ASSERT(attemptsTableOffset > 0);
MOZ_ASSERT(typesTableOffset > regionTableOffset);
MOZ_ASSERT(attemptsTableOffset > typesTableOffset);
// Copy over the table out of the writer's buffer.
uint8_t *data = cx->runtime()->pod_malloc<uint8_t>(writer.length());
if (!data)
return false;
memcpy(data, writer.buffer(), writer.length());
trackedOptimizationsMap_ = data;
trackedOptimizationsMapSize_ = writer.length();
trackedOptimizationsRegionTableOffset_ = regionTableOffset;
trackedOptimizationsTypesTableOffset_ = typesTableOffset;
trackedOptimizationsAttemptsTableOffset_ = attemptsTableOffset;
verifyCompactTrackedOptimizationsMap(code, numRegions, unique, allTypes);
JitSpew(JitSpew_OptimizationTracking,
"== Compact Native To Optimizations Map [%p-%p] size %u",
data, data + trackedOptimizationsMapSize_, trackedOptimizationsMapSize_);
JitSpew(JitSpew_OptimizationTracking,
" with type list of length %u, size %u",
allTypes->length(), allTypes->length() * sizeof(types::Type));
return true;
}
void
CodeGeneratorShared::verifyCompactTrackedOptimizationsMap(JitCode *code, uint32_t numRegions,
const UniqueTrackedOptimizations &unique,
const types::TypeSet::TypeList *allTypes)
{
#ifdef DEBUG
MOZ_ASSERT(trackedOptimizationsMap_ != nullptr);
MOZ_ASSERT(trackedOptimizationsMapSize_ > 0);
MOZ_ASSERT(trackedOptimizationsRegionTableOffset_ > 0);
MOZ_ASSERT(trackedOptimizationsTypesTableOffset_ > 0);
MOZ_ASSERT(trackedOptimizationsAttemptsTableOffset_ > 0);
// Table pointers must all be 4-byte aligned.
const uint8_t *regionTableAddr = trackedOptimizationsMap_ +
trackedOptimizationsRegionTableOffset_;
const uint8_t *typesTableAddr = trackedOptimizationsMap_ +
trackedOptimizationsTypesTableOffset_;
const uint8_t *attemptsTableAddr = trackedOptimizationsMap_ +
trackedOptimizationsAttemptsTableOffset_;
MOZ_ASSERT(uintptr_t(regionTableAddr) % sizeof(uint32_t) == 0);
MOZ_ASSERT(uintptr_t(typesTableAddr) % sizeof(uint32_t) == 0);
MOZ_ASSERT(uintptr_t(attemptsTableAddr) % sizeof(uint32_t) == 0);
// Assert that the number of entries matches up for the tables.
const IonTrackedOptimizationsRegionTable *regionTable =
(const IonTrackedOptimizationsRegionTable *) regionTableAddr;
MOZ_ASSERT(regionTable->numEntries() == numRegions);
const IonTrackedOptimizationsTypesTable *typesTable =
(const IonTrackedOptimizationsTypesTable *) typesTableAddr;
MOZ_ASSERT(typesTable->numEntries() == unique.count());
const IonTrackedOptimizationsAttemptsTable *attemptsTable =
(const IonTrackedOptimizationsAttemptsTable *) attemptsTableAddr;
MOZ_ASSERT(attemptsTable->numEntries() == unique.count());
// Verify each region.
uint32_t trackedIdx = 0;
for (uint32_t regionIdx = 0; regionIdx < regionTable->numEntries(); regionIdx++) {
// Check reverse offsets are within bounds.
MOZ_ASSERT(regionTable->entryOffset(regionIdx) <= trackedOptimizationsRegionTableOffset_);
MOZ_ASSERT_IF(regionIdx > 0, regionTable->entryOffset(regionIdx) <
regionTable->entryOffset(regionIdx - 1));
IonTrackedOptimizationsRegion region = regionTable->entry(regionIdx);
// Check the region range is covered by jitcode.
MOZ_ASSERT(region.startOffset() <= code->instructionsSize());
MOZ_ASSERT(region.endOffset() <= code->instructionsSize());
IonTrackedOptimizationsRegion::RangeIterator iter = region.ranges();
while (iter.more()) {
// Assert that the offsets are correctly decoded from the delta.
uint32_t startOffset, endOffset;
uint8_t index;
iter.readNext(&startOffset, &endOffset, &index);
NativeToTrackedOptimizations &entry = trackedOptimizations_[trackedIdx++];
MOZ_ASSERT(startOffset == entry.startOffset.offset());
MOZ_ASSERT(endOffset == entry.endOffset.offset());
MOZ_ASSERT(index == unique.indexOf(entry.optimizations));
// Assert that the type info and attempts vector are correctly
// decoded. Since this is a DEBUG-only verification, crash on OOM.
IonTrackedOptimizationsTypeInfo typeInfo = typesTable->entry(index);
TempTrackedTypeInfoVector tvec(alloc());
MOZ_ALWAYS_TRUE(typeInfo.readVector(&tvec, allTypes));
MOZ_ASSERT(entry.optimizations->matchTypes(tvec));
IonTrackedOptimizationsAttempts attempts = attemptsTable->entry(index);
TempAttemptsVector avec(alloc());
MOZ_ALWAYS_TRUE(attempts.readVector(&avec));
MOZ_ASSERT(entry.optimizations->matchAttempts(avec));
}
}
#endif
}
void
CodeGeneratorShared::markSafepoint(LInstruction *ins)
{

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

@ -25,6 +25,7 @@ class OutOfLineCode;
class CodeGenerator;
class MacroAssembler;
class IonCache;
class UniqueTrackedOptimizations;
template <class ArgSeq, class StoreOutputTo>
class OutOfLineCallVM;
@ -114,6 +115,26 @@ class CodeGeneratorShared : public LElementVisitor
return gen->isProfilerInstrumentationEnabled();
}
public:
struct NativeToTrackedOptimizations {
// [startOffset, endOffset)
CodeOffsetLabel startOffset;
CodeOffsetLabel endOffset;
const TrackedOptimizations *optimizations;
};
protected:
js::Vector<NativeToTrackedOptimizations, 0, SystemAllocPolicy> trackedOptimizations_;
uint8_t *trackedOptimizationsMap_;
uint32_t trackedOptimizationsMapSize_;
uint32_t trackedOptimizationsRegionTableOffset_;
uint32_t trackedOptimizationsTypesTableOffset_;
uint32_t trackedOptimizationsAttemptsTableOffset_;
bool isOptimizationTrackingEnabled() {
return gen->isOptimizationTrackingEnabled();
}
protected:
// The offset of the first instruction of the OSR entry block from the
// beginning of the code buffer.
@ -243,6 +264,9 @@ class CodeGeneratorShared : public LElementVisitor
void dumpNativeToBytecodeEntries();
void dumpNativeToBytecodeEntry(uint32_t idx);
bool addTrackedOptimizationsEntry(const TrackedOptimizations *optimizations);
void extendTrackedOptimizationsEntry(const TrackedOptimizations *optimizations);
public:
MIRGenerator &mirGen() const {
return *gen;
@ -313,6 +337,12 @@ class CodeGeneratorShared : public LElementVisitor
bool generateCompactNativeToBytecodeMap(JSContext *cx, JitCode *code);
void verifyCompactNativeToBytecodeMap(JitCode *code);
bool generateCompactTrackedOptimizationsMap(JSContext *cx, JitCode *code,
types::TypeSet::TypeList *allTypes);
void verifyCompactTrackedOptimizationsMap(JitCode *code, uint32_t numRegions,
const UniqueTrackedOptimizations &unique,
const types::TypeSet::TypeList *allTypes);
// Mark the safepoint on |ins| as corresponding to the current assembler location.
// The location should be just after a call.
void markSafepoint(LInstruction *ins);

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

@ -2180,7 +2180,7 @@ GCRuntime::relocateArenas()
if (CanRelocateZone(rt, zone)) {
zone->setGCState(Zone::Compact);
StopAllOffThreadCompilations(zone);
jit::StopAllOffThreadCompilations(zone);
relocatedList = zone->arenas.relocateArenas(relocatedList);
}
}

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

@ -420,7 +420,7 @@ TypeSet::isSubset(const TypeSet *other) const
}
bool
TypeSet::enumerateTypes(TypeList *list)
TypeSet::enumerateTypes(TypeList *list) const
{
/* If any type is possible, there's no need to worry about specifics. */
if (flags & TYPE_FLAG_UNKNOWN)

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

@ -511,7 +511,7 @@ class TypeSet
/* Get a list of all types in this set. */
typedef Vector<Type, 1, SystemAllocPolicy> TypeList;
bool enumerateTypes(TypeList *list);
bool enumerateTypes(TypeList *list) const;
/*
* Iterate through the objects in this set. getObjectCount overapproximates

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

@ -178,6 +178,7 @@ UNIFIED_SOURCES += [
'jit/MIR.cpp',
'jit/MIRGraph.cpp',
'jit/MoveResolver.cpp',
'jit/OptimizationTracking.cpp',
'jit/PerfSpewer.cpp',
'jit/RangeAnalysis.cpp',
'jit/Recover.cpp',

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

@ -1551,8 +1551,8 @@ js_InitArrayBufferClass(JSContext *cx, HandleObject obj)
RootedId byteLengthId(cx, NameToId(cx->names().byteLength));
unsigned attrs = JSPROP_SHARED | JSPROP_GETTER;
JSObject *getter = NewFunction(cx, NullPtr(), ArrayBufferObject::byteLengthGetter, 0,
JSFunction::NATIVE_FUN, global, NullPtr());
JSObject *getter = NewFunction(cx, js::NullPtr(), ArrayBufferObject::byteLengthGetter, 0,
JSFunction::NATIVE_FUN, global, js::NullPtr());
if (!getter)
return nullptr;

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

@ -86,7 +86,7 @@
*
* To find the Shape for a particular property of an object initially requires
* a linear search. But if the number of searches starting at any particular
* Shape in the property tree exceeds MAX_LINEAR_SEARCHES and the Shape's
* Shape in the property tree exceeds LINEAR_SEARCHES_MAX and the Shape's
* lineage has (excluding the EmptyShape) at least MIN_ENTRIES, we create an
* auxiliary hash table -- the ShapeTable -- that allows faster lookup.
* Furthermore, a ShapeTable is always created for dictionary mode lists,

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

@ -410,16 +410,14 @@ FontFaceSet::StartLoad(gfxUserFontEntry* aUserFontEntry,
return NS_ERROR_OUT_OF_MEMORY;
#ifdef PR_LOGGING
if (PR_LOG_TEST(nsFontFaceLoader::GetFontDownloaderLog(),
PR_LOG_DEBUG)) {
if (LOG_ENABLED()) {
nsAutoCString fontURI, referrerURI;
aFontFaceSrc->mURI->GetSpec(fontURI);
if (aFontFaceSrc->mReferrer)
aFontFaceSrc->mReferrer->GetSpec(referrerURI);
PR_LOG(nsFontFaceLoader::GetFontDownloaderLog(), PR_LOG_DEBUG,
("fontdownloader (%p) download start - font uri: (%s) "
"referrer uri: (%s)\n",
fontLoader.get(), fontURI.get(), referrerURI.get()));
LOG(("userfonts (%p) download start - font uri: (%s) "
"referrer uri: (%s)\n",
fontLoader.get(), fontURI.get(), referrerURI.get()));
}
#endif
@ -612,10 +610,12 @@ FontFaceSet::UpdateRules(const nsTArray<nsFontFaceRuleContainer>& aRules)
mUserFontSet->mLocalRulesUsed = false;
#if PR_LOGGING
LOG(("userfonts (%p) userfont rules update (%s) rule count: %d",
mUserFontSet.get(),
(modified ? "modified" : "not modified"),
mRuleFaces.Length()));
if (LOG_ENABLED() && !mRuleFaces.IsEmpty()) {
LOG(("userfonts (%p) userfont rules update (%s) rule count: %d",
mUserFontSet.get(),
(modified ? "modified" : "not modified"),
mRuleFaces.Length()));
}
#endif
return modified;
@ -1073,9 +1073,8 @@ FontFaceSet::LogMessage(gfxUserFontEntry* aUserFontEntry,
message.Append(fontURI);
#ifdef PR_LOGGING
if (PR_LOG_TEST(gfxUserFontSet::GetUserFontsLog(), PR_LOG_DEBUG)) {
PR_LOG(gfxUserFontSet::GetUserFontsLog(), PR_LOG_DEBUG,
("userfonts (%p) %s", mUserFontSet.get(), message.get()));
if (LOG_ENABLED()) {
LOG(("userfonts (%p) %s", mUserFontSet.get(), message.get()));
}
#endif

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

@ -25,20 +25,9 @@
using namespace mozilla;
#ifdef PR_LOGGING
PRLogModuleInfo*
nsFontFaceLoader::GetFontDownloaderLog()
{
static PRLogModuleInfo* sLog;
if (!sLog)
sLog = PR_NewLogModule("fontdownloader");
return sLog;
}
#endif /* PR_LOGGING */
#define LOG(args) PR_LOG(GetFontDownloaderLog(), PR_LOG_DEBUG, args)
#define LOG_ENABLED() PR_LOG_TEST(GetFontDownloaderLog(), PR_LOG_DEBUG)
#define LOG(args) PR_LOG(gfxUserFontSet::GetUserFontsLog(), PR_LOG_DEBUG, args)
#define LOG_ENABLED() PR_LOG_TEST(gfxUserFontSet::GetUserFontsLog(), \
PR_LOG_DEBUG)
nsFontFaceLoader::nsFontFaceLoader(gfxUserFontEntry* aUserFontEntry,
nsIURI* aFontURI,
@ -119,7 +108,7 @@ nsFontFaceLoader::LoadTimerCallback(nsITimer* aTimer, void* aClosure)
delay >> 1,
nsITimer::TYPE_ONE_SHOT);
updateUserFontSet = false;
LOG(("fontdownloader (%p) 75%% done, resetting timer\n", loader));
LOG(("userfonts (%p) 75%% done, resetting timer\n", loader));
}
}
@ -133,7 +122,7 @@ nsFontFaceLoader::LoadTimerCallback(nsITimer* aTimer, void* aClosure)
if (ctx) {
loader->mFontFaceSet->IncrementGeneration();
ctx->UserFontSetUpdated();
LOG(("fontdownloader (%p) timeout reflow\n", loader));
LOG(("userfonts (%p) timeout reflow\n", loader));
}
}
}
@ -159,10 +148,10 @@ nsFontFaceLoader::OnStreamComplete(nsIStreamLoader* aLoader,
nsAutoCString fontURI;
mFontURI->GetSpec(fontURI);
if (NS_SUCCEEDED(aStatus)) {
LOG(("fontdownloader (%p) download completed - font uri: (%s)\n",
LOG(("userfonts (%p) download completed - font uri: (%s)\n",
this, fontURI.get()));
} else {
LOG(("fontdownloader (%p) download failed - font uri: (%s) error: %8.8x\n",
LOG(("userfonts (%p) download failed - font uri: (%s) error: %8.8x\n",
this, fontURI.get(), aStatus));
}
}
@ -205,7 +194,7 @@ nsFontFaceLoader::OnStreamComplete(nsIStreamLoader* aLoader,
// Update layout for the presence of the new font. Since this is
// asynchronous, reflows will coalesce.
ctx->UserFontSetUpdated();
LOG(("fontdownloader (%p) reflow\n", this));
LOG(("userfonts (%p) reflow\n", this));
}
// done with font set

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

@ -46,10 +46,6 @@ public:
nsIURI* aTargetURI,
nsISupports* aContext);
#ifdef PR_LOGGING
static PRLogModuleInfo* GetFontDownloaderLog();
#endif
protected:
virtual ~nsFontFaceLoader();

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

@ -1,69 +0,0 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* 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/. */
package org.mozilla.gecko.gfx;
import org.mozilla.gecko.mozglue.DirectBufferAllocator;
import android.graphics.Bitmap;
import android.util.Log;
import java.nio.ByteBuffer;
/** A Cairo image that simply saves a buffer of pixel data. */
public class BufferedCairoImage extends CairoImage {
private ByteBuffer mBuffer;
private IntSize mSize;
private int mFormat;
private static final String LOGTAG = "GeckoBufferedCairoImage";
/** Creates a buffered Cairo image from a byte buffer. */
public BufferedCairoImage(ByteBuffer inBuffer, int inWidth, int inHeight, int inFormat) {
setBuffer(inBuffer, inWidth, inHeight, inFormat);
}
/** Creates a buffered Cairo image from an Android bitmap. */
public BufferedCairoImage(Bitmap bitmap) {
setBitmap(bitmap);
}
private synchronized void freeBuffer() {
mBuffer = DirectBufferAllocator.free(mBuffer);
}
@Override
public void destroy() {
try {
freeBuffer();
} catch (Exception ex) {
Log.e(LOGTAG, "error clearing buffer: ", ex);
}
}
@Override
public ByteBuffer getBuffer() { return mBuffer; }
@Override
public IntSize getSize() { return mSize; }
@Override
public int getFormat() { return mFormat; }
public void setBuffer(ByteBuffer buffer, int width, int height, int format) {
freeBuffer();
mBuffer = buffer;
mSize = new IntSize(width, height);
mFormat = format;
}
public void setBitmap(Bitmap bitmap) {
mFormat = CairoUtils.bitmapConfigToCairoFormat(bitmap.getConfig());
mSize = new IntSize(bitmap.getWidth(), bitmap.getHeight());
int bpp = CairoUtils.bitsPerPixelForCairoFormat(mFormat);
mBuffer = DirectBufferAllocator.allocate(mSize.getArea() * bpp);
bitmap.copyPixelsToBuffer(mBuffer.asIntBuffer());
}
}

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

@ -0,0 +1,96 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* 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/. */
package org.mozilla.gecko.gfx;
import org.mozilla.gecko.mozglue.DirectBufferAllocator;
import android.graphics.Bitmap;
import android.util.Log;
import java.nio.ByteBuffer;
/** A buffered image that simply saves a buffer of pixel data. */
public class BufferedImage {
private ByteBuffer mBuffer;
private IntSize mSize;
private int mFormat;
private static final String LOGTAG = "GeckoBufferedImage";
/** Creates an empty buffered image */
public BufferedImage() {
setBuffer(null, 0, 0, 0);
}
/** Creates a buffered image from an Android bitmap. */
public BufferedImage(Bitmap bitmap) {
setBitmap(bitmap);
}
private synchronized void freeBuffer() {
mBuffer = DirectBufferAllocator.free(mBuffer);
}
public void destroy() {
try {
freeBuffer();
} catch (Exception ex) {
Log.e(LOGTAG, "error clearing buffer: ", ex);
}
}
public ByteBuffer getBuffer() { return mBuffer; }
public IntSize getSize() { return mSize; }
public int getFormat() { return mFormat; }
public static final int FORMAT_INVALID = -1;
public static final int FORMAT_ARGB32 = 0;
public static final int FORMAT_RGB24 = 1;
public static final int FORMAT_A8 = 2;
public static final int FORMAT_A1 = 3;
public static final int FORMAT_RGB16_565 = 4;
public void setBuffer(ByteBuffer buffer, int width, int height, int format) {
freeBuffer();
mBuffer = buffer;
mSize = new IntSize(width, height);
mFormat = format;
}
public void setBitmap(Bitmap bitmap) {
mFormat = bitmapConfigToFormat(bitmap.getConfig());
mSize = new IntSize(bitmap.getWidth(), bitmap.getHeight());
int bpp = bitsPerPixelForFormat(mFormat);
mBuffer = DirectBufferAllocator.allocate(mSize.getArea() * bpp);
bitmap.copyPixelsToBuffer(mBuffer.asIntBuffer());
}
private static int bitsPerPixelForFormat(int format) {
switch (format) {
case FORMAT_A1: return 1;
case FORMAT_A8: return 8;
case FORMAT_RGB16_565: return 16;
case FORMAT_RGB24: return 24;
case FORMAT_ARGB32: return 32;
default:
throw new RuntimeException("Unknown Cairo format");
}
}
private static int bitmapConfigToFormat(Bitmap.Config config) {
if (config == null)
return FORMAT_ARGB32; /* Droid Pro fix. */
switch (config) {
case ALPHA_8: return FORMAT_A8;
case ARGB_4444: throw new RuntimeException("ARGB_444 unsupported");
case ARGB_8888: return FORMAT_ARGB32;
case RGB_565: return FORMAT_RGB16_565;
default: throw new RuntimeException("Unknown Skia bitmap config");
}
}
}

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

@ -7,28 +7,28 @@ package org.mozilla.gecko.gfx;
import javax.microedition.khronos.opengles.GL10;
/** Information needed to render Cairo bitmaps using OpenGL ES. */
public class CairoGLInfo {
/** Information needed to render buffered bitmaps using OpenGL ES. */
public class BufferedImageGLInfo {
public final int internalFormat;
public final int format;
public final int type;
public CairoGLInfo(int cairoFormat) {
switch (cairoFormat) {
case CairoImage.FORMAT_ARGB32:
public BufferedImageGLInfo(int bufferedImageFormat) {
switch (bufferedImageFormat) {
case BufferedImage.FORMAT_ARGB32:
internalFormat = format = GL10.GL_RGBA; type = GL10.GL_UNSIGNED_BYTE;
break;
case CairoImage.FORMAT_RGB24:
case BufferedImage.FORMAT_RGB24:
internalFormat = format = GL10.GL_RGB; type = GL10.GL_UNSIGNED_BYTE;
break;
case CairoImage.FORMAT_RGB16_565:
case BufferedImage.FORMAT_RGB16_565:
internalFormat = format = GL10.GL_RGB; type = GL10.GL_UNSIGNED_SHORT_5_6_5;
break;
case CairoImage.FORMAT_A8:
case CairoImage.FORMAT_A1:
throw new RuntimeException("Cairo FORMAT_A1 and FORMAT_A8 unsupported");
case BufferedImage.FORMAT_A8:
case BufferedImage.FORMAT_A1:
throw new RuntimeException("BufferedImage FORMAT_A1 and FORMAT_A8 unsupported");
default:
throw new RuntimeException("Unknown Cairo format");
throw new RuntimeException("Unknown BufferedImage format");
}
}
}

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